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

Side by Side Diff: ios/web/public/test/http_server.mm

Issue 2898733003: Split up ios/web:test_support. (Closed)
Patch Set: don't break downstream clients Created 3 years, 6 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
« no previous file with comments | « ios/web/public/test/http_server.h ('k') | ios/web/public/test/http_server/BUILD.gn » ('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 2014 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 #import "ios/web/public/test/http_server.h"
6
7 #import <Foundation/Foundation.h>
8
9 #include <string>
10
11 #include "base/logging.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/sys_string_conversions.h"
15 #import "ios/third_party/gcdwebserver/src/GCDWebServer/Core/GCDWebServer.h"
16 #import "ios/third_party/gcdwebserver/src/GCDWebServer/Core/GCDWebServerResponse .h"
17 #import "ios/third_party/gcdwebserver/src/GCDWebServer/Requests/GCDWebServerData Request.h"
18 #import "net/base/mac/url_conversions.h"
19
20 #include "url/gurl.h"
21
22 namespace {
23
24 // The default port on which the GCDWebServer is brought up on.
25 const NSUInteger kDefaultPort = 8080;
26
27 // Converts a GCDWebServerDataRequest (received from the GCDWebServer servlet)
28 // to a request object that the ResponseProvider expects.
29 web::ResponseProvider::Request ResponseProviderRequestFromGCDWebServerRequest(
30 GCDWebServerDataRequest* request) {
31 GURL url(net::GURLWithNSURL(request.URL));
32 std::string method(base::SysNSStringToUTF8(request.method));
33 base::scoped_nsobject<NSString> body(
34 [[NSString alloc] initWithData:request.data
35 encoding:NSUTF8StringEncoding]);
36 __block net::HttpRequestHeaders headers;
37 [[request headers] enumerateKeysAndObjectsUsingBlock:^(NSString* header_key,
38 NSString* header_value,
39 BOOL*) {
40 headers.SetHeader(base::SysNSStringToUTF8(header_key),
41 base::SysNSStringToUTF8(header_value));
42 }];
43 return web::ResponseProvider::Request(url, method,
44 base::SysNSStringToUTF8(body), headers);
45 }
46
47 } // namespace
48
49 namespace web {
50 namespace test {
51
52 RefCountedResponseProviderWrapper::RefCountedResponseProviderWrapper(
53 std::unique_ptr<ResponseProvider> response_provider)
54 : response_provider_(std::move(response_provider)) {}
55
56 RefCountedResponseProviderWrapper::~RefCountedResponseProviderWrapper() {}
57
58 // static
59 HttpServer& HttpServer::GetSharedInstance() {
60 static web::test::HttpServer* shared_instance = nullptr;
61 static dispatch_once_t once;
62 dispatch_once(&once, ^{
63 shared_instance = new HttpServer();
64 });
65 return *shared_instance;
66 }
67
68 // static
69 HttpServer& HttpServer::GetSharedInstanceWithResponseProviders(
70 ProviderList response_providers) {
71 DCHECK([NSThread isMainThread]);
72 HttpServer& server = HttpServer::GetSharedInstance();
73 // Use non-const reference as the response_provider ownership is transfered.
74 for (std::unique_ptr<ResponseProvider>& provider : response_providers)
75 server.AddResponseProvider(std::move(provider));
76 return server;
77 }
78
79 void HttpServer::InitHttpServer() {
80 DCHECK(gcd_web_server_);
81 // Note: This block is called from an arbitrary GCD thread.
82 id process_request =
83 ^GCDWebServerResponse*(GCDWebServerDataRequest* request) {
84 // Relax the cross-thread access restriction to non-thread-safe RefCount.
85 // TODO(crbug.com/707010): Remove ScopedAllowCrossThreadRefCountAccess.
86 base::ScopedAllowCrossThreadRefCountAccess
87 allow_cross_thread_ref_count_access;
88
89 ResponseProvider::Request provider_request =
90 ResponseProviderRequestFromGCDWebServerRequest(request);
91 scoped_refptr<RefCountedResponseProviderWrapper>
92 ref_counted_response_provider = GetResponseProviderForRequest(
93 provider_request);
94
95 if (!ref_counted_response_provider) {
96 return [GCDWebServerResponse response];
97 }
98 ResponseProvider* response_provider =
99 ref_counted_response_provider->GetResponseProvider();
100 if (!response_provider) {
101 return [GCDWebServerResponse response];
102 }
103
104 return response_provider->GetGCDWebServerResponse(provider_request);
105 };
106 [gcd_web_server_ removeAllHandlers];
107 // Register a servlet for all HTTP GET, POST methods.
108 [gcd_web_server_ addDefaultHandlerForMethod:@"GET"
109 requestClass:[GCDWebServerDataRequest class]
110 processBlock:process_request];
111 [gcd_web_server_ addDefaultHandlerForMethod:@"POST"
112 requestClass:[GCDWebServerDataRequest class]
113 processBlock:process_request];
114 }
115
116 HttpServer::HttpServer() : port_(0) {
117 gcd_web_server_.reset([[GCDWebServer alloc] init]);
118 InitHttpServer();
119 }
120
121 HttpServer::~HttpServer() {
122 }
123
124 bool HttpServer::StartOnPort(NSUInteger port) {
125 DCHECK([NSThread isMainThread]);
126 DCHECK(!IsRunning()) << "The server is already running."
127 << " Please stop it before starting it again.";
128 BOOL success = [gcd_web_server_ startWithPort:port bonjourName:@""];
129 if (success) {
130 SetPort(port);
131 }
132 return success;
133 }
134
135 void HttpServer::StartOrDie() {
136 DCHECK([NSThread isMainThread]);
137 StartOnPort(kDefaultPort);
138 CHECK(IsRunning());
139 }
140
141 void HttpServer::Stop() {
142 DCHECK([NSThread isMainThread]);
143 DCHECK(IsRunning()) << "Cannot stop an already stopped server.";
144 RemoveAllResponseProviders();
145 [gcd_web_server_ stop];
146 SetPort(0);
147 }
148
149 bool HttpServer::IsRunning() const {
150 DCHECK([NSThread isMainThread]);
151 return [gcd_web_server_ isRunning];
152 }
153
154 NSUInteger HttpServer::GetPort() const {
155 base::AutoLock autolock(port_lock_);
156 return port_;
157 }
158
159 // static
160 GURL HttpServer::MakeUrl(const std::string &url) {
161 return HttpServer::GetSharedInstance().MakeUrlForHttpServer(url);
162 }
163
164 GURL HttpServer::MakeUrlForHttpServer(const std::string& url) const {
165 GURL result(url);
166 DCHECK(result.is_valid());
167 const std::string kLocalhostHost = std::string("localhost");
168 if (result.port() == base::IntToString(GetPort()) &&
169 result.host() == kLocalhostHost) {
170 return result;
171 }
172
173 GURL::Replacements replacements;
174 replacements.SetHostStr(kLocalhostHost);
175
176 const std::string port = std::string(
177 base::IntToString(static_cast<int>(GetPort())));
178 replacements.SetPortStr(port);
179
180 // It is necessary to prepend the host of the input URL so that URLs such
181 // as http://origin/foo, http://destination/foo can be disamgiguated.
182 const std::string new_path = std::string(result.host() + result.path());
183 replacements.SetPathStr(new_path);
184
185 return result.ReplaceComponents(replacements);
186 }
187
188 scoped_refptr<RefCountedResponseProviderWrapper>
189 HttpServer::GetResponseProviderForRequest(
190 const web::ResponseProvider::Request& request) {
191 base::AutoLock autolock(provider_list_lock_);
192 // Relax the cross-thread access restriction to non-thread-safe RefCount.
193 // The lock above protects non-thread-safe RefCount in HTTPServer.
194 base::ScopedAllowCrossThreadRefCountAccess
195 allow_cross_thread_ref_count_access;
196 scoped_refptr<RefCountedResponseProviderWrapper> result;
197 for (const auto& ref_counted_response_provider : providers_) {
198 ResponseProvider* response_provider =
199 ref_counted_response_provider.get()->GetResponseProvider();
200 if (response_provider->CanHandleRequest(request)) {
201 DCHECK(!result) <<
202 "No more than one response provider can handle the same request.";
203 result = ref_counted_response_provider;
204 }
205 }
206 return result;
207 }
208
209 void HttpServer::AddResponseProvider(
210 std::unique_ptr<ResponseProvider> response_provider) {
211 DCHECK([NSThread isMainThread]);
212 DCHECK(IsRunning()) << "Can add a response provider only when the server is "
213 << "running.";
214 base::AutoLock autolock(provider_list_lock_);
215 // Relax the cross-thread access restriction to non-thread-safe RefCount.
216 // The lock above protects non-thread-safe RefCount in HTTPServer.
217 base::ScopedAllowCrossThreadRefCountAccess
218 allow_cross_thread_ref_count_access;
219 scoped_refptr<RefCountedResponseProviderWrapper>
220 ref_counted_response_provider(
221 new RefCountedResponseProviderWrapper(std::move(response_provider)));
222 providers_.push_back(ref_counted_response_provider);
223 }
224
225 void HttpServer::RemoveResponseProvider(ResponseProvider* response_provider) {
226 DCHECK([NSThread isMainThread]);
227 base::AutoLock autolock(provider_list_lock_);
228 // Relax the cross-thread access restriction to non-thread-safe RefCount.
229 // The lock above protects non-thread-safe RefCount in HTTPServer.
230 base::ScopedAllowCrossThreadRefCountAccess
231 allow_cross_thread_ref_count_access;
232 auto found_iter = providers_.end();
233 for (auto it = providers_.begin(); it != providers_.end(); ++it) {
234 if ((*it)->GetResponseProvider() == response_provider) {
235 found_iter = it;
236 break;
237 }
238 }
239 if (found_iter != providers_.end()) {
240 providers_.erase(found_iter);
241 }
242 }
243
244 void HttpServer::RemoveAllResponseProviders() {
245 DCHECK([NSThread isMainThread]);
246 base::AutoLock autolock(provider_list_lock_);
247 // Relax the cross-thread access restriction to non-thread-safe RefCount.
248 // The lock above protects non-thread-safe RefCount in HTTPServer.
249 base::ScopedAllowCrossThreadRefCountAccess
250 allow_cross_thread_ref_count_access;
251 providers_.clear();
252 }
253
254 void HttpServer::SetPort(NSUInteger port) {
255 base::AutoLock autolock(port_lock_);
256 port_ = port;
257 }
258
259 } // namespace test
260 } // namespace web
OLDNEW
« no previous file with comments | « ios/web/public/test/http_server.h ('k') | ios/web/public/test/http_server/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698