1dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Use of this source code is governed by a BSD-style license that can be
3dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// found in the LICENSE file.
4dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
5dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "net/tools/flip_server/mem_cache.h"
6dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
7dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include <dirent.h>
8dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include <errno.h>
9dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include <fcntl.h>
10dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include <stdio.h>
11dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include <sys/stat.h>
12dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include <sys/types.h>
13dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
14dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include <deque>
15dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
16dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/string_piece.h"
17dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "net/tools/dump_cache/url_to_filename_encoder.h"
18dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "net/tools/dump_cache/url_utilities.h"
19dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "net/tools/flip_server/balsa_frame.h"
20dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "net/tools/flip_server/balsa_headers.h"
21dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
22dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// The directory where cache locates);
23dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenstd::string FLAGS_cache_base_dir = ".";
24dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
25dc0f95d653279beabeb9817299e2902918ba123eKristian Monsennamespace net {
26dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
27dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid StoreBodyAndHeadersVisitor::ProcessBodyData(const char *input,
28dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                                 size_t size) {
29dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  body.append(input, size);
30dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
31dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
32dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid StoreBodyAndHeadersVisitor::HandleHeaderError(BalsaFrame* framer) {
33dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  HandleError();
34dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
35dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
36dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid StoreBodyAndHeadersVisitor::HandleHeaderWarning(BalsaFrame* framer) {
37dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  HandleError();
38dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
39dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
40dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid StoreBodyAndHeadersVisitor::HandleChunkingError(BalsaFrame* framer) {
41dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  HandleError();
42dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
43dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
44dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid StoreBodyAndHeadersVisitor::HandleBodyError(BalsaFrame* framer) {
45dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  HandleError();
46dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
47dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
48dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenFileData::FileData(BalsaHeaders* h, const std::string& b)
49dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    : headers(h), body(b) {
50dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
51dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
52dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenFileData::FileData() {}
53dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
54dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenFileData::~FileData() {}
55dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
56dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid FileData::CopyFrom(const FileData& file_data) {
57dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    headers = new BalsaHeaders;
58dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    headers->CopyFrom(*(file_data.headers));
59dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    filename = file_data.filename;
60dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    related_files = file_data.related_files;
61dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    body = file_data.body;
62dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
63dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
64dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenMemoryCache::MemoryCache() {}
65dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
66dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenMemoryCache::~MemoryCache() {}
67dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
68dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid MemoryCache::CloneFrom(const MemoryCache& mc) {
69dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  for (Files::const_iterator i = mc.files_.begin();
70dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen       i != mc.files_.end();
71dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen       ++i) {
72dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    Files::iterator out_i =
73dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        files_.insert(make_pair(i->first, FileData())).first;
74dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    out_i->second.CopyFrom(i->second);
75dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    cwd_ = mc.cwd_;
76dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
77dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
78dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
79dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid MemoryCache::AddFiles() {
80dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  std::deque<std::string> paths;
81dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  cwd_ = FLAGS_cache_base_dir;
82dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  paths.push_back(cwd_ + "/GET_");
83dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DIR* current_dir = NULL;
84dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  while (!paths.empty()) {
85dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    while (current_dir == NULL && !paths.empty()) {
86dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      std::string current_dir_name = paths.front();
87dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      VLOG(1) << "Attempting to open dir: \"" << current_dir_name << "\"";
88dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      current_dir = opendir(current_dir_name.c_str());
89dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      paths.pop_front();
90dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
91dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (current_dir == NULL) {
92dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        perror("Unable to open directory. ");
93dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        current_dir_name.clear();
94dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        continue;
95dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      }
96dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
97dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (current_dir) {
98dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        VLOG(1) << "Succeeded opening";
99dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        for (struct dirent* dir_data = readdir(current_dir);
100dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen             dir_data != NULL;
101dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen             dir_data = readdir(current_dir)) {
102dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          std::string current_entry_name =
103dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            current_dir_name + "/" + dir_data->d_name;
104dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          if (dir_data->d_type == DT_REG) {
105dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            VLOG(1) << "Found file: " << current_entry_name;
106dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            ReadAndStoreFileContents(current_entry_name.c_str());
107dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          } else if (dir_data->d_type == DT_DIR) {
108dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            VLOG(1) << "Found subdir: " << current_entry_name;
109dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            if (std::string(dir_data->d_name) != "." &&
110dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                std::string(dir_data->d_name) != "..") {
111dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen              VLOG(1) << "Adding to search path: " << current_entry_name;
112dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen              paths.push_front(current_entry_name);
113dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            }
114dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          }
115dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        }
116dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        VLOG(1) << "Oops, no data left. Closing dir.";
117dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        closedir(current_dir);
118dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        current_dir = NULL;
119dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      }
120dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
121dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
122dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
123dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
124dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid MemoryCache::ReadToString(const char* filename, std::string* output) {
125dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  output->clear();
126dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  int fd = open(filename, 0, "r");
127dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (fd == -1)
128dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return;
129dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  char buffer[4096];
130dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  ssize_t read_status = read(fd, buffer, sizeof(buffer));
131dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  while (read_status > 0) {
132dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    output->append(buffer, static_cast<size_t>(read_status));
133dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    do {
134dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      read_status = read(fd, buffer, sizeof(buffer));
135dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    } while (read_status <= 0 && errno == EINTR);
136dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
137dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  close(fd);
138dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
139dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
140dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid MemoryCache::ReadAndStoreFileContents(const char* filename) {
141dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  StoreBodyAndHeadersVisitor visitor;
142dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  BalsaFrame framer;
143dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  framer.set_balsa_visitor(&visitor);
144dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  framer.set_balsa_headers(&(visitor.headers));
145dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  std::string filename_contents;
146dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  ReadToString(filename, &filename_contents);
147dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
148dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Ugly hack to make everything look like 1.1.
149dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (filename_contents.find("HTTP/1.0") == 0)
150dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    filename_contents[7] = '1';
151dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
152dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  size_t pos = 0;
153dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  size_t old_pos = 0;
154dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  while (true) {
155dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    old_pos = pos;
156dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    pos += framer.ProcessInput(filename_contents.data() + pos,
157dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                               filename_contents.size() - pos);
158dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (framer.Error() || pos == old_pos) {
159dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      LOG(ERROR) << "Unable to make forward progress, or error"
160dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        " framing file: " << filename;
161dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (framer.Error()) {
162dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        LOG(INFO) << "********************************************ERROR!";
163dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        return;
164dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      }
165dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      return;
166dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
167dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (framer.MessageFullyRead()) {
168dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      // If no Content-Length or Transfer-Encoding was captured in the
169dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      // file, then the rest of the data is the body.  Many of the captures
170dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      // from within Chrome don't have content-lengths.
171dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (!visitor.body.length())
172dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        visitor.body = filename_contents.substr(pos);
173dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      break;
174dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
175dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
176dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  visitor.headers.RemoveAllOfHeader("content-length");
177dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  visitor.headers.RemoveAllOfHeader("transfer-encoding");
178dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  visitor.headers.RemoveAllOfHeader("connection");
179dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  visitor.headers.AppendHeader("transfer-encoding", "chunked");
180dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  visitor.headers.AppendHeader("connection", "keep-alive");
181dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
182dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Experiment with changing headers for forcing use of cached
183dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // versions of content.
184dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // TODO(mbelshe) REMOVE ME
185dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#if 0
186dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // TODO(mbelshe) append current date.
187dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  visitor.headers.RemoveAllOfHeader("date");
188dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (visitor.headers.HasHeader("expires")) {
189dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    visitor.headers.RemoveAllOfHeader("expires");
190dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    visitor.headers.AppendHeader("expires",
191dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                               "Fri, 30 Aug, 2019 12:00:00 GMT");
192dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
193dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#endif
194dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  BalsaHeaders* headers = new BalsaHeaders;
195dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  headers->CopyFrom(visitor.headers);
196dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  std::string filename_stripped = std::string(filename).substr(cwd_.size() + 1);
197dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  LOG(INFO) << "Adding file (" << visitor.body.length() << " bytes): "
198dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            << filename_stripped;
199dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  files_[filename_stripped] = FileData();
200dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  FileData& fd = files_[filename_stripped];
201dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  fd = FileData(headers, visitor.body);
202dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  fd.filename = std::string(filename_stripped,
203dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                            filename_stripped.find_first_of('/'));
204dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
205dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
206dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenFileData* MemoryCache::GetFileData(const std::string& filename) {
207dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  Files::iterator fi = files_.end();
208dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (filename.compare(filename.length() - 5, 5, ".html", 5) == 0) {
209dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    std::string new_filename(filename.data(), filename.size() - 5);
210dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    new_filename += ".http";
211dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    fi = files_.find(new_filename);
212dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
213dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (fi == files_.end())
214dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    fi = files_.find(filename);
215dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
216dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (fi == files_.end()) {
217dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return NULL;
218dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
219dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return &(fi->second);
220dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
221dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
222dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool MemoryCache::AssignFileData(const std::string& filename,
223dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                 MemCacheIter* mci) {
224dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  mci->file_data = GetFileData(filename);
225dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (mci->file_data == NULL) {
226dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    LOG(ERROR) << "Could not find file data for " << filename;
227dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return false;
228dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
229dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return true;
230dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
231dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
232dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}  // namespace net
233dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
234