1 // Copyright (c) 2012 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.
5 #include "net/url_request/url_request_redirect_job.h"
10 #include "base/compiler_specific.h"
11 #include "base/logging.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/strings/stringprintf.h"
14 #include "net/base/load_timing_info.h"
15 #include "net/base/net_errors.h"
16 #include "net/base/net_log.h"
17 #include "net/http/http_response_headers.h"
18 #include "net/http/http_util.h"
19 #include "net/url_request/url_request.h"
23 URLRequestRedirectJob::URLRequestRedirectJob(URLRequest* request,
24 NetworkDelegate* network_delegate,
25 const GURL& redirect_destination,
26 ResponseCode response_code,
27 const std::string& redirect_reason)
28 : URLRequestJob(request, network_delegate),
29 redirect_destination_(redirect_destination),
30 response_code_(response_code),
31 redirect_reason_(redirect_reason),
33 DCHECK(!redirect_reason_.empty());
36 void URLRequestRedirectJob::GetResponseInfo(HttpResponseInfo* info) {
37 // Should only be called after the URLRequest has been notified there's header
39 DCHECK(fake_headers_.get());
41 // This assumes |info| is a freshly constructed HttpResponseInfo.
42 info->headers = fake_headers_;
43 info->request_time = response_time_;
44 info->response_time = response_time_;
47 void URLRequestRedirectJob::GetLoadTimingInfo(
48 LoadTimingInfo* load_timing_info) const {
49 // Set send_start and send_end to receive_headers_end_ to be consistent
50 // with network cache behavior.
51 load_timing_info->send_start = receive_headers_end_;
52 load_timing_info->send_end = receive_headers_end_;
53 load_timing_info->receive_headers_end = receive_headers_end_;
56 void URLRequestRedirectJob::Start() {
57 request()->net_log().AddEvent(
58 NetLog::TYPE_URL_REQUEST_REDIRECT_JOB,
59 NetLog::StringCallback("reason", &redirect_reason_));
60 base::MessageLoop::current()->PostTask(
62 base::Bind(&URLRequestRedirectJob::StartAsync,
63 weak_factory_.GetWeakPtr()));
66 bool URLRequestRedirectJob::CopyFragmentOnRedirect(const GURL& location) const {
67 // The instantiators have full control over the desired redirection target,
68 // including the reference fragment part of the URL.
72 int URLRequestRedirectJob::GetResponseCode() const {
73 // Should only be called after the URLRequest has been notified there's header
75 DCHECK(fake_headers_.get());
76 return response_code_;
79 URLRequestRedirectJob::~URLRequestRedirectJob() {}
81 void URLRequestRedirectJob::StartAsync() {
82 receive_headers_end_ = base::TimeTicks::Now();
83 response_time_ = base::Time::Now();
85 std::string header_string =
86 base::StringPrintf("HTTP/1.1 %i Internal Redirect\n"
88 "Non-Authoritative-Reason: %s",
90 redirect_destination_.spec().c_str(),
91 redirect_reason_.c_str());
93 std::string http_origin;
94 const net::HttpRequestHeaders& request_headers =
95 request_->extra_request_headers();
96 if (request_headers.GetHeader("Origin", &http_origin)) {
97 // If this redirect is used in a cross-origin request, add CORS headers to
98 // make sure that the redirect gets through. Note that the destination URL
99 // is still subject to the usual CORS policy, i.e. the resource will only
100 // be available to web pages if the server serves the response with the
101 // required CORS response headers.
102 header_string += base::StringPrintf(
104 "Access-Control-Allow-Origin: %s\n"
105 "Access-Control-Allow-Credentials: true",
106 http_origin.c_str());
109 fake_headers_ = new HttpResponseHeaders(
110 HttpUtil::AssembleRawHeaders(header_string.c_str(),
111 header_string.length()));
112 DCHECK(fake_headers_->IsRedirect(NULL));
114 request()->net_log().AddEvent(
115 NetLog::TYPE_URL_REQUEST_FAKE_RESPONSE_HEADERS_CREATED,
117 &HttpResponseHeaders::NetLogCallback,
118 base::Unretained(fake_headers_.get())));
120 // TODO(mmenke): Consider calling the NetworkDelegate with the headers here.
121 // There's some weirdness about how to handle the case in which the delegate
122 // tries to modify the redirect location, in terms of how IsSafeRedirect
123 // should behave, and whether the fragment should be copied.
124 URLRequestJob::NotifyHeadersComplete();