Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(243)

Side by Side Diff: chrome_frame/test/test_server.cc

Issue 218019: Initial import of the Chrome Frame codebase. Integration in chrome.gyp coming... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 11 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome_frame/test/test_server.h ('k') | chrome_frame/test/test_server_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/logging.h"
6 #include "base/registry.h"
7 #include "base/string_util.h"
8
9 #include "chrome_frame/test/test_server.h"
10
11 #include "net/base/winsock_init.h"
12 #include "net/http/http_util.h"
13
14 namespace test_server {
15 const char kDefaultHeaderTemplate[] =
16 "HTTP/1.1 %hs\r\n"
17 "Connection: close\r\n"
18 "Content-Type: %hs\r\n"
19 "Content-Length: %i\r\n\r\n";
20 const char kStatusOk[] = "200 OK";
21 const char kStatusNotFound[] = "404 Not Found";
22 const char kDefaultContentType[] = "text/html; charset=UTF-8";
23
24 void Request::ParseHeaders(const std::string& headers) {
25 size_t pos = headers.find("\r\n");
26 DCHECK(pos != std::string::npos);
27 if (pos != std::string::npos) {
28 headers_ = headers.substr(pos + 2);
29
30 StringTokenizer tokenizer(headers.begin(), headers.begin() + pos, " ");
31 std::string* parse[] = { &method_, &path_, &version_ };
32 int field = 0;
33 while (tokenizer.GetNext() && field < arraysize(parse)) {
34 parse[field++]->assign(tokenizer.token_begin(),
35 tokenizer.token_end());
36 }
37 }
38
39 // Check for content-length in case we're being sent some data.
40 net::HttpUtil::HeadersIterator it(headers_.begin(), headers_.end(),
41 "\r\n");
42 while (it.GetNext()) {
43 if (LowerCaseEqualsASCII(it.name(), "content-length")) {
44 content_length_ = StringToInt(it.values().c_str());
45 break;
46 }
47 }
48 }
49
50 bool Connection::CheckRequestReceived() {
51 bool ready = false;
52 if (request_.method().length()) {
53 // Headers have already been parsed. Just check content length.
54 ready = (data_.size() >= request_.content_length());
55 } else {
56 size_t index = data_.find("\r\n\r\n");
57 if (index != std::string::npos) {
58 // Parse the headers before returning and chop them of the
59 // data buffer we've already received.
60 std::string headers(data_.substr(0, index + 2));
61 request_.ParseHeaders(headers);
62 data_.erase(0, index + 4);
63 ready = (data_.size() >= request_.content_length());
64 }
65 }
66
67 return ready;
68 }
69
70 bool FileResponse::GetContentType(std::string* content_type) const {
71 size_t length = ContentLength();
72 char buffer[4096];
73 void* data = NULL;
74
75 if (length) {
76 // Create a copy of the first few bytes of the file.
77 // If we try and use the mapped file directly, FindMimeFromData will crash
78 // 'cause it cheats and temporarily tries to write to the buffer!
79 length = std::min(arraysize(buffer), length);
80 memcpy(buffer, file_->data(), length);
81 data = buffer;
82 }
83
84 LPOLESTR mime_type = NULL;
85 FindMimeFromData(NULL, file_path_.value().c_str(), data, length, NULL,
86 FMFD_DEFAULT, &mime_type, 0);
87 if (mime_type) {
88 *content_type = WideToASCII(mime_type);
89 ::CoTaskMemFree(mime_type);
90 }
91
92 return content_type->length() > 0;
93 }
94
95 void FileResponse::WriteContents(ListenSocket* socket) const {
96 DCHECK(file_.get());
97 if (file_.get()) {
98 socket->Send(reinterpret_cast<const char*>(file_->data()),
99 file_->length(), false);
100 }
101 }
102
103 size_t FileResponse::ContentLength() const {
104 if (file_.get() == NULL) {
105 file_.reset(new file_util::MemoryMappedFile());
106 if (!file_->Initialize(file_path_)) {
107 NOTREACHED();
108 file_.reset();
109 }
110 }
111 return file_.get() ? file_->length() : 0;
112 }
113
114 bool RedirectResponse::GetCustomHeaders(std::string* headers) const {
115 *headers = StringPrintf("HTTP/1.1 302 Found\r\n"
116 "Connection: close\r\n"
117 "Content-Length: 0\r\n"
118 "Content-Type: text/html\r\n"
119 "Location: %hs\r\n\r\n", redirect_url_.c_str());
120 return true;
121 }
122
123 SimpleWebServer::SimpleWebServer(int port) {
124 CHECK(MessageLoop::current()) << "SimpleWebServer requires a message loop";
125 net::EnsureWinsockInit();
126 AddResponse(&quit_);
127 server_ = ListenSocket::Listen("127.0.0.1", port, this);
128 DCHECK(server_.get() != NULL);
129 }
130
131 SimpleWebServer::~SimpleWebServer() {
132 ConnectionList::const_iterator it;
133 for (it = connections_.begin(); it != connections_.end(); it++)
134 delete (*it);
135 connections_.clear();
136 }
137
138 void SimpleWebServer::AddResponse(Response* response) {
139 responses_.push_back(response);
140 }
141
142 Response* SimpleWebServer::FindResponse(const Request& request) const {
143 std::list<Response*>::const_iterator it;
144 for (it = responses_.begin(); it != responses_.end(); it++) {
145 Response* response = (*it);
146 if (response->Matches(request)) {
147 return response;
148 }
149 }
150 return NULL;
151 }
152
153 Connection* SimpleWebServer::FindConnection(const ListenSocket* socket) const {
154 ConnectionList::const_iterator it;
155 for (it = connections_.begin(); it != connections_.end(); it++) {
156 if ((*it)->IsSame(socket)) {
157 return (*it);
158 }
159 }
160 return NULL;
161 }
162
163 void SimpleWebServer::DidAccept(ListenSocket* server,
164 ListenSocket* connection) {
165 connections_.push_back(new Connection(connection));
166 }
167
168 void SimpleWebServer::DidRead(ListenSocket* connection,
169 const std::string& data) {
170 Connection* c = FindConnection(connection);
171 DCHECK(c);
172 c->AddData(data);
173 if (c->CheckRequestReceived()) {
174 const Request& request = c->request();
175 Response* response = FindResponse(request);
176 if (response) {
177 std::string headers;
178 if (!response->GetCustomHeaders(&headers)) {
179 std::string content_type;
180 if (!response->GetContentType(&content_type))
181 content_type = kDefaultContentType;
182 headers = StringPrintf(kDefaultHeaderTemplate, kStatusOk,
183 content_type.c_str(), response->ContentLength());
184 }
185
186 connection->Send(headers, false);
187 response->WriteContents(connection);
188 response->IncrementAccessCounter();
189 } else {
190 std::string payload = "sorry, I can't find " + request.path();
191 std::string headers(StringPrintf(kDefaultHeaderTemplate, kStatusNotFound,
192 kDefaultContentType, payload.length()));
193 connection->Send(headers, false);
194 connection->Send(payload, false);
195 }
196 }
197 }
198
199 void SimpleWebServer::DidClose(ListenSocket* sock) {
200 // To keep the historical list of connections reasonably tidy, we delete
201 // 404's when the connection ends.
202 Connection* c = FindConnection(sock);
203 DCHECK(c);
204 if (!FindResponse(c->request())) {
205 // extremely inefficient, but in one line and not that common... :)
206 connections_.erase(std::find(connections_.begin(), connections_.end(), c));
207 delete c;
208 }
209 }
210
211 } // namespace test_server
OLDNEW
« no previous file with comments | « chrome_frame/test/test_server.h ('k') | chrome_frame/test/test_server_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698