1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/url_request/url_request_redirect_job.h"
6
7 #include <string>
8
9 #include "base/check.h"
10 #include "base/compiler_specific.h"
11 #include "base/functional/bind.h"
12 #include "base/location.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/task/single_thread_task_runner.h"
15 #include "base/values.h"
16 #include "net/base/load_timing_info.h"
17 #include "net/base/net_errors.h"
18 #include "net/http/http_log_util.h"
19 #include "net/http/http_raw_request_headers.h"
20 #include "net/http/http_response_headers.h"
21 #include "net/log/net_log.h"
22 #include "net/log/net_log_event_type.h"
23 #include "net/log/net_log_with_source.h"
24 #include "net/url_request/redirect_util.h"
25 #include "net/url_request/url_request.h"
26 #include "net/url_request/url_request_job.h"
27
28 namespace net {
29
URLRequestRedirectJob(URLRequest * request,const GURL & redirect_destination,RedirectUtil::ResponseCode response_code,const std::string & redirect_reason)30 URLRequestRedirectJob::URLRequestRedirectJob(
31 URLRequest* request,
32 const GURL& redirect_destination,
33 RedirectUtil::ResponseCode response_code,
34 const std::string& redirect_reason)
35 : URLRequestJob(request),
36 redirect_destination_(redirect_destination),
37 response_code_(response_code),
38 redirect_reason_(redirect_reason) {
39 DCHECK(!redirect_reason_.empty());
40 }
41
42 URLRequestRedirectJob::~URLRequestRedirectJob() = default;
43
GetResponseInfo(HttpResponseInfo * info)44 void URLRequestRedirectJob::GetResponseInfo(HttpResponseInfo* info) {
45 // Should only be called after the URLRequest has been notified there's header
46 // information.
47 DCHECK(fake_headers_.get());
48
49 // This assumes |info| is a freshly constructed HttpResponseInfo.
50 info->headers = fake_headers_;
51 info->request_time = response_time_;
52 info->response_time = response_time_;
53 }
54
GetLoadTimingInfo(LoadTimingInfo * load_timing_info) const55 void URLRequestRedirectJob::GetLoadTimingInfo(
56 LoadTimingInfo* load_timing_info) const {
57 // Set send_start, send_end, and receive_headers_start to
58 // receive_headers_end_ to be consistent with network cache behavior.
59 load_timing_info->send_start = receive_headers_end_;
60 load_timing_info->send_end = receive_headers_end_;
61 load_timing_info->receive_headers_start = receive_headers_end_;
62 load_timing_info->receive_headers_end = receive_headers_end_;
63 }
64
Start()65 void URLRequestRedirectJob::Start() {
66 request()->net_log().AddEventWithStringParams(
67 NetLogEventType::URL_REQUEST_REDIRECT_JOB, "reason", redirect_reason_);
68 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
69 FROM_HERE, base::BindOnce(&URLRequestRedirectJob::StartAsync,
70 weak_factory_.GetWeakPtr()));
71 }
72
Kill()73 void URLRequestRedirectJob::Kill() {
74 weak_factory_.InvalidateWeakPtrs();
75 URLRequestJob::Kill();
76 }
77
CopyFragmentOnRedirect(const GURL & location) const78 bool URLRequestRedirectJob::CopyFragmentOnRedirect(const GURL& location) const {
79 // The instantiators have full control over the desired redirection target,
80 // including the reference fragment part of the URL.
81 return false;
82 }
83
StartAsync()84 void URLRequestRedirectJob::StartAsync() {
85 DCHECK(request_);
86
87 receive_headers_end_ = base::TimeTicks::Now();
88 response_time_ = base::Time::Now();
89
90 const HttpRequestHeaders& request_headers = request_->extra_request_headers();
91 fake_headers_ = RedirectUtil::SynthesizeRedirectHeaders(
92 redirect_destination_, response_code_, redirect_reason_, request_headers);
93
94 NetLogResponseHeaders(
95 request()->net_log(),
96 NetLogEventType::URL_REQUEST_FAKE_RESPONSE_HEADERS_CREATED,
97 fake_headers_.get());
98
99 // Send request headers along if there's a callback
100 if (request_headers_callback_) {
101 HttpRawRequestHeaders raw_request_headers;
102 for (const auto& header : request_headers.GetHeaderVector()) {
103 raw_request_headers.Add(header.key, header.value);
104 }
105
106 // Just to make extra sure everyone knows this is an internal header
107 raw_request_headers.set_request_line(
108 base::StringPrintf("%s %s HTTP/1.1\r\n", request_->method().c_str(),
109 request_->url().PathForRequest().c_str()));
110 request_headers_callback_.Run(std::move(raw_request_headers));
111 }
112
113 // TODO(mmenke): Consider calling the NetworkDelegate with the headers here.
114 // There's some weirdness about how to handle the case in which the delegate
115 // tries to modify the redirect location, in terms of how IsSafeRedirect
116 // should behave, and whether the fragment should be copied.
117 URLRequestJob::NotifyHeadersComplete();
118 }
119
SetRequestHeadersCallback(RequestHeadersCallback callback)120 void URLRequestRedirectJob::SetRequestHeadersCallback(
121 RequestHeadersCallback callback) {
122 request_headers_callback_ = std::move(callback);
123 }
124
125 } // namespace net
126