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/location.h"
12 #include "base/logging.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "base/values.h"
17 #include "net/base/load_timing_info.h"
18 #include "net/base/net_errors.h"
19 #include "net/http/http_response_headers.h"
20 #include "net/http/http_util.h"
21 #include "net/log/net_log.h"
22 #include "net/url_request/url_request.h"
26 URLRequestRedirectJob::URLRequestRedirectJob(URLRequest
* request
,
27 NetworkDelegate
* network_delegate
,
28 const GURL
& redirect_destination
,
29 ResponseCode response_code
,
30 const std::string
& redirect_reason
)
31 : URLRequestJob(request
, network_delegate
),
32 redirect_destination_(redirect_destination
),
33 response_code_(response_code
),
34 redirect_reason_(redirect_reason
),
36 DCHECK(!redirect_reason_
.empty());
39 void URLRequestRedirectJob::GetResponseInfo(HttpResponseInfo
* info
) {
40 // Should only be called after the URLRequest has been notified there's header
42 DCHECK(fake_headers_
.get());
44 // This assumes |info| is a freshly constructed HttpResponseInfo.
45 info
->headers
= fake_headers_
;
46 info
->request_time
= response_time_
;
47 info
->response_time
= response_time_
;
50 void URLRequestRedirectJob::GetLoadTimingInfo(
51 LoadTimingInfo
* load_timing_info
) const {
52 // Set send_start and send_end to receive_headers_end_ to be consistent
53 // with network cache behavior.
54 load_timing_info
->send_start
= receive_headers_end_
;
55 load_timing_info
->send_end
= receive_headers_end_
;
56 load_timing_info
->receive_headers_end
= receive_headers_end_
;
59 void URLRequestRedirectJob::Start() {
60 request()->net_log().AddEvent(
61 NetLog::TYPE_URL_REQUEST_REDIRECT_JOB
,
62 NetLog::StringCallback("reason", &redirect_reason_
));
63 base::ThreadTaskRunnerHandle::Get()->PostTask(
64 FROM_HERE
, base::Bind(&URLRequestRedirectJob::StartAsync
,
65 weak_factory_
.GetWeakPtr()));
68 void URLRequestRedirectJob::Kill() {
69 weak_factory_
.InvalidateWeakPtrs();
70 URLRequestJob::Kill();
73 bool URLRequestRedirectJob::CopyFragmentOnRedirect(const GURL
& location
) const {
74 // The instantiators have full control over the desired redirection target,
75 // including the reference fragment part of the URL.
79 int URLRequestRedirectJob::GetResponseCode() const {
80 // Should only be called after the URLRequest has been notified there's header
82 DCHECK(fake_headers_
.get());
83 return response_code_
;
86 URLRequestRedirectJob::~URLRequestRedirectJob() {}
88 void URLRequestRedirectJob::StartAsync() {
90 DCHECK(request_
->status().is_success());
92 receive_headers_end_
= base::TimeTicks::Now();
93 response_time_
= base::Time::Now();
95 std::string header_string
=
96 base::StringPrintf("HTTP/1.1 %i Internal Redirect\n"
98 "Non-Authoritative-Reason: %s",
100 redirect_destination_
.spec().c_str(),
101 redirect_reason_
.c_str());
103 std::string http_origin
;
104 const HttpRequestHeaders
& request_headers
= request_
->extra_request_headers();
105 if (request_headers
.GetHeader("Origin", &http_origin
)) {
106 // If this redirect is used in a cross-origin request, add CORS headers to
107 // make sure that the redirect gets through. Note that the destination URL
108 // is still subject to the usual CORS policy, i.e. the resource will only
109 // be available to web pages if the server serves the response with the
110 // required CORS response headers.
111 header_string
+= base::StringPrintf(
113 "Access-Control-Allow-Origin: %s\n"
114 "Access-Control-Allow-Credentials: true",
115 http_origin
.c_str());
118 fake_headers_
= new HttpResponseHeaders(
119 HttpUtil::AssembleRawHeaders(header_string
.c_str(),
120 header_string
.length()));
121 DCHECK(fake_headers_
->IsRedirect(NULL
));
123 request()->net_log().AddEvent(
124 NetLog::TYPE_URL_REQUEST_FAKE_RESPONSE_HEADERS_CREATED
,
126 &HttpResponseHeaders::NetLogCallback
,
127 base::Unretained(fake_headers_
.get())));
129 // TODO(mmenke): Consider calling the NetworkDelegate with the headers here.
130 // There's some weirdness about how to handle the case in which the delegate
131 // tries to modify the redirect location, in terms of how IsSafeRedirect
132 // should behave, and whether the fragment should be copied.
133 URLRequestJob::NotifyHeadersComplete();