15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_redirect_job.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <string> 85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h" 11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/logging.h" 129ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h" 135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/strings/stringprintf.h" 14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/base/load_timing_info.h" 155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "net/base/net_errors.h" 16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/base/net_log.h" 175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "net/http/http_response_headers.h" 185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "net/http/http_util.h" 19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/url_request/url_request.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)URLRequestRedirectJob::URLRequestRedirectJob(URLRequest* request, 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetworkDelegate* network_delegate, 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const GURL& redirect_destination, 265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ResponseCode response_code, 27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const std::string& redirect_reason) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : URLRequestJob(request, network_delegate), 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) redirect_destination_(redirect_destination), 305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) response_code_(response_code), 31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) redirect_reason_(redirect_reason), 32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) weak_factory_(this) { 33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(!redirect_reason_.empty()); 34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void URLRequestRedirectJob::GetResponseInfo(HttpResponseInfo* info) { 375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Should only be called after the URLRequest has been notified there's header 385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // information. 391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK(fake_headers_.get()); 405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // This assumes |info| is a freshly constructed HttpResponseInfo. 425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) info->headers = fake_headers_; 435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) info->request_time = response_time_; 445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) info->response_time = response_time_; 455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void URLRequestRedirectJob::GetLoadTimingInfo( 485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LoadTimingInfo* load_timing_info) const { 495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Set send_start and send_end to receive_headers_end_ to be consistent 505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // with network cache behavior. 515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) load_timing_info->send_start = receive_headers_end_; 525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) load_timing_info->send_end = receive_headers_end_; 535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) load_timing_info->receive_headers_end = receive_headers_end_; 545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLRequestRedirectJob::Start() { 57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) request()->net_log().AddEvent( 58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) NetLog::TYPE_URL_REQUEST_REDIRECT_JOB, 59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) NetLog::StringCallback("reason", &redirect_reason_)); 6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::MessageLoop::current()->PostTask( 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&URLRequestRedirectJob::StartAsync, 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_factory_.GetWeakPtr())); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 66c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool URLRequestRedirectJob::CopyFragmentOnRedirect(const GURL& location) const { 67c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // The instantiators have full control over the desired redirection target, 68c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // including the reference fragment part of the URL. 69c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return false; 70c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 71c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)int URLRequestRedirectJob::GetResponseCode() const { 735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Should only be called after the URLRequest has been notified there's header 745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // information. 751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK(fake_headers_.get()); 765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return response_code_; 775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)URLRequestRedirectJob::~URLRequestRedirectJob() {} 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLRequestRedirectJob::StartAsync() { 82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch receive_headers_end_ = base::TimeTicks::Now(); 835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) response_time_ = base::Time::Now(); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::string header_string = 865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::StringPrintf("HTTP/1.1 %i Internal Redirect\n" 875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "Location: %s\n" 885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "Non-Authoritative-Reason: %s", 895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) response_code_, 905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) redirect_destination_.spec().c_str(), 915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) redirect_reason_.c_str()); 921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci std::string http_origin; 941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const net::HttpRequestHeaders& request_headers = 951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci request_->extra_request_headers(); 961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (request_headers.GetHeader("Origin", &http_origin)) { 971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // If this redirect is used in a cross-origin request, add CORS headers to 981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // make sure that the redirect gets through. Note that the destination URL 991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // is still subject to the usual CORS policy, i.e. the resource will only 1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // be available to web pages if the server serves the response with the 1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // required CORS response headers. 1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci header_string += base::StringPrintf( 1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci "\n" 1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci "Access-Control-Allow-Origin: %s\n" 1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci "Access-Control-Allow-Credentials: true", 1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci http_origin.c_str()); 1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) fake_headers_ = new HttpResponseHeaders( 1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) HttpUtil::AssembleRawHeaders(header_string.c_str(), 1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) header_string.length())); 1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(fake_headers_->IsRedirect(NULL)); 1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) request()->net_log().AddEvent( 1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) NetLog::TYPE_URL_REQUEST_FAKE_RESPONSE_HEADERS_CREATED, 1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Bind( 1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) &HttpResponseHeaders::NetLogCallback, 1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Unretained(fake_headers_.get()))); 1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // TODO(mmenke): Consider calling the NetworkDelegate with the headers here. 1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // There's some weirdness about how to handle the case in which the delegate 1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // tries to modify the redirect location, in terms of how IsSafeRedirect 1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // should behave, and whether the fragment should be copied. 1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) URLRequestJob::NotifyHeadersComplete(); 125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 128