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

Side by Side Diff: content/renderer/service_worker/service_worker_context_client.cc

Issue 2596173002: Use explicit WebString <-> string conversion methods for workers (Closed)
Patch Set: Created 4 years 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
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 #include "content/renderer/service_worker/service_worker_context_client.h" 5 #include "content/renderer/service_worker/service_worker_context_client.h"
6 6
7 #include <memory> 7 #include <memory>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/lazy_instance.h" 10 #include "base/lazy_instance.h"
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 RequestContextFrameType frame_type) { 148 RequestContextFrameType frame_type) {
149 return static_cast<blink::WebURLRequest::FrameType>(frame_type); 149 return static_cast<blink::WebURLRequest::FrameType>(frame_type);
150 } 150 }
151 151
152 blink::WebServiceWorkerClientInfo 152 blink::WebServiceWorkerClientInfo
153 ToWebServiceWorkerClientInfo(const ServiceWorkerClientInfo& client_info) { 153 ToWebServiceWorkerClientInfo(const ServiceWorkerClientInfo& client_info) {
154 DCHECK(client_info.IsValid()); 154 DCHECK(client_info.IsValid());
155 155
156 blink::WebServiceWorkerClientInfo web_client_info; 156 blink::WebServiceWorkerClientInfo web_client_info;
157 157
158 web_client_info.uuid = base::UTF8ToUTF16(client_info.client_uuid); 158 web_client_info.uuid = blink::WebString::fromASCII(client_info.client_uuid);
159 web_client_info.pageVisibilityState = client_info.page_visibility_state; 159 web_client_info.pageVisibilityState = client_info.page_visibility_state;
160 web_client_info.isFocused = client_info.is_focused; 160 web_client_info.isFocused = client_info.is_focused;
161 web_client_info.url = client_info.url; 161 web_client_info.url = client_info.url;
162 web_client_info.frameType = GetBlinkFrameType(client_info.frame_type); 162 web_client_info.frameType = GetBlinkFrameType(client_info.frame_type);
163 web_client_info.clientType = client_info.client_type; 163 web_client_info.clientType = client_info.client_type;
164 164
165 return web_client_info; 165 return web_client_info;
166 } 166 }
167 167
168 // Use this template in willDestroyWorkerContext to abort all the pending 168 // Use this template in willDestroyWorkerContext to abort all the pending
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 if (result_reported_) 254 if (result_reported_)
255 return; 255 return;
256 ServiceWorkerContextClient* client = 256 ServiceWorkerContextClient* client =
257 ServiceWorkerContextClient::ThreadSpecificInstance(); 257 ServiceWorkerContextClient::ThreadSpecificInstance();
258 if (!client) 258 if (!client)
259 return; 259 return;
260 client->OnNavigationPreloadError( 260 client->OnNavigationPreloadError(
261 fetch_event_id_, 261 fetch_event_id_,
262 base::MakeUnique<blink::WebServiceWorkerError>( 262 base::MakeUnique<blink::WebServiceWorkerError>(
263 blink::WebServiceWorkerError::ErrorTypeAbort, 263 blink::WebServiceWorkerError::ErrorTypeAbort,
264 blink::WebString::fromUTF8( 264 blink::WebString::fromASCII(
265 "Service Worker navigation preload aborted. Need to guard with " 265 "Service Worker navigation preload aborted. Need to guard with "
266 "respondWith or waitUntil."))); 266 "respondWith or waitUntil.")));
267 } 267 }
268 268
269 void OnReceiveResponse( 269 void OnReceiveResponse(
270 const ResourceResponseHead& response_head, 270 const ResourceResponseHead& response_head,
271 mojom::DownloadedTempFilePtr downloaded_file) override { 271 mojom::DownloadedTempFilePtr downloaded_file) override {
272 DCHECK(!response_); 272 DCHECK(!response_);
273 DCHECK(!downloaded_file); 273 DCHECK(!downloaded_file);
274 response_ = base::MakeUnique<blink::WebServiceWorkerResponse>(); 274 response_ = base::MakeUnique<blink::WebServiceWorkerResponse>();
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
447 447
448 blink::WebURL ServiceWorkerContextClient::scope() const { 448 blink::WebURL ServiceWorkerContextClient::scope() const {
449 return service_worker_scope_; 449 return service_worker_scope_;
450 } 450 }
451 451
452 void ServiceWorkerContextClient::getClient( 452 void ServiceWorkerContextClient::getClient(
453 const blink::WebString& id, 453 const blink::WebString& id,
454 std::unique_ptr<blink::WebServiceWorkerClientCallbacks> callbacks) { 454 std::unique_ptr<blink::WebServiceWorkerClientCallbacks> callbacks) {
455 DCHECK(callbacks); 455 DCHECK(callbacks);
456 int request_id = context_->client_callbacks.Add(std::move(callbacks)); 456 int request_id = context_->client_callbacks.Add(std::move(callbacks));
457 Send(new ServiceWorkerHostMsg_GetClient( 457 Send(new ServiceWorkerHostMsg_GetClient(GetRoutingID(), request_id,
458 GetRoutingID(), request_id, base::UTF16ToUTF8(base::StringPiece16(id)))); 458 id.utf8()));
kinuko 2016/12/22 08:23:44 These ids should be ascii-only, but since it's giv
459 } 459 }
460 460
461 void ServiceWorkerContextClient::getClients( 461 void ServiceWorkerContextClient::getClients(
462 const blink::WebServiceWorkerClientQueryOptions& weboptions, 462 const blink::WebServiceWorkerClientQueryOptions& weboptions,
463 std::unique_ptr<blink::WebServiceWorkerClientsCallbacks> callbacks) { 463 std::unique_ptr<blink::WebServiceWorkerClientsCallbacks> callbacks) {
464 DCHECK(callbacks); 464 DCHECK(callbacks);
465 int request_id = context_->clients_callbacks.Add(std::move(callbacks)); 465 int request_id = context_->clients_callbacks.Add(std::move(callbacks));
466 ServiceWorkerClientQueryOptions options; 466 ServiceWorkerClientQueryOptions options;
467 options.client_type = weboptions.clientType; 467 options.client_type = weboptions.clientType;
468 options.include_uncontrolled = weboptions.includeUncontrolled; 468 options.include_uncontrolled = weboptions.includeUncontrolled;
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
623 base::Bind(&CallWorkerContextDestroyedOnMainThread, 623 base::Bind(&CallWorkerContextDestroyedOnMainThread,
624 embedded_worker_id_)); 624 embedded_worker_id_));
625 } 625 }
626 626
627 void ServiceWorkerContextClient::reportException( 627 void ServiceWorkerContextClient::reportException(
628 const blink::WebString& error_message, 628 const blink::WebString& error_message,
629 int line_number, 629 int line_number,
630 int column_number, 630 int column_number,
631 const blink::WebString& source_url) { 631 const blink::WebString& source_url) {
632 Send(new EmbeddedWorkerHostMsg_ReportException( 632 Send(new EmbeddedWorkerHostMsg_ReportException(
633 embedded_worker_id_, error_message, line_number, column_number, 633 embedded_worker_id_, error_message.utf16(), line_number, column_number,
634 blink::WebStringToGURL(source_url))); 634 blink::WebStringToGURL(source_url)));
635 } 635 }
636 636
637 void ServiceWorkerContextClient::reportConsoleMessage( 637 void ServiceWorkerContextClient::reportConsoleMessage(
638 int source, 638 int source,
639 int level, 639 int level,
640 const blink::WebString& message, 640 const blink::WebString& message,
641 int line_number, 641 int line_number,
642 const blink::WebString& source_url) { 642 const blink::WebString& source_url) {
643 EmbeddedWorkerHostMsg_ReportConsoleMessage_Params params; 643 EmbeddedWorkerHostMsg_ReportConsoleMessage_Params params;
644 params.source_identifier = source; 644 params.source_identifier = source;
645 params.message_level = level; 645 params.message_level = level;
646 params.message = message; 646 params.message = message.utf16();
647 params.line_number = line_number; 647 params.line_number = line_number;
648 params.source_url = blink::WebStringToGURL(source_url); 648 params.source_url = blink::WebStringToGURL(source_url);
649 649
650 Send(new EmbeddedWorkerHostMsg_ReportConsoleMessage( 650 Send(new EmbeddedWorkerHostMsg_ReportConsoleMessage(
651 embedded_worker_id_, params)); 651 embedded_worker_id_, params));
652 } 652 }
653 653
654 void ServiceWorkerContextClient::sendDevToolsMessage( 654 void ServiceWorkerContextClient::sendDevToolsMessage(
655 int session_id, 655 int session_id,
656 int call_id, 656 int call_id,
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
834 void ServiceWorkerContextClient::postMessageToClient( 834 void ServiceWorkerContextClient::postMessageToClient(
835 const blink::WebString& uuid, 835 const blink::WebString& uuid,
836 const blink::WebString& message, 836 const blink::WebString& message,
837 blink::WebMessagePortChannelArray* channels) { 837 blink::WebMessagePortChannelArray* channels) {
838 // This may send channels for MessagePorts, and all internal book-keeping 838 // This may send channels for MessagePorts, and all internal book-keeping
839 // messages for MessagePort (e.g. QueueMessages) are sent from main thread 839 // messages for MessagePort (e.g. QueueMessages) are sent from main thread
840 // (with thread hopping), so we need to do the same thread hopping here not 840 // (with thread hopping), so we need to do the same thread hopping here not
841 // to overtake those messages. 841 // to overtake those messages.
842 std::unique_ptr<blink::WebMessagePortChannelArray> channel_array(channels); 842 std::unique_ptr<blink::WebMessagePortChannelArray> channel_array(channels);
843 main_thread_task_runner_->PostTask( 843 main_thread_task_runner_->PostTask(
844 FROM_HERE, base::Bind(&SendPostMessageToClientOnMainThread, 844 FROM_HERE,
845 base::RetainedRef(sender_), GetRoutingID(), 845 base::Bind(&SendPostMessageToClientOnMainThread,
846 base::UTF16ToUTF8(base::StringPiece16(uuid)), 846 base::RetainedRef(sender_), GetRoutingID(), uuid.utf8(),
847 static_cast<base::string16>(message), 847 message.utf16(), base::Passed(&channel_array)));
848 base::Passed(&channel_array)));
849 } 848 }
850 849
851 void ServiceWorkerContextClient::focus( 850 void ServiceWorkerContextClient::focus(
852 const blink::WebString& uuid, 851 const blink::WebString& uuid,
853 std::unique_ptr<blink::WebServiceWorkerClientCallbacks> callback) { 852 std::unique_ptr<blink::WebServiceWorkerClientCallbacks> callback) {
854 DCHECK(callback); 853 DCHECK(callback);
855 int request_id = context_->client_callbacks.Add(std::move(callback)); 854 int request_id = context_->client_callbacks.Add(std::move(callback));
856 Send(new ServiceWorkerHostMsg_FocusClient( 855 Send(new ServiceWorkerHostMsg_FocusClient(GetRoutingID(), request_id,
857 GetRoutingID(), request_id, 856 uuid.utf8()));
858 base::UTF16ToUTF8(base::StringPiece16(uuid))));
859 } 857 }
860 858
861 void ServiceWorkerContextClient::navigate( 859 void ServiceWorkerContextClient::navigate(
862 const blink::WebString& uuid, 860 const blink::WebString& uuid,
863 const blink::WebURL& url, 861 const blink::WebURL& url,
864 std::unique_ptr<blink::WebServiceWorkerClientCallbacks> callback) { 862 std::unique_ptr<blink::WebServiceWorkerClientCallbacks> callback) {
865 DCHECK(callback); 863 DCHECK(callback);
866 int request_id = context_->client_callbacks.Add(std::move(callback)); 864 int request_id = context_->client_callbacks.Add(std::move(callback));
867 Send(new ServiceWorkerHostMsg_NavigateClient( 865 Send(new ServiceWorkerHostMsg_NavigateClient(GetRoutingID(), request_id,
868 GetRoutingID(), request_id, base::UTF16ToUTF8(base::StringPiece16(uuid)), 866 uuid.utf8(), url));
869 url));
870 } 867 }
871 868
872 void ServiceWorkerContextClient::skipWaiting( 869 void ServiceWorkerContextClient::skipWaiting(
873 std::unique_ptr<blink::WebServiceWorkerSkipWaitingCallbacks> callbacks) { 870 std::unique_ptr<blink::WebServiceWorkerSkipWaitingCallbacks> callbacks) {
874 DCHECK(callbacks); 871 DCHECK(callbacks);
875 int request_id = context_->skip_waiting_callbacks.Add(std::move(callbacks)); 872 int request_id = context_->skip_waiting_callbacks.Add(std::move(callbacks));
876 Send(new ServiceWorkerHostMsg_SkipWaiting(GetRoutingID(), request_id)); 873 Send(new ServiceWorkerHostMsg_SkipWaiting(GetRoutingID(), request_id));
877 } 874 }
878 875
879 void ServiceWorkerContextClient::claim( 876 void ServiceWorkerContextClient::claim(
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
955 base::MakeUnique<DispatchExtendableMessageEventCallback>(callback)); 952 base::MakeUnique<DispatchExtendableMessageEventCallback>(callback));
956 953
957 blink::WebMessagePortChannelArray ports = 954 blink::WebMessagePortChannelArray ports =
958 WebMessagePortChannelImpl::CreatePorts(event->message_ports, 955 WebMessagePortChannelImpl::CreatePorts(event->message_ports,
959 event->new_routing_ids, 956 event->new_routing_ids,
960 main_thread_task_runner_); 957 main_thread_task_runner_);
961 if (event->source.client_info.IsValid()) { 958 if (event->source.client_info.IsValid()) {
962 blink::WebServiceWorkerClientInfo web_client = 959 blink::WebServiceWorkerClientInfo web_client =
963 ToWebServiceWorkerClientInfo(event->source.client_info); 960 ToWebServiceWorkerClientInfo(event->source.client_info);
964 proxy_->dispatchExtendableMessageEvent( 961 proxy_->dispatchExtendableMessageEvent(
965 request_id, event->message, event->source_origin, ports, web_client); 962 request_id, blink::WebString::fromUTF16(event->message),
963 event->source_origin, ports, web_client);
966 return; 964 return;
967 } 965 }
968 966
969 DCHECK(event->source.service_worker_info.IsValid()); 967 DCHECK(event->source.service_worker_info.IsValid());
970 std::unique_ptr<ServiceWorkerHandleReference> handle = 968 std::unique_ptr<ServiceWorkerHandleReference> handle =
971 ServiceWorkerHandleReference::Adopt(event->source.service_worker_info, 969 ServiceWorkerHandleReference::Adopt(event->source.service_worker_info,
972 sender_.get()); 970 sender_.get());
973 ServiceWorkerDispatcher* dispatcher = 971 ServiceWorkerDispatcher* dispatcher =
974 ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance( 972 ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance(
975 sender_.get(), main_thread_task_runner_.get()); 973 sender_.get(), main_thread_task_runner_.get());
976 scoped_refptr<WebServiceWorkerImpl> worker = 974 scoped_refptr<WebServiceWorkerImpl> worker =
977 dispatcher->GetOrCreateServiceWorker(std::move(handle)); 975 dispatcher->GetOrCreateServiceWorker(std::move(handle));
978 proxy_->dispatchExtendableMessageEvent( 976 proxy_->dispatchExtendableMessageEvent(
979 request_id, event->message, event->source_origin, ports, 977 request_id, blink::WebString::fromUTF16(event->message),
980 WebServiceWorkerImpl::CreateHandle(worker)); 978 event->source_origin, ports, WebServiceWorkerImpl::CreateHandle(worker));
981 } 979 }
982 980
983 void ServiceWorkerContextClient::OnInstallEvent(int request_id) { 981 void ServiceWorkerContextClient::OnInstallEvent(int request_id) {
984 TRACE_EVENT0("ServiceWorker", 982 TRACE_EVENT0("ServiceWorker",
985 "ServiceWorkerContextClient::OnInstallEvent"); 983 "ServiceWorkerContextClient::OnInstallEvent");
986 proxy_->dispatchInstallEvent(request_id); 984 proxy_->dispatchInstallEvent(request_id);
987 } 985 }
988 986
989 void ServiceWorkerContextClient::DispatchFetchEvent( 987 void ServiceWorkerContextClient::DispatchFetchEvent(
990 int fetch_event_id, 988 int fetch_event_id,
(...skipping 18 matching lines...) Expand all
1009 1007
1010 webRequest.setURL(blink::WebURL(request.url)); 1008 webRequest.setURL(blink::WebURL(request.url));
1011 webRequest.setMethod(blink::WebString::fromUTF8(request.method)); 1009 webRequest.setMethod(blink::WebString::fromUTF8(request.method));
1012 for (ServiceWorkerHeaderMap::const_iterator it = request.headers.begin(); 1010 for (ServiceWorkerHeaderMap::const_iterator it = request.headers.begin();
1013 it != request.headers.end(); 1011 it != request.headers.end();
1014 ++it) { 1012 ++it) {
1015 webRequest.setHeader(blink::WebString::fromUTF8(it->first), 1013 webRequest.setHeader(blink::WebString::fromUTF8(it->first),
1016 blink::WebString::fromUTF8(it->second)); 1014 blink::WebString::fromUTF8(it->second));
1017 } 1015 }
1018 if (!request.blob_uuid.empty()) { 1016 if (!request.blob_uuid.empty()) {
1019 webRequest.setBlob(blink::WebString::fromUTF8(request.blob_uuid), 1017 webRequest.setBlob(blink::WebString::fromASCII(request.blob_uuid),
1020 request.blob_size); 1018 request.blob_size);
1021 } 1019 }
1022 webRequest.setReferrer( 1020 webRequest.setReferrer(
1023 blink::WebString::fromUTF8(request.referrer.url.spec()), 1021 blink::WebString::fromUTF8(request.referrer.url.spec()),
1024 request.referrer.policy); 1022 request.referrer.policy);
1025 webRequest.setMode(GetBlinkFetchRequestMode(request.mode)); 1023 webRequest.setMode(GetBlinkFetchRequestMode(request.mode));
1026 webRequest.setIsMainResourceLoad(request.is_main_resource_load); 1024 webRequest.setIsMainResourceLoad(request.is_main_resource_load);
1027 webRequest.setCredentialsMode( 1025 webRequest.setCredentialsMode(
1028 GetBlinkFetchCredentialsMode(request.credentials_mode)); 1026 GetBlinkFetchCredentialsMode(request.credentials_mode));
1029 webRequest.setRedirectMode(GetBlinkFetchRedirectMode(request.redirect_mode)); 1027 webRequest.setRedirectMode(GetBlinkFetchRedirectMode(request.redirect_mode));
(...skipping 14 matching lines...) Expand all
1044 int request_id, 1042 int request_id,
1045 const std::string& notification_id, 1043 const std::string& notification_id,
1046 const PlatformNotificationData& notification_data, 1044 const PlatformNotificationData& notification_data,
1047 int action_index, 1045 int action_index,
1048 const base::NullableString16& reply) { 1046 const base::NullableString16& reply) {
1049 TRACE_EVENT0("ServiceWorker", 1047 TRACE_EVENT0("ServiceWorker",
1050 "ServiceWorkerContextClient::OnNotificationClickEvent"); 1048 "ServiceWorkerContextClient::OnNotificationClickEvent");
1051 proxy_->dispatchNotificationClickEvent( 1049 proxy_->dispatchNotificationClickEvent(
1052 request_id, blink::WebString::fromUTF8(notification_id), 1050 request_id, blink::WebString::fromUTF8(notification_id),
1053 ToWebNotificationData(notification_data), action_index, 1051 ToWebNotificationData(notification_data), action_index,
1054 blink::WebString(reply)); 1052 blink::WebString::fromUTF16(reply));
1055 } 1053 }
1056 1054
1057 void ServiceWorkerContextClient::OnNotificationCloseEvent( 1055 void ServiceWorkerContextClient::OnNotificationCloseEvent(
1058 int request_id, 1056 int request_id,
1059 const std::string& notification_id, 1057 const std::string& notification_id,
1060 const PlatformNotificationData& notification_data) { 1058 const PlatformNotificationData& notification_data) {
1061 TRACE_EVENT0("ServiceWorker", 1059 TRACE_EVENT0("ServiceWorker",
1062 "ServiceWorkerContextClient::OnNotificationCloseEvent"); 1060 "ServiceWorkerContextClient::OnNotificationCloseEvent");
1063 proxy_->dispatchNotificationCloseEvent( 1061 proxy_->dispatchNotificationCloseEvent(
1064 request_id, blink::WebString::fromUTF8(notification_id), 1062 request_id, blink::WebString::fromUTF8(notification_id),
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
1252 blink::WebServiceWorkerError::ErrorType error_type, 1250 blink::WebServiceWorkerError::ErrorType error_type,
1253 const base::string16& message) { 1251 const base::string16& message) {
1254 TRACE_EVENT0("ServiceWorker", 1252 TRACE_EVENT0("ServiceWorker",
1255 "ServiceWorkerContextClient::OnClaimClientsError"); 1253 "ServiceWorkerContextClient::OnClaimClientsError");
1256 blink::WebServiceWorkerClientsClaimCallbacks* callbacks = 1254 blink::WebServiceWorkerClientsClaimCallbacks* callbacks =
1257 context_->claim_clients_callbacks.Lookup(request_id); 1255 context_->claim_clients_callbacks.Lookup(request_id);
1258 if (!callbacks) { 1256 if (!callbacks) {
1259 NOTREACHED() << "Got stray response: " << request_id; 1257 NOTREACHED() << "Got stray response: " << request_id;
1260 return; 1258 return;
1261 } 1259 }
1262 callbacks->onError(blink::WebServiceWorkerError(error_type, message)); 1260 callbacks->onError(blink::WebServiceWorkerError(
1261 error_type, blink::WebString::fromUTF16(message)));
1263 context_->claim_clients_callbacks.Remove(request_id); 1262 context_->claim_clients_callbacks.Remove(request_id);
1264 } 1263 }
1265 1264
1266 void ServiceWorkerContextClient::OnPing() { 1265 void ServiceWorkerContextClient::OnPing() {
1267 Send(new ServiceWorkerHostMsg_Pong(GetRoutingID())); 1266 Send(new ServiceWorkerHostMsg_Pong(GetRoutingID()));
1268 } 1267 }
1269 1268
1270 void ServiceWorkerContextClient::OnNavigationPreloadResponse( 1269 void ServiceWorkerContextClient::OnNavigationPreloadResponse(
1271 int fetch_event_id, 1270 int fetch_event_id,
1272 std::unique_ptr<blink::WebServiceWorkerResponse> response, 1271 std::unique_ptr<blink::WebServiceWorkerResponse> response,
(...skipping 16 matching lines...) Expand all
1289 } 1288 }
1290 1289
1291 base::WeakPtr<ServiceWorkerContextClient> 1290 base::WeakPtr<ServiceWorkerContextClient>
1292 ServiceWorkerContextClient::GetWeakPtr() { 1291 ServiceWorkerContextClient::GetWeakPtr() {
1293 DCHECK(worker_task_runner_->RunsTasksOnCurrentThread()); 1292 DCHECK(worker_task_runner_->RunsTasksOnCurrentThread());
1294 DCHECK(context_); 1293 DCHECK(context_);
1295 return context_->weak_factory.GetWeakPtr(); 1294 return context_->weak_factory.GetWeakPtr();
1296 } 1295 }
1297 1296
1298 } // namespace content 1297 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698