summaryrefslogtreecommitdiffstats
path: root/chromium/net/tools
diff options
context:
space:
mode:
authorJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-08 14:30:41 +0200
committerJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-12 13:49:54 +0200
commitab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch)
tree498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/net/tools
parent4ce69f7403811819800e7c5ae1318b2647e778d1 (diff)
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/net/tools')
-rw-r--r--chromium/net/tools/DEPS4
-rw-r--r--chromium/net/tools/balsa/balsa_enums.h5
-rw-r--r--chromium/net/tools/balsa/balsa_frame.cc15
-rw-r--r--chromium/net/tools/balsa/balsa_frame.h2
-rw-r--r--chromium/net/tools/balsa/balsa_headers.cc25
-rw-r--r--chromium/net/tools/balsa/balsa_headers.h2
-rw-r--r--chromium/net/tools/balsa/string_piece_utils.h29
-rw-r--r--chromium/net/tools/crash_cache/crash_cache.cc6
-rw-r--r--chromium/net/tools/crl_set_dump/crl_set_dump.cc3
-rw-r--r--chromium/net/tools/disk_cache_memory_test/disk_cache_memory_test.cc5
-rw-r--r--chromium/net/tools/dns_fuzz_stub/dns_fuzz_stub.cc2
-rw-r--r--chromium/net/tools/dump_cache/cache_dumper.cc2
-rw-r--r--chromium/net/tools/dump_cache/cache_dumper.h2
-rw-r--r--chromium/net/tools/dump_cache/dump_cache.cc9
-rw-r--r--chromium/net/tools/dump_cache/dump_files.cc25
-rw-r--r--chromium/net/tools/dump_cache/upgrade_win.cc8
-rw-r--r--chromium/net/tools/fetch/fetch_client.cc231
-rw-r--r--chromium/net/tools/fetch/fetch_server.cc57
-rw-r--r--chromium/net/tools/fetch/http_listen_socket.cc249
-rw-r--r--chromium/net/tools/fetch/http_listen_socket.h70
-rw-r--r--chromium/net/tools/fetch/http_server.cc12
-rw-r--r--chromium/net/tools/fetch/http_server.h26
-rw-r--r--chromium/net/tools/fetch/http_server_request_info.cc11
-rw-r--r--chromium/net/tools/fetch/http_server_request_info.h26
-rw-r--r--chromium/net/tools/fetch/http_server_response_info.cc11
-rw-r--r--chromium/net/tools/fetch/http_server_response_info.h39
-rw-r--r--chromium/net/tools/fetch/http_session.cc33
-rw-r--r--chromium/net/tools/fetch/http_session.h27
-rw-r--r--chromium/net/tools/flip_server/flip_in_mem_edsm_server.cc4
-rw-r--r--chromium/net/tools/flip_server/loadtime_measurement.h54
-rw-r--r--chromium/net/tools/flip_server/sm_connection.cc4
-rw-r--r--chromium/net/tools/flip_server/sm_connection.h3
-rw-r--r--chromium/net/tools/flip_server/spdy_interface.cc48
-rw-r--r--chromium/net/tools/flip_server/spdy_interface.h15
-rw-r--r--chromium/net/tools/flip_server/spdy_interface_test.cc93
-rw-r--r--chromium/net/tools/flip_server/spdy_ssl.cc4
-rw-r--r--chromium/net/tools/gdig/file_net_log.cc2
-rw-r--r--chromium/net/tools/gdig/gdig.cc18
-rw-r--r--chromium/net/tools/get_server_time/get_server_time.cc47
-rw-r--r--chromium/net/tools/net_watcher/net_watcher.cc10
-rw-r--r--chromium/net/tools/quic/end_to_end_test.cc696
-rw-r--r--chromium/net/tools/quic/quic_client.cc121
-rw-r--r--chromium/net/tools/quic/quic_client.h92
-rw-r--r--chromium/net/tools/quic/quic_client_bin.cc57
-rw-r--r--chromium/net/tools/quic/quic_client_session.cc25
-rw-r--r--chromium/net/tools/quic/quic_client_session.h14
-rw-r--r--chromium/net/tools/quic/quic_client_session_test.cc24
-rw-r--r--chromium/net/tools/quic/quic_default_packet_writer.cc29
-rw-r--r--chromium/net/tools/quic/quic_default_packet_writer.h23
-rw-r--r--chromium/net/tools/quic/quic_dispatcher.cc381
-rw-r--r--chromium/net/tools/quic/quic_dispatcher.h149
-rw-r--r--chromium/net/tools/quic/quic_dispatcher_test.cc320
-rw-r--r--chromium/net/tools/quic/quic_epoll_clock.h4
-rw-r--r--chromium/net/tools/quic/quic_in_memory_cache.cc27
-rw-r--r--chromium/net/tools/quic/quic_in_memory_cache.h16
-rw-r--r--chromium/net/tools/quic/quic_in_memory_cache_test.cc2
-rw-r--r--chromium/net/tools/quic/quic_packet_writer_wrapper.cc48
-rw-r--r--chromium/net/tools/quic/quic_packet_writer_wrapper.h50
-rw-r--r--chromium/net/tools/quic/quic_server.cc63
-rw-r--r--chromium/net/tools/quic/quic_server.h42
-rw-r--r--chromium/net/tools/quic/quic_server_bin.cc10
-rw-r--r--chromium/net/tools/quic/quic_server_session.cc31
-rw-r--r--chromium/net/tools/quic/quic_server_session.h25
-rw-r--r--chromium/net/tools/quic/quic_server_session_test.cc217
-rw-r--r--chromium/net/tools/quic/quic_server_test.cc32
-rw-r--r--chromium/net/tools/quic/quic_socket_utils.cc68
-rw-r--r--chromium/net/tools/quic/quic_socket_utils.h31
-rw-r--r--chromium/net/tools/quic/quic_spdy_client_stream.cc43
-rw-r--r--chromium/net/tools/quic/quic_spdy_client_stream.h12
-rw-r--r--chromium/net/tools/quic/quic_spdy_client_stream_test.cc36
-rw-r--r--chromium/net/tools/quic/quic_spdy_server_stream.cc38
-rw-r--r--chromium/net/tools/quic/quic_spdy_server_stream.h3
-rw-r--r--chromium/net/tools/quic/quic_spdy_server_stream_test.cc146
-rw-r--r--chromium/net/tools/quic/quic_time_wait_list_manager.cc301
-rw-r--r--chromium/net/tools/quic/quic_time_wait_list_manager.h198
-rw-r--r--chromium/net/tools/quic/quic_time_wait_list_manager_test.cc439
-rw-r--r--chromium/net/tools/quic/spdy_utils.cc8
-rw-r--r--chromium/net/tools/quic/spdy_utils.h3
-rw-r--r--chromium/net/tools/quic/test_tools/http_message.cc (renamed from chromium/net/tools/quic/test_tools/http_message_test_utils.cc)4
-rw-r--r--chromium/net/tools/quic/test_tools/http_message.h (renamed from chromium/net/tools/quic/test_tools/http_message_test_utils.h)8
-rw-r--r--chromium/net/tools/quic/test_tools/mock_epoll_server.h12
-rw-r--r--chromium/net/tools/quic/test_tools/mock_quic_dispatcher.cc11
-rw-r--r--chromium/net/tools/quic/test_tools/mock_quic_dispatcher.h9
-rw-r--r--chromium/net/tools/quic/test_tools/packet_dropping_test_writer.cc78
-rw-r--r--chromium/net/tools/quic/test_tools/packet_dropping_test_writer.h38
-rw-r--r--chromium/net/tools/quic/test_tools/quic_client_peer.cc14
-rw-r--r--chromium/net/tools/quic/test_tools/quic_client_peer.h12
-rw-r--r--chromium/net/tools/quic/test_tools/quic_dispatcher_peer.cc21
-rw-r--r--chromium/net/tools/quic/test_tools/quic_dispatcher_peer.h20
-rw-r--r--chromium/net/tools/quic/test_tools/quic_server_peer.cc5
-rw-r--r--chromium/net/tools/quic/test_tools/quic_server_peer.h6
-rw-r--r--chromium/net/tools/quic/test_tools/quic_test_client.cc349
-rw-r--r--chromium/net/tools/quic/test_tools/quic_test_client.h162
-rw-r--r--chromium/net/tools/quic/test_tools/quic_test_utils.cc60
-rw-r--r--chromium/net/tools/quic/test_tools/quic_test_utils.h100
-rw-r--r--chromium/net/tools/quic/test_tools/server_thread.cc45
-rw-r--r--chromium/net/tools/quic/test_tools/server_thread.h21
-rw-r--r--chromium/net/tools/quic/test_tools/simple_client.cc36
-rw-r--r--chromium/net/tools/quic/test_tools/simple_client.h159
-rw-r--r--chromium/net/tools/testserver/run_testserver.cc7
-rwxr-xr-xchromium/net/tools/testserver/testserver.py142
-rw-r--r--chromium/net/tools/testserver/testserver_base.py8
-rw-r--r--chromium/net/tools/tld_cleanup/BUILD.gn14
-rw-r--r--chromium/net/tools/tld_cleanup/PRESUBMIT.py32
-rw-r--r--chromium/net/tools/tld_cleanup/README13
-rwxr-xr-xchromium/net/tools/tld_cleanup/make_dafsa.py469
-rwxr-xr-xchromium/net/tools/tld_cleanup/make_dafsa_unittest.py757
-rw-r--r--chromium/net/tools/tld_cleanup/tld_cleanup.cc2
-rw-r--r--chromium/net/tools/tld_cleanup/tld_cleanup_util.cc4
109 files changed, 4927 insertions, 2753 deletions
diff --git a/chromium/net/tools/DEPS b/chromium/net/tools/DEPS
index 1ea12e4c3b9..4648a84aacb 100644
--- a/chromium/net/tools/DEPS
+++ b/chromium/net/tools/DEPS
@@ -1,3 +1,7 @@
+include_rules = [
+ "+base/i18n",
+]
+
skip_child_includes = [
"balsa",
"flip_server",
diff --git a/chromium/net/tools/balsa/balsa_enums.h b/chromium/net/tools/balsa/balsa_enums.h
index a59dcda687c..2a49abada92 100644
--- a/chromium/net/tools/balsa/balsa_enums.h
+++ b/chromium/net/tools/balsa/balsa_enums.h
@@ -24,6 +24,11 @@ struct BalsaFrameEnums {
};
enum ErrorCode {
+#if defined(_WIN32)
+ // On Windows, <WinError.h> defines the NO_ERROR macro as 0L, which
+ // breaks the compilation of the "NO_ERROR = 0" line.
+#undef NO_ERROR
+#endif
NO_ERROR = 0, // A sentinel value for convenience, none of the callbacks
// should ever see this error code.
// Header parsing errors
diff --git a/chromium/net/tools/balsa/balsa_frame.cc b/chromium/net/tools/balsa/balsa_frame.cc
index 96e91935597..463a678dead 100644
--- a/chromium/net/tools/balsa/balsa_frame.cc
+++ b/chromium/net/tools/balsa/balsa_frame.cc
@@ -8,7 +8,6 @@
#if __SSE2__
#include <emmintrin.h>
#endif // __SSE2__
-#include <strings.h>
#include <limits>
#include <string>
@@ -26,6 +25,13 @@
#include "net/tools/balsa/split.h"
#include "net/tools/balsa/string_piece_utils.h"
+#if defined(COMPILER_MSVC)
+#include <string.h>
+#define strncasecmp _strnicmp
+#else
+#include <strings.h>
+#endif
+
namespace net {
// Constants holding some header names for headers which can affect the way the
@@ -426,7 +432,7 @@ void BalsaFrame::ProcessFirstLine(const char* begin, const char* end) {
}
if (is_request_) {
- int version_length =
+ size_t version_length =
headers_->whitespace_4_idx_ - headers_->non_whitespace_3_idx_;
visitor_->ProcessRequestFirstLine(
begin + headers_->non_whitespace_1_idx_,
@@ -1556,9 +1562,4 @@ size_t BalsaFrame::ProcessInput(const char* input, size_t size) {
return current - input;
}
-const uint32 BalsaFrame::kValidTerm1;
-const uint32 BalsaFrame::kValidTerm1Mask;
-const uint32 BalsaFrame::kValidTerm2;
-const uint32 BalsaFrame::kValidTerm2Mask;
-
} // namespace net
diff --git a/chromium/net/tools/balsa/balsa_frame.h b/chromium/net/tools/balsa/balsa_frame.h
index 8e1240c86e9..6178d795d90 100644
--- a/chromium/net/tools/balsa/balsa_frame.h
+++ b/chromium/net/tools/balsa/balsa_frame.h
@@ -5,8 +5,6 @@
#ifndef NET_TOOLS_BALSA_BALSA_FRAME_H_
#define NET_TOOLS_BALSA_BALSA_FRAME_H_
-#include <strings.h>
-
#include <utility>
#include <vector>
diff --git a/chromium/net/tools/balsa/balsa_headers.cc b/chromium/net/tools/balsa/balsa_headers.cc
index 27bfd24a514..a77b75b89e5 100644
--- a/chromium/net/tools/balsa/balsa_headers.cc
+++ b/chromium/net/tools/balsa/balsa_headers.cc
@@ -6,11 +6,11 @@
#include <stdio.h>
#include <algorithm>
-#include <ext/hash_set>
#include <string>
#include <utility>
#include <vector>
+#include "base/containers/hash_tables.h"
#include "base/logging.h"
#include "base/port.h"
#include "base/strings/string_piece.h"
@@ -20,15 +20,28 @@
#include "net/tools/balsa/simple_buffer.h"
#include "third_party/tcmalloc/chromium/src/base/googleinit.h"
+#if defined(COMPILER_MSVC)
+#include <string.h>
+#define snprintf _snprintf
+#define strncasecmp _strnicmp
+#else
+#include <strings.h>
+#endif
+
namespace {
const char kContentLength[] = "Content-Length";
const char kTransferEncoding[] = "Transfer-Encoding";
const char kSpaceChar = ' ';
-__gnu_cxx::hash_set<base::StringPiece,
- net::StringPieceCaseHash,
- net::StringPieceCaseEqual> g_multivalued_headers;
+#if defined(COMPILER_MSVC)
+base::hash_set<base::StringPiece,
+ net::StringPieceCaseCompare> g_multivalued_headers;
+#else
+base::hash_set<base::StringPiece,
+ net::StringPieceCaseHash,
+ net::StringPieceCaseEqual> g_multivalued_headers;
+#endif
void InitMultivaluedHeaders() {
g_multivalued_headers.insert("accept");
@@ -66,8 +79,6 @@ const int kFastToBufferSize = 32; // I think 22 is adequate, but anyway..
namespace net {
-const size_t BalsaBuffer::kDefaultBlocksize;
-
BalsaHeaders::iterator_base::iterator_base() : headers_(NULL), idx_(0) { }
BalsaHeaders::iterator_base::iterator_base(const iterator_base& it)
@@ -542,7 +553,7 @@ const base::StringPiece BalsaHeaders::GetHeader(
const HeaderLines::const_iterator begin = header_lines_.begin();
HeaderLines::const_iterator i = GetConstHeaderLinesIterator(key, begin);
if (i == end) {
- return base::StringPiece(NULL, 0);
+ return base::StringPiece();
}
return GetValueFromHeaderLineDescription(*i);
}
diff --git a/chromium/net/tools/balsa/balsa_headers.h b/chromium/net/tools/balsa/balsa_headers.h
index 47cf388b8ab..840aae5e72e 100644
--- a/chromium/net/tools/balsa/balsa_headers.h
+++ b/chromium/net/tools/balsa/balsa_headers.h
@@ -938,7 +938,7 @@ class BalsaHeaders {
return transfer_encoding_is_chunked_;
}
- static bool ResponseCodeImpliesNoBody(int code) {
+ static bool ResponseCodeImpliesNoBody(size_t code) {
// From HTTP spec section 6.1.1 all 1xx responses must not have a body,
// as well as 204 No Content and 304 Not Modified.
return ((code >= 100) && (code <= 199)) || (code == 204) || (code == 304);
diff --git a/chromium/net/tools/balsa/string_piece_utils.h b/chromium/net/tools/balsa/string_piece_utils.h
index eb0eaf365c8..12fc69be85f 100644
--- a/chromium/net/tools/balsa/string_piece_utils.h
+++ b/chromium/net/tools/balsa/string_piece_utils.h
@@ -12,6 +12,34 @@
namespace net {
+#if defined(COMPILER_MSVC)
+struct StringPieceCaseCompare {
+ static const size_t bucket_size = 4;
+
+ size_t operator()(const base::StringPiece& sp) const {
+ // based on __stl_string_hash in http://www.sgi.com/tech/stl/string
+ size_t hash_val = 0;
+ for (base::StringPiece::const_iterator it = sp.begin();
+ it != sp.end(); ++it) {
+ hash_val = 5 * hash_val + tolower(*it);
+ }
+ return hash_val;
+ }
+
+ bool operator()(const base::StringPiece& sp1,
+ const base::StringPiece& sp2) const {
+ size_t len1 = sp1.length();
+ size_t len2 = sp2.length();
+ bool sp1_shorter = len1 < len2;
+ size_t len = sp1_shorter ? len1 : len2;
+ int rv = _memicmp(sp1.data(), sp2.data(), len);
+ if (rv == 0) {
+ return sp1_shorter;
+ }
+ return rv < 0;
+ }
+};
+#else // COMPILER_MSVC
struct StringPieceCaseHash {
size_t operator()(const base::StringPiece& sp) const {
// based on __stl_string_hash in http://www.sgi.com/tech/stl/string
@@ -23,6 +51,7 @@ struct StringPieceCaseHash {
return hash_val;
}
};
+#endif // COMPILER_MSVC
struct StringPieceUtils {
static bool EqualIgnoreCase(const base::StringPiece& piece1,
diff --git a/chromium/net/tools/crash_cache/crash_cache.cc b/chromium/net/tools/crash_cache/crash_cache.cc
index 32934a6a870..aeeafbe56bf 100644
--- a/chromium/net/tools/crash_cache/crash_cache.cc
+++ b/chromium/net/tools/crash_cache/crash_cache.cc
@@ -25,10 +25,10 @@
#include "net/base/net_errors.h"
#include "net/base/net_export.h"
#include "net/base/test_completion_callback.h"
-#include "net/disk_cache/backend_impl.h"
+#include "net/disk_cache/blockfile/backend_impl.h"
+#include "net/disk_cache/blockfile/rankings.h"
#include "net/disk_cache/disk_cache.h"
#include "net/disk_cache/disk_cache_test_util.h"
-#include "net/disk_cache/rankings.h"
using base::Time;
@@ -47,7 +47,7 @@ int RunSlave(RankCrashes action) {
base::FilePath exe;
PathService::Get(base::FILE_EXE, &exe);
- CommandLine cmdline(exe);
+ base::CommandLine cmdline(exe);
cmdline.AppendArg(base::IntToString(action));
base::ProcessHandle handle;
diff --git a/chromium/net/tools/crl_set_dump/crl_set_dump.cc b/chromium/net/tools/crl_set_dump/crl_set_dump.cc
index 6c3bb54bab5..ce6f5e5570d 100644
--- a/chromium/net/tools/crl_set_dump/crl_set_dump.cc
+++ b/chromium/net/tools/crl_set_dump/crl_set_dump.cc
@@ -62,8 +62,7 @@ int main(int argc, char** argv) {
if (!output_filename.empty()) {
const std::string out = final_crl_set->Serialize();
- if (file_util::WriteFile(output_filename, out.data(),
- out.size()) == -1) {
+ if (base::WriteFile(output_filename, out.data(), out.size()) == -1) {
fprintf(stderr, "Failed to write resulting CRL set\n");
return 1;
}
diff --git a/chromium/net/tools/disk_cache_memory_test/disk_cache_memory_test.cc b/chromium/net/tools/disk_cache_memory_test/disk_cache_memory_test.cc
index aafd2caf216..f129ef22984 100644
--- a/chromium/net/tools/disk_cache_memory_test/disk_cache_memory_test.cc
+++ b/chromium/net/tools/disk_cache_memory_test/disk_cache_memory_test.cc
@@ -267,8 +267,9 @@ bool ParseAndStoreSpec(const std::string& spec_str,
bool Main(int argc, char** argv) {
base::AtExitManager at_exit_manager;
base::MessageLoopForIO message_loop;
- CommandLine::Init(argc, argv);
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ base::CommandLine::Init(argc, argv);
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
if (command_line.HasSwitch("help")) {
PrintUsage(&std::cout);
return true;
diff --git a/chromium/net/tools/dns_fuzz_stub/dns_fuzz_stub.cc b/chromium/net/tools/dns_fuzz_stub/dns_fuzz_stub.cc
index f9caa79df62..d77abeee881 100644
--- a/chromium/net/tools/dns_fuzz_stub/dns_fuzz_stub.cc
+++ b/chromium/net/tools/dns_fuzz_stub/dns_fuzz_stub.cc
@@ -58,7 +58,7 @@ bool ReadTestCase(const char* filename,
return false;
}
- scoped_ptr<Value> value(base::JSONReader::Read(json));
+ scoped_ptr<base::Value> value(base::JSONReader::Read(json));
if (!value.get()) {
LOG(ERROR) << filename << ": couldn't parse JSON.";
return false;
diff --git a/chromium/net/tools/dump_cache/cache_dumper.cc b/chromium/net/tools/dump_cache/cache_dumper.cc
index 7d29a5c1785..28981644282 100644
--- a/chromium/net/tools/dump_cache/cache_dumper.cc
+++ b/chromium/net/tools/dump_cache/cache_dumper.cc
@@ -8,7 +8,7 @@
#include "base/strings/utf_string_conversions.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
-#include "net/disk_cache/entry_impl.h"
+#include "net/disk_cache/blockfile/entry_impl.h"
#include "net/http/http_cache.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
diff --git a/chromium/net/tools/dump_cache/cache_dumper.h b/chromium/net/tools/dump_cache/cache_dumper.h
index 4bdf4a1bd2f..9c5837ce566 100644
--- a/chromium/net/tools/dump_cache/cache_dumper.h
+++ b/chromium/net/tools/dump_cache/cache_dumper.h
@@ -8,7 +8,7 @@
#include <string>
#include "base/files/file_path.h"
-#include "net/disk_cache/backend_impl.h"
+#include "net/disk_cache/blockfile/backend_impl.h"
#ifdef WIN32
// Dumping the cache often creates very large filenames, which are tricky
diff --git a/chromium/net/tools/dump_cache/dump_cache.cc b/chromium/net/tools/dump_cache/dump_cache.cc
index d4ccc294448..b3970e6053f 100644
--- a/chromium/net/tools/dump_cache/dump_cache.cc
+++ b/chromium/net/tools/dump_cache/dump_cache.cc
@@ -13,7 +13,7 @@
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
-#include "net/disk_cache/disk_format.h"
+#include "net/disk_cache/blockfile/disk_format.h"
#include "net/tools/dump_cache/dump_files.h"
#include "net/tools/dump_cache/simple_cache_dumper.h"
@@ -96,7 +96,7 @@ int LaunchSlave(CommandLine command_line,
if (!base::LaunchProcess(command_line, base::LaunchOptions(), NULL)) {
printf("Unable to launch the needed version of this tool: %ls\n",
command_line.GetProgram().value().c_str());
- printf(kUpgradeHelp);
+ printf("%s", kUpgradeHelp);
return TOOL_NOT_FOUND;
}
return ALL_GOOD;
@@ -110,9 +110,10 @@ int main(int argc, const char* argv[]) {
// Setup an AtExitManager so Singleton objects will be destroyed.
base::AtExitManager at_exit_manager;
- CommandLine::Init(argc, argv);
+ base::CommandLine::Init(argc, argv);
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
base::FilePath input_path = command_line.GetSwitchValuePath(kInputPath);
if (input_path.empty())
return Help();
diff --git a/chromium/net/tools/dump_cache/dump_files.cc b/chromium/net/tools/dump_cache/dump_files.cc
index 7f4fb58343d..796f205e818 100644
--- a/chromium/net/tools/dump_cache/dump_files.cc
+++ b/chromium/net/tools/dump_cache/dump_files.cc
@@ -14,16 +14,16 @@
#include <string>
#include "base/file_util.h"
+#include "base/files/file.h"
#include "base/files/file_enumerator.h"
#include "base/format_macros.h"
#include "base/message_loop/message_loop.h"
-#include "net/base/file_stream.h"
-#include "net/disk_cache/block_files.h"
-#include "net/disk_cache/disk_format.h"
-#include "net/disk_cache/mapped_file.h"
-#include "net/disk_cache/stats.h"
-#include "net/disk_cache/storage_block-inl.h"
-#include "net/disk_cache/storage_block.h"
+#include "net/disk_cache/blockfile/block_files.h"
+#include "net/disk_cache/blockfile/disk_format.h"
+#include "net/disk_cache/blockfile/mapped_file.h"
+#include "net/disk_cache/blockfile/stats.h"
+#include "net/disk_cache/blockfile/storage_block-inl.h"
+#include "net/disk_cache/blockfile/storage_block.h"
namespace {
@@ -31,14 +31,13 @@ const base::FilePath::CharType kIndexName[] = FILE_PATH_LITERAL("index");
// Reads the |header_size| bytes from the beginning of file |name|.
bool ReadHeader(const base::FilePath& name, char* header, int header_size) {
- net::FileStream file(NULL);
- file.OpenSync(name, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ);
- if (!file.IsOpen()) {
+ base::File file(name, base::File::FLAG_OPEN | base::File::FLAG_READ);
+ if (!file.IsValid()) {
printf("Unable to open file %s\n", name.MaybeAsASCII().c_str());
return false;
}
- int read = file.ReadSync(header, header_size);
+ int read = file.Read(0, header, header_size);
if (read != header_size) {
printf("Unable to read file %s\n", name.MaybeAsASCII().c_str());
return false;
@@ -57,7 +56,7 @@ int GetMajorVersionFromFile(const base::FilePath& name) {
// Dumps the contents of the Stats record.
void DumpStats(const base::FilePath& path, disk_cache::CacheAddr addr) {
// We need a message loop, although we really don't run any task.
- base::MessageLoop loop(base::MessageLoop::TYPE_IO);
+ base::MessageLoopForIO loop;
disk_cache::BlockFiles block_files(path);
if (!block_files.Init(false)) {
@@ -355,7 +354,7 @@ int DumpContents(const base::FilePath& input_path) {
DumpHeaders(input_path);
// We need a message loop, although we really don't run any task.
- base::MessageLoop loop(base::MessageLoop::TYPE_IO);
+ base::MessageLoopForIO loop;
CacheDumper dumper(input_path);
if (!dumper.Init())
return -1;
diff --git a/chromium/net/tools/dump_cache/upgrade_win.cc b/chromium/net/tools/dump_cache/upgrade_win.cc
index 5135592429b..dfb9e5c32fc 100644
--- a/chromium/net/tools/dump_cache/upgrade_win.cc
+++ b/chromium/net/tools/dump_cache/upgrade_win.cc
@@ -17,8 +17,8 @@
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
-#include "net/disk_cache/backend_impl.h"
-#include "net/disk_cache/entry_impl.h"
+#include "net/disk_cache/blockfile/backend_impl.h"
+#include "net/disk_cache/blockfile/entry_impl.h"
#include "net/http/http_cache.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
@@ -893,7 +893,7 @@ HANDLE CreateServer(base::string16* pipe_number) {
// This is the controller process for an upgrade operation.
int UpgradeCache(const base::FilePath& output_path, HANDLE pipe) {
- base::MessageLoop loop(base::MessageLoop::TYPE_IO);
+ base::MessageLoopForIO loop;
MasterSM master(output_path, pipe);
if (!master.DoInit()) {
@@ -908,7 +908,7 @@ int UpgradeCache(const base::FilePath& output_path, HANDLE pipe) {
// This process will only execute commands from the controller.
int RunSlave(const base::FilePath& input_path,
const base::string16& pipe_number) {
- base::MessageLoop loop(base::MessageLoop::TYPE_IO);
+ base::MessageLoopForIO loop;
base::win::ScopedHandle pipe(OpenServer(pipe_number));
if (!pipe.IsValid()) {
diff --git a/chromium/net/tools/fetch/fetch_client.cc b/chromium/net/tools/fetch/fetch_client.cc
deleted file mode 100644
index 12fae24399a..00000000000
--- a/chromium/net/tools/fetch/fetch_client.cc
+++ /dev/null
@@ -1,231 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "build/build_config.h"
-
-#include "base/at_exit.h"
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/command_line.h"
-#include "base/lazy_instance.h"
-#include "base/message_loop/message_loop.h"
-#include "base/metrics/stats_counters.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "net/base/completion_callback.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/base/request_priority.h"
-#include "net/cert/cert_verifier.h"
-#include "net/dns/host_resolver.h"
-#include "net/http/http_auth_handler_factory.h"
-#include "net/http/http_cache.h"
-#include "net/http/http_network_layer.h"
-#include "net/http/http_network_session.h"
-#include "net/http/http_request_info.h"
-#include "net/http/http_server_properties_impl.h"
-#include "net/http/http_stream_factory.h"
-#include "net/http/http_transaction.h"
-#include "net/http/transport_security_state.h"
-#include "net/proxy/proxy_service.h"
-#include "net/ssl/ssl_config_service_defaults.h"
-
-void usage(const char* program_name) {
- printf("usage: %s --url=<url> [--n=<clients>] [--stats] [--use_cache]\n",
- program_name);
- exit(1);
-}
-
-// Test Driver
-class Driver {
- public:
- Driver()
- : clients_(0) {}
-
- void ClientStarted() { clients_++; }
- void ClientStopped() {
- if (!--clients_) {
- base::MessageLoop::current()->Quit();
- }
- }
-
- private:
- int clients_;
-};
-
-static base::LazyInstance<Driver> g_driver = LAZY_INSTANCE_INITIALIZER;
-
-// A network client
-class Client {
- public:
- Client(net::HttpTransactionFactory* factory, const std::string& url) :
- url_(url),
- buffer_(new net::IOBuffer(kBufferSize)) {
- int rv = factory->CreateTransaction(
- net::DEFAULT_PRIORITY, &transaction_, NULL);
- DCHECK_EQ(net::OK, rv);
- buffer_->AddRef();
- g_driver.Get().ClientStarted();
- request_info_.url = url_;
- request_info_.method = "GET";
- int state = transaction_->Start(
- &request_info_,
- base::Bind(&Client::OnConnectComplete, base::Unretained(this)),
- net::BoundNetLog());
- DCHECK(state == net::ERR_IO_PENDING);
- };
-
- private:
- void OnConnectComplete(int result) {
- // Do work here.
- int state = transaction_->Read(
- buffer_.get(), kBufferSize,
- base::Bind(&Client::OnReadComplete, base::Unretained(this)));
- if (state == net::ERR_IO_PENDING)
- return; // IO has started.
- if (state < 0)
- return; // ERROR!
- OnReadComplete(state);
- }
-
- void OnReadComplete(int result) {
- if (result == 0) {
- OnRequestComplete(result);
- return;
- }
-
- // Deal with received data here.
- base::StatsCounter bytes_read("FetchClient.bytes_read");
- bytes_read.Add(result);
-
- // Issue a read for more data.
- int state = transaction_->Read(
- buffer_.get(), kBufferSize,
- base::Bind(&Client::OnReadComplete, base::Unretained(this)));
- if (state == net::ERR_IO_PENDING)
- return; // IO has started.
- if (state < 0)
- return; // ERROR!
- OnReadComplete(state);
- }
-
- void OnRequestComplete(int result) {
- base::StatsCounter requests("FetchClient.requests");
- requests.Increment();
- g_driver.Get().ClientStopped();
- printf(".");
- }
-
- static const int kBufferSize = (16 * 1024);
- GURL url_;
- net::HttpRequestInfo request_info_;
- scoped_ptr<net::HttpTransaction> transaction_;
- scoped_refptr<net::IOBuffer> buffer_;
-};
-
-int main(int argc, char** argv) {
- base::AtExitManager exit;
- base::StatsTable table("fetchclient", 50, 1000);
- table.set_current(&table);
-
- CommandLine::Init(argc, argv);
- const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
- std::string url = parsed_command_line.GetSwitchValueASCII("url");
- if (!url.length())
- usage(argv[0]);
- int client_limit = 1;
- if (parsed_command_line.HasSwitch("n")) {
- base::StringToInt(parsed_command_line.GetSwitchValueASCII("n"),
- &client_limit);
- }
- bool use_cache = parsed_command_line.HasSwitch("use-cache");
-
- // Do work here.
- base::MessageLoop loop(base::MessageLoop::TYPE_IO);
-
- net::HttpStreamFactory::EnableNpnHttp2Draft04();
-
- scoped_ptr<net::HostResolver> host_resolver(
- net::HostResolver::CreateDefaultResolver(NULL));
- scoped_ptr<net::CertVerifier> cert_verifier(
- net::CertVerifier::CreateDefault());
- scoped_ptr<net::TransportSecurityState> transport_security_state(
- new net::TransportSecurityState);
- scoped_ptr<net::ProxyService> proxy_service(
- net::ProxyService::CreateDirect());
- scoped_refptr<net::SSLConfigService> ssl_config_service(
- new net::SSLConfigServiceDefaults);
- net::HttpTransactionFactory* factory = NULL;
- scoped_ptr<net::HttpAuthHandlerFactory> http_auth_handler_factory(
- net::HttpAuthHandlerFactory::CreateDefault(host_resolver.get()));
- net::HttpServerPropertiesImpl http_server_properties;
-
- net::HttpNetworkSession::Params session_params;
- session_params.host_resolver = host_resolver.get();
- session_params.cert_verifier = cert_verifier.get();
- session_params.transport_security_state = transport_security_state.get();
- session_params.proxy_service = proxy_service.get();
- session_params.http_auth_handler_factory = http_auth_handler_factory.get();
- session_params.http_server_properties = http_server_properties.GetWeakPtr();
- session_params.ssl_config_service = ssl_config_service.get();
-
- scoped_refptr<net::HttpNetworkSession> network_session(
- new net::HttpNetworkSession(session_params));
- if (use_cache) {
- factory = new net::HttpCache(network_session.get(),
- net::HttpCache::DefaultBackend::InMemory(0));
- } else {
- factory = new net::HttpNetworkLayer(network_session.get());
- }
-
- {
- base::StatsCounterTimer driver_time("FetchClient.total_time");
- base::StatsScope<base::StatsCounterTimer> scope(driver_time);
-
- Client** clients = new Client*[client_limit];
- for (int i = 0; i < client_limit; i++)
- clients[i] = new Client(factory, url);
-
- base::MessageLoop::current()->Run();
- }
-
- // Print Statistics here.
- int num_clients = table.GetCounterValue("c:FetchClient.requests");
- int test_time = table.GetCounterValue("t:FetchClient.total_time");
- int bytes_read = table.GetCounterValue("c:FetchClient.bytes_read");
-
- printf("\n");
- printf("Clients : %d\n", num_clients);
- printf("Time : %dms\n", test_time);
- printf("Bytes Read : %d\n", bytes_read);
- if (test_time > 0) {
- const char *units = "bps";
- double bps = static_cast<float>(bytes_read * 8) /
- (static_cast<float>(test_time) / 1000.0);
-
- if (bps > (1024*1024)) {
- bps /= (1024*1024);
- units = "Mbps";
- } else if (bps > 1024) {
- bps /= 1024;
- units = "Kbps";
- }
- printf("Bandwidth : %.2f%s\n", bps, units);
- }
-
- if (parsed_command_line.HasSwitch("stats")) {
- // Dump the stats table.
- printf("<stats>\n");
- int counter_max = table.GetMaxCounters();
- for (int index = 0; index < counter_max; index++) {
- std::string name(table.GetRowName(index));
- if (name.length() > 0) {
- int value = table.GetRowValue(index);
- printf("%s:\t%d\n", name.c_str(), value);
- }
- }
- printf("</stats>\n");
- }
- return 0;
-}
diff --git a/chromium/net/tools/fetch/fetch_server.cc b/chromium/net/tools/fetch/fetch_server.cc
deleted file mode 100644
index a2ffc5b5708..00000000000
--- a/chromium/net/tools/fetch/fetch_server.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/at_exit.h"
-#include "base/command_line.h"
-#include "base/memory/singleton.h"
-#include "base/message_loop/message_loop.h"
-#include "base/metrics/stats_counters.h"
-#include "net/base/completion_callback.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/base/winsock_init.h"
-#include "net/http/http_network_layer.h"
-#include "net/http/http_request_info.h"
-#include "net/http/http_transaction.h"
-#include "net/proxy/proxy_service.h"
-#include "net/tools/fetch/http_server.h"
-
-void usage(const char* program_name) {
- printf("usage: %s\n", program_name);
- exit(-1);
-}
-
-int main(int argc, char**argv) {
- base::AtExitManager exit;
- base::StatsTable table("fetchserver", 50, 1000);
- table.set_current(&table);
-
-#if defined(OS_WIN)
- net::EnsureWinsockInit();
-#endif // defined(OS_WIN)
-
- CommandLine::Init(0, NULL);
- const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
-
- // Do work here.
- base::MessageLoop loop;
- HttpServer server(std::string(),
- 80); // TODO(mbelshe): make port configurable
- base::MessageLoop::current()->Run();
-
- if (parsed_command_line.HasSwitch("stats")) {
- // Dump the stats table.
- printf("<stats>\n");
- int counter_max = table.GetMaxCounters();
- for (int index=0; index < counter_max; index++) {
- std::string name(table.GetRowName(index));
- if (name.length() > 0) {
- int value = table.GetRowValue(index);
- printf("%s:\t%d\n", name.c_str(), value);
- }
- }
- printf("</stats>\n");
- }
-
-}
diff --git a/chromium/net/tools/fetch/http_listen_socket.cc b/chromium/net/tools/fetch/http_listen_socket.cc
deleted file mode 100644
index 410a0ba55e5..00000000000
--- a/chromium/net/tools/fetch/http_listen_socket.cc
+++ /dev/null
@@ -1,249 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/tools/fetch/http_listen_socket.h"
-
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/stl_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "net/tools/fetch/http_server_request_info.h"
-#include "net/tools/fetch/http_server_response_info.h"
-
-HttpListenSocket::HttpListenSocket(net::SocketDescriptor s,
- HttpListenSocket::Delegate* delegate)
- : net::TCPListenSocket(s, this),
- delegate_(delegate) {
-}
-
-HttpListenSocket::~HttpListenSocket() {
- STLDeleteElements(&connections_);
-}
-
-void HttpListenSocket::Accept() {
- net::SocketDescriptor conn = net::TCPListenSocket::AcceptSocket();
- DCHECK_NE(conn, net::kInvalidSocket);
- if (conn == net::kInvalidSocket) {
- // TODO
- } else {
- scoped_ptr<StreamListenSocket> sock(
- new HttpListenSocket(conn, delegate_));
- DidAccept(this, sock.Pass());
- }
-}
-
-// static
-scoped_ptr<HttpListenSocket> HttpListenSocket::CreateAndListen(
- const std::string& ip,
- int port,
- HttpListenSocket::Delegate* delegate) {
- net::SocketDescriptor s = net::TCPListenSocket::CreateAndBind(ip, port);
- if (s == net::kInvalidSocket) {
- // TODO (ibrar): error handling.
- } else {
- scoped_ptr<HttpListenSocket> serv(new HttpListenSocket(s, delegate));
- serv->Listen();
- return serv.Pass();
- }
- return scoped_ptr<HttpListenSocket>();
-}
-
-//
-// HTTP Request Parser
-// This HTTP request parser uses a simple state machine to quickly parse
-// through the headers. The parser is not 100% complete, as it is designed
-// for use in this simple test driver.
-//
-// Known issues:
-// - does not handle whitespace on first HTTP line correctly. Expects
-// a single space between the method/url and url/protocol.
-
-// Input character types.
-enum header_parse_inputs {
- INPUT_SPACE,
- INPUT_CR,
- INPUT_LF,
- INPUT_COLON,
- INPUT_DEFAULT,
- MAX_INPUTS
-};
-
-// Parser states.
-enum header_parse_states {
- ST_METHOD, // Receiving the method.
- ST_URL, // Receiving the URL.
- ST_PROTO, // Receiving the protocol.
- ST_HEADER, // Starting a Request Header.
- ST_NAME, // Receiving a request header name.
- ST_SEPARATOR, // Receiving the separator between header name and value.
- ST_VALUE, // Receiving a request header value.
- ST_DONE, // Parsing is complete and successful.
- ST_ERR, // Parsing encountered invalid syntax.
- MAX_STATES
-};
-
-// State transition table.
-int parser_state[MAX_STATES][MAX_INPUTS] = {
-/* METHOD */ { ST_URL, ST_ERR, ST_ERR, ST_ERR, ST_METHOD },
-/* URL */ { ST_PROTO, ST_ERR, ST_ERR, ST_URL, ST_URL },
-/* PROTOCOL */ { ST_ERR, ST_HEADER, ST_NAME, ST_ERR, ST_PROTO },
-/* HEADER */ { ST_ERR, ST_ERR, ST_NAME, ST_ERR, ST_ERR },
-/* NAME */ { ST_SEPARATOR, ST_DONE, ST_ERR, ST_SEPARATOR, ST_NAME },
-/* SEPARATOR */ { ST_SEPARATOR, ST_ERR, ST_ERR, ST_SEPARATOR, ST_VALUE },
-/* VALUE */ { ST_VALUE, ST_HEADER, ST_NAME, ST_VALUE, ST_VALUE },
-/* DONE */ { ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE },
-/* ERR */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR }
-};
-
-// Convert an input character to the parser's input token.
-int charToInput(char ch) {
- switch(ch) {
- case ' ':
- return INPUT_SPACE;
- case '\r':
- return INPUT_CR;
- case '\n':
- return INPUT_LF;
- case ':':
- return INPUT_COLON;
- }
- return INPUT_DEFAULT;
-}
-
-HttpServerRequestInfo* HttpListenSocket::ParseHeaders() {
- int pos = 0;
- int data_len = recv_data_.length();
- int state = ST_METHOD;
- HttpServerRequestInfo* info = new HttpServerRequestInfo();
- std::string buffer;
- std::string header_name;
- std::string header_value;
- while (pos < data_len) {
- char ch = recv_data_[pos++];
- int input = charToInput(ch);
- int next_state = parser_state[state][input];
-
- bool transition = (next_state != state);
- if (transition) {
- // Do any actions based on state transitions.
- switch (state) {
- case ST_METHOD:
- info->method = buffer;
- buffer.clear();
- break;
- case ST_URL:
- info->url = GURL(buffer);
- buffer.clear();
- break;
- case ST_PROTO:
- // TODO(mbelshe): Deal better with parsing protocol.
- DCHECK(buffer == "HTTP/1.1");
- buffer.clear();
- break;
- case ST_NAME:
- header_name = buffer;
- buffer.clear();
- break;
- case ST_VALUE:
- header_value = buffer;
- // TODO(mbelshe): Deal better with duplicate headers.
- DCHECK(info->headers.find(header_name) == info->headers.end());
- info->headers[header_name] = header_value;
- buffer.clear();
- break;
- }
- state = next_state;
- } else {
- // Do any actions based on current state.
- switch (state) {
- case ST_METHOD:
- case ST_URL:
- case ST_PROTO:
- case ST_VALUE:
- case ST_NAME:
- buffer.append(&ch, 1);
- break;
- case ST_DONE:
- recv_data_ = recv_data_.substr(pos);
- return info;
- case ST_ERR:
- delete info;
- return NULL;
- }
- }
- }
- // No more characters, but we haven't finished parsing yet.
- delete info;
- return NULL;
-}
-
-void HttpListenSocket::DidAccept(
- net::StreamListenSocket* server,
- scoped_ptr<net::StreamListenSocket> connection) {
- connections_.insert(connection.release());
-}
-
-void HttpListenSocket::DidRead(net::StreamListenSocket* connection,
- const char* data,
- int len) {
- recv_data_.append(data, len);
- while (recv_data_.length()) {
- HttpServerRequestInfo* request = ParseHeaders();
- if (!request)
- break;
- delegate_->OnRequest(this, request);
- delete request;
- }
-}
-
-void HttpListenSocket::DidClose(net::StreamListenSocket* sock) {
- size_t count = connections_.erase(sock);
- DCHECK_EQ(1u, count);
- delete sock;
-}
-
-// Convert the numeric status code to a string.
-// e.g. 200 -> "200 OK".
-std::string ServerStatus(int code) {
- switch(code) {
- case 200:
- return std::string("200 OK");
- // TODO(mbelshe): handle other codes.
- }
- NOTREACHED();
- return std::string();
-}
-
-void HttpListenSocket::Respond(HttpServerResponseInfo* info,
- std::string& data) {
- std::string response;
-
- // Status line.
- response = info->protocol + " ";
- response += ServerStatus(info->status);
- response += "\r\n";
-
- // Standard headers.
- if (info->content_type.length())
- response += "Content-type: " + info->content_type + "\r\n";
-
- if (info->content_length > 0)
- response += "Content-length: " + base::IntToString(info->content_length) +
- "\r\n";
-
- if (info->connection_close)
- response += "Connection: close\r\n";
-
- // TODO(mbelshe): support additional headers.
-
- // End of headers.
- response += "\r\n";
-
- // Add data.
- response += data;
-
- // Write it all out.
- this->Send(response, false);
-}
diff --git a/chromium/net/tools/fetch/http_listen_socket.h b/chromium/net/tools/fetch/http_listen_socket.h
deleted file mode 100644
index e0a58c03e2c..00000000000
--- a/chromium/net/tools/fetch/http_listen_socket.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_BASE_TOOLS_HTTP_LISTEN_SOCKET_H_
-#define NET_BASE_TOOLS_HTTP_LISTEN_SOCKET_H_
-
-#include <set>
-
-#include "base/message_loop/message_loop.h"
-#include "net/socket/stream_listen_socket.h"
-#include "net/socket/tcp_listen_socket.h"
-
-class HttpServerRequestInfo;
-class HttpServerResponseInfo;
-
-// Implements a simple HTTP listen socket on top of the raw socket interface.
-class HttpListenSocket : public net::TCPListenSocket,
- public net::StreamListenSocket::Delegate {
- public:
- class Delegate {
- public:
- virtual void OnRequest(HttpListenSocket* connection,
- HttpServerRequestInfo* info) = 0;
-
- protected:
- virtual ~Delegate() {}
- };
-
- virtual ~HttpListenSocket();
-
- static scoped_ptr<HttpListenSocket> CreateAndListen(
- const std::string& ip, int port, HttpListenSocket::Delegate* delegate);
-
- // Send a server response.
- // TODO(mbelshe): make this capable of non-ascii data.
- void Respond(HttpServerResponseInfo* info, std::string& data);
-
- // StreamListenSocket::Delegate.
- virtual void DidAccept(
- net::StreamListenSocket* server,
- scoped_ptr<net::StreamListenSocket> connection) OVERRIDE;
- virtual void DidRead(net::StreamListenSocket* connection,
- const char* data, int len) OVERRIDE;
- virtual void DidClose(net::StreamListenSocket* sock) OVERRIDE;
-
- protected:
- // Overrides TCPListenSocket::Accept().
- virtual void Accept() OVERRIDE;
-
- private:
- static const int kReadBufSize = 16 * 1024;
-
- // Must run in the IO thread.
- HttpListenSocket(net::SocketDescriptor s, HttpListenSocket::Delegate* del);
-
- // Expects the raw data to be stored in recv_data_. If parsing is successful,
- // will remove the data parsed from recv_data_, leaving only the unused
- // recv data.
- HttpServerRequestInfo* ParseHeaders();
-
- HttpListenSocket::Delegate* const delegate_;
- std::string recv_data_;
-
- std::set<StreamListenSocket*> connections_;
-
- DISALLOW_COPY_AND_ASSIGN(HttpListenSocket);
-};
-
-#endif // NET_BASE_TOOLS_HTTP_LISTEN_SOCKET_H_
diff --git a/chromium/net/tools/fetch/http_server.cc b/chromium/net/tools/fetch/http_server.cc
deleted file mode 100644
index 71afb67bc30..00000000000
--- a/chromium/net/tools/fetch/http_server.cc
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/tools/fetch/http_server.h"
-
-HttpServer::HttpServer(std::string ip, int port)
- : session_(new HttpSession(ip, port)) {
-}
-
-HttpServer::~HttpServer() {
-}
diff --git a/chromium/net/tools/fetch/http_server.h b/chromium/net/tools/fetch/http_server.h
deleted file mode 100644
index 691413078e5..00000000000
--- a/chromium/net/tools/fetch/http_server.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_BASE_TOOLS_HTTP_SERVER_H_
-#define NET_BASE_TOOLS_HTTP_SERVER_H_
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "net/tools/fetch/http_session.h"
-
-// Implements a simple, single-threaded HttpServer.
-// Right now, this class implements no functionality above and beyond
-// the HttpSession.
-class HttpServer {
-public:
- HttpServer(std::string ip, int port);
- ~HttpServer();
-
-private:
- scoped_ptr<HttpSession> session_;
- DISALLOW_COPY_AND_ASSIGN(HttpServer);
-};
-
-#endif // NET_BASE_TOOLS_HTTP_SERVER_H_
-
diff --git a/chromium/net/tools/fetch/http_server_request_info.cc b/chromium/net/tools/fetch/http_server_request_info.cc
deleted file mode 100644
index 52b6860e0a4..00000000000
--- a/chromium/net/tools/fetch/http_server_request_info.cc
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/tools/fetch/http_server_request_info.h"
-
-HttpServerRequestInfo::HttpServerRequestInfo()
- : net::HttpRequestInfo() {
-}
-
-HttpServerRequestInfo::~HttpServerRequestInfo() {}
diff --git a/chromium/net/tools/fetch/http_server_request_info.h b/chromium/net/tools/fetch/http_server_request_info.h
deleted file mode 100644
index 9b0fae18d16..00000000000
--- a/chromium/net/tools/fetch/http_server_request_info.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_BASE_TOOLS_HTTP_SERVER_REQUEST_INFO_H_
-#define NET_BASE_TOOLS_HTTP_SERVER_REQUEST_INFO_H_
-
-#include <map>
-#include <string>
-
-#include "net/http/http_request_info.h"
-
-// Meta information about an HTTP request.
-// This is geared toward servers in that it keeps a map of the headers and
-// values rather than just a list of header strings (which net::HttpRequestInfo
-// does).
-class HttpServerRequestInfo : public net::HttpRequestInfo {
- public:
- HttpServerRequestInfo();
- virtual ~HttpServerRequestInfo();
-
- // A map of the names -> values for HTTP headers.
- std::map<std::string, std::string> headers;
-};
-
-#endif // NET_BASE_TOOLS_HTTP_SERVER_REQUEST_INFO_H_
diff --git a/chromium/net/tools/fetch/http_server_response_info.cc b/chromium/net/tools/fetch/http_server_response_info.cc
deleted file mode 100644
index d9ca02a6d0d..00000000000
--- a/chromium/net/tools/fetch/http_server_response_info.cc
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/tools/fetch/http_server_response_info.h"
-
-HttpServerResponseInfo::HttpServerResponseInfo()
- : status(200), content_length(0), connection_close(false) {
-}
-
-HttpServerResponseInfo::~HttpServerResponseInfo() {}
diff --git a/chromium/net/tools/fetch/http_server_response_info.h b/chromium/net/tools/fetch/http_server_response_info.h
deleted file mode 100644
index e01f7300d97..00000000000
--- a/chromium/net/tools/fetch/http_server_response_info.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_HTTP_HTTP_RESPONSE_INFO_H_
-#define NET_HTTP_HTTP_RESPONSE_INFO_H_
-
-#include <map>
-#include <string>
-
-// Meta information about a server response.
-class HttpServerResponseInfo {
- public:
- HttpServerResponseInfo();
- ~HttpServerResponseInfo();
-
- // The response protocol.
- std::string protocol;
-
- // The status code.
- int status;
-
- // The server identifier.
- std::string server_name;
-
- // The content type.
- std::string content_type;
-
- // The content length.
- int content_length;
-
- // Should we close the connection.
- bool connection_close;
-
- // Additional response headers.
- std::map<std::string, std::string> headers;
-};
-
-#endif // NET_HTTP_HTTP_RESPONSE_INFO_H_
diff --git a/chromium/net/tools/fetch/http_session.cc b/chromium/net/tools/fetch/http_session.cc
deleted file mode 100644
index d9e991b798a..00000000000
--- a/chromium/net/tools/fetch/http_session.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/tools/fetch/http_session.h"
-#include "net/tools/fetch/http_server_response_info.h"
-
-HttpSession::HttpSession(const std::string& ip, int port)
- : socket_(HttpListenSocket::CreateAndListen(ip, port, this)) {
-}
-
-HttpSession::~HttpSession() {
-}
-
-void HttpSession::OnRequest(HttpListenSocket* connection,
- HttpServerRequestInfo* info) {
- // TODO(mbelshe): Make this function more interesting.
-
- // Generate a 10KB sequence of data.
- CR_DEFINE_STATIC_LOCAL(std::string, data, ());
- if (data.length() == 0) {
- while (data.length() < (10 * 1024))
- data += 'a' + (rand() % 26);
- }
-
- HttpServerResponseInfo response_info;
- response_info.protocol = "HTTP/1.1";
- response_info.status = 200;
- response_info.content_type = "text/plain";
- response_info.content_length = data.length();
-
- connection->Respond(&response_info, data);
-}
diff --git a/chromium/net/tools/fetch/http_session.h b/chromium/net/tools/fetch/http_session.h
deleted file mode 100644
index b0266f2a9f7..00000000000
--- a/chromium/net/tools/fetch/http_session.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_BASE_TOOLS_HTTP_SESSION_H_
-#define NET_BASE_TOOLS_HTTP_SESSION_H_
-
-#include "base/basictypes.h"
-#include "net/http/http_request_info.h"
-#include "net/tools/fetch/http_listen_socket.h"
-
-// An HttpSession encapsulates a server-side HTTP listen socket.
-class HttpSession : HttpListenSocket::Delegate {
- public:
- HttpSession(const std::string& ip, int port);
- virtual ~HttpSession();
-
- virtual void OnRequest(HttpListenSocket* connection,
- HttpServerRequestInfo* info) OVERRIDE;
-
- private:
- scoped_ptr<HttpListenSocket> socket_;
- DISALLOW_COPY_AND_ASSIGN(HttpSession);
-};
-
-#endif // NET_BASE_TOOLS_HTTP_SESSION_H_
-
diff --git a/chromium/net/tools/flip_server/flip_in_mem_edsm_server.cc b/chromium/net/tools/flip_server/flip_in_mem_edsm_server.cc
index ef1cefd6125..a8459b63c97 100644
--- a/chromium/net/tools/flip_server/flip_in_mem_edsm_server.cc
+++ b/chromium/net/tools/flip_server/flip_in_mem_edsm_server.cc
@@ -161,8 +161,8 @@ int main(int argc, char** argv) {
signal(SIGINT, SignalHandler);
signal(SIGHUP, SignalHandler);
- CommandLine::Init(argc, argv);
- CommandLine cl(argc, argv);
+ base::CommandLine::Init(argc, argv);
+ base::CommandLine cl(argc, argv);
if (cl.HasSwitch("help") || argc < 2) {
printf("%s <options>\n", argv[0]);
diff --git a/chromium/net/tools/flip_server/loadtime_measurement.h b/chromium/net/tools/flip_server/loadtime_measurement.h
index ccbb2e53234..59fcc0bfcdc 100644
--- a/chromium/net/tools/flip_server/loadtime_measurement.h
+++ b/chromium/net/tools/flip_server/loadtime_measurement.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef NET_TOOLS_FLIP_SERVER_LOADTIME_MEASUREMENT_H__
-#define NET_TOOLS_FLIP_SERVER_LOADTIME_MEASUREMENT_H__
+#ifndef NET_TOOLS_FLIP_SERVER_LOADTIME_MEASUREMENT_H_
+#define NET_TOOLS_FLIP_SERVER_LOADTIME_MEASUREMENT_H_
#include <errno.h>
#include <fcntl.h>
@@ -15,6 +15,9 @@
#include <string>
#include <vector>
+#include "base/file_util.h"
+#include "base/strings/string_split.h"
+
// Class to handle loadtime measure related urls, which all start with testing
// The in memory server has a singleton object of this class. It includes a
// html file containing javascript to go through a list of urls and upload the
@@ -26,8 +29,8 @@ class LoadtimeMeasurement {
const std::string& pageload_html_file)
: num_urls_(0), pageload_html_file_(pageload_html_file) {
std::string urls_string;
- read_file_to_string(urls_file.c_str(), &urls_string);
- split_string(urls_string, '\n', &urls_);
+ base::ReadFileToString(urls_file, &urls_string);
+ base::SplitString(urls_string, '\n', &urls_);
num_urls_ = urls_.size();
}
@@ -39,7 +42,7 @@ class LoadtimeMeasurement {
// remove "/testing/" from uri to get the action
std::string action = uri.substr(9);
if (pageload_html_file_.find(action) != std::string::npos) {
- read_file_to_string(pageload_html_file_.c_str(), &output);
+ base::ReadFileToString(pageload_html_file_, &output);
return;
}
if (action.find("get_total_iteration") == 0) {
@@ -70,13 +73,13 @@ class LoadtimeMeasurement {
}
if (action.find("record_page_load") == 0) {
std::vector<std::string> query;
- split_string(action, '?', &query);
+ base::SplitString(action, '?', &query);
std::vector<std::string> params;
- split_string(query[1], '&', &params);
+ base::SplitString(query[1], '&', &params);
std::vector<std::string> url;
std::vector<std::string> loadtime;
- split_string(params[1], '=', &url);
- split_string(params[2], '=', &loadtime);
+ base::SplitString(params[1], '=', &url);
+ base::SplitString(params[2], '=', &loadtime);
loadtimes_[url[1]] = atoi(loadtime[1].c_str());
output.append("OK");
return;
@@ -84,41 +87,10 @@ class LoadtimeMeasurement {
}
private:
- void read_file_to_string(const char* filename, std::string* output) {
- output->clear();
- int fd = open(filename, 0, "r");
- if (fd == -1)
- return;
- char buffer[4096];
- ssize_t read_status = read(fd, buffer, sizeof(buffer));
- while (read_status > 0) {
- output->append(buffer, static_cast<size_t>(read_status));
- do {
- read_status = read(fd, buffer, sizeof(buffer));
- } while (read_status <= 0 && errno == EINTR);
- }
- close(fd);
- }
-
- void split_string(const std::string& str,
- char sepa,
- std::vector<std::string>* sub_strs) {
- size_t b = 0;
- size_t e = str.find_first_of(sepa, b);
- while (e != std::string::npos && e > b) {
- sub_strs->push_back(str.substr(b, e - b));
- b = e + 1;
- e = str.find_first_of(sepa, b);
- }
- if (b < str.size()) {
- sub_strs->push_back(str.substr(b));
- }
- }
-
int num_urls_;
std::vector<std::string> urls_;
std::map<std::string, int> loadtimes_;
const std::string pageload_html_file_;
};
-#endif // NET_TOOLS_FLIP_SERVER_LOADTIME_MEASUREMENT_H__
+#endif // NET_TOOLS_FLIP_SERVER_LOADTIME_MEASUREMENT_H_
diff --git a/chromium/net/tools/flip_server/sm_connection.cc b/chromium/net/tools/flip_server/sm_connection.cc
index 158cd30ff4f..4acdea44adf 100644
--- a/chromium/net/tools/flip_server/sm_connection.cc
+++ b/chromium/net/tools/flip_server/sm_connection.cc
@@ -391,7 +391,9 @@ bool SMConnection::SetupProtocolInterfaces() {
VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
<< (sm_spdy_interface_ ? "Creating" : "Reusing")
<< " SPDY interface.";
- if (!sm_spdy_interface_)
+ if (sm_spdy_interface_)
+ sm_spdy_interface_->CreateFramer(version);
+ else
sm_spdy_interface_ = new SpdySM(
this, NULL, epoll_server_, memory_cache_, acceptor_, version);
sm_interface_ = sm_spdy_interface_;
diff --git a/chromium/net/tools/flip_server/sm_connection.h b/chromium/net/tools/flip_server/sm_connection.h
index 93ad42e7e5a..2fe3228c0a1 100644
--- a/chromium/net/tools/flip_server/sm_connection.h
+++ b/chromium/net/tools/flip_server/sm_connection.h
@@ -25,6 +25,7 @@ namespace net {
class FlipAcceptor;
class MemoryCache;
struct SSLState;
+class SpdySM;
// A frame of data to be sent.
class DataFrame {
@@ -146,7 +147,7 @@ class SMConnection : public SMConnectionInterface,
RingBuffer read_buffer_;
OutputList output_list_;
- SMInterface* sm_spdy_interface_;
+ SpdySM* sm_spdy_interface_;
SMInterface* sm_http_interface_;
SMInterface* sm_streamer_interface_;
SMInterface* sm_interface_;
diff --git a/chromium/net/tools/flip_server/spdy_interface.cc b/chromium/net/tools/flip_server/spdy_interface.cc
index 41ad43025e2..73025dd5407 100644
--- a/chromium/net/tools/flip_server/spdy_interface.cc
+++ b/chromium/net/tools/flip_server/spdy_interface.cc
@@ -51,7 +51,7 @@ SpdySM::SpdySM(SMConnection* connection,
buffered_spdy_framer_->set_visitor(this);
}
-SpdySM::~SpdySM() { delete buffered_spdy_framer_; }
+SpdySM::~SpdySM() { }
void SpdySM::InitSMConnection(SMConnectionPoolInterface* connection_pool,
SMInterface* sm_interface,
@@ -130,7 +130,6 @@ int SpdySM::SpdyHandleNewStream(SpdyStreamId stream_id,
VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: OnSyn(" << stream_id << ")";
VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: # headers: " << headers.size();
- SpdyHeaderBlock supplement;
SpdyHeaderBlock::const_iterator method = headers.end();
SpdyHeaderBlock::const_iterator host = headers.end();
SpdyHeaderBlock::const_iterator path = headers.end();
@@ -138,6 +137,8 @@ int SpdySM::SpdyHandleNewStream(SpdyStreamId stream_id,
SpdyHeaderBlock::const_iterator version = headers.end();
SpdyHeaderBlock::const_iterator url = headers.end();
+ std::string path_string, host_string, version_string;
+
if (spdy_version() == SPDY2) {
url = headers.find("url");
method = headers.find("method");
@@ -153,22 +154,23 @@ int SpdySM::SpdyHandleNewStream(SpdyStreamId stream_id,
// path contains a query string with a http:// in one of its values,
// UrlUtilities::GetUrlPath will fail and always return a / breaking
// the request. GetUrlPath assumes the absolute URL is being passed in.
- std::string path_string = UrlUtilities::GetUrlPath(url->second);
- std::string host_string = UrlUtilities::GetUrlHost(url->second);
- path = supplement.insert(std::make_pair(":path", path_string)).first;
- host = supplement.insert(std::make_pair(":host", host_string)).first;
+ path_string = UrlUtilities::GetUrlPath(url->second);
+ host_string = UrlUtilities::GetUrlHost(url->second);
+ version_string = version->second;
} else {
method = headers.find(":method");
host = headers.find(":host");
path = headers.find(":path");
scheme = headers.find(":scheme");
- version = supplement.insert(std::make_pair(":version", "HTTP/1.1")).first;
if (method == headers.end() || host == headers.end() ||
path == headers.end() || scheme == headers.end()) {
VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: A mandatory header is "
<< "missing. Not creating stream";
return 0;
}
+ host_string = host->second;
+ path_string = path->second;
+ version_string = "HTTP/1.1";
}
if (scheme->second.compare("https") == 0) {
@@ -177,16 +179,16 @@ int SpdySM::SpdyHandleNewStream(SpdyStreamId stream_id,
if (acceptor_->flip_handler_type_ == FLIP_HANDLER_SPDY_SERVER) {
VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Request: " << method->second
- << " " << path->second;
- std::string filename = EncodeURL(path->second,
- host->second,
+ << " " << path_string;
+ std::string filename = EncodeURL(path_string,
+ host_string,
method->second);
NewStream(stream_id, priority, filename);
} else {
http_data +=
- method->second + " " + path->second + " " + version->second + "\r\n";
+ method->second + " " + path_string + " " + version_string + "\r\n";
VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Request: " << method->second << " "
- << path->second << " " << version->second;
+ << path_string << " " << version_string;
http_data += "Host: " + (*is_https_scheme ?
acceptor_->https_server_ip_ :
acceptor_->http_server_ip_) + "\r\n";
@@ -241,7 +243,6 @@ void SpdySM::OnStreamFrameData(SpdyStreamId stream_id,
void SpdySM::OnSynStream(SpdyStreamId stream_id,
SpdyStreamId associated_stream_id,
SpdyPriority priority,
- uint8 credential_slot,
bool fin,
bool unidirectional,
const SpdyHeaderBlock& headers) {
@@ -296,21 +297,25 @@ void SpdySM::OnRstStream(SpdyStreamId stream_id, SpdyRstStreamStatus status) {
}
size_t SpdySM::ProcessReadInput(const char* data, size_t len) {
+ DCHECK(buffered_spdy_framer_);
return buffered_spdy_framer_->ProcessInput(data, len);
}
size_t SpdySM::ProcessWriteInput(const char* data, size_t len) { return 0; }
bool SpdySM::MessageFullyRead() const {
+ DCHECK(buffered_spdy_framer_);
return buffered_spdy_framer_->MessageFullyRead();
}
bool SpdySM::Error() const {
+ DCHECK(buffered_spdy_framer_);
return close_on_error_ || buffered_spdy_framer_->HasError();
}
const char* SpdySM::ErrorAsString() const {
DCHECK(Error());
+ DCHECK(buffered_spdy_framer_);
return SpdyFramer::ErrorCodeToString(buffered_spdy_framer_->error_code());
}
@@ -322,9 +327,7 @@ void SpdySM::ResetForNewInterface(int32 server_idx) {
void SpdySM::ResetForNewConnection() {
// seq_num is not cleared, intentionally.
- delete buffered_spdy_framer_;
- buffered_spdy_framer_ = new BufferedSpdyFramer(SPDY2, true);
- buffered_spdy_framer_->set_visitor(this);
+ buffered_spdy_framer_.reset();
valid_spdy_session_ = false;
client_output_ordering_.Reset();
next_outgoing_stream_id_ = 2;
@@ -332,6 +335,8 @@ void SpdySM::ResetForNewConnection() {
// Send a settings frame
int SpdySM::PostAcceptHook() {
+ // We should have buffered_spdy_framer_ set after reuse
+ DCHECK(buffered_spdy_framer_);
SettingsMap settings;
settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, 100);
@@ -469,8 +474,9 @@ size_t SpdySM::SendSynStreamImpl(uint32 stream_id,
}
}
+ DCHECK(buffered_spdy_framer_);
SpdyFrame* fsrcf = buffered_spdy_framer_->CreateSynStream(
- stream_id, 0, 0, 0, CONTROL_FLAG_NONE, &block);
+ stream_id, 0, 0, CONTROL_FLAG_NONE, &block);
size_t df_size = fsrcf->size();
EnqueueDataFrame(new SpdyFrameDataFrame(fsrcf));
@@ -492,6 +498,7 @@ size_t SpdySM::SendSynReplyImpl(uint32 stream_id, const BalsaHeaders& headers) {
block[":version"] = headers.response_version().as_string();
}
+ DCHECK(buffered_spdy_framer_);
SpdyFrame* fsrcf = buffered_spdy_framer_->CreateSynReply(
stream_id, CONTROL_FLAG_NONE, &block);
size_t df_size = fsrcf->size();
@@ -507,6 +514,7 @@ void SpdySM::SendDataFrameImpl(uint32 stream_id,
int64 len,
SpdyDataFlags flags,
bool compress) {
+ DCHECK(buffered_spdy_framer_);
// TODO(mbelshe): We can't compress here - before going into the
// priority queue. Compression needs to be done
// with late binding.
@@ -607,4 +615,10 @@ void SpdySM::GetOutput() {
}
}
+void SpdySM::CreateFramer(SpdyMajorVersion spdy_version) {
+ DCHECK(!buffered_spdy_framer_);
+ buffered_spdy_framer_.reset(new BufferedSpdyFramer(spdy_version, true));
+ buffered_spdy_framer_->set_visitor(this);
+}
+
} // namespace net
diff --git a/chromium/net/tools/flip_server/spdy_interface.h b/chromium/net/tools/flip_server/spdy_interface.h
index 6e5ad0b0a8f..e472cf2ac59 100644
--- a/chromium/net/tools/flip_server/spdy_interface.h
+++ b/chromium/net/tools/flip_server/spdy_interface.h
@@ -10,6 +10,7 @@
#include <vector>
#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
#include "net/spdy/buffered_spdy_framer.h"
#include "net/spdy/spdy_protocol.h"
#include "net/tools/balsa/balsa_headers.h"
@@ -45,6 +46,9 @@ class SpdySM : public BufferedSpdyFramerVisitorInterface, public SMInterface {
std::string remote_ip,
bool use_ssl) OVERRIDE;
+ // Create new SPDY framer after reusing SpdySM and negotiating new version
+ void CreateFramer(SpdyMajorVersion spdy_version);
+
private:
virtual void set_is_request() OVERRIDE {}
SMInterface* NewConnectionInterface();
@@ -66,7 +70,6 @@ class SpdySM : public BufferedSpdyFramerVisitorInterface, public SMInterface {
virtual void OnSynStream(SpdyStreamId stream_id,
SpdyStreamId associated_stream_id,
SpdyPriority priority,
- uint8 credential_slot,
bool fin,
bool unidirectional,
const SpdyHeaderBlock& headers) OVERRIDE;
@@ -108,7 +111,7 @@ class SpdySM : public BufferedSpdyFramerVisitorInterface, public SMInterface {
uint32 value) OVERRIDE {}
// Called when a PING frame has been parsed.
- virtual void OnPing(uint32 unique_id) OVERRIDE {}
+ virtual void OnPing(SpdyPingId unique_id, bool is_ack) OVERRIDE {}
// Called when a RST_STREAM frame has been parsed.
virtual void OnRstStream(SpdyStreamId stream_id,
@@ -124,7 +127,8 @@ class SpdySM : public BufferedSpdyFramerVisitorInterface, public SMInterface {
// Called when a PUSH_PROMISE frame has been parsed.
virtual void OnPushPromise(SpdyStreamId stream_id,
- SpdyStreamId promised_stream_id) OVERRIDE {}
+ SpdyStreamId promised_stream_id,
+ const SpdyHeaderBlock& headers) OVERRIDE {}
public:
virtual size_t ProcessReadInput(const char* data, size_t len) OVERRIDE;
@@ -159,7 +163,7 @@ class SpdySM : public BufferedSpdyFramerVisitorInterface, public SMInterface {
int64 len,
uint32 flags,
bool compress) OVERRIDE;
- BufferedSpdyFramer* spdy_framer() { return buffered_spdy_framer_; }
+ BufferedSpdyFramer* spdy_framer() { return buffered_spdy_framer_.get(); }
const OutputOrdering& output_ordering() const {
return client_output_ordering_;
@@ -170,6 +174,7 @@ class SpdySM : public BufferedSpdyFramerVisitorInterface, public SMInterface {
forward_ip_header_ = value;
}
SpdyMajorVersion spdy_version() const {
+ DCHECK(buffered_spdy_framer_);
return buffered_spdy_framer_->protocol_version();
}
@@ -189,7 +194,7 @@ class SpdySM : public BufferedSpdyFramerVisitorInterface, public SMInterface {
virtual void GetOutput() OVERRIDE;
private:
- BufferedSpdyFramer* buffered_spdy_framer_;
+ scoped_ptr<BufferedSpdyFramer> buffered_spdy_framer_;
bool valid_spdy_session_; // True if we have seen valid data on this session.
// Use this to fail fast when junk is sent to our
// port.
diff --git a/chromium/net/tools/flip_server/spdy_interface_test.cc b/chromium/net/tools/flip_server/spdy_interface_test.cc
index 3b988520158..7e2e5245cbb 100644
--- a/chromium/net/tools/flip_server/spdy_interface_test.cc
+++ b/chromium/net/tools/flip_server/spdy_interface_test.cc
@@ -44,15 +44,13 @@ class SpdyFramerVisitor : public BufferedSpdyFramerVisitorInterface {
virtual ~SpdyFramerVisitor() {}
MOCK_METHOD1(OnError, void(SpdyFramer::SpdyError));
MOCK_METHOD2(OnStreamError, void(SpdyStreamId, const std::string&));
- MOCK_METHOD7(OnSynStream,
+ MOCK_METHOD6(OnSynStream,
void(SpdyStreamId,
SpdyStreamId,
SpdyPriority,
- uint8,
bool,
bool,
const SpdyHeaderBlock&));
- MOCK_METHOD3(OnSynStream, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
MOCK_METHOD3(OnSynReply, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
MOCK_METHOD3(OnHeaders, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
MOCK_METHOD3(OnDataFrameHeader, void(SpdyStreamId, size_t, bool));
@@ -62,11 +60,12 @@ class SpdyFramerVisitor : public BufferedSpdyFramerVisitorInterface {
bool));
MOCK_METHOD1(OnSettings, void(bool clear_persisted));
MOCK_METHOD3(OnSetting, void(SpdySettingsIds, uint8, uint32));
- MOCK_METHOD1(OnPing, void(uint32 unique_id));
+ MOCK_METHOD2(OnPing, void(SpdyPingId unique_id, bool is_ack));
MOCK_METHOD2(OnRstStream, void(SpdyStreamId, SpdyRstStreamStatus));
MOCK_METHOD2(OnGoAway, void(SpdyStreamId, SpdyGoAwayStatus));
MOCK_METHOD2(OnWindowUpdate, void(SpdyStreamId, uint32));
- MOCK_METHOD2(OnPushPromise, void(SpdyStreamId, SpdyStreamId));
+ MOCK_METHOD3(OnPushPromise,
+ void(SpdyStreamId, SpdyStreamId, const SpdyHeaderBlock&));
};
class FakeSMConnection : public SMConnection {
@@ -243,7 +242,7 @@ TEST_P(SpdySMProxyTest, OnSynStream_SPDY2) {
InvokeWithoutArgs(&saver, &StringSaver::Save),
Return(0)));
}
- visitor->OnSynStream(stream_id, associated_id, 0, 0, false, false, block);
+ visitor->OnSynStream(stream_id, associated_id, 0, false, false, block);
ASSERT_EQ(expected, saver.string);
}
@@ -278,7 +277,7 @@ TEST_P(SpdySMProxyTest, OnSynStream) {
InvokeWithoutArgs(&saver, &StringSaver::Save),
Return(0)));
}
- visitor->OnSynStream(stream_id, associated_id, 0, 0, false, false, block);
+ visitor->OnSynStream(stream_id, associated_id, 0, false, false, block);
ASSERT_EQ(expected, saver.string);
}
@@ -294,7 +293,7 @@ TEST_P(SpdySMProxyTest, OnStreamFrameData_SPDY2) {
SpdyHeaderBlock block;
testing::MockFunction<void(int)> checkpoint; // NOLINT
- scoped_ptr<SpdyFrame> frame(spdy_framer_->CreatePingFrame(12));
+ scoped_ptr<SpdyFrame> frame(spdy_framer_->CreatePingFrame(12, false));
block["method"] = "GET";
block["url"] = "http://www.example.com/path";
block["scheme"] = "http";
@@ -310,7 +309,7 @@ TEST_P(SpdySMProxyTest, OnStreamFrameData_SPDY2) {
ProcessWriteInput(frame->data(), frame->size())).Times(1);
}
- visitor->OnSynStream(stream_id, associated_id, 0, 0, false, false, block);
+ visitor->OnSynStream(stream_id, associated_id, 0, false, false, block);
checkpoint.Call(0);
visitor->OnStreamFrameData(stream_id, frame->data(), frame->size(), true);
}
@@ -327,7 +326,7 @@ TEST_P(SpdySMProxyTest, OnStreamFrameData) {
SpdyHeaderBlock block;
testing::MockFunction<void(int)> checkpoint; // NOLINT
- scoped_ptr<SpdyFrame> frame(spdy_framer_->CreatePingFrame(12));
+ scoped_ptr<SpdyFrame> frame(spdy_framer_->CreatePingFrame(12, false));
block[":method"] = "GET";
block[":host"] = "www.example.com";
block[":path"] = "/path";
@@ -345,7 +344,7 @@ TEST_P(SpdySMProxyTest, OnStreamFrameData) {
ProcessWriteInput(frame->data(), frame->size())).Times(1);
}
- visitor->OnSynStream(stream_id, associated_id, 0, 0, false, false, block);
+ visitor->OnSynStream(stream_id, associated_id, 0, false, false, block);
checkpoint.Call(0);
visitor->OnStreamFrameData(stream_id, frame->data(), frame->size(), true);
}
@@ -397,7 +396,19 @@ TEST_P(SpdySMProxyTest, ResetForNewConnection) {
interface_->ResetForNewConnection();
ASSERT_FALSE(HasStream(stream_id));
- ASSERT_EQ(SpdyFramer::SPDY_RESET, interface_->spdy_framer()->state());
+ ASSERT_TRUE(interface_->spdy_framer() == NULL);
+}
+
+TEST_P(SpdySMProxyTest, CreateFramer) {
+ interface_->ResetForNewConnection();
+ interface_->CreateFramer(SPDY2);
+ ASSERT_TRUE(interface_->spdy_framer() != NULL);
+ ASSERT_EQ(interface_->spdy_version(), SPDY2);
+
+ interface_->ResetForNewConnection();
+ interface_->CreateFramer(SPDY3);
+ ASSERT_TRUE(interface_->spdy_framer() != NULL);
+ ASSERT_EQ(interface_->spdy_version(), SPDY3);
}
TEST_P(SpdySMProxyTest, PostAcceptHook) {
@@ -455,8 +466,13 @@ TEST_P(SpdySMProxyTest, SendErrorNotFound_SPDY2) {
{
InSequence s;
- EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
- .WillOnce(SaveArg<2>(&actual_header_block));
+ if (GetParam() < SPDY4) {
+ EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
+ .WillOnce(SaveArg<2>(&actual_header_block));
+ } else {
+ EXPECT_CALL(*spdy_framer_visitor_, OnHeaders(stream_id, false, _))
+ .WillOnce(SaveArg<2>(&actual_header_block));
+ }
EXPECT_CALL(checkpoint, Call(0));
EXPECT_CALL(*spdy_framer_visitor_,
OnDataFrameHeader(stream_id, _, true));
@@ -499,9 +515,15 @@ TEST_P(SpdySMProxyTest, SendErrorNotFound) {
{
InSequence s;
- EXPECT_CALL(*spdy_framer_visitor_,
- OnSynReply(stream_id, false, _))
- .WillOnce(SaveArg<2>(&actual_header_block));
+ if (GetParam() < SPDY4) {
+ EXPECT_CALL(*spdy_framer_visitor_,
+ OnSynReply(stream_id, false, _))
+ .WillOnce(SaveArg<2>(&actual_header_block));
+ } else {
+ EXPECT_CALL(*spdy_framer_visitor_,
+ OnHeaders(stream_id, false, _))
+ .WillOnce(SaveArg<2>(&actual_header_block));
+ }
EXPECT_CALL(checkpoint, Call(0));
EXPECT_CALL(*spdy_framer_visitor_,
OnDataFrameHeader(stream_id, _, true));
@@ -547,8 +569,8 @@ TEST_P(SpdySMProxyTest, SendSynStream_SPDY2) {
{
InSequence s;
EXPECT_CALL(*spdy_framer_visitor_,
- OnSynStream(stream_id, 0, _, _, false, false, _))
- .WillOnce(SaveArg<6>(&actual_header_block));
+ OnSynStream(stream_id, 0, _, false, false, _))
+ .WillOnce(SaveArg<5>(&actual_header_block));
}
spdy_framer_->ProcessInput(df->data, df->size);
@@ -581,8 +603,8 @@ TEST_P(SpdySMProxyTest, SendSynStream) {
{
InSequence s;
EXPECT_CALL(*spdy_framer_visitor_,
- OnSynStream(stream_id, 0, _, _, false, false, _))
- .WillOnce(SaveArg<6>(&actual_header_block));
+ OnSynStream(stream_id, 0, _, false, false, _))
+ .WillOnce(SaveArg<5>(&actual_header_block));
}
spdy_framer_->ProcessInput(df->data, df->size);
@@ -614,8 +636,13 @@ TEST_P(SpdySMProxyTest, SendSynReply_SPDY2) {
{
InSequence s;
- EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
- .WillOnce(SaveArg<2>(&actual_header_block));
+ if (GetParam() < SPDY4) {
+ EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
+ .WillOnce(SaveArg<2>(&actual_header_block));
+ } else {
+ EXPECT_CALL(*spdy_framer_visitor_, OnHeaders(stream_id, false, _))
+ .WillOnce(SaveArg<2>(&actual_header_block));
+ }
}
spdy_framer_->ProcessInput(df->data, df->size);
@@ -645,8 +672,13 @@ TEST_P(SpdySMProxyTest, SendSynReply) {
{
InSequence s;
- EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
- .WillOnce(SaveArg<2>(&actual_header_block));
+ if (GetParam() < SPDY4) {
+ EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
+ .WillOnce(SaveArg<2>(&actual_header_block));
+ } else {
+ EXPECT_CALL(*spdy_framer_visitor_, OnHeaders(stream_id, false, _))
+ .WillOnce(SaveArg<2>(&actual_header_block));
+ }
}
spdy_framer_->ProcessInput(df->data, df->size);
@@ -787,7 +819,7 @@ TEST_P(SpdySMServerTest, OnSynStream) {
BalsaHeaders headers;
memory_cache_->InsertFile(&headers, "GET_/path", "");
}
- visitor->OnSynStream(stream_id, 0, 0, 0, true, true, spdy_headers);
+ visitor->OnSynStream(stream_id, 0, 0, true, true, spdy_headers);
ASSERT_TRUE(HasStream(stream_id));
}
@@ -817,8 +849,13 @@ TEST_P(SpdySMServerTest, NewStreamError) {
{
InSequence s;
- EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
- .WillOnce(SaveArg<2>(&actual_header_block));
+ if (GetParam() < SPDY4) {
+ EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
+ .WillOnce(SaveArg<2>(&actual_header_block));
+ } else {
+ EXPECT_CALL(*spdy_framer_visitor_, OnHeaders(stream_id, false, _))
+ .WillOnce(SaveArg<2>(&actual_header_block));
+ }
EXPECT_CALL(checkpoint, Call(0));
EXPECT_CALL(*spdy_framer_visitor_,
OnDataFrameHeader(stream_id, _, true));
diff --git a/chromium/net/tools/flip_server/spdy_ssl.cc b/chromium/net/tools/flip_server/spdy_ssl.cc
index 1f18a0b30ff..2a5cb0e4953 100644
--- a/chromium/net/tools/flip_server/spdy_ssl.cc
+++ b/chromium/net/tools/flip_server/spdy_ssl.cc
@@ -42,9 +42,7 @@ void InitSSL(SSLState* state,
PrintSslError();
state->ssl_method = SSLv23_method();
- // TODO(joth): Remove const_cast when the openssl 1.0.0 upgrade is complete.
- // (See http://codereview.chromium.org/9254031).
- state->ssl_ctx = SSL_CTX_new(const_cast<SSL_METHOD*>(state->ssl_method));
+ state->ssl_ctx = SSL_CTX_new(state->ssl_method);
if (!state->ssl_ctx) {
PrintSslError();
LOG(FATAL) << "Unable to create SSL context";
diff --git a/chromium/net/tools/gdig/file_net_log.cc b/chromium/net/tools/gdig/file_net_log.cc
index 7c755c855fe..5020f6de647 100644
--- a/chromium/net/tools/gdig/file_net_log.cc
+++ b/chromium/net/tools/gdig/file_net_log.cc
@@ -27,7 +27,7 @@ void FileNetLogObserver::OnAddEntry(const net::NetLog::Entry& entry) {
const char* source = NetLog::SourceTypeToString(entry.source().type);
const char* type = NetLog::EventTypeToString(entry.type());
- scoped_ptr<Value> param_value(entry.ParametersToValue());
+ scoped_ptr<base::Value> param_value(entry.ParametersToValue());
std::string params;
if (param_value.get() != NULL) {
JSONStringValueSerializer serializer(&params);
diff --git a/chromium/net/tools/gdig/gdig.cc b/chromium/net/tools/gdig/gdig.cc
index db0704c5a84..fbee8860ad6 100644
--- a/chromium/net/tools/gdig/gdig.cc
+++ b/chromium/net/tools/gdig/gdig.cc
@@ -16,6 +16,7 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "net/base/address_list.h"
#include "net/base/ip_endpoint.h"
@@ -275,8 +276,9 @@ GDig::Result GDig::Main(int argc, const char* argv[]) {
}
bool GDig::ParseCommandLine(int argc, const char* argv[]) {
- CommandLine::Init(argc, argv);
- const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
+ base::CommandLine::Init(argc, argv);
+ const base::CommandLine& parsed_command_line =
+ *base::CommandLine::ForCurrentProcess();
if (parsed_command_line.HasSwitch("config_timeout")) {
int timeout_seconds = 0;
@@ -299,7 +301,6 @@ bool GDig::ParseCommandLine(int argc, const char* argv[]) {
std::map<std::string, NetLog::LogLevel> log_levels;
log_levels["all"] = NetLog::LOG_ALL;
log_levels["no_bytes"] = NetLog::LOG_ALL_BUT_BYTES;
- log_levels["basic"] = NetLog::LOG_BASIC;
if (log_levels.find(log_param) != log_levels.end()) {
level = log_levels[log_param];
@@ -362,7 +363,7 @@ bool GDig::ParseCommandLine(int argc, const char* argv[]) {
ReplayLogEntry entry;
entry.start_time = base::TimeDelta();
#if defined(OS_WIN)
- entry.domain_name = WideToASCII(parsed_command_line.GetArgs()[0]);
+ entry.domain_name = base::UTF16ToASCII(parsed_command_line.GetArgs()[0]);
#else
entry.domain_name = parsed_command_line.GetArgs()[0];
#endif
@@ -420,12 +421,11 @@ void GDig::OnDnsConfig(const DnsConfig& dns_config_const) {
scoped_ptr<DnsClient> dns_client(DnsClient::CreateClient(NULL));
dns_client->SetConfig(dns_config);
+ HostResolver::Options options;
+ options.max_concurrent_resolves = parallellism_;
+ options.max_retry_attempts = 1u;
scoped_ptr<HostResolverImpl> resolver(
- new HostResolverImpl(
- HostCache::CreateDefaultCache(),
- PrioritizedDispatcher::Limits(NUM_PRIORITIES, parallellism_),
- HostResolverImpl::ProcTaskParams(NULL, 1),
- log_.get()));
+ new HostResolverImpl(options, log_.get()));
resolver->SetDnsClient(dns_client.Pass());
resolver_ = resolver.Pass();
diff --git a/chromium/net/tools/get_server_time/get_server_time.cc b/chromium/net/tools/get_server_time/get_server_time.cc
index 19a2010d83e..ddc08b2f5c1 100644
--- a/chromium/net/tools/get_server_time/get_server_time.cc
+++ b/chromium/net/tools/get_server_time/get_server_time.cc
@@ -48,6 +48,8 @@
#include "net/proxy/proxy_config_service_fixed.h"
#endif
+using base::UTF16ToUTF8;
+
namespace {
// base::TimeTicks::Now() is documented to have a resolution of
@@ -148,32 +150,6 @@ BuildURLRequestContext(net::NetLog* net_log) {
return context.Pass();
}
-class SingleThreadRequestContextGetter : public net::URLRequestContextGetter {
- public:
- // Since there's only a single thread, there's no need to worry
- // about when |context_| gets created.
- SingleThreadRequestContextGetter(
- net::NetLog* net_log,
- const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner)
- : context_(BuildURLRequestContext(net_log)),
- main_task_runner_(main_task_runner) {}
-
- virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE {
- return context_.get();
- }
-
- virtual scoped_refptr<base::SingleThreadTaskRunner>
- GetNetworkTaskRunner() const OVERRIDE {
- return main_task_runner_;
- }
-
- private:
- virtual ~SingleThreadRequestContextGetter() {}
-
- const scoped_ptr<net::URLRequestContext> context_;
- const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
-};
-
// Assuming that the time |server_time| was received from a server,
// that the request for the server was started on |start_ticks|, and
// that it ended on |end_ticks|, fills |server_now| with an estimate
@@ -218,12 +194,13 @@ int main(int argc, char* argv[]) {
#endif
base::AtExitManager exit_manager;
- CommandLine::Init(argc, argv);
+ base::CommandLine::Init(argc, argv);
logging::LoggingSettings settings;
settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
logging::InitLogging(settings);
- const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& parsed_command_line =
+ *base::CommandLine::ForCurrentProcess();
GURL url(parsed_command_line.GetSwitchValueASCII("url"));
if (!url.is_valid() ||
(url.scheme() != "http" && url.scheme() != "https")) {
@@ -249,15 +226,19 @@ int main(int argc, char* argv[]) {
net::NetLog net_log;
PrintingLogObserver printing_log_observer;
net_log.AddThreadSafeObserver(&printing_log_observer, net::NetLog::LOG_ALL);
- scoped_refptr<SingleThreadRequestContextGetter> context_getter(
- new SingleThreadRequestContextGetter(&net_log,
- main_loop.message_loop_proxy()));
QuitDelegate delegate;
scoped_ptr<net::URLFetcher> fetcher(
net::URLFetcher::Create(url, net::URLFetcher::HEAD, &delegate));
- fetcher->SetRequestContext(context_getter.get());
-
+ scoped_ptr<net::URLRequestContext> url_request_context(
+ BuildURLRequestContext(&net_log));
+ fetcher->SetRequestContext(
+ // Since there's only a single thread, there's no need to worry
+ // about when the URLRequestContext gets created.
+ // The URLFetcher will take a reference on the object, and hence
+ // implicitly take ownership.
+ new net::TrivialURLRequestContextGetter(url_request_context.get(),
+ main_loop.message_loop_proxy()));
const base::Time start_time = base::Time::Now();
const base::TimeTicks start_ticks = base::TimeTicks::Now();
diff --git a/chromium/net/tools/net_watcher/net_watcher.cc b/chromium/net/tools/net_watcher/net_watcher.cc
index 67eb124f8ac..421e6951271 100644
--- a/chromium/net/tools/net_watcher/net_watcher.cc
+++ b/chromium/net/tools/net_watcher/net_watcher.cc
@@ -21,7 +21,7 @@
#include "net/proxy/proxy_config_service.h"
#include "net/proxy/proxy_service.h"
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+#if defined(USE_GLIB) && !defined(OS_CHROMEOS)
#include <glib-object.h>
#endif
@@ -50,6 +50,8 @@ const char* ConnectionTypeToString(
return "CONNECTION_4G";
case net::NetworkChangeNotifier::CONNECTION_NONE:
return "CONNECTION_NONE";
+ case net::NetworkChangeNotifier::CONNECTION_BLUETOOTH:
+ return "CONNECTION_BLUETOOTH";
default:
return "CONNECTION_UNEXPECTED";
}
@@ -131,7 +133,7 @@ int main(int argc, char* argv[]) {
#if defined(OS_MACOSX)
base::mac::ScopedNSAutoreleasePool pool;
#endif
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+#if defined(USE_GLIB) && !defined(OS_CHROMEOS)
// g_type_init will be deprecated in 2.36. 2.35 is the development
// version for 2.36, hence do not call g_type_init starting 2.35.
// http://developer.gnome.org/gobject/unstable/gobject-Type-Information.html#g-type-init
@@ -140,9 +142,9 @@ int main(int argc, char* argv[]) {
// Normally handled by BrowserMainLoop::InitializeToolkit().
g_type_init();
#endif
-#endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+#endif // defined(USE_GLIB) && !defined(OS_CHROMEOS)
base::AtExitManager exit_manager;
- CommandLine::Init(argc, argv);
+ base::CommandLine::Init(argc, argv);
logging::LoggingSettings settings;
settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
logging::InitLogging(settings);
diff --git a/chromium/net/tools/quic/end_to_end_test.cc b/chromium/net/tools/quic/end_to_end_test.cc
index 2b94b0f2fd1..a21dc4082a3 100644
--- a/chromium/net/tools/quic/end_to_end_test.cc
+++ b/chromium/net/tools/quic/end_to_end_test.cc
@@ -4,30 +4,39 @@
#include <stddef.h>
#include <string>
+#include <sys/epoll.h>
#include <vector>
+#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/strings/string_number_conversions.h"
#include "base/synchronization/waitable_event.h"
+#include "base/time/time.h"
#include "net/base/ip_endpoint.h"
#include "net/quic/congestion_control/tcp_cubic_sender.h"
#include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
#include "net/quic/crypto/null_encrypter.h"
+#include "net/quic/quic_flags.h"
#include "net/quic/quic_framer.h"
#include "net/quic/quic_packet_creator.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/quic_sent_packet_manager.h"
+#include "net/quic/quic_server_id.h"
#include "net/quic/test_tools/quic_connection_peer.h"
+#include "net/quic/test_tools/quic_flow_controller_peer.h"
#include "net/quic/test_tools/quic_session_peer.h"
-#include "net/quic/test_tools/quic_test_writer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/reliable_quic_stream_peer.h"
+#include "net/test/gtest_util.h"
+#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
#include "net/tools/quic/quic_in_memory_cache.h"
+#include "net/tools/quic/quic_packet_writer_wrapper.h"
#include "net/tools/quic/quic_server.h"
#include "net/tools/quic/quic_socket_utils.h"
#include "net/tools/quic/quic_spdy_client_stream.h"
-#include "net/tools/quic/test_tools/http_message_test_utils.h"
+#include "net/tools/quic/test_tools/http_message.h"
#include "net/tools/quic/test_tools/packet_dropping_test_writer.h"
#include "net/tools/quic/test_tools/quic_client_peer.h"
#include "net/tools/quic/test_tools/quic_dispatcher_peer.h"
@@ -39,10 +48,14 @@
using base::StringPiece;
using base::WaitableEvent;
+using net::EpollServer;
+using net::test::GenerateBody;
using net::test::QuicConnectionPeer;
+using net::test::QuicFlowControllerPeer;
using net::test::QuicSessionPeer;
-using net::test::QuicTestWriter;
using net::test::ReliableQuicStreamPeer;
+using net::test::ValueRestore;
+using net::test::kClientDataStreamId1;
using net::tools::test::PacketDroppingTestWriter;
using net::tools::test::QuicDispatcherPeer;
using net::tools::test::QuicServerPeer;
@@ -58,14 +71,6 @@ namespace {
const char* kFooResponseBody = "Artichoke hearts make me happy.";
const char* kBarResponseBody = "Palm hearts are pretty delicious, also.";
-void GenerateBody(string* body, int length) {
- body->clear();
- body->reserve(length);
- for (int i = 0; i < length; ++i) {
- body->append(1, static_cast<char>(32 + i % (126 - 32)));
- }
-}
-
// Run all tests with the cross products of all versions.
struct TestParams {
TestParams(const QuicVersionVector& client_supported_versions,
@@ -98,7 +103,6 @@ struct TestParams {
vector<TestParams> GetTestParams() {
vector<TestParams> params;
QuicVersionVector all_supported_versions = QuicSupportedVersions();
-
for (int use_pacing = 0; use_pacing < 2; ++use_pacing) {
// Add an entry for server and client supporting all versions.
params.push_back(TestParams(all_supported_versions,
@@ -106,19 +110,6 @@ vector<TestParams> GetTestParams() {
all_supported_versions[0],
use_pacing != 0));
- // Test client supporting 1 version and server supporting all versions.
- // Simulate an old client and exercise version downgrade in the server.
- // No protocol negotiation should occur. Skip the i = 0 case because it
- // is essentially the same as the default case.
- for (size_t i = 1; i < all_supported_versions.size(); ++i) {
- QuicVersionVector client_supported_versions;
- client_supported_versions.push_back(all_supported_versions[i]);
- params.push_back(TestParams(client_supported_versions,
- all_supported_versions,
- client_supported_versions[0],
- use_pacing != 0));
- }
-
// Test client supporting all versions and server supporting 1 version.
// Simulate an old server and exercise version downgrade in the client.
// Protocol negotiation should occur. Skip the i = 0 case because it is
@@ -126,6 +117,12 @@ vector<TestParams> GetTestParams() {
for (size_t i = 1; i < all_supported_versions.size(); ++i) {
QuicVersionVector server_supported_versions;
server_supported_versions.push_back(all_supported_versions[i]);
+ if (all_supported_versions[i] >= QUIC_VERSION_17) {
+ // Until flow control is globally rolled out and we remove
+ // QUIC_VERSION_16, the server MUST support at least one QUIC version
+ // that does not use flow control.
+ server_supported_versions.push_back(QUIC_VERSION_16);
+ }
params.push_back(TestParams(all_supported_versions,
server_supported_versions,
server_supported_versions[0],
@@ -135,6 +132,28 @@ vector<TestParams> GetTestParams() {
return params;
}
+class ServerDelegate : public PacketDroppingTestWriter::Delegate {
+ public:
+ explicit ServerDelegate(QuicDispatcher* dispatcher)
+ : dispatcher_(dispatcher) {}
+ virtual ~ServerDelegate() {}
+ virtual void OnCanWrite() OVERRIDE { dispatcher_->OnCanWrite(); }
+ private:
+ QuicDispatcher* dispatcher_;
+};
+
+class ClientDelegate : public PacketDroppingTestWriter::Delegate {
+ public:
+ explicit ClientDelegate(QuicClient* client) : client_(client) {}
+ virtual ~ClientDelegate() {}
+ virtual void OnCanWrite() OVERRIDE {
+ EpollEvent event(EPOLLOUT, false);
+ client_->OnEvent(client_->fd(), &event);
+ }
+ private:
+ QuicClient* client_;
+};
+
class EndToEndTest : public ::testing::TestWithParam<TestParams> {
protected:
EndToEndTest()
@@ -148,14 +167,32 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
client_supported_versions_ = GetParam().client_supported_versions;
server_supported_versions_ = GetParam().server_supported_versions;
negotiated_version_ = GetParam().negotiated_version;
- FLAGS_limit_rto_increase_for_tests = true;
FLAGS_enable_quic_pacing = GetParam().use_pacing;
- LOG(INFO) << "Using Configuration: " << GetParam();
+
+ if (negotiated_version_ >= QUIC_VERSION_17) {
+ FLAGS_enable_quic_stream_flow_control_2 = true;
+ }
+ if (negotiated_version_ >= QUIC_VERSION_19) {
+ FLAGS_enable_quic_connection_flow_control_2 = true;
+ }
+ VLOG(1) << "Using Configuration: " << GetParam();
client_config_.SetDefaults();
server_config_.SetDefaults();
- server_config_.set_initial_round_trip_time_us(kMaxInitialRoundTripTimeUs,
- 0);
+
+ // Use different flow control windows for client/server.
+ client_config_.SetInitialFlowControlWindowToSend(
+ 2 * kInitialSessionFlowControlWindowForTest);
+ client_config_.SetInitialStreamFlowControlWindowToSend(
+ 2 * kInitialStreamFlowControlWindowForTest);
+ client_config_.SetInitialSessionFlowControlWindowToSend(
+ 2 * kInitialSessionFlowControlWindowForTest);
+ server_config_.SetInitialFlowControlWindowToSend(
+ 3 * kInitialSessionFlowControlWindowForTest);
+ server_config_.SetInitialStreamFlowControlWindowToSend(
+ 3 * kInitialStreamFlowControlWindowForTest);
+ server_config_.SetInitialSessionFlowControlWindowToSend(
+ 3 * kInitialSessionFlowControlWindowForTest);
QuicInMemoryCachePeer::ResetForTests();
AddToCache("GET", "https://www.google.com/foo",
@@ -170,54 +207,99 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
QuicInMemoryCachePeer::ResetForTests();
}
- virtual QuicTestClient* CreateQuicClient(QuicTestWriter* writer) {
- QuicTestClient* client = new QuicTestClient(server_address_,
- server_hostname_,
- false, // not secure
- client_config_,
- client_supported_versions_);
+ QuicTestClient* CreateQuicClient(QuicPacketWriterWrapper* writer) {
+ QuicTestClient* client = new QuicTestClient(
+ server_address_,
+ server_hostname_,
+ false, // not secure
+ client_config_,
+ client_supported_versions_);
client->UseWriter(writer);
client->Connect();
return client;
}
- virtual bool Initialize() {
+ void set_client_initial_flow_control_receive_window(uint32 window) {
+ CHECK(client_.get() == NULL);
+ DVLOG(1) << "Setting client initial flow control window: " << window;
+ client_config_.SetInitialFlowControlWindowToSend(window);
+ }
+
+ void set_client_initial_stream_flow_control_receive_window(uint32 window) {
+ CHECK(client_.get() == NULL);
+ DLOG(INFO) << "Setting client initial stream flow control window: "
+ << window;
+ client_config_.SetInitialStreamFlowControlWindowToSend(window);
+ }
+
+ void set_client_initial_session_flow_control_receive_window(uint32 window) {
+ CHECK(client_.get() == NULL);
+ DLOG(INFO) << "Setting client initial session flow control window: "
+ << window;
+ client_config_.SetInitialSessionFlowControlWindowToSend(window);
+ }
+
+ void set_server_initial_flow_control_receive_window(uint32 window) {
+ CHECK(server_thread_.get() == NULL);
+ DVLOG(1) << "Setting server initial flow control window: " << window;
+ server_config_.SetInitialFlowControlWindowToSend(window);
+ }
+
+ void set_server_initial_stream_flow_control_receive_window(uint32 window) {
+ CHECK(server_thread_.get() == NULL);
+ DLOG(INFO) << "Setting server initial stream flow control window: "
+ << window;
+ server_config_.SetInitialStreamFlowControlWindowToSend(window);
+ }
+
+ void set_server_initial_session_flow_control_receive_window(uint32 window) {
+ CHECK(server_thread_.get() == NULL);
+ DLOG(INFO) << "Setting server initial session flow control window: "
+ << window;
+ server_config_.SetInitialSessionFlowControlWindowToSend(window);
+ }
+
+ bool Initialize() {
// Start the server first, because CreateQuicClient() attempts
// to connect to the server.
StartServer();
client_.reset(CreateQuicClient(client_writer_));
- QuicEpollConnectionHelper* helper =
+ static EpollEvent event(EPOLLOUT, false);
+ client_writer_->Initialize(
reinterpret_cast<QuicEpollConnectionHelper*>(
QuicConnectionPeer::GetHelper(
- client_->client()->session()->connection()));
- client_writer_->SetConnectionHelper(helper);
+ client_->client()->session()->connection())),
+ new ClientDelegate(client_->client()));
return client_->client()->connected();
}
- virtual void SetUp() {
- // The ownership of these gets transferred to the QuicTestWriter and
- // QuicDispatcher when Initialize() is executed.
+ virtual void SetUp() OVERRIDE {
+ // The ownership of these gets transferred to the QuicPacketWriterWrapper
+ // and QuicDispatcher when Initialize() is executed.
client_writer_ = new PacketDroppingTestWriter();
server_writer_ = new PacketDroppingTestWriter();
}
- virtual void TearDown() {
+ virtual void TearDown() OVERRIDE {
StopServer();
}
void StartServer() {
- server_thread_.reset(new ServerThread(server_address_, server_config_,
- server_supported_versions_,
- strike_register_no_startup_period_));
- server_thread_->Start();
- server_thread_->WaitForServerStartup();
+ server_thread_.reset(
+ new ServerThread(
+ new QuicServer(server_config_, server_supported_versions_),
+ server_address_,
+ strike_register_no_startup_period_));
+ server_thread_->Initialize();
server_address_ = IPEndPoint(server_address_.address(),
server_thread_->GetPort());
QuicDispatcher* dispatcher =
QuicServerPeer::GetDispatcher(server_thread_->server());
- server_writer_->SetConnectionHelper(
- QuicDispatcherPeer::GetHelper(dispatcher));
QuicDispatcherPeer::UseWriter(dispatcher, server_writer_);
+ server_writer_->Initialize(
+ QuicDispatcherPeer::GetHelper(dispatcher),
+ new ServerDelegate(dispatcher));
+ server_thread_->Start();
server_started_ = true;
}
@@ -243,8 +325,10 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
void SetPacketLossPercentage(int32 loss) {
// TODO(rtenneti): enable when we can do random packet loss tests in
// chrome's tree.
- // client_writer_->set_fake_packet_loss_percentage(loss);
- // server_writer_->set_fake_packet_loss_percentage(loss);
+ if (loss != 0 && loss != 100)
+ return;
+ client_writer_->set_fake_packet_loss_percentage(loss);
+ server_writer_->set_fake_packet_loss_percentage(loss);
}
void SetPacketSendDelay(QuicTime::Delta delay) {
@@ -261,6 +345,36 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
// server_writer_->set_fake_reorder_percentage(reorder);
}
+ // Verifies that the client and server connections were both free of packets
+ // being discarded, based on connection stats.
+ // Calls server_thread_ Pause() and Resume(), which may only be called once
+ // per test.
+ void VerifyCleanConnection(bool had_packet_loss) {
+ QuicConnectionStats client_stats =
+ client_->client()->session()->connection()->GetStats();
+ if (!had_packet_loss) {
+ EXPECT_EQ(0u, client_stats.packets_lost);
+ }
+ EXPECT_EQ(0u, client_stats.packets_discarded);
+ EXPECT_EQ(0u, client_stats.packets_dropped);
+ EXPECT_EQ(client_stats.packets_received, client_stats.packets_processed);
+
+ server_thread_->Pause();
+ QuicDispatcher* dispatcher =
+ QuicServerPeer::GetDispatcher(server_thread_->server());
+ ASSERT_EQ(1u, dispatcher->session_map().size());
+ QuicSession* session = dispatcher->session_map().begin()->second;
+ QuicConnectionStats server_stats = session->connection()->GetStats();
+ if (!had_packet_loss) {
+ EXPECT_EQ(0u, server_stats.packets_lost);
+ }
+ EXPECT_EQ(0u, server_stats.packets_discarded);
+ // TODO(ianswett): Restore the check for packets_dropped equals 0.
+ // The expect for packets received is equal to packets processed fails
+ // due to version negotiation packets.
+ server_thread_->Resume();
+ }
+
IPEndPoint server_address_;
string server_hostname_;
scoped_ptr<ServerThread> server_thread_;
@@ -398,12 +512,14 @@ TEST_P(EndToEndTest, PostMissingBytes) {
EXPECT_EQ(500u, client_->response_headers()->parsed_response_code());
}
-TEST_P(EndToEndTest, LargePostNoPacketLoss) {
+// TODO(rtenneti): DISABLED_LargePostNoPacketLoss seems to be flaky.
+// http://crbug.com/297040.
+TEST_P(EndToEndTest, DISABLED_LargePostNoPacketLoss) {
ASSERT_TRUE(Initialize());
client_->client()->WaitForCryptoHandshakeConfirmed();
- // 1 Mb body.
+ // 1 MB body.
string body;
GenerateBody(&body, 1024 * 1024);
@@ -412,6 +528,25 @@ TEST_P(EndToEndTest, LargePostNoPacketLoss) {
request.AddBody(body, true);
EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
+ VerifyCleanConnection(false);
+}
+
+TEST_P(EndToEndTest, LargePostNoPacketLoss1sRTT) {
+ ASSERT_TRUE(Initialize());
+ SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(1000));
+
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+
+ // 100 KB body.
+ string body;
+ GenerateBody(&body, 100 * 1024);
+
+ HTTPMessage request(HttpConstants::HTTP_1_1,
+ HttpConstants::POST, "/foo");
+ request.AddBody(body, true);
+
+ EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
+ VerifyCleanConnection(false);
}
TEST_P(EndToEndTest, LargePostWithPacketLoss) {
@@ -424,7 +559,7 @@ TEST_P(EndToEndTest, LargePostWithPacketLoss) {
client_->client()->WaitForCryptoHandshakeConfirmed();
SetPacketLossPercentage(30);
- // 10 Kb body.
+ // 10 KB body.
string body;
GenerateBody(&body, 1024 * 10);
@@ -433,19 +568,23 @@ TEST_P(EndToEndTest, LargePostWithPacketLoss) {
request.AddBody(body, true);
EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
+ VerifyCleanConnection(true);
}
-TEST_P(EndToEndTest, LargePostNoPacketLossWithDelayAndReordering) {
+TEST_P(EndToEndTest, LargePostWithPacketLossAndBlockedSocket) {
+ // Connect with lower fake packet loss than we'd like to test. Until
+ // b/10126687 is fixed, losing handshake packets is pretty brutal.
+ SetPacketLossPercentage(5);
ASSERT_TRUE(Initialize());
+ // Wait for the server SHLO before upping the packet loss.
client_->client()->WaitForCryptoHandshakeConfirmed();
- // Both of these must be called when the writer is not actively used.
- SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2));
- SetReorderPercentage(30);
+ SetPacketLossPercentage(10);
+ client_writer_->set_fake_blocked_socket_percentage(10);
- // 1 Mb body.
+ // 10 KB body.
string body;
- GenerateBody(&body, 1024 * 1024);
+ GenerateBody(&body, 1024 * 10);
HTTPMessage request(HttpConstants::HTTP_1_1,
HttpConstants::POST, "/foo");
@@ -454,20 +593,17 @@ TEST_P(EndToEndTest, LargePostNoPacketLossWithDelayAndReordering) {
EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
}
-TEST_P(EndToEndTest, LargePostWithPacketLossAndBlocketSocket) {
- // Connect with lower fake packet loss than we'd like to test. Until
- // b/10126687 is fixed, losing handshake packets is pretty brutal.
- SetPacketLossPercentage(5);
+TEST_P(EndToEndTest, LargePostNoPacketLossWithDelayAndReordering) {
ASSERT_TRUE(Initialize());
- // Wait for the server SHLO before upping the packet loss.
client_->client()->WaitForCryptoHandshakeConfirmed();
- SetPacketLossPercentage(30);
- client_writer_->set_fake_blocked_socket_percentage(10);
+ // Both of these must be called when the writer is not actively used.
+ SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2));
+ SetReorderPercentage(30);
- // 10 Kb body.
+ // 1 MB body.
string body;
- GenerateBody(&body, 1024 * 10);
+ GenerateBody(&body, 1024 * 1024);
HTTPMessage request(HttpConstants::HTTP_1_1,
HttpConstants::POST, "/foo");
@@ -500,6 +636,14 @@ TEST_P(EndToEndTest, DISABLED_LargePostZeroRTTFailure) {
// The 0-RTT handshake should succeed.
client_->Connect();
+ if (client_supported_versions_[0] >= QUIC_VERSION_17 &&
+ negotiated_version_ < QUIC_VERSION_17) {
+ // If the version negotiation has resulted in a downgrade, then the client
+ // must wait for the handshake to complete before sending any data.
+ // Otherwise it may have queued QUIC_VERSION_17 frames which will trigger a
+ // DFATAL when they are serialized after the downgrade.
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+ }
client_->WaitForResponseForMs(-1);
ASSERT_TRUE(client_->client()->connected());
EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
@@ -513,16 +657,35 @@ TEST_P(EndToEndTest, DISABLED_LargePostZeroRTTFailure) {
StartServer();
client_->Connect();
+ if (client_supported_versions_[0] >= QUIC_VERSION_17 &&
+ negotiated_version_ < QUIC_VERSION_17) {
+ // If the version negotiation has resulted in a downgrade, then the client
+ // must wait for the handshake to complete before sending any data.
+ // Otherwise it may have queued QUIC_VERSION_17 frames which will trigger a
+ // DFATAL when they are serialized after the downgrade.
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+ }
ASSERT_TRUE(client_->client()->connected());
EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
EXPECT_EQ(2, client_->client()->session()->GetNumSentClientHellos());
+ VerifyCleanConnection(false);
}
-// TODO(ianswett): Enable once b/9295090 is fixed.
-TEST_P(EndToEndTest, DISABLED_LargePostFEC) {
- SetPacketLossPercentage(30);
+TEST_P(EndToEndTest, LargePostFEC) {
+ // Connect without packet loss to avoid issues with losing handshake packets,
+ // and then up the packet loss rate (b/10126687).
ASSERT_TRUE(Initialize());
- client_->options()->max_packets_per_fec_group = 6;
+
+ // Wait for the server SHLO before upping the packet loss.
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+ SetPacketLossPercentage(30);
+
+ // Enable FEC protection.
+ QuicPacketCreator* creator = QuicConnectionPeer::GetPacketCreator(
+ client_->client()->session()->connection());
+ creator->set_max_packets_per_fec_group(3);
+ // Set FecPolicy to always protect data on all streams.
+ client_->SetFecPolicy(FEC_PROTECT_ALWAYS);
string body;
GenerateBody(&body, 10240);
@@ -530,21 +693,23 @@ TEST_P(EndToEndTest, DISABLED_LargePostFEC) {
HTTPMessage request(HttpConstants::HTTP_1_1,
HttpConstants::POST, "/foo");
request.AddBody(body, true);
-
EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
+ VerifyCleanConnection(true);
}
-TEST_P(EndToEndTest, LargePostLargeBuffer) {
+// TODO(shess): This is flaky on ChromiumOS bots.
+// http://crbug.com/374871
+TEST_P(EndToEndTest, DISABLED_LargePostSmallBandwidthLargeBuffer) {
ASSERT_TRUE(Initialize());
SetPacketSendDelay(QuicTime::Delta::FromMicroseconds(1));
- // 1Mbit per second with a 128k buffer from server to client. Wireless
+ // 256KB per second with a 256KB buffer from server to client. Wireless
// clients commonly have larger buffers, but our max CWND is 200.
server_writer_->set_max_bandwidth_and_buffer_size(
- QuicBandwidth::FromBytesPerSecond(256 * 1024), 128 * 1024);
+ QuicBandwidth::FromBytesPerSecond(256 * 1024), 256 * 1024);
client_->client()->WaitForCryptoHandshakeConfirmed();
- // 1 Mb body.
+ // 1 MB body.
string body;
GenerateBody(&body, 1024 * 1024);
@@ -553,6 +718,52 @@ TEST_P(EndToEndTest, LargePostLargeBuffer) {
request.AddBody(body, true);
EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
+ // This connection will not drop packets, because the buffer size is larger
+ // than the default receive window.
+ VerifyCleanConnection(false);
+}
+
+TEST_P(EndToEndTest, DoNotSetResumeWriteAlarmIfConnectionFlowControlBlocked) {
+ // Regression test for b/14677858.
+ // Test that the resume write alarm is not set in QuicConnection::OnCanWrite
+ // if currently connection level flow control blocked. If set, this results in
+ // an infinite loop in the EpollServer, as the alarm fires and is immediately
+ // rescheduled.
+ ASSERT_TRUE(Initialize());
+ if (negotiated_version_ < QUIC_VERSION_19) {
+ return;
+ }
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+
+ // Ensure both stream and connection level are flow control blocked by setting
+ // the send window offset to 0.
+ const uint64 kFlowControlWindow =
+ server_config_.GetInitialFlowControlWindowToSend();
+ QuicSpdyClientStream* stream = client_->GetOrCreateStream();
+ QuicSession* session = client_->client()->session();
+ QuicFlowControllerPeer::SetSendWindowOffset(stream->flow_controller(), 0);
+ QuicFlowControllerPeer::SetSendWindowOffset(session->flow_controller(), 0);
+ EXPECT_TRUE(stream->flow_controller()->IsBlocked());
+ EXPECT_TRUE(session->flow_controller()->IsBlocked());
+
+ // Make sure that the stream has data pending so that it will be marked as
+ // write blocked when it receives a stream level WINDOW_UPDATE.
+ stream->SendBody("hello", false);
+
+ // The stream now attempts to write, fails because it is still connection
+ // level flow control blocked, and is added to the write blocked list.
+ QuicWindowUpdateFrame window_update(stream->id(), 2 * kFlowControlWindow);
+ stream->OnWindowUpdateFrame(window_update);
+
+ // Prior to fixing b/14677858 this call would result in an infinite loop in
+ // Chromium. As a proxy for detecting this, we now check whether the
+ // resume_writes_alarm is set after OnCanWrite. It should not be, as the
+ // connection is still flow control blocked.
+ session->connection()->OnCanWrite();
+
+ QuicAlarm* resume_writes_alarm =
+ QuicConnectionPeer::GetResumeWritesAlarm(session->connection());
+ EXPECT_FALSE(resume_writes_alarm->IsSet());
}
TEST_P(EndToEndTest, InvalidStream) {
@@ -570,7 +781,7 @@ TEST_P(EndToEndTest, InvalidStream) {
QuicSessionPeer::SetNextStreamId(client_->client()->session(), 2);
client_->SendCustomSynchronousRequest(request);
-// EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error());
+ // EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error());
EXPECT_EQ(QUIC_PACKET_FOR_NONEXISTENT_STREAM, client_->connection_error());
}
@@ -598,23 +809,7 @@ TEST_P(EndToEndTest, DISABLED_MultipleTermination) {
ReliableQuicStreamPeer::SetWriteSideClosed(
false, client_->GetOrCreateStream());
-#if !defined(WIN32) && defined(GTEST_HAS_DEATH_TEST)
-#if !defined(DCHECK_ALWAYS_ON)
- EXPECT_DEBUG_DEATH({
- client_->SendData("eep", true);
- client_->WaitForResponse();
- EXPECT_EQ(QUIC_MULTIPLE_TERMINATION_OFFSETS, client_->stream_error());
- },
- "Check failed: !fin_buffered_");
-#else
- EXPECT_DEATH({
- client_->SendData("eep", true);
- client_->WaitForResponse();
- EXPECT_EQ(QUIC_MULTIPLE_TERMINATION_OFFSETS, client_->stream_error());
- },
- "Check failed: !fin_buffered_");
-#endif
-#endif
+ EXPECT_DFATAL(client_->SendData("eep", true), "Fin already buffered");
}
TEST_P(EndToEndTest, Timeout) {
@@ -629,6 +824,30 @@ TEST_P(EndToEndTest, Timeout) {
}
}
+TEST_P(EndToEndTest, NegotiateMaxOpenStreams) {
+ // Negotiate 1 max open stream.
+ client_config_.set_max_streams_per_connection(1, 1);
+ ASSERT_TRUE(Initialize());
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+
+ // Make the client misbehave after negotiation.
+ QuicSessionPeer::SetMaxOpenStreams(client_->client()->session(), 10);
+
+ HTTPMessage request(HttpConstants::HTTP_1_1,
+ HttpConstants::POST, "/foo");
+ request.AddHeader("content-length", "3");
+ request.set_has_complete_message(false);
+
+ // Open two simultaneous streams.
+ client_->SendMessage(request);
+ client_->SendMessage(request);
+ client_->WaitForResponse();
+
+ EXPECT_FALSE(client_->connected());
+ EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error());
+ EXPECT_EQ(QUIC_TOO_MANY_OPEN_STREAMS, client_->connection_error());
+}
+
TEST_P(EndToEndTest, LimitMaxOpenStreams) {
// Server limits the number of max streams to 2.
server_config_.set_max_streams_per_connection(2, 2);
@@ -644,13 +863,10 @@ TEST_P(EndToEndTest, LimitMaxOpenStreams) {
// TODO(rtenneti): DISABLED_LimitCongestionWindowAndRTT seems to be flaky.
// http://crbug.com/321870.
TEST_P(EndToEndTest, DISABLED_LimitCongestionWindowAndRTT) {
- server_config_.set_server_initial_congestion_window(kMaxInitialWindow,
- kDefaultInitialWindow);
- // Client tries to negotiate twice the server's max and negotiation settles
- // on the max.
- client_config_.set_server_initial_congestion_window(2 * kMaxInitialWindow,
- kDefaultInitialWindow);
- client_config_.set_initial_round_trip_time_us(1, 1);
+ // Client tries to request twice the server's max initial window, and the
+ // server limits it to the max.
+ client_config_.SetInitialCongestionWindowToSend(2 * kMaxInitialWindow);
+ client_config_.SetInitialRoundTripTimeUsToSend(1);
ASSERT_TRUE(Initialize());
client_->client()->WaitForCryptoHandshakeConfirmed();
@@ -662,17 +878,11 @@ TEST_P(EndToEndTest, DISABLED_LimitCongestionWindowAndRTT) {
QuicServerPeer::GetDispatcher(server_thread_->server());
ASSERT_EQ(1u, dispatcher->session_map().size());
QuicSession* session = dispatcher->session_map().begin()->second;
- QuicConfig* client_negotiated_config = client_->client()->session()->config();
- QuicConfig* server_negotiated_config = session->config();
const QuicSentPacketManager& client_sent_packet_manager =
client_->client()->session()->connection()->sent_packet_manager();
const QuicSentPacketManager& server_sent_packet_manager =
session->connection()->sent_packet_manager();
- EXPECT_EQ(kMaxInitialWindow,
- client_negotiated_config->server_initial_congestion_window());
- EXPECT_EQ(kMaxInitialWindow,
- server_negotiated_config->server_initial_congestion_window());
// The client shouldn't set it's initial window based on the negotiated value.
EXPECT_EQ(kDefaultInitialWindow * kDefaultTCPMSS,
client_sent_packet_manager.GetCongestionWindow());
@@ -684,13 +894,14 @@ TEST_P(EndToEndTest, DISABLED_LimitCongestionWindowAndRTT) {
EXPECT_EQ(FLAGS_enable_quic_pacing,
client_sent_packet_manager.using_pacing());
- EXPECT_EQ(1u, client_negotiated_config->initial_round_trip_time_us());
- EXPECT_EQ(1u, server_negotiated_config->initial_round_trip_time_us());
+ EXPECT_EQ(100000u,
+ client_sent_packet_manager.GetRttStats()->initial_rtt_us());
+ EXPECT_EQ(1u, server_sent_packet_manager.GetRttStats()->initial_rtt_us());
// Now use the negotiated limits with packet loss.
SetPacketLossPercentage(30);
- // 10 Kb body.
+ // 10 KB body.
string body;
GenerateBody(&body, 1024 * 10);
@@ -703,11 +914,42 @@ TEST_P(EndToEndTest, DISABLED_LimitCongestionWindowAndRTT) {
EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
}
-TEST_P(EndToEndTest, InitialRTT) {
- // Client tries to negotiate twice the server's max and negotiation settles
- // on the max.
- client_config_.set_initial_round_trip_time_us(2 * kMaxInitialRoundTripTimeUs,
- 0);
+TEST_P(EndToEndTest, MaxInitialRTT) {
+ // Client tries to suggest twice the server's max initial rtt and the server
+ // uses the max.
+ client_config_.SetInitialRoundTripTimeUsToSend(
+ 2 * kMaxInitialRoundTripTimeUs);
+
+ ASSERT_TRUE(Initialize());
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+ server_thread_->WaitForCryptoHandshakeConfirmed();
+
+ // Pause the server so we can access the server's internals without races.
+ server_thread_->Pause();
+ QuicDispatcher* dispatcher =
+ QuicServerPeer::GetDispatcher(server_thread_->server());
+ ASSERT_EQ(1u, dispatcher->session_map().size());
+ QuicSession* session = dispatcher->session_map().begin()->second;
+ const QuicSentPacketManager& client_sent_packet_manager =
+ client_->client()->session()->connection()->sent_packet_manager();
+ const QuicSentPacketManager& server_sent_packet_manager =
+ session->connection()->sent_packet_manager();
+
+ // Now that acks have been exchanged, the RTT estimate has decreased on the
+ // server and is not infinite on the client.
+ EXPECT_FALSE(
+ client_sent_packet_manager.GetRttStats()->SmoothedRtt().IsInfinite());
+ EXPECT_EQ(static_cast<int64>(kMaxInitialRoundTripTimeUs),
+ server_sent_packet_manager.GetRttStats()->initial_rtt_us());
+ EXPECT_GE(
+ static_cast<int64>(kMaxInitialRoundTripTimeUs),
+ server_sent_packet_manager.GetRttStats()->SmoothedRtt().ToMicroseconds());
+ server_thread_->Resume();
+}
+
+TEST_P(EndToEndTest, MinInitialRTT) {
+ // Client tries to suggest 0 and the server uses the default.
+ client_config_.SetInitialRoundTripTimeUsToSend(0);
ASSERT_TRUE(Initialize());
client_->client()->WaitForCryptoHandshakeConfirmed();
@@ -719,22 +961,22 @@ TEST_P(EndToEndTest, InitialRTT) {
QuicServerPeer::GetDispatcher(server_thread_->server());
ASSERT_EQ(1u, dispatcher->session_map().size());
QuicSession* session = dispatcher->session_map().begin()->second;
- QuicConfig* client_negotiated_config = client_->client()->session()->config();
- QuicConfig* server_negotiated_config = session->config();
const QuicSentPacketManager& client_sent_packet_manager =
client_->client()->session()->connection()->sent_packet_manager();
const QuicSentPacketManager& server_sent_packet_manager =
session->connection()->sent_packet_manager();
- EXPECT_EQ(kMaxInitialRoundTripTimeUs,
- client_negotiated_config->initial_round_trip_time_us());
- EXPECT_EQ(kMaxInitialRoundTripTimeUs,
- server_negotiated_config->initial_round_trip_time_us());
// Now that acks have been exchanged, the RTT estimate has decreased on the
// server and is not infinite on the client.
- EXPECT_FALSE(client_sent_packet_manager.SmoothedRtt().IsInfinite());
- EXPECT_GE(static_cast<int64>(kMaxInitialRoundTripTimeUs),
- server_sent_packet_manager.SmoothedRtt().ToMicroseconds());
+ EXPECT_FALSE(
+ client_sent_packet_manager.GetRttStats()->SmoothedRtt().IsInfinite());
+ // Expect the default rtt of 100ms.
+ EXPECT_EQ(static_cast<int64>(100 * base::Time::kMicrosecondsPerMillisecond),
+ server_sent_packet_manager.GetRttStats()->initial_rtt_us());
+ // Ensure the bandwidth is valid.
+ client_sent_packet_manager.BandwidthEstimate();
+ server_sent_packet_manager.BandwidthEstimate();
+ server_thread_->Resume();
}
TEST_P(EndToEndTest, ResetConnection) {
@@ -770,7 +1012,35 @@ TEST_P(EndToEndTest, MaxStreamsUberTest) {
}
}
-class WrongAddressWriter : public QuicTestWriter {
+TEST_P(EndToEndTest, StreamCancelErrorTest) {
+ ASSERT_TRUE(Initialize());
+ string small_body;
+ GenerateBody(&small_body, 256);
+
+ AddToCache("GET", "/small_response", "HTTP/1.1", "200", "OK", small_body);
+
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+
+ QuicSession* session = client_->client()->session();
+ // Lose the request.
+ SetPacketLossPercentage(100);
+ EXPECT_LT(0, client_->SendRequest("/small_response"));
+ client_->client()->WaitForEvents();
+ // Transmit the cancel, and ensure the connection is torn down properly.
+ SetPacketLossPercentage(0);
+ QuicStreamId stream_id = kClientDataStreamId1;
+ session->SendRstStream(stream_id, QUIC_STREAM_CANCELLED, 0);
+
+ // WaitForEvents waits 50ms and returns true if there are outstanding
+ // requests.
+ while (client_->client()->WaitForEvents() == true) {
+ }
+ // It should be completely fine to RST a stream before any data has been
+ // received for that stream.
+ EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error());
+}
+
+class WrongAddressWriter : public QuicPacketWriterWrapper {
public:
WrongAddressWriter() {
IPAddressNumber ip;
@@ -779,12 +1049,13 @@ class WrongAddressWriter : public QuicTestWriter {
}
virtual WriteResult WritePacket(
- const char* buffer, size_t buf_len,
+ const char* buffer,
+ size_t buf_len,
const IPAddressNumber& real_self_address,
- const IPEndPoint& peer_address,
- QuicBlockedWriterInterface* blocked_writer) OVERRIDE {
- return writer()->WritePacket(buffer, buf_len, self_address_.address(),
- peer_address, blocked_writer);
+ const IPEndPoint& peer_address) OVERRIDE {
+ // Use wrong address!
+ return QuicPacketWriterWrapper::WritePacket(
+ buffer, buf_len, self_address_.address(), peer_address);
}
virtual bool IsWriteBlockedDataBuffered() const OVERRIDE {
@@ -794,7 +1065,10 @@ class WrongAddressWriter : public QuicTestWriter {
IPEndPoint self_address_;
};
-TEST_P(EndToEndTest, ConnectionMigration) {
+TEST_P(EndToEndTest, ConnectionMigrationClientIPChanged) {
+ // Tests that the client's IP can not change during an established QUIC
+ // connection. If it changes, the connection is closed by the server as we do
+ // not yet support IP migration.
ASSERT_TRUE(Initialize());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
@@ -802,8 +1076,7 @@ TEST_P(EndToEndTest, ConnectionMigration) {
scoped_ptr<WrongAddressWriter> writer(new WrongAddressWriter());
- writer->set_writer(new QuicDefaultPacketWriter(
- QuicClientPeer::GetFd(client_->client())));
+ writer->set_writer(new QuicDefaultPacketWriter(client_->client()->fd()));
QuicConnectionPeer::SetWriter(client_->client()->session()->connection(),
writer.get());
@@ -813,6 +1086,157 @@ TEST_P(EndToEndTest, ConnectionMigration) {
EXPECT_EQ(QUIC_ERROR_MIGRATING_ADDRESS, client_->connection_error());
}
+TEST_P(EndToEndTest, ConnectionMigrationClientPortChanged) {
+ // Tests that the client's port can change during an established QUIC
+ // connection, and that doing so does not result in the connection being
+ // closed by the server.
+ FLAGS_quic_allow_port_migration = true;
+
+ ASSERT_TRUE(Initialize());
+
+ EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
+ EXPECT_EQ(200u, client_->response_headers()->parsed_response_code());
+
+ // Store the client address which was used to send the first request.
+ IPEndPoint old_address = client_->client()->client_address();
+
+ // Stop listening on the old FD.
+ EpollServer* eps = client_->epoll_server();
+ int old_fd = client_->client()->fd();
+ eps->UnregisterFD(old_fd);
+ // Create a new socket before closing the old one, which will result in a new
+ // ephemeral port.
+ QuicClientPeer::CreateUDPSocket(client_->client());
+ close(old_fd);
+
+ // The packet writer needs to be updated to use the new FD.
+ client_->client()->CreateQuicPacketWriter();
+
+ // Change the internal state of the client and connection to use the new port,
+ // this is done because in a real NAT rebinding the client wouldn't see any
+ // port change, and so expects no change to incoming port.
+ // This is kind of ugly, but needed as we are simply swapping out the client
+ // FD rather than any more complex NAT rebinding simulation.
+ int new_port = client_->client()->client_address().port();
+ QuicClientPeer::SetClientPort(client_->client(), new_port);
+ QuicConnectionPeer::SetSelfAddress(
+ client_->client()->session()->connection(),
+ IPEndPoint(
+ client_->client()->session()->connection()->self_address().address(),
+ new_port));
+
+ // Register the new FD for epoll events.
+ int new_fd = client_->client()->fd();
+ eps->RegisterFD(new_fd, client_->client(), EPOLLIN | EPOLLOUT | EPOLLET);
+
+ // Send a second request, using the new FD.
+ EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest("/bar"));
+ EXPECT_EQ(200u, client_->response_headers()->parsed_response_code());
+
+ // Verify that the client's ephemeral port is different.
+ IPEndPoint new_address = client_->client()->client_address();
+ EXPECT_EQ(old_address.address(), new_address.address());
+ EXPECT_NE(old_address.port(), new_address.port());
+}
+
+
+TEST_P(EndToEndTest, DifferentFlowControlWindowsQ019) {
+ // TODO(rjshade): Remove this test when removing QUIC_VERSION_19.
+ // Client and server can set different initial flow control receive windows.
+ // These are sent in CHLO/SHLO. Tests that these values are exchanged properly
+ // in the crypto handshake.
+
+ const uint32 kClientIFCW = 123456;
+ set_client_initial_flow_control_receive_window(kClientIFCW);
+
+ const uint32 kServerIFCW = 654321;
+ set_server_initial_flow_control_receive_window(kServerIFCW);
+
+ ASSERT_TRUE(Initialize());
+ if (negotiated_version_ > QUIC_VERSION_19) {
+ return;
+ }
+
+ // Values are exchanged during crypto handshake, so wait for that to finish.
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+ server_thread_->WaitForCryptoHandshakeConfirmed();
+
+ // Client should have the right value for server's receive window.
+ EXPECT_EQ(kServerIFCW, client_->client()
+ ->session()
+ ->config()
+ ->ReceivedInitialFlowControlWindowBytes());
+
+ // Server should have the right value for client's receive window.
+ server_thread_->Pause();
+ QuicDispatcher* dispatcher =
+ QuicServerPeer::GetDispatcher(server_thread_->server());
+ QuicSession* session = dispatcher->session_map().begin()->second;
+ EXPECT_EQ(kClientIFCW,
+ session->config()->ReceivedInitialFlowControlWindowBytes());
+ server_thread_->Resume();
+}
+
+TEST_P(EndToEndTest, DifferentFlowControlWindowsQ020) {
+ // TODO(rjshade): Rename to DifferentFlowControlWindows when removing
+ // QUIC_VERSION_19.
+ // Client and server can set different initial flow control receive windows.
+ // These are sent in CHLO/SHLO. Tests that these values are exchanged properly
+ // in the crypto handshake.
+ const uint32 kClientStreamIFCW = 123456;
+ const uint32 kClientSessionIFCW = 234567;
+ set_client_initial_stream_flow_control_receive_window(kClientStreamIFCW);
+ set_client_initial_session_flow_control_receive_window(kClientSessionIFCW);
+
+ const uint32 kServerStreamIFCW = 654321;
+ const uint32 kServerSessionIFCW = 765432;
+ set_server_initial_stream_flow_control_receive_window(kServerStreamIFCW);
+ set_server_initial_session_flow_control_receive_window(kServerSessionIFCW);
+
+ ASSERT_TRUE(Initialize());
+ if (negotiated_version_ <= QUIC_VERSION_19) {
+ return;
+ }
+
+ // Values are exchanged during crypto handshake, so wait for that to finish.
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+ server_thread_->WaitForCryptoHandshakeConfirmed();
+
+ // Open a data stream to make sure the stream level flow control is updated.
+ QuicSpdyClientStream* stream = client_->GetOrCreateStream();
+ stream->SendBody("hello", false);
+
+ // Client should have the right values for server's receive window.
+ EXPECT_EQ(kServerStreamIFCW,
+ client_->client()
+ ->session()
+ ->config()
+ ->ReceivedInitialStreamFlowControlWindowBytes());
+ EXPECT_EQ(kServerSessionIFCW,
+ client_->client()
+ ->session()
+ ->config()
+ ->ReceivedInitialSessionFlowControlWindowBytes());
+ EXPECT_EQ(kServerStreamIFCW, QuicFlowControllerPeer::SendWindowOffset(
+ stream->flow_controller()));
+ EXPECT_EQ(kServerSessionIFCW,
+ QuicFlowControllerPeer::SendWindowOffset(
+ client_->client()->session()->flow_controller()));
+
+ // Server should have the right values for client's receive window.
+ server_thread_->Pause();
+ QuicDispatcher* dispatcher =
+ QuicServerPeer::GetDispatcher(server_thread_->server());
+ QuicSession* session = dispatcher->session_map().begin()->second;
+ EXPECT_EQ(kClientStreamIFCW,
+ session->config()->ReceivedInitialStreamFlowControlWindowBytes());
+ EXPECT_EQ(kClientSessionIFCW,
+ session->config()->ReceivedInitialSessionFlowControlWindowBytes());
+ EXPECT_EQ(kClientSessionIFCW, QuicFlowControllerPeer::SendWindowOffset(
+ session->flow_controller()));
+ server_thread_->Resume();
+}
+
} // namespace
} // namespace test
} // namespace tools
diff --git a/chromium/net/tools/quic/quic_client.cc b/chromium/net/tools/quic/quic_client.cc
index dcf9612a38f..19e98013af2 100644
--- a/chromium/net/tools/quic/quic_client.cc
+++ b/chromium/net/tools/quic/quic_client.cc
@@ -12,11 +12,14 @@
#include <unistd.h>
#include "base/logging.h"
+#include "net/quic/congestion_control/tcp_receiver.h"
#include "net/quic/crypto/quic_random.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_data_reader.h"
#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_server_id.h"
#include "net/tools/balsa/balsa_headers.h"
+#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
#include "net/tools/quic/quic_socket_utils.h"
#include "net/tools/quic/quic_spdy_client_stream.h"
@@ -31,12 +34,14 @@ namespace tools {
const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET;
QuicClient::QuicClient(IPEndPoint server_address,
- const string& server_hostname,
+ const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
- bool print_response)
+ bool print_response,
+ EpollServer* epoll_server)
: server_address_(server_address),
- server_hostname_(server_hostname),
+ server_id_(server_id),
local_port_(0),
+ epoll_server_(epoll_server),
fd_(-1),
helper_(CreateQuicConnectionHelper()),
initialized_(false),
@@ -48,20 +53,23 @@ QuicClient::QuicClient(IPEndPoint server_address,
}
QuicClient::QuicClient(IPEndPoint server_address,
- const string& server_hostname,
+ const QuicServerId& server_id,
+ const QuicVersionVector& supported_versions,
+ bool print_response,
const QuicConfig& config,
- const QuicVersionVector& supported_versions)
+ EpollServer* epoll_server)
: server_address_(server_address),
- server_hostname_(server_hostname),
+ server_id_(server_id),
config_(config),
local_port_(0),
+ epoll_server_(epoll_server),
fd_(-1),
helper_(CreateQuicConnectionHelper()),
initialized_(false),
packets_dropped_(0),
overflow_supported_(false),
supported_versions_(supported_versions),
- print_response_(false) {
+ print_response_(print_response) {
}
QuicClient::~QuicClient() {
@@ -69,14 +77,27 @@ QuicClient::~QuicClient() {
session()->connection()->SendConnectionClosePacket(
QUIC_PEER_GOING_AWAY, "");
}
+ if (fd_ > 0) {
+ epoll_server_->UnregisterFD(fd_);
+ }
}
bool QuicClient::Initialize() {
DCHECK(!initialized_);
- epoll_server_.set_timeout_in_us(50 * 1000);
+ epoll_server_->set_timeout_in_us(50 * 1000);
crypto_config_.SetDefaults();
+ if (!CreateUDPSocket()) {
+ return false;
+ }
+
+ epoll_server_->RegisterFD(fd_, this, kEpollFlags);
+ initialized_ = true;
+ return true;
+}
+
+bool QuicClient::CreateUDPSocket() {
int address_family = server_address_.GetSockAddrFamily();
fd_ = socket(address_family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
if (fd_ < 0) {
@@ -93,6 +114,16 @@ bool QuicClient::Initialize() {
overflow_supported_ = true;
}
+ if (!QuicSocketUtils::SetReceiveBufferSize(fd_,
+ TcpReceiver::kReceiveWindowTCP)) {
+ return false;
+ }
+
+ if (!QuicSocketUtils::SetSendBufferSize(fd_,
+ TcpReceiver::kReceiveWindowTCP)) {
+ return false;
+ }
+
int get_local_ip = 1;
if (address_family == AF_INET) {
rc = setsockopt(fd_, IPPROTO_IP, IP_PKTINFO,
@@ -137,8 +168,6 @@ bool QuicClient::Initialize() {
LOG(ERROR) << "Unable to get self address. Error: " << strerror(errno);
}
- epoll_server_.RegisterFD(fd_, this, kEpollFlags);
- initialized_ = true;
return true;
}
@@ -153,7 +182,8 @@ bool QuicClient::Connect() {
}
bool QuicClient::StartConnect() {
- DCHECK(!connected() && initialized_);
+ DCHECK(initialized_);
+ DCHECK(!connected());
QuicPacketWriter* writer = CreateQuicPacketWriter();
if (writer_.get() != writer) {
@@ -161,9 +191,9 @@ bool QuicClient::StartConnect() {
}
session_.reset(new QuicClientSession(
- server_hostname_,
+ server_id_,
config_,
- new QuicConnection(GenerateGuid(), server_address_, helper_.get(),
+ new QuicConnection(GenerateConnectionId(), server_address_, helper_.get(),
writer_.get(), false, supported_versions_),
&crypto_config_));
return session_->CryptoConnect();
@@ -180,23 +210,24 @@ void QuicClient::Disconnect() {
if (connected()) {
session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
}
- epoll_server_.UnregisterFD(fd_);
+ epoll_server_->UnregisterFD(fd_);
close(fd_);
fd_ = -1;
initialized_ = false;
}
void QuicClient::SendRequestsAndWaitForResponse(
- const CommandLine::StringVector& args) {
+ const base::CommandLine::StringVector& args) {
for (size_t i = 0; i < args.size(); ++i) {
BalsaHeaders headers;
headers.SetRequestFirstlineFromStringPieces("GET", args[i], "HTTP/1.1");
QuicSpdyClientStream* stream = CreateReliableClientStream();
+ DCHECK(stream != NULL);
stream->SendRequest(headers, "", true);
stream->set_visitor(this);
}
- while (WaitForEvents()) { }
+ while (WaitForEvents()) {}
}
QuicSpdyClientStream* QuicClient::CreateReliableClientStream() {
@@ -210,23 +241,23 @@ QuicSpdyClientStream* QuicClient::CreateReliableClientStream() {
void QuicClient::WaitForStreamToClose(QuicStreamId id) {
DCHECK(connected());
- while (!session_->IsClosedStream(id)) {
- epoll_server_.WaitForEventsAndExecuteCallbacks();
+ while (connected() && !session_->IsClosedStream(id)) {
+ epoll_server_->WaitForEventsAndExecuteCallbacks();
}
}
void QuicClient::WaitForCryptoHandshakeConfirmed() {
DCHECK(connected());
- while (!session_->IsCryptoHandshakeConfirmed()) {
- epoll_server_.WaitForEventsAndExecuteCallbacks();
+ while (connected() && !session_->IsCryptoHandshakeConfirmed()) {
+ epoll_server_->WaitForEventsAndExecuteCallbacks();
}
}
bool QuicClient::WaitForEvents() {
DCHECK(connected());
- epoll_server_.WaitForEventsAndExecuteCallbacks();
+ epoll_server_->WaitForEventsAndExecuteCallbacks();
return session_->num_active_requests() != 0;
}
@@ -238,20 +269,26 @@ void QuicClient::OnEvent(int fd, EpollEvent* event) {
}
}
if (connected() && (event->in_events & EPOLLOUT)) {
+ writer_->SetWritable();
session_->connection()->OnCanWrite();
}
if (event->in_events & EPOLLERR) {
- DLOG(INFO) << "Epollerr";
+ DVLOG(1) << "Epollerr";
}
}
void QuicClient::OnClose(QuicDataStream* stream) {
+ QuicSpdyClientStream* client_stream =
+ static_cast<QuicSpdyClientStream*>(stream);
+ if (response_listener_.get() != NULL) {
+ response_listener_->OnCompleteResponse(
+ stream->id(), client_stream->headers(), client_stream->data());
+ }
+
if (!print_response_) {
return;
}
- QuicSpdyClientStream* client_stream =
- static_cast<QuicSpdyClientStream*>(stream);
const BalsaHeaders& headers = client_stream->headers();
printf("%s\n", headers.first_line().as_string().c_str());
for (BalsaHeaders::const_header_lines_iterator i =
@@ -263,30 +300,32 @@ void QuicClient::OnClose(QuicDataStream* stream) {
printf("%s\n", client_stream->data().c_str());
}
-QuicPacketCreator::Options* QuicClient::options() {
- if (session() == NULL) {
- return NULL;
- }
- return session_->options();
-}
-
bool QuicClient::connected() const {
return session_.get() && session_->connection() &&
session_->connection()->connected();
}
-QuicGuid QuicClient::GenerateGuid() {
+QuicConnectionId QuicClient::GenerateConnectionId() {
return QuicRandom::GetInstance()->RandUint64();
}
QuicEpollConnectionHelper* QuicClient::CreateQuicConnectionHelper() {
- return new QuicEpollConnectionHelper(&epoll_server_);
+ return new QuicEpollConnectionHelper(epoll_server_);
}
QuicPacketWriter* QuicClient::CreateQuicPacketWriter() {
return new QuicDefaultPacketWriter(fd_);
}
+int QuicClient::ReadPacket(char* buffer,
+ int buffer_len,
+ IPEndPoint* server_address,
+ IPAddressNumber* client_ip) {
+ return QuicSocketUtils::ReadPacket(
+ fd_, buffer, buffer_len, overflow_supported_ ? &packets_dropped_ : NULL,
+ client_ip, server_address);
+}
+
bool QuicClient::ReadAndProcessPacket() {
// Allocate some extra space so we can send an error if the server goes over
// the limit.
@@ -295,27 +334,13 @@ bool QuicClient::ReadAndProcessPacket() {
IPEndPoint server_address;
IPAddressNumber client_ip;
- int bytes_read = QuicSocketUtils::ReadPacket(
- fd_, buf, arraysize(buf), overflow_supported_ ? &packets_dropped_ : NULL,
- &client_ip, &server_address);
+ int bytes_read = ReadPacket(buf, arraysize(buf), &server_address, &client_ip);
if (bytes_read < 0) {
return false;
}
QuicEncryptedPacket packet(buf, bytes_read, false);
- QuicGuid our_guid = session_->connection()->guid();
- QuicGuid packet_guid;
-
- if (!QuicFramer::ReadGuidFromPacket(packet, &packet_guid)) {
- DLOG(INFO) << "Could not read GUID from packet";
- return true;
- }
- if (packet_guid != our_guid) {
- DLOG(INFO) << "Ignoring packet from unexpected GUID: "
- << packet_guid << " instead of " << our_guid;
- return true;
- }
IPEndPoint client_address(client_ip, client_address_.port());
session_->connection()->ProcessUdpPacket(
diff --git a/chromium/net/tools/quic/quic_client.h b/chromium/net/tools/quic/quic_client.h
index 02f45e6c56a..13aff636ada 100644
--- a/chromium/net/tools/quic/quic_client.h
+++ b/chromium/net/tools/quic/quic_client.h
@@ -10,6 +10,7 @@
#include <string>
+#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
#include "net/base/ip_endpoint.h"
@@ -24,6 +25,7 @@
namespace net {
class ProofVerifier;
+class QuicServerId;
namespace tools {
@@ -36,14 +38,28 @@ class QuicClientPeer;
class QuicClient : public EpollCallbackInterface,
public QuicDataStream::Visitor {
public:
+ class ResponseListener {
+ public:
+ ResponseListener() {}
+ virtual ~ResponseListener() {}
+ virtual void OnCompleteResponse(QuicStreamId id,
+ const BalsaHeaders& response_headers,
+ const string& response_body) = 0;
+ };
+
+ // Create a quic client, which will have events managed by an externally owned
+ // EpollServer.
QuicClient(IPEndPoint server_address,
- const string& server_hostname,
+ const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
- bool print_response);
+ bool print_response,
+ EpollServer* epoll_server);
QuicClient(IPEndPoint server_address,
- const std::string& server_hostname,
+ const QuicServerId& server_id,
+ const QuicVersionVector& supported_versions,
+ bool print_response,
const QuicConfig& config,
- const QuicVersionVector& supported_versions);
+ EpollServer* epoll_server);
virtual ~QuicClient();
@@ -69,11 +85,12 @@ class QuicClient : public EpollCallbackInterface,
// Disconnects from the QUIC server.
void Disconnect();
- // Sends a request simple GET for each URL in arg, and then waits for
+ // Sends a request simple GET for each URL in |args|, and then waits for
// each to complete.
- void SendRequestsAndWaitForResponse(const CommandLine::StringVector& args);
+ void SendRequestsAndWaitForResponse(const
+ base::CommandLine::StringVector& args);
- // Returns a newly created CreateReliableClientStream, owned by the
+ // Returns a newly created QuicSpdyClientStream, owned by the
// QuicClient.
QuicSpdyClientStream* CreateReliableClientStream();
@@ -88,8 +105,9 @@ class QuicClient : public EpollCallbackInterface,
bool WaitForEvents();
// From EpollCallbackInterface
- virtual void OnRegistration(
- EpollServer* eps, int fd, int event_mask) OVERRIDE {}
+ virtual void OnRegistration(EpollServer* eps,
+ int fd,
+ int event_mask) OVERRIDE {}
virtual void OnModification(int fd, int event_mask) OVERRIDE {}
virtual void OnEvent(int fd, EpollEvent* event) OVERRIDE;
// |fd_| can be unregistered without the client being disconnected. This
@@ -101,8 +119,6 @@ class QuicClient : public EpollCallbackInterface,
// QuicDataStream::Visitor
virtual void OnClose(QuicDataStream* stream) OVERRIDE;
- QuicPacketCreator::Options* options();
-
QuicClientSession* session() { return session_.get(); }
bool connected() const;
@@ -119,13 +135,19 @@ class QuicClient : public EpollCallbackInterface,
const IPEndPoint& client_address() const { return client_address_; }
- EpollServer* epoll_server() { return &epoll_server_; }
+ EpollServer* epoll_server() { return epoll_server_; }
int fd() { return fd_; }
+ const QuicServerId& server_id() const { return server_id_; }
+
// This should only be set before the initial Connect()
- void set_server_hostname(const string& hostname) {
- server_hostname_ = hostname;
+ void set_server_id(const QuicServerId& server_id) {
+ server_id_ = server_id;
+ }
+
+ void SetUserAgentID(const string& user_agent_id) {
+ crypto_config_.set_user_agent_id(user_agent_id);
}
// SetProofVerifier sets the ProofVerifier that will be used to verify the
@@ -135,29 +157,48 @@ class QuicClient : public EpollCallbackInterface,
crypto_config_.SetProofVerifier(verifier);
}
- // SetChannelIDSigner sets a ChannelIDSigner that will be called when the
- // server supports channel IDs to sign a message proving possession of the
- // given ChannelID. This object takes ownership of |signer|.
- void SetChannelIDSigner(ChannelIDSigner* signer) {
- crypto_config_.SetChannelIDSigner(signer);
+ // SetChannelIDSource sets a ChannelIDSource that will be called, when the
+ // server supports channel IDs, to obtain a channel ID for signing a message
+ // proving possession of the channel ID. This object takes ownership of
+ // |source|.
+ void SetChannelIDSource(ChannelIDSource* source) {
+ crypto_config_.SetChannelIDSource(source);
+ }
+
+ void SetSupportedVersions(const QuicVersionVector& versions) {
+ supported_versions_ = versions;
+ }
+
+ // Takes ownership of the listener.
+ void set_response_listener(ResponseListener* listener) {
+ response_listener_.reset(listener);
}
protected:
- virtual QuicGuid GenerateGuid();
+ virtual QuicConnectionId GenerateConnectionId();
virtual QuicEpollConnectionHelper* CreateQuicConnectionHelper();
virtual QuicPacketWriter* CreateQuicPacketWriter();
+ virtual int ReadPacket(char* buffer,
+ int buffer_len,
+ IPEndPoint* server_address,
+ IPAddressNumber* client_ip);
+
private:
friend class net::tools::test::QuicClientPeer;
+ // Used during initialization: creates the UDP socket FD, sets socket options,
+ // and binds the socket to our address.
+ bool CreateUDPSocket();
+
// Read a UDP packet and hand it to the framer.
bool ReadAndProcessPacket();
// Address of the server.
const IPEndPoint server_address_;
- // Hostname of the server. This may be a DNS name or an IP address literal.
- std::string server_hostname_;
+ // |server_id_| is a tuple (hostname, port, is_https) of the server.
+ QuicServerId server_id_;
// config_ and crypto_config_ contain configuration and cached state about
// servers.
@@ -175,13 +216,16 @@ class QuicClient : public EpollCallbackInterface,
// Session which manages streams.
scoped_ptr<QuicClientSession> session_;
// Listens for events on the client socket.
- EpollServer epoll_server_;
+ EpollServer* epoll_server_;
// UDP socket.
int fd_;
// Helper to be used by created connections.
scoped_ptr<QuicEpollConnectionHelper> helper_;
+ // Listens for full responses.
+ scoped_ptr<ResponseListener> response_listener_;
+
// Writer used to actually send packets to the wire.
scoped_ptr<QuicPacketWriter> writer_;
@@ -191,7 +235,7 @@ class QuicClient : public EpollCallbackInterface,
// If overflow_supported_ is true, this will be the number of packets dropped
// during the lifetime of the server. This may overflow if enough packets
// are dropped.
- int packets_dropped_;
+ uint32 packets_dropped_;
// True if the kernel supports SO_RXQ_OVFL, the number of packets dropped
// because the socket would otherwise overflow.
diff --git a/chromium/net/tools/quic/quic_client_bin.cc b/chromium/net/tools/quic/quic_client_bin.cc
index 2f8cfac1736..f743a7dc127 100644
--- a/chromium/net/tools/quic/quic_client_bin.cc
+++ b/chromium/net/tools/quic/quic_client_bin.cc
@@ -4,6 +4,11 @@
// A binary wrapper for QuicClient. Connects to --hostname via --address
// on --port and requests URLs specified on the command line.
+// Pass --secure to check the certificates using proof verifier.
+// Pass --initial_stream_flow_control_window to specify the size of the initial
+// stream flow control receive window to advertise to server.
+// Pass --initial_session_flow_control_window to specify the size of the initial
+// session flow control receive window to advertise to server.
//
// For example:
// quic_client --address=127.0.0.1 --port=6122 --hostname=www.google.com
@@ -16,16 +21,34 @@
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "net/base/ip_endpoint.h"
+#include "net/base/privacy_mode.h"
#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_server_id.h"
+#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_client.h"
+// The port the quic client will connect to.
int32 FLAGS_port = 6121;
std::string FLAGS_address = "127.0.0.1";
+// The hostname the quic client will connect to.
std::string FLAGS_hostname = "localhost";
+// Size of the initial stream flow control receive window to advertise to
+// server.
+int32 FLAGS_initial_stream_flow_control_window = 100 * net::kMaxPacketSize;
+// Size of the initial session flow control receive window to advertise to
+// server.
+int32 FLAGS_initial_session_flow_control_window = 200 * net::kMaxPacketSize;
+// Check the certificates using proof verifier.
+bool FLAGS_secure = false;
int main(int argc, char *argv[]) {
- CommandLine::Init(argc, argv);
- CommandLine* line = CommandLine::ForCurrentProcess();
+ base::CommandLine::Init(argc, argv);
+ base::CommandLine* line = base::CommandLine::ForCurrentProcess();
+
+ logging::LoggingSettings settings;
+ settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
+ CHECK(logging::InitLogging(settings));
+
if (line->HasSwitch("h") || line->HasSwitch("help")) {
const char* help_str =
"Usage: quic_client [options]\n"
@@ -34,7 +57,8 @@ int main(int argc, char *argv[]) {
"-h, --help show this help message and exit\n"
"--port=<port> specify the port to connect to\n"
"--address=<address> specify the IP address to connect to\n"
- "--host=<host> specify the SNI hostname to use\n";
+ "--host=<host> specify the SNI hostname to use\n"
+ "--secure check certificates\n";
std::cout << help_str;
exit(0);
}
@@ -50,18 +74,35 @@ int main(int argc, char *argv[]) {
if (line->HasSwitch("hostname")) {
FLAGS_hostname = line->GetSwitchValueASCII("hostname");
}
- LOG(INFO) << "server port: " << FLAGS_port
- << " address: " << FLAGS_address
- << " hostname: " << FLAGS_hostname;
+ if (line->HasSwitch("secure")) {
+ FLAGS_secure = true;
+ }
+ VLOG(1) << "server port: " << FLAGS_port
+ << " address: " << FLAGS_address
+ << " hostname: " << FLAGS_hostname
+ << " secure: " << FLAGS_secure;
base::AtExitManager exit_manager;
net::IPAddressNumber addr;
CHECK(net::ParseIPLiteralToNumber(FLAGS_address, &addr));
+
+ net::QuicConfig config;
+ config.SetDefaults();
+ config.SetInitialFlowControlWindowToSend(
+ FLAGS_initial_session_flow_control_window);
+ config.SetInitialStreamFlowControlWindowToSend(
+ FLAGS_initial_stream_flow_control_window);
+ config.SetInitialSessionFlowControlWindowToSend(
+ FLAGS_initial_session_flow_control_window);
+
// TODO(rjshade): Set version on command line.
+ net::EpollServer epoll_server;
net::tools::QuicClient client(
- net::IPEndPoint(addr, FLAGS_port), FLAGS_hostname,
- net::QuicSupportedVersions(), true);
+ net::IPEndPoint(addr, FLAGS_port),
+ net::QuicServerId(FLAGS_hostname, FLAGS_port, FLAGS_secure,
+ net::PRIVACY_MODE_DISABLED),
+ net::QuicSupportedVersions(), true, config, &epoll_server);
client.Initialize();
diff --git a/chromium/net/tools/quic/quic_client_session.cc b/chromium/net/tools/quic/quic_client_session.cc
index 5bcf6f201f4..aca5418ac37 100644
--- a/chromium/net/tools/quic/quic_client_session.cc
+++ b/chromium/net/tools/quic/quic_client_session.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "net/quic/crypto/crypto_protocol.h"
+#include "net/quic/quic_server_id.h"
#include "net/tools/quic/quic_spdy_client_stream.h"
using std::string;
@@ -14,30 +15,38 @@ namespace net {
namespace tools {
QuicClientSession::QuicClientSession(
- const string& server_hostname,
+ const QuicServerId& server_id,
const QuicConfig& config,
QuicConnection* connection,
QuicCryptoClientConfig* crypto_config)
- : QuicSession(connection, config),
- crypto_stream_(server_hostname, this, crypto_config) {
+ : QuicClientSessionBase(connection, config),
+ crypto_stream_(server_id, this, NULL, crypto_config) {
}
QuicClientSession::~QuicClientSession() {
}
+void QuicClientSession::OnProofValid(
+ const QuicCryptoClientConfig::CachedState& /*cached*/) {
+}
+
+void QuicClientSession::OnProofVerifyDetailsAvailable(
+ const ProofVerifyDetails& /*verify_details*/) {
+}
+
QuicSpdyClientStream* QuicClientSession::CreateOutgoingDataStream() {
if (!crypto_stream_.encryption_established()) {
- DLOG(INFO) << "Encryption not active so no outgoing stream created.";
+ DVLOG(1) << "Encryption not active so no outgoing stream created.";
return NULL;
}
if (GetNumOpenStreams() >= get_max_open_streams()) {
- DLOG(INFO) << "Failed to create a new outgoing stream. "
- << "Already " << GetNumOpenStreams() << " open.";
+ DVLOG(1) << "Failed to create a new outgoing stream. "
+ << "Already " << GetNumOpenStreams() << " open.";
return NULL;
}
if (goaway_received()) {
- DLOG(INFO) << "Failed to create a new outgoing stream. "
- << "Already received goaway.";
+ DVLOG(1) << "Failed to create a new outgoing stream. "
+ << "Already received goaway.";
return NULL;
}
QuicSpdyClientStream* stream
diff --git a/chromium/net/tools/quic/quic_client_session.h b/chromium/net/tools/quic/quic_client_session.h
index dcee15e4275..3aad445fcd2 100644
--- a/chromium/net/tools/quic/quic_client_session.h
+++ b/chromium/net/tools/quic/quic_client_session.h
@@ -9,26 +9,34 @@
#include <string>
+#include "base/basictypes.h"
+#include "net/quic/quic_client_session_base.h"
#include "net/quic/quic_crypto_client_stream.h"
#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_session.h"
#include "net/tools/quic/quic_spdy_client_stream.h"
namespace net {
class QuicConnection;
+class QuicServerId;
class ReliableQuicStream;
namespace tools {
-class QuicClientSession : public QuicSession {
+class QuicClientSession : public QuicClientSessionBase {
public:
- QuicClientSession(const std::string& server_hostname,
+ QuicClientSession(const QuicServerId& server_id,
const QuicConfig& config,
QuicConnection* connection,
QuicCryptoClientConfig* crypto_config);
virtual ~QuicClientSession();
+ // QuicClientSessionBase methods:
+ virtual void OnProofValid(
+ const QuicCryptoClientConfig::CachedState& cached) OVERRIDE;
+ virtual void OnProofVerifyDetailsAvailable(
+ const ProofVerifyDetails& verify_details) OVERRIDE;
+
// QuicSession methods:
virtual QuicSpdyClientStream* CreateOutgoingDataStream() OVERRIDE;
virtual QuicCryptoClientStream* GetCryptoStream() OVERRIDE;
diff --git a/chromium/net/tools/quic/quic_client_session_test.cc b/chromium/net/tools/quic/quic_client_session_test.cc
index c893c20b5e3..7b50f42ab39 100644
--- a/chromium/net/tools/quic/quic_client_session_test.cc
+++ b/chromium/net/tools/quic/quic_client_session_test.cc
@@ -16,6 +16,7 @@
using net::test::CryptoTestUtils;
using net::test::DefaultQuicConfig;
using net::test::PacketSavingConnection;
+using net::test::SupportedVersions;
using testing::_;
namespace net {
@@ -24,14 +25,20 @@ namespace test {
namespace {
const char kServerHostname[] = "www.example.com";
+const uint16 kPort = 80;
-class ToolsQuicClientSessionTest : public ::testing::Test {
+class ToolsQuicClientSessionTest
+ : public ::testing::TestWithParam<QuicVersion> {
protected:
ToolsQuicClientSessionTest()
- : connection_(new PacketSavingConnection(false)) {
+ : connection_(new PacketSavingConnection(false,
+ SupportedVersions(GetParam()))) {
crypto_config_.SetDefaults();
- session_.reset(new QuicClientSession(kServerHostname, DefaultQuicConfig(),
- connection_, &crypto_config_));
+ session_.reset(new QuicClientSession(
+ QuicServerId(kServerHostname, kPort, false, PRIVACY_MODE_DISABLED),
+ DefaultQuicConfig(),
+ connection_,
+ &crypto_config_));
session_->config()->SetDefaults();
}
@@ -46,11 +53,14 @@ class ToolsQuicClientSessionTest : public ::testing::Test {
QuicCryptoClientConfig crypto_config_;
};
-TEST_F(ToolsQuicClientSessionTest, CryptoConnect) {
+INSTANTIATE_TEST_CASE_P(Tests, ToolsQuicClientSessionTest,
+ ::testing::ValuesIn(QuicSupportedVersions()));
+
+TEST_P(ToolsQuicClientSessionTest, CryptoConnect) {
CompleteCryptoHandshake();
}
-TEST_F(ToolsQuicClientSessionTest, MaxNumStreams) {
+TEST_P(ToolsQuicClientSessionTest, MaxNumStreams) {
session_->config()->set_max_streams_per_connection(1, 1);
// FLAGS_max_streams_per_connection = 1;
// Initialize crypto before the client session will create a stream.
@@ -67,7 +77,7 @@ TEST_F(ToolsQuicClientSessionTest, MaxNumStreams) {
EXPECT_TRUE(stream);
}
-TEST_F(ToolsQuicClientSessionTest, GoAwayReceived) {
+TEST_P(ToolsQuicClientSessionTest, GoAwayReceived) {
CompleteCryptoHandshake();
// After receiving a GoAway, I should no longer be able to create outgoing
diff --git a/chromium/net/tools/quic/quic_default_packet_writer.cc b/chromium/net/tools/quic/quic_default_packet_writer.cc
index 9d3e30831c1..84f118aee00 100644
--- a/chromium/net/tools/quic/quic_default_packet_writer.cc
+++ b/chromium/net/tools/quic/quic_default_packet_writer.cc
@@ -9,22 +9,37 @@
namespace net {
namespace tools {
-QuicDefaultPacketWriter::QuicDefaultPacketWriter(int fd) : fd_(fd) {}
+QuicDefaultPacketWriter::QuicDefaultPacketWriter(int fd)
+ : fd_(fd),
+ write_blocked_(false) {}
QuicDefaultPacketWriter::~QuicDefaultPacketWriter() {}
WriteResult QuicDefaultPacketWriter::WritePacket(
- const char* buffer, size_t buf_len,
- const net::IPAddressNumber& self_address,
- const net::IPEndPoint& peer_address,
- QuicBlockedWriterInterface* blocked_writer) {
- return QuicSocketUtils::WritePacket(fd_, buffer, buf_len,
- self_address, peer_address);
+ const char* buffer,
+ size_t buf_len,
+ const IPAddressNumber& self_address,
+ const IPEndPoint& peer_address) {
+ DCHECK(!IsWriteBlocked());
+ WriteResult result = QuicSocketUtils::WritePacket(
+ fd_, buffer, buf_len, self_address, peer_address);
+ if (result.status == WRITE_STATUS_BLOCKED) {
+ write_blocked_ = true;
+ }
+ return result;
}
bool QuicDefaultPacketWriter::IsWriteBlockedDataBuffered() const {
return false;
}
+bool QuicDefaultPacketWriter::IsWriteBlocked() const {
+ return write_blocked_;
+}
+
+void QuicDefaultPacketWriter::SetWritable() {
+ write_blocked_ = false;
+}
+
} // namespace tools
} // namespace net
diff --git a/chromium/net/tools/quic/quic_default_packet_writer.h b/chromium/net/tools/quic/quic_default_packet_writer.h
index 20f5fb0db61..7b5a36bdce1 100644
--- a/chromium/net/tools/quic/quic_default_packet_writer.h
+++ b/chromium/net/tools/quic/quic_default_packet_writer.h
@@ -11,7 +11,6 @@
namespace net {
-class QuicBlockedWriterInterface;
struct WriteResult;
namespace tools {
@@ -23,15 +22,27 @@ class QuicDefaultPacketWriter : public QuicPacketWriter {
virtual ~QuicDefaultPacketWriter();
// QuicPacketWriter
- virtual WriteResult WritePacket(
- const char* buffer, size_t buf_len,
- const net::IPAddressNumber& self_address,
- const net::IPEndPoint& peer_address,
- QuicBlockedWriterInterface* blocked_writer) OVERRIDE;
+ virtual WriteResult WritePacket(const char* buffer,
+ size_t buf_len,
+ const IPAddressNumber& self_address,
+ const IPEndPoint& peer_address) OVERRIDE;
virtual bool IsWriteBlockedDataBuffered() const OVERRIDE;
+ virtual bool IsWriteBlocked() const OVERRIDE;
+ virtual void SetWritable() OVERRIDE;
+
+ void set_fd(int fd) { fd_ = fd; }
+
+ protected:
+ void set_write_blocked(bool is_blocked) {
+ write_blocked_ = is_blocked;
+ }
+ int fd() { return fd_; }
private:
int fd_;
+ bool write_blocked_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicDefaultPacketWriter);
};
} // namespace tools
diff --git a/chromium/net/tools/quic/quic_dispatcher.cc b/chromium/net/tools/quic/quic_dispatcher.cc
index 297234d9755..b873f98618a 100644
--- a/chromium/net/tools/quic/quic_dispatcher.cc
+++ b/chromium/net/tools/quic/quic_dispatcher.cc
@@ -6,17 +6,23 @@
#include <errno.h>
+#include "base/debug/stack_trace.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "net/quic/quic_blocked_writer_interface.h"
+#include "net/quic/quic_flags.h"
#include "net/quic/quic_utils.h"
+#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_default_packet_writer.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
#include "net/tools/quic/quic_socket_utils.h"
+#include "net/tools/quic/quic_time_wait_list_manager.h"
namespace net {
+
namespace tools {
+using base::StringPiece;
using std::make_pair;
class DeleteSessionsAlarm : public EpollAlarm {
@@ -35,22 +41,140 @@ class DeleteSessionsAlarm : public EpollAlarm {
QuicDispatcher* dispatcher_;
};
+class QuicDispatcher::QuicFramerVisitor : public QuicFramerVisitorInterface {
+ public:
+ explicit QuicFramerVisitor(QuicDispatcher* dispatcher)
+ : dispatcher_(dispatcher),
+ connection_id_(0) {}
+
+ // QuicFramerVisitorInterface implementation
+ virtual void OnPacket() OVERRIDE {}
+ virtual bool OnUnauthenticatedPublicHeader(
+ const QuicPacketPublicHeader& header) OVERRIDE {
+ connection_id_ = header.connection_id;
+ return dispatcher_->OnUnauthenticatedPublicHeader(header);
+ }
+ virtual bool OnUnauthenticatedHeader(
+ const QuicPacketHeader& header) OVERRIDE {
+ dispatcher_->OnUnauthenticatedHeader(header);
+ return false;
+ }
+ virtual void OnError(QuicFramer* framer) OVERRIDE {
+ DVLOG(1) << QuicUtils::ErrorToString(framer->error());
+ }
+
+ virtual bool OnProtocolVersionMismatch(
+ QuicVersion /*received_version*/) OVERRIDE {
+ if (dispatcher_->time_wait_list_manager()->IsConnectionIdInTimeWait(
+ connection_id_)) {
+ // Keep processing after protocol mismatch - this will be dealt with by
+ // the TimeWaitListManager.
+ return true;
+ } else {
+ DLOG(DFATAL) << "Version mismatch, connection ID (" << connection_id_
+ << ") not in time wait list.";
+ return false;
+ }
+ }
+
+ // The following methods should never get called because we always return
+ // false from OnUnauthenticatedHeader(). As a result, we never process the
+ // payload of the packet.
+ virtual void OnPublicResetPacket(
+ const QuicPublicResetPacket& /*packet*/) OVERRIDE {
+ DCHECK(false);
+ }
+ virtual void OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& /*packet*/) OVERRIDE {
+ DCHECK(false);
+ }
+ virtual void OnDecryptedPacket(EncryptionLevel level) OVERRIDE {
+ DCHECK(false);
+ }
+ virtual bool OnPacketHeader(const QuicPacketHeader& /*header*/) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual void OnRevivedPacket() OVERRIDE {
+ DCHECK(false);
+ }
+ virtual void OnFecProtectedPayload(StringPiece /*payload*/) OVERRIDE {
+ DCHECK(false);
+ }
+ virtual bool OnStreamFrame(const QuicStreamFrame& /*frame*/) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual bool OnAckFrame(const QuicAckFrame& /*frame*/) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual bool OnCongestionFeedbackFrame(
+ const QuicCongestionFeedbackFrame& /*frame*/) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual bool OnStopWaitingFrame(
+ const QuicStopWaitingFrame& /*frame*/) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual bool OnPingFrame(const QuicPingFrame& /*frame*/) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual bool OnRstStreamFrame(const QuicRstStreamFrame& /*frame*/) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual bool OnConnectionCloseFrame(
+ const QuicConnectionCloseFrame & /*frame*/) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual bool OnGoAwayFrame(const QuicGoAwayFrame& /*frame*/) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& /*frame*/)
+ OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual bool OnBlockedFrame(const QuicBlockedFrame& frame) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual void OnFecData(const QuicFecData& /*fec*/) OVERRIDE {
+ DCHECK(false);
+ }
+ virtual void OnPacketComplete() OVERRIDE {
+ DCHECK(false);
+ }
+
+ private:
+ QuicDispatcher* dispatcher_;
+
+ // Latched in OnUnauthenticatedPublicHeader for use later.
+ QuicConnectionId connection_id_;
+};
+
QuicDispatcher::QuicDispatcher(const QuicConfig& config,
const QuicCryptoServerConfig& crypto_config,
const QuicVersionVector& supported_versions,
- int fd,
EpollServer* epoll_server)
: config_(config),
crypto_config_(crypto_config),
- time_wait_list_manager_(
- new QuicTimeWaitListManager(this, epoll_server, supported_versions)),
delete_sessions_alarm_(new DeleteSessionsAlarm(this)),
epoll_server_(epoll_server),
- fd_(fd),
- write_blocked_(false),
helper_(new QuicEpollConnectionHelper(epoll_server_)),
- writer_(new QuicDefaultPacketWriter(fd)),
- supported_versions_(supported_versions) {
+ supported_versions_(supported_versions),
+ supported_versions_no_flow_control_(supported_versions),
+ supported_versions_no_connection_flow_control_(supported_versions),
+ current_packet_(NULL),
+ framer_(supported_versions, /*unused*/ QuicTime::Zero(), true),
+ framer_visitor_(new QuicFramerVisitor(this)) {
+ framer_.set_visitor(framer_visitor_.get());
}
QuicDispatcher::~QuicDispatcher() {
@@ -58,89 +182,121 @@ QuicDispatcher::~QuicDispatcher() {
STLDeleteElements(&closed_session_list_);
}
-void QuicDispatcher::set_fd(int fd) {
- fd_ = fd;
- writer_.reset(new QuicDefaultPacketWriter(fd));
-}
+void QuicDispatcher::Initialize(int fd) {
+ DCHECK(writer_ == NULL);
+ writer_.reset(CreateWriter(fd));
+ time_wait_list_manager_.reset(CreateQuicTimeWaitListManager());
-WriteResult QuicDispatcher::WritePacket(const char* buffer, size_t buf_len,
- const IPAddressNumber& self_address,
- const IPEndPoint& peer_address,
- QuicBlockedWriterInterface* writer) {
- if (write_blocked_) {
- write_blocked_list_.insert(make_pair(writer, true));
- return WriteResult(WRITE_STATUS_BLOCKED, EAGAIN);
+ // Remove all versions > QUIC_VERSION_16 from the
+ // supported_versions_no_flow_control_ vector.
+ QuicVersionVector::iterator it =
+ find(supported_versions_no_flow_control_.begin(),
+ supported_versions_no_flow_control_.end(), QUIC_VERSION_17);
+ if (it != supported_versions_no_flow_control_.end()) {
+ supported_versions_no_flow_control_.erase(
+ supported_versions_no_flow_control_.begin(), it + 1);
}
+ CHECK(!supported_versions_no_flow_control_.empty());
- WriteResult result =
- writer_->WritePacket(buffer, buf_len, self_address, peer_address, writer);
- if (result.status == WRITE_STATUS_BLOCKED) {
- write_blocked_list_.insert(make_pair(writer, true));
- write_blocked_ = true;
+ // Remove all versions > QUIC_VERSION_18 from the
+ // supported_versions_no_connection_flow_control_ vector.
+ QuicVersionVector::iterator connection_it = find(
+ supported_versions_no_connection_flow_control_.begin(),
+ supported_versions_no_connection_flow_control_.end(), QUIC_VERSION_19);
+ if (connection_it != supported_versions_no_connection_flow_control_.end()) {
+ supported_versions_no_connection_flow_control_.erase(
+ supported_versions_no_connection_flow_control_.begin(),
+ connection_it + 1);
}
- return result;
-}
-
-bool QuicDispatcher::IsWriteBlockedDataBuffered() const {
- return writer_->IsWriteBlockedDataBuffered();
+ CHECK(!supported_versions_no_connection_flow_control_.empty());
}
void QuicDispatcher::ProcessPacket(const IPEndPoint& server_address,
const IPEndPoint& client_address,
- QuicGuid guid,
- bool has_version_flag,
const QuicEncryptedPacket& packet) {
+ current_server_address_ = server_address;
+ current_client_address_ = client_address;
+ current_packet_ = &packet;
+ // ProcessPacket will cause the packet to be dispatched in
+ // OnUnauthenticatedPublicHeader, or sent to the time wait list manager
+ // in OnAuthenticatedHeader.
+ framer_.ProcessPacket(packet);
+ // TODO(rjshade): Return a status describing if/why a packet was dropped,
+ // and log somehow. Maybe expose as a varz.
+}
+
+bool QuicDispatcher::OnUnauthenticatedPublicHeader(
+ const QuicPacketPublicHeader& header) {
QuicSession* session = NULL;
- SessionMap::iterator it = session_map_.find(guid);
+ QuicConnectionId connection_id = header.connection_id;
+ SessionMap::iterator it = session_map_.find(connection_id);
if (it == session_map_.end()) {
- if (time_wait_list_manager_->IsGuidInTimeWait(guid)) {
- time_wait_list_manager_->ProcessPacket(server_address,
- client_address,
- guid,
- packet);
- return;
+ if (header.reset_flag) {
+ return false;
+ }
+ if (time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)) {
+ return HandlePacketForTimeWait(header);
}
// Ensure the packet has a version negotiation bit set before creating a new
// session for it. All initial packets for a new connection are required to
// have the flag set. Otherwise it may be a stray packet.
- if (has_version_flag) {
- session = CreateQuicSession(guid, server_address, client_address);
+ if (header.version_flag) {
+ session = CreateQuicSession(connection_id, current_server_address_,
+ current_client_address_);
}
if (session == NULL) {
- DLOG(INFO) << "Failed to create session for " << guid;
- // Add this guid fo the time-wait state, to safely reject future packets.
- // We don't know the version here, so assume latest.
- // TODO(ianswett): Produce a no-version version negotiation packet.
- time_wait_list_manager_->AddGuidToTimeWait(guid,
- supported_versions_.front(),
- NULL);
- time_wait_list_manager_->ProcessPacket(server_address,
- client_address,
- guid,
- packet);
- return;
+ DVLOG(1) << "Failed to create session for " << connection_id;
+ // Add this connection_id fo the time-wait state, to safely reject future
+ // packets.
+
+ if (header.version_flag &&
+ !framer_.IsSupportedVersion(header.versions.front())) {
+ // TODO(ianswett): Produce a no-version version negotiation packet.
+ return false;
+ }
+
+ // Use the version in the packet if possible, otherwise assume the latest.
+ QuicVersion version = header.version_flag ? header.versions.front() :
+ supported_versions_.front();
+ time_wait_list_manager_->AddConnectionIdToTimeWait(
+ connection_id, version, NULL);
+ DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id));
+ return HandlePacketForTimeWait(header);
}
- DLOG(INFO) << "Created new session for " << guid;
- session_map_.insert(make_pair(guid, session));
+ DVLOG(1) << "Created new session for " << connection_id;
+ session_map_.insert(make_pair(connection_id, session));
} else {
session = it->second;
}
session->connection()->ProcessUdpPacket(
- server_address, client_address, packet);
+ current_server_address_, current_client_address_, *current_packet_);
+
+ // Do not parse the packet further. The session will process it completely.
+ return false;
+}
+
+void QuicDispatcher::OnUnauthenticatedHeader(const QuicPacketHeader& header) {
+ DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(
+ header.public_header.connection_id));
+ time_wait_list_manager_->ProcessPacket(current_server_address_,
+ current_client_address_,
+ header.public_header.connection_id,
+ header.packet_sequence_number,
+ *current_packet_);
}
void QuicDispatcher::CleanUpSession(SessionMap::iterator it) {
QuicConnection* connection = it->second->connection();
QuicEncryptedPacket* connection_close_packet =
- connection->ReleaseConnectionClosePacket();
+ connection->ReleaseConnectionClosePacket();
write_blocked_list_.erase(connection);
- time_wait_list_manager_->AddGuidToTimeWait(it->first,
- connection->version(),
- connection_close_packet);
+ time_wait_list_manager_->AddConnectionIdToTimeWait(it->first,
+ connection->version(),
+ connection_close_packet);
session_map_.erase(it);
}
@@ -148,37 +304,29 @@ void QuicDispatcher::DeleteSessions() {
STLDeleteElements(&closed_session_list_);
}
-void QuicDispatcher::UseWriter(QuicPacketWriter* writer) {
- writer_.reset(writer);
-}
-
-bool QuicDispatcher::OnCanWrite() {
+void QuicDispatcher::OnCanWrite() {
// We got an EPOLLOUT: the socket should not be blocked.
- write_blocked_ = false;
+ writer_->SetWritable();
// Give each writer one attempt to write.
int num_writers = write_blocked_list_.size();
for (int i = 0; i < num_writers; ++i) {
if (write_blocked_list_.empty()) {
- break;
+ return;
}
- QuicBlockedWriterInterface* writer = write_blocked_list_.begin()->first;
+ QuicBlockedWriterInterface* blocked_writer =
+ write_blocked_list_.begin()->first;
write_blocked_list_.erase(write_blocked_list_.begin());
- bool can_write_more = writer->OnCanWrite();
- if (write_blocked_) {
- // We were unable to write. Wait for the next EPOLLOUT.
- // In this case, the session would have been added to the blocked list
- // up in WritePacket.
- return false;
- }
- // The socket is not blocked but the writer has ceded work. Add it to the
- // end of the list.
- if (can_write_more) {
- write_blocked_list_.insert(make_pair(writer, true));
+ blocked_writer->OnCanWrite();
+ if (writer_->IsWriteBlocked()) {
+ // We were unable to write. Wait for the next EPOLLOUT. The writer is
+ // responsible for adding itself to the blocked list via OnWriteBlocked().
+ return;
}
}
+}
- // We're not write blocked. Return true if there's more work to do.
+bool QuicDispatcher::HasPendingWrites() const {
return !write_blocked_list_.empty();
}
@@ -192,15 +340,19 @@ void QuicDispatcher::Shutdown() {
DeleteSessions();
}
-void QuicDispatcher::OnConnectionClosed(QuicGuid guid, QuicErrorCode error) {
- SessionMap::iterator it = session_map_.find(guid);
+void QuicDispatcher::OnConnectionClosed(QuicConnectionId connection_id,
+ QuicErrorCode error) {
+ SessionMap::iterator it = session_map_.find(connection_id);
if (it == session_map_.end()) {
- LOG(DFATAL) << "GUID " << guid << " does not exist in the session map. "
+ LOG(DFATAL) << "ConnectionId " << connection_id
+ << " does not exist in the session map. "
<< "Error: " << QuicUtils::ErrorToString(error);
+ LOG(DFATAL) << base::debug::StackTrace().ToString();
return;
}
- DLOG_IF(INFO, error != QUIC_NO_ERROR) << "Closing connection (" << guid
+ DLOG_IF(INFO, error != QUIC_NO_ERROR) << "Closing connection ("
+ << connection_id
<< ") due to error: "
<< QuicUtils::ErrorToString(error);
@@ -212,16 +364,75 @@ void QuicDispatcher::OnConnectionClosed(QuicGuid guid, QuicErrorCode error) {
CleanUpSession(it);
}
+void QuicDispatcher::OnWriteBlocked(QuicBlockedWriterInterface* writer) {
+ DCHECK(writer_->IsWriteBlocked());
+ write_blocked_list_.insert(make_pair(writer, true));
+}
+
+QuicPacketWriter* QuicDispatcher::CreateWriter(int fd) {
+ return new QuicDefaultPacketWriter(fd);
+}
+
QuicSession* QuicDispatcher::CreateQuicSession(
- QuicGuid guid,
+ QuicConnectionId connection_id,
const IPEndPoint& server_address,
const IPEndPoint& client_address) {
QuicServerSession* session = new QuicServerSession(
- config_, new QuicConnection(guid, client_address, helper_.get(), this,
- true, supported_versions_), this);
+ config_,
+ CreateQuicConnection(connection_id, server_address, client_address),
+ this);
session->InitializeSession(crypto_config_);
return session;
}
+QuicConnection* QuicDispatcher::CreateQuicConnection(
+ QuicConnectionId connection_id,
+ const IPEndPoint& server_address,
+ const IPEndPoint& client_address) {
+ if (FLAGS_enable_quic_stream_flow_control_2 &&
+ FLAGS_enable_quic_connection_flow_control_2) {
+ DLOG(INFO) << "Creating QuicDispatcher with all versions.";
+ return new QuicConnection(connection_id, client_address, helper_.get(),
+ writer_.get(), true, supported_versions_);
+ }
+
+ if (FLAGS_enable_quic_stream_flow_control_2 &&
+ !FLAGS_enable_quic_connection_flow_control_2) {
+ DLOG(INFO) << "Connection flow control disabled, creating QuicDispatcher "
+ << "WITHOUT version 19 or higher.";
+ return new QuicConnection(connection_id, client_address, helper_.get(),
+ writer_.get(), true,
+ supported_versions_no_connection_flow_control_);
+ }
+
+ DLOG(INFO) << "Flow control disabled, creating QuicDispatcher WITHOUT "
+ << "version 17 or higher.";
+ return new QuicConnection(connection_id, client_address, helper_.get(),
+ writer_.get(), true,
+ supported_versions_no_flow_control_);
+}
+
+QuicTimeWaitListManager* QuicDispatcher::CreateQuicTimeWaitListManager() {
+ return new QuicTimeWaitListManager(
+ writer_.get(), this, epoll_server(), supported_versions());
+}
+
+bool QuicDispatcher::HandlePacketForTimeWait(
+ const QuicPacketPublicHeader& header) {
+ if (header.reset_flag) {
+ // Public reset packets do not have sequence numbers, so ignore the packet.
+ return false;
+ }
+
+ // Switch the framer to the correct version, so that the sequence number can
+ // be parsed correctly.
+ framer_.set_version(time_wait_list_manager_->GetQuicVersionFromConnectionId(
+ header.connection_id));
+
+ // Continue parsing the packet to extract the sequence number. Then
+ // send it to the time wait manager in OnUnathenticatedHeader.
+ return true;
+}
+
} // namespace tools
} // namespace net
diff --git a/chromium/net/tools/quic/quic_dispatcher.h b/chromium/net/tools/quic/quic_dispatcher.h
index 58a4c0c1423..d60ba69883d 100644
--- a/chromium/net/tools/quic/quic_dispatcher.h
+++ b/chromium/net/tools/quic/quic_dispatcher.h
@@ -10,14 +10,13 @@
#include <list>
+#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
#include "base/memory/scoped_ptr.h"
#include "net/base/ip_endpoint.h"
#include "net/base/linked_hash_map.h"
#include "net/quic/quic_blocked_writer_interface.h"
-#include "net/quic/quic_packet_writer.h"
#include "net/quic/quic_protocol.h"
-#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_server_session.h"
#include "net/tools/quic/quic_time_wait_list_manager.h"
@@ -42,6 +41,8 @@ class QuicSession;
namespace tools {
+class QuicPacketWriterWrapper;
+
namespace test {
class QuicDispatcherPeer;
} // namespace test
@@ -49,7 +50,7 @@ class QuicDispatcherPeer;
class DeleteSessionsAlarm;
class QuicEpollConnectionHelper;
-class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner {
+class QuicDispatcher : public QuicServerSessionVisitor {
public:
// Ideally we'd have a linked_hash_set: the boolean is unused.
typedef linked_hash_map<QuicBlockedWriterInterface*, bool> WriteBlockedList;
@@ -60,87 +61,134 @@ class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner {
QuicDispatcher(const QuicConfig& config,
const QuicCryptoServerConfig& crypto_config,
const QuicVersionVector& supported_versions,
- int fd,
EpollServer* epoll_server);
+
virtual ~QuicDispatcher();
- // QuicPacketWriter
- virtual WriteResult WritePacket(
- const char* buffer, size_t buf_len,
- const IPAddressNumber& self_address,
- const IPEndPoint& peer_address,
- QuicBlockedWriterInterface* writer) OVERRIDE;
- virtual bool IsWriteBlockedDataBuffered() const OVERRIDE;
+ virtual void Initialize(int fd);
// Process the incoming packet by creating a new session, passing it to
// an existing session, or passing it to the TimeWaitListManager.
virtual void ProcessPacket(const IPEndPoint& server_address,
const IPEndPoint& client_address,
- QuicGuid guid,
- bool has_version_flag,
const QuicEncryptedPacket& packet);
- // Called when the underyling connection becomes writable to allow
- // queued writes to happen.
- //
- // Returns true if more writes are possible, false otherwise.
- virtual bool OnCanWrite();
+ // Called when the socket becomes writable to allow queued writes to happen.
+ virtual void OnCanWrite();
+
+ // Returns true if there's anything in the blocked writer list.
+ virtual bool HasPendingWrites() const;
// Sends ConnectionClose frames to all connected clients.
void Shutdown();
+ // QuicServerSessionVisitor interface implementation:
// Ensure that the closed connection is cleaned up asynchronously.
- virtual void OnConnectionClosed(QuicGuid guid, QuicErrorCode error) OVERRIDE;
+ virtual void OnConnectionClosed(QuicConnectionId connection_id,
+ QuicErrorCode error) OVERRIDE;
- // Sets the fd and creates a default packet writer with that fd.
- void set_fd(int fd);
+ // Queues the blocked writer for later resumption.
+ virtual void OnWriteBlocked(QuicBlockedWriterInterface* writer) OVERRIDE;
- typedef base::hash_map<QuicGuid, QuicSession*> SessionMap;
-
- virtual QuicSession* CreateQuicSession(
- QuicGuid guid,
- const IPEndPoint& server_address,
- const IPEndPoint& client_address);
+ typedef base::hash_map<QuicConnectionId, QuicSession*> SessionMap;
// Deletes all sessions on the closed session list and clears the list.
void DeleteSessions();
const SessionMap& session_map() const { return session_map_; }
- // Uses the specified |writer| instead of QuicSocketUtils and takes ownership
- // of writer.
- void UseWriter(QuicPacketWriter* writer);
-
WriteBlockedList* write_blocked_list() { return &write_blocked_list_; }
protected:
- const QuicConfig& config_;
- const QuicCryptoServerConfig& crypto_config_;
+ // Instantiates a new low-level packet writer. Caller takes ownership of the
+ // returned object.
+ virtual QuicPacketWriter* CreateWriter(int fd);
+
+ virtual QuicSession* CreateQuicSession(QuicConnectionId connection_id,
+ const IPEndPoint& server_address,
+ const IPEndPoint& client_address);
+
+ virtual QuicConnection* CreateQuicConnection(
+ QuicConnectionId connection_id,
+ const IPEndPoint& server_address,
+ const IPEndPoint& client_address);
+
+ // Called by |framer_visitor_| when the public header has been parsed.
+ virtual bool OnUnauthenticatedPublicHeader(
+ const QuicPacketPublicHeader& header);
+
+ // Create and return the time wait list manager for this dispatcher, which
+ // will be owned by the dispatcher as time_wait_list_manager_
+ virtual QuicTimeWaitListManager* CreateQuicTimeWaitListManager();
+
+ // Replaces the packet writer with |writer|. Takes ownership of |writer|.
+ void set_writer(QuicPacketWriter* writer) {
+ writer_.reset(writer);
+ }
QuicTimeWaitListManager* time_wait_list_manager() {
return time_wait_list_manager_.get();
}
- QuicEpollConnectionHelper* helper() { return helper_.get(); }
EpollServer* epoll_server() { return epoll_server_; }
const QuicVersionVector& supported_versions() const {
return supported_versions_;
}
+ const QuicVersionVector& supported_versions_no_flow_control() const {
+ return supported_versions_no_flow_control_;
+ }
+
+ const QuicVersionVector& supported_versions_no_connection_flow_control()
+ const {
+ return supported_versions_no_connection_flow_control_;
+ }
+
+ const IPEndPoint& current_server_address() {
+ return current_server_address_;
+ }
+ const IPEndPoint& current_client_address() {
+ return current_client_address_;
+ }
+ const QuicEncryptedPacket& current_packet() {
+ return *current_packet_;
+ }
+
+ const QuicConfig& config() const { return config_; }
+
+ const QuicCryptoServerConfig& crypto_config() const { return crypto_config_; }
+
+ QuicFramer* framer() { return &framer_; }
+
+ QuicEpollConnectionHelper* helper() { return helper_.get(); }
+
+ QuicPacketWriter* writer() { return writer_.get(); }
+
private:
+ class QuicFramerVisitor;
friend class net::tools::test::QuicDispatcherPeer;
+ // Called by |framer_visitor_| when the private header has been parsed
+ // of a data packet that is destined for the time wait manager.
+ void OnUnauthenticatedHeader(const QuicPacketHeader& header);
+
// Removes the session from the session map and write blocked list, and
- // adds the GUID to the time-wait list.
+ // adds the ConnectionId to the time-wait list.
void CleanUpSession(SessionMap::iterator it);
+ bool HandlePacketForTimeWait(const QuicPacketPublicHeader& header);
+
+ const QuicConfig& config_;
+
+ const QuicCryptoServerConfig& crypto_config_;
+
// The list of connections waiting to write.
WriteBlockedList write_blocked_list_;
SessionMap session_map_;
- // Entity that manages guids in time wait state.
+ // Entity that manages connection_ids in time wait state.
scoped_ptr<QuicTimeWaitListManager> time_wait_list_manager_;
// An alarm which deletes closed sessions.
@@ -151,13 +199,6 @@ class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner {
EpollServer* epoll_server_; // Owned by the server.
- // The connection for client-server communication
- int fd_;
-
- // True if the session is write blocked due to the socket returning EAGAIN.
- // False if we have gotten a call to OnCanWrite after the last failed write.
- bool write_blocked_;
-
// The helper used for all connections.
scoped_ptr<QuicEpollConnectionHelper> helper_;
@@ -170,6 +211,28 @@ class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner {
// skipped as necessary).
const QuicVersionVector supported_versions_;
+ // Versions which do not support flow control (introduced in QUIC_VERSION_17).
+ // This is used to construct new QuicConnections when flow control is disabled
+ // via flag.
+ // TODO(rjshade): Remove this when
+ // FLAGS_enable_quic_stream_flow_control_2 is removed.
+ QuicVersionVector supported_versions_no_flow_control_;
+ // Versions which do not support *connection* flow control (introduced in
+ // QUIC_VERSION_19).
+ // This is used to construct new QuicConnections when connection flow control
+ // is disabled via flag.
+ // TODO(rjshade): Remove this when
+ // FLAGS_enable_quic_connection_flow_control_2 is removed.
+ QuicVersionVector supported_versions_no_connection_flow_control_;
+
+ // Information about the packet currently being handled.
+ IPEndPoint current_client_address_;
+ IPEndPoint current_server_address_;
+ const QuicEncryptedPacket* current_packet_;
+
+ QuicFramer framer_;
+ scoped_ptr<QuicFramerVisitor> framer_visitor_;
+
DISALLOW_COPY_AND_ASSIGN(QuicDispatcher);
};
diff --git a/chromium/net/tools/quic/quic_dispatcher_test.cc b/chromium/net/tools/quic/quic_dispatcher_test.cc
index 74cab69e6a7..41c3c27946a 100644
--- a/chromium/net/tools/quic/quic_dispatcher_test.cc
+++ b/chromium/net/tools/quic/quic_dispatcher_test.cc
@@ -11,8 +11,11 @@
#include "net/quic/crypto/quic_crypto_server_config.h"
#include "net/quic/crypto/quic_random.h"
#include "net/quic/quic_crypto_stream.h"
+#include "net/quic/quic_flags.h"
+#include "net/quic/quic_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/tools/epoll_server/epoll_server.h"
+#include "net/tools/quic/quic_packet_writer_wrapper.h"
#include "net/tools/quic/quic_time_wait_list_manager.h"
#include "net/tools/quic/test_tools/quic_dispatcher_peer.h"
#include "net/tools/quic/test_tools/quic_test_utils.h"
@@ -21,15 +24,16 @@
using base::StringPiece;
using net::EpollServer;
+using net::test::ConstructEncryptedPacket;
using net::test::MockSession;
+using net::test::ValueRestore;
using net::tools::test::MockConnection;
using std::make_pair;
-using testing::_;
using testing::DoAll;
-using testing::Invoke;
using testing::InSequence;
-using testing::Return;
+using testing::Invoke;
using testing::WithoutArgs;
+using testing::_;
namespace net {
namespace tools {
@@ -41,14 +45,20 @@ class TestDispatcher : public QuicDispatcher {
explicit TestDispatcher(const QuicConfig& config,
const QuicCryptoServerConfig& crypto_config,
EpollServer* eps)
- : QuicDispatcher(config, crypto_config, QuicSupportedVersions(), 1, eps) {
+ : QuicDispatcher(config,
+ crypto_config,
+ QuicSupportedVersions(),
+ eps) {
}
MOCK_METHOD3(CreateQuicSession, QuicSession*(
- QuicGuid guid,
+ QuicConnectionId connection_id,
const IPEndPoint& server_address,
const IPEndPoint& client_address));
using QuicDispatcher::write_blocked_list;
+
+ using QuicDispatcher::current_server_address;
+ using QuicDispatcher::current_client_address;
};
// A Connection class which unregisters the session from the dispatcher
@@ -57,30 +67,31 @@ class TestDispatcher : public QuicDispatcher {
// involve a lot more mocking.
class MockServerConnection : public MockConnection {
public:
- MockServerConnection(QuicGuid guid,
+ MockServerConnection(QuicConnectionId connection_id,
QuicDispatcher* dispatcher)
- : MockConnection(guid, true),
- dispatcher_(dispatcher) {
- }
+ : MockConnection(connection_id, true),
+ dispatcher_(dispatcher) {}
+
void UnregisterOnConnectionClosed() {
- LOG(ERROR) << "Unregistering " << guid();
- dispatcher_->OnConnectionClosed(guid(), QUIC_NO_ERROR);
+ LOG(ERROR) << "Unregistering " << connection_id();
+ dispatcher_->OnConnectionClosed(connection_id(), QUIC_NO_ERROR);
}
private:
QuicDispatcher* dispatcher_;
};
QuicSession* CreateSession(QuicDispatcher* dispatcher,
- QuicGuid guid,
- const IPEndPoint& addr,
+ QuicConnectionId connection_id,
+ const IPEndPoint& client_address,
MockSession** session) {
- MockServerConnection* connection = new MockServerConnection(guid, dispatcher);
+ MockServerConnection* connection =
+ new MockServerConnection(connection_id, dispatcher);
*session = new MockSession(connection);
ON_CALL(*connection, SendConnectionClose(_)).WillByDefault(
WithoutArgs(Invoke(
connection, &MockServerConnection::UnregisterOnConnectionClosed)));
EXPECT_CALL(*reinterpret_cast<MockConnection*>((*session)->connection()),
- ProcessUdpPacket(_, addr, _));
+ ProcessUdpPacket(_, client_address, _));
return *session;
}
@@ -93,6 +104,7 @@ class QuicDispatcherTest : public ::testing::Test {
dispatcher_(config_, crypto_config_, &eps_),
session1_(NULL),
session2_(NULL) {
+ dispatcher_.Initialize(1);
}
virtual ~QuicDispatcherTest() {}
@@ -105,22 +117,25 @@ class QuicDispatcherTest : public ::testing::Test {
return reinterpret_cast<MockConnection*>(session2_->connection());
}
- void ProcessPacket(IPEndPoint addr,
- QuicGuid guid,
+ void ProcessPacket(IPEndPoint client_address,
+ QuicConnectionId connection_id,
bool has_version_flag,
const string& data) {
- dispatcher_.ProcessPacket(
- IPEndPoint(), addr, guid, has_version_flag,
- QuicEncryptedPacket(data.data(), data.length()));
+ scoped_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
+ connection_id, has_version_flag, false, 1, data));
+ data_ = string(packet->data(), packet->length());
+ dispatcher_.ProcessPacket(server_address_, client_address, *packet);
}
void ValidatePacket(const QuicEncryptedPacket& packet) {
- EXPECT_TRUE(packet.AsStringPiece().find(data_) != StringPiece::npos);
+ EXPECT_EQ(data_.length(), packet.AsStringPiece().length());
+ EXPECT_EQ(data_, packet.AsStringPiece());
}
EpollServer eps_;
QuicConfig config_;
QuicCryptoServerConfig crypto_config_;
+ IPEndPoint server_address_;
TestDispatcher dispatcher_;
MockSession* session1_;
MockSession* session2_;
@@ -128,34 +143,39 @@ class QuicDispatcherTest : public ::testing::Test {
};
TEST_F(QuicDispatcherTest, ProcessPackets) {
- IPEndPoint addr(net::test::Loopback4(), 1);
+ IPEndPoint client_address(net::test::Loopback4(), 1);
+ IPAddressNumber any4;
+ CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &any4));
+ server_address_ = IPEndPoint(any4, 5);
- EXPECT_CALL(dispatcher_, CreateQuicSession(1, _, addr))
+ EXPECT_CALL(dispatcher_, CreateQuicSession(1, _, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, 1, addr, &session1_)));
- ProcessPacket(addr, 1, true, "foo");
+ &dispatcher_, 1, client_address, &session1_)));
+ ProcessPacket(client_address, 1, true, "foo");
+ EXPECT_EQ(client_address, dispatcher_.current_client_address());
+ EXPECT_EQ(server_address_, dispatcher_.current_server_address());
- EXPECT_CALL(dispatcher_, CreateQuicSession(2, _, addr))
+
+ EXPECT_CALL(dispatcher_, CreateQuicSession(2, _, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, 2, addr, &session2_)));
- ProcessPacket(addr, 2, true, "bar");
+ &dispatcher_, 2, client_address, &session2_)));
+ ProcessPacket(client_address, 2, true, "bar");
- data_ = "eep";
EXPECT_CALL(*reinterpret_cast<MockConnection*>(session1_->connection()),
ProcessUdpPacket(_, _, _)).Times(1).
WillOnce(testing::WithArgs<2>(Invoke(
this, &QuicDispatcherTest::ValidatePacket)));
- ProcessPacket(addr, 1, false, "eep");
+ ProcessPacket(client_address, 1, false, "eep");
}
TEST_F(QuicDispatcherTest, Shutdown) {
- IPEndPoint addr(net::test::Loopback4(), 1);
+ IPEndPoint client_address(net::test::Loopback4(), 1);
- EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, addr))
+ EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, 1, addr, &session1_)));
+ &dispatcher_, 1, client_address, &session1_)));
- ProcessPacket(addr, 1, true, "foo");
+ ProcessPacket(client_address, 1, true, "foo");
EXPECT_CALL(*reinterpret_cast<MockConnection*>(session1_->connection()),
SendConnectionClose(QUIC_PEER_GOING_AWAY));
@@ -166,34 +186,36 @@ TEST_F(QuicDispatcherTest, Shutdown) {
class MockTimeWaitListManager : public QuicTimeWaitListManager {
public:
MockTimeWaitListManager(QuicPacketWriter* writer,
+ QuicServerSessionVisitor* visitor,
EpollServer* eps)
- : QuicTimeWaitListManager(writer, eps, QuicSupportedVersions()) {
+ : QuicTimeWaitListManager(writer, visitor, eps, QuicSupportedVersions()) {
}
- MOCK_METHOD4(ProcessPacket, void(const IPEndPoint& server_address,
+ MOCK_METHOD5(ProcessPacket, void(const IPEndPoint& server_address,
const IPEndPoint& client_address,
- QuicGuid guid,
+ QuicConnectionId connection_id,
+ QuicPacketSequenceNumber sequence_number,
const QuicEncryptedPacket& packet));
};
TEST_F(QuicDispatcherTest, TimeWaitListManager) {
MockTimeWaitListManager* time_wait_list_manager =
new MockTimeWaitListManager(
- QuicDispatcherPeer::GetWriter(&dispatcher_), &eps_);
+ QuicDispatcherPeer::GetWriter(&dispatcher_), &dispatcher_, &eps_);
// dispatcher takes the ownership of time_wait_list_manager.
QuicDispatcherPeer::SetTimeWaitListManager(&dispatcher_,
time_wait_list_manager);
// Create a new session.
- IPEndPoint addr(net::test::Loopback4(), 1);
- QuicGuid guid = 1;
- EXPECT_CALL(dispatcher_, CreateQuicSession(guid, _, addr))
+ IPEndPoint client_address(net::test::Loopback4(), 1);
+ QuicConnectionId connection_id = 1;
+ EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, _, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, guid, addr, &session1_)));
- ProcessPacket(addr, guid, true, "foo");
+ &dispatcher_, connection_id, client_address, &session1_)));
+ ProcessPacket(client_address, connection_id, true, "foo");
// Close the connection by sending public reset packet.
QuicPublicResetPacket packet;
- packet.public_header.guid = guid;
+ packet.public_header.connection_id = connection_id;
packet.public_header.reset_flag = true;
packet.public_header.version_flag = false;
packet.rejected_sequence_number = 19191;
@@ -209,47 +231,117 @@ TEST_F(QuicDispatcherTest, TimeWaitListManager) {
.WillOnce(Invoke(
reinterpret_cast<MockConnection*>(session1_->connection()),
&MockConnection::ReallyProcessUdpPacket));
- dispatcher_.ProcessPacket(IPEndPoint(), addr, guid, true, *encrypted);
- EXPECT_TRUE(time_wait_list_manager->IsGuidInTimeWait(guid));
-
- // Dispatcher forwards subsequent packets for this guid to the time wait list
- // manager.
- EXPECT_CALL(*time_wait_list_manager, ProcessPacket(_, _, guid, _)).Times(1);
- ProcessPacket(addr, guid, true, "foo");
+ dispatcher_.ProcessPacket(IPEndPoint(), client_address, *encrypted);
+ EXPECT_TRUE(time_wait_list_manager->IsConnectionIdInTimeWait(connection_id));
+
+ // Dispatcher forwards subsequent packets for this connection_id to the time
+ // wait list manager.
+ EXPECT_CALL(*time_wait_list_manager,
+ ProcessPacket(_, _, connection_id, _, _)).Times(1);
+ ProcessPacket(client_address, connection_id, true, "foo");
}
TEST_F(QuicDispatcherTest, StrayPacketToTimeWaitListManager) {
MockTimeWaitListManager* time_wait_list_manager =
new MockTimeWaitListManager(
- QuicDispatcherPeer::GetWriter(&dispatcher_), &eps_);
+ QuicDispatcherPeer::GetWriter(&dispatcher_), &dispatcher_, &eps_);
// dispatcher takes the ownership of time_wait_list_manager.
QuicDispatcherPeer::SetTimeWaitListManager(&dispatcher_,
time_wait_list_manager);
- IPEndPoint addr(net::test::Loopback4(), 1);
- QuicGuid guid = 1;
- // Dispatcher forwards all packets for this guid to the time wait list
- // manager.
+ IPEndPoint client_address(net::test::Loopback4(), 1);
+ QuicConnectionId connection_id = 1;
+ // Dispatcher forwards all packets for this connection_id to the time wait
+ // list manager.
EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, _)).Times(0);
- EXPECT_CALL(*time_wait_list_manager, ProcessPacket(_, _, guid, _)).Times(1);
+ EXPECT_CALL(*time_wait_list_manager,
+ ProcessPacket(_, _, connection_id, _, _)).Times(1);
string data = "foo";
- ProcessPacket(addr, guid, false, "foo");
+ ProcessPacket(client_address, connection_id, false, "foo");
+}
+
+TEST(QuicDispatcherFlowControlTest, NoNewVersion17ConnectionsIfFlagDisabled) {
+ // If FLAGS_enable_quic_stream_flow_control_2 is disabled
+ // then the dispatcher should stop creating connections that support
+ // QUIC_VERSION_17 (existing connections will stay alive).
+ // TODO(rjshade): Remove once
+ // FLAGS_enable_quic_stream_flow_control_2 is removed.
+
+ EpollServer eps;
+ QuicConfig config;
+ QuicCryptoServerConfig server_config(QuicCryptoServerConfig::TESTING,
+ QuicRandom::GetInstance());
+ IPEndPoint client(net::test::Loopback4(), 1);
+ IPEndPoint server(net::test::Loopback4(), 1);
+ QuicConnectionId kCID = 1234;
+
+ QuicVersion kTestQuicVersions[] = {QUIC_VERSION_17,
+ QUIC_VERSION_16,
+ QUIC_VERSION_15};
+ QuicVersionVector kTestVersions;
+ for (size_t i = 0; i < arraysize(kTestQuicVersions); ++i) {
+ kTestVersions.push_back(kTestQuicVersions[i]);
+ }
+
+ QuicDispatcher dispatcher(config, server_config, kTestVersions, &eps);
+ dispatcher.Initialize(0);
+
+ // When flag is enabled, new connections should support QUIC_VERSION_17.
+ ValueRestore<bool> old_flag(&FLAGS_enable_quic_stream_flow_control_2, true);
+ scoped_ptr<QuicConnection> connection_1(
+ QuicDispatcherPeer::CreateQuicConnection(&dispatcher, kCID, client,
+ server));
+ EXPECT_EQ(QUIC_VERSION_17, connection_1->version());
+
+
+ // When flag is disabled, new connections should not support QUIC_VERSION_17.
+ FLAGS_enable_quic_stream_flow_control_2 = false;
+ scoped_ptr<QuicConnection> connection_2(
+ QuicDispatcherPeer::CreateQuicConnection(&dispatcher, kCID, client,
+ server));
+ EXPECT_EQ(QUIC_VERSION_16, connection_2->version());
}
-class QuicWriteBlockedListTest : public QuicDispatcherTest {
+class BlockingWriter : public QuicPacketWriterWrapper {
+ public:
+ BlockingWriter() : write_blocked_(false) {}
+
+ virtual bool IsWriteBlocked() const OVERRIDE { return write_blocked_; }
+ virtual void SetWritable() OVERRIDE { write_blocked_ = false; }
+
+ virtual WriteResult WritePacket(
+ const char* buffer,
+ size_t buf_len,
+ const IPAddressNumber& self_client_address,
+ const IPEndPoint& peer_client_address) OVERRIDE {
+ if (write_blocked_) {
+ return WriteResult(WRITE_STATUS_BLOCKED, EAGAIN);
+ } else {
+ return QuicPacketWriterWrapper::WritePacket(
+ buffer, buf_len, self_client_address, peer_client_address);
+ }
+ }
+
+ bool write_blocked_;
+};
+
+class QuicDispatcherWriteBlockedListTest : public QuicDispatcherTest {
public:
virtual void SetUp() {
- IPEndPoint addr(net::test::Loopback4(), 1);
+ writer_ = new BlockingWriter;
+ QuicDispatcherPeer::UseWriter(&dispatcher_, writer_);
- EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, addr))
+ IPEndPoint client_address(net::test::Loopback4(), 1);
+
+ EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, 1, addr, &session1_)));
- ProcessPacket(addr, 1, true, "foo");
+ &dispatcher_, 1, client_address, &session1_)));
+ ProcessPacket(client_address, 1, true, "foo");
- EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, addr))
+ EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, 2, addr, &session2_)));
- ProcessPacket(addr, 2, true, "bar");
+ &dispatcher_, 2, client_address, &session2_)));
+ ProcessPacket(client_address, 2, true, "bar");
blocked_list_ = dispatcher_.write_blocked_list();
}
@@ -260,90 +352,105 @@ class QuicWriteBlockedListTest : public QuicDispatcherTest {
dispatcher_.Shutdown();
}
- bool SetBlocked() {
- QuicDispatcherPeer::SetWriteBlocked(&dispatcher_);
- return true;
+ void SetBlocked() {
+ writer_->write_blocked_ = true;
+ }
+
+ void BlockConnection2() {
+ writer_->write_blocked_ = true;
+ dispatcher_.OnWriteBlocked(connection2());
}
protected:
+ BlockingWriter* writer_;
QuicDispatcher::WriteBlockedList* blocked_list_;
};
-TEST_F(QuicWriteBlockedListTest, BasicOnCanWrite) {
+TEST_F(QuicDispatcherWriteBlockedListTest, BasicOnCanWrite) {
// No OnCanWrite calls because no connections are blocked.
dispatcher_.OnCanWrite();
- // Register connection 1 for events, and make sure it's nofitied.
- blocked_list_->insert(make_pair(connection1(), true));
+ // Register connection 1 for events, and make sure it's notified.
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection1());
EXPECT_CALL(*connection1(), OnCanWrite());
dispatcher_.OnCanWrite();
// It should get only one notification.
EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
- EXPECT_FALSE(dispatcher_.OnCanWrite());
+ dispatcher_.OnCanWrite();
+ EXPECT_FALSE(dispatcher_.HasPendingWrites());
}
-TEST_F(QuicWriteBlockedListTest, OnCanWriteOrder) {
+TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteOrder) {
// Make sure we handle events in order.
InSequence s;
- blocked_list_->insert(make_pair(connection1(), true));
- blocked_list_->insert(make_pair(connection2(), true));
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_.OnWriteBlocked(connection2());
EXPECT_CALL(*connection1(), OnCanWrite());
EXPECT_CALL(*connection2(), OnCanWrite());
dispatcher_.OnCanWrite();
// Check the other ordering.
- blocked_list_->insert(make_pair(connection2(), true));
- blocked_list_->insert(make_pair(connection1(), true));
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection2());
+ dispatcher_.OnWriteBlocked(connection1());
EXPECT_CALL(*connection2(), OnCanWrite());
EXPECT_CALL(*connection1(), OnCanWrite());
dispatcher_.OnCanWrite();
}
-TEST_F(QuicWriteBlockedListTest, OnCanWriteRemove) {
+TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteRemove) {
// Add and remove one connction.
- blocked_list_->insert(make_pair(connection1(), true));
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection1());
blocked_list_->erase(connection1());
EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
dispatcher_.OnCanWrite();
// Add and remove one connction and make sure it doesn't affect others.
- blocked_list_->insert(make_pair(connection1(), true));
- blocked_list_->insert(make_pair(connection2(), true));
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_.OnWriteBlocked(connection2());
blocked_list_->erase(connection1());
EXPECT_CALL(*connection2(), OnCanWrite());
dispatcher_.OnCanWrite();
// Add it, remove it, and add it back and make sure things are OK.
- blocked_list_->insert(make_pair(connection1(), true));
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection1());
blocked_list_->erase(connection1());
- blocked_list_->insert(make_pair(connection1(), true));
+ dispatcher_.OnWriteBlocked(connection1());
EXPECT_CALL(*connection1(), OnCanWrite()).Times(1);
dispatcher_.OnCanWrite();
}
-TEST_F(QuicWriteBlockedListTest, DoubleAdd) {
+TEST_F(QuicDispatcherWriteBlockedListTest, DoubleAdd) {
// Make sure a double add does not necessitate a double remove.
- blocked_list_->insert(make_pair(connection1(), true));
- blocked_list_->insert(make_pair(connection1(), true));
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_.OnWriteBlocked(connection1());
blocked_list_->erase(connection1());
EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
dispatcher_.OnCanWrite();
// Make sure a double add does not result in two OnCanWrite calls.
- blocked_list_->insert(make_pair(connection1(), true));
- blocked_list_->insert(make_pair(connection1(), true));
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_.OnWriteBlocked(connection1());
EXPECT_CALL(*connection1(), OnCanWrite()).Times(1);
dispatcher_.OnCanWrite();
}
-TEST_F(QuicWriteBlockedListTest, OnCanWriteHandleBlock) {
+TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteHandleBlock) {
// Finally make sure if we write block on a write call, we stop calling.
InSequence s;
- blocked_list_->insert(make_pair(connection1(), true));
- blocked_list_->insert(make_pair(connection2(), true));
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_.OnWriteBlocked(connection2());
EXPECT_CALL(*connection1(), OnCanWrite()).WillOnce(
- Invoke(this, &QuicWriteBlockedListTest::SetBlocked));
+ Invoke(this, &QuicDispatcherWriteBlockedListTest::SetBlocked));
EXPECT_CALL(*connection2(), OnCanWrite()).Times(0);
dispatcher_.OnCanWrite();
@@ -352,34 +459,41 @@ TEST_F(QuicWriteBlockedListTest, OnCanWriteHandleBlock) {
dispatcher_.OnCanWrite();
}
-TEST_F(QuicWriteBlockedListTest, LimitedWrites) {
+TEST_F(QuicDispatcherWriteBlockedListTest, LimitedWrites) {
// Make sure we call both writers. The first will register for more writing
// but should not be immediately called due to limits.
InSequence s;
- blocked_list_->insert(make_pair(connection1(), true));
- blocked_list_->insert(make_pair(connection2(), true));
- EXPECT_CALL(*connection1(), OnCanWrite()).WillOnce(Return(true));
- EXPECT_CALL(*connection2(), OnCanWrite()).WillOnce(Return(false));
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_.OnWriteBlocked(connection2());
+ EXPECT_CALL(*connection1(), OnCanWrite());
+ EXPECT_CALL(*connection2(), OnCanWrite()).WillOnce(
+ Invoke(this, &QuicDispatcherWriteBlockedListTest::BlockConnection2));
dispatcher_.OnCanWrite();
+ EXPECT_TRUE(dispatcher_.HasPendingWrites());
// Now call OnCanWrite again, and connection1 should get its second chance
- EXPECT_CALL(*connection1(), OnCanWrite());
+ EXPECT_CALL(*connection2(), OnCanWrite());
dispatcher_.OnCanWrite();
+ EXPECT_FALSE(dispatcher_.HasPendingWrites());
}
-TEST_F(QuicWriteBlockedListTest, TestWriteLimits) {
+TEST_F(QuicDispatcherWriteBlockedListTest, TestWriteLimits) {
// Finally make sure if we write block on a write call, we stop calling.
InSequence s;
- blocked_list_->insert(make_pair(connection1(), true));
- blocked_list_->insert(make_pair(connection2(), true));
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_.OnWriteBlocked(connection2());
EXPECT_CALL(*connection1(), OnCanWrite()).WillOnce(
- Invoke(this, &QuicWriteBlockedListTest::SetBlocked));
+ Invoke(this, &QuicDispatcherWriteBlockedListTest::SetBlocked));
EXPECT_CALL(*connection2(), OnCanWrite()).Times(0);
dispatcher_.OnCanWrite();
+ EXPECT_TRUE(dispatcher_.HasPendingWrites());
// And we'll resume where we left off when we get another call.
EXPECT_CALL(*connection2(), OnCanWrite());
dispatcher_.OnCanWrite();
+ EXPECT_FALSE(dispatcher_.HasPendingWrites());
}
} // namespace
diff --git a/chromium/net/tools/quic/quic_epoll_clock.h b/chromium/net/tools/quic/quic_epoll_clock.h
index fb21354a9e0..d96bff64389 100644
--- a/chromium/net/tools/quic/quic_epoll_clock.h
+++ b/chromium/net/tools/quic/quic_epoll_clock.h
@@ -5,6 +5,7 @@
#ifndef NET_TOOLS_QUIC_QUIC_EPOLL_CLOCK_H_
#define NET_TOOLS_QUIC_QUIC_EPOLL_CLOCK_H_
+#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "net/quic/quic_clock.h"
#include "net/quic/quic_time.h"
@@ -31,6 +32,9 @@ class QuicEpollClock : public QuicClock {
protected:
EpollServer* epoll_server_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicEpollClock);
};
} // namespace tools
diff --git a/chromium/net/tools/quic/quic_in_memory_cache.cc b/chromium/net/tools/quic/quic_in_memory_cache.cc
index c7c7cd04ebf..af46ca37daa 100644
--- a/chromium/net/tools/quic/quic_in_memory_cache.cc
+++ b/chromium/net/tools/quic/quic_in_memory_cache.cc
@@ -99,7 +99,7 @@ void QuicInMemoryCache::AddSimpleResponse(StringPiece method,
void QuicInMemoryCache::AddResponse(const BalsaHeaders& request_headers,
const BalsaHeaders& response_headers,
StringPiece response_body) {
- LOG(INFO) << "Adding response for: " << GetKey(request_headers);
+ VLOG(1) << "Adding response for: " << GetKey(request_headers);
if (ContainsKey(responses_, GetKey(request_headers))) {
LOG(DFATAL) << "Response for given request already exists!";
return;
@@ -110,6 +110,18 @@ void QuicInMemoryCache::AddResponse(const BalsaHeaders& request_headers,
responses_[GetKey(request_headers)] = new_response;
}
+void QuicInMemoryCache::AddSpecialResponse(StringPiece method,
+ StringPiece path,
+ StringPiece version,
+ SpecialResponseType response_type) {
+ BalsaHeaders request_headers, response_headers;
+ request_headers.SetRequestFirstlineFromStringPieces(method,
+ path,
+ version);
+ AddResponse(request_headers, response_headers, "");
+ responses_[GetKey(request_headers)]->response_type_ = response_type;
+}
+
QuicInMemoryCache::QuicInMemoryCache() {
Initialize();
}
@@ -122,11 +134,11 @@ void QuicInMemoryCache::ResetForTests() {
void QuicInMemoryCache::Initialize() {
// If there's no defined cache dir, we have no initialization to do.
if (FLAGS_quic_in_memory_cache_dir.empty()) {
- LOG(WARNING) << "No cache directory found. Skipping initialization.";
+ VLOG(1) << "No cache directory found. Skipping initialization.";
return;
}
- LOG(INFO) << "Attempting to initialize QuicInMemoryCache from directory: "
- << FLAGS_quic_in_memory_cache_dir;
+ VLOG(1) << "Attempting to initialize QuicInMemoryCache from directory: "
+ << FLAGS_quic_in_memory_cache_dir;
FilePath directory(FLAGS_quic_in_memory_cache_dir);
base::FileEnumerator file_list(directory,
@@ -199,8 +211,8 @@ void QuicInMemoryCache::Initialize() {
"HTTP/1.1");
request_headers.ReplaceOrAppendHeader("host", host);
- LOG(INFO) << "Inserting 'http://" << GetKey(request_headers)
- << "' into QuicInMemoryCache.";
+ VLOG(1) << "Inserting 'http://" << GetKey(request_headers)
+ << "' into QuicInMemoryCache.";
AddResponse(request_headers, response_headers, caching_visitor.body());
@@ -214,6 +226,9 @@ QuicInMemoryCache::~QuicInMemoryCache() {
string QuicInMemoryCache::GetKey(const BalsaHeaders& request_headers) const {
StringPiece uri = request_headers.request_uri();
+ if (uri.size() == 0) {
+ return "";
+ }
StringPiece host;
if (uri[0] == '/') {
host = request_headers.GetHeader("host");
diff --git a/chromium/net/tools/quic/quic_in_memory_cache.h b/chromium/net/tools/quic/quic_in_memory_cache.h
index 3be25a6cac1..be091d5579e 100644
--- a/chromium/net/tools/quic/quic_in_memory_cache.h
+++ b/chromium/net/tools/quic/quic_in_memory_cache.h
@@ -32,12 +32,19 @@ class QuicServer;
// `wget -p --save_headers <url>`
class QuicInMemoryCache {
public:
+ enum SpecialResponseType {
+ REGULAR_RESPONSE, // Send the headers and body like a server should.
+ CLOSE_CONNECTION, // Close the connection (sending the close packet).
+ IGNORE_REQUEST, // Do nothing, expect the client to time out.
+ };
+
// Container for response header/body pairs.
class Response {
public:
- Response() {}
+ Response() : response_type_(REGULAR_RESPONSE) {}
~Response() {}
+ const SpecialResponseType response_type() const { return response_type_; }
const BalsaHeaders& headers() const { return headers_; }
const base::StringPiece body() const { return base::StringPiece(body_); }
@@ -51,6 +58,7 @@ class QuicInMemoryCache {
body.CopyToString(&body_);
}
+ SpecialResponseType response_type_;
BalsaHeaders headers_;
std::string body_;
@@ -79,6 +87,12 @@ class QuicInMemoryCache {
const BalsaHeaders& response_headers,
base::StringPiece response_body);
+ // Simulate a special behavior at a particular path.
+ void AddSpecialResponse(base::StringPiece method,
+ base::StringPiece path,
+ base::StringPiece version,
+ SpecialResponseType response_type);
+
private:
typedef base::hash_map<std::string, Response*> ResponseMap;
friend struct DefaultSingletonTraits<QuicInMemoryCache>;
diff --git a/chromium/net/tools/quic/quic_in_memory_cache_test.cc b/chromium/net/tools/quic/quic_in_memory_cache_test.cc
index adcb59917c5..1d4d24cff9f 100644
--- a/chromium/net/tools/quic/quic_in_memory_cache_test.cc
+++ b/chromium/net/tools/quic/quic_in_memory_cache_test.cc
@@ -39,7 +39,7 @@ class QuicInMemoryCacheTest : public ::testing::Test {
headers->ReplaceOrAppendHeader("host", host);
}
- virtual void SetUp() {
+ virtual void SetUp() OVERRIDE {
QuicInMemoryCachePeer::ResetForTests();
}
diff --git a/chromium/net/tools/quic/quic_packet_writer_wrapper.cc b/chromium/net/tools/quic/quic_packet_writer_wrapper.cc
new file mode 100644
index 00000000000..3d1b03d48e9
--- /dev/null
+++ b/chromium/net/tools/quic/quic_packet_writer_wrapper.cc
@@ -0,0 +1,48 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/tools/quic/quic_packet_writer_wrapper.h"
+
+#include "net/quic/quic_types.h"
+
+namespace net {
+namespace tools {
+
+QuicPacketWriterWrapper::QuicPacketWriterWrapper() {}
+
+QuicPacketWriterWrapper::QuicPacketWriterWrapper(QuicPacketWriter* writer)
+ : writer_(writer) {}
+
+QuicPacketWriterWrapper::~QuicPacketWriterWrapper() {}
+
+WriteResult QuicPacketWriterWrapper::WritePacket(
+ const char* buffer,
+ size_t buf_len,
+ const net::IPAddressNumber& self_address,
+ const net::IPEndPoint& peer_address) {
+ return writer_->WritePacket(buffer, buf_len, self_address, peer_address);
+}
+
+bool QuicPacketWriterWrapper::IsWriteBlockedDataBuffered() const {
+ return writer_->IsWriteBlockedDataBuffered();
+}
+
+bool QuicPacketWriterWrapper::IsWriteBlocked() const {
+ return writer_->IsWriteBlocked();
+}
+
+void QuicPacketWriterWrapper::SetWritable() {
+ writer_->SetWritable();
+}
+
+void QuicPacketWriterWrapper::set_writer(QuicPacketWriter* writer) {
+ writer_.reset(writer);
+}
+
+QuicPacketWriter* QuicPacketWriterWrapper::release_writer() {
+ return writer_.release();
+}
+
+} // namespace tools
+} // namespace net
diff --git a/chromium/net/tools/quic/quic_packet_writer_wrapper.h b/chromium/net/tools/quic/quic_packet_writer_wrapper.h
new file mode 100644
index 00000000000..9dafe776e24
--- /dev/null
+++ b/chromium/net/tools/quic/quic_packet_writer_wrapper.h
@@ -0,0 +1,50 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_TOOLS_QUIC_QUIC_PACKET_WRITER_WRAPPER_H_
+#define NET_TOOLS_QUIC_QUIC_PACKET_WRITER_WRAPPER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "net/quic/quic_packet_writer.h"
+
+namespace net {
+
+namespace tools {
+
+// Wraps a writer object to allow dynamically extending functionality. Use
+// cases: replace writer while dispatcher and connections hold on to the
+// wrapper; mix in monitoring in internal server; mix in mocks in unit tests.
+class QuicPacketWriterWrapper : public net::QuicPacketWriter {
+ public:
+ QuicPacketWriterWrapper();
+ explicit QuicPacketWriterWrapper(QuicPacketWriter* writer);
+ virtual ~QuicPacketWriterWrapper();
+
+ // Default implementation of the QuicPacketWriter interface. Passes everything
+ // to |writer_|.
+ virtual WriteResult WritePacket(
+ const char* buffer,
+ size_t buf_len,
+ const IPAddressNumber& self_address,
+ const IPEndPoint& peer_address) OVERRIDE;
+ virtual bool IsWriteBlockedDataBuffered() const OVERRIDE;
+ virtual bool IsWriteBlocked() const OVERRIDE;
+ virtual void SetWritable() OVERRIDE;
+
+ // Takes ownership of |writer|.
+ void set_writer(QuicPacketWriter* writer);
+
+ // Releases ownership of |writer_|.
+ QuicPacketWriter* release_writer();
+
+ private:
+ scoped_ptr<QuicPacketWriter> writer_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicPacketWriterWrapper);
+};
+
+} // namespace tools
+} // namespace net
+
+#endif // NET_TOOLS_QUIC_QUIC_PACKET_WRITER_WRAPPER_H_
diff --git a/chromium/net/tools/quic/quic_server.cc b/chromium/net/tools/quic/quic_server.cc
index a62cfbbdf15..be3d9fbd128 100644
--- a/chromium/net/tools/quic/quic_server.cc
+++ b/chromium/net/tools/quic/quic_server.cc
@@ -12,6 +12,7 @@
#include <sys/socket.h>
#include "net/base/ip_endpoint.h"
+#include "net/quic/congestion_control/tcp_receiver.h"
#include "net/quic/crypto/crypto_handshake.h"
#include "net/quic/crypto/quic_random.h"
#include "net/quic/quic_clock.h"
@@ -29,6 +30,7 @@
const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET;
static const char kSourceAddressTokenSecret[] = "secret";
+const uint32 kServerInitialFlowControlWindow = 100 * net::kMaxPacketSize;
namespace net {
namespace tools {
@@ -43,9 +45,6 @@ QuicServer::QuicServer()
supported_versions_(QuicSupportedVersions()) {
// Use hardcoded crypto parameters for now.
config_.SetDefaults();
- config_.set_initial_round_trip_time_us(kMaxInitialRoundTripTimeUs, 0);
- config_.set_server_initial_congestion_window(kMaxInitialWindow,
- kDefaultInitialWindow);
Initialize();
}
@@ -76,6 +75,9 @@ void QuicServer::Initialize() {
crypto_config_.AddDefaultConfig(
QuicRandom::GetInstance(), &clock,
QuicCryptoServerConfig::ConfigOptions()));
+
+ // Set flow control options in the config.
+ config_.SetInitialCongestionWindowToSend(kServerInitialFlowControlWindow);
}
QuicServer::~QuicServer() {
@@ -107,6 +109,19 @@ bool QuicServer::Listen(const IPEndPoint& address) {
overflow_supported_ = true;
}
+ // These send and receive buffer sizes are sized for a single connection,
+ // because the default usage of QuicServer is as a test server with one or
+ // two clients. Adjust higher for use with many clients.
+ if (!QuicSocketUtils::SetReceiveBufferSize(fd_,
+ TcpReceiver::kReceiveWindowTCP)) {
+ return false;
+ }
+
+ if (!QuicSocketUtils::SetSendBufferSize(fd_,
+ TcpReceiver::kReceiveWindowTCP)) {
+ return false;
+ }
+
// Enable the socket option that allows the local address to be
// returned if the socket is bound to more than on address.
int get_local_ip = 1;
@@ -133,7 +148,7 @@ bool QuicServer::Listen(const IPEndPoint& address) {
return false;
}
- LOG(INFO) << "Listening on " << address.ToString();
+ DVLOG(1) << "Listening on " << address.ToString();
if (port_ == 0) {
SockaddrStorage storage;
IPEndPoint server_address;
@@ -143,17 +158,24 @@ bool QuicServer::Listen(const IPEndPoint& address) {
return false;
}
port_ = server_address.port();
- LOG(INFO) << "Kernel assigned port is " << port_;
+ DVLOG(1) << "Kernel assigned port is " << port_;
}
epoll_server_.RegisterFD(fd_, this, kEpollFlags);
- dispatcher_.reset(new QuicDispatcher(config_, crypto_config_,
- supported_versions_,
- fd_, &epoll_server_));
+ dispatcher_.reset(CreateQuicDispatcher());
+ dispatcher_->Initialize(fd_);
return true;
}
+QuicDispatcher* QuicServer::CreateQuicDispatcher() {
+ return new QuicDispatcher(
+ config_,
+ crypto_config_,
+ supported_versions_,
+ &epoll_server_);
+}
+
void QuicServer::WaitForEvents() {
epoll_server_.WaitForEventsAndExecuteCallbacks();
}
@@ -172,7 +194,7 @@ void QuicServer::OnEvent(int fd, EpollEvent* event) {
event->out_ready_mask = 0;
if (event->in_events & EPOLLIN) {
- LOG(ERROR) << "EPOLLIN";
+ DVLOG(1) << "EPOLLIN";
bool read = true;
while (read) {
read = ReadAndDispatchSinglePacket(
@@ -181,8 +203,8 @@ void QuicServer::OnEvent(int fd, EpollEvent* event) {
}
}
if (event->in_events & EPOLLOUT) {
- bool can_write_more = dispatcher_->OnCanWrite();
- if (can_write_more) {
+ dispatcher_->OnCanWrite();
+ if (dispatcher_->HasPendingWrites()) {
event->out_ready_mask |= EPOLLOUT;
}
}
@@ -191,25 +213,10 @@ void QuicServer::OnEvent(int fd, EpollEvent* event) {
}
/* static */
-void QuicServer::MaybeDispatchPacket(QuicDispatcher* dispatcher,
- const QuicEncryptedPacket& packet,
- const IPEndPoint& server_address,
- const IPEndPoint& client_address) {
- QuicGuid guid;
- if (!QuicFramer::ReadGuidFromPacket(packet, &guid)) {
- return;
- }
-
- bool has_version_flag = QuicFramer::HasVersionFlag(packet);
-
- dispatcher->ProcessPacket(
- server_address, client_address, guid, has_version_flag, packet);
-}
-
bool QuicServer::ReadAndDispatchSinglePacket(int fd,
int port,
QuicDispatcher* dispatcher,
- int* packets_dropped) {
+ uint32* packets_dropped) {
// Allocate some extra space so we can send an error if the client goes over
// the limit.
char buf[2 * kMaxPacketSize];
@@ -228,7 +235,7 @@ bool QuicServer::ReadAndDispatchSinglePacket(int fd,
QuicEncryptedPacket packet(buf, bytes_read, false);
IPEndPoint server_address(server_ip, port);
- MaybeDispatchPacket(dispatcher, packet, server_address, client_address);
+ dispatcher->ProcessPacket(server_address, client_address, packet);
return true;
}
diff --git a/chromium/net/tools/quic/quic_server.h b/chromium/net/tools/quic/quic_server.h
index 7c8e4054f53..6285fd769d9 100644
--- a/chromium/net/tools/quic/quic_server.h
+++ b/chromium/net/tools/quic/quic_server.h
@@ -8,6 +8,7 @@
#ifndef NET_TOOLS_QUIC_QUIC_SERVER_H_
#define NET_TOOLS_QUIC_QUIC_SERVER_H_
+#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "net/base/ip_endpoint.h"
#include "net/quic/crypto/quic_crypto_server_config.h"
@@ -44,8 +45,9 @@ class QuicServer : public EpollCallbackInterface {
void Shutdown();
// From EpollCallbackInterface
- virtual void OnRegistration(
- EpollServer* eps, int fd, int event_mask) OVERRIDE {}
+ virtual void OnRegistration(EpollServer* eps,
+ int fd,
+ int event_mask) OVERRIDE {}
virtual void OnModification(int fd, int event_mask) OVERRIDE {}
virtual void OnEvent(int fd, EpollEvent* event) OVERRIDE;
virtual void OnUnregistration(int fd, bool replaced) OVERRIDE {}
@@ -58,28 +60,38 @@ class QuicServer : public EpollCallbackInterface {
// dropped packets.
static bool ReadAndDispatchSinglePacket(int fd, int port,
QuicDispatcher* dispatcher,
- int* packets_dropped);
+ uint32* packets_dropped);
virtual void OnShutdown(EpollServer* eps, int fd) OVERRIDE {}
- // Dispatches the given packet only if it looks like a valid QUIC packet.
- // TODO(rjshade): Return a status describing why a packet was dropped, and log
- // somehow. Maybe expose as a varz.
- static void MaybeDispatchPacket(QuicDispatcher* dispatcher,
- const QuicEncryptedPacket& packet,
- const IPEndPoint& server_address,
- const IPEndPoint& client_address);
-
void SetStrikeRegisterNoStartupPeriod() {
crypto_config_.set_strike_register_no_startup_period();
}
+ // SetProofSource sets the ProofSource that will be used to verify the
+ // server's certificate, and takes ownership of |source|.
+ void SetProofSource(ProofSource* source) {
+ crypto_config_.SetProofSource(source);
+ }
+
bool overflow_supported() { return overflow_supported_; }
- int packets_dropped() { return packets_dropped_; }
+ uint32 packets_dropped() { return packets_dropped_; }
int port() { return port_; }
+ protected:
+ virtual QuicDispatcher* CreateQuicDispatcher();
+
+ const QuicConfig& config() const { return config_; }
+ const QuicCryptoServerConfig& crypto_config() const {
+ return crypto_config_;
+ }
+ const QuicVersionVector& supported_versions() const {
+ return supported_versions_;
+ }
+ EpollServer* epoll_server() { return &epoll_server_; }
+
private:
friend class net::tools::test::QuicServerPeer;
@@ -100,7 +112,7 @@ class QuicServer : public EpollCallbackInterface {
// If overflow_supported_ is true this will be the number of packets dropped
// during the lifetime of the server. This may overflow if enough packets
// are dropped.
- int packets_dropped_;
+ uint32 packets_dropped_;
// True if the kernel supports SO_RXQ_OVFL, the number of packets dropped
// because the socket would otherwise overflow.
@@ -121,6 +133,10 @@ class QuicServer : public EpollCallbackInterface {
// skipped as necessary).
QuicVersionVector supported_versions_;
+ // Size of flow control receive window to advertise to clients on new
+ // connections.
+ uint32 server_initial_flow_control_receive_window_;
+
DISALLOW_COPY_AND_ASSIGN(QuicServer);
};
diff --git a/chromium/net/tools/quic/quic_server_bin.cc b/chromium/net/tools/quic/quic_server_bin.cc
index a71cbcf6218..2d349ac4792 100644
--- a/chromium/net/tools/quic/quic_server_bin.cc
+++ b/chromium/net/tools/quic/quic_server_bin.cc
@@ -10,6 +10,7 @@
#include "base/at_exit.h"
#include "base/basictypes.h"
#include "base/command_line.h"
+#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "net/base/ip_endpoint.h"
#include "net/tools/quic/quic_in_memory_cache.h"
@@ -20,8 +21,13 @@
int32 FLAGS_port = 6121;
int main(int argc, char *argv[]) {
- CommandLine::Init(argc, argv);
- CommandLine* line = CommandLine::ForCurrentProcess();
+ base::CommandLine::Init(argc, argv);
+ base::CommandLine* line = base::CommandLine::ForCurrentProcess();
+
+ logging::LoggingSettings settings;
+ settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
+ CHECK(logging::InitLogging(settings));
+
if (line->HasSwitch("h") || line->HasSwitch("help")) {
const char* help_str =
"Usage: quic_server [options]\n"
diff --git a/chromium/net/tools/quic/quic_server_session.cc b/chromium/net/tools/quic/quic_server_session.cc
index dcb112e0204..d7bc3b84e70 100644
--- a/chromium/net/tools/quic/quic_server_session.cc
+++ b/chromium/net/tools/quic/quic_server_session.cc
@@ -12,16 +12,13 @@
namespace net {
namespace tools {
-QuicServerSession::QuicServerSession(
- const QuicConfig& config,
- QuicConnection* connection,
- QuicSessionOwner* owner)
+QuicServerSession::QuicServerSession(const QuicConfig& config,
+ QuicConnection* connection,
+ QuicServerSessionVisitor* visitor)
: QuicSession(connection, config),
- owner_(owner) {
-}
+ visitor_(visitor) {}
-QuicServerSession::~QuicServerSession() {
-}
+QuicServerSession::~QuicServerSession() {}
void QuicServerSession::InitializeSession(
const QuicCryptoServerConfig& crypto_config) {
@@ -36,18 +33,28 @@ QuicCryptoServerStream* QuicServerSession::CreateQuicCryptoServerStream(
void QuicServerSession::OnConnectionClosed(QuicErrorCode error,
bool from_peer) {
QuicSession::OnConnectionClosed(error, from_peer);
- owner_->OnConnectionClosed(connection()->guid(), error);
+ // In the unlikely event we get a connection close while doing an asynchronous
+ // crypto event, make sure we cancel the callback.
+ if (crypto_stream_.get() != NULL) {
+ crypto_stream_->CancelOutstandingCallbacks();
+ }
+ visitor_->OnConnectionClosed(connection()->connection_id(), error);
+}
+
+void QuicServerSession::OnWriteBlocked() {
+ QuicSession::OnWriteBlocked();
+ visitor_->OnWriteBlocked(connection());
}
bool QuicServerSession::ShouldCreateIncomingDataStream(QuicStreamId id) {
if (id % 2 == 0) {
- DLOG(INFO) << "Invalid incoming even stream_id:" << id;
+ DVLOG(1) << "Invalid incoming even stream_id:" << id;
connection()->SendConnectionClose(QUIC_INVALID_STREAM_ID);
return false;
}
if (GetNumOpenStreams() >= get_max_open_streams()) {
- DLOG(INFO) << "Failed to create a new incoming stream with id:" << id
- << " Already " << GetNumOpenStreams() << " open.";
+ DVLOG(1) << "Failed to create a new incoming stream with id:" << id
+ << " Already " << GetNumOpenStreams() << " open.";
connection()->SendConnectionClose(QUIC_TOO_MANY_OPEN_STREAMS);
return false;
}
diff --git a/chromium/net/tools/quic/quic_server_session.h b/chromium/net/tools/quic/quic_server_session.h
index f4705519791..e05ba161d4f 100644
--- a/chromium/net/tools/quic/quic_server_session.h
+++ b/chromium/net/tools/quic/quic_server_session.h
@@ -10,6 +10,7 @@
#include <set>
#include <vector>
+#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
#include "base/memory/scoped_ptr.h"
#include "net/quic/quic_crypto_server_stream.h"
@@ -18,6 +19,7 @@
namespace net {
+class QuicBlockedWriterInterface;
class QuicConfig;
class QuicConnection;
class QuicCryptoServerConfig;
@@ -31,28 +33,33 @@ class QuicServerSessionPeer;
// An interface from the session to the entity owning the session.
// This lets the session notify its owner (the Dispatcher) when the connection
-// is closed.
-class QuicSessionOwner {
+// is closed or blocked.
+class QuicServerSessionVisitor {
public:
- virtual ~QuicSessionOwner() {}
+ virtual ~QuicServerSessionVisitor() {}
- virtual void OnConnectionClosed(QuicGuid guid, QuicErrorCode error) = 0;
+ virtual void OnConnectionClosed(QuicConnectionId connection_id,
+ QuicErrorCode error) = 0;
+ virtual void OnWriteBlocked(QuicBlockedWriterInterface* writer) = 0;
};
class QuicServerSession : public QuicSession {
public:
QuicServerSession(const QuicConfig& config,
- QuicConnection *connection,
- QuicSessionOwner* owner);
+ QuicConnection* connection,
+ QuicServerSessionVisitor* visitor);
// Override the base class to notify the owner of the connection close.
virtual void OnConnectionClosed(QuicErrorCode error, bool from_peer) OVERRIDE;
+ virtual void OnWriteBlocked() OVERRIDE;
virtual ~QuicServerSession();
virtual void InitializeSession(const QuicCryptoServerConfig& crypto_config);
- const QuicCryptoServerStream* crypto_stream() { return crypto_stream_.get(); }
+ const QuicCryptoServerStream* crypto_stream() const {
+ return crypto_stream_.get();
+ }
protected:
// QuicSession methods:
@@ -66,13 +73,13 @@ class QuicServerSession : public QuicSession {
virtual bool ShouldCreateIncomingDataStream(QuicStreamId id);
virtual QuicCryptoServerStream* CreateQuicCryptoServerStream(
- const QuicCryptoServerConfig& crypto_config);
+ const QuicCryptoServerConfig& crypto_config);
private:
friend class test::QuicServerSessionPeer;
scoped_ptr<QuicCryptoServerStream> crypto_stream_;
- QuicSessionOwner* owner_;
+ QuicServerSessionVisitor* visitor_;
DISALLOW_COPY_AND_ASSIGN(QuicServerSession);
};
diff --git a/chromium/net/tools/quic/quic_server_session_test.cc b/chromium/net/tools/quic/quic_server_session_test.cc
index a3dd9968285..1e04a7fd768 100644
--- a/chromium/net/tools/quic/quic_server_session_test.cc
+++ b/chromium/net/tools/quic/quic_server_session_test.cc
@@ -7,10 +7,10 @@
#include "net/quic/crypto/quic_crypto_server_config.h"
#include "net/quic/crypto/quic_random.h"
#include "net/quic/quic_connection.h"
+#include "net/quic/quic_utils.h"
#include "net/quic/test_tools/quic_connection_peer.h"
#include "net/quic/test_tools/quic_data_stream_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_spdy_server_stream.h"
#include "net/tools/quic/test_tools/quic_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -20,8 +20,13 @@ using __gnu_cxx::vector;
using net::test::MockConnection;
using net::test::QuicConnectionPeer;
using net::test::QuicDataStreamPeer;
-using testing::_;
+using net::test::SupportedVersions;
+using net::test::kClientDataStreamId1;
+using net::test::kClientDataStreamId2;
+using net::test::kClientDataStreamId3;
+using net::test::kClientDataStreamId4;
using testing::StrictMock;
+using testing::_;
namespace net {
namespace tools {
@@ -29,206 +34,152 @@ namespace test {
class QuicServerSessionPeer {
public:
- static QuicDataStream* GetIncomingReliableStream(
+ static QuicDataStream* GetIncomingDataStream(
QuicServerSession* s, QuicStreamId id) {
- return s->GetIncomingReliableStream(id);
+ return s->GetIncomingDataStream(id);
}
static QuicDataStream* GetDataStream(QuicServerSession* s, QuicStreamId id) {
return s->GetDataStream(id);
}
};
-class CloseOnDataStream : public QuicDataStream {
- public:
- CloseOnDataStream(QuicStreamId id, QuicSession* session)
- : QuicDataStream(id, session) {
- }
-
- virtual bool OnStreamFrame(const QuicStreamFrame& frame) OVERRIDE {
- session()->MarkDecompressionBlocked(1, id());
- session()->CloseStream(id());
- return true;
- }
-
- virtual uint32 ProcessData(const char* data, uint32 data_len) OVERRIDE {
- return 0;
- }
-};
-
-class TestQuicQuicServerSession : public QuicServerSession {
- public:
- TestQuicQuicServerSession(const QuicConfig& config,
- QuicConnection* connection,
- QuicSessionOwner* owner)
- : QuicServerSession(config, connection, owner),
- close_stream_on_data_(false) {
- }
-
- virtual QuicDataStream* CreateIncomingDataStream(
- QuicStreamId id) OVERRIDE {
- if (!ShouldCreateIncomingDataStream(id)) {
- return NULL;
- }
- if (close_stream_on_data_) {
- return new CloseOnDataStream(id, this);
- } else {
- return new QuicSpdyServerStream(id, this);
- }
- }
-
- void CloseStreamOnData() {
- close_stream_on_data_ = true;
- }
-
- private:
- bool close_stream_on_data_;
-};
-
namespace {
-class QuicServerSessionTest : public ::testing::Test {
+class QuicServerSessionTest : public ::testing::TestWithParam<QuicVersion> {
protected:
QuicServerSessionTest()
: crypto_config_(QuicCryptoServerConfig::TESTING,
QuicRandom::GetInstance()) {
config_.SetDefaults();
config_.set_max_streams_per_connection(3, 3);
-
- connection_ = new MockConnection(true);
- session_.reset(new TestQuicQuicServerSession(
- config_, connection_, &owner_));
+ config_.SetInitialFlowControlWindowToSend(
+ kInitialSessionFlowControlWindowForTest);
+ config_.SetInitialStreamFlowControlWindowToSend(
+ kInitialStreamFlowControlWindowForTest);
+ config_.SetInitialSessionFlowControlWindowToSend(
+ kInitialSessionFlowControlWindowForTest);
+
+ connection_ =
+ new StrictMock<MockConnection>(true, SupportedVersions(GetParam()));
+ session_.reset(new QuicServerSession(config_, connection_, &owner_));
session_->InitializeSession(crypto_config_);
visitor_ = QuicConnectionPeer::GetVisitor(connection_);
}
- void MarkHeadersReadForStream(QuicStreamId id) {
- QuicDataStream* stream = QuicServerSessionPeer::GetDataStream(
- session_.get(), id);
- ASSERT_TRUE(stream != NULL);
- QuicDataStreamPeer::SetHeadersDecompressed(stream, true);
- }
+ QuicVersion version() const { return connection_->version(); }
- StrictMock<MockQuicSessionOwner> owner_;
- MockConnection* connection_;
+ StrictMock<MockQuicServerSessionVisitor> owner_;
+ StrictMock<MockConnection>* connection_;
QuicConfig config_;
QuicCryptoServerConfig crypto_config_;
- scoped_ptr<TestQuicQuicServerSession> session_;
+ scoped_ptr<QuicServerSession> session_;
QuicConnectionVisitorInterface* visitor_;
};
-TEST_F(QuicServerSessionTest, CloseStreamDueToReset) {
+INSTANTIATE_TEST_CASE_P(Tests, QuicServerSessionTest,
+ ::testing::ValuesIn(QuicSupportedVersions()));
+
+TEST_P(QuicServerSessionTest, CloseStreamDueToReset) {
// Open a stream, then reset it.
// Send two bytes of payload to open it.
- QuicStreamFrame data1(3, false, 0, MakeIOVector("HT"));
+ QuicStreamFrame data1(kClientDataStreamId1, false, 0, MakeIOVector("HT"));
vector<QuicStreamFrame> frames;
frames.push_back(data1);
- EXPECT_TRUE(visitor_->OnStreamFrames(frames));
+ session_->OnStreamFrames(frames);
EXPECT_EQ(1u, session_->GetNumOpenStreams());
- // Pretend we got full headers, so we won't trigger the 'unrecoverable
- // compression context' state.
- MarkHeadersReadForStream(3);
-
- // Send a reset.
- QuicRstStreamFrame rst1(3, QUIC_STREAM_NO_ERROR);
+ // Send a reset (and expect the peer to send a RST in response).
+ QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_STREAM_NO_ERROR, 0);
+ EXPECT_CALL(*connection_, SendRstStream(kClientDataStreamId1,
+ QUIC_RST_FLOW_CONTROL_ACCOUNTING, 0));
visitor_->OnRstStream(rst1);
EXPECT_EQ(0u, session_->GetNumOpenStreams());
// Send the same two bytes of payload in a new packet.
- EXPECT_TRUE(visitor_->OnStreamFrames(frames));
+ visitor_->OnStreamFrames(frames);
// The stream should not be re-opened.
EXPECT_EQ(0u, session_->GetNumOpenStreams());
+ EXPECT_TRUE(connection_->connected());
}
-TEST_F(QuicServerSessionTest, NeverOpenStreamDueToReset) {
- // Send a reset.
- QuicRstStreamFrame rst1(3, QUIC_STREAM_NO_ERROR);
+TEST_P(QuicServerSessionTest, NeverOpenStreamDueToReset) {
+ // Send a reset (and expect the peer to send a RST in response).
+ QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_STREAM_NO_ERROR, 0);
+ EXPECT_CALL(*connection_, SendRstStream(kClientDataStreamId1,
+ QUIC_RST_FLOW_CONTROL_ACCOUNTING, 0));
visitor_->OnRstStream(rst1);
EXPECT_EQ(0u, session_->GetNumOpenStreams());
// Send two bytes of payload.
- QuicStreamFrame data1(3, false, 0, MakeIOVector("HT"));
+ QuicStreamFrame data1(kClientDataStreamId1, false, 0, MakeIOVector("HT"));
vector<QuicStreamFrame> frames;
frames.push_back(data1);
-
- // When we get data for the closed stream, it implies the far side has
- // compressed some headers. As a result we're going to bail due to
- // unrecoverable compression context state.
- EXPECT_CALL(*connection_, SendConnectionClose(
- QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED));
- EXPECT_FALSE(visitor_->OnStreamFrames(frames));
+ visitor_->OnStreamFrames(frames);
// The stream should never be opened, now that the reset is received.
EXPECT_EQ(0u, session_->GetNumOpenStreams());
+ EXPECT_TRUE(connection_->connected());
}
-TEST_F(QuicServerSessionTest, GoOverPrematureClosedStreamLimit) {
- QuicStreamFrame data1(3, false, 0, MakeIOVector("H"));
- vector<QuicStreamFrame> frames;
- frames.push_back(data1);
-
- // Set up the stream such that it's open in OnPacket, but closes half way
- // through while on the decompression blocked list.
- session_->CloseStreamOnData();
-
- EXPECT_CALL(*connection_, SendConnectionClose(
- QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED));
- EXPECT_FALSE(visitor_->OnStreamFrames(frames));
-}
-
-TEST_F(QuicServerSessionTest, AcceptClosedStream) {
+TEST_P(QuicServerSessionTest, AcceptClosedStream) {
vector<QuicStreamFrame> frames;
// Send (empty) compressed headers followed by two bytes of data.
- frames.push_back(
- QuicStreamFrame(3, false, 0, MakeIOVector("\1\0\0\0\0\0\0\0HT")));
- frames.push_back(
- QuicStreamFrame(5, false, 0, MakeIOVector("\2\0\0\0\0\0\0\0HT")));
- EXPECT_TRUE(visitor_->OnStreamFrames(frames));
-
- // Pretend we got full headers, so we won't trigger the 'unercoverable
- // compression context' state.
- MarkHeadersReadForStream(3);
-
- // Send a reset.
- QuicRstStreamFrame rst(3, QUIC_STREAM_NO_ERROR);
+ frames.push_back(QuicStreamFrame(kClientDataStreamId1, false, 0,
+ MakeIOVector("\1\0\0\0\0\0\0\0HT")));
+ frames.push_back(QuicStreamFrame(kClientDataStreamId2, false, 0,
+ MakeIOVector("\2\0\0\0\0\0\0\0HT")));
+ visitor_->OnStreamFrames(frames);
+ EXPECT_EQ(2u, session_->GetNumOpenStreams());
+
+ // Send a reset (and expect the peer to send a RST in response).
+ QuicRstStreamFrame rst(kClientDataStreamId1, QUIC_STREAM_NO_ERROR, 0);
+ EXPECT_CALL(*connection_, SendRstStream(kClientDataStreamId1,
+ QUIC_RST_FLOW_CONTROL_ACCOUNTING, 0));
visitor_->OnRstStream(rst);
// If we were tracking, we'd probably want to reject this because it's data
// past the reset point of stream 3. As it's a closed stream we just drop the
// data on the floor, but accept the packet because it has data for stream 5.
frames.clear();
- frames.push_back(QuicStreamFrame(3, false, 2, MakeIOVector("TP")));
- frames.push_back(QuicStreamFrame(5, false, 2, MakeIOVector("TP")));
- EXPECT_TRUE(visitor_->OnStreamFrames(frames));
+ frames.push_back(
+ QuicStreamFrame(kClientDataStreamId1, false, 2, MakeIOVector("TP")));
+ frames.push_back(
+ QuicStreamFrame(kClientDataStreamId2, false, 2, MakeIOVector("TP")));
+ visitor_->OnStreamFrames(frames);
+ // The stream should never be opened, now that the reset is received.
+ EXPECT_EQ(1u, session_->GetNumOpenStreams());
+ EXPECT_TRUE(connection_->connected());
}
-TEST_F(QuicServerSessionTest, MaxNumConnections) {
+TEST_P(QuicServerSessionTest, MaxNumConnections) {
EXPECT_EQ(0u, session_->GetNumOpenStreams());
- EXPECT_TRUE(
- QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 3));
- EXPECT_TRUE(
- QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 5));
- EXPECT_TRUE(
- QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 7));
- EXPECT_FALSE(
- QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 9));
+ EXPECT_TRUE(QuicServerSessionPeer::GetIncomingDataStream(
+ session_.get(), kClientDataStreamId1));
+ EXPECT_TRUE(QuicServerSessionPeer::GetIncomingDataStream(
+ session_.get(), kClientDataStreamId2));
+ EXPECT_TRUE(QuicServerSessionPeer::GetIncomingDataStream(
+ session_.get(), kClientDataStreamId3));
+ EXPECT_CALL(*connection_, SendConnectionClose(QUIC_TOO_MANY_OPEN_STREAMS));
+ EXPECT_FALSE(QuicServerSessionPeer::GetIncomingDataStream(
+ session_.get(), kClientDataStreamId4));
}
-TEST_F(QuicServerSessionTest, MaxNumConnectionsImplicit) {
+TEST_P(QuicServerSessionTest, MaxNumConnectionsImplicit) {
EXPECT_EQ(0u, session_->GetNumOpenStreams());
- EXPECT_TRUE(
- QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 3));
- // Implicitly opens two more streams before 9.
- EXPECT_FALSE(
- QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 9));
+ EXPECT_TRUE(QuicServerSessionPeer::GetIncomingDataStream(
+ session_.get(), kClientDataStreamId1));
+ // Implicitly opens two more streams.
+ EXPECT_CALL(*connection_, SendConnectionClose(QUIC_TOO_MANY_OPEN_STREAMS));
+ EXPECT_FALSE(QuicServerSessionPeer::GetIncomingDataStream(
+ session_.get(), kClientDataStreamId4));
}
-TEST_F(QuicServerSessionTest, GetEvenIncomingError) {
+TEST_P(QuicServerSessionTest, GetEvenIncomingError) {
// Incoming streams on the server session must be odd.
+ EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_STREAM_ID));
EXPECT_EQ(NULL,
- QuicServerSessionPeer::GetIncomingReliableStream(
- session_.get(), 2));
+ QuicServerSessionPeer::GetIncomingDataStream(session_.get(), 4));
}
} // namespace
diff --git a/chromium/net/tools/quic/quic_server_test.cc b/chromium/net/tools/quic/quic_server_test.cc
index 7d24edc28bb..e2d7c4f3288 100644
--- a/chromium/net/tools/quic/quic_server_test.cc
+++ b/chromium/net/tools/quic/quic_server_test.cc
@@ -21,13 +21,13 @@ class QuicServerDispatchPacketTest : public ::testing::Test {
public:
QuicServerDispatchPacketTest()
: crypto_config_("blah", QuicRandom::GetInstance()),
- dispatcher_(config_, crypto_config_, 1234, &eps_) {}
-
+ dispatcher_(config_, crypto_config_, &eps_) {
+ dispatcher_.Initialize(1234);
+ }
- void MaybeDispatchPacket(const QuicEncryptedPacket& packet) {
+ void DispatchPacket(const QuicEncryptedPacket& packet) {
IPEndPoint client_addr, server_addr;
- QuicServer::MaybeDispatchPacket(&dispatcher_, packet,
- client_addr, server_addr);
+ dispatcher_.ProcessPacket(server_addr, client_addr, packet);
}
protected:
@@ -37,23 +37,11 @@ class QuicServerDispatchPacketTest : public ::testing::Test {
MockQuicDispatcher dispatcher_;
};
-TEST_F(QuicServerDispatchPacketTest, DoNotDispatchPacketWithoutGUID) {
- // Packet too short to be considered valid.
- unsigned char invalid_packet[] = { 0x00 };
- QuicEncryptedPacket encrypted_invalid_packet(
- QuicUtils::AsChars(invalid_packet), arraysize(invalid_packet), false);
-
- // We expect the invalid packet to be dropped, and ProcessPacket should never
- // be called.
- EXPECT_CALL(dispatcher_, ProcessPacket(_, _, _, _, _)).Times(0);
- MaybeDispatchPacket(encrypted_invalid_packet);
-}
-
-TEST_F(QuicServerDispatchPacketTest, DispatchValidPacket) {
+TEST_F(QuicServerDispatchPacketTest, DispatchPacket) {
unsigned char valid_packet[] = {
- // public flags (8 byte guid)
+ // public flags (8 byte connection_id)
0x3C,
- // guid
+ // connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet sequence number
@@ -64,8 +52,8 @@ TEST_F(QuicServerDispatchPacketTest, DispatchValidPacket) {
QuicEncryptedPacket encrypted_valid_packet(QuicUtils::AsChars(valid_packet),
arraysize(valid_packet), false);
- EXPECT_CALL(dispatcher_, ProcessPacket(_, _, _, _, _)).Times(1);
- MaybeDispatchPacket(encrypted_valid_packet);
+ EXPECT_CALL(dispatcher_, ProcessPacket(_, _, _)).Times(1);
+ DispatchPacket(encrypted_valid_packet);
}
} // namespace
diff --git a/chromium/net/tools/quic/quic_socket_utils.cc b/chromium/net/tools/quic/quic_socket_utils.cc
index 87071a681ae..3202150917b 100644
--- a/chromium/net/tools/quic/quic_socket_utils.cc
+++ b/chromium/net/tools/quic/quic_socket_utils.cc
@@ -11,6 +11,7 @@
#include <sys/uio.h>
#include <string>
+#include "base/basictypes.h"
#include "base/logging.h"
#include "net/quic/quic_protocol.h"
@@ -51,7 +52,7 @@ IPAddressNumber QuicSocketUtils::GetAddressFromMsghdr(struct msghdr *hdr) {
// static
bool QuicSocketUtils::GetOverflowFromMsghdr(struct msghdr *hdr,
- int *dropped_packets) {
+ uint32 *dropped_packets) {
if (hdr->msg_controllen > 0) {
struct cmsghdr *cmsg;
for (cmsg = CMSG_FIRSTHDR(hdr);
@@ -79,8 +80,26 @@ int QuicSocketUtils::SetGetAddressInfo(int fd, int address_family) {
}
// static
+bool QuicSocketUtils::SetSendBufferSize(int fd, size_t size) {
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) != 0) {
+ LOG(ERROR) << "Failed to set socket send size";
+ return false;
+ }
+ return true;
+}
+
+// static
+bool QuicSocketUtils::SetReceiveBufferSize(int fd, size_t size) {
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) != 0) {
+ LOG(ERROR) << "Failed to set socket recv size";
+ return false;
+ }
+ return true;
+}
+
+// static
int QuicSocketUtils::ReadPacket(int fd, char* buffer, size_t buf_len,
- int* dropped_packets,
+ uint32* dropped_packets,
IPAddressNumber* self_address,
IPEndPoint* peer_address) {
CHECK(peer_address != NULL);
@@ -135,6 +154,28 @@ int QuicSocketUtils::ReadPacket(int fd, char* buffer, size_t buf_len,
return bytes_read;
}
+size_t QuicSocketUtils::SetIpInfoInCmsg(const IPAddressNumber& self_address,
+ cmsghdr* cmsg) {
+ if (GetAddressFamily(self_address) == ADDRESS_FAMILY_IPV4) {
+ cmsg->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
+ cmsg->cmsg_level = IPPROTO_IP;
+ cmsg->cmsg_type = IP_PKTINFO;
+ in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg));
+ memset(pktinfo, 0, sizeof(in_pktinfo));
+ pktinfo->ipi_ifindex = 0;
+ memcpy(&pktinfo->ipi_spec_dst, &self_address[0], self_address.size());
+ return sizeof(in_pktinfo);
+ } else {
+ cmsg->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
+ cmsg->cmsg_level = IPPROTO_IPV6;
+ cmsg->cmsg_type = IPV6_PKTINFO;
+ in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg));
+ memset(pktinfo, 0, sizeof(in6_pktinfo));
+ memcpy(&pktinfo->ipi6_addr, &self_address[0], self_address.size());
+ return sizeof(in6_pktinfo);
+ }
+}
+
// static
WriteResult QuicSocketUtils::WritePacket(int fd,
const char* buffer,
@@ -164,30 +205,11 @@ WriteResult QuicSocketUtils::WritePacket(int fd,
if (self_address.empty()) {
hdr.msg_control = 0;
hdr.msg_controllen = 0;
- } else if (GetAddressFamily(self_address) == ADDRESS_FAMILY_IPV4) {
- hdr.msg_control = cbuf;
- hdr.msg_controllen = kSpaceForIp;
- cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
-
- cmsg->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
- cmsg->cmsg_level = IPPROTO_IP;
- cmsg->cmsg_type = IP_PKTINFO;
- in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg));
- memset(pktinfo, 0, sizeof(in_pktinfo));
- pktinfo->ipi_ifindex = 0;
- memcpy(&pktinfo->ipi_spec_dst, &self_address[0], self_address.size());
- hdr.msg_controllen = cmsg->cmsg_len;
} else {
hdr.msg_control = cbuf;
hdr.msg_controllen = kSpaceForIp;
- cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
-
- cmsg->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
- cmsg->cmsg_level = IPPROTO_IPV6;
- cmsg->cmsg_type = IPV6_PKTINFO;
- in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg));
- memset(pktinfo, 0, sizeof(in6_pktinfo));
- memcpy(&pktinfo->ipi6_addr, &self_address[0], self_address.size());
+ cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr);
+ SetIpInfoInCmsg(self_address, cmsg);
hdr.msg_controllen = cmsg->cmsg_len;
}
diff --git a/chromium/net/tools/quic/quic_socket_utils.h b/chromium/net/tools/quic/quic_socket_utils.h
index 8f0feffced2..03b95e5179e 100644
--- a/chromium/net/tools/quic/quic_socket_utils.h
+++ b/chromium/net/tools/quic/quic_socket_utils.h
@@ -11,8 +11,9 @@
#include <sys/socket.h>
#include <string>
+#include "base/basictypes.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_types.h"
namespace net {
namespace tools {
@@ -26,12 +27,19 @@ class QuicSocketUtils {
// If the msghdr contains an SO_RXQ_OVFL entry, this will set dropped_packets
// to the correct value and return true. Otherwise it will return false.
- static bool GetOverflowFromMsghdr(struct msghdr *hdr, int *dropped_packets);
+ static bool GetOverflowFromMsghdr(struct msghdr *hdr,
+ uint32 *dropped_packets);
// Sets either IP_PKTINFO or IPV6_PKTINFO on the socket, based on
// address_family. Returns the return code from setsockopt.
static int SetGetAddressInfo(int fd, int address_family);
+ // Sets the send buffer size to |size| and returns false if it fails.
+ static bool SetSendBufferSize(int fd, size_t size);
+
+ // Sets the receive buffer size to |size| and returns false if it fails.
+ static bool SetReceiveBufferSize(int fd, size_t size);
+
// Reads buf_len from the socket. If reading is successful, returns bytes
// read and sets peer_address to the peer address. Otherwise returns -1.
//
@@ -41,8 +49,10 @@ class QuicSocketUtils {
//
// If self_address is non-null, it will be set to the address the peer sent
// packets to, assuming a packet was read.
- static int ReadPacket(int fd, char* buffer, size_t buf_len,
- int* dropped_packets,
+ static int ReadPacket(int fd,
+ char* buffer,
+ size_t buf_len,
+ uint32* dropped_packets,
IPAddressNumber* self_address,
IPEndPoint* peer_address);
@@ -50,9 +60,20 @@ class QuicSocketUtils {
// status to WRITE_STATUS_OK and sets bytes_written. Otherwise sets the
// result's status to WRITE_STATUS_BLOCKED or WRITE_STATUS_ERROR and sets
// error_code to errno.
- static WriteResult WritePacket(int fd, const char* buffer, size_t buf_len,
+ static WriteResult WritePacket(int fd,
+ const char* buffer,
+ size_t buf_len,
const IPAddressNumber& self_address,
const IPEndPoint& peer_address);
+
+ // A helper for WritePacket which fills in the cmsg with the supplied self
+ // address.
+ // Returns the length of the packet info structure used.
+ static size_t SetIpInfoInCmsg(const IPAddressNumber& self_address,
+ cmsghdr* cmsg);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicSocketUtils);
};
} // namespace tools
diff --git a/chromium/net/tools/quic/quic_spdy_client_stream.cc b/chromium/net/tools/quic/quic_spdy_client_stream.cc
index 1956c7940db..8423295a1ac 100644
--- a/chromium/net/tools/quic/quic_spdy_client_stream.cc
+++ b/chromium/net/tools/quic/quic_spdy_client_stream.cc
@@ -20,7 +20,9 @@ QuicSpdyClientStream::QuicSpdyClientStream(QuicStreamId id,
QuicClientSession* session)
: QuicDataStream(id, session),
read_buf_(new GrowableIOBuffer()),
- response_headers_received_(false) {
+ response_headers_received_(false),
+ header_bytes_read_(0),
+ header_bytes_written_(0) {
}
QuicSpdyClientStream::~QuicSpdyClientStream() {
@@ -28,29 +30,37 @@ QuicSpdyClientStream::~QuicSpdyClientStream() {
bool QuicSpdyClientStream::OnStreamFrame(const QuicStreamFrame& frame) {
if (!write_side_closed()) {
- DLOG(INFO) << "Got a response before the request was complete. "
- << "Aborting request.";
+ DVLOG(1) << "Got a response before the request was complete. "
+ << "Aborting request.";
CloseWriteSide();
}
return QuicDataStream::OnStreamFrame(frame);
}
-uint32 QuicSpdyClientStream::ProcessData(const char* data, uint32 length) {
- uint32 total_bytes_processed = 0;
+void QuicSpdyClientStream::OnStreamHeadersComplete(bool fin,
+ size_t frame_len) {
+ header_bytes_read_ = frame_len;
+ QuicDataStream::OnStreamHeadersComplete(fin, frame_len);
+}
+
+uint32 QuicSpdyClientStream::ProcessData(const char* data,
+ uint32 data_len) {
+ int total_bytes_processed = 0;
// Are we still reading the response headers.
if (!response_headers_received_) {
// Grow the read buffer if necessary.
- if (read_buf_->RemainingCapacity() < (int)length) {
+ if (read_buf_->RemainingCapacity() < (int)data_len) {
read_buf_->SetCapacity(read_buf_->capacity() + kHeaderBufInitialSize);
}
- memcpy(read_buf_->data(), data, length);
- read_buf_->set_offset(read_buf_->offset() + length);
+ memcpy(read_buf_->data(), data, data_len);
+ read_buf_->set_offset(read_buf_->offset() + data_len);
ParseResponseHeaders();
} else {
- data_.append(data + total_bytes_processed, length - total_bytes_processed);
+ data_.append(data + total_bytes_processed,
+ data_len - total_bytes_processed);
}
- return length;
+ return data_len;
}
void QuicSpdyClientStream::OnFinRead() {
@@ -71,15 +81,16 @@ ssize_t QuicSpdyClientStream::SendRequest(const BalsaHeaders& headers,
SpdyUtils::RequestHeadersToSpdyHeaders(headers);
bool send_fin_with_headers = fin && body.empty();
- string headers_string = session()->compressor()->CompressHeadersWithPriority(
- priority(), header_block);
- WriteOrBufferData(headers_string, send_fin_with_headers);
+ size_t bytes_sent = body.size();
+ header_bytes_written_ = WriteHeaders(
+ header_block, send_fin_with_headers, NULL);
+ bytes_sent += header_bytes_written_;
if (!body.empty()) {
- WriteOrBufferData(body, fin);
+ WriteOrBufferData(body, fin, NULL);
}
- return headers_string.size() + body.size();
+ return bytes_sent;
}
int QuicSpdyClientStream::ParseResponseHeaders() {
@@ -109,7 +120,7 @@ int QuicSpdyClientStream::ParseResponseHeaders() {
// Sends body data to the server and returns the number of bytes sent.
void QuicSpdyClientStream::SendBody(const string& data, bool fin) {
- return WriteOrBufferData(data, fin);
+ WriteOrBufferData(data, fin, NULL);
}
} // namespace tools
diff --git a/chromium/net/tools/quic/quic_spdy_client_stream.h b/chromium/net/tools/quic/quic_spdy_client_stream.h
index 2b17205f53e..1292e197603 100644
--- a/chromium/net/tools/quic/quic_spdy_client_stream.h
+++ b/chromium/net/tools/quic/quic_spdy_client_stream.h
@@ -8,6 +8,7 @@
#include <sys/types.h>
#include <string>
+#include "base/basictypes.h"
#include "base/strings/string_piece.h"
#include "net/base/io_buffer.h"
#include "net/quic/quic_data_stream.h"
@@ -33,6 +34,9 @@ class QuicSpdyClientStream : public QuicDataStream {
// SPDY/HTTP does not support bidirectional streaming.
virtual bool OnStreamFrame(const QuicStreamFrame& frame) OVERRIDE;
+ // Override the base class to store the size of the headers.
+ virtual void OnStreamHeadersComplete(bool fin, size_t frame_len) OVERRIDE;
+
// ReliableQuicStream implementation called by the session when there's
// data for us.
virtual uint32 ProcessData(const char* data, uint32 data_len) OVERRIDE;
@@ -54,6 +58,10 @@ class QuicSpdyClientStream : public QuicDataStream {
// Returns whatever headers have been received for this stream.
const BalsaHeaders& headers() { return headers_; }
+ size_t header_bytes_read() const { return header_bytes_read_; }
+
+ size_t header_bytes_written() const { return header_bytes_written_; }
+
// While the server's set_priority shouldn't be called externally, the creator
// of client-side streams should be able to set the priority.
using QuicDataStream::set_priority;
@@ -66,6 +74,10 @@ class QuicSpdyClientStream : public QuicDataStream {
scoped_refptr<GrowableIOBuffer> read_buf_;
bool response_headers_received_;
+ size_t header_bytes_read_;
+ size_t header_bytes_written_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicSpdyClientStream);
};
} // namespace tools
diff --git a/chromium/net/tools/quic/quic_spdy_client_stream_test.cc b/chromium/net/tools/quic/quic_spdy_client_stream_test.cc
index 44c640cbdea..475f832b1c5 100644
--- a/chromium/net/tools/quic/quic_spdy_client_stream_test.cc
+++ b/chromium/net/tools/quic/quic_spdy_client_stream_test.cc
@@ -7,7 +7,6 @@
#include "base/strings/string_number_conversions.h"
#include "net/quic/quic_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_client_session.h"
#include "net/tools/quic/quic_spdy_client_stream.h"
#include "net/tools/quic/spdy_utils.h"
@@ -16,6 +15,8 @@
#include "testing/gtest/include/gtest/gtest.h"
using net::test::DefaultQuicConfig;
+using net::test::SupportedVersions;
+using testing::StrictMock;
using testing::TestWithParam;
namespace net {
@@ -23,23 +24,35 @@ namespace tools {
namespace test {
namespace {
-class QuicSpdyClientStreamTest : public ::testing::Test {
+class QuicSpdyClientStreamTest : public TestWithParam<QuicVersion> {
public:
QuicSpdyClientStreamTest()
- : session_("example.com", DefaultQuicConfig(),
- new MockConnection(false),
+ : connection_(new StrictMock<MockConnection>(
+ false, SupportedVersions(GetParam()))),
+ session_(QuicServerId("example.com", 80, false, PRIVACY_MODE_DISABLED),
+ DefaultQuicConfig(),
+ connection_,
&crypto_config_),
body_("hello world") {
- session_.config()->SetDefaults();
crypto_config_.SetDefaults();
headers_.SetResponseFirstlineFromStringPieces("HTTP/1.1", "200", "Ok");
headers_.ReplaceOrAppendHeader("content-length", "11");
headers_string_ = SpdyUtils::SerializeResponseHeaders(headers_);
+
+ // New streams rely on having the peer's flow control receive window
+ // negotiated in the config.
+ session_.config()->SetInitialFlowControlWindowToSend(
+ kInitialSessionFlowControlWindowForTest);
+ session_.config()->SetInitialStreamFlowControlWindowToSend(
+ kInitialStreamFlowControlWindowForTest);
+ session_.config()->SetInitialSessionFlowControlWindowToSend(
+ kInitialSessionFlowControlWindowForTest);
stream_.reset(new QuicSpdyClientStream(3, &session_));
}
+ StrictMock<MockConnection>* connection_;
QuicClientSession session_;
scoped_ptr<QuicSpdyClientStream> stream_;
BalsaHeaders headers_;
@@ -48,7 +61,10 @@ class QuicSpdyClientStreamTest : public ::testing::Test {
QuicCryptoClientConfig crypto_config_;
};
-TEST_F(QuicSpdyClientStreamTest, TestFraming) {
+INSTANTIATE_TEST_CASE_P(Tests, QuicSpdyClientStreamTest,
+ ::testing::ValuesIn(QuicSupportedVersions()));
+
+TEST_P(QuicSpdyClientStreamTest, TestFraming) {
EXPECT_EQ(headers_string_.size(), stream_->ProcessData(
headers_string_.c_str(), headers_string_.size()));
EXPECT_EQ(body_.size(),
@@ -57,7 +73,7 @@ TEST_F(QuicSpdyClientStreamTest, TestFraming) {
EXPECT_EQ(body_, stream_->data());
}
-TEST_F(QuicSpdyClientStreamTest, TestFramingOnePacket) {
+TEST_P(QuicSpdyClientStreamTest, TestFramingOnePacket) {
string message = headers_string_ + body_;
EXPECT_EQ(message.size(), stream_->ProcessData(
@@ -66,7 +82,7 @@ TEST_F(QuicSpdyClientStreamTest, TestFramingOnePacket) {
EXPECT_EQ(body_, stream_->data());
}
-TEST_F(QuicSpdyClientStreamTest, DISABLED_TestFramingExtraData) {
+TEST_P(QuicSpdyClientStreamTest, DISABLED_TestFramingExtraData) {
string large_body = "hello world!!!!!!";
EXPECT_EQ(headers_string_.size(), stream_->ProcessData(
@@ -75,12 +91,14 @@ TEST_F(QuicSpdyClientStreamTest, DISABLED_TestFramingExtraData) {
EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_->stream_error());
EXPECT_EQ(200u, stream_->headers().parsed_response_code());
+ EXPECT_CALL(*connection_,
+ SendRstStream(stream_->id(), QUIC_BAD_APPLICATION_PAYLOAD, 0));
stream_->ProcessData(large_body.c_str(), large_body.size());
EXPECT_NE(QUIC_STREAM_NO_ERROR, stream_->stream_error());
}
-TEST_F(QuicSpdyClientStreamTest, TestNoBidirectionalStreaming) {
+TEST_P(QuicSpdyClientStreamTest, TestNoBidirectionalStreaming) {
QuicStreamFrame frame(3, false, 3, MakeIOVector("asd"));
EXPECT_FALSE(stream_->write_side_closed());
diff --git a/chromium/net/tools/quic/quic_spdy_server_stream.cc b/chromium/net/tools/quic/quic_spdy_server_stream.cc
index c1a9cf15e18..7ae20d02e97 100644
--- a/chromium/net/tools/quic/quic_spdy_server_stream.cc
+++ b/chromium/net/tools/quic/quic_spdy_server_stream.cc
@@ -28,22 +28,23 @@ QuicSpdyServerStream::QuicSpdyServerStream(QuicStreamId id,
QuicSpdyServerStream::~QuicSpdyServerStream() {
}
-uint32 QuicSpdyServerStream::ProcessData(const char* data, uint32 length) {
+uint32 QuicSpdyServerStream::ProcessData(const char* data, uint32 data_len) {
uint32 total_bytes_processed = 0;
// Are we still reading the request headers.
if (!request_headers_received_) {
// Grow the read buffer if necessary.
- if (read_buf_->RemainingCapacity() < (int)length) {
+ if (read_buf_->RemainingCapacity() < (int)data_len) {
read_buf_->SetCapacity(read_buf_->capacity() + kHeaderBufInitialSize);
}
- memcpy(read_buf_->data(), data, length);
- read_buf_->set_offset(read_buf_->offset() + length);
+ memcpy(read_buf_->data(), data, data_len);
+ read_buf_->set_offset(read_buf_->offset() + data_len);
ParseRequestHeaders();
} else {
- body_.append(data + total_bytes_processed, length - total_bytes_processed);
+ body_.append(data + total_bytes_processed,
+ data_len - total_bytes_processed);
}
- return length;
+ return data_len;
}
void QuicSpdyServerStream::OnFinRead() {
@@ -55,7 +56,7 @@ void QuicSpdyServerStream::OnFinRead() {
if (!request_headers_received_) {
SendErrorResponse(); // We're not done reading headers.
} else if ((headers_.content_length_status() ==
- BalsaHeadersEnums::VALID_CONTENT_LENGTH) &&
+ BalsaHeadersEnums::VALID_CONTENT_LENGTH) &&
body_.size() != headers_.content_length()) {
SendErrorResponse(); // Invalid content length
} else {
@@ -97,12 +98,23 @@ void QuicSpdyServerStream::SendResponse() {
return;
}
- DLOG(INFO) << "Sending response for stream " << id();
+ if (response->response_type() == QuicInMemoryCache::CLOSE_CONNECTION) {
+ DVLOG(1) << "Special response: closing connection.";
+ CloseConnection(QUIC_NO_ERROR);
+ return;
+ }
+
+ if (response->response_type() == QuicInMemoryCache::IGNORE_REQUEST) {
+ DVLOG(1) << "Special response: ignoring request.";
+ return;
+ }
+
+ DVLOG(1) << "Sending response for stream " << id();
SendHeadersAndBody(response->headers(), response->body());
}
void QuicSpdyServerStream::SendErrorResponse() {
- DLOG(INFO) << "Sending error response for stream " << id();
+ DVLOG(1) << "Sending error response for stream " << id();
BalsaHeaders headers;
headers.SetResponseFirstlineFromStringPieces(
"HTTP/1.1", "500", "Server Error");
@@ -110,7 +122,7 @@ void QuicSpdyServerStream::SendErrorResponse() {
SendHeadersAndBody(headers, "bad");
}
-void QuicSpdyServerStream:: SendHeadersAndBody(
+void QuicSpdyServerStream::SendHeadersAndBody(
const BalsaHeaders& response_headers,
StringPiece body) {
// We only support SPDY and HTTP, and neither handles bidirectional streaming.
@@ -121,12 +133,10 @@ void QuicSpdyServerStream:: SendHeadersAndBody(
SpdyHeaderBlock header_block =
SpdyUtils::ResponseHeadersToSpdyHeaders(response_headers);
- string headers_string =
- session()->compressor()->CompressHeaders(header_block);
- WriteOrBufferData(headers_string, body.empty());
+ WriteHeaders(header_block, body.empty(), NULL);
if (!body.empty()) {
- WriteOrBufferData(body, true);
+ WriteOrBufferData(body, true, NULL);
}
}
diff --git a/chromium/net/tools/quic/quic_spdy_server_stream.h b/chromium/net/tools/quic/quic_spdy_server_stream.h
index 574ef76f33d..741f7867331 100644
--- a/chromium/net/tools/quic/quic_spdy_server_stream.h
+++ b/chromium/net/tools/quic/quic_spdy_server_stream.h
@@ -7,6 +7,7 @@
#include <string>
+#include "base/basictypes.h"
#include "net/base/io_buffer.h"
#include "net/quic/quic_data_stream.h"
#include "net/quic/quic_protocol.h"
@@ -56,6 +57,8 @@ class QuicSpdyServerStream : public QuicDataStream {
// Buffer into which response header data is read.
scoped_refptr<GrowableIOBuffer> read_buf_;
bool request_headers_received_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicSpdyServerStream);
};
} // namespace tools
diff --git a/chromium/net/tools/quic/quic_spdy_server_stream_test.cc b/chromium/net/tools/quic/quic_spdy_server_stream_test.cc
index c0ec9449707..e01569ede79 100644
--- a/chromium/net/tools/quic/quic_spdy_server_stream_test.cc
+++ b/chromium/net/tools/quic/quic_spdy_server_stream_test.cc
@@ -8,7 +8,6 @@
#include "base/strings/string_piece.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_spdy_compressor.h"
#include "net/quic/quic_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/tools/epoll_server/epoll_server.h"
@@ -20,8 +19,9 @@
#include "testing/gtest/include/gtest/gtest.h"
using base::StringPiece;
-using net::tools::test::MockConnection;
using net::test::MockSession;
+using net::test::SupportedVersions;
+using net::tools::test::MockConnection;
using std::string;
using testing::_;
using testing::AnyNumber;
@@ -29,7 +29,6 @@ using testing::Invoke;
using testing::InvokeArgument;
using testing::InSequence;
using testing::Return;
-using testing::StrEq;
using testing::StrictMock;
using testing::WithArgs;
@@ -46,25 +45,35 @@ class QuicSpdyServerStreamPeer : public QuicSpdyServerStream {
using QuicSpdyServerStream::SendResponse;
using QuicSpdyServerStream::SendErrorResponse;
- const string& body() {
- return body_;
+ BalsaHeaders* mutable_headers() {
+ return &headers_;
}
- const BalsaHeaders& headers() {
- return headers_;
+ static void SendResponse(QuicSpdyServerStream* stream) {
+ stream->SendResponse();
}
- BalsaHeaders* mutable_headers() {
- return &headers_;
+ static void SendErrorResponse(QuicSpdyServerStream* stream) {
+ stream->SendResponse();
+ }
+
+ static const string& body(QuicSpdyServerStream* stream) {
+ return stream->body_;
+ }
+
+ static const BalsaHeaders& headers(QuicSpdyServerStream* stream) {
+ return stream->headers_;
}
};
namespace {
-class QuicSpdyServerStreamTest : public ::testing::Test {
+class QuicSpdyServerStreamTest : public ::testing::TestWithParam<QuicVersion> {
public:
QuicSpdyServerStreamTest()
- : session_(new MockConnection(true)),
+ : connection_(new StrictMock<MockConnection>(
+ true, SupportedVersions(GetParam()))),
+ session_(connection_),
body_("hello world") {
BalsaHeaders request_headers;
request_headers.SetRequestFirstlineFromStringPieces(
@@ -72,35 +81,23 @@ class QuicSpdyServerStreamTest : public ::testing::Test {
request_headers.ReplaceOrAppendHeader("content-length", "11");
headers_string_ = SpdyUtils::SerializeRequestHeaders(request_headers);
- stream_.reset(new QuicSpdyServerStreamPeer(3, &session_));
- }
- QuicConsumedData ValidateHeaders(const struct iovec* iov) {
- StringPiece headers =
- StringPiece(static_cast<const char*>(iov[0].iov_base), iov[0].iov_len);
- headers_string_ = SpdyUtils::SerializeResponseHeaders(
- response_headers_);
- QuicSpdyDecompressor decompressor;
- TestDecompressorVisitor visitor;
-
- // First the header id, then the compressed data.
- EXPECT_EQ(1, headers[0]);
- EXPECT_EQ(0, headers[1]);
- EXPECT_EQ(0, headers[2]);
- EXPECT_EQ(0, headers[3]);
- EXPECT_EQ(static_cast<size_t>(headers.length() - 4),
- decompressor.DecompressData(headers.substr(4), &visitor));
-
- EXPECT_EQ(headers_string_, visitor.data());
-
- return QuicConsumedData(headers.size(), false);
+ // New streams rely on having the peer's flow control receive window
+ // negotiated in the config.
+ session_.config()->SetInitialFlowControlWindowToSend(
+ kInitialSessionFlowControlWindowForTest);
+ session_.config()->SetInitialStreamFlowControlWindowToSend(
+ kInitialStreamFlowControlWindowForTest);
+ session_.config()->SetInitialSessionFlowControlWindowToSend(
+ kInitialSessionFlowControlWindowForTest);
+ stream_.reset(new QuicSpdyServerStreamPeer(3, &session_));
}
static void SetUpTestCase() {
QuicInMemoryCachePeer::ResetForTests();
}
- virtual void SetUp() {
+ virtual void SetUp() OVERRIDE {
QuicInMemoryCache* cache = QuicInMemoryCache::GetInstance();
BalsaHeaders request_headers, response_headers;
@@ -130,8 +127,17 @@ class QuicSpdyServerStreamTest : public ::testing::Test {
cache->AddResponse(request_headers, response_headers, body);
}
+ const string& StreamBody() {
+ return QuicSpdyServerStreamPeer::body(stream_.get());
+ }
+
+ const BalsaHeaders& StreamHeaders() {
+ return QuicSpdyServerStreamPeer::headers(stream_.get());
+ }
+
BalsaHeaders response_headers_;
EpollServer eps_;
+ StrictMock<MockConnection>* connection_;
StrictMock<MockSession> session_;
scoped_ptr<QuicSpdyServerStreamPeer> stream_;
string headers_string_;
@@ -140,32 +146,31 @@ class QuicSpdyServerStreamTest : public ::testing::Test {
QuicConsumedData ConsumeAllData(
QuicStreamId id,
- const struct iovec* iov,
- int iov_count,
+ const IOVector& data,
QuicStreamOffset offset,
bool fin,
+ FecProtection /*fec_protection_*/,
QuicAckNotifier::DelegateInterface* /*ack_notifier_delegate*/) {
- ssize_t consumed_length = 0;
- for (int i = 0; i < iov_count; ++i) {
- consumed_length += iov[i].iov_len;
- }
- return QuicConsumedData(consumed_length, fin);
+ return QuicConsumedData(data.TotalBufferSize(), fin);
}
-TEST_F(QuicSpdyServerStreamTest, TestFraming) {
+INSTANTIATE_TEST_CASE_P(Tests, QuicSpdyServerStreamTest,
+ ::testing::ValuesIn(QuicSupportedVersions()));
+
+TEST_P(QuicSpdyServerStreamTest, TestFraming) {
EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(AnyNumber()).
WillRepeatedly(Invoke(ConsumeAllData));
EXPECT_EQ(headers_string_.size(), stream_->ProcessData(
headers_string_.c_str(), headers_string_.size()));
EXPECT_EQ(body_.size(), stream_->ProcessData(body_.c_str(), body_.size()));
- EXPECT_EQ(11u, stream_->headers().content_length());
- EXPECT_EQ("https://www.google.com/", stream_->headers().request_uri());
- EXPECT_EQ("POST", stream_->headers().request_method());
- EXPECT_EQ(body_, stream_->body());
+ EXPECT_EQ(11u, StreamHeaders().content_length());
+ EXPECT_EQ("https://www.google.com/", StreamHeaders().request_uri());
+ EXPECT_EQ("POST", StreamHeaders().request_method());
+ EXPECT_EQ(body_, StreamBody());
}
-TEST_F(QuicSpdyServerStreamTest, TestFramingOnePacket) {
+TEST_P(QuicSpdyServerStreamTest, TestFramingOnePacket) {
EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(AnyNumber()).
WillRepeatedly(Invoke(ConsumeAllData));
@@ -173,14 +178,13 @@ TEST_F(QuicSpdyServerStreamTest, TestFramingOnePacket) {
EXPECT_EQ(message.size(), stream_->ProcessData(
message.c_str(), message.size()));
- EXPECT_EQ(11u, stream_->headers().content_length());
- EXPECT_EQ("https://www.google.com/",
- stream_->headers().request_uri());
- EXPECT_EQ("POST", stream_->headers().request_method());
- EXPECT_EQ(body_, stream_->body());
+ EXPECT_EQ(11u, StreamHeaders().content_length());
+ EXPECT_EQ("https://www.google.com/", StreamHeaders().request_uri());
+ EXPECT_EQ("POST", StreamHeaders().request_method());
+ EXPECT_EQ(body_, StreamBody());
}
-TEST_F(QuicSpdyServerStreamTest, TestFramingExtraData) {
+TEST_P(QuicSpdyServerStreamTest, TestFramingExtraData) {
string large_body = "hello world!!!!!!";
// We'll automatically write out an error (headers + body)
@@ -192,12 +196,12 @@ TEST_F(QuicSpdyServerStreamTest, TestFramingExtraData) {
// Content length is still 11. This will register as an error and we won't
// accept the bytes.
stream_->ProcessData(large_body.c_str(), large_body.size());
- EXPECT_EQ(11u, stream_->headers().content_length());
- EXPECT_EQ("https://www.google.com/", stream_->headers().request_uri());
- EXPECT_EQ("POST", stream_->headers().request_method());
+ EXPECT_EQ(11u, StreamHeaders().content_length());
+ EXPECT_EQ("https://www.google.com/", StreamHeaders().request_uri());
+ EXPECT_EQ("POST", StreamHeaders().request_method());
}
-TEST_F(QuicSpdyServerStreamTest, TestSendResponse) {
+TEST_P(QuicSpdyServerStreamTest, TestSendResponse) {
BalsaHeaders* request_headers = stream_->mutable_headers();
request_headers->SetRequestFirstlineFromStringPieces(
"GET",
@@ -209,40 +213,34 @@ TEST_F(QuicSpdyServerStreamTest, TestSendResponse) {
response_headers_.ReplaceOrAppendHeader("content-length", "3");
InSequence s;
- EXPECT_CALL(session_, WritevData(_, _, 1, _, _, _)).Times(1)
- .WillOnce(WithArgs<1>(Invoke(
- this, &QuicSpdyServerStreamTest::ValidateHeaders)));
-
- EXPECT_CALL(session_, WritevData(_, _, 1, _, _, _)).Times(1).
+ EXPECT_CALL(session_,
+ WritevData(kHeadersStreamId, _, 0, false, _, NULL));
+ EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(1).
WillOnce(Return(QuicConsumedData(3, true)));
- stream_->SendResponse();
+ QuicSpdyServerStreamPeer::SendResponse(stream_.get());
EXPECT_TRUE(stream_->read_side_closed());
EXPECT_TRUE(stream_->write_side_closed());
}
-TEST_F(QuicSpdyServerStreamTest, TestSendErrorResponse) {
+TEST_P(QuicSpdyServerStreamTest, TestSendErrorResponse) {
response_headers_.SetResponseFirstlineFromStringPieces(
"HTTP/1.1", "500", "Server Error");
response_headers_.ReplaceOrAppendHeader("content-length", "3");
InSequence s;
- EXPECT_CALL(session_, WritevData(_, _, 1, _, _, _)).Times(1)
- .WillOnce(WithArgs<1>(Invoke(
- this, &QuicSpdyServerStreamTest::ValidateHeaders)));
-
- EXPECT_CALL(session_, WritevData(_, _, 1, _, _, _)).Times(1).
+ EXPECT_CALL(session_,
+ WritevData(kHeadersStreamId, _, 0, false, _, NULL));
+ EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(1).
WillOnce(Return(QuicConsumedData(3, true)));
- stream_->SendErrorResponse();
+ QuicSpdyServerStreamPeer::SendErrorResponse(stream_.get());
EXPECT_TRUE(stream_->read_side_closed());
EXPECT_TRUE(stream_->write_side_closed());
}
-TEST_F(QuicSpdyServerStreamTest, InvalidHeadersWithFin) {
+TEST_P(QuicSpdyServerStreamTest, InvalidHeadersWithFin) {
char arr[] = {
- 0x00, 0x00, 0x00, 0x05, // ....
- 0x00, 0x00, 0x00, 0x05, // ....
0x3a, 0x68, 0x6f, 0x73, // :hos
0x74, 0x00, 0x00, 0x00, // t...
0x00, 0x00, 0x00, 0x00, // ....
@@ -265,8 +263,8 @@ TEST_F(QuicSpdyServerStreamTest, InvalidHeadersWithFin) {
0x54, 0x54, 0x50, 0x2f, // TTP/
0x31, 0x2e, 0x31, // 1.1
};
- QuicStreamFrame frame(
- stream_->id(), true, 0, MakeIOVector(StringPiece(arr, arraysize(arr))));
+ StringPiece data(arr, arraysize(arr));
+ QuicStreamFrame frame(stream_->id(), true, 0, MakeIOVector(data));
// Verify that we don't crash when we get a invalid headers in stream frame.
stream_->OnStreamFrame(frame);
}
diff --git a/chromium/net/tools/quic/quic_time_wait_list_manager.cc b/chromium/net/tools/quic/quic_time_wait_list_manager.cc
index df9e378e722..9744ff89e53 100644
--- a/chromium/net/tools/quic/quic_time_wait_list_manager.cc
+++ b/chromium/net/tools/quic/quic_time_wait_list_manager.cc
@@ -17,6 +17,8 @@
#include "net/quic/quic_framer.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/quic_utils.h"
+#include "net/tools/epoll_server/epoll_server.h"
+#include "net/tools/quic/quic_server_session.h"
using base::StringPiece;
using std::make_pair;
@@ -26,23 +28,24 @@ namespace tools {
namespace {
-// Time period for which the guid should live in time wait state..
+// Time period for which the connection_id should live in time wait state..
const int kTimeWaitSeconds = 5;
} // namespace
// A very simple alarm that just informs the QuicTimeWaitListManager to clean
-// up old guids. This alarm should be unregistered and deleted before the
-// QuicTimeWaitListManager is deleted.
-class GuidCleanUpAlarm : public EpollAlarm {
+// up old connection_ids. This alarm should be unregistered and deleted before
+// the QuicTimeWaitListManager is deleted.
+class ConnectionIdCleanUpAlarm : public EpollAlarm {
public:
- explicit GuidCleanUpAlarm(QuicTimeWaitListManager* time_wait_list_manager)
+ explicit ConnectionIdCleanUpAlarm(
+ QuicTimeWaitListManager* time_wait_list_manager)
: time_wait_list_manager_(time_wait_list_manager) {
}
virtual int64 OnAlarm() OVERRIDE {
EpollAlarm::OnAlarm();
- time_wait_list_manager_->CleanUpOldGuids();
+ time_wait_list_manager_->CleanUpOldConnectionIds();
// Let the time wait manager register the alarm at appropriate time.
return 0;
}
@@ -52,19 +55,9 @@ class GuidCleanUpAlarm : public EpollAlarm {
QuicTimeWaitListManager* time_wait_list_manager_;
};
-struct QuicTimeWaitListManager::GuidAddTime {
- GuidAddTime(QuicGuid guid, const QuicTime& time)
- : guid(guid),
- time_added(time) {
- }
-
- QuicGuid guid;
- QuicTime time_added;
-};
-
// This class stores pending public reset packets to be sent to clients.
// server_address - server address on which a packet what was received for
-// a guid in time wait state.
+// a connection_id in time wait state.
// client_address - address of the client that sent that packet. Needed to send
// the public reset packet back to the client.
// packet - the pending public reset packet that is to be sent to the client.
@@ -93,174 +86,103 @@ class QuicTimeWaitListManager::QueuedPacket {
QuicTimeWaitListManager::QuicTimeWaitListManager(
QuicPacketWriter* writer,
+ QuicServerSessionVisitor* visitor,
EpollServer* epoll_server,
const QuicVersionVector& supported_versions)
- : framer_(supported_versions,
- QuicTime::Zero(), // unused
- true),
- epoll_server_(epoll_server),
+ : epoll_server_(epoll_server),
kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)),
- guid_clean_up_alarm_(new GuidCleanUpAlarm(this)),
- clock_(epoll_server),
+ connection_id_clean_up_alarm_(new ConnectionIdCleanUpAlarm(this)),
+ clock_(epoll_server_),
writer_(writer),
- is_write_blocked_(false) {
- framer_.set_visitor(this);
- SetGuidCleanUpAlarm();
+ visitor_(visitor) {
+ SetConnectionIdCleanUpAlarm();
}
QuicTimeWaitListManager::~QuicTimeWaitListManager() {
- guid_clean_up_alarm_->UnregisterIfRegistered();
- STLDeleteElements(&time_ordered_guid_list_);
+ connection_id_clean_up_alarm_->UnregisterIfRegistered();
STLDeleteElements(&pending_packets_queue_);
- for (GuidMapIterator it = guid_map_.begin(); it != guid_map_.end(); ++it) {
+ for (ConnectionIdMap::iterator it = connection_id_map_.begin();
+ it != connection_id_map_.end();
+ ++it) {
delete it->second.close_packet;
}
}
-void QuicTimeWaitListManager::AddGuidToTimeWait(
- QuicGuid guid,
+void QuicTimeWaitListManager::AddConnectionIdToTimeWait(
+ QuicConnectionId connection_id,
QuicVersion version,
QuicEncryptedPacket* close_packet) {
- DCHECK(!IsGuidInTimeWait(guid));
- // Initialize the guid with 0 packets received.
- GuidData data(0, version, close_packet);
- guid_map_.insert(make_pair(guid, data));
- time_ordered_guid_list_.push_back(new GuidAddTime(guid,
- clock_.ApproximateNow()));
-}
-
-bool QuicTimeWaitListManager::IsGuidInTimeWait(QuicGuid guid) const {
- return guid_map_.find(guid) != guid_map_.end();
+ DVLOG(1) << "Adding " << connection_id << " to the time wait list.";
+ int num_packets = 0;
+ ConnectionIdMap::iterator it = connection_id_map_.find(connection_id);
+ if (it != connection_id_map_.end()) { // Replace record if it is reinserted.
+ num_packets = it->second.num_packets;
+ delete it->second.close_packet;
+ connection_id_map_.erase(it);
+ }
+ ConnectionIdData data(num_packets, version, clock_.ApproximateNow(),
+ close_packet);
+ connection_id_map_.insert(make_pair(connection_id, data));
}
-void QuicTimeWaitListManager::ProcessPacket(
- const IPEndPoint& server_address,
- const IPEndPoint& client_address,
- QuicGuid guid,
- const QuicEncryptedPacket& packet) {
- DCHECK(IsGuidInTimeWait(guid));
- server_address_ = server_address;
- client_address_ = client_address;
-
- // Set the framer to the appropriate version for this GUID, before processing.
- QuicVersion version = GetQuicVersionFromGuid(guid);
- framer_.set_version(version);
-
- framer_.ProcessPacket(packet);
+bool QuicTimeWaitListManager::IsConnectionIdInTimeWait(
+ QuicConnectionId connection_id) const {
+ return ContainsKey(connection_id_map_, connection_id);
}
-QuicVersion QuicTimeWaitListManager::GetQuicVersionFromGuid(QuicGuid guid) {
- GuidMapIterator it = guid_map_.find(guid);
- DCHECK(it != guid_map_.end());
+QuicVersion QuicTimeWaitListManager::GetQuicVersionFromConnectionId(
+ QuicConnectionId connection_id) {
+ ConnectionIdMap::iterator it = connection_id_map_.find(connection_id);
+ DCHECK(it != connection_id_map_.end());
return (it->second).version;
}
-bool QuicTimeWaitListManager::OnCanWrite() {
- is_write_blocked_ = false;
- while (!is_write_blocked_ && !pending_packets_queue_.empty()) {
+void QuicTimeWaitListManager::OnCanWrite() {
+ while (!pending_packets_queue_.empty()) {
QueuedPacket* queued_packet = pending_packets_queue_.front();
- WriteToWire(queued_packet);
- if (!is_write_blocked_) {
- pending_packets_queue_.pop_front();
- delete queued_packet;
+ if (!WriteToWire(queued_packet)) {
+ return;
}
+ pending_packets_queue_.pop_front();
+ delete queued_packet;
}
-
- return !is_write_blocked_;
}
-void QuicTimeWaitListManager::OnError(QuicFramer* framer) {
- DLOG(INFO) << QuicUtils::ErrorToString(framer->error());
-}
-
-bool QuicTimeWaitListManager::OnProtocolVersionMismatch(
- QuicVersion received_version) {
- // Drop such packets whose version don't match.
- return false;
-}
-
-bool QuicTimeWaitListManager::OnUnauthenticatedHeader(
- const QuicPacketHeader& header) {
+void QuicTimeWaitListManager::ProcessPacket(
+ const IPEndPoint& server_address,
+ const IPEndPoint& client_address,
+ QuicConnectionId connection_id,
+ QuicPacketSequenceNumber sequence_number,
+ const QuicEncryptedPacket& /*packet*/) {
+ DCHECK(IsConnectionIdInTimeWait(connection_id));
+ DVLOG(1) << "Processing " << connection_id << " in time wait state.";
// TODO(satyamshekhar): Think about handling packets from different client
// addresses.
- GuidMapIterator it = guid_map_.find(header.public_header.guid);
- DCHECK(it != guid_map_.end());
+ ConnectionIdMap::iterator it = connection_id_map_.find(connection_id);
+ DCHECK(it != connection_id_map_.end());
// Increment the received packet count.
++((it->second).num_packets);
if (!ShouldSendResponse((it->second).num_packets)) {
- return false;
+ return;
}
if (it->second.close_packet) {
QueuedPacket* queued_packet =
- new QueuedPacket(server_address_,
- client_address_,
+ new QueuedPacket(server_address,
+ client_address,
it->second.close_packet->Clone());
// Takes ownership of the packet.
SendOrQueuePacket(queued_packet);
} else {
- // We don't need the packet anymore. Just tell the client what sequence
- // number we rejected.
- SendPublicReset(server_address_,
- client_address_,
- header.public_header.guid,
- header.packet_sequence_number);
+ SendPublicReset(server_address,
+ client_address,
+ connection_id,
+ sequence_number);
}
- // Never process the body of the packet in time wait state.
- return false;
-}
-
-bool QuicTimeWaitListManager::OnPacketHeader(const QuicPacketHeader& header) {
- DCHECK(false);
- return false;
-}
-
-void QuicTimeWaitListManager::OnRevivedPacket() {
- DCHECK(false);
-}
-
-void QuicTimeWaitListManager::OnFecProtectedPayload(StringPiece /*payload*/) {
- DCHECK(false);
-}
-
-bool QuicTimeWaitListManager::OnStreamFrame(const QuicStreamFrame& /*frame*/) {
- DCHECK(false);
- return false;
-}
-
-bool QuicTimeWaitListManager::OnAckFrame(const QuicAckFrame& /*frame*/) {
- DCHECK(false);
- return false;
-}
-
-bool QuicTimeWaitListManager::OnCongestionFeedbackFrame(
- const QuicCongestionFeedbackFrame& /*frame*/) {
- DCHECK(false);
- return false;
}
-bool QuicTimeWaitListManager::OnRstStreamFrame(
- const QuicRstStreamFrame& /*frame*/) {
- DCHECK(false);
- return false;
-}
-
-bool QuicTimeWaitListManager::OnConnectionCloseFrame(
- const QuicConnectionCloseFrame & /*frame*/) {
- DCHECK(false);
- return false;
-}
-
-bool QuicTimeWaitListManager::OnGoAwayFrame(const QuicGoAwayFrame& /*frame*/) {
- DCHECK(false);
- return false;
-}
-
-void QuicTimeWaitListManager::OnFecData(const QuicFecData& /*fec*/) {
- DCHECK(false);
-}
-
-// Returns true if the number of packets received for this guid is a power of 2
-// to throttle the number of public reset packets we send to a client.
+// Returns true if the number of packets received for this connection_id is a
+// power of 2 to throttle the number of public reset packets we send to a
+// client.
bool QuicTimeWaitListManager::ShouldSendResponse(int received_packet_count) {
return (received_packet_count & (received_packet_count - 1)) == 0;
}
@@ -268,95 +190,100 @@ bool QuicTimeWaitListManager::ShouldSendResponse(int received_packet_count) {
void QuicTimeWaitListManager::SendPublicReset(
const IPEndPoint& server_address,
const IPEndPoint& client_address,
- QuicGuid guid,
+ QuicConnectionId connection_id,
QuicPacketSequenceNumber rejected_sequence_number) {
QuicPublicResetPacket packet;
- packet.public_header.guid = guid;
+ packet.public_header.connection_id = connection_id;
packet.public_header.reset_flag = true;
packet.public_header.version_flag = false;
packet.rejected_sequence_number = rejected_sequence_number;
- // TODO(satyamshekhar): generate a valid nonce for this guid.
+ // TODO(satyamshekhar): generate a valid nonce for this connection_id.
packet.nonce_proof = 1010101;
+ packet.client_address = client_address;
QueuedPacket* queued_packet = new QueuedPacket(
server_address,
client_address,
- QuicFramer::BuildPublicResetPacket(packet));
+ BuildPublicReset(packet));
// Takes ownership of the packet.
SendOrQueuePacket(queued_packet);
}
+QuicEncryptedPacket* QuicTimeWaitListManager::BuildPublicReset(
+ const QuicPublicResetPacket& packet) {
+ return QuicFramer::BuildPublicResetPacket(packet);
+}
+
// Either sends the packet and deletes it or makes pending queue the
// owner of the packet.
void QuicTimeWaitListManager::SendOrQueuePacket(QueuedPacket* packet) {
- if (!is_write_blocked_) {
- // TODO(satyamshekhar): Handle packets that fail due to error other than
- // EAGAIN or EWOULDBLOCK.
- WriteToWire(packet);
- }
-
- if (is_write_blocked_) {
+ if (WriteToWire(packet)) {
+ delete packet;
+ } else {
// pending_packets_queue takes the ownership of the queued packet.
pending_packets_queue_.push_back(packet);
- } else {
- delete packet;
}
}
-void QuicTimeWaitListManager::WriteToWire(QueuedPacket* queued_packet) {
- DCHECK(!is_write_blocked_);
+bool QuicTimeWaitListManager::WriteToWire(QueuedPacket* queued_packet) {
+ if (writer_->IsWriteBlocked()) {
+ visitor_->OnWriteBlocked(this);
+ return false;
+ }
WriteResult result = writer_->WritePacket(
queued_packet->packet()->data(),
queued_packet->packet()->length(),
queued_packet->server_address().address(),
- queued_packet->client_address(),
- this);
-
+ queued_packet->client_address());
if (result.status == WRITE_STATUS_BLOCKED) {
- is_write_blocked_ = true;
+ // If blocked and unbuffered, return false to retry sending.
+ DCHECK(writer_->IsWriteBlocked());
+ visitor_->OnWriteBlocked(this);
+ return writer_->IsWriteBlockedDataBuffered();
} else if (result.status == WRITE_STATUS_ERROR) {
LOG(WARNING) << "Received unknown error while sending reset packet to "
<< queued_packet->client_address().ToString() << ": "
<< strerror(result.error_code);
}
+ return true;
}
-void QuicTimeWaitListManager::SetGuidCleanUpAlarm() {
- guid_clean_up_alarm_->UnregisterIfRegistered();
+void QuicTimeWaitListManager::SetConnectionIdCleanUpAlarm() {
+ connection_id_clean_up_alarm_->UnregisterIfRegistered();
int64 next_alarm_interval;
- if (!time_ordered_guid_list_.empty()) {
- GuidAddTime* oldest_guid = time_ordered_guid_list_.front();
+ if (!connection_id_map_.empty()) {
+ QuicTime oldest_connection_id =
+ connection_id_map_.begin()->second.time_added;
QuicTime now = clock_.ApproximateNow();
- DCHECK(now.Subtract(oldest_guid->time_added) < kTimeWaitPeriod_);
- next_alarm_interval = oldest_guid->time_added
- .Add(kTimeWaitPeriod_)
- .Subtract(now)
- .ToMicroseconds();
+ if (now.Subtract(oldest_connection_id) < kTimeWaitPeriod_) {
+ next_alarm_interval = oldest_connection_id.Add(kTimeWaitPeriod_)
+ .Subtract(now)
+ .ToMicroseconds();
+ } else {
+ LOG(ERROR) << "ConnectionId lingered for longer than kTimeWaitPeriod";
+ next_alarm_interval = 0;
+ }
} else {
- // No guids added so none will expire before kTimeWaitPeriod_.
+ // No connection_ids added so none will expire before kTimeWaitPeriod_.
next_alarm_interval = kTimeWaitPeriod_.ToMicroseconds();
}
- epoll_server_->RegisterAlarmApproximateDelta(next_alarm_interval,
- guid_clean_up_alarm_.get());
+ epoll_server_->RegisterAlarmApproximateDelta(
+ next_alarm_interval, connection_id_clean_up_alarm_.get());
}
-void QuicTimeWaitListManager::CleanUpOldGuids() {
+void QuicTimeWaitListManager::CleanUpOldConnectionIds() {
QuicTime now = clock_.ApproximateNow();
- while (time_ordered_guid_list_.size() > 0) {
- DCHECK_EQ(time_ordered_guid_list_.size(), guid_map_.size());
- GuidAddTime* oldest_guid = time_ordered_guid_list_.front();
- if (now.Subtract(oldest_guid->time_added) < kTimeWaitPeriod_) {
+ while (!connection_id_map_.empty()) {
+ ConnectionIdMap::iterator it = connection_id_map_.begin();
+ QuicTime oldest_connection_id = it->second.time_added;
+ if (now.Subtract(oldest_connection_id) < kTimeWaitPeriod_) {
break;
}
- // This guid has lived its age, retire it now.
- GuidMapIterator it = guid_map_.find(oldest_guid->guid);
- DCHECK(it != guid_map_.end());
+ // This connection_id has lived its age, retire it now.
delete it->second.close_packet;
- guid_map_.erase(oldest_guid->guid);
- time_ordered_guid_list_.pop_front();
- delete oldest_guid;
+ connection_id_map_.erase(it);
}
- SetGuidCleanUpAlarm();
+ SetConnectionIdCleanUpAlarm();
}
} // namespace tools
diff --git a/chromium/net/tools/quic/quic_time_wait_list_manager.h b/chromium/net/tools/quic/quic_time_wait_list_manager.h
index bb24f144a02..426f09f0872 100644
--- a/chromium/net/tools/quic/quic_time_wait_list_manager.h
+++ b/chromium/net/tools/quic/quic_time_wait_list_manager.h
@@ -2,195 +2,175 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// Handles packets for guids in time wait state by discarding the packet and
-// sending the clients a public reset packet with exponential backoff.
+// Handles packets for connection_ids in time wait state by discarding the
+// packet and sending the clients a public reset packet with exponential
+// backoff.
#ifndef NET_TOOLS_QUIC_QUIC_TIME_WAIT_LIST_MANAGER_H_
#define NET_TOOLS_QUIC_QUIC_TIME_WAIT_LIST_MANAGER_H_
#include <deque>
+#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
#include "base/strings/string_piece.h"
+#include "net/base/linked_hash_map.h"
#include "net/quic/quic_blocked_writer_interface.h"
#include "net/quic/quic_framer.h"
#include "net/quic/quic_packet_writer.h"
#include "net/quic/quic_protocol.h"
-#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_epoll_clock.h"
namespace net {
+
+class EpollServer;
+
namespace tools {
-class GuidCleanUpAlarm;
+class ConnectionIdCleanUpAlarm;
+class QuicServerSessionVisitor;
namespace test {
class QuicTimeWaitListManagerPeer;
} // namespace test
-// Maintains a list of all guids that have been recently closed. A guid lives in
-// this state for kTimeWaitPeriod. All packets received for guids in this state
-// are handed over to the QuicTimeWaitListManager by the QuicDispatcher.
-// Decides whether to send a public reset packet, a copy of the previously sent
-// connection close packet, or nothing to the client which sent a packet
-// with the guid in time wait state. After the guid expires its time wait
-// period, a new connection/session will be created if a packet is received
-// for this guid.
-class QuicTimeWaitListManager : public QuicBlockedWriterInterface,
- public QuicFramerVisitorInterface {
+// Maintains a list of all connection_ids that have been recently closed. A
+// connection_id lives in this state for kTimeWaitPeriod. All packets received
+// for connection_ids in this state are handed over to the
+// QuicTimeWaitListManager by the QuicDispatcher. Decides whether to send a
+// public reset packet, a copy of the previously sent connection close packet,
+// or nothing to the client which sent a packet with the connection_id in time
+// wait state. After the connection_id expires its time wait period, a new
+// connection/session will be created if a packet is received for this
+// connection_id.
+class QuicTimeWaitListManager : public QuicBlockedWriterInterface {
public:
// writer - the entity that writes to the socket. (Owned by the dispatcher)
+ // visitor - the entity that manages blocked writers. (The dispatcher)
// epoll_server - used to run clean up alarms. (Owned by the dispatcher)
QuicTimeWaitListManager(QuicPacketWriter* writer,
+ QuicServerSessionVisitor* visitor,
EpollServer* epoll_server,
const QuicVersionVector& supported_versions);
virtual ~QuicTimeWaitListManager();
- // Adds the given guid to time wait state for kTimeWaitPeriod. Henceforth,
- // any packet bearing this guid should not be processed while the guid remains
- // in this list. If a non-NULL |close_packet| is provided, it is sent again
- // when packets are received for added guids. If NULL, a public reset packet
- // is sent with the specified |version|. DCHECKs that guid is not already on
- // the list.
- void AddGuidToTimeWait(QuicGuid guid,
- QuicVersion version,
- QuicEncryptedPacket* close_packet); // Owned.
-
- // Returns true if the guid is in time wait state, false otherwise. Packets
- // received for this guid should not lead to creation of new QuicSessions.
- bool IsGuidInTimeWait(QuicGuid guid) const;
-
- // Called when a packet is received for a guid that is in time wait state.
- // Sends a public reset packet to the client which sent this guid. Sending
- // of the public reset packet is throttled by using exponential back off.
- // DCHECKs for the guid to be in time wait state.
- // virtual to override in tests.
+ // Adds the given connection_id to time wait state for kTimeWaitPeriod.
+ // Henceforth, any packet bearing this connection_id should not be processed
+ // while the connection_id remains in this list. If a non-NULL |close_packet|
+ // is provided, it is sent again when packets are received for added
+ // connection_ids. If NULL, a public reset packet is sent with the specified
+ // |version|. DCHECKs that connection_id is not already on the list.
+ void AddConnectionIdToTimeWait(QuicConnectionId connection_id,
+ QuicVersion version,
+ QuicEncryptedPacket* close_packet); // Owned.
+
+ // Returns true if the connection_id is in time wait state, false otherwise.
+ // Packets received for this connection_id should not lead to creation of new
+ // QuicSessions.
+ bool IsConnectionIdInTimeWait(QuicConnectionId connection_id) const;
+
+ // Called when a packet is received for a connection_id that is in time wait
+ // state. Sends a public reset packet to the client which sent this
+ // connection_id. Sending of the public reset packet is throttled by using
+ // exponential back off. DCHECKs for the connection_id to be in time wait
+ // state. virtual to override in tests.
virtual void ProcessPacket(const IPEndPoint& server_address,
const IPEndPoint& client_address,
- QuicGuid guid,
+ QuicConnectionId connection_id,
+ QuicPacketSequenceNumber sequence_number,
const QuicEncryptedPacket& packet);
// Called by the dispatcher when the underlying socket becomes writable again,
// since we might need to send pending public reset packets which we didn't
// send because the underlying socket was write blocked.
- virtual bool OnCanWrite() OVERRIDE;
-
- // Used to delete guid entries that have outlived their time wait period.
- void CleanUpOldGuids();
-
- // QuicFramerVisitorInterface
- virtual void OnError(QuicFramer* framer) OVERRIDE;
- virtual bool OnProtocolVersionMismatch(QuicVersion received_version) OVERRIDE;
- virtual bool OnUnauthenticatedHeader(const QuicPacketHeader& header) OVERRIDE;
- virtual void OnPacket() OVERRIDE {}
- virtual void OnPublicResetPacket(
- const QuicPublicResetPacket& /*packet*/) OVERRIDE {}
- virtual void OnVersionNegotiationPacket(
- const QuicVersionNegotiationPacket& /*packet*/) OVERRIDE {}
-
- virtual void OnPacketComplete() OVERRIDE {}
- // The following methods should never get called because we always return
- // false from OnUnauthenticatedHeader(). We never process the encrypted bytes.
- virtual bool OnPacketHeader(const QuicPacketHeader& header) OVERRIDE;
- virtual void OnRevivedPacket() OVERRIDE;
- virtual void OnFecProtectedPayload(base::StringPiece /*payload*/) OVERRIDE;
- virtual bool OnStreamFrame(const QuicStreamFrame& /*frame*/) OVERRIDE;
- virtual bool OnAckFrame(const QuicAckFrame& /*frame*/) OVERRIDE;
- virtual bool OnCongestionFeedbackFrame(
- const QuicCongestionFeedbackFrame& /*frame*/) OVERRIDE;
- virtual bool OnRstStreamFrame(const QuicRstStreamFrame& /*frame*/) OVERRIDE;
- virtual bool OnConnectionCloseFrame(
- const QuicConnectionCloseFrame & /*frame*/) OVERRIDE;
- virtual bool OnGoAwayFrame(const QuicGoAwayFrame& /*frame*/) OVERRIDE;
- virtual void OnFecData(const QuicFecData& /*fec*/) OVERRIDE;
+ virtual void OnCanWrite() OVERRIDE;
+
+ // Used to delete connection_id entries that have outlived their time wait
+ // period.
+ void CleanUpOldConnectionIds();
+
+ // Given a ConnectionId that exists in the time wait list, returns the
+ // QuicVersion associated with it.
+ QuicVersion GetQuicVersionFromConnectionId(QuicConnectionId connection_id);
+
+ protected:
+ virtual QuicEncryptedPacket* BuildPublicReset(
+ const QuicPublicResetPacket& packet);
private:
friend class test::QuicTimeWaitListManagerPeer;
- // Stores the guid and the time it was added to time wait state.
- struct GuidAddTime;
// Internal structure to store pending public reset packets.
class QueuedPacket;
- // Decides if a packet should be sent for this guid based on the number of
- // received packets.
+ // Decides if a packet should be sent for this connection_id based on the
+ // number of received packets.
bool ShouldSendResponse(int received_packet_count);
- // Given a GUID that exists in the time wait list, returns the QuicVersion
- // associated with it. Used internally to set the framer version before
- // writing the public reset packet.
- QuicVersion GetQuicVersionFromGuid(QuicGuid guid);
-
// Creates a public reset packet and sends it or queues it to be sent later.
void SendPublicReset(const IPEndPoint& server_address,
const IPEndPoint& client_address,
- QuicGuid guid,
+ QuicConnectionId connection_id,
QuicPacketSequenceNumber rejected_sequence_number);
// Either sends the packet and deletes it or makes pending_packets_queue_ the
// owner of the packet.
void SendOrQueuePacket(QueuedPacket* packet);
- // Should only be called when write_blocked_ == false. We only care if the
- // writing was unsuccessful because the socket got blocked, which can be
- // tested using write_blocked_ == true. In case of all other errors we drop
- // the packet. Hence, we return void.
- void WriteToWire(QueuedPacket* packet);
+ // Sends the packet out. Returns true if the packet was successfully consumed.
+ // If the writer got blocked and did not buffer the packet, we'll need to keep
+ // the packet and retry sending. In case of all other errors we drop the
+ // packet.
+ bool WriteToWire(QueuedPacket* packet);
// Register the alarm with the epoll server to wake up at appropriate time.
- void SetGuidCleanUpAlarm();
-
- // A map from a recently closed guid to the number of packets received after
- // the termination of the connection bound to the guid.
- struct GuidData {
- GuidData(int num_packets_,
- QuicVersion version_,
- QuicEncryptedPacket* close_packet)
+ void SetConnectionIdCleanUpAlarm();
+
+ // A map from a recently closed connection_id to the number of packets
+ // received after the termination of the connection bound to the
+ // connection_id.
+ struct ConnectionIdData {
+ ConnectionIdData(int num_packets_,
+ QuicVersion version_,
+ QuicTime time_added_,
+ QuicEncryptedPacket* close_packet)
: num_packets(num_packets_),
version(version_),
+ time_added(time_added_),
close_packet(close_packet) {}
int num_packets;
QuicVersion version;
+ QuicTime time_added;
QuicEncryptedPacket* close_packet;
};
- base::hash_map<QuicGuid, GuidData> guid_map_;
- typedef base::hash_map<QuicGuid, GuidData>::iterator GuidMapIterator;
- // Maintains a list of GuidAddTime elements which it owns, in the
- // order they should be deleted.
- std::deque<GuidAddTime*> time_ordered_guid_list_;
+ // linked_hash_map allows lookup by ConnectionId and traversal in add order.
+ typedef linked_hash_map<QuicConnectionId, ConnectionIdData> ConnectionIdMap;
+ ConnectionIdMap connection_id_map_;
// Pending public reset packets that need to be sent out to the client
// when we are given a chance to write by the dispatcher.
std::deque<QueuedPacket*> pending_packets_queue_;
- // Used to parse incoming packets.
- QuicFramer framer_;
-
- // Server and client address of the last packet processed.
- IPEndPoint server_address_;
- IPEndPoint client_address_;
-
- // Used to schedule alarms to delete old guids which have been in the list for
- // too long. Owned by the dispatcher.
+ // Used to schedule alarms to delete old connection_ids which have been in the
+ // list for too long.
EpollServer* epoll_server_;
- // Time period for which guids should remain in time wait state.
+ // Time period for which connection_ids should remain in time wait state.
const QuicTime::Delta kTimeWaitPeriod_;
- // Alarm registered with the epoll server to clean up guids that have out
- // lived their duration in time wait state.
- scoped_ptr<GuidCleanUpAlarm> guid_clean_up_alarm_;
+ // Alarm registered with the epoll server to clean up connection_ids that have
+ // out lived their duration in time wait state.
+ scoped_ptr<ConnectionIdCleanUpAlarm> connection_id_clean_up_alarm_;
// Clock to efficiently measure approximate time from the epoll server.
QuicEpollClock clock_;
- // Interface that writes given buffer to the socket. Owned by the dispatcher.
+ // Interface that writes given buffer to the socket.
QuicPacketWriter* writer_;
- // True if the underlying udp socket is write blocked, i.e will return EAGAIN
- // on sendmsg.
- bool is_write_blocked_;
+ // Interface that manages blocked writers.
+ QuicServerSessionVisitor* visitor_;
DISALLOW_COPY_AND_ASSIGN(QuicTimeWaitListManager);
};
diff --git a/chromium/net/tools/quic/quic_time_wait_list_manager_test.cc b/chromium/net/tools/quic/quic_time_wait_list_manager_test.cc
index 22fd8ef4d06..67abd5928f7 100644
--- a/chromium/net/tools/quic/quic_time_wait_list_manager_test.cc
+++ b/chromium/net/tools/quic/quic_time_wait_list_manager_test.cc
@@ -14,37 +14,56 @@
#include "net/quic/quic_framer.h"
#include "net/quic/quic_packet_writer.h"
#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/tools/quic/test_tools/mock_epoll_server.h"
#include "net/tools/quic/test_tools/quic_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-using net::test::FramerVisitorCapturingPublicReset;
-using testing::_;
+using net::test::BuildUnsizedDataPacket;
+using net::test::NoOpFramerVisitor;
+using net::test::QuicVersionMax;
+using net::test::QuicVersionMin;
using testing::Args;
+using testing::Assign;
+using testing::DoAll;
using testing::Matcher;
using testing::MatcherInterface;
+using testing::NiceMock;
using testing::Return;
+using testing::ReturnPointee;
using testing::SetArgPointee;
+using testing::StrictMock;
using testing::Truly;
+using testing::_;
namespace net {
namespace tools {
namespace test {
-class QuicTimeWaitListManagerPeer {
+class FramerVisitorCapturingPublicReset : public NoOpFramerVisitor {
public:
- static QuicVersion version(QuicTimeWaitListManager* manager) {
- return manager->framer_.version();
+ FramerVisitorCapturingPublicReset() {}
+ virtual ~FramerVisitorCapturingPublicReset() OVERRIDE {}
+
+ virtual void OnPublicResetPacket(
+ const QuicPublicResetPacket& public_reset) OVERRIDE {
+ public_reset_packet_ = public_reset;
}
- static bool is_write_blocked(QuicTimeWaitListManager* manager) {
- return manager->is_write_blocked_;
+ const QuicPublicResetPacket public_reset_packet() {
+ return public_reset_packet_;
}
+ private:
+ QuicPublicResetPacket public_reset_packet_;
+};
+
+class QuicTimeWaitListManagerPeer {
+ public:
static bool ShouldSendResponse(QuicTimeWaitListManager* manager,
- int received_packet_count) {
+ int received_packet_count) {
return manager->ShouldSendResponse(received_packet_count);
}
@@ -52,67 +71,72 @@ class QuicTimeWaitListManagerPeer {
return manager->kTimeWaitPeriod_;
}
- static QuicVersion GetQuicVersionFromGuid(QuicTimeWaitListManager* manager,
- QuicGuid guid) {
- return manager->GetQuicVersionFromGuid(guid);
+ static QuicVersion GetQuicVersionFromConnectionId(
+ QuicTimeWaitListManager* manager,
+ QuicConnectionId connection_id) {
+ return manager->GetQuicVersionFromConnectionId(connection_id);
}
};
namespace {
-class TestTimeWaitListManager : public QuicTimeWaitListManager {
- public:
- TestTimeWaitListManager(QuicPacketWriter* writer,
- EpollServer* epoll_server)
- : QuicTimeWaitListManager(writer, epoll_server, QuicSupportedVersions()) {
- }
-};
-
class MockFakeTimeEpollServer : public FakeTimeEpollServer {
public:
MOCK_METHOD2(RegisterAlarm, void(int64 timeout_in_us,
EpollAlarmCallbackInterface* alarm));
};
-class QuicTimeWaitListManagerTest : public testing::Test {
+class QuicTimeWaitListManagerTest : public ::testing::Test {
protected:
QuicTimeWaitListManagerTest()
- : time_wait_list_manager_(
- &writer_, &epoll_server_, QuicSupportedVersions()),
+ : time_wait_list_manager_(&writer_, &visitor_,
+ &epoll_server_, QuicSupportedVersions()),
framer_(QuicSupportedVersions(), QuicTime::Zero(), true),
- guid_(45) {
- }
+ connection_id_(45),
+ client_address_(net::test::TestPeerIPAddress(), kTestPort),
+ writer_is_blocked_(false) {}
- virtual ~QuicTimeWaitListManagerTest() {}
+ virtual ~QuicTimeWaitListManagerTest() OVERRIDE {}
- void AddGuid(QuicGuid guid) {
- AddGuid(guid, net::test::QuicVersionMax(), NULL);
+ virtual void SetUp() OVERRIDE {
+ EXPECT_CALL(writer_, IsWriteBlocked())
+ .WillRepeatedly(ReturnPointee(&writer_is_blocked_));
+ EXPECT_CALL(writer_, IsWriteBlockedDataBuffered())
+ .WillRepeatedly(Return(false));
}
- void AddGuid(QuicGuid guid,
- QuicVersion version,
- QuicEncryptedPacket* packet) {
- time_wait_list_manager_.AddGuidToTimeWait(guid, version, packet);
+ void AddConnectionId(QuicConnectionId connection_id) {
+ AddConnectionId(connection_id, QuicVersionMax(), NULL);
}
- bool IsGuidInTimeWait(QuicGuid guid) {
- return time_wait_list_manager_.IsGuidInTimeWait(guid);
+ void AddConnectionId(QuicConnectionId connection_id,
+ QuicVersion version,
+ QuicEncryptedPacket* packet) {
+ time_wait_list_manager_.AddConnectionIdToTimeWait(
+ connection_id, version, packet);
}
- void ProcessPacket(QuicGuid guid, const QuicEncryptedPacket& packet) {
+ bool IsConnectionIdInTimeWait(QuicConnectionId connection_id) {
+ return time_wait_list_manager_.IsConnectionIdInTimeWait(connection_id);
+ }
+
+ void ProcessPacket(QuicConnectionId connection_id,
+ QuicPacketSequenceNumber sequence_number) {
+ QuicEncryptedPacket packet(NULL, 0);
time_wait_list_manager_.ProcessPacket(server_address_,
client_address_,
- guid,
+ connection_id,
+ sequence_number,
packet);
}
QuicEncryptedPacket* ConstructEncryptedPacket(
EncryptionLevel level,
- QuicGuid guid,
+ QuicConnectionId connection_id,
QuicPacketSequenceNumber sequence_number) {
QuicPacketHeader header;
- header.public_header.guid = guid;
- header.public_header.guid_length = PACKET_8BYTE_GUID;
+ header.public_header.connection_id = connection_id;
+ header.public_header.connection_id_length = PACKET_8BYTE_CONNECTION_ID;
header.public_header.version_flag = false;
header.public_header.reset_flag = false;
header.public_header.sequence_number_length = PACKET_6BYTE_SEQUENCE_NUMBER;
@@ -127,7 +151,7 @@ class QuicTimeWaitListManagerTest : public testing::Test {
QuicFrames frames;
frames.push_back(frame);
scoped_ptr<QuicPacket> packet(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ BuildUnsizedDataPacket(&framer_, header, frames).packet);
EXPECT_TRUE(packet != NULL);
QuicEncryptedPacket* encrypted = framer_.EncryptPacket(ENCRYPTION_NONE,
sequence_number,
@@ -136,26 +160,28 @@ class QuicTimeWaitListManagerTest : public testing::Test {
return encrypted;
}
- MockFakeTimeEpollServer epoll_server_;
- MockPacketWriter writer_;
+ NiceMock<MockFakeTimeEpollServer> epoll_server_;
+ StrictMock<MockPacketWriter> writer_;
+ StrictMock<MockQuicServerSessionVisitor> visitor_;
QuicTimeWaitListManager time_wait_list_manager_;
QuicFramer framer_;
- QuicGuid guid_;
+ QuicConnectionId connection_id_;
IPEndPoint server_address_;
IPEndPoint client_address_;
+ bool writer_is_blocked_;
};
class ValidatePublicResetPacketPredicate
: public MatcherInterface<const std::tr1::tuple<const char*, int> > {
public:
- explicit ValidatePublicResetPacketPredicate(QuicGuid guid,
+ explicit ValidatePublicResetPacketPredicate(QuicConnectionId connection_id,
QuicPacketSequenceNumber number)
- : guid_(guid), sequence_number_(number) {
+ : connection_id_(connection_id), sequence_number_(number) {
}
virtual bool MatchAndExplain(
const std::tr1::tuple<const char*, int> packet_buffer,
- testing::MatchResultListener* /* listener */) const {
+ testing::MatchResultListener* /* listener */) const OVERRIDE {
FramerVisitorCapturingPublicReset visitor;
QuicFramer framer(QuicSupportedVersions(),
QuicTime::Zero(),
@@ -165,119 +191,73 @@ class ValidatePublicResetPacketPredicate
std::tr1::get<1>(packet_buffer));
framer.ProcessPacket(encrypted);
QuicPublicResetPacket packet = visitor.public_reset_packet();
- return guid_ == packet.public_header.guid &&
+ return connection_id_ == packet.public_header.connection_id &&
packet.public_header.reset_flag && !packet.public_header.version_flag &&
- sequence_number_ == packet.rejected_sequence_number;
+ sequence_number_ == packet.rejected_sequence_number &&
+ net::test::TestPeerIPAddress() == packet.client_address.address() &&
+ kTestPort == packet.client_address.port();
}
- virtual void DescribeTo(::std::ostream* os) const { }
+ virtual void DescribeTo(::std::ostream* os) const OVERRIDE {}
- virtual void DescribeNegationTo(::std::ostream* os) const { }
+ virtual void DescribeNegationTo(::std::ostream* os) const OVERRIDE {}
private:
- QuicGuid guid_;
+ QuicConnectionId connection_id_;
QuicPacketSequenceNumber sequence_number_;
};
Matcher<const std::tr1::tuple<const char*, int> > PublicResetPacketEq(
- QuicGuid guid,
+ QuicConnectionId connection_id,
QuicPacketSequenceNumber sequence_number) {
- return MakeMatcher(new ValidatePublicResetPacketPredicate(guid,
+ return MakeMatcher(new ValidatePublicResetPacketPredicate(connection_id,
sequence_number));
}
-TEST_F(QuicTimeWaitListManagerTest, CheckGuidInTimeWait) {
- EXPECT_FALSE(IsGuidInTimeWait(guid_));
- AddGuid(guid_);
- EXPECT_TRUE(IsGuidInTimeWait(guid_));
+TEST_F(QuicTimeWaitListManagerTest, CheckConnectionIdInTimeWait) {
+ EXPECT_FALSE(IsConnectionIdInTimeWait(connection_id_));
+ AddConnectionId(connection_id_);
+ EXPECT_TRUE(IsConnectionIdInTimeWait(connection_id_));
}
TEST_F(QuicTimeWaitListManagerTest, SendConnectionClose) {
size_t kConnectionCloseLength = 100;
- AddGuid(guid_,
- net::test::QuicVersionMax(),
- new QuicEncryptedPacket(
- new char[kConnectionCloseLength], kConnectionCloseLength, true));
+ AddConnectionId(
+ connection_id_,
+ QuicVersionMax(),
+ new QuicEncryptedPacket(
+ new char[kConnectionCloseLength], kConnectionCloseLength, true));
const int kRandomSequenceNumber = 1;
- scoped_ptr<QuicEncryptedPacket> packet(
- ConstructEncryptedPacket(ENCRYPTION_NONE, guid_, kRandomSequenceNumber));
EXPECT_CALL(writer_, WritePacket(_, kConnectionCloseLength,
server_address_.address(),
- client_address_,
- &time_wait_list_manager_))
+ client_address_))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1)));
- ProcessPacket(guid_, *packet);
+ ProcessPacket(connection_id_, kRandomSequenceNumber);
}
TEST_F(QuicTimeWaitListManagerTest, SendPublicReset) {
- AddGuid(guid_);
- const int kRandomSequenceNumber = 1;
- scoped_ptr<QuicEncryptedPacket> packet(
- ConstructEncryptedPacket(ENCRYPTION_NONE, guid_, kRandomSequenceNumber));
- EXPECT_CALL(writer_, WritePacket(_, _,
- server_address_.address(),
- client_address_,
- &time_wait_list_manager_))
- .With(Args<0, 1>(PublicResetPacketEq(guid_,
- kRandomSequenceNumber)))
- .WillOnce(Return(WriteResult(WRITE_STATUS_OK, packet->length())));
-
- ProcessPacket(guid_, *packet);
-}
-
-TEST_F(QuicTimeWaitListManagerTest, SendPublicResetUndecryptable) {
- AddGuid(guid_);
+ AddConnectionId(connection_id_);
const int kRandomSequenceNumber = 1;
- scoped_ptr<QuicEncryptedPacket> packet(
- ConstructEncryptedPacket(
- ENCRYPTION_INITIAL, guid_, kRandomSequenceNumber));
EXPECT_CALL(writer_, WritePacket(_, _,
server_address_.address(),
- client_address_,
- &time_wait_list_manager_))
- .With(Args<0, 1>(PublicResetPacketEq(guid_,
+ client_address_))
+ .With(Args<0, 1>(PublicResetPacketEq(connection_id_,
kRandomSequenceNumber)))
- .WillOnce(Return(WriteResult(WRITE_STATUS_OK, packet->length())));
-
- ProcessPacket(guid_, *packet);
-}
-
-TEST_F(QuicTimeWaitListManagerTest, DropInvalidPacket) {
- AddGuid(guid_);
- const char buffer[] = "invalid";
- QuicEncryptedPacket packet(buffer, arraysize(buffer));
- // Will get called for a valid packet since received packet count = 1 (2 ^ 0).
- EXPECT_CALL(writer_, WritePacket(_, _, _, _, _)).Times(0);
- ProcessPacket(guid_, packet);
-}
+ .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
-TEST_F(QuicTimeWaitListManagerTest, DropPublicResetPacket) {
- AddGuid(guid_);
- QuicPublicResetPacket packet;
- packet.public_header.guid = guid_;
- packet.public_header.version_flag = false;
- packet.public_header.reset_flag = true;
- packet.rejected_sequence_number = 239191;
- packet.nonce_proof = 1010101;
- scoped_ptr<QuicEncryptedPacket> public_reset_packet(
- QuicFramer::BuildPublicResetPacket(packet));
- // Will get called for a data packet since received packet count = 1 (2 ^ 0).
- EXPECT_CALL(writer_, WritePacket(_, _, _, _, _)).Times(0);
- ProcessPacket(guid_, *public_reset_packet);
+ ProcessPacket(connection_id_, kRandomSequenceNumber);
}
TEST_F(QuicTimeWaitListManagerTest, SendPublicResetWithExponentialBackOff) {
- AddGuid(guid_);
+ AddConnectionId(connection_id_);
for (int sequence_number = 1; sequence_number < 101; ++sequence_number) {
- scoped_ptr<QuicEncryptedPacket> packet(
- ConstructEncryptedPacket(ENCRYPTION_NONE, guid_, sequence_number));
if ((sequence_number & (sequence_number - 1)) == 0) {
- EXPECT_CALL(writer_, WritePacket(_, _, _, _, _))
+ EXPECT_CALL(writer_, WritePacket(_, _, _, _))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1)));
}
- ProcessPacket(guid_, *packet);
+ ProcessPacket(connection_id_, sequence_number);
// Send public reset with exponential back off.
if ((sequence_number & (sequence_number - 1)) == 0) {
EXPECT_TRUE(QuicTimeWaitListManagerPeer::ShouldSendResponse(
@@ -289,157 +269,192 @@ TEST_F(QuicTimeWaitListManagerTest, SendPublicResetWithExponentialBackOff) {
}
}
-TEST_F(QuicTimeWaitListManagerTest, CleanUpOldGuids) {
- const int kGuidCount = 100;
- const int kOldGuidCount = 31;
+TEST_F(QuicTimeWaitListManagerTest, CleanUpOldConnectionIds) {
+ const int kConnectionIdCount = 100;
+ const int kOldConnectionIdCount = 31;
- // Add guids such that their expiry time is kTimeWaitPeriod_.
+ // Add connection_ids such that their expiry time is kTimeWaitPeriod_.
epoll_server_.set_now_in_usec(0);
- for (int guid = 1; guid <= kOldGuidCount; ++guid) {
- AddGuid(guid);
+ for (int connection_id = 1;
+ connection_id <= kOldConnectionIdCount;
+ ++connection_id) {
+ AddConnectionId(connection_id);
}
- // Add remaining guids such that their add time is 2 * kTimeWaitPeriod.
+ // Add remaining connection_ids such that their add time is
+ // 2 * kTimeWaitPeriod.
const QuicTime::Delta time_wait_period =
QuicTimeWaitListManagerPeer::time_wait_period(&time_wait_list_manager_);
epoll_server_.set_now_in_usec(time_wait_period.ToMicroseconds());
- for (int guid = kOldGuidCount + 1; guid <= kGuidCount; ++guid) {
- AddGuid(guid);
+ for (int connection_id = kOldConnectionIdCount + 1;
+ connection_id <= kConnectionIdCount;
+ ++connection_id) {
+ AddConnectionId(connection_id);
}
QuicTime::Delta offset = QuicTime::Delta::FromMicroseconds(39);
// Now set the current time as time_wait_period + offset usecs.
epoll_server_.set_now_in_usec(time_wait_period.Add(offset).ToMicroseconds());
- // After all the old guids are cleaned up, check the next alarm interval.
+ // After all the old connection_ids are cleaned up, check the next alarm
+ // interval.
int64 next_alarm_time = epoll_server_.ApproximateNowInUsec() +
time_wait_period.Subtract(offset).ToMicroseconds();
EXPECT_CALL(epoll_server_, RegisterAlarm(next_alarm_time, _));
- time_wait_list_manager_.CleanUpOldGuids();
- for (int guid = 1; guid <= kGuidCount; ++guid) {
- EXPECT_EQ(guid > kOldGuidCount, IsGuidInTimeWait(guid))
- << "kOldGuidCount: " << kOldGuidCount
- << " guid: " << guid;
+ time_wait_list_manager_.CleanUpOldConnectionIds();
+ for (int connection_id = 1;
+ connection_id <= kConnectionIdCount;
+ ++connection_id) {
+ EXPECT_EQ(connection_id > kOldConnectionIdCount,
+ IsConnectionIdInTimeWait(connection_id))
+ << "kOldConnectionIdCount: " << kOldConnectionIdCount
+ << " connection_id: " << connection_id;
}
}
TEST_F(QuicTimeWaitListManagerTest, SendQueuedPackets) {
- QuicGuid guid = 1;
- AddGuid(guid);
+ QuicConnectionId connection_id = 1;
+ AddConnectionId(connection_id);
QuicPacketSequenceNumber sequence_number = 234;
- scoped_ptr<QuicEncryptedPacket> packet(
- ConstructEncryptedPacket(ENCRYPTION_NONE, guid, sequence_number));
+ scoped_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
+ ENCRYPTION_NONE, connection_id, sequence_number));
// Let first write through.
EXPECT_CALL(writer_, WritePacket(_, _,
server_address_.address(),
- client_address_,
- &time_wait_list_manager_))
- .With(Args<0, 1>(PublicResetPacketEq(guid,
+ client_address_))
+ .With(Args<0, 1>(PublicResetPacketEq(connection_id,
sequence_number)))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, packet->length())));
- ProcessPacket(guid, *packet);
- EXPECT_FALSE(
- QuicTimeWaitListManagerPeer::is_write_blocked(&time_wait_list_manager_));
+ ProcessPacket(connection_id, sequence_number);
// write block for the next packet.
EXPECT_CALL(writer_, WritePacket(_, _,
server_address_.address(),
- client_address_,
- &time_wait_list_manager_))
- .With(Args<0, 1>(PublicResetPacketEq(guid,
+ client_address_))
+ .With(Args<0, 1>(PublicResetPacketEq(connection_id,
sequence_number)))
- .WillOnce(Return(WriteResult(WRITE_STATUS_BLOCKED, EAGAIN)));
- ProcessPacket(guid, *packet);
+ .WillOnce(DoAll(
+ Assign(&writer_is_blocked_, true),
+ Return(WriteResult(WRITE_STATUS_BLOCKED, EAGAIN))));
+ EXPECT_CALL(visitor_, OnWriteBlocked(&time_wait_list_manager_));
+ ProcessPacket(connection_id, sequence_number);
// 3rd packet. No public reset should be sent;
- ProcessPacket(guid, *packet);
- EXPECT_TRUE(
- QuicTimeWaitListManagerPeer::is_write_blocked(&time_wait_list_manager_));
+ ProcessPacket(connection_id, sequence_number);
- // write packet should not be called since already write blocked but the
+ // write packet should not be called since we are write blocked but the
// should be queued.
- QuicGuid other_guid = 2;
- AddGuid(other_guid);
+ QuicConnectionId other_connection_id = 2;
+ AddConnectionId(other_connection_id);
QuicPacketSequenceNumber other_sequence_number = 23423;
scoped_ptr<QuicEncryptedPacket> other_packet(
ConstructEncryptedPacket(
- ENCRYPTION_NONE, other_guid, other_sequence_number));
- EXPECT_CALL(writer_, WritePacket(_, _, _, _, _))
+ ENCRYPTION_NONE, other_connection_id, other_sequence_number));
+ EXPECT_CALL(writer_, WritePacket(_, _, _, _))
.Times(0);
- ProcessPacket(other_guid, *other_packet);
+ EXPECT_CALL(visitor_, OnWriteBlocked(&time_wait_list_manager_));
+ ProcessPacket(other_connection_id, other_sequence_number);
// Now expect all the write blocked public reset packets to be sent again.
+ writer_is_blocked_ = false;
EXPECT_CALL(writer_, WritePacket(_, _,
server_address_.address(),
- client_address_,
- &time_wait_list_manager_))
- .With(Args<0, 1>(PublicResetPacketEq(guid,
+ client_address_))
+ .With(Args<0, 1>(PublicResetPacketEq(connection_id,
sequence_number)))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, packet->length())));
EXPECT_CALL(writer_, WritePacket(_, _,
server_address_.address(),
- client_address_,
- &time_wait_list_manager_))
- .With(Args<0, 1>(PublicResetPacketEq(other_guid,
+ client_address_))
+ .With(Args<0, 1>(PublicResetPacketEq(other_connection_id,
other_sequence_number)))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK,
other_packet->length())));
time_wait_list_manager_.OnCanWrite();
- EXPECT_FALSE(
- QuicTimeWaitListManagerPeer::is_write_blocked(&time_wait_list_manager_));
}
-TEST_F(QuicTimeWaitListManagerTest, MakeSureFramerUsesCorrectVersion) {
+TEST_F(QuicTimeWaitListManagerTest, GetQuicVersionFromMap) {
+ const int kConnectionId1 = 123;
+ const int kConnectionId2 = 456;
+ const int kConnectionId3 = 789;
+
+ AddConnectionId(kConnectionId1, QuicVersionMin(), NULL);
+ AddConnectionId(kConnectionId2, QuicVersionMax(), NULL);
+ AddConnectionId(kConnectionId3, QuicVersionMax(), NULL);
+
+ EXPECT_EQ(QuicVersionMin(),
+ QuicTimeWaitListManagerPeer::GetQuicVersionFromConnectionId(
+ &time_wait_list_manager_, kConnectionId1));
+ EXPECT_EQ(QuicVersionMax(),
+ QuicTimeWaitListManagerPeer::GetQuicVersionFromConnectionId(
+ &time_wait_list_manager_, kConnectionId2));
+ EXPECT_EQ(QuicVersionMax(),
+ QuicTimeWaitListManagerPeer::GetQuicVersionFromConnectionId(
+ &time_wait_list_manager_, kConnectionId3));
+}
+
+TEST_F(QuicTimeWaitListManagerTest, AddConnectionIdTwice) {
+ // Add connection_ids such that their expiry time is kTimeWaitPeriod_.
+ epoll_server_.set_now_in_usec(0);
+ AddConnectionId(connection_id_);
+ EXPECT_TRUE(IsConnectionIdInTimeWait(connection_id_));
+ size_t kConnectionCloseLength = 100;
+ AddConnectionId(
+ connection_id_,
+ QuicVersionMax(),
+ new QuicEncryptedPacket(
+ new char[kConnectionCloseLength], kConnectionCloseLength, true));
+ EXPECT_TRUE(IsConnectionIdInTimeWait(connection_id_));
+
+ EXPECT_CALL(writer_, WritePacket(_,
+ kConnectionCloseLength,
+ server_address_.address(),
+ client_address_))
+ .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1)));
+
const int kRandomSequenceNumber = 1;
- scoped_ptr<QuicEncryptedPacket> packet;
+ ProcessPacket(connection_id_, kRandomSequenceNumber);
- AddGuid(guid_, net::test::QuicVersionMin(), NULL);
- framer_.set_version(net::test::QuicVersionMin());
- packet.reset(
- ConstructEncryptedPacket(ENCRYPTION_NONE, guid_, kRandomSequenceNumber));
+ const QuicTime::Delta time_wait_period =
+ QuicTimeWaitListManagerPeer::time_wait_period(&time_wait_list_manager_);
- // Reset packet should be written, using the minimum quic version.
- EXPECT_CALL(writer_, WritePacket(_, _, _, _, _)).Times(1)
- .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
- ProcessPacket(guid_, *packet);
- EXPECT_EQ(QuicTimeWaitListManagerPeer::version(&time_wait_list_manager_),
- net::test::QuicVersionMin());
-
- // New guid
- ++guid_;
-
- AddGuid(guid_, net::test::QuicVersionMax(), NULL);
- framer_.set_version(net::test::QuicVersionMax());
- packet.reset(
- ConstructEncryptedPacket(ENCRYPTION_NONE, guid_, kRandomSequenceNumber));
-
- // Reset packet should be written, using the maximum quic version.
- EXPECT_CALL(writer_, WritePacket(_, _, _, _, _)).Times(1)
- .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
- ProcessPacket(guid_, *packet);
- EXPECT_EQ(QuicTimeWaitListManagerPeer::version(&time_wait_list_manager_),
- net::test::QuicVersionMax());
-}
+ QuicTime::Delta offset = QuicTime::Delta::FromMicroseconds(39);
+ // Now set the current time as time_wait_period + offset usecs.
+ epoll_server_.set_now_in_usec(time_wait_period.Add(offset).ToMicroseconds());
+ // After the connection_ids are cleaned up, check the next alarm interval.
+ int64 next_alarm_time = epoll_server_.ApproximateNowInUsec() +
+ time_wait_period.ToMicroseconds();
-TEST_F(QuicTimeWaitListManagerTest, GetQuicVersionFromMap) {
- const int kGuid1 = 123;
- const int kGuid2 = 456;
- const int kGuid3 = 789;
-
- AddGuid(kGuid1, net::test::QuicVersionMin(), NULL);
- AddGuid(kGuid2, net::test::QuicVersionMax(), NULL);
- AddGuid(kGuid3, net::test::QuicVersionMax(), NULL);
-
- EXPECT_EQ(net::test::QuicVersionMin(),
- QuicTimeWaitListManagerPeer::GetQuicVersionFromGuid(
- &time_wait_list_manager_, kGuid1));
- EXPECT_EQ(net::test::QuicVersionMax(),
- QuicTimeWaitListManagerPeer::GetQuicVersionFromGuid(
- &time_wait_list_manager_, kGuid2));
- EXPECT_EQ(net::test::QuicVersionMax(),
- QuicTimeWaitListManagerPeer::GetQuicVersionFromGuid(
- &time_wait_list_manager_, kGuid3));
+ EXPECT_CALL(epoll_server_, RegisterAlarm(next_alarm_time, _));
+ time_wait_list_manager_.CleanUpOldConnectionIds();
+ EXPECT_FALSE(IsConnectionIdInTimeWait(connection_id_));
}
+TEST_F(QuicTimeWaitListManagerTest, ConnectionIdsOrderedByTime) {
+ // Simple randomization: the values of connection_ids are swapped based on the
+ // current seconds on the clock. If the container is broken, the test will be
+ // 50% flaky.
+ int odd_second = static_cast<int>(epoll_server_.ApproximateNowInUsec()) % 2;
+ EXPECT_TRUE(odd_second == 0 || odd_second == 1);
+ const QuicConnectionId kConnectionId1 = odd_second;
+ const QuicConnectionId kConnectionId2 = 1 - odd_second;
+
+ // 1 will hash lower than 2, but we add it later. They should come out in the
+ // add order, not hash order.
+ epoll_server_.set_now_in_usec(0);
+ AddConnectionId(kConnectionId1);
+ epoll_server_.set_now_in_usec(10);
+ AddConnectionId(kConnectionId2);
+
+ const QuicTime::Delta time_wait_period =
+ QuicTimeWaitListManagerPeer::time_wait_period(&time_wait_list_manager_);
+ epoll_server_.set_now_in_usec(time_wait_period.ToMicroseconds() + 1);
+
+ EXPECT_CALL(epoll_server_, RegisterAlarm(_, _));
+
+ time_wait_list_manager_.CleanUpOldConnectionIds();
+ EXPECT_FALSE(IsConnectionIdInTimeWait(kConnectionId1));
+ EXPECT_TRUE(IsConnectionIdInTimeWait(kConnectionId2));
+}
} // namespace
} // namespace test
} // namespace tools
diff --git a/chromium/net/tools/quic/spdy_utils.cc b/chromium/net/tools/quic/spdy_utils.cc
index c350a96f9e2..7f146493671 100644
--- a/chromium/net/tools/quic/spdy_utils.cc
+++ b/chromium/net/tools/quic/spdy_utils.cc
@@ -38,8 +38,8 @@ void PopulateSpdyHeaderBlock(const BalsaHeaders& headers,
hi != headers.header_lines_end();
++hi) {
if ((hi->second.length() == 0) && !allow_empty_values) {
- DLOG(INFO) << "Dropping empty header " << hi->first.as_string()
- << " from headers";
+ DVLOG(1) << "Dropping empty header " << hi->first.as_string()
+ << " from headers";
continue;
}
@@ -157,8 +157,8 @@ string SpdyUtils::SerializeResponseHeaders(
// static
string SpdyUtils::SerializeUncompressedHeaders(const SpdyHeaderBlock& headers) {
- int length = SpdyFramer::GetSerializedLength(SPDY3, &headers);
- SpdyFrameBuilder builder(length);
+ size_t length = SpdyFramer::GetSerializedLength(SPDY3, &headers);
+ SpdyFrameBuilder builder(length, SPDY3);
SpdyFramer::WriteHeaderBlock(&builder, SPDY3, &headers);
scoped_ptr<SpdyFrame> block(builder.take());
return string(block->data(), length);
diff --git a/chromium/net/tools/quic/spdy_utils.h b/chromium/net/tools/quic/spdy_utils.h
index cfad5f1918b..e0ae4edb905 100644
--- a/chromium/net/tools/quic/spdy_utils.h
+++ b/chromium/net/tools/quic/spdy_utils.h
@@ -37,6 +37,9 @@ class SpdyUtils {
static std::string SerializeUncompressedHeaders(
const SpdyHeaderBlock& headers);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SpdyUtils);
};
} // namespace tools
diff --git a/chromium/net/tools/quic/test_tools/http_message_test_utils.cc b/chromium/net/tools/quic/test_tools/http_message.cc
index 70eb59290fa..9bd3cffc312 100644
--- a/chromium/net/tools/quic/test_tools/http_message_test_utils.cc
+++ b/chromium/net/tools/quic/test_tools/http_message.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "net/tools/quic/test_tools/http_message_test_utils.h"
+#include "net/tools/quic/test_tools/http_message.h"
#include <vector>
diff --git a/chromium/net/tools/quic/test_tools/http_message_test_utils.h b/chromium/net/tools/quic/test_tools/http_message.h
index fefdb4909cd..6b63dafd76c 100644
--- a/chromium/net/tools/quic/test_tools/http_message_test_utils.h
+++ b/chromium/net/tools/quic/test_tools/http_message.h
@@ -1,9 +1,9 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef NET_TOOLS_QUIC_TEST_TOOLS_TEST_TOOLS_HTTP_MESSAGE_TEST_UTILS_H_
-#define NET_TOOLS_QUIC_TEST_TOOLS_TEST_TOOLS_HTTP_MESSAGE_TEST_UTILS_H_
+#ifndef NET_TOOLS_QUIC_TEST_TOOLS_TEST_TOOLS_HTTP_MESSAGE_H_
+#define NET_TOOLS_QUIC_TEST_TOOLS_TEST_TOOLS_HTTP_MESSAGE_H_
#include <string>
#include <vector>
@@ -130,4 +130,4 @@ class HTTPMessage {
} // namespace tools
} // namespace net
-#endif // NET_TOOLS_QUIC_TEST_TOOLS_TEST_TOOLS_HTTP_MESSAGE_TEST_UTILS_H_
+#endif // NET_TOOLS_QUIC_TEST_TOOLS_TEST_TOOLS_HTTP_MESSAGE_H_
diff --git a/chromium/net/tools/quic/test_tools/mock_epoll_server.h b/chromium/net/tools/quic/test_tools/mock_epoll_server.h
index fbc16956d72..cdb6a36a7ce 100644
--- a/chromium/net/tools/quic/test_tools/mock_epoll_server.h
+++ b/chromium/net/tools/quic/test_tools/mock_epoll_server.h
@@ -43,6 +43,8 @@ class FakeTimeEpollServer : public EpollServer {
private:
int64 now_in_usec_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeTimeEpollServer);
};
class MockEpollServer : public FakeTimeEpollServer {
@@ -83,20 +85,22 @@ class MockEpollServer : public FakeTimeEpollServer {
protected: // functions
// These functions do nothing here, as we're not actually
// using the epoll_* syscalls.
- virtual void DelFD(int fd) const OVERRIDE { }
- virtual void AddFD(int fd, int event_mask) const OVERRIDE { }
- virtual void ModFD(int fd, int event_mask) const OVERRIDE { }
+ virtual void DelFD(int fd) const OVERRIDE {}
+ virtual void AddFD(int fd, int event_mask) const OVERRIDE {}
+ virtual void ModFD(int fd, int event_mask) const OVERRIDE {}
// Replaces the epoll_server's epoll_wait_impl.
virtual int epoll_wait_impl(int epfd,
struct epoll_event* events,
int max_events,
int timeout_in_ms) OVERRIDE;
- virtual void SetNonblocking (int fd) OVERRIDE { }
+ virtual void SetNonblocking (int fd) OVERRIDE {}
private: // members
EventQueue event_queue_;
int64 until_in_usec_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockEpollServer);
};
} // namespace test
diff --git a/chromium/net/tools/quic/test_tools/mock_quic_dispatcher.cc b/chromium/net/tools/quic/test_tools/mock_quic_dispatcher.cc
index 2d9c1ec184f..13271ca8afc 100644
--- a/chromium/net/tools/quic/test_tools/mock_quic_dispatcher.cc
+++ b/chromium/net/tools/quic/test_tools/mock_quic_dispatcher.cc
@@ -4,6 +4,8 @@
#include "net/tools/quic/test_tools/mock_quic_dispatcher.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+
namespace net {
namespace tools {
namespace test {
@@ -11,11 +13,12 @@ namespace test {
MockQuicDispatcher::MockQuicDispatcher(
const QuicConfig& config,
const QuicCryptoServerConfig& crypto_config,
- QuicGuid guid,
EpollServer* eps)
- : QuicDispatcher(config, crypto_config, QuicSupportedVersions(), guid,
- eps) {
-}
+ : QuicDispatcher(config,
+ crypto_config,
+ QuicSupportedVersions(),
+ eps) {}
+
MockQuicDispatcher::~MockQuicDispatcher() {}
} // namespace test
diff --git a/chromium/net/tools/quic/test_tools/mock_quic_dispatcher.h b/chromium/net/tools/quic/test_tools/mock_quic_dispatcher.h
index 5f885e875b6..d1559115bf2 100644
--- a/chromium/net/tools/quic/test_tools/mock_quic_dispatcher.h
+++ b/chromium/net/tools/quic/test_tools/mock_quic_dispatcher.h
@@ -21,15 +21,16 @@ class MockQuicDispatcher : public QuicDispatcher {
public:
MockQuicDispatcher(const QuicConfig& config,
const QuicCryptoServerConfig& crypto_config,
- QuicGuid guid,
EpollServer* eps);
+
virtual ~MockQuicDispatcher();
- MOCK_METHOD5(ProcessPacket, void(const IPEndPoint& server_address,
+ MOCK_METHOD3(ProcessPacket, void(const IPEndPoint& server_address,
const IPEndPoint& client_address,
- QuicGuid guid,
- bool has_version_flag,
const QuicEncryptedPacket& packet));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockQuicDispatcher);
};
} // namespace test
diff --git a/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.cc b/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.cc
index 11aafb69495..05a7385181f 100644
--- a/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.cc
+++ b/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.cc
@@ -10,8 +10,6 @@
#include "net/tools/quic/quic_epoll_connection_helper.h"
#include "net/tools/quic/quic_socket_utils.h"
-using net::test::QuicTestWriter;
-
namespace net {
namespace tools {
namespace test {
@@ -21,11 +19,11 @@ namespace test {
class WriteUnblockedAlarm : public QuicAlarm::Delegate {
public:
explicit WriteUnblockedAlarm(PacketDroppingTestWriter* writer)
- : writer_(writer) { }
+ : writer_(writer) {}
virtual QuicTime OnAlarm() OVERRIDE {
- DCHECK(writer_->blocked_writer());
- writer_->blocked_writer()->OnCanWrite();
+ DVLOG(1) << "Unblocking socket.";
+ writer_->OnCanWrite();
return QuicTime::Zero();
}
@@ -37,8 +35,7 @@ class WriteUnblockedAlarm : public QuicAlarm::Delegate {
// later point.
class DelayAlarm : public QuicAlarm::Delegate {
public:
- explicit DelayAlarm(PacketDroppingTestWriter* writer)
- : writer_(writer) { }
+ explicit DelayAlarm(PacketDroppingTestWriter* writer) : writer_(writer) {}
virtual QuicTime OnAlarm() OVERRIDE {
return writer_->ReleaseOldPackets();
@@ -50,7 +47,6 @@ class DelayAlarm : public QuicAlarm::Delegate {
PacketDroppingTestWriter::PacketDroppingTestWriter()
: clock_(NULL),
- blocked_writer_(NULL),
cur_buffer_size_(0),
config_mutex_(),
fake_packet_loss_percentage_(0),
@@ -60,45 +56,45 @@ PacketDroppingTestWriter::PacketDroppingTestWriter()
fake_bandwidth_(QuicBandwidth::Zero()),
buffer_size_(0) {
uint32 seed = base::RandInt(0, std::numeric_limits<int32>::max());
- LOG(INFO) << "Seeding packet loss with " << seed;
+ VLOG(1) << "Seeding packet loss with " << seed;
simple_random_.set_seed(seed);
}
-PacketDroppingTestWriter::~PacketDroppingTestWriter() { }
+PacketDroppingTestWriter::~PacketDroppingTestWriter() {}
-void PacketDroppingTestWriter::SetConnectionHelper(
- QuicEpollConnectionHelper* helper) {
+void PacketDroppingTestWriter::Initialize(
+ QuicEpollConnectionHelper* helper,
+ Delegate* on_can_write) {
clock_ = helper->GetClock();
write_unblocked_alarm_.reset(
helper->CreateAlarm(new WriteUnblockedAlarm(this)));
delay_alarm_.reset(
helper->CreateAlarm(new DelayAlarm(this)));
+ on_can_write_.reset(on_can_write);
}
WriteResult PacketDroppingTestWriter::WritePacket(
- const char* buffer, size_t buf_len,
+ const char* buffer,
+ size_t buf_len,
const net::IPAddressNumber& self_address,
- const net::IPEndPoint& peer_address,
- QuicBlockedWriterInterface* blocked_writer) {
+ const net::IPEndPoint& peer_address) {
ReleaseOldPackets();
base::AutoLock locked(config_mutex_);
if (fake_packet_loss_percentage_ > 0 &&
simple_random_.RandUint64() % 100 <
static_cast<uint64>(fake_packet_loss_percentage_)) {
- DLOG(INFO) << "Dropping packet.";
+ DVLOG(1) << "Dropping packet.";
return WriteResult(WRITE_STATUS_OK, buf_len);
}
if (fake_blocked_socket_percentage_ > 0 &&
simple_random_.RandUint64() % 100 <
static_cast<uint64>(fake_blocked_socket_percentage_)) {
- DLOG(INFO) << "Blocking socket.";
+ CHECK(on_can_write_.get() != NULL);
+ DVLOG(1) << "Blocking socket.";
if (!write_unblocked_alarm_->IsSet()) {
- blocked_writer_ = blocked_writer;
- // Set the alarm for 1ms in the future.
- write_unblocked_alarm_->Set(
- clock_->ApproximateNow().Add(
- QuicTime::Delta::FromMilliseconds(1)));
+ // Set the alarm to fire immediately.
+ write_unblocked_alarm_->Set(clock_->ApproximateNow());
}
return WriteResult(WRITE_STATUS_BLOCKED, EAGAIN);
}
@@ -106,7 +102,7 @@ WriteResult PacketDroppingTestWriter::WritePacket(
if (!fake_packet_delay_.IsZero() || !fake_bandwidth_.IsZero()) {
if (buffer_size_ > 0 && buf_len + cur_buffer_size_ > buffer_size_) {
// Drop packets which do not fit into the buffer.
- DLOG(INFO) << "Dropping packet because the buffer is full.";
+ DVLOG(1) << "Dropping packet because the buffer is full.";
return WriteResult(WRITE_STATUS_OK, buf_len);
}
@@ -133,12 +129,22 @@ WriteResult PacketDroppingTestWriter::WritePacket(
return WriteResult(WRITE_STATUS_OK, buf_len);
}
- return writer()->WritePacket(buffer, buf_len, self_address, peer_address,
- blocked_writer);
+ return QuicPacketWriterWrapper::WritePacket(
+ buffer, buf_len, self_address, peer_address);
}
-bool PacketDroppingTestWriter::IsWriteBlockedDataBuffered() const {
- return false;
+bool PacketDroppingTestWriter::IsWriteBlocked() const {
+ if (write_unblocked_alarm_.get() != NULL && write_unblocked_alarm_->IsSet()) {
+ return true;
+ }
+ return QuicPacketWriterWrapper::IsWriteBlocked();
+}
+
+void PacketDroppingTestWriter::SetWritable() {
+ if (write_unblocked_alarm_.get() != NULL && write_unblocked_alarm_->IsSet()) {
+ write_unblocked_alarm_->Cancel();
+ }
+ QuicPacketWriterWrapper::SetWritable();
}
QuicTime PacketDroppingTestWriter::ReleaseNextPacket() {
@@ -151,17 +157,18 @@ QuicTime PacketDroppingTestWriter::ReleaseNextPacket() {
if (delayed_packets_.size() > 1 && fake_packet_reorder_percentage_ > 0 &&
simple_random_.RandUint64() % 100 <
static_cast<uint64>(fake_packet_reorder_percentage_)) {
- DLOG(INFO) << "Reordering packets.";
+ DVLOG(1) << "Reordering packets.";
++iter;
// Swap the send times when re-ordering packets.
delayed_packets_.begin()->send_time = iter->send_time;
}
- DLOG(INFO) << "Releasing packet. " << (delayed_packets_.size() - 1)
- << " remaining.";
+ DVLOG(1) << "Releasing packet. " << (delayed_packets_.size() - 1)
+ << " remaining.";
// Grab the next one off the queue and send it.
- writer()->WritePacket(iter->buffer.data(), iter->buffer.length(),
- iter->self_address, iter->peer_address, NULL);
+ QuicPacketWriterWrapper::WritePacket(
+ iter->buffer.data(), iter->buffer.length(),
+ iter->self_address, iter->peer_address);
DCHECK_GE(cur_buffer_size_, iter->buffer.length());
cur_buffer_size_ -= iter->buffer.length();
delayed_packets_.erase(iter);
@@ -184,6 +191,10 @@ QuicTime PacketDroppingTestWriter::ReleaseOldPackets() {
return QuicTime::Zero();
}
+void PacketDroppingTestWriter::OnCanWrite() {
+ on_can_write_->OnCanWrite();
+}
+
PacketDroppingTestWriter::DelayedWrite::DelayedWrite(
const char* buffer,
size_t buf_len,
@@ -193,8 +204,7 @@ PacketDroppingTestWriter::DelayedWrite::DelayedWrite(
: buffer(buffer, buf_len),
self_address(self_address),
peer_address(peer_address),
- send_time(send_time) {
-}
+ send_time(send_time) {}
PacketDroppingTestWriter::DelayedWrite::~DelayedWrite() {}
diff --git a/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.h b/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.h
index 2a736e0cfe2..35097229cf3 100644
--- a/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.h
+++ b/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.h
@@ -7,14 +7,14 @@
#include <list>
+#include "base/basictypes.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h"
#include "net/quic/quic_alarm.h"
-#include "net/quic/quic_blocked_writer_interface.h"
-#include "net/quic/quic_packet_writer.h"
-#include "net/quic/test_tools/quic_test_writer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
#include "net/tools/quic/quic_epoll_clock.h"
+#include "net/tools/quic/quic_packet_writer_wrapper.h"
#include "net/tools/quic/test_tools/quic_test_client.h"
#include "net/tools/quic/test_tools/quic_test_utils.h"
@@ -25,29 +25,41 @@ namespace test {
// Simulates a connection that drops packets a configured percentage of the time
// and has a blocked socket a configured percentage of the time. Also provides
// the options to delay packets and reorder packets if delay is enabled.
-class PacketDroppingTestWriter : public net::test::QuicTestWriter {
+class PacketDroppingTestWriter : public QuicPacketWriterWrapper {
public:
+ class Delegate {
+ public:
+ virtual ~Delegate() {}
+ virtual void OnCanWrite() = 0;
+ };
+
PacketDroppingTestWriter();
virtual ~PacketDroppingTestWriter();
- void SetConnectionHelper(QuicEpollConnectionHelper* helper);
+ // Must be called before blocking, reordering or delaying (loss is OK). May be
+ // called after connecting if the helper is not available before.
+ // |on_can_write| will be triggered when fake-unblocking; ownership will be
+ // assumed.
+ void Initialize(QuicEpollConnectionHelper* helper, Delegate* on_can_write);
// QuicPacketWriter methods:
virtual WriteResult WritePacket(
- const char* buffer, size_t buf_len,
+ const char* buffer,
+ size_t buf_len,
const IPAddressNumber& self_address,
- const IPEndPoint& peer_address,
- QuicBlockedWriterInterface* blocked_writer) OVERRIDE;
+ const IPEndPoint& peer_address) OVERRIDE;
+
+ virtual bool IsWriteBlocked() const OVERRIDE;
- virtual bool IsWriteBlockedDataBuffered() const OVERRIDE;
+ virtual void SetWritable() OVERRIDE;
// Writes out any packet which should have been sent by now
// to the contained writer and returns the time
// for the next delayed packet to be written.
QuicTime ReleaseOldPackets();
- QuicBlockedWriterInterface* blocked_writer() { return blocked_writer_; }
+ void OnCanWrite();
// The percent of time a packet is simulated as being lost.
void set_fake_packet_loss_percentage(int32 fake_packet_loss_percentage) {
@@ -102,7 +114,7 @@ class PacketDroppingTestWriter : public net::test::QuicTestWriter {
QuicTime ReleaseNextPacket();
// A single packet which will be sent at the supplied send_time.
- class DelayedWrite {
+ struct DelayedWrite {
public:
DelayedWrite(const char* buffer,
size_t buf_len,
@@ -122,8 +134,8 @@ class PacketDroppingTestWriter : public net::test::QuicTestWriter {
const QuicClock* clock_;
scoped_ptr<QuicAlarm> write_unblocked_alarm_;
scoped_ptr<QuicAlarm> delay_alarm_;
- QuicBlockedWriterInterface* blocked_writer_;
- SimpleRandom simple_random_;
+ scoped_ptr<Delegate> on_can_write_;
+ net::test::SimpleRandom simple_random_;
// Stored packets delayed by fake packet delay or bandwidth restrictions.
DelayedPacketList delayed_packets_;
QuicByteCount cur_buffer_size_;
diff --git a/chromium/net/tools/quic/test_tools/quic_client_peer.cc b/chromium/net/tools/quic/test_tools/quic_client_peer.cc
index 25fdb7eedc5..89f1c82650c 100644
--- a/chromium/net/tools/quic/test_tools/quic_client_peer.cc
+++ b/chromium/net/tools/quic/test_tools/quic_client_peer.cc
@@ -11,8 +11,18 @@ namespace tools {
namespace test {
// static
-int QuicClientPeer::GetFd(QuicClient* client) {
- return client->fd_;
+QuicCryptoClientConfig* QuicClientPeer::GetCryptoConfig(QuicClient* client) {
+ return &client->crypto_config_;
+}
+
+// static
+bool QuicClientPeer::CreateUDPSocket(QuicClient* client) {
+ return client->CreateUDPSocket();
+}
+
+// static
+void QuicClientPeer::SetClientPort(QuicClient* client, int port) {
+ client->client_address_ = IPEndPoint(client->client_address_.address(), port);
}
} // namespace test
diff --git a/chromium/net/tools/quic/test_tools/quic_client_peer.h b/chromium/net/tools/quic/test_tools/quic_client_peer.h
index 016120aa8bf..b26fc6d829c 100644
--- a/chromium/net/tools/quic/test_tools/quic_client_peer.h
+++ b/chromium/net/tools/quic/test_tools/quic_client_peer.h
@@ -5,7 +5,12 @@
#ifndef NET_TOOLS_QUIC_TEST_TOOLS_QUIC_CLIENT_PEER_H_
#define NET_TOOLS_QUIC_TEST_TOOLS_QUIC_CLIENT_PEER_H_
+#include "base/basictypes.h"
+
namespace net {
+
+class QuicCryptoClientConfig;
+
namespace tools {
class QuicClient;
@@ -14,7 +19,12 @@ namespace test {
class QuicClientPeer {
public:
- static int GetFd(QuicClient* client);
+ static QuicCryptoClientConfig* GetCryptoConfig(QuicClient* client);
+ static bool CreateUDPSocket(QuicClient* client);
+ static void SetClientPort(QuicClient* client, int port);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicClientPeer);
};
} // namespace test
diff --git a/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.cc b/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.cc
index c96eafd57e5..cd27802f512 100644
--- a/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.cc
+++ b/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.cc
@@ -5,8 +5,7 @@
#include "net/tools/quic/test_tools/quic_dispatcher_peer.h"
#include "net/tools/quic/quic_dispatcher.h"
-
-using net::test::QuicTestWriter;
+#include "net/tools/quic/quic_packet_writer_wrapper.h"
namespace net {
namespace tools {
@@ -20,13 +19,8 @@ void QuicDispatcherPeer::SetTimeWaitListManager(
}
// static
-void QuicDispatcherPeer::SetWriteBlocked(QuicDispatcher* dispatcher) {
- dispatcher->write_blocked_ = true;
-}
-
-// static
void QuicDispatcherPeer::UseWriter(QuicDispatcher* dispatcher,
- QuicTestWriter* writer) {
+ QuicPacketWriterWrapper* writer) {
writer->set_writer(dispatcher->writer_.release());
dispatcher->writer_.reset(writer);
}
@@ -42,6 +36,17 @@ QuicEpollConnectionHelper* QuicDispatcherPeer::GetHelper(
return dispatcher->helper_.get();
}
+// static
+QuicConnection* QuicDispatcherPeer::CreateQuicConnection(
+ QuicDispatcher* dispatcher,
+ QuicConnectionId connection_id,
+ const IPEndPoint& server,
+ const IPEndPoint& client) {
+ return dispatcher->CreateQuicConnection(connection_id,
+ server,
+ client);
+}
+
} // namespace test
} // namespace tools
} // namespace net
diff --git a/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.h b/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.h
index f463453f17a..45125c251d2 100644
--- a/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.h
+++ b/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.h
@@ -5,11 +5,15 @@
#ifndef NET_TOOLS_QUIC_TEST_TOOLS_QUIC_DISPATCHER_PEER_H_
#define NET_TOOLS_QUIC_TEST_TOOLS_QUIC_DISPATCHER_PEER_H_
-#include "net/quic/test_tools/quic_test_writer.h"
#include "net/tools/quic/quic_dispatcher.h"
+#include "net/base/ip_endpoint.h"
+
namespace net {
namespace tools {
+
+class QuicPacketWriterWrapper;
+
namespace test {
class QuicDispatcherPeer {
@@ -18,14 +22,22 @@ class QuicDispatcherPeer {
QuicDispatcher* dispatcher,
QuicTimeWaitListManager* time_wait_list_manager);
- static void SetWriteBlocked(QuicDispatcher* dispatcher);
-
+ // Injects |writer| into |dispatcher| as the top level writer.
static void UseWriter(QuicDispatcher* dispatcher,
- net::test::QuicTestWriter* writer);
+ QuicPacketWriterWrapper* writer);
static QuicPacketWriter* GetWriter(QuicDispatcher* dispatcher);
static QuicEpollConnectionHelper* GetHelper(QuicDispatcher* dispatcher);
+
+ static QuicConnection* CreateQuicConnection(
+ QuicDispatcher* dispatcher,
+ QuicConnectionId connection_id,
+ const IPEndPoint& server,
+ const IPEndPoint& client);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicDispatcherPeer);
};
} // namespace test
diff --git a/chromium/net/tools/quic/test_tools/quic_server_peer.cc b/chromium/net/tools/quic/test_tools/quic_server_peer.cc
index 15f31297d17..33a086f2096 100644
--- a/chromium/net/tools/quic/test_tools/quic_server_peer.cc
+++ b/chromium/net/tools/quic/test_tools/quic_server_peer.cc
@@ -28,11 +28,6 @@ QuicDispatcher* QuicServerPeer::GetDispatcher(QuicServer* server) {
return server->dispatcher_.get();
}
-// static
-int QuicServerPeer::GetFD(QuicServer* server) {
- return server->fd_;
-}
-
} // namespace test
} // namespace tools
} // namespace net
diff --git a/chromium/net/tools/quic/test_tools/quic_server_peer.h b/chromium/net/tools/quic/test_tools/quic_server_peer.h
index 65e2c5e96b2..f5f625db74f 100644
--- a/chromium/net/tools/quic/test_tools/quic_server_peer.h
+++ b/chromium/net/tools/quic/test_tools/quic_server_peer.h
@@ -5,6 +5,8 @@
#ifndef NET_TOOLS_QUIC_TEST_TOOLS_QUIC_SERVER_PEER_H_
#define NET_TOOLS_QUIC_TEST_TOOLS_QUIC_SERVER_PEER_H_
+#include "base/basictypes.h"
+
namespace net {
namespace tools {
@@ -19,7 +21,9 @@ class QuicServerPeer {
static bool SetSmallSocket(QuicServer* server);
static void DisableRecvmmsg(QuicServer* server);
static QuicDispatcher* GetDispatcher(QuicServer* server);
- static int GetFD(QuicServer* server);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicServerPeer);
};
} // namespace test
diff --git a/chromium/net/tools/quic/test_tools/quic_test_client.cc b/chromium/net/tools/quic/test_tools/quic_test_client.cc
index 57edadeec70..3e77bb51d6d 100644
--- a/chromium/net/tools/quic/test_tools/quic_test_client.cc
+++ b/chromium/net/tools/quic/test_tools/quic_test_client.cc
@@ -10,39 +10,49 @@
#include "net/cert/cert_verify_result.h"
#include "net/cert/x509_certificate.h"
#include "net/quic/crypto/proof_verifier.h"
+#include "net/quic/quic_server_id.h"
#include "net/quic/test_tools/quic_connection_peer.h"
+#include "net/quic/test_tools/quic_session_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/quic/test_tools/reliable_quic_stream_peer.h"
#include "net/tools/balsa/balsa_headers.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
+#include "net/tools/quic/quic_packet_writer_wrapper.h"
#include "net/tools/quic/quic_spdy_client_stream.h"
-#include "net/tools/quic/test_tools/http_message_test_utils.h"
+#include "net/tools/quic/test_tools/http_message.h"
+#include "net/tools/quic/test_tools/quic_client_peer.h"
#include "url/gurl.h"
using base::StringPiece;
+using net::QuicServerId;
using net::test::QuicConnectionPeer;
-using net::test::QuicTestWriter;
+using net::test::QuicSessionPeer;
+using net::test::ReliableQuicStreamPeer;
using std::string;
using std::vector;
+namespace net {
+namespace tools {
+namespace test {
namespace {
// RecordingProofVerifier accepts any certificate chain and records the common
// name of the leaf.
-class RecordingProofVerifier : public net::ProofVerifier {
+class RecordingProofVerifier : public ProofVerifier {
public:
// ProofVerifier interface.
- virtual net::ProofVerifier::Status VerifyProof(
+ virtual QuicAsyncStatus VerifyProof(
const string& hostname,
const string& server_config,
const vector<string>& certs,
const string& signature,
+ const ProofVerifyContext* context,
string* error_details,
- scoped_ptr<net::ProofVerifyDetails>* details,
- net::ProofVerifierCallback* callback) OVERRIDE {
- delete callback;
-
+ scoped_ptr<ProofVerifyDetails>* details,
+ ProofVerifierCallback* callback) OVERRIDE {
common_name_.clear();
if (certs.empty()) {
- return FAILURE;
+ return QUIC_FAILURE;
}
// Convert certs to X509Certificate.
@@ -53,11 +63,11 @@ class RecordingProofVerifier : public net::ProofVerifier {
scoped_refptr<net::X509Certificate> cert =
net::X509Certificate::CreateFromDERCertChain(cert_pieces);
if (!cert.get()) {
- return FAILURE;
+ return QUIC_FAILURE;
}
common_name_ = cert->subject().GetDisplayName();
- return SUCCESS;
+ return QUIC_SUCCESS;
}
const string& common_name() const { return common_name_; }
@@ -68,10 +78,6 @@ class RecordingProofVerifier : public net::ProofVerifier {
} // anonymous namespace
-namespace net {
-namespace tools {
-namespace test {
-
BalsaHeaders* MungeHeaders(const BalsaHeaders* const_headers,
bool secure) {
StringPiece uri = const_headers->request_uri();
@@ -94,101 +100,130 @@ BalsaHeaders* MungeHeaders(const BalsaHeaders* const_headers,
return headers;
}
-// A quic client which allows mocking out writes.
-class QuicEpollClient : public QuicClient {
- public:
- typedef QuicClient Super;
-
- QuicEpollClient(IPEndPoint server_address,
- const string& server_hostname,
- const QuicVersionVector& supported_versions)
- : Super(server_address, server_hostname, supported_versions, false),
- override_guid_(0), test_writer_(NULL) {
- }
-
- QuicEpollClient(IPEndPoint server_address,
- const string& server_hostname,
- const QuicConfig& config,
- const QuicVersionVector& supported_versions)
- : Super(server_address, server_hostname, config, supported_versions),
- override_guid_(0), test_writer_(NULL) {
- }
-
- virtual ~QuicEpollClient() {
- if (connected()) {
- Disconnect();
- }
- }
-
- virtual QuicPacketWriter* CreateQuicPacketWriter() OVERRIDE {
- QuicPacketWriter* writer = Super::CreateQuicPacketWriter();
- if (!test_writer_) {
- return writer;
- }
- test_writer_->set_writer(writer);
- return test_writer_;
+MockableQuicClient::MockableQuicClient(
+ IPEndPoint server_address,
+ const QuicServerId& server_id,
+ const QuicVersionVector& supported_versions,
+ EpollServer* epoll_server)
+ : QuicClient(server_address,
+ server_id,
+ supported_versions,
+ false,
+ epoll_server),
+ override_connection_id_(0),
+ test_writer_(NULL) {}
+
+MockableQuicClient::MockableQuicClient(
+ IPEndPoint server_address,
+ const QuicServerId& server_id,
+ const QuicConfig& config,
+ const QuicVersionVector& supported_versions,
+ EpollServer* epoll_server)
+ : QuicClient(server_address,
+ server_id,
+ supported_versions,
+ false,
+ config,
+ epoll_server),
+ override_connection_id_(0),
+ test_writer_(NULL) {}
+
+MockableQuicClient::~MockableQuicClient() {
+ if (connected()) {
+ Disconnect();
}
+}
- virtual QuicGuid GenerateGuid() OVERRIDE {
- return override_guid_ ? override_guid_ : Super::GenerateGuid();
+QuicPacketWriter* MockableQuicClient::CreateQuicPacketWriter() {
+ QuicPacketWriter* writer = QuicClient::CreateQuicPacketWriter();
+ if (!test_writer_) {
+ return writer;
}
+ test_writer_->set_writer(writer);
+ return test_writer_;
+}
- // Takes ownership of writer.
- void UseWriter(QuicTestWriter* writer) { test_writer_ = writer; }
-
- void UseGuid(QuicGuid guid) {
- override_guid_ = guid;
- }
+QuicConnectionId MockableQuicClient::GenerateConnectionId() {
+ return override_connection_id_ ? override_connection_id_
+ : QuicClient::GenerateConnectionId();
+}
- private:
- QuicGuid override_guid_; // GUID to use, if nonzero
- QuicTestWriter* test_writer_;
-};
+// Takes ownership of writer.
+void MockableQuicClient::UseWriter(QuicPacketWriterWrapper* writer) {
+ CHECK(test_writer_ == NULL);
+ test_writer_ = writer;
+}
-QuicTestClient::QuicTestClient(IPEndPoint address, const string& hostname,
- const QuicVersionVector& supported_versions)
- : client_(new QuicEpollClient(address, hostname, supported_versions)) {
- Initialize(address, hostname, true);
+void MockableQuicClient::UseConnectionId(QuicConnectionId connection_id) {
+ override_connection_id_ = connection_id;
}
-QuicTestClient::QuicTestClient(IPEndPoint address,
- const string& hostname,
+QuicTestClient::QuicTestClient(IPEndPoint server_address,
+ const string& server_hostname,
+ const QuicVersionVector& supported_versions)
+ : client_(new MockableQuicClient(server_address,
+ QuicServerId(server_hostname,
+ server_address.port(),
+ false,
+ PRIVACY_MODE_DISABLED),
+ supported_versions,
+ &epoll_server_)) {
+ Initialize(true);
+}
+
+QuicTestClient::QuicTestClient(IPEndPoint server_address,
+ const string& server_hostname,
bool secure,
const QuicVersionVector& supported_versions)
- : client_(new QuicEpollClient(address, hostname, supported_versions)) {
- Initialize(address, hostname, secure);
+ : client_(new MockableQuicClient(server_address,
+ QuicServerId(server_hostname,
+ server_address.port(),
+ secure,
+ PRIVACY_MODE_DISABLED),
+ supported_versions,
+ &epoll_server_)) {
+ Initialize(secure);
+}
+
+QuicTestClient::QuicTestClient(
+ IPEndPoint server_address,
+ const string& server_hostname,
+ bool secure,
+ const QuicConfig& config,
+ const QuicVersionVector& supported_versions)
+ : client_(
+ new MockableQuicClient(server_address,
+ QuicServerId(server_hostname,
+ server_address.port(),
+ secure,
+ PRIVACY_MODE_DISABLED),
+ config,
+ supported_versions,
+ &epoll_server_)) {
+ Initialize(secure);
+}
+
+QuicTestClient::QuicTestClient() {
}
-QuicTestClient::QuicTestClient(IPEndPoint address,
- const string& hostname,
- bool secure,
- const QuicConfig& config,
- const QuicVersionVector& supported_versions)
- : client_(new QuicEpollClient(address, hostname, config,
- supported_versions)) {
- Initialize(address, hostname, secure);
+QuicTestClient::~QuicTestClient() {
+ if (stream_) {
+ stream_->set_visitor(NULL);
+ }
}
-void QuicTestClient::Initialize(IPEndPoint address,
- const string& hostname,
- bool secure) {
- server_address_ = address;
+void QuicTestClient::Initialize(bool secure) {
priority_ = 3;
connect_attempted_ = false;
secure_ = secure;
auto_reconnect_ = false;
buffer_body_ = true;
+ fec_policy_ = FEC_PROTECT_OPTIONAL;
proof_verifier_ = NULL;
ClearPerRequestState();
ExpectCertificates(secure_);
}
-QuicTestClient::~QuicTestClient() {
- if (stream_) {
- stream_->set_visitor(NULL);
- }
-}
-
void QuicTestClient::ExpectCertificates(bool on) {
if (on) {
proof_verifier_ = new RecordingProofVerifier;
@@ -199,8 +234,14 @@ void QuicTestClient::ExpectCertificates(bool on) {
}
}
+void QuicTestClient::SetUserAgentID(const string& user_agent_id) {
+ client_->SetUserAgentID(user_agent_id);
+}
+
ssize_t QuicTestClient::SendRequest(const string& uri) {
- HTTPMessage message(HttpConstants::HTTP_1_1, HttpConstants::GET, uri);
+ HTTPMessage message(HttpConstants::HTTP_1_1,
+ HttpConstants::GET,
+ uri);
return SendMessage(message);
}
@@ -211,7 +252,11 @@ ssize_t QuicTestClient::SendMessage(const HTTPMessage& message) {
if (!connected()) {
GURL url(message.headers()->request_uri().as_string());
if (!url.host().empty()) {
- client_->set_server_hostname(url.host());
+ client_->set_server_id(
+ QuicServerId(url.host(),
+ url.EffectiveIntPort(),
+ url.SchemeIs("https"),
+ PRIVACY_MODE_DISABLED));
}
}
@@ -236,6 +281,34 @@ ssize_t QuicTestClient::SendData(string data, bool last_data) {
return data.length();
}
+bool QuicTestClient::response_complete() const {
+ return response_complete_;
+}
+
+int QuicTestClient::response_header_size() const {
+ return response_header_size_;
+}
+
+int64 QuicTestClient::response_body_size() const {
+ return response_body_size_;
+}
+
+bool QuicTestClient::buffer_body() const {
+ return buffer_body_;
+}
+
+void QuicTestClient::set_buffer_body(bool buffer_body) {
+ buffer_body_ = buffer_body;
+}
+
+bool QuicTestClient::ServerInLameDuckMode() const {
+ return false;
+}
+
+const string& QuicTestClient::response_body() {
+ return response_;
+}
+
string QuicTestClient::SendCustomSynchronousRequest(
const HTTPMessage& message) {
SendMessage(message);
@@ -268,26 +341,39 @@ QuicSpdyClientStream* QuicTestClient::GetOrCreateStream() {
}
stream_->set_visitor(this);
reinterpret_cast<QuicSpdyClientStream*>(stream_)->set_priority(priority_);
+ // Set FEC policy on stream.
+ ReliableQuicStreamPeer::SetFecPolicy(stream_, fec_policy_);
}
return stream_;
}
+QuicErrorCode QuicTestClient::connection_error() {
+ return client()->session()->error();
+}
+
+MockableQuicClient* QuicTestClient::client() { return client_.get(); }
+
const string& QuicTestClient::cert_common_name() const {
return reinterpret_cast<RecordingProofVerifier*>(proof_verifier_)
->common_name();
}
-bool QuicTestClient::connected() const {
- return client_->connected();
+QuicTagValueMap QuicTestClient::GetServerConfig() const {
+ QuicCryptoClientConfig* config =
+ QuicClientPeer::GetCryptoConfig(client_.get());
+ QuicCryptoClientConfig::CachedState* state =
+ config->LookupOrCreate(client_->server_id());
+ const CryptoHandshakeMessage* handshake_msg = state->GetServerConfig();
+ if (handshake_msg != NULL) {
+ return handshake_msg->tag_value_map();
+ } else {
+ return QuicTagValueMap();
+ }
}
-void QuicTestClient::WaitForResponse() {
- if (stream_ == NULL) {
- // The client has likely disconnected.
- return;
- }
- client_->WaitForStreamToClose(stream_->id());
+bool QuicTestClient::connected() const {
+ return client_->connected();
}
void QuicTestClient::Connect() {
@@ -328,9 +414,9 @@ void QuicTestClient::ClearPerRequestState() {
void QuicTestClient::WaitForResponseForMs(int timeout_ms) {
int64 timeout_us = timeout_ms * base::Time::kMicrosecondsPerMillisecond;
- int64 old_timeout_us = client()->epoll_server()->timeout_in_us();
+ int64 old_timeout_us = epoll_server()->timeout_in_us();
if (timeout_us > 0) {
- client()->epoll_server()->set_timeout_in_us(timeout_us);
+ epoll_server()->set_timeout_in_us(timeout_us);
}
const QuicClock* clock =
QuicConnectionPeer::GetHelper(client()->session()->connection())->
@@ -343,15 +429,15 @@ void QuicTestClient::WaitForResponseForMs(int timeout_ms) {
client_->WaitForEvents();
}
if (timeout_us > 0) {
- client()->epoll_server()->set_timeout_in_us(old_timeout_us);
+ epoll_server()->set_timeout_in_us(old_timeout_us);
}
}
void QuicTestClient::WaitForInitialResponseForMs(int timeout_ms) {
int64 timeout_us = timeout_ms * base::Time::kMicrosecondsPerMillisecond;
- int64 old_timeout_us = client()->epoll_server()->timeout_in_us();
+ int64 old_timeout_us = epoll_server()->timeout_in_us();
if (timeout_us > 0) {
- client()->epoll_server()->set_timeout_in_us(timeout_us);
+ epoll_server()->set_timeout_in_us(timeout_us);
}
const QuicClock* clock =
QuicConnectionPeer::GetHelper(client()->session()->connection())->
@@ -365,7 +451,7 @@ void QuicTestClient::WaitForInitialResponseForMs(int timeout_ms) {
client_->WaitForEvents();
}
if (timeout_us > 0) {
- client()->epoll_server()->set_timeout_in_us(old_timeout_us);
+ epoll_server()->set_timeout_in_us(old_timeout_us);
}
}
@@ -389,7 +475,7 @@ const BalsaHeaders* QuicTestClient::response_headers() const {
}
}
-int QuicTestClient::response_size() const {
+int64 QuicTestClient::response_size() const {
return bytes_read_;
}
@@ -413,28 +499,71 @@ void QuicTestClient::OnClose(QuicDataStream* stream) {
response_headers_complete_ = stream_->headers_decompressed();
headers_.CopyFrom(stream_->headers());
stream_error_ = stream_->stream_error();
- bytes_read_ = stream_->stream_bytes_read();
- bytes_written_ = stream_->stream_bytes_written();
+ bytes_read_ = stream_->stream_bytes_read() + stream_->header_bytes_read();
+ bytes_written_ =
+ stream_->stream_bytes_written() + stream_->header_bytes_written();
response_header_size_ = headers_.GetSizeForWriteBuffer();
response_body_size_ = stream_->data().size();
stream_ = NULL;
}
-void QuicTestClient::UseWriter(QuicTestWriter* writer) {
- reinterpret_cast<QuicEpollClient*>(client_.get())->UseWriter(writer);
+void QuicTestClient::UseWriter(QuicPacketWriterWrapper* writer) {
+ client_->UseWriter(writer);
}
-void QuicTestClient::UseGuid(QuicGuid guid) {
+void QuicTestClient::UseConnectionId(QuicConnectionId connection_id) {
DCHECK(!connected());
- reinterpret_cast<QuicEpollClient*>(client_.get())->UseGuid(guid);
+ client_->UseConnectionId(connection_id);
+}
+
+ssize_t QuicTestClient::SendAndWaitForResponse(const void *buffer,
+ size_t size) {
+ LOG(DFATAL) << "Not implemented";
+ return 0;
+}
+
+void QuicTestClient::Bind(IPEndPoint* local_address) {
+ DLOG(WARNING) << "Bind will be done during connect";
+}
+
+string QuicTestClient::SerializeMessage(const HTTPMessage& message) {
+ LOG(DFATAL) << "Not implemented";
+ return "";
+}
+
+IPAddressNumber QuicTestClient::bind_to_address() const {
+ return client_->bind_to_address();
+}
+
+void QuicTestClient::set_bind_to_address(IPAddressNumber address) {
+ client_->set_bind_to_address(address);
+}
+
+const IPEndPoint& QuicTestClient::address() const {
+ LOG(DFATAL) << "Not implemented";
+ return client_->server_address();
+}
+
+size_t QuicTestClient::requests_sent() const {
+ LOG(DFATAL) << "Not implemented";
+ return 0;
}
void QuicTestClient::WaitForWriteToFlush() {
- while (connected() && client()->session()->HasQueuedData()) {
+ while (connected() && client()->session()->HasDataToWrite()) {
client_->WaitForEvents();
}
}
+void QuicTestClient::SetFecPolicy(FecPolicy fec_policy) {
+ fec_policy_ = fec_policy;
+ // Set policy for headers and crypto streams.
+ ReliableQuicStreamPeer::SetFecPolicy(
+ QuicSessionPeer::GetHeadersStream(client()->session()), fec_policy);
+ ReliableQuicStreamPeer::SetFecPolicy(client()->session()->GetCryptoStream(),
+ fec_policy);
+}
+
} // namespace test
} // namespace tools
} // namespace net
diff --git a/chromium/net/tools/quic/test_tools/quic_test_client.h b/chromium/net/tools/quic/test_tools/quic_test_client.h
index e67a2a159bb..93c0352bca6 100644
--- a/chromium/net/tools/quic/test_tools/quic_test_client.h
+++ b/chromium/net/tools/quic/test_tools/quic_test_client.h
@@ -2,18 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef NET_QUIC_TEST_TOOLS_QUIC_TEST_CLIENT_H_
-#define NET_QUIC_TEST_TOOLS_QUIC_TEST_CLIENT_H_
+#ifndef NET_TOOLS_QUIC_TEST_TOOLS_QUIC_TEST_CLIENT_H_
+#define NET_TOOLS_QUIC_TEST_TOOLS_QUIC_TEST_CLIENT_H_
#include <string>
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
+#include "net/base/ip_endpoint.h"
#include "net/quic/quic_framer.h"
#include "net/quic/quic_packet_creator.h"
#include "net/quic/quic_protocol.h"
-#include "net/quic/test_tools/quic_test_writer.h"
+#include "net/tools/balsa/balsa_frame.h"
+#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_client.h"
+#include "net/tools/quic/test_tools/simple_client.h"
namespace net {
@@ -21,14 +24,46 @@ class ProofVerifier;
namespace tools {
+class QuicPacketWriterWrapper;
+
namespace test {
class HTTPMessage;
+class MockableQuicClient;
-// A toy QUIC client used for testing.
-class QuicTestClient : public QuicDataStream::Visitor {
+// A quic client which allows mocking out writes.
+class MockableQuicClient : public QuicClient {
public:
- QuicTestClient(IPEndPoint server_address, const string& server_hostname,
+ MockableQuicClient(IPEndPoint server_address,
+ const QuicServerId& server_id,
+ const QuicVersionVector& supported_versions,
+ EpollServer* epoll_server);
+
+ MockableQuicClient(IPEndPoint server_address,
+ const QuicServerId& server_id,
+ const QuicConfig& config,
+ const QuicVersionVector& supported_versions,
+ EpollServer* epoll_server);
+
+ virtual ~MockableQuicClient() OVERRIDE;
+ virtual QuicPacketWriter* CreateQuicPacketWriter() OVERRIDE;
+ virtual QuicConnectionId GenerateConnectionId() OVERRIDE;
+ void UseWriter(QuicPacketWriterWrapper* writer);
+ void UseConnectionId(QuicConnectionId connection_id);
+
+ private:
+ QuicConnectionId override_connection_id_; // ConnectionId to use, if nonzero
+ QuicPacketWriterWrapper* test_writer_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockableQuicClient);
+};
+
+// A toy QUIC client used for testing, mostly following the SimpleClient APIs.
+class QuicTestClient : public SimpleClient,
+ public QuicDataStream::Visitor {
+ public:
+ QuicTestClient(IPEndPoint server_address,
+ const string& server_hostname,
const QuicVersionVector& supported_versions);
QuicTestClient(IPEndPoint server_address,
const string& server_hostname,
@@ -47,77 +82,99 @@ class QuicTestClient : public QuicDataStream::Visitor {
// name is recorded and available with |cert_common_name()|.
void ExpectCertificates(bool on);
- // Clears any outstanding state and sends a simple GET of 'uri' to the
- // server. Returns 0 if the request failed and no bytes were written.
- ssize_t SendRequest(const string& uri);
- ssize_t SendMessage(const HTTPMessage& message);
-
- string SendCustomSynchronousRequest(const HTTPMessage& message);
- string SendSynchronousRequest(const string& uri);
+ // Sets the |user_agent_id| of the |client_|.
+ void SetUserAgentID(const string& user_agent_id);
// Wraps data in a quic packet and sends it.
ssize_t SendData(string data, bool last_data);
- QuicPacketCreator::Options* options() { return client_->options(); }
-
- void WaitForResponse();
-
- void Connect();
- void ResetConnection();
- void Disconnect();
- IPEndPoint LocalSocketAddress() const;
- void ClearPerRequestState();
- void WaitForResponseForMs(int timeout_ms);
- void WaitForInitialResponseForMs(int timeout_ms);
- ssize_t Send(const void *buffer, size_t size);
- bool response_complete() const { return response_complete_; }
- bool response_headers_complete() const;
- const BalsaHeaders* response_headers() const;
- int response_size() const;
- int response_header_size() const { return response_header_size_; }
- int response_body_size() const { return response_body_size_; }
- size_t bytes_read() const;
- size_t bytes_written() const;
- bool buffer_body() const { return buffer_body_; }
- void set_buffer_body(bool buffer_body) { buffer_body_ = buffer_body; }
+ // From SimpleClient
+ // Clears any outstanding state and sends a simple GET of 'uri' to the
+ // server. Returns 0 if the request failed and no bytes were written.
+ virtual ssize_t SendRequest(const string& uri) OVERRIDE;
+ virtual ssize_t SendMessage(const HTTPMessage& message) OVERRIDE;
+ virtual string SendCustomSynchronousRequest(
+ const HTTPMessage& message) OVERRIDE;
+ virtual string SendSynchronousRequest(const string& uri) OVERRIDE;
+ virtual void Connect() OVERRIDE;
+ virtual void ResetConnection() OVERRIDE;
+ virtual void Disconnect() OVERRIDE;
+ virtual IPEndPoint LocalSocketAddress() const OVERRIDE;
+ virtual void ClearPerRequestState() OVERRIDE;
+ virtual void WaitForResponseForMs(int timeout_ms) OVERRIDE;
+ virtual void WaitForInitialResponseForMs(int timeout_ms) OVERRIDE;
+ virtual ssize_t Send(const void *buffer, size_t size) OVERRIDE;
+ virtual bool response_complete() const OVERRIDE;
+ virtual bool response_headers_complete() const OVERRIDE;
+ virtual const BalsaHeaders* response_headers() const OVERRIDE;
+ virtual int64 response_size() const OVERRIDE;
+ virtual int response_header_size() const OVERRIDE;
+ virtual int64 response_body_size() const OVERRIDE;
+ virtual size_t bytes_read() const OVERRIDE;
+ virtual size_t bytes_written() const OVERRIDE;
+ virtual bool buffer_body() const OVERRIDE;
+ virtual void set_buffer_body(bool buffer_body) OVERRIDE;
+ virtual bool ServerInLameDuckMode() const OVERRIDE;
+ virtual const string& response_body() OVERRIDE;
+ virtual bool connected() const OVERRIDE;
+ // These functions are all unimplemented functions from SimpleClient, and log
+ // DFATAL if called by users of SimpleClient.
+ virtual ssize_t SendAndWaitForResponse(const void *buffer,
+ size_t size) OVERRIDE;
+ virtual void Bind(IPEndPoint* local_address) OVERRIDE;
+ virtual string SerializeMessage(const HTTPMessage& message) OVERRIDE;
+ virtual IPAddressNumber bind_to_address() const OVERRIDE;
+ virtual void set_bind_to_address(IPAddressNumber address) OVERRIDE;
+ virtual const IPEndPoint& address() const OVERRIDE;
+ virtual size_t requests_sent() const OVERRIDE;
// From QuicDataStream::Visitor
virtual void OnClose(QuicDataStream* stream) OVERRIDE;
// Configures client_ to take ownership of and use the writer.
// Must be called before initial connect.
- void UseWriter(net::test::QuicTestWriter* writer);
- // If the given GUID is nonzero, configures client_ to use a specific GUID
- // instead of a random one.
- void UseGuid(QuicGuid guid);
+ void UseWriter(QuicPacketWriterWrapper* writer);
+ // If the given ConnectionId is nonzero, configures client_ to use a specific
+ // ConnectionId instead of a random one.
+ void UseConnectionId(QuicConnectionId connection_id);
// Returns NULL if the maximum number of streams have already been created.
QuicSpdyClientStream* GetOrCreateStream();
QuicRstStreamErrorCode stream_error() { return stream_error_; }
- QuicErrorCode connection_error() { return client()->session()->error(); }
+ QuicErrorCode connection_error();
- QuicClient* client() { return client_.get(); }
+ MockableQuicClient* client();
// cert_common_name returns the common name value of the server's certificate,
// or the empty string if no certificate was presented.
const string& cert_common_name() const;
- const string& response_body() {return response_;}
- bool connected() const;
+ // Get the server config map.
+ QuicTagValueMap GetServerConfig() const;
void set_auto_reconnect(bool reconnect) { auto_reconnect_ = reconnect; }
void set_priority(QuicPriority priority) { priority_ = priority; }
+ // Sets client's FEC policy. This policy applies to the data stream(s), and
+ // also to the headers and crypto streams.
+ void SetFecPolicy(FecPolicy fec_policy);
+
void WaitForWriteToFlush();
- private:
- void Initialize(IPEndPoint address, const string& hostname, bool secure);
+ EpollServer* epoll_server() { return &epoll_server_; }
+
+ protected:
+ QuicTestClient();
- IPEndPoint server_address_;
- IPEndPoint client_address_;
- scoped_ptr<QuicClient> client_; // The actual client
+ void Initialize(bool secure);
+
+ void set_client(MockableQuicClient* client) { client_.reset(client); }
+
+ private:
+ EpollServer epoll_server_;
+ scoped_ptr<MockableQuicClient> client_; // The actual client
QuicSpdyClientStream* stream_;
QuicRstStreamErrorCode stream_error_;
@@ -132,7 +189,7 @@ class QuicTestClient : public QuicDataStream::Visitor {
// The number of uncompressed HTTP header bytes received.
int response_header_size_;
// The number of HTTP body bytes received.
- int response_body_size_;
+ int64 response_body_size_;
// True if we tried to connect already since the last call to Disconnect().
bool connect_attempted_;
bool secure_;
@@ -142,10 +199,13 @@ class QuicTestClient : public QuicDataStream::Visitor {
bool auto_reconnect_;
// Should we buffer the response body? Defaults to true.
bool buffer_body_;
-
+ // FEC policy for data sent by this client.
+ FecPolicy fec_policy_;
// proof_verifier_ points to a RecordingProofVerifier that is owned by
// client_.
ProofVerifier* proof_verifier_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicTestClient);
};
} // namespace test
@@ -153,4 +213,4 @@ class QuicTestClient : public QuicDataStream::Visitor {
} // namespace tools
} // namespace net
-#endif // NET_QUIC_TEST_TOOLS_QUIC_TEST_CLIENT_H_
+#endif // NET_TOOLS_QUIC_TEST_TOOLS_QUIC_TEST_CLIENT_H_
diff --git a/chromium/net/tools/quic/test_tools/quic_test_utils.cc b/chromium/net/tools/quic/test_tools/quic_test_utils.cc
index 1aad3273832..d46eae5b734 100644
--- a/chromium/net/tools/quic/test_tools/quic_test_utils.cc
+++ b/chromium/net/tools/quic/test_tools/quic_test_utils.cc
@@ -4,47 +4,59 @@
#include "net/tools/quic/test_tools/quic_test_utils.h"
-#include "base/sha1.h"
#include "net/quic/quic_connection.h"
#include "net/quic/test_tools/quic_connection_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
using base::StringPiece;
+using net::test::MakeAckFrame;
using net::test::MockHelper;
+using net::test::QuicConnectionPeer;
namespace net {
namespace tools {
namespace test {
MockConnection::MockConnection(bool is_server)
- : QuicConnection(kTestGuid,
+ : QuicConnection(kTestConnectionId,
IPEndPoint(net::test::Loopback4(), kTestPort),
new testing::NiceMock<MockHelper>(),
new testing::NiceMock<MockPacketWriter>(),
is_server, QuicSupportedVersions()),
- writer_(net::test::QuicConnectionPeer::GetWriter(this)),
+ writer_(QuicConnectionPeer::GetWriter(this)),
helper_(helper()) {
}
MockConnection::MockConnection(IPEndPoint address,
bool is_server)
- : QuicConnection(kTestGuid, address,
+ : QuicConnection(kTestConnectionId, address,
new testing::NiceMock<MockHelper>(),
new testing::NiceMock<MockPacketWriter>(),
is_server, QuicSupportedVersions()),
- writer_(net::test::QuicConnectionPeer::GetWriter(this)),
+ writer_(QuicConnectionPeer::GetWriter(this)),
helper_(helper()) {
}
-MockConnection::MockConnection(QuicGuid guid,
+MockConnection::MockConnection(QuicConnectionId connection_id,
bool is_server)
- : QuicConnection(guid,
+ : QuicConnection(connection_id,
IPEndPoint(net::test::Loopback4(), kTestPort),
new testing::NiceMock<MockHelper>(),
new testing::NiceMock<MockPacketWriter>(),
is_server, QuicSupportedVersions()),
- writer_(net::test::QuicConnectionPeer::GetWriter(this)),
+ writer_(QuicConnectionPeer::GetWriter(this)),
+ helper_(helper()) {
+}
+
+MockConnection::MockConnection(bool is_server,
+ const QuicVersionVector& supported_versions)
+ : QuicConnection(kTestConnectionId,
+ IPEndPoint(net::test::Loopback4(), kTestPort),
+ new testing::NiceMock<MockHelper>(),
+ new testing::NiceMock<MockPacketWriter>(),
+ is_server, QuicSupportedVersions()),
+ writer_(QuicConnectionPeer::GetWriter(this)),
helper_(helper()) {
}
@@ -55,18 +67,21 @@ void MockConnection::AdvanceTime(QuicTime::Delta delta) {
static_cast<MockHelper*>(helper())->AdvanceTime(delta);
}
-uint64 SimpleRandom::RandUint64() {
- unsigned char hash[base::kSHA1Length];
- base::SHA1HashBytes(reinterpret_cast<unsigned char*>(&seed_), sizeof(seed_),
- hash);
- memcpy(&seed_, hash, sizeof(seed_));
- return seed_;
+QuicAckFrame MakeAckFrameWithNackRanges(
+ size_t num_nack_ranges, QuicPacketSequenceNumber least_unacked) {
+ QuicAckFrame ack = MakeAckFrame(2 * num_nack_ranges + least_unacked,
+ least_unacked);
+ // Add enough missing packets to get num_nack_ranges nack ranges.
+ for (QuicPacketSequenceNumber i = 1; i < 2 * num_nack_ranges; i += 2) {
+ ack.received_info.missing_packets.insert(least_unacked + i);
+ }
+ return ack;
}
TestSession::TestSession(QuicConnection* connection,
const QuicConfig& config)
- : QuicSession(connection, config),
- crypto_stream_(NULL) {
+ : QuicSession(connection, config),
+ crypto_stream_(NULL) {
}
TestSession::~TestSession() {}
@@ -85,19 +100,10 @@ MockPacketWriter::MockPacketWriter() {
MockPacketWriter::~MockPacketWriter() {
}
-MockQuicSessionOwner::MockQuicSessionOwner() {
-}
-
-MockQuicSessionOwner::~MockQuicSessionOwner() {
-}
-
-bool TestDecompressorVisitor::OnDecompressedData(StringPiece data) {
- data.AppendToString(&data_);
- return true;
+MockQuicServerSessionVisitor::MockQuicServerSessionVisitor() {
}
-void TestDecompressorVisitor::OnDecompressionError() {
- error_ = true;
+MockQuicServerSessionVisitor::~MockQuicServerSessionVisitor() {
}
MockAckNotifierDelegate::MockAckNotifierDelegate() {
diff --git a/chromium/net/tools/quic/test_tools/quic_test_utils.h b/chromium/net/tools/quic/test_tools/quic_test_utils.h
index 986665bd1ed..a889a42ee0d 100644
--- a/chromium/net/tools/quic/test_tools/quic_test_utils.h
+++ b/chromium/net/tools/quic/test_tools/quic_test_utils.h
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// Common utilities for Quic tests
+
#ifndef NET_TOOLS_QUIC_TEST_TOOLS_QUIC_TEST_UTILS_H_
#define NET_TOOLS_QUIC_TEST_TOOLS_QUIC_TEST_UTILS_H_
@@ -11,7 +13,6 @@
#include "net/quic/quic_connection.h"
#include "net/quic/quic_packet_writer.h"
#include "net/quic/quic_session.h"
-#include "net/quic/quic_spdy_decompressor.h"
#include "net/spdy/spdy_framer.h"
#include "net/tools/quic/quic_server_session.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -24,38 +25,31 @@ class IPEndPoint;
namespace tools {
namespace test {
-static const QuicGuid kTestGuid = 42;
+static const QuicConnectionId kTestConnectionId = 42;
static const int kTestPort = 123;
+static const uint32 kInitialStreamFlowControlWindowForTest =
+ 32 * 1024; // 32 KB
+static const uint32 kInitialSessionFlowControlWindowForTest =
+ 64 * 1024; // 64 KB
-// Simple random number generator used to compute random numbers suitable
-// for pseudo-randomly dropping packets in tests. It works by computing
-// the sha1 hash of the current seed, and using the first 64 bits as
-// the next random number, and the next seed.
-class SimpleRandom {
- public:
- SimpleRandom() : seed_(0) {}
-
- // Returns a random number in the range [0, kuint64max].
- uint64 RandUint64();
-
- void set_seed(uint64 seed) { seed_ = seed; }
-
- private:
- uint64 seed_;
-};
+// Testing convenience method to construct a QuicAckFrame with |num_nack_ranges|
+// nack ranges of width 1 packet, starting from |least_unacked|.
+QuicAckFrame MakeAckFrameWithNackRanges(size_t num_nack_ranges,
+ QuicPacketSequenceNumber least_unacked);
class MockConnection : public QuicConnection {
public:
- // Uses a MockHelper, GUID of 42, and 127.0.0.1:123.
+ // Uses a MockHelper, ConnectionId of 42, and 127.0.0.1:123.
explicit MockConnection(bool is_server);
- // Uses a MockHelper, GUID of 42.
- MockConnection(IPEndPoint address,
- bool is_server);
+ // Uses a MockHelper, ConnectionId of 42.
+ MockConnection(IPEndPoint address, bool is_server);
// Uses a MockHelper, and 127.0.0.1:123
- MockConnection(QuicGuid guid,
- bool is_server);
+ MockConnection(QuicConnectionId connection_id, bool is_server);
+
+ // Uses a Mock helper, ConnectionId of 42, and 127.0.0.1:123.
+ MockConnection(bool is_server, const QuicVersionVector& supported_versions);
virtual ~MockConnection();
@@ -70,12 +64,19 @@ class MockConnection : public QuicConnection {
MOCK_METHOD2(SendConnectionCloseWithDetails, void(
QuicErrorCode error,
const std::string& details));
- MOCK_METHOD2(SendRstStream, void(QuicStreamId id,
- QuicRstStreamErrorCode error));
+ MOCK_METHOD2(SendConnectionClosePacket, void(QuicErrorCode error,
+ const std::string& details));
+ MOCK_METHOD3(SendRstStream, void(QuicStreamId id,
+ QuicRstStreamErrorCode error,
+ QuicStreamOffset bytes_written));
MOCK_METHOD3(SendGoAway, void(QuicErrorCode error,
QuicStreamId last_good_stream_id,
const std::string& reason));
- MOCK_METHOD0(OnCanWrite, bool());
+ MOCK_METHOD1(SendBlocked, void(QuicStreamId id));
+ MOCK_METHOD2(SendWindowUpdate, void(QuicStreamId id,
+ QuicStreamOffset byte_offset));
+ MOCK_METHOD0(OnCanWrite, void());
+ MOCK_CONST_METHOD0(HasPendingWrites, bool());
void ReallyProcessUdpPacket(const IPEndPoint& self_address,
const IPEndPoint& peer_address,
@@ -102,10 +103,11 @@ class TestSession : public QuicSession {
void SetCryptoStream(QuicCryptoStream* stream);
- virtual QuicCryptoStream* GetCryptoStream();
+ virtual QuicCryptoStream* GetCryptoStream() OVERRIDE;
private:
QuicCryptoStream* crypto_stream_;
+
DISALLOW_COPY_AND_ASSIGN(TestSession);
};
@@ -114,42 +116,46 @@ class MockPacketWriter : public QuicPacketWriter {
MockPacketWriter();
virtual ~MockPacketWriter();
- MOCK_METHOD5(WritePacket,
+ MOCK_METHOD4(WritePacket,
WriteResult(const char* buffer,
size_t buf_len,
const IPAddressNumber& self_address,
- const IPEndPoint& peer_address,
- QuicBlockedWriterInterface* blocked_writer));
+ const IPEndPoint& peer_address));
MOCK_CONST_METHOD0(IsWriteBlockedDataBuffered, bool());
-};
+ MOCK_CONST_METHOD0(IsWriteBlocked, bool());
+ MOCK_METHOD0(SetWritable, void());
-class MockQuicSessionOwner : public QuicSessionOwner {
- public:
- MockQuicSessionOwner();
- ~MockQuicSessionOwner();
- MOCK_METHOD2(OnConnectionClosed, void(QuicGuid guid, QuicErrorCode error));
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockPacketWriter);
};
-class TestDecompressorVisitor : public QuicSpdyDecompressor::Visitor {
+class MockQuicServerSessionVisitor : public QuicServerSessionVisitor {
public:
- virtual ~TestDecompressorVisitor() {}
- virtual bool OnDecompressedData(base::StringPiece data) OVERRIDE;
- virtual void OnDecompressionError() OVERRIDE;
-
- std::string data() { return data_; }
- bool error() { return error_; }
+ MockQuicServerSessionVisitor();
+ virtual ~MockQuicServerSessionVisitor();
+ MOCK_METHOD2(OnConnectionClosed, void(QuicConnectionId connection_id,
+ QuicErrorCode error));
+ MOCK_METHOD1(OnWriteBlocked, void(QuicBlockedWriterInterface* writer));
private:
- std::string data_;
- bool error_;
+ DISALLOW_COPY_AND_ASSIGN(MockQuicServerSessionVisitor);
};
class MockAckNotifierDelegate : public QuicAckNotifier::DelegateInterface {
public:
MockAckNotifierDelegate();
+
+ MOCK_METHOD5(OnAckNotification, void(int num_original_packets,
+ int num_original_bytes,
+ int num_retransmitted_packets,
+ int num_retransmitted_bytes,
+ QuicTime::Delta delta_largest_observed));
+
+ protected:
+ // Object is ref counted.
virtual ~MockAckNotifierDelegate();
- MOCK_METHOD0(OnAckNotification, void());
+ DISALLOW_COPY_AND_ASSIGN(MockAckNotifierDelegate);
};
} // namespace test
diff --git a/chromium/net/tools/quic/test_tools/server_thread.cc b/chromium/net/tools/quic/test_tools/server_thread.cc
index a1bebc760d5..337cc64cd08 100644
--- a/chromium/net/tools/quic/test_tools/server_thread.cc
+++ b/chromium/net/tools/quic/test_tools/server_thread.cc
@@ -10,57 +10,62 @@ namespace net {
namespace tools {
namespace test {
-ServerThread::ServerThread(IPEndPoint address,
- const QuicConfig& config,
- const QuicVersionVector& supported_versions,
+ServerThread::ServerThread(QuicServer* server,
+ IPEndPoint address,
bool strike_register_no_startup_period)
: SimpleThread("server_thread"),
- listening_(true, false),
confirmed_(true, false),
pause_(true, false),
paused_(true, false),
resume_(true, false),
quit_(true, false),
- server_(config, supported_versions),
+ server_(server),
address_(address),
- port_(0) {
+ port_(0),
+ initialized_(false) {
if (strike_register_no_startup_period) {
- server_.SetStrikeRegisterNoStartupPeriod();
+ server_->SetStrikeRegisterNoStartupPeriod();
}
}
-ServerThread::~ServerThread() {
-}
+ServerThread::~ServerThread() {}
-void ServerThread::Run() {
- server_.Listen(address_);
+void ServerThread::Initialize() {
+ if (initialized_) {
+ return;
+ }
+
+ server_->Listen(address_);
port_lock_.Acquire();
- port_ = server_.port();
+ port_ = server_->port();
port_lock_.Release();
- listening_.Signal();
+ initialized_ = true;
+}
+
+void ServerThread::Run() {
+ if (!initialized_) {
+ Initialize();
+ }
+
while (!quit_.IsSignaled()) {
if (pause_.IsSignaled() && !resume_.IsSignaled()) {
paused_.Signal();
resume_.Wait();
}
- server_.WaitForEvents();
+ server_->WaitForEvents();
MaybeNotifyOfHandshakeConfirmation();
}
- server_.Shutdown();
+ server_->Shutdown();
}
int ServerThread::GetPort() {
port_lock_.Acquire();
int rc = port_;
port_lock_.Release();
- return rc;
-}
-
-void ServerThread::WaitForServerStartup() {
- listening_.Wait();
+ return rc;
}
void ServerThread::WaitForCryptoHandshakeConfirmed() {
diff --git a/chromium/net/tools/quic/test_tools/server_thread.h b/chromium/net/tools/quic/test_tools/server_thread.h
index ed36c37b349..6066d974d18 100644
--- a/chromium/net/tools/quic/test_tools/server_thread.h
+++ b/chromium/net/tools/quic/test_tools/server_thread.h
@@ -17,18 +17,18 @@ namespace test {
// Simple wrapper class to run server in a thread.
class ServerThread : public base::SimpleThread {
public:
- ServerThread(IPEndPoint address,
- const QuicConfig& config,
- const QuicVersionVector& supported_versions,
+ ServerThread(QuicServer* server,
+ IPEndPoint address,
bool strike_register_no_startup_period);
virtual ~ServerThread();
- // SimpleThread implementation.
- virtual void Run() OVERRIDE;
+ // Prepares the server, but does not start accepting connections. Useful for
+ // injecting mocks.
+ void Initialize();
- // Waits until the server has started and is listening for requests.
- void WaitForServerStartup();
+ // Runs the event loop. Will initialize if necessary.
+ virtual void Run() OVERRIDE;
// Waits for the handshake to be confirmed for the first session created.
void WaitForCryptoHandshakeConfirmed();
@@ -48,7 +48,7 @@ class ServerThread : public base::SimpleThread {
// Returns the underlying server. Care must be taken to avoid data races
// when accessing the server. It is always safe to access the server
// after calling Pause() and before calling Resume().
- QuicServer* server() { return &server_; }
+ QuicServer* server() { return server_.get(); }
// Returns the port that the server is listening on.
int GetPort();
@@ -56,7 +56,6 @@ class ServerThread : public base::SimpleThread {
private:
void MaybeNotifyOfHandshakeConfirmation();
- base::WaitableEvent listening_; // Notified when the server is listening.
base::WaitableEvent confirmed_; // Notified when the first handshake is
// confirmed.
base::WaitableEvent pause_; // Notified when the server should pause.
@@ -64,11 +63,13 @@ class ServerThread : public base::SimpleThread {
base::WaitableEvent resume_; // Notified when the server should resume.
base::WaitableEvent quit_; // Notified when the server should quit.
- tools::QuicServer server_;
+ scoped_ptr<QuicServer> server_;
IPEndPoint address_;
base::Lock port_lock_;
int port_;
+ bool initialized_;
+
DISALLOW_COPY_AND_ASSIGN(ServerThread);
};
diff --git a/chromium/net/tools/quic/test_tools/simple_client.cc b/chromium/net/tools/quic/test_tools/simple_client.cc
new file mode 100644
index 00000000000..46f5b9d6877
--- /dev/null
+++ b/chromium/net/tools/quic/test_tools/simple_client.cc
@@ -0,0 +1,36 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/tools/quic/test_tools/simple_client.h"
+
+namespace net {
+namespace tools {
+namespace test {
+
+void SimpleClient::WaitForResponse() {
+ WaitForResponseForMs(-1);
+}
+
+// Waits for some data or response from the server.
+void SimpleClient::WaitForInitialResponse() {
+ WaitForInitialResponseForMs(-1);
+}
+
+int SimpleClient::ResetSocket() {
+ LOG(FATAL) << "SimpleClient::ResetSocket is not implemented";
+ return 0;
+}
+
+int SimpleClient::HalfClose() {
+ LOG(FATAL) << "SimpleClient::HalfClose is not implemented";
+ return 0;
+}
+
+int SimpleClient::response_header_size() const { return 0; }
+
+int64 SimpleClient::response_body_size() const { return 0; }
+
+} // namespace net
+} // namespace tools
+} // namespace test
diff --git a/chromium/net/tools/quic/test_tools/simple_client.h b/chromium/net/tools/quic/test_tools/simple_client.h
new file mode 100644
index 00000000000..9277fcbf18d
--- /dev/null
+++ b/chromium/net/tools/quic/test_tools/simple_client.h
@@ -0,0 +1,159 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_TOOLS_QUIC_TEST_TOOLS_SIMPLE_CLIENT_H_
+#define NET_TOOLS_QUIC_TEST_TOOLS_SIMPLE_CLIENT_H_
+
+#include <string>
+#include <vector>
+
+#include "net/base/ip_endpoint.h"
+#include "net/tools/balsa/balsa_frame.h"
+
+namespace net {
+namespace tools {
+namespace test {
+
+class HTTPMessage;
+
+class SimpleClient {
+ public:
+ virtual ~SimpleClient() {}
+
+ // Clears any outstanding state and sends 'size' bytes from 'buffer' to the
+ // server, possibly with multiple send operations. Returns 'size' on success
+ // and -1 on error. Callers should assume that any return value other than
+ // 'size' indicates failure.
+ virtual ssize_t Send(const void *buffer, size_t size) = 0;
+
+ // Serialize and send an HTTP request.
+ virtual ssize_t SendMessage(const HTTPMessage& message) = 0;
+
+ // Clears any outstanding state, sends 'size' bytes from 'buffer' and waits
+ // for a response or an error.
+ virtual ssize_t SendAndWaitForResponse(const void *buffer, size_t size) = 0;
+
+ // Clears any outstanding state and sends a simple GET of 'uri' to the
+ // server.
+ virtual ssize_t SendRequest(const std::string& uri) = 0;
+
+ // The response body is returned as a string.
+ virtual std::string SendCustomSynchronousRequest(
+ const HTTPMessage& message) = 0;
+ virtual std::string SendSynchronousRequest(const std::string& url) = 0;
+
+ // Returns once a complete response or a connection close has been received
+ // from the server.
+ virtual void WaitForResponse();
+
+ // Waits for some data or response from the server.
+ virtual void WaitForInitialResponse();
+
+ // Returns once a complete response or a connection close has been received
+ // from the server, or once the timeout expires. -1 for no timeout.
+ virtual void WaitForResponseForMs(int timeout_ms) = 0;
+
+ // Waits for some data or response from the server, or once the timeout
+ // expires. -1 for no timeout.
+ virtual void WaitForInitialResponseForMs(int timeout_ms) = 0;
+
+ // Clears any outstanding state from the last request.
+ virtual void ClearPerRequestState() = 0;
+
+ // Closes and reopens the connection to the server.
+ virtual void ResetConnection() = 0;
+
+ // Closes the connection to the server.
+ virtual void Disconnect() = 0;
+
+ // Both will return 0 on success, -1 otherwise.
+ // Sends out RST packet to peer.
+ // TODO(yongfa): Probably should be an interface too. LOG(FATAL) here
+ // to prevent accidental invocation.
+ virtual int ResetSocket();
+
+ virtual int HalfClose();
+
+ // Connects to the server. This should be done implicitly by Send*
+ // functions, but can be done explicitly as well.
+ virtual void Connect() = 0;
+
+ // Bind to the specified address. If set_bind_to_address() is called, this
+ // is called automatically on connect, but can be done explicitly to make
+ // LocalIPEndPoint() meaningful before actually connecting.
+ // Sets *local_address to the actual address bound to, which can be different
+ // if the given address has port 0.
+ virtual void Bind(IPEndPoint* local_address) = 0;
+
+ // Returns the local socket address of the client fd. Call only when
+ // connected.
+ // To get the local IPAdress, use LocalSocketAddress().host().
+ // To get the local port, use LocalSocketAddress.port().
+ virtual IPEndPoint LocalSocketAddress() const = 0;
+
+ // Returns the serialized message that would be sent by any of the HTTPMessage
+ // functions above.
+ virtual std::string SerializeMessage(const HTTPMessage& message) = 0;
+
+ // Sets the IP address to bind to on future Connect()s in case Bind() is not
+ // called in advance. If it's set to uninitialized IPAddress, default loopback
+ // address will be used.
+ virtual IPAddressNumber bind_to_address() const = 0;
+ virtual void set_bind_to_address(IPAddressNumber address) = 0;
+
+ // Returns true if the headers have been processed and are available.
+ virtual bool response_headers_complete() const = 0;
+
+ // Returns the response headers, if a response was completely framed.
+ // Undefined behavior otherwise.
+ virtual const BalsaHeaders* response_headers() const = 0;
+
+ // Returns true iff response has been fully received.
+ virtual bool response_complete() const = 0;
+
+ // Returns the number of bytes read from the server during this request.
+ virtual int64 response_size() const = 0;
+
+ // Returns the number of header bytes received during this request, if
+ // meaningful for the protocol.
+ virtual int response_header_size() const;
+
+ // Returns the number of body bytes received during this request, if
+ // meaningful for the protocol.
+ virtual int64 response_body_size() const;
+
+ // Returns the response body, if there was one. If there was no response, or
+ // if buffer_body() is false, returns an empty string.
+ virtual const std::string& response_body() = 0;
+
+ // The address the client is connected to.
+ virtual const IPEndPoint& address() const = 0;
+
+ // Returns true if the client is connected, false otherwise.
+ virtual bool connected() const = 0;
+
+ // Returns true if the server has informed the client that it is
+ // in "lame duck" mode, indicating intent to shut down and
+ // requesting that no further connections be established.
+ virtual bool ServerInLameDuckMode() const = 0;
+
+ // Return the number of bytes read off the wire by this client.
+ virtual size_t bytes_read() const = 0;
+
+ // Returns the number of bytes written to the wire by this client.
+ virtual size_t bytes_written() const = 0;
+
+ // Return the number of requests sent.
+ virtual size_t requests_sent() const = 0;
+
+ // Instructs the client to populate response_body().
+ virtual bool buffer_body() const = 0;
+ virtual void set_buffer_body(bool buffer_body) = 0;
+};
+
+} // namespace test
+} // namespace tools
+} // namespace net
+
+#endif // NET_TOOLS_QUIC_TEST_TOOLS_SIMPLE_CLIENT_H_
diff --git a/chromium/net/tools/testserver/run_testserver.cc b/chromium/net/tools/testserver/run_testserver.cc
index acf4177a8dd..717fee17a19 100644
--- a/chromium/net/tools/testserver/run_testserver.cc
+++ b/chromium/net/tools/testserver/run_testserver.cc
@@ -25,8 +25,8 @@ int main(int argc, const char* argv[]) {
base::MessageLoopForIO message_loop;
// Process command line
- CommandLine::Init(argc, argv);
- CommandLine* command_line = CommandLine::ForCurrentProcess();
+ base::CommandLine::Init(argc, argv);
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
logging::LoggingSettings settings;
settings.logging_dest = logging::LOG_TO_ALL;
@@ -113,7 +113,8 @@ int main(int argc, const char* argv[]) {
if (!base::DirectoryExists(test_server->document_root())) {
printf("Error: invalid doc root: \"%s\" does not exist!\n",
- UTF16ToUTF8(test_server->document_root().LossyDisplayName()).c_str());
+ base::UTF16ToUTF8(
+ test_server->document_root().LossyDisplayName()).c_str());
return -1;
}
diff --git a/chromium/net/tools/testserver/testserver.py b/chromium/net/tools/testserver/testserver.py
index 0a1f59b0c59..33faf463d3a 100755
--- a/chromium/net/tools/testserver/testserver.py
+++ b/chromium/net/tools/testserver/testserver.py
@@ -27,6 +27,7 @@ import re
import select
import socket
import SocketServer
+import ssl
import struct
import sys
import threading
@@ -38,20 +39,36 @@ import zlib
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(BASE_DIR)))
-import echo_message
-import testserver_base
+# Temporary hack to deal with tlslite 0.3.8 -> 0.4.6 upgrade.
+#
+# TODO(davidben): Remove this when it has cycled through all the bots and
+# developer checkouts or when http://crbug.com/356276 is resolved.
+try:
+ os.remove(os.path.join(ROOT_DIR, 'third_party', 'tlslite',
+ 'tlslite', 'utils', 'hmac.pyc'))
+except Exception:
+ pass
# Append at the end of sys.path, it's fine to use the system library.
sys.path.append(os.path.join(ROOT_DIR, 'third_party', 'pyftpdlib', 'src'))
-sys.path.append(os.path.join(ROOT_DIR, 'third_party', 'tlslite'))
-import pyftpdlib.ftpserver
-import tlslite
-import tlslite.api
-# Insert at the beginning of the path, we want this to be used
+# Insert at the beginning of the path, we want to use our copies of the library
# unconditionally.
sys.path.insert(0, os.path.join(ROOT_DIR, 'third_party', 'pywebsocket', 'src'))
+sys.path.insert(0, os.path.join(ROOT_DIR, 'third_party', 'tlslite'))
+
+import mod_pywebsocket.standalone
from mod_pywebsocket.standalone import WebSocketServer
+# import manually
+mod_pywebsocket.standalone.ssl = ssl
+
+import pyftpdlib.ftpserver
+
+import tlslite
+import tlslite.api
+
+import echo_message
+import testserver_base
SERVER_HTTP = 0
SERVER_FTP = 1
@@ -84,6 +101,7 @@ class WebSocketOptions:
self.certificate = None
self.tls_client_auth = False
self.tls_client_ca = None
+ self.tls_module = 'ssl'
self.use_basic_auth = False
@@ -134,10 +152,12 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn,
client verification."""
def __init__(self, server_address, request_hander_class, pem_cert_and_key,
- ssl_client_auth, ssl_client_cas, ssl_bulk_ciphers,
+ ssl_client_auth, ssl_client_cas, ssl_client_cert_types,
+ ssl_bulk_ciphers, ssl_key_exchanges, enable_npn,
record_resume_info, tls_intolerant, signed_cert_timestamps,
fallback_scsv_enabled, ocsp_response):
- self.cert_chain = tlslite.api.X509CertChain().parseChain(pem_cert_and_key)
+ self.cert_chain = tlslite.api.X509CertChain()
+ self.cert_chain.parsePemList(pem_cert_and_key)
# Force using only python implementation - otherwise behavior is different
# depending on whether m2crypto Python module is present (error is thrown
# when it is). m2crypto uses a C (based on OpenSSL) implementation under
@@ -147,19 +167,38 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn,
implementations=['python'])
self.ssl_client_auth = ssl_client_auth
self.ssl_client_cas = []
- self.tls_intolerant = tls_intolerant
+ self.ssl_client_cert_types = []
+ if enable_npn:
+ self.next_protos = ['http/1.1']
+ else:
+ self.next_protos = None
+ if tls_intolerant == 0:
+ self.tls_intolerant = None
+ else:
+ self.tls_intolerant = (3, tls_intolerant)
self.signed_cert_timestamps = signed_cert_timestamps
self.fallback_scsv_enabled = fallback_scsv_enabled
self.ocsp_response = ocsp_response
- for ca_file in ssl_client_cas:
- s = open(ca_file).read()
- x509 = tlslite.api.X509()
- x509.parse(s)
- self.ssl_client_cas.append(x509.subject)
+ if ssl_client_auth:
+ for ca_file in ssl_client_cas:
+ s = open(ca_file).read()
+ x509 = tlslite.api.X509()
+ x509.parse(s)
+ self.ssl_client_cas.append(x509.subject)
+
+ for cert_type in ssl_client_cert_types:
+ self.ssl_client_cert_types.append({
+ "rsa_sign": tlslite.api.ClientCertificateType.rsa_sign,
+ "dss_sign": tlslite.api.ClientCertificateType.dss_sign,
+ "ecdsa_sign": tlslite.api.ClientCertificateType.ecdsa_sign,
+ }[cert_type])
+
self.ssl_handshake_settings = tlslite.api.HandshakeSettings()
if ssl_bulk_ciphers is not None:
self.ssl_handshake_settings.cipherNames = ssl_bulk_ciphers
+ if ssl_key_exchanges is not None:
+ self.ssl_handshake_settings.keyExchangeNames = ssl_key_exchanges
if record_resume_info:
# If record_resume_info is true then we'll replace the session cache with
@@ -182,6 +221,8 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn,
reqCert=self.ssl_client_auth,
settings=self.ssl_handshake_settings,
reqCAs=self.ssl_client_cas,
+ reqCertTypes=self.ssl_client_cert_types,
+ nextProtos=self.next_protos,
tlsIntolerant=self.tls_intolerant,
signedCertTimestamps=
self.signed_cert_timestamps,
@@ -288,7 +329,6 @@ class TestPageHandler(testserver_base.BasePageHandler):
self.NoContentHandler,
self.ServerRedirectHandler,
self.ClientRedirectHandler,
- self.MultipartHandler,
self.GetSSLSessionCacheHandler,
self.SSLManySmallRecords,
self.GetChannelID,
@@ -1398,29 +1438,6 @@ class TestPageHandler(testserver_base.BasePageHandler):
return True
- def MultipartHandler(self):
- """Send a multipart response (10 text/html pages)."""
-
- test_name = '/multipart'
- if not self._ShouldHandleRequest(test_name):
- return False
-
- num_frames = 10
- bound = '12345'
- self.send_response(200)
- self.send_header('Content-Type',
- 'multipart/x-mixed-replace;boundary=' + bound)
- self.end_headers()
-
- for i in xrange(num_frames):
- self.wfile.write('--' + bound + '\r\n')
- self.wfile.write('Content-Type: text/html\r\n\r\n')
- self.wfile.write('<title>page ' + str(i) + '</title>')
- self.wfile.write('page ' + str(i))
-
- self.wfile.write('--' + bound + '--')
- return True
-
def GetSSLSessionCacheHandler(self):
"""Send a reply containing a log of the session cache operations."""
@@ -1431,11 +1448,14 @@ class TestPageHandler(testserver_base.BasePageHandler):
self.send_header('Content-Type', 'text/plain')
self.end_headers()
try:
- for (action, sessionID) in self.server.session_cache.log:
- self.wfile.write('%s\t%s\n' % (action, sessionID.encode('hex')))
+ log = self.server.session_cache.log
except AttributeError:
self.wfile.write('Pass --https-record-resume in order to use' +
' this request')
+ return True
+
+ for (action, sessionID) in log:
+ self.wfile.write('%s\t%s\n' % (action, bytes(sessionID).encode('hex')))
return True
def SSLManySmallRecords(self):
@@ -1465,7 +1485,7 @@ class TestPageHandler(testserver_base.BasePageHandler):
self.send_response(200)
self.send_header('Content-Type', 'text/plain')
self.end_headers()
- channel_id = self.server.tlsConnection.channel_id.tostring()
+ channel_id = bytes(self.server.tlsConnection.channel_id)
self.wfile.write(hashlib.sha256(channel_id).digest().encode('base64'))
return True
@@ -1956,17 +1976,22 @@ class ServerRunner(testserver_base.TestServerRunner):
server = HTTPSServer((host, port), TestPageHandler, pem_cert_and_key,
self.options.ssl_client_auth,
self.options.ssl_client_ca,
+ self.options.ssl_client_cert_type,
self.options.ssl_bulk_cipher,
+ self.options.ssl_key_exchange,
+ self.options.enable_npn,
self.options.record_resume,
self.options.tls_intolerant,
self.options.signed_cert_timestamps_tls_ext.decode(
"base64"),
self.options.fallback_scsv,
stapled_ocsp_response)
- print 'HTTPS server started on %s:%d...' % (host, server.server_port)
+ print 'HTTPS server started on https://%s:%d...' % \
+ (host, server.server_port)
else:
server = HTTPServer((host, port), TestPageHandler)
- print 'HTTP server started on %s:%d...' % (host, server.server_port)
+ print 'HTTP server started on http://%s:%d...' % \
+ (host, server.server_port)
server.data_dir = self.__make_data_dir()
server.file_root_url = self.options.file_root_url
@@ -1979,7 +2004,9 @@ class ServerRunner(testserver_base.TestServerRunner):
# is required to work correctly. It should be fixed from pywebsocket side.
os.chdir(self.__make_data_dir())
websocket_options = WebSocketOptions(host, port, '.')
+ scheme = "ws"
if self.options.cert_and_key_file:
+ scheme = "wss"
websocket_options.use_tls = True
websocket_options.private_key = self.options.cert_and_key_file
websocket_options.certificate = self.options.cert_and_key_file
@@ -1994,7 +2021,8 @@ class ServerRunner(testserver_base.TestServerRunner):
self.options.ssl_client_ca[0] + ' exiting...')
websocket_options.tls_client_ca = self.options.ssl_client_ca[0]
server = WebSocketServer(websocket_options)
- print 'WebSocket server started on %s:%d...' % (host, server.server_port)
+ print 'WebSocket server started on %s://%s:%d...' % \
+ (scheme, host, server.server_port)
server_data['port'] = server.server_port
elif self.options.server_type == SERVER_TCP_ECHO:
# Used for generating the key (randomly) that encodes the "echo request"
@@ -2137,6 +2165,15 @@ class ServerRunner(testserver_base.TestServerRunner):
'file. This option may appear multiple '
'times, indicating multiple CA names should '
'be sent in the request.')
+ self.option_parser.add_option('--ssl-client-cert-type', action='append',
+ default=[], help='Specify that the client '
+ 'certificate request should include the '
+ 'specified certificate_type value. This '
+ 'option may appear multiple times, '
+ 'indicating multiple values should be send '
+ 'in the request. Valid values are '
+ '"rsa_sign", "dss_sign", and "ecdsa_sign". '
+ 'If omitted, "rsa_sign" will be used.')
self.option_parser.add_option('--ssl-bulk-cipher', action='append',
help='Specify the bulk encryption '
'algorithm(s) that will be accepted by the '
@@ -2145,6 +2182,21 @@ class ServerRunner(testserver_base.TestServerRunner):
'algorithms will be used. This option may '
'appear multiple times, indicating '
'multiple algorithms should be enabled.');
+ self.option_parser.add_option('--ssl-key-exchange', action='append',
+ help='Specify the key exchange algorithm(s)'
+ 'that will be accepted by the SSL server. '
+ 'Valid values are "rsa", "dhe_rsa". If '
+ 'omitted, all algorithms will be used. This '
+ 'option may appear multiple times, '
+ 'indicating multiple algorithms should be '
+ 'enabled.');
+ # TODO(davidben): Add ALPN support to tlslite.
+ self.option_parser.add_option('--enable-npn', dest='enable_npn',
+ default=False, const=True,
+ action='store_const',
+ help='Enable server support for the NPN '
+ 'extension. The server will advertise '
+ 'support for exactly one protocol, http/1.1')
self.option_parser.add_option('--file-root-url', default='/files/',
help='Specify a root URL for files served.')
diff --git a/chromium/net/tools/testserver/testserver_base.py b/chromium/net/tools/testserver/testserver_base.py
index 455ca5c3202..0d3f65fdca9 100644
--- a/chromium/net/tools/testserver/testserver_base.py
+++ b/chromium/net/tools/testserver/testserver_base.py
@@ -14,6 +14,8 @@ import struct
import sys
import warnings
+import tlslite.errors
+
# Ignore deprecation warnings, they make our output more cluttered.
warnings.filterwarnings("ignore", category=DeprecationWarning)
@@ -71,6 +73,9 @@ class BrokenPipeHandlerMixIn:
def handle_error(self, request, client_address):
value = sys.exc_info()[1]
+ if isinstance(value, tlslite.errors.TLSClosedConnectionError):
+ print "testserver.py: Closed connection"
+ return
if isinstance(value, socket.error):
err = value.args[0]
if sys.platform in ('win32', 'cygwin'):
@@ -81,6 +86,9 @@ class BrokenPipeHandlerMixIn:
if err == pipe_err:
print "testserver.py: Broken pipe"
return
+ if err == errno.ECONNRESET:
+ print "testserver.py: Connection reset by peer"
+ return
SocketServer.BaseServer.handle_error(self, request, client_address)
diff --git a/chromium/net/tools/tld_cleanup/BUILD.gn b/chromium/net/tools/tld_cleanup/BUILD.gn
new file mode 100644
index 00000000000..bf89c008bb0
--- /dev/null
+++ b/chromium/net/tools/tld_cleanup/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("tld_cleanup") {
+ sources = [
+ "tld_cleanup_util.cc",
+ "tld_cleanup_util.h",
+ ]
+ deps = [
+ "//base",
+ "//url",
+ ]
+}
diff --git a/chromium/net/tools/tld_cleanup/PRESUBMIT.py b/chromium/net/tools/tld_cleanup/PRESUBMIT.py
new file mode 100644
index 00000000000..8391e0e61a1
--- /dev/null
+++ b/chromium/net/tools/tld_cleanup/PRESUBMIT.py
@@ -0,0 +1,32 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+"""Chromium presubmit script for src/net/tools/tld_cleanup."""
+
+
+def _RunMakeDafsaTests(input_api, output_api):
+ """Runs unittest for make_dafsa if any related file has been modified."""
+ files = ('net/tools/tld_cleanup/make_dafsa.py',
+ 'net/tools/tld_cleanup/make_dafsa_unittest.py')
+ if not any(f in input_api.LocalPaths() for f in files):
+ return []
+ test_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
+ 'make_dafsa_unittest.py')
+ cmd_name = 'make_dafsa_unittest'
+ cmd = [input_api.python_executable, test_path]
+ test_cmd = input_api.Command(
+ name=cmd_name,
+ cmd=cmd,
+ kwargs={},
+ message=output_api.PresubmitPromptWarning)
+ return input_api.RunTests([test_cmd])
+
+
+def CheckChangeOnUpload(input_api, output_api):
+ return _RunMakeDafsaTests(input_api, output_api)
+
+
+def CheckChangeOnCommit(input_api, output_api):
+ return _RunMakeDafsaTests(input_api, output_api)
diff --git a/chromium/net/tools/tld_cleanup/README b/chromium/net/tools/tld_cleanup/README
index a7f137d7660..13614700e42 100644
--- a/chromium/net/tools/tld_cleanup/README
+++ b/chromium/net/tools/tld_cleanup/README
@@ -20,12 +20,9 @@ When updating src/net/base/registry_controlled_domains/effective_tld_names.dat:
src/build/Debug. It will re-generate
src/net/base/registry_controlled_domains/effective_tld_names.gperf.
-6. Run gperf on the new effective_tld_names.gperf:
- pushd src/net/base/registry_controlled_domains;
- gperf -a -L "C++" -C -c -o -t -k '*' -NFindDomain -P -K name_offset -D -m 10 \
- effective_tld_names.gperf > effective_tld_names.cc;
- popd;
- It will produce a new effective_tld_names.cc.
+6. Check in the updated effective_tld_names.dat, effective_tld_names.gperf
-7. Check in the updated effective_tld_names.dat, effective_tld_names.gperf,
- and effective_tld_names.cc together.
+Note that gperf is no longer used for effective_tld_names, but when building
+chromium the file effective_tld_names.gperf will be parsed by make_dafsa.py
+to generate the file effective_tld_names-inc.cc, which is included in
+registry_controlled_domain.cc
diff --git a/chromium/net/tools/tld_cleanup/make_dafsa.py b/chromium/net/tools/tld_cleanup/make_dafsa.py
new file mode 100755
index 00000000000..78358effa84
--- /dev/null
+++ b/chromium/net/tools/tld_cleanup/make_dafsa.py
@@ -0,0 +1,469 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+A Deterministic acyclic finite state automaton (DAFSA) is a compact
+representation of an unordered word list (dictionary).
+
+http://en.wikipedia.org/wiki/Deterministic_acyclic_finite_state_automaton
+
+This python program converts a list of strings to a byte array in C++.
+This python program fetches strings and return values from a gperf file
+and generates a C++ file with a byte array representing graph that can be
+used as a memory efficient replacement for the perfect hash table.
+
+The input strings are assumed to consist of printable 7-bit ASCII characters
+and the return values are assumed to be one digit integers.
+
+In this program a DAFSA is a diamond shaped graph starting at a common
+source node and ending at a common sink node. All internal nodes contain
+a label and each word is represented by the labels in one path from
+the source node to the sink node.
+
+The following python represention is used for nodes:
+
+ Source node: [ children ]
+ Internal node: (label, [ children ])
+ Sink node: None
+
+The graph is first compressed by prefixes like a trie. In the next step
+suffixes are compressed so that the graph gets diamond shaped. Finally
+one to one linked nodes are replaced by nodes with the labels joined.
+
+The order of the operations is crucial since lookups will be performed
+starting from the source with no backtracking. Thus a node must have at
+most one child with a label starting by the same character. The output
+is also arranged so that all jumps are to increasing addresses, thus forward
+in memory.
+
+The generated output has suffix free decoding so that the sign of leading
+bits in a link (a reference to a child node) indicate if it has a size of one,
+two or three bytes and if it is the last outgoing link from the actual node.
+A node label is terminated by a byte with the leading bit set.
+
+The generated byte array can described by the following BNF:
+
+<byte> ::= < 8-bit value in range [0x00-0xFF] >
+
+<char> ::= < printable 7-bit ASCII character, byte in range [0x20-0x7F] >
+<end_char> ::= < char + 0x80, byte in range [0xA0-0xFF] >
+<return value> ::= < value + 0x80, byte in range [0x80-0x8F] >
+
+<offset1> ::= < byte in range [0x00-0x3F] >
+<offset2> ::= < byte in range [0x40-0x5F] >
+<offset3> ::= < byte in range [0x60-0x7F] >
+
+<end_offset1> ::= < byte in range [0x80-0xBF] >
+<end_offset2> ::= < byte in range [0xC0-0xDF] >
+<end_offset3> ::= < byte in range [0xE0-0xFF] >
+
+<prefix> ::= <char>
+
+<label> ::= <end_char>
+ | <char> <label>
+
+<end_label> ::= <return_value>
+ | <char> <end_label>
+
+<offset> ::= <offset1>
+ | <offset2> <byte>
+ | <offset3> <byte> <byte>
+
+<end_offset> ::= <end_offset1>
+ | <end_offset2> <byte>
+ | <end_offset3> <byte> <byte>
+
+<offsets> ::= <end_offset>
+ | <offset> <offsets>
+
+<source> ::= <offsets>
+
+<node> ::= <label> <offsets>
+ | <prefix> <node>
+ | <end_label>
+
+<dafsa> ::= <source>
+ | <dafsa> <node>
+
+Decoding:
+
+<char> -> printable 7-bit ASCII character
+<end_char> & 0x7F -> printable 7-bit ASCII character
+<return value> & 0x0F -> integer
+<offset1 & 0x3F> -> integer
+((<offset2> & 0x1F>) << 8) + <byte> -> integer
+((<offset3> & 0x1F>) << 16) + (<byte> << 8) + <byte> -> integer
+
+end_offset1, end_offset2 and and_offset3 are decoded same as offset1,
+offset2 and offset3 respectively.
+
+The first offset in a list of offsets is the distance in bytes between the
+offset itself and the first child node. Subsequent offsets are the distance
+between previous child node and next child node. Thus each offset links a node
+to a child node. The distance is always counted between start addresses, i.e.
+first byte in decoded offset or first byte in child node.
+
+Example 1:
+
+%%
+aa, 1
+a, 2
+%%
+
+The input is first parsed to a list of words:
+["aa1", "a2"]
+
+A fully expanded graph is created from the words:
+source = [node1, node4]
+node1 = ("a", [node2])
+node2 = ("a", [node3])
+node3 = ("\x01", [sink])
+node4 = ("a", [node5])
+node5 = ("\x02", [sink])
+sink = None
+
+Compression results in the following graph:
+source = [node1]
+node1 = ("a", [node2, node3])
+node2 = ("\x02", [sink])
+node3 = ("a\x01", [sink])
+sink = None
+
+A C++ representation of the compressed graph is generated:
+
+const unsigned char dafsa[7] = {
+ 0x81, 0xE1, 0x02, 0x81, 0x82, 0x61, 0x81,
+};
+
+The bytes in the generated array has the following meaning:
+
+ 0: 0x81 <end_offset1> child at position 0 + (0x81 & 0x3F) -> jump to 1
+
+ 1: 0xE1 <end_char> label character (0xE1 & 0x7F) -> match "a"
+ 2: 0x02 <offset1> child at position 2 + (0x02 & 0x3F) -> jump to 4
+
+ 3: 0x81 <end_offset1> child at position 4 + (0x81 & 0x3F) -> jump to 5
+ 4: 0x82 <return_value> 0x82 & 0x0F -> return 2
+
+ 5: 0x61 <char> label character 0x61 -> match "a"
+ 6: 0x81 <return_value> 0x81 & 0x0F -> return 1
+
+Example 2:
+
+%%
+aa, 1
+bbb, 2
+baa, 1
+%%
+
+The input is first parsed to a list of words:
+["aa1", "bbb2", "baa1"]
+
+Compression results in the following graph:
+source = [node1, node2]
+node1 = ("b", [node2, node3])
+node2 = ("aa\x01", [sink])
+node3 = ("bb\x02", [sink])
+sink = None
+
+A C++ representation of the compressed graph is generated:
+
+const unsigned char dafsa[11] = {
+ 0x02, 0x83, 0xE2, 0x02, 0x83, 0x61, 0x61, 0x81, 0x62, 0x62, 0x82,
+};
+
+The bytes in the generated array has the following meaning:
+
+ 0: 0x02 <offset1> child at position 0 + (0x02 & 0x3F) -> jump to 2
+ 1: 0x83 <end_offset1> child at position 2 + (0x83 & 0x3F) -> jump to 5
+
+ 2: 0xE2 <end_char> label character (0xE2 & 0x7F) -> match "b"
+ 3: 0x02 <offset1> child at position 3 + (0x02 & 0x3F) -> jump to 5
+ 4: 0x83 <end_offset1> child at position 5 + (0x83 & 0x3F) -> jump to 8
+
+ 5: 0x61 <char> label character 0x61 -> match "a"
+ 6: 0x61 <char> label character 0x61 -> match "a"
+ 7: 0x81 <return_value> 0x81 & 0x0F -> return 1
+
+ 8: 0x62 <char> label character 0x62 -> match "b"
+ 9: 0x62 <char> label character 0x62 -> match "b"
+10: 0x82 <return_value> 0x82 & 0x0F -> return 2
+"""
+
+import sys
+
+class InputError(Exception):
+ """Exception raised for errors in the input file."""
+
+
+def to_dafsa(words):
+ """Generates a DAFSA from a word list and returns the source node.
+
+ Each word is split into characters so that each character is represented by
+ a unique node. It is assumed the word list is not empty.
+ """
+ if not words:
+ raise InputError('The domain list must not be empty')
+ def ToNodes(word):
+ """Split words into characters"""
+ if not 0x1F < ord(word[0]) < 0x80:
+ raise InputError('Domain names must be printable 7-bit ASCII')
+ if len(word) == 1:
+ return chr(ord(word[0]) & 0x0F), [None]
+ return word[0], [ToNodes(word[1:])]
+ return [ToNodes(word) for word in words]
+
+
+def to_words(node):
+ """Generates a word list from all paths starting from an internal node."""
+ if not node:
+ return ['']
+ return [(node[0] + word) for child in node[1] for word in to_words(child)]
+
+
+def reverse(dafsa):
+ """Generates a new DAFSA that is reversed, so that the old sink node becomes
+ the new source node.
+ """
+ sink = []
+ nodemap = {}
+
+ def dfs(node, parent):
+ """Creates reverse nodes.
+
+ A new reverse node will be created for each old node. The new node will
+ get a reversed label and the parents of the old node as children.
+ """
+ if not node:
+ sink.append(parent)
+ elif id(node) not in nodemap:
+ nodemap[id(node)] = (node[0][::-1], [parent])
+ for child in node[1]:
+ dfs(child, nodemap[id(node)])
+ else:
+ nodemap[id(node)][1].append(parent)
+
+ for node in dafsa:
+ dfs(node, None)
+ return sink
+
+
+def join_labels(dafsa):
+ """Generates a new DAFSA where internal nodes are merged if there is a one to
+ one connection.
+ """
+ parentcount = { id(None): 2 }
+ nodemap = { id(None): None }
+
+ def count_parents(node):
+ """Count incoming references"""
+ if id(node) in parentcount:
+ parentcount[id(node)] += 1
+ else:
+ parentcount[id(node)] = 1
+ for child in node[1]:
+ count_parents(child)
+
+ def join(node):
+ """Create new nodes"""
+ if id(node) not in nodemap:
+ children = [join(child) for child in node[1]]
+ if len(children) == 1 and parentcount[id(node[1][0])] == 1:
+ child = children[0]
+ nodemap[id(node)] = (node[0] + child[0], child[1])
+ else:
+ nodemap[id(node)] = (node[0], children)
+ return nodemap[id(node)]
+
+ for node in dafsa:
+ count_parents(node)
+ return [join(node) for node in dafsa]
+
+
+def join_suffixes(dafsa):
+ """Generates a new DAFSA where nodes that represent the same word lists
+ towards the sink are merged.
+ """
+ nodemap = { frozenset(('',)): None }
+
+ def join(node):
+ """Returns a macthing node. A new node is created if no matching node
+ exists. The graph is accessed in dfs order.
+ """
+ suffixes = frozenset(to_words(node))
+ if suffixes not in nodemap:
+ nodemap[suffixes] = (node[0], [join(child) for child in node[1]])
+ return nodemap[suffixes]
+
+ return [join(node) for node in dafsa]
+
+
+def top_sort(dafsa):
+ """Generates list of nodes in topological sort order."""
+ incoming = {}
+
+ def count_incoming(node):
+ """Counts incoming references."""
+ if node:
+ if id(node) not in incoming:
+ incoming[id(node)] = 1
+ for child in node[1]:
+ count_incoming(child)
+ else:
+ incoming[id(node)] += 1
+
+ for node in dafsa:
+ count_incoming(node)
+
+ for node in dafsa:
+ incoming[id(node)] -= 1
+
+ waiting = [node for node in dafsa if incoming[id(node)] == 0]
+ nodes = []
+
+ while waiting:
+ node = waiting.pop()
+ assert incoming[id(node)] == 0
+ nodes.append(node)
+ for child in node[1]:
+ if child:
+ incoming[id(child)] -= 1
+ if incoming[id(child)] == 0:
+ waiting.append(child)
+ return nodes
+
+
+def encode_links(children, offsets, current):
+ """Encodes a list of children as one, two or three byte offsets."""
+ if not children[0]:
+ # This is an <end_label> node and no links follow such nodes
+ assert len(children) == 1
+ return []
+ guess = 3 * len(children)
+ assert children
+ children = sorted(children, key = lambda x: -offsets[id(x)])
+ while True:
+ offset = current + guess
+ buf = []
+ for child in children:
+ last = len(buf)
+ distance = offset - offsets[id(child)]
+ assert distance > 0 and distance < (1 << 21)
+
+ if distance < (1 << 6):
+ # A 6-bit offset: "s0xxxxxx"
+ buf.append(distance)
+ elif distance < (1 << 13):
+ # A 13-bit offset: "s10xxxxxxxxxxxxx"
+ buf.append(0x40 | (distance >> 8))
+ buf.append(distance & 0xFF)
+ else:
+ # A 21-bit offset: "s11xxxxxxxxxxxxxxxxxxxxx"
+ buf.append(0x60 | (distance >> 16))
+ buf.append((distance >> 8) & 0xFF)
+ buf.append(distance & 0xFF)
+ # Distance in first link is relative to following record.
+ # Distance in other links are relative to previous link.
+ offset -= distance
+ if len(buf) == guess:
+ break
+ guess = len(buf)
+ # Set most significant bit to mark end of links in this node.
+ buf[last] |= (1 << 7)
+ buf.reverse()
+ return buf
+
+
+def encode_prefix(label):
+ """Encodes a node label as a list of bytes without a trailing high byte.
+
+ This method encodes a node if there is exactly one child and the
+ child follows immidiately after so that no jump is needed. This label
+ will then be a prefix to the label in the child node.
+ """
+ assert label
+ return [ord(c) for c in reversed(label)]
+
+
+def encode_label(label):
+ """Encodes a node label as a list of bytes with a trailing high byte >0x80.
+ """
+ buf = encode_prefix(label)
+ # Set most significant bit to mark end of label in this node.
+ buf[0] |= (1 << 7)
+ return buf
+
+
+def encode(dafsa):
+ """Encodes a DAFSA to a list of bytes"""
+ output = []
+ offsets = {}
+
+ for node in reversed(top_sort(dafsa)):
+ if (len(node[1]) == 1 and node[1][0] and
+ (offsets[id(node[1][0])] == len(output))):
+ output.extend(encode_prefix(node[0]))
+ else:
+ output.extend(encode_links(node[1], offsets, len(output)))
+ output.extend(encode_label(node[0]))
+ offsets[id(node)] = len(output)
+
+ output.extend(encode_links(dafsa, offsets, len(output)))
+ output.reverse()
+ return output
+
+
+def to_cxx(data):
+ """Generates C++ code from a list of encoded bytes."""
+ text = '/* This file is generated. DO NOT EDIT!\n\n'
+ text += 'The byte array encodes effective tld names. See make_dafsa.py for'
+ text += ' documentation.'
+ text += '*/\n\n'
+ text += 'const unsigned char kDafsa[%s] = {\n' % len(data)
+ for i in range(0, len(data), 12):
+ text += ' '
+ text += ', '.join('0x%02x' % byte for byte in data[i:i + 12])
+ text += ',\n'
+ text += '};\n'
+ return text
+
+
+def words_to_cxx(words):
+ """Generates C++ code from a word list"""
+ dafsa = to_dafsa(words)
+ for fun in (reverse, join_suffixes, reverse, join_suffixes, join_labels):
+ dafsa = fun(dafsa)
+ return to_cxx(encode(dafsa))
+
+
+def parse_gperf(infile):
+ """Parses gperf file and extract strings and return code"""
+ lines = [line.strip() for line in infile]
+ # Extract strings after the first '%%' and before the second '%%'.
+ begin = lines.index('%%') + 1
+ end = lines.index('%%', begin)
+ lines = lines[begin:end]
+ for line in lines:
+ if line[-3:-1] != ', ':
+ raise InputError('Expected "domainname, <digit>", found "%s"' % line)
+ # Technically the DAFSA format could support return values in range [0-31],
+ # but the values below are the only with a defined meaning.
+ if line[-1] not in '0124':
+ raise InputError('Expected value to be one of {0,1,2,4}, found "%s"' %
+ line[-1])
+ return [line[:-3] + line[-1] for line in lines]
+
+
+def main():
+ if len(sys.argv) != 3:
+ print('usage: %s infile outfile' % sys.argv[0])
+ return 1
+ with open(sys.argv[1], 'r') as infile, open(sys.argv[2], 'w') as outfile:
+ outfile.write(words_to_cxx(parse_gperf(infile)))
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/chromium/net/tools/tld_cleanup/make_dafsa_unittest.py b/chromium/net/tools/tld_cleanup/make_dafsa_unittest.py
new file mode 100755
index 00000000000..5ff92e62292
--- /dev/null
+++ b/chromium/net/tools/tld_cleanup/make_dafsa_unittest.py
@@ -0,0 +1,757 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+import sys
+import unittest
+import make_dafsa
+
+
+class ParseGperfTest(unittest.TestCase):
+ def testMalformedKey(self):
+ """Tests exception is thrown at bad format."""
+ infile1 = [ '%%', '', '%%' ]
+ self.assertRaises(make_dafsa.InputError, make_dafsa.parse_gperf, infile1)
+
+ infile2 = [ '%%', 'apa,1', '%%' ]
+ self.assertRaises(make_dafsa.InputError, make_dafsa.parse_gperf, infile2)
+
+ infile3 = [ '%%', 'apa, 1', '%%' ]
+ self.assertRaises(make_dafsa.InputError, make_dafsa.parse_gperf, infile3)
+
+ def testBadValues(self):
+ """Tests exception is thrown when value is out of range."""
+ infile1 = [ '%%', 'a, -1', '%%' ]
+ self.assertRaises(make_dafsa.InputError, make_dafsa.parse_gperf, infile1)
+
+ infile2 = [ '%%', 'a, x', '%%' ]
+ self.assertRaises(make_dafsa.InputError, make_dafsa.parse_gperf, infile2)
+
+ infile3 = [ '%%', 'a, 3', '%%' ]
+ self.assertRaises(make_dafsa.InputError, make_dafsa.parse_gperf, infile3)
+
+ infile4 = [ '%%', 'a, 6', '%%' ]
+ self.assertRaises(make_dafsa.InputError, make_dafsa.parse_gperf, infile4)
+
+ infile5 = [ '%%', 'a, 12', '%%' ]
+ self.assertRaises(make_dafsa.InputError, make_dafsa.parse_gperf, infile5)
+
+ def testValues(self):
+ """Tests legal values are accepted."""
+ infile1 = [ '%%', 'a, 0', '%%' ]
+ words1 = [ 'a0' ]
+ self.assertEqual(make_dafsa.parse_gperf(infile1), words1)
+
+ infile2 = [ '%%', 'a, 1', '%%' ]
+ words2 = [ 'a1' ]
+ self.assertEqual(make_dafsa.parse_gperf(infile2), words2)
+
+ infile3 = [ '%%', 'a, 2', '%%' ]
+ words3 = [ 'a2' ]
+ self.assertEqual(make_dafsa.parse_gperf(infile3), words3)
+
+ infile4 = [ '%%', 'a, 4', '%%' ]
+ words4 = [ 'a4' ]
+ self.assertEqual(make_dafsa.parse_gperf(infile4), words4)
+
+ def testOneWord(self):
+ """Tests a single key can be parsed."""
+ infile = [ '%%', 'apa, 1', '%%' ]
+ words = [ 'apa1' ]
+ self.assertEqual(make_dafsa.parse_gperf(infile), words)
+
+ def testTwoWords(self):
+ """Tests a sequence of keys can be parsed."""
+ infile = [ '%%', 'apa, 1', 'bepa.com, 2', '%%' ]
+ words = [ 'apa1', 'bepa.com2' ]
+ self.assertEqual(make_dafsa.parse_gperf(infile), words)
+
+
+class ToDafsaTest(unittest.TestCase):
+ def testEmptyInput(self):
+ """Tests exception is thrown at empty input."""
+ words = ()
+ self.assertRaises(make_dafsa.InputError, make_dafsa.to_dafsa, words)
+
+ def testNonASCII(self):
+ """Tests exception is thrown if illegal characters are used."""
+ words1 = ( chr(0x1F) + 'a1', )
+ self.assertRaises(make_dafsa.InputError, make_dafsa.to_dafsa, words1)
+
+ words2 = ( 'a' + chr(0x1F) + '1', )
+ self.assertRaises(make_dafsa.InputError, make_dafsa.to_dafsa, words2)
+
+ words3 = ( chr(0x80) + 'a1', )
+ self.assertRaises(make_dafsa.InputError, make_dafsa.to_dafsa, words3)
+
+ words4 = ( 'a' + chr(0x80) + '1', )
+ self.assertRaises(make_dafsa.InputError, make_dafsa.to_dafsa, words4)
+
+ def testChar(self):
+ """Tests a DAFSA can be created from a single character domain name."""
+ words = [ 'a0' ]
+ node2 = ( chr(0), [ None ] )
+ node1 = ( 'a', [ node2 ] )
+ source = [ node1 ]
+ self.assertEqual(make_dafsa.to_dafsa(words), source)
+
+ def testChars(self):
+ """Tests a DAFSA can be created from a multi character domain name."""
+ words = [ 'ab0' ]
+ node3 = ( chr(0), [ None ] )
+ node2 = ( 'b', [ node3 ] )
+ node1 = ( 'a', [ node2 ] )
+ source = [ node1 ]
+ self.assertEqual(make_dafsa.to_dafsa(words), source)
+
+ def testWords(self):
+ """Tests a DAFSA can be created from a sequence of domain names."""
+ words = [ 'a0', 'b1' ]
+ node4 = ( chr(1), [ None ] )
+ node3 = ( 'b', [ node4 ] )
+ node2 = ( chr(0), [ None ] )
+ node1 = ( 'a', [ node2 ] )
+ source = [ node1, node3 ]
+ self.assertEqual(make_dafsa.to_dafsa(words), source)
+
+
+class ToWordsTest(unittest.TestCase):
+ def testSink(self):
+ """Tests the sink is exapnded to a list with an empty string."""
+ node1 = None
+ words = [ '' ]
+ self.assertEqual(make_dafsa.to_words(node1), words)
+
+ def testSingleNode(self):
+ """Tests a single node is expanded to a list with the label string."""
+
+ # 'ab' -> [ 'ab' ]
+
+ node1 = ( 'ab', [ None ] )
+ words = [ 'ab' ]
+ self.assertEqual(make_dafsa.to_words(node1), words)
+
+ def testChain(self):
+ """Tests a sequence of nodes are preoperly expanded."""
+
+ # 'ab' -> 'cd' => [ 'abcd' ]
+
+ node2 = ( 'cd', [ None ] )
+ node1 = ( 'ab', [ node2 ] )
+ words = [ 'abcd' ]
+ self.assertEqual(make_dafsa.to_words(node1), words)
+
+ def testInnerTerminator(self):
+ """Tests a sequence with an inner terminator is expanded to two strings."""
+
+ # 'a' -> 'b'
+ # \ => [ 'ab', 'a' ]
+ # {sink}
+
+ node2 = ( 'b', [ None ] )
+ node1 = ( 'a', [ node2, None ] )
+ words = [ 'ab', 'a' ]
+ self.assertEqual(make_dafsa.to_words(node1), words)
+
+ def testDiamond(self):
+ """Tests a diamond can be expanded to a word list."""
+
+ # 'cd'
+ # / \
+ # 'ab' 'gh'
+ # \ /
+ # 'ef'
+
+ node4 = ( 'gh', [ None ] )
+ node3 = ( 'ef', [ node4 ] )
+ node2 = ( 'cd', [ node4 ] )
+ node1 = ( 'ab', [ node2, node3 ] )
+ words = [ 'abcdgh', 'abefgh' ]
+ self.assertEqual(make_dafsa.to_words(node1), words)
+
+
+class JoinLabelsTest(unittest.TestCase):
+ def testLabel(self):
+ """Tests a single label passes unchanged."""
+
+ # 'a' => 'a'
+
+ node1 = ( 'a', [ None ] )
+ source = [ node1 ]
+ self.assertEqual(make_dafsa.join_labels(source), source)
+
+ def testInnerTerminator(self):
+ """Tests a sequence with an inner terminator passes unchanged."""
+
+ # 'a' -> 'b' 'a' -> 'b'
+ # \ => \
+ # {sink} {sink}
+
+ node2 = ( 'b', [ None ] )
+ node1 = ( 'a', [ node2, None ] )
+ source = [ node1 ]
+ self.assertEqual(make_dafsa.join_labels(source), source)
+
+ def testLabels(self):
+ """Tests a sequence of labels can be joined."""
+
+ # 'a' -> 'b' => 'ab'
+
+ node2 = ( 'b', [ None ] )
+ node1 = ( 'a', [ node2 ] )
+ source1 = [ node1 ]
+ node3 = ( 'ab', [ None ] )
+ source2 = [ node3 ]
+ self.assertEqual(make_dafsa.join_labels(source1), source2)
+
+ def testCompositeLabels(self):
+ """Tests a sequence of multi character labels can be joined."""
+
+ # 'ab' -> 'cd' => 'abcd'
+
+ node2 = ( 'cd', [ None ] )
+ node1 = ( 'ab', [ node2 ] )
+ source1 = [ node1 ]
+ node3 = ( 'abcd', [ None ] )
+ source2 = [ node3 ]
+ self.assertEqual(make_dafsa.join_labels(source1), source2)
+
+ def testAtomicTrie(self):
+ """Tests a trie formed DAFSA with atomic labels passes unchanged."""
+
+ # 'b' 'b'
+ # / /
+ # 'a' => 'a'
+ # \ \
+ # 'c' 'c'
+
+ node3 = ( 'c', [ None ] )
+ node2 = ( 'b', [ None ] )
+ node1 = ( 'a', [ node2, node3 ] )
+ source = [ node1 ]
+ self.assertEqual(make_dafsa.join_labels(source), source)
+
+ def testReverseAtomicTrie(self):
+ """Tests a reverse trie formed DAFSA with atomic labels passes unchanged."""
+
+ # 'a' 'a'
+ # \ \
+ # 'c' => 'c'
+ # / /
+ # 'b' 'b'
+
+ node3 = ( 'c', [ None ] )
+ node2 = ( 'b', [ node3 ] )
+ node1 = ( 'a', [ node3 ] )
+ source = [ node1, node2 ]
+ self.assertEqual(make_dafsa.join_labels(source), source)
+
+ def testChainedTrie(self):
+ """Tests a trie formed DAFSA with chained labels can be joined."""
+
+ # 'c' -> 'd' 'cd'
+ # / /
+ # 'a' -> 'b' => 'ab'
+ # \ \
+ # 'e' -> 'f' 'ef'
+
+ node6 = ( 'f', [ None ] )
+ node5 = ( 'e', [ node6 ] )
+ node4 = ( 'd', [ None ] )
+ node3 = ( 'c', [ node4 ] )
+ node2 = ( 'b', [ node3, node5 ] )
+ node1 = ( 'a', [ node2 ] )
+ source1 = [ node1 ]
+ node9 = ( 'ef', [ None ] )
+ node8 = ( 'cd', [ None ] )
+ node7 = ( 'ab', [ node8, node9 ] )
+ source2 = [ node7 ]
+ self.assertEqual(make_dafsa.join_labels(source1), source2)
+
+ def testReverseChainedTrie(self):
+ """Tests a reverse trie formed DAFSA with chained labels can be joined."""
+
+ # 'a' -> 'b' 'ab'
+ # \ \
+ # 'e' -> 'f' => 'ef'
+ # / /
+ # 'c' -> 'd' 'cd'
+
+ node6 = ( 'f', [ None ] )
+ node5 = ( 'e', [ node6 ] )
+ node4 = ( 'd', [ node5 ] )
+ node3 = ( 'c', [ node4 ] )
+ node2 = ( 'b', [ node5 ] )
+ node1 = ( 'a', [ node2 ] )
+ source1 = [ node1, node3 ]
+ node9 = ( 'ef', [ None ] )
+ node8 = ( 'cd', [ node9 ] )
+ node7 = ( 'ab', [ node9 ] )
+ source2 = [ node7, node8 ]
+ self.assertEqual(make_dafsa.join_labels(source1), source2)
+
+
+class JoinSuffixesTest(unittest.TestCase):
+ def testSingleLabel(self):
+ """Tests a single label passes unchanged."""
+
+ # 'a' => 'a'
+
+ node1 = ( 'a', [ None ] )
+ source = [ node1 ]
+ self.assertEqual(make_dafsa.join_suffixes(source), source)
+
+ def testInnerTerminator(self):
+ """Tests a sequence with an inner terminator passes unchanged."""
+
+ # 'a' -> 'b' 'a' -> 'b'
+ # \ => \
+ # {sink} {sink}
+
+ node2 = ( 'b', [ None ] )
+ node1 = ( 'a', [ node2, None ] )
+ source = [ node1 ]
+ self.assertEqual(make_dafsa.join_suffixes(source), source)
+
+ def testDistinctTrie(self):
+ """Tests a trie formed DAFSA with distinct labels passes unchanged."""
+
+ # 'b' 'b'
+ # / /
+ # 'a' => 'a'
+ # \ \
+ # 'c' 'c'
+
+ node3 = ( 'c', [ None ] )
+ node2 = ( 'b', [ None ] )
+ node1 = ( 'a', [ node2, node3 ] )
+ source = [ node1 ]
+ self.assertEqual(make_dafsa.join_suffixes(source), source)
+
+ def testReverseDistinctTrie(self):
+ """Tests a reverse trie formed DAFSA with distinct labels passes unchanged.
+ """
+
+ # 'a' 'a'
+ # \ \
+ # 'c' => 'c'
+ # / /
+ # 'b' 'b'
+
+ node3 = ( 'c', [ None ] )
+ node2 = ( 'b', [ node3 ] )
+ node1 = ( 'a', [ node3 ] )
+ source = [ node1, node2 ]
+ self.assertEqual(make_dafsa.join_suffixes(source), source)
+
+ def testJoinTwoHeads(self):
+ """Tests two heads can be joined even if there is something else between."""
+
+ # 'a' ------'a'
+ # /
+ # 'b' => 'b' /
+ # /
+ # 'a' ---
+ #
+ # The picture above should shows that the new version should have just one
+ # instance of the node with label 'a'.
+
+ node3 = ( 'a', [ None ] )
+ node2 = ( 'b', [ None ] )
+ node1 = ( 'a', [ None ] )
+ source1 = [ node1, node2, node3 ]
+ source2 = make_dafsa.join_suffixes(source1)
+
+ # Both versions should expand to the same content.
+ self.assertEqual(source1, source2)
+ # But the new version should have just one instance of 'a'.
+ self.assertIs(source2[0], source2[2])
+
+ def testJoinTails(self):
+ """Tests tails can be joined."""
+
+ # 'a' -> 'c' 'a'
+ # \
+ # => 'c'
+ # /
+ # 'b' -> 'c' 'b'
+
+ node4 = ( 'c', [ None ] )
+ node3 = ( 'b', [ node4 ] )
+ node2 = ( 'c', [ None ] )
+ node1 = ( 'a', [ node2 ] )
+ source1 = [ node1, node3 ]
+ source2 = make_dafsa.join_suffixes(source1)
+
+ # Both versions should expand to the same content.
+ self.assertEqual(source1, source2)
+ # But the new version should have just one tail.
+ self.assertIs(source2[0][1][0], source2[1][1][0])
+
+ def testMakeRecursiveTrie(self):
+ """Tests recursive suffix join."""
+
+ # 'a' -> 'e' -> 'g' 'a'
+ # \
+ # 'e'
+ # / \
+ # 'b' -> 'e' -> 'g' 'b' \
+ # \
+ # => 'g'
+ # /
+ # 'c' -> 'f' -> 'g' 'c' /
+ # \ /
+ # 'f'
+ # /
+ # 'd' -> 'f' -> 'g' 'd'
+
+ node7 = ( 'g', [ None ] )
+ node6 = ( 'f', [ node7 ] )
+ node5 = ( 'e', [ node7 ] )
+ node4 = ( 'd', [ node6 ] )
+ node3 = ( 'c', [ node6 ] )
+ node2 = ( 'b', [ node5 ] )
+ node1 = ( 'a', [ node5 ] )
+ source1 = [ node1, node2, node3, node4 ]
+ source2 = make_dafsa.join_suffixes(source1)
+
+ # Both versions should expand to the same content.
+ self.assertEqual(source1, source2)
+ # But the new version should have just one 'e'.
+ self.assertIs(source2[0][1][0], source2[1][1][0])
+ # And one 'f'.
+ self.assertIs(source2[2][1][0], source2[3][1][0])
+ # And one 'g'.
+ self.assertIs(source2[0][1][0][1][0], source2[2][1][0][1][0])
+
+ def testMakeDiamond(self):
+ """Test we can join suffixes of a trie."""
+
+ # 'b' -> 'd' 'b'
+ # / / \
+ # 'a' => 'a' 'd'
+ # \ \ /
+ # 'c' -> 'd' 'c'
+
+ node5 = ( 'd', [ None ] )
+ node4 = ( 'c', [ node5 ] )
+ node3 = ( 'd', [ None ] )
+ node2 = ( 'b', [ node3 ] )
+ node1 = ( 'a', [ node2, node4 ] )
+ source1 = [ node1 ]
+ source2 = make_dafsa.join_suffixes(source1)
+
+ # Both versions should expand to the same content.
+ self.assertEqual(source1, source2)
+ # But the new version should have just one 'd'.
+ self.assertIs(source2[0][1][0][1][0], source2[0][1][1][1][0])
+
+ def testJoinOneChild(self):
+ """Tests that we can join some children but not all."""
+
+ # 'c' ----'c'
+ # / / /
+ # 'a' 'a' /
+ # \ \ /
+ # 'd' 'd'/
+ # => /
+ # 'c' /
+ # / /
+ # 'b' 'b'
+ # \ \
+ # 'e' 'e'
+
+ node6 = ( 'e', [ None ] )
+ node5 = ( 'c', [ None ] )
+ node4 = ( 'b', [ node5, node6 ] )
+ node3 = ( 'd', [ None ] )
+ node2 = ( 'c', [ None ] )
+ node1 = ( 'a', [ node2, node3 ] )
+ source1 = [ node1, node4 ]
+ source2 = make_dafsa.join_suffixes(source1)
+
+ # Both versions should expand to the same content.
+ self.assertEqual(source1, source2)
+ # But the new version should have just one 'c'.
+ self.assertIs(source2[0][1][0], source2[1][1][0])
+
+
+class ReverseTest(unittest.TestCase):
+ def testAtomicLabel(self):
+ """Tests an atomic label passes unchanged."""
+
+ # 'a' => 'a'
+
+ node1 = ( 'a', [ None ] )
+ source = [ node1 ]
+ self.assertEqual(make_dafsa.reverse(source), source)
+
+ def testLabel(self):
+ """Tests that labels are reversed."""
+
+ # 'ab' => 'ba'
+
+ node1 = ( 'ab', [ None ] )
+ source1 = [ node1 ]
+ node2 = ( 'ba', [ None ] )
+ source2 = [ node2 ]
+ self.assertEqual(make_dafsa.reverse(source1), source2)
+
+ def testChain(self):
+ """Tests that edges are reversed."""
+
+ # 'a' -> 'b' => 'b' -> 'a'
+
+ node2 = ( 'b', [ None ] )
+ node1 = ( 'a', [ node2 ] )
+ source1 = [ node1 ]
+ node4 = ( 'a', [ None ] )
+ node3 = ( 'b', [ node4 ] )
+ source2 = [ node3 ]
+ self.assertEqual(make_dafsa.reverse(source1), source2)
+
+ def testInnerTerminator(self):
+ """Tests a sequence with an inner terminator can be reversed."""
+
+ # 'a' -> 'b' 'b' -> 'a'
+ # \ => /
+ # {sink} ------
+
+ node2 = ( 'b', [ None ] )
+ node1 = ( 'a', [ node2, None ] )
+ source1 = [ node1 ]
+ node4 = ( 'a', [ None ] )
+ node3 = ( 'b', [ node4 ] )
+ source2 = [ node3, node4 ]
+ self.assertEqual(make_dafsa.reverse(source1), source2)
+
+ def testAtomicTrie(self):
+ """Tests a trie formed DAFSA can be reversed."""
+
+ # 'b' 'b'
+ # / \
+ # 'a' => 'a'
+ # \ /
+ # 'c' 'c'
+
+ node3 = ( 'c', [ None ] )
+ node2 = ( 'b', [ None ] )
+ node1 = ( 'a', [ node2, node3 ] )
+ source1 = [ node1 ]
+ node6 = ( 'a', [ None ] )
+ node5 = ( 'c', [ node6 ] )
+ node4 = ( 'b', [ node6 ] )
+ source2 = [ node4, node5 ]
+ self.assertEqual(make_dafsa.reverse(source1), source2)
+
+ def testReverseAtomicTrie(self):
+ """Tests a reverse trie formed DAFSA can be reversed."""
+
+ # 'a' 'a'
+ # \ /
+ # 'c' => 'c'
+ # / \
+ # 'b' 'b'
+
+ node3 = ( 'c', [ None ] )
+ node2 = ( 'b', [ node3 ] )
+ node1 = ( 'a', [ node3 ] )
+ source1 = [ node1, node2 ]
+ node6 = ( 'b', [ None ] )
+ node5 = ( 'a', [ None ] )
+ node4 = ( 'c', [ node5, node6 ] )
+ source2 = [ node4 ]
+ self.assertEqual(make_dafsa.reverse(source1), source2)
+
+ def testDiamond(self):
+ """Tests we can reverse both edges and nodes in a diamond."""
+
+ # 'cd' 'dc'
+ # / \ / \
+ # 'ab' 'gh' => 'hg' 'ba'
+ # \ / \ /
+ # 'ef' 'fe'
+
+ node4 = ( 'gh', [ None ] )
+ node3 = ( 'ef', [ node4 ] )
+ node2 = ( 'cd', [ node4 ] )
+ node1 = ( 'ab', [ node2, node3 ] )
+ source1 = [ node1 ]
+ node8 = ( 'ba', [ None ] )
+ node7 = ( 'fe', [ node8 ] )
+ node6 = ( 'dc', [ node8 ] )
+ node5 = ( 'hg', [ node6, node7 ] )
+ source2 = [ node5 ]
+ self.assertEqual(make_dafsa.reverse(source1), source2)
+
+
+class TopSortTest(unittest.TestCase):
+ def testNode(self):
+ """Tests a DAFSA with one node can be sorted."""
+
+ # 'a' => [ 'a' ]
+
+ node1 = ( 'a', [ None ] )
+ source = [ node1 ]
+ nodes = [ node1 ]
+ self.assertEqual(make_dafsa.top_sort(source), nodes)
+
+ def testDiamond(self):
+ """Tests nodes in a diamond can be sorted."""
+
+ # 'b'
+ # / \
+ # 'a' 'd'
+ # \ /
+ # 'c'
+
+ node4 = ( 'd', [ None ] )
+ node3 = ( 'c', [ node4 ] )
+ node2 = ( 'b', [ node4 ] )
+ node1 = ( 'a', [ node2, node3 ] )
+ source = [ node1 ]
+ nodes = make_dafsa.top_sort(source)
+ self.assertLess(nodes.index(node1), nodes.index(node2))
+ self.assertLess(nodes.index(node2), nodes.index(node4))
+ self.assertLess(nodes.index(node3), nodes.index(node4))
+
+
+class EncodePrefixTest(unittest.TestCase):
+ def testChar(self):
+ """Tests to encode a single character prefix."""
+ label = 'a'
+ bytes = [ ord('a') ]
+ self.assertEqual(make_dafsa.encode_prefix(label), bytes)
+
+ def testChars(self):
+ """Tests to encode a multi character prefix."""
+ label = 'ab'
+ bytes = [ ord('b'), ord('a') ]
+ self.assertEqual(make_dafsa.encode_prefix(label), bytes)
+
+
+class EncodeLabelTest(unittest.TestCase):
+ def testChar(self):
+ """Tests to encode a single character label."""
+ label = 'a'
+ bytes = [ ord('a') + 0x80 ]
+ self.assertEqual(make_dafsa.encode_label(label), bytes)
+
+ def testChars(self):
+ """Tests to encode a multi character label."""
+ label = 'ab'
+ bytes = [ ord('b') + 0x80, ord('a') ]
+ self.assertEqual(make_dafsa.encode_label(label), bytes)
+
+
+class EncodeLinksTest(unittest.TestCase):
+ def testEndLabel(self):
+ """Tests to encode link to the sink."""
+ children = [ None ]
+ offsets = {}
+ bytes = 0
+ output = []
+ self.assertEqual(make_dafsa.encode_links(children, offsets, bytes),
+ output)
+
+ def testOneByteOffset(self):
+ """Tests to encode a single one byte offset."""
+ node = ( '', [ None ] )
+ children = [ node ]
+ offsets = { id(node) : 2 }
+ bytes = 5
+ output = [ 132 ]
+ self.assertEqual(make_dafsa.encode_links(children, offsets, bytes),
+ output)
+
+ def testOneByteOffsets(self):
+ """Tests to encode a sequence of one byte offsets."""
+ node1 = ( '', [ None ] )
+ node2 = ( '', [ None ] )
+ children = [ node1, node2 ]
+ offsets = { id(node1) : 2, id(node2) : 1 }
+ bytes = 5
+ output = [ 129, 5 ]
+ self.assertEqual(make_dafsa.encode_links(children, offsets, bytes),
+ output)
+
+ def testTwoBytesOffset(self):
+ """Tests to encode a single two byte offset."""
+ node = ( '', [ None ] )
+ children = [ node ]
+ offsets = { id(node) : 2 }
+ bytes = 1005
+ output = [ 237, 195]
+ self.assertEqual(make_dafsa.encode_links(children, offsets, bytes),
+ output)
+
+ def testTwoBytesOffsets(self):
+ """Tests to encode a sequence of two byte offsets."""
+ node1 = ( '', [ None ] )
+ node2 = ( '', [ None ] )
+ node3 = ( '', [ None ] )
+ children = [ node1, node2, node3 ]
+ offsets = { id(node1) : 1002, id(node2) : 2, id(node3) : 2002 }
+ bytes = 3005
+ output = [ 232, 195, 232, 67, 241, 67 ]
+ self.assertEqual(make_dafsa.encode_links(children, offsets, bytes),
+ output)
+
+ def testThreeBytesOffset(self):
+ """Tests to encode a single three byte offset."""
+ node = ( '', [ None ] )
+ children = [ node ]
+ offsets = { id(node) : 2 }
+ bytes = 100005
+ output = [ 166, 134, 225 ]
+ self.assertEqual(make_dafsa.encode_links(children, offsets, bytes),
+ output)
+
+ def testThreeBytesOffsets(self):
+ """Tests to encode a sequence of three byte offsets."""
+ node1 = ( '', [ None ] )
+ node2 = ( '', [ None ] )
+ node3 = ( '', [ None ] )
+ children = [ node1, node2, node3 ]
+ offsets = { id(node1) : 100002, id(node2) : 2, id(node3) : 200002 }
+ bytes = 300005
+ output = [ 160, 134, 225, 160, 134, 97, 172, 134, 97 ]
+ self.assertEqual(make_dafsa.encode_links(children, offsets, bytes),
+ output)
+
+ def testOneTwoThreeBytesOffsets(self):
+ """Tests to encode offsets of different sizes."""
+ node1 = ( '', [ None ] )
+ node2 = ( '', [ None ] )
+ node3 = ( '', [ None ] )
+ children = [ node1, node2, node3 ]
+ offsets = { id(node1) : 10003, id(node2) : 10002, id(node3) : 100002 }
+ bytes = 300005
+ output = [ 129, 143, 95, 97, 74, 13, 99 ]
+ self.assertEqual(make_dafsa.encode_links(children, offsets, bytes),
+ output)
+
+
+class ExamplesTest(unittest.TestCase):
+ def testExample1(self):
+ """Tests Example 1 from make_dafsa.py."""
+ infile = [ '%%', 'aa, 1', 'a, 2', '%%' ]
+ bytes = [ 0x81, 0xE1, 0x02, 0x81, 0x82, 0x61, 0x81 ]
+ outfile = make_dafsa.to_cxx(bytes)
+ self.assertEqual(make_dafsa.words_to_cxx(make_dafsa.parse_gperf(infile)),
+ outfile)
+
+ def testExample2(self):
+ """Tests Example 2 from make_dafsa.py."""
+ infile = [ '%%', 'aa, 1', 'bbb, 2', 'baa, 1', '%%' ]
+ bytes = [ 0x02, 0x83, 0xE2, 0x02, 0x83, 0x61, 0x61, 0x81, 0x62, 0x62,
+ 0x82 ]
+ outfile = make_dafsa.to_cxx(bytes)
+ self.assertEqual(make_dafsa.words_to_cxx(make_dafsa.parse_gperf(infile)),
+ outfile)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/chromium/net/tools/tld_cleanup/tld_cleanup.cc b/chromium/net/tools/tld_cleanup/tld_cleanup.cc
index a4b127bdf2c..5594145cd39 100644
--- a/chromium/net/tools/tld_cleanup/tld_cleanup.cc
+++ b/chromium/net/tools/tld_cleanup/tld_cleanup.cc
@@ -53,7 +53,7 @@ int main(int argc, const char* argv[]) {
logging::LOG_TO_ALL;
#endif
- CommandLine::Init(argc, argv);
+ base::CommandLine::Init(argc, argv);
base::FilePath log_filename;
PathService::Get(base::DIR_EXE, &log_filename);
diff --git a/chromium/net/tools/tld_cleanup/tld_cleanup_util.cc b/chromium/net/tools/tld_cleanup/tld_cleanup_util.cc
index 623403fed93..5a206e4c61a 100644
--- a/chromium/net/tools/tld_cleanup/tld_cleanup_util.cc
+++ b/chromium/net/tools/tld_cleanup/tld_cleanup_util.cc
@@ -61,7 +61,7 @@ bool WriteRules(const RuleMap& rules, const base::FilePath& outfile) {
data.append("%%\n");
- int written = file_util::WriteFile(outfile,
+ int written = base::WriteFile(outfile,
data.data(),
static_cast<int>(data.size()));
@@ -115,7 +115,7 @@ NormalizeResult NormalizeRule(std::string* domain, Rule* rule) {
url.append(*domain);
GURL gurl(url);
const std::string& spec = gurl.possibly_invalid_spec();
- url_parse::Component host = gurl.parsed_for_possibly_invalid_spec().host;
+ url::Component host = gurl.parsed_for_possibly_invalid_spec().host;
if (host.len < 0) {
LOG(ERROR) << "Ignoring rule that couldn't be normalized: " << *domain;
return kError;