xref: /aosp_15_r20/external/cronet/net/url_request/url_request_job_factory.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2011 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_job_factory.h"
6 
7 #include "base/containers/contains.h"
8 #include "net/base/net_errors.h"
9 #include "net/net_buildflags.h"
10 #include "net/url_request/url_request.h"
11 #include "net/url_request/url_request_error_job.h"
12 #include "net/url_request/url_request_http_job.h"
13 #include "net/url_request/url_request_interceptor.h"
14 #include "url/gurl.h"
15 #include "url/url_constants.h"
16 
17 namespace net {
18 
19 namespace {
20 
21 URLRequestInterceptor* g_interceptor_for_testing = nullptr;
22 
23 // TODO(mmenke): Look into removing this class and
24 // URLRequestJobFactory::ProtocolHandlers completely. The only other subclass
25 // is iOS-only.
26 class HttpProtocolHandler : public URLRequestJobFactory::ProtocolHandler {
27  public:
28   // URLRequest::is_for_websockets() must match `is_for_websockets`, or requests
29   // will be failed. This is so that attempts to fetch WebSockets requests
30   // fails, and attempts to use HTTP URLs for WebSockets also fail.
HttpProtocolHandler(bool is_for_websockets)31   explicit HttpProtocolHandler(bool is_for_websockets)
32       : is_for_websockets_(is_for_websockets) {}
33 
34   HttpProtocolHandler(const HttpProtocolHandler&) = delete;
35   HttpProtocolHandler& operator=(const HttpProtocolHandler&) = delete;
36   ~HttpProtocolHandler() override = default;
37 
CreateJob(URLRequest * request) const38   std::unique_ptr<URLRequestJob> CreateJob(URLRequest* request) const override {
39     if (request->is_for_websockets() != is_for_websockets_) {
40       return std::make_unique<URLRequestErrorJob>(request,
41                                                   ERR_UNKNOWN_URL_SCHEME);
42     }
43     return URLRequestHttpJob::Create(request);
44   }
45 
46   const bool is_for_websockets_;
47 };
48 
49 }  // namespace
50 
51 URLRequestJobFactory::ProtocolHandler::~ProtocolHandler() = default;
52 
IsSafeRedirectTarget(const GURL & location) const53 bool URLRequestJobFactory::ProtocolHandler::IsSafeRedirectTarget(
54     const GURL& location) const {
55   return true;
56 }
57 
URLRequestJobFactory()58 URLRequestJobFactory::URLRequestJobFactory() {
59   SetProtocolHandler(url::kHttpScheme, std::make_unique<HttpProtocolHandler>(
60                                            /*is_for_websockets=*/false));
61   SetProtocolHandler(url::kHttpsScheme, std::make_unique<HttpProtocolHandler>(
62                                             /*is_for_websockets=*/false));
63 #if BUILDFLAG(ENABLE_WEBSOCKETS)
64   SetProtocolHandler(url::kWsScheme, std::make_unique<HttpProtocolHandler>(
65                                          /*is_for_websockets=*/true));
66   SetProtocolHandler(url::kWssScheme, std::make_unique<HttpProtocolHandler>(
67                                           /*is_for_websockets=*/true));
68 #endif  // BUILDFLAG(ENABLE_WEBSOCKETS)
69 }
70 
~URLRequestJobFactory()71 URLRequestJobFactory::~URLRequestJobFactory() {
72   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
73 }
74 
SetProtocolHandler(const std::string & scheme,std::unique_ptr<ProtocolHandler> protocol_handler)75 bool URLRequestJobFactory::SetProtocolHandler(
76     const std::string& scheme,
77     std::unique_ptr<ProtocolHandler> protocol_handler) {
78   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
79 
80   if (!protocol_handler) {
81     auto it = protocol_handler_map_.find(scheme);
82     if (it == protocol_handler_map_.end())
83       return false;
84 
85     protocol_handler_map_.erase(it);
86     return true;
87   }
88 
89   if (base::Contains(protocol_handler_map_, scheme))
90     return false;
91   protocol_handler_map_[scheme] = std::move(protocol_handler);
92   return true;
93 }
94 
CreateJob(URLRequest * request) const95 std::unique_ptr<URLRequestJob> URLRequestJobFactory::CreateJob(
96     URLRequest* request) const {
97   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
98 
99   // If we are given an invalid URL, then don't even try to inspect the scheme.
100   if (!request->url().is_valid())
101     return std::make_unique<URLRequestErrorJob>(request, ERR_INVALID_URL);
102 
103   if (g_interceptor_for_testing) {
104     std::unique_ptr<URLRequestJob> job(
105         g_interceptor_for_testing->MaybeInterceptRequest(request));
106     if (job)
107       return job;
108   }
109 
110   auto it = protocol_handler_map_.find(request->url().scheme());
111   if (it == protocol_handler_map_.end()) {
112     return std::make_unique<URLRequestErrorJob>(request,
113                                                 ERR_UNKNOWN_URL_SCHEME);
114   }
115 
116   return it->second->CreateJob(request);
117 }
118 
IsSafeRedirectTarget(const GURL & location) const119 bool URLRequestJobFactory::IsSafeRedirectTarget(const GURL& location) const {
120   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
121   if (!location.is_valid()) {
122     // Error cases are safely handled.
123     return true;
124   }
125   auto it = protocol_handler_map_.find(location.scheme());
126   if (it == protocol_handler_map_.end()) {
127     // Unhandled cases are safely handled.
128     return true;
129   }
130   return it->second->IsSafeRedirectTarget(location);
131 }
132 
SetInterceptorForTesting(URLRequestInterceptor * interceptor)133 void URLRequestJobFactory::SetInterceptorForTesting(
134     URLRequestInterceptor* interceptor) {
135   DCHECK(!interceptor || !g_interceptor_for_testing);
136 
137   g_interceptor_for_testing = interceptor;
138 }
139 
140 }  // namespace net
141