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

Side by Side Diff: chrome/common/resource_dispatcher.cc

Issue 3941001: Convert LOG(INFO) to VLOG(1) - chrome/common/. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 2 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/common/notification_service.cc ('k') | chrome/common/sandbox_policy.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 // See http://dev.chromium.org/developers/design-documents/multi-process-resourc e-loading 5 // See http://dev.chromium.org/developers/design-documents/multi-process-resourc e-loading
6 6
7 #include "chrome/common/resource_dispatcher.h" 7 #include "chrome/common/resource_dispatcher.h"
8 8
9 #include "base/basictypes.h" 9 #include "base/basictypes.h"
10 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
11 #include "base/file_path.h" 11 #include "base/file_path.h"
12 #include "base/message_loop.h" 12 #include "base/message_loop.h"
13 #include "base/shared_memory.h" 13 #include "base/shared_memory.h"
14 #include "base/string_util.h" 14 #include "base/string_util.h"
15 #include "chrome/common/extensions/extension_localization_peer.h" 15 #include "chrome/common/extensions/extension_localization_peer.h"
16 #include "chrome/common/render_messages.h" 16 #include "chrome/common/render_messages.h"
17 #include "chrome/common/render_messages_params.h" 17 #include "chrome/common/render_messages_params.h"
18 #include "chrome/common/resource_response.h" 18 #include "chrome/common/resource_response.h"
19 #include "chrome/common/security_filter_peer.h" 19 #include "chrome/common/security_filter_peer.h"
20 #include "net/base/net_errors.h" 20 #include "net/base/net_errors.h"
21 #include "net/base/net_util.h" 21 #include "net/base/net_util.h"
22 #include "net/base/upload_data.h" 22 #include "net/base/upload_data.h"
23 #include "net/http/http_response_headers.h" 23 #include "net/http/http_response_headers.h"
24 #include "webkit/glue/resource_type.h" 24 #include "webkit/glue/resource_type.h"
25 #include "webkit/glue/webkit_glue.h" 25 #include "webkit/glue/webkit_glue.h"
26 26
27 // Uncomment to enable logging of request traffic
28 // #define LOG_RESOURCE_REQUESTS
29
30 #ifdef LOG_RESOURCE_REQUESTS
31 # define RESOURCE_LOG(stuff) LOG(INFO) << stuff
32 #else
33 # define RESOURCE_LOG(stuff)
34 #endif
35
36 // Each resource request is assigned an ID scoped to this process. 27 // Each resource request is assigned an ID scoped to this process.
37 static int MakeRequestID() { 28 static int MakeRequestID() {
38 // NOTE: The resource_dispatcher_host also needs probably unique 29 // NOTE: The resource_dispatcher_host also needs probably unique
39 // request_ids, so they count down from -2 (-1 is a special we're 30 // request_ids, so they count down from -2 (-1 is a special we're
40 // screwed value), while the renderer process counts up. 31 // screwed value), while the renderer process counts up.
41 static int next_request_id = 0; 32 static int next_request_id = 0;
42 return next_request_id++; 33 return next_request_id++;
43 } 34 }
44 35
45 // ResourceLoaderBridge implementation ---------------------------------------- 36 // ResourceLoaderBridge implementation ----------------------------------------
(...skipping 15 matching lines...) Expand all
61 uint64 offset, 52 uint64 offset,
62 uint64 length, 53 uint64 length,
63 const base::Time& expected_modification_time); 54 const base::Time& expected_modification_time);
64 virtual void AppendBlobToUpload(const GURL& blob_url); 55 virtual void AppendBlobToUpload(const GURL& blob_url);
65 virtual void SetUploadIdentifier(int64 identifier); 56 virtual void SetUploadIdentifier(int64 identifier);
66 virtual bool Start(Peer* peer); 57 virtual bool Start(Peer* peer);
67 virtual void Cancel(); 58 virtual void Cancel();
68 virtual void SetDefersLoading(bool value); 59 virtual void SetDefersLoading(bool value);
69 virtual void SyncLoad(SyncLoadResponse* response); 60 virtual void SyncLoad(SyncLoadResponse* response);
70 61
71 #ifdef LOG_RESOURCE_REQUESTS
72 const std::string& url() const { return url_; }
73 #endif
74
75 private: 62 private:
76 ResourceLoaderBridge::Peer* peer_; 63 ResourceLoaderBridge::Peer* peer_;
77 64
78 // The resource dispatcher for this loader. The bridge doesn't own it, but 65 // The resource dispatcher for this loader. The bridge doesn't own it, but
79 // it's guaranteed to outlive the bridge. 66 // it's guaranteed to outlive the bridge.
80 ResourceDispatcher* dispatcher_; 67 ResourceDispatcher* dispatcher_;
81 68
82 // The request to send, created on initialization for modification and 69 // The request to send, created on initialization for modification and
83 // appending data. 70 // appending data.
84 ViewHostMsg_Resource_Request request_; 71 ViewHostMsg_Resource_Request request_;
85 72
86 // ID for the request, valid once Start()ed, -1 if not valid yet. 73 // ID for the request, valid once Start()ed, -1 if not valid yet.
87 int request_id_; 74 int request_id_;
88 75
89 // The routing id used when sending IPC messages. 76 // The routing id used when sending IPC messages.
90 int routing_id_; 77 int routing_id_;
91 78
92 #ifdef LOG_RESOURCE_REQUESTS
93 // indicates the URL of this resource request for help debugging
94 std::string url_;
95 #endif
96
97 // The following two members are specified if the request is initiated by 79 // The following two members are specified if the request is initiated by
98 // a plugin like Gears. 80 // a plugin like Gears.
99 81
100 // Contains the id of the host renderer. 82 // Contains the id of the host renderer.
101 int host_renderer_id_; 83 int host_renderer_id_;
102 84
103 // Contains the id of the host render view. 85 // Contains the id of the host render view.
104 int host_render_view_id_; 86 int host_render_view_id_;
105 }; 87 };
106 88
(...skipping 17 matching lines...) Expand all
124 request_.main_frame_origin = request_info.main_frame_origin; 106 request_.main_frame_origin = request_info.main_frame_origin;
125 request_.headers = request_info.headers; 107 request_.headers = request_info.headers;
126 request_.load_flags = request_info.load_flags; 108 request_.load_flags = request_info.load_flags;
127 request_.origin_child_id = request_info.requestor_pid; 109 request_.origin_child_id = request_info.requestor_pid;
128 request_.resource_type = request_info.request_type; 110 request_.resource_type = request_info.request_type;
129 request_.request_context = request_info.request_context; 111 request_.request_context = request_info.request_context;
130 request_.appcache_host_id = request_info.appcache_host_id; 112 request_.appcache_host_id = request_info.appcache_host_id;
131 request_.download_to_file = request_info.download_to_file; 113 request_.download_to_file = request_info.download_to_file;
132 request_.host_renderer_id = host_renderer_id_; 114 request_.host_renderer_id = host_renderer_id_;
133 request_.host_render_view_id = host_render_view_id_; 115 request_.host_render_view_id = host_render_view_id_;
134
135 #ifdef LOG_RESOURCE_REQUESTS
136 url_ = request_.url.possibly_invalid_spec();
137 #endif
138 } 116 }
139 117
140 IPCResourceLoaderBridge::~IPCResourceLoaderBridge() { 118 IPCResourceLoaderBridge::~IPCResourceLoaderBridge() {
141 // we remove our hook for the resource dispatcher only when going away, since 119 // we remove our hook for the resource dispatcher only when going away, since
142 // it doesn't keep track of whether we've force terminated the request 120 // it doesn't keep track of whether we've force terminated the request
143 if (request_id_ >= 0) { 121 if (request_id_ >= 0) {
144 // this operation may fail, as the dispatcher will have preemptively 122 // this operation may fail, as the dispatcher will have preemptively
145 // removed us when the renderer sends the ReceivedAllData message. 123 // removed us when the renderer sends the ReceivedAllData message.
146 dispatcher_->RemovePendingRequest(request_id_); 124 dispatcher_->RemovePendingRequest(request_id_);
147 125
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 request_.upload_data->set_identifier(identifier); 170 request_.upload_data->set_identifier(identifier);
193 } 171 }
194 172
195 // Writes a footer on the message and sends it 173 // Writes a footer on the message and sends it
196 bool IPCResourceLoaderBridge::Start(Peer* peer) { 174 bool IPCResourceLoaderBridge::Start(Peer* peer) {
197 if (request_id_ != -1) { 175 if (request_id_ != -1) {
198 NOTREACHED() << "Starting a request twice"; 176 NOTREACHED() << "Starting a request twice";
199 return false; 177 return false;
200 } 178 }
201 179
202 RESOURCE_LOG("Starting request for " << url_);
203
204 peer_ = peer; 180 peer_ = peer;
205 181
206 // generate the request ID, and append it to the message 182 // generate the request ID, and append it to the message
207 request_id_ = dispatcher_->AddPendingRequest( 183 request_id_ = dispatcher_->AddPendingRequest(
208 peer_, request_.resource_type, request_.url); 184 peer_, request_.resource_type, request_.url);
209 185
210 return dispatcher_->message_sender()->Send( 186 return dispatcher_->message_sender()->Send(
211 new ViewHostMsg_RequestResource(routing_id_, request_id_, request_)); 187 new ViewHostMsg_RequestResource(routing_id_, request_id_, request_));
212 } 188 }
213 189
214 void IPCResourceLoaderBridge::Cancel() { 190 void IPCResourceLoaderBridge::Cancel() {
215 if (request_id_ < 0) { 191 if (request_id_ < 0) {
216 NOTREACHED() << "Trying to cancel an unstarted request"; 192 NOTREACHED() << "Trying to cancel an unstarted request";
217 return; 193 return;
218 } 194 }
219 195
220 RESOURCE_LOG("Canceling request for " << url_);
221
222 dispatcher_->CancelPendingRequest(routing_id_, request_id_); 196 dispatcher_->CancelPendingRequest(routing_id_, request_id_);
223 197
224 // We can't remove the request ID from the resource dispatcher because more 198 // We can't remove the request ID from the resource dispatcher because more
225 // data might be pending. Sending the cancel message may cause more data 199 // data might be pending. Sending the cancel message may cause more data
226 // to be flushed, and will then cause a complete message to be sent. 200 // to be flushed, and will then cause a complete message to be sent.
227 } 201 }
228 202
229 void IPCResourceLoaderBridge::SetDefersLoading(bool value) { 203 void IPCResourceLoaderBridge::SetDefersLoading(bool value) {
230 if (request_id_ < 0) { 204 if (request_id_ < 0) {
231 NOTREACHED() << "Trying to (un)defer an unstarted request"; 205 NOTREACHED() << "Trying to (un)defer an unstarted request";
232 return; 206 return;
233 } 207 }
234 208
235 dispatcher_->SetDefersLoading(request_id_, value); 209 dispatcher_->SetDefersLoading(request_id_, value);
236 } 210 }
237 211
238 void IPCResourceLoaderBridge::SyncLoad(SyncLoadResponse* response) { 212 void IPCResourceLoaderBridge::SyncLoad(SyncLoadResponse* response) {
239 if (request_id_ != -1) { 213 if (request_id_ != -1) {
240 NOTREACHED() << "Starting a request twice"; 214 NOTREACHED() << "Starting a request twice";
241 response->status.set_status(URLRequestStatus::FAILED); 215 response->status.set_status(URLRequestStatus::FAILED);
242 return; 216 return;
243 } 217 }
244 218
245 RESOURCE_LOG("Making sync request for " << url_);
246
247 request_id_ = MakeRequestID(); 219 request_id_ = MakeRequestID();
248 220
249 SyncLoadResult result; 221 SyncLoadResult result;
250 IPC::SyncMessage* msg = new ViewHostMsg_SyncLoad(routing_id_, request_id_, 222 IPC::SyncMessage* msg = new ViewHostMsg_SyncLoad(routing_id_, request_id_,
251 request_, &result); 223 request_, &result);
252 // NOTE: This may pump events (see RenderThread::Send). 224 // NOTE: This may pump events (see RenderThread::Send).
253 if (!dispatcher_->message_sender()->Send(msg)) { 225 if (!dispatcher_->message_sender()->Send(msg)) {
254 response->status.set_status(URLRequestStatus::FAILED); 226 response->status.set_status(URLRequestStatus::FAILED);
255 return; 227 return;
256 } 228 }
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
336 } 308 }
337 return &(it->second); 309 return &(it->second);
338 } 310 }
339 311
340 void ResourceDispatcher::OnUploadProgress( 312 void ResourceDispatcher::OnUploadProgress(
341 const IPC::Message& message, int request_id, int64 position, int64 size) { 313 const IPC::Message& message, int request_id, int64 position, int64 size) {
342 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); 314 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
343 if (!request_info) 315 if (!request_info)
344 return; 316 return;
345 317
346 RESOURCE_LOG("Dispatching upload progress for " <<
347 request_info->peer->GetURLForDebugging().possibly_invalid_spec());
348 request_info->peer->OnUploadProgress(position, size); 318 request_info->peer->OnUploadProgress(position, size);
349 319
350 // Acknowledge receipt 320 // Acknowledge receipt
351 message_sender()->Send( 321 message_sender()->Send(
352 new ViewHostMsg_UploadProgress_ACK(message.routing_id(), request_id)); 322 new ViewHostMsg_UploadProgress_ACK(message.routing_id(), request_id));
353 } 323 }
354 324
355 void ResourceDispatcher::OnReceivedResponse( 325 void ResourceDispatcher::OnReceivedResponse(
356 int request_id, const ResourceResponseHead& response_head) { 326 int request_id, const ResourceResponseHead& response_head) {
357 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); 327 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
358 if (!request_info) 328 if (!request_info)
359 return; 329 return;
360 330
361 if (response_head.replace_extension_localization_templates) { 331 if (response_head.replace_extension_localization_templates) {
362 webkit_glue::ResourceLoaderBridge::Peer* new_peer = 332 webkit_glue::ResourceLoaderBridge::Peer* new_peer =
363 ExtensionLocalizationPeer::CreateExtensionLocalizationPeer( 333 ExtensionLocalizationPeer::CreateExtensionLocalizationPeer(
364 request_info->peer, message_sender(), response_head.mime_type, 334 request_info->peer, message_sender(), response_head.mime_type,
365 request_info->url); 335 request_info->url);
366 if (new_peer) 336 if (new_peer)
367 request_info->peer = new_peer; 337 request_info->peer = new_peer;
368 } 338 }
369 339
370 RESOURCE_LOG("Dispatching response for " <<
371 request_info->peer->GetURLForDebugging().possibly_invalid_spec());
372 request_info->peer->OnReceivedResponse(response_head, false); 340 request_info->peer->OnReceivedResponse(response_head, false);
373 } 341 }
374 342
375 void ResourceDispatcher::OnReceivedCachedMetadata( 343 void ResourceDispatcher::OnReceivedCachedMetadata(
376 int request_id, const std::vector<char>& data) { 344 int request_id, const std::vector<char>& data) {
377 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); 345 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
378 if (!request_info) 346 if (!request_info)
379 return; 347 return;
380 348
381 if (data.size()) { 349 if (data.size())
382 RESOURCE_LOG("Dispatching " << data.size() << " metadata bytes for " <<
383 request_info->peer->GetURLForDebugging().possibly_invalid_spec());
384 request_info->peer->OnReceivedCachedMetadata(&data.front(), data.size()); 350 request_info->peer->OnReceivedCachedMetadata(&data.front(), data.size());
385 }
386 } 351 }
387 352
388 void ResourceDispatcher::OnReceivedData(const IPC::Message& message, 353 void ResourceDispatcher::OnReceivedData(const IPC::Message& message,
389 int request_id, 354 int request_id,
390 base::SharedMemoryHandle shm_handle, 355 base::SharedMemoryHandle shm_handle,
391 int data_len) { 356 int data_len) {
392 // Acknowledge the reception of this data. 357 // Acknowledge the reception of this data.
393 message_sender()->Send( 358 message_sender()->Send(
394 new ViewHostMsg_DataReceived_ACK(message.routing_id(), request_id)); 359 new ViewHostMsg_DataReceived_ACK(message.routing_id(), request_id));
395 360
396 const bool shm_valid = base::SharedMemory::IsHandleValid(shm_handle); 361 const bool shm_valid = base::SharedMemory::IsHandleValid(shm_handle);
397 DCHECK((shm_valid && data_len > 0) || (!shm_valid && !data_len)); 362 DCHECK((shm_valid && data_len > 0) || (!shm_valid && !data_len));
398 base::SharedMemory shared_mem(shm_handle, true); // read only 363 base::SharedMemory shared_mem(shm_handle, true); // read only
399 364
400 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); 365 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
401 if (!request_info) 366 if (!request_info)
402 return; 367 return;
403 368
404 if (data_len > 0 && shared_mem.Map(data_len)) { 369 if (data_len > 0 && shared_mem.Map(data_len)) {
405 RESOURCE_LOG("Dispatching " << data_len << " bytes for " <<
406 request_info->peer->GetURLForDebugging().possibly_invalid_spec());
407 const char* data = static_cast<char*>(shared_mem.memory()); 370 const char* data = static_cast<char*>(shared_mem.memory());
408 request_info->peer->OnReceivedData(data, data_len); 371 request_info->peer->OnReceivedData(data, data_len);
409 } 372 }
410 } 373 }
411 374
412 void ResourceDispatcher::OnDownloadedData(const IPC::Message& message, 375 void ResourceDispatcher::OnDownloadedData(const IPC::Message& message,
413 int request_id, 376 int request_id,
414 int data_len) { 377 int data_len) {
415 // Acknowledge the reception of this message. 378 // Acknowledge the reception of this message.
416 message_sender()->Send( 379 message_sender()->Send(
417 new ViewHostMsg_DataDownloaded_ACK(message.routing_id(), request_id)); 380 new ViewHostMsg_DataDownloaded_ACK(message.routing_id(), request_id));
418 381
419 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); 382 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
420 if (!request_info) 383 if (!request_info)
421 return; 384 return;
422 385
423 RESOURCE_LOG("Dispatching " << data_len << " downloaded for " <<
424 request_info->peer->GetURLForDebugging().possibly_invalid_spec());
darin (slow to review) 2010/10/21 23:31:02 we can probably delete GetURLForDebugging() now.
425 request_info->peer->OnDownloadedData(data_len); 386 request_info->peer->OnDownloadedData(data_len);
426 } 387 }
427 388
428 void ResourceDispatcher::OnReceivedRedirect( 389 void ResourceDispatcher::OnReceivedRedirect(
429 const IPC::Message& message, 390 const IPC::Message& message,
430 int request_id, 391 int request_id,
431 const GURL& new_url, 392 const GURL& new_url,
432 const webkit_glue::ResourceResponseInfo& info) { 393 const webkit_glue::ResourceResponseInfo& info) {
433 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); 394 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
434 if (!request_info) 395 if (!request_info)
435 return; 396 return;
436 397
437 RESOURCE_LOG(
438 "Dispatching redirect for " <<
439 request_info->peer->GetURLForDebugging().possibly_invalid_spec());
440
441 bool has_new_first_party_for_cookies = false; 398 bool has_new_first_party_for_cookies = false;
442 GURL new_first_party_for_cookies; 399 GURL new_first_party_for_cookies;
443 if (request_info->peer->OnReceivedRedirect(new_url, info, 400 if (request_info->peer->OnReceivedRedirect(new_url, info,
444 &has_new_first_party_for_cookies, 401 &has_new_first_party_for_cookies,
445 &new_first_party_for_cookies)) { 402 &new_first_party_for_cookies)) {
446 message_sender()->Send( 403 message_sender()->Send(
447 new ViewHostMsg_FollowRedirect(message.routing_id(), request_id, 404 new ViewHostMsg_FollowRedirect(message.routing_id(), request_id,
448 has_new_first_party_for_cookies, 405 has_new_first_party_for_cookies,
449 new_first_party_for_cookies)); 406 new_first_party_for_cookies));
450 } else { 407 } else {
451 CancelPendingRequest(message.routing_id(), request_id); 408 CancelPendingRequest(message.routing_id(), request_id);
452 } 409 }
453 } 410 }
454 411
455 void ResourceDispatcher::OnRequestComplete(int request_id, 412 void ResourceDispatcher::OnRequestComplete(int request_id,
456 const URLRequestStatus& status, 413 const URLRequestStatus& status,
457 const std::string& security_info, 414 const std::string& security_info,
458 const base::Time& completion_time) { 415 const base::Time& completion_time) {
459 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); 416 PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
460 if (!request_info) 417 if (!request_info)
461 return; 418 return;
462 419
463 webkit_glue::ResourceLoaderBridge::Peer* peer = request_info->peer; 420 webkit_glue::ResourceLoaderBridge::Peer* peer = request_info->peer;
464 421
465 RESOURCE_LOG("Dispatching complete for " <<
466 peer->GetURLForDebugging().possibly_invalid_spec());
467
468 if (status.status() == URLRequestStatus::CANCELED && 422 if (status.status() == URLRequestStatus::CANCELED &&
469 status.os_error() != net::ERR_ABORTED) { 423 status.os_error() != net::ERR_ABORTED) {
470 // Resource canceled with a specific error are filtered. 424 // Resource canceled with a specific error are filtered.
471 SecurityFilterPeer* new_peer = 425 SecurityFilterPeer* new_peer =
472 SecurityFilterPeer::CreateSecurityFilterPeerForDeniedRequest( 426 SecurityFilterPeer::CreateSecurityFilterPeerForDeniedRequest(
473 request_info->resource_type, 427 request_info->resource_type,
474 request_info->peer, 428 request_info->peer,
475 status.os_error()); 429 status.os_error());
476 if (new_peer) { 430 if (new_peer) {
477 request_info->peer = new_peer; 431 request_info->peer = new_peer;
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
639 593
640 // static 594 // static
641 void ResourceDispatcher::ReleaseResourcesInMessageQueue(MessageQueue* queue) { 595 void ResourceDispatcher::ReleaseResourcesInMessageQueue(MessageQueue* queue) {
642 while (!queue->empty()) { 596 while (!queue->empty()) {
643 IPC::Message* message = queue->front(); 597 IPC::Message* message = queue->front();
644 ReleaseResourcesInDataMessage(*message); 598 ReleaseResourcesInDataMessage(*message);
645 queue->pop_front(); 599 queue->pop_front();
646 delete message; 600 delete message;
647 } 601 }
648 } 602 }
OLDNEW
« no previous file with comments | « chrome/common/notification_service.cc ('k') | chrome/common/sandbox_policy.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698