xref: /aosp_15_r20/external/cronet/net/url_request/url_request_redirect_job.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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