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