Index: chrome_frame/test/test_server.cc |
diff --git a/chrome_frame/test/test_server.cc b/chrome_frame/test/test_server.cc |
deleted file mode 100644 |
index 327ed2f837f1c9578f30948d29fdb3407f6322c8..0000000000000000000000000000000000000000 |
--- a/chrome_frame/test/test_server.cc |
+++ /dev/null |
@@ -1,422 +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 "chrome_frame/test/test_server.h" |
- |
-#include <windows.h> |
-#include <objbase.h> |
-#include <urlmon.h> |
- |
-#include "base/bind.h" |
-#include "base/logging.h" |
-#include "base/strings/string_number_conversions.h" |
-#include "base/strings/string_piece.h" |
-#include "base/strings/string_util.h" |
-#include "base/strings/stringprintf.h" |
-#include "base/strings/utf_string_conversions.h" |
-#include "chrome_frame/test/chrome_frame_test_utils.h" |
-#include "net/base/winsock_init.h" |
-#include "net/http/http_util.h" |
-#include "net/socket/tcp_listen_socket.h" |
- |
-namespace test_server { |
-const char kDefaultHeaderTemplate[] = |
- "HTTP/1.1 %hs\r\n" |
- "Connection: close\r\n" |
- "Content-Type: %hs\r\n" |
- "Content-Length: %i\r\n\r\n"; |
-const char kStatusOk[] = "200 OK"; |
-const char kStatusNotFound[] = "404 Not Found"; |
-const char kDefaultContentType[] = "text/html; charset=UTF-8"; |
- |
-void Request::ParseHeaders(const std::string& headers) { |
- DCHECK(method_.length() == 0); |
- |
- size_t pos = headers.find("\r\n"); |
- DCHECK(pos != std::string::npos); |
- if (pos != std::string::npos) { |
- headers_ = headers.substr(pos + 2); |
- |
- base::StringTokenizer tokenizer( |
- headers.begin(), headers.begin() + pos, " "); |
- std::string* parse[] = { &method_, &path_, &version_ }; |
- int field = 0; |
- while (tokenizer.GetNext() && field < arraysize(parse)) { |
- parse[field++]->assign(tokenizer.token_begin(), |
- tokenizer.token_end()); |
- } |
- } |
- |
- // Check for content-length in case we're being sent some data. |
- net::HttpUtil::HeadersIterator it(headers_.begin(), headers_.end(), |
- "\r\n"); |
- while (it.GetNext()) { |
- if (LowerCaseEqualsASCII(it.name(), "content-length")) { |
- int int_content_length; |
- base::StringToInt(base::StringPiece(it.values_begin(), |
- it.values_end()), |
- &int_content_length); |
- content_length_ = int_content_length; |
- break; |
- } |
- } |
-} |
- |
-void Request::OnDataReceived(const std::string& data) { |
- content_ += data; |
- |
- if (method_.length() == 0) { |
- size_t index = content_.find("\r\n\r\n"); |
- if (index != std::string::npos) { |
- // Parse the headers before returning and chop them of the |
- // data buffer we've already received. |
- std::string headers(content_.substr(0, index + 2)); |
- ParseHeaders(headers); |
- content_.erase(0, index + 4); |
- } |
- } |
-} |
- |
-ResponseForPath::~ResponseForPath() { |
-} |
- |
-SimpleResponse::~SimpleResponse() { |
-} |
- |
-bool FileResponse::GetContentType(std::string* content_type) const { |
- size_t length = ContentLength(); |
- char buffer[4096]; |
- void* data = NULL; |
- |
- if (length) { |
- // Create a copy of the first few bytes of the file. |
- // If we try and use the mapped file directly, FindMimeFromData will crash |
- // 'cause it cheats and temporarily tries to write to the buffer! |
- length = std::min(arraysize(buffer), length); |
- memcpy(buffer, file_->data(), length); |
- data = buffer; |
- } |
- |
- LPOLESTR mime_type = NULL; |
- FindMimeFromData(NULL, file_path_.value().c_str(), data, length, NULL, |
- FMFD_DEFAULT, &mime_type, 0); |
- if (mime_type) { |
- *content_type = WideToASCII(mime_type); |
- ::CoTaskMemFree(mime_type); |
- } |
- |
- return content_type->length() > 0; |
-} |
- |
-void FileResponse::WriteContents(net::StreamListenSocket* socket) const { |
- DCHECK(file_.get()); |
- if (file_.get()) { |
- socket->Send(reinterpret_cast<const char*>(file_->data()), |
- file_->length(), false); |
- } |
-} |
- |
-size_t FileResponse::ContentLength() const { |
- if (file_.get() == NULL) { |
- file_.reset(new base::MemoryMappedFile()); |
- if (!file_->Initialize(file_path_)) { |
- NOTREACHED(); |
- file_.reset(); |
- } |
- } |
- return file_.get() ? file_->length() : 0; |
-} |
- |
-bool RedirectResponse::GetCustomHeaders(std::string* headers) const { |
- *headers = base::StringPrintf("HTTP/1.1 302 Found\r\n" |
- "Connection: close\r\n" |
- "Content-Length: 0\r\n" |
- "Content-Type: text/html\r\n" |
- "Location: %hs\r\n\r\n", |
- redirect_url_.c_str()); |
- return true; |
-} |
- |
-SimpleWebServer::SimpleWebServer(int port) { |
- Construct(chrome_frame_test::GetLocalIPv4Address(), port); |
-} |
- |
-SimpleWebServer::SimpleWebServer(const std::string& address, int port) { |
- Construct(address, port); |
-} |
- |
-SimpleWebServer::~SimpleWebServer() { |
- ConnectionList::const_iterator it; |
- for (it = connections_.begin(); it != connections_.end(); ++it) |
- delete (*it); |
- connections_.clear(); |
-} |
- |
-void SimpleWebServer::Construct(const std::string& address, int port) { |
- CHECK(base::MessageLoop::current()) |
- << "SimpleWebServer requires a message loop"; |
- net::EnsureWinsockInit(); |
- AddResponse(&quit_); |
- host_ = address; |
- server_ = net::TCPListenSocket::CreateAndListen(address, port, this); |
- LOG_IF(DFATAL, !server_.get()) |
- << "Failed to create listener socket at " << address << ":" << port; |
-} |
- |
-void SimpleWebServer::AddResponse(Response* response) { |
- responses_.push_back(response); |
-} |
- |
-void SimpleWebServer::DeleteAllResponses() { |
- std::list<Response*>::const_iterator it; |
- for (it = responses_.begin(); it != responses_.end(); ++it) { |
- if ((*it) != &quit_) |
- delete (*it); |
- } |
-} |
- |
-Response* SimpleWebServer::FindResponse(const Request& request) const { |
- std::list<Response*>::const_iterator it; |
- for (it = responses_.begin(); it != responses_.end(); it++) { |
- Response* response = (*it); |
- if (response->Matches(request)) { |
- return response; |
- } |
- } |
- return NULL; |
-} |
- |
-Connection* SimpleWebServer::FindConnection( |
- const net::StreamListenSocket* socket) const { |
- ConnectionList::const_iterator it; |
- for (it = connections_.begin(); it != connections_.end(); it++) { |
- if ((*it)->IsSame(socket)) { |
- return (*it); |
- } |
- } |
- return NULL; |
-} |
- |
-void SimpleWebServer::DidAccept( |
- net::StreamListenSocket* server, |
- scoped_ptr<net::StreamListenSocket> connection) { |
- connections_.push_back(new Connection(connection.Pass())); |
-} |
- |
-void SimpleWebServer::DidRead(net::StreamListenSocket* connection, |
- const char* data, |
- int len) { |
- Connection* c = FindConnection(connection); |
- DCHECK(c); |
- Request& r = c->request(); |
- std::string str(data, len); |
- r.OnDataReceived(str); |
- if (r.AllContentReceived()) { |
- const Request& request = c->request(); |
- Response* response = FindResponse(request); |
- if (response) { |
- std::string headers; |
- if (!response->GetCustomHeaders(&headers)) { |
- std::string content_type; |
- if (!response->GetContentType(&content_type)) |
- content_type = kDefaultContentType; |
- headers = base::StringPrintf(kDefaultHeaderTemplate, kStatusOk, |
- content_type.c_str(), |
- response->ContentLength()); |
- } |
- |
- connection->Send(headers, false); |
- response->WriteContents(connection); |
- response->IncrementAccessCounter(); |
- } else { |
- std::string payload = "sorry, I can't find " + request.path(); |
- std::string headers(base::StringPrintf(kDefaultHeaderTemplate, |
- kStatusNotFound, |
- kDefaultContentType, |
- payload.length())); |
- connection->Send(headers, false); |
- connection->Send(payload, false); |
- } |
- } |
-} |
- |
-void SimpleWebServer::DidClose(net::StreamListenSocket* sock) { |
- // To keep the historical list of connections reasonably tidy, we delete |
- // 404's when the connection ends. |
- Connection* c = FindConnection(sock); |
- DCHECK(c); |
- c->OnSocketClosed(); |
- if (!FindResponse(c->request())) { |
- // extremely inefficient, but in one line and not that common... :) |
- connections_.erase(std::find(connections_.begin(), connections_.end(), c)); |
- delete c; |
- } |
-} |
- |
-HTTPTestServer::HTTPTestServer(int port, const std::wstring& address, |
- base::FilePath root_dir) |
- : port_(port), address_(address), root_dir_(root_dir) { |
- net::EnsureWinsockInit(); |
- server_ = net::TCPListenSocket::CreateAndListen( |
- base::WideToUTF8(address), port, this); |
-} |
- |
-HTTPTestServer::~HTTPTestServer() { |
-} |
- |
-std::list<scoped_refptr<ConfigurableConnection>>::iterator |
-HTTPTestServer::FindConnection(const net::StreamListenSocket* socket) { |
- ConnectionList::iterator it; |
- // Scan through the list searching for the desired socket. Along the way, |
- // erase any connections for which the corresponding socket has already been |
- // forgotten about as a result of all data having been sent. |
- for (it = connection_list_.begin(); it != connection_list_.end(); ) { |
- ConfigurableConnection* connection = it->get(); |
- if (connection->socket_ == NULL) { |
- connection_list_.erase(it++); |
- continue; |
- } |
- if (connection->socket_ == socket) |
- break; |
- ++it; |
- } |
- |
- return it; |
-} |
- |
-scoped_refptr<ConfigurableConnection> HTTPTestServer::ConnectionFromSocket( |
- const net::StreamListenSocket* socket) { |
- ConnectionList::iterator it = FindConnection(socket); |
- if (it != connection_list_.end()) |
- return *it; |
- return NULL; |
-} |
- |
-void HTTPTestServer::DidAccept(net::StreamListenSocket* server, |
- scoped_ptr<net::StreamListenSocket> socket) { |
- connection_list_.push_back(new ConfigurableConnection(socket.Pass())); |
-} |
- |
-void HTTPTestServer::DidRead(net::StreamListenSocket* socket, |
- const char* data, |
- int len) { |
- scoped_refptr<ConfigurableConnection> connection = |
- ConnectionFromSocket(socket); |
- if (connection) { |
- std::string str(data, len); |
- connection->r_.OnDataReceived(str); |
- if (connection->r_.AllContentReceived()) { |
- VLOG(1) << __FUNCTION__ << ": " << connection->r_.method() << " " |
- << connection->r_.path(); |
- std::wstring path = base::UTF8ToWide(connection->r_.path()); |
- if (LowerCaseEqualsASCII(connection->r_.method(), "post")) |
- this->Post(connection, path, connection->r_); |
- else |
- this->Get(connection, path, connection->r_); |
- } |
- } |
-} |
- |
-void HTTPTestServer::DidClose(net::StreamListenSocket* socket) { |
- ConnectionList::iterator it = FindConnection(socket); |
- if (it != connection_list_.end()) |
- connection_list_.erase(it); |
-} |
- |
-std::wstring HTTPTestServer::Resolve(const std::wstring& path) { |
- // Remove the first '/' if needed. |
- std::wstring stripped_path = path; |
- if (path.size() && path[0] == L'/') |
- stripped_path = path.substr(1); |
- |
- if (port_ == 80) { |
- if (stripped_path.empty()) { |
- return base::StringPrintf(L"http://%ls", address_.c_str()); |
- } else { |
- return base::StringPrintf(L"http://%ls/%ls", address_.c_str(), |
- stripped_path.c_str()); |
- } |
- } else { |
- if (stripped_path.empty()) { |
- return base::StringPrintf(L"http://%ls:%d", address_.c_str(), port_); |
- } else { |
- return base::StringPrintf(L"http://%ls:%d/%ls", address_.c_str(), port_, |
- stripped_path.c_str()); |
- } |
- } |
-} |
- |
-void ConfigurableConnection::SendChunk() { |
- int size = (int)data_.size(); |
- const char* chunk_ptr = data_.c_str() + cur_pos_; |
- int bytes_to_send = std::min(options_.chunk_size_, size - cur_pos_); |
- |
- socket_->Send(chunk_ptr, bytes_to_send); |
- VLOG(1) << "Sent(" << cur_pos_ << "," << bytes_to_send << "): " |
- << base::StringPiece(chunk_ptr, bytes_to_send); |
- |
- cur_pos_ += bytes_to_send; |
- if (cur_pos_ < size) { |
- base::MessageLoop::current()->PostDelayedTask( |
- FROM_HERE, base::Bind(&ConfigurableConnection::SendChunk, this), |
- base::TimeDelta::FromMilliseconds(options_.timeout_)); |
- } else { |
- Close(); |
- } |
-} |
- |
-void ConfigurableConnection::Close() { |
- socket_.reset(); |
-} |
- |
-void ConfigurableConnection::Send(const std::string& headers, |
- const std::string& content) { |
- SendOptions options(SendOptions::IMMEDIATE, 0, 0); |
- SendWithOptions(headers, content, options); |
-} |
- |
-void ConfigurableConnection::SendWithOptions(const std::string& headers, |
- const std::string& content, |
- const SendOptions& options) { |
- std::string content_length_header; |
- if (!content.empty() && |
- std::string::npos == headers.find("Context-Length:")) { |
- content_length_header = base::StringPrintf("Content-Length: %u\r\n", |
- content.size()); |
- } |
- |
- // Save the options. |
- options_ = options; |
- |
- if (options_.speed_ == SendOptions::IMMEDIATE) { |
- socket_->Send(headers); |
- socket_->Send(content_length_header, true); |
- socket_->Send(content); |
- // Post a task to close the socket since StreamListenSocket doesn't like |
- // instances to go away from within its callbacks. |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, base::Bind(&ConfigurableConnection::Close, this)); |
- |
- return; |
- } |
- |
- if (options_.speed_ == SendOptions::IMMEDIATE_HEADERS_DELAYED_CONTENT) { |
- socket_->Send(headers); |
- socket_->Send(content_length_header, true); |
- VLOG(1) << "Headers sent: " << headers << content_length_header; |
- data_.append(content); |
- } |
- |
- if (options_.speed_ == SendOptions::DELAYED) { |
- data_ = headers; |
- data_.append(content_length_header); |
- data_.append("\r\n"); |
- } |
- |
- base::MessageLoop::current()->PostDelayedTask( |
- FROM_HERE, base::Bind(&ConfigurableConnection::SendChunk, this), |
- base::TimeDelta::FromMilliseconds(options.timeout_)); |
-} |
- |
-} // namespace test_server |