• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "net/test/url_request/url_request_failed_job.h"
11 
12 #include "base/check_op.h"
13 #include "base/functional/bind.h"
14 #include "base/location.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/task/single_thread_task_runner.h"
17 #include "net/base/net_errors.h"
18 #include "net/base/url_util.h"
19 #include "net/http/http_response_headers.h"
20 #include "net/url_request/url_request.h"
21 #include "net/url_request/url_request_filter.h"
22 #include "net/url_request/url_request_interceptor.h"
23 
24 namespace net {
25 
26 namespace {
27 
28 const char kMockHostname[] = "mock.failed.request";
29 
30 // String names of failure phases matching FailurePhase enum.
31 const char* kFailurePhase[]{
32     "start",      // START
33     "readsync",   // READ_SYNC
34     "readasync",  // READ_ASYNC
35 };
36 
37 static_assert(std::size(kFailurePhase) ==
38                   URLRequestFailedJob::FailurePhase::MAX_FAILURE_PHASE,
39               "kFailurePhase must match FailurePhase enum");
40 
41 class MockJobInterceptor : public URLRequestInterceptor {
42  public:
43   MockJobInterceptor() = default;
44 
45   MockJobInterceptor(const MockJobInterceptor&) = delete;
46   MockJobInterceptor& operator=(const MockJobInterceptor&) = delete;
47 
48   ~MockJobInterceptor() override = default;
49 
50   // URLRequestJobFactory::ProtocolHandler implementation:
MaybeInterceptRequest(URLRequest * request) const51   std::unique_ptr<URLRequestJob> MaybeInterceptRequest(
52       URLRequest* request) const override {
53     int net_error = OK;
54     URLRequestFailedJob::FailurePhase phase =
55         URLRequestFailedJob::FailurePhase::MAX_FAILURE_PHASE;
56     for (size_t i = 0; i < std::size(kFailurePhase); i++) {
57       std::string phase_error_string;
58       if (GetValueForKeyInQuery(request->url(), kFailurePhase[i],
59                                 &phase_error_string)) {
60         if (base::StringToInt(phase_error_string, &net_error)) {
61           phase = static_cast<URLRequestFailedJob::FailurePhase>(i);
62           break;
63         }
64       }
65     }
66     return std::make_unique<URLRequestFailedJob>(request, phase, net_error);
67   }
68 };
69 
GetMockUrl(const std::string & scheme,const std::string & hostname,URLRequestFailedJob::FailurePhase phase,int net_error)70 GURL GetMockUrl(const std::string& scheme,
71                 const std::string& hostname,
72                 URLRequestFailedJob::FailurePhase phase,
73                 int net_error) {
74   CHECK_GE(phase, URLRequestFailedJob::FailurePhase::START);
75   CHECK_LE(phase, URLRequestFailedJob::FailurePhase::READ_ASYNC);
76   CHECK_LT(net_error, OK);
77   return GURL(scheme + "://" + hostname + "/error?" + kFailurePhase[phase] +
78               "=" + base::NumberToString(net_error));
79 }
80 
81 }  // namespace
82 
URLRequestFailedJob(URLRequest * request,FailurePhase phase,int net_error)83 URLRequestFailedJob::URLRequestFailedJob(URLRequest* request,
84                                          FailurePhase phase,
85                                          int net_error)
86     : URLRequestJob(request), phase_(phase), net_error_(net_error) {
87   CHECK_GE(phase, URLRequestFailedJob::FailurePhase::START);
88   CHECK_LE(phase, URLRequestFailedJob::FailurePhase::READ_ASYNC);
89   CHECK_LT(net_error, OK);
90 }
91 
URLRequestFailedJob(URLRequest * request,int net_error)92 URLRequestFailedJob::URLRequestFailedJob(URLRequest* request, int net_error)
93     : URLRequestFailedJob(request, START, net_error) {}
94 
95 URLRequestFailedJob::~URLRequestFailedJob() = default;
96 
Start()97 void URLRequestFailedJob::Start() {
98   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
99       FROM_HERE, base::BindOnce(&URLRequestFailedJob::StartAsync,
100                                 weak_factory_.GetWeakPtr()));
101 }
102 
ReadRawData(IOBuffer * buf,int buf_size)103 int URLRequestFailedJob::ReadRawData(IOBuffer* buf, int buf_size) {
104   CHECK(phase_ == READ_SYNC || phase_ == READ_ASYNC);
105   if (net_error_ == ERR_IO_PENDING || phase_ == READ_SYNC)
106     return net_error_;
107 
108   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
109       FROM_HERE, base::BindOnce(&URLRequestFailedJob::ReadRawDataComplete,
110                                 weak_factory_.GetWeakPtr(), net_error_));
111   return ERR_IO_PENDING;
112 }
113 
GetResponseInfo(HttpResponseInfo * info)114 void URLRequestFailedJob::GetResponseInfo(HttpResponseInfo* info) {
115   *info = response_info_;
116 }
117 
PopulateNetErrorDetails(NetErrorDetails * details) const118 void URLRequestFailedJob::PopulateNetErrorDetails(
119     NetErrorDetails* details) const {
120   if (net_error_ == ERR_QUIC_PROTOCOL_ERROR) {
121     details->quic_connection_error = quic::QUIC_INTERNAL_ERROR;
122   } else if (net_error_ == ERR_NETWORK_CHANGED) {
123     details->quic_connection_error =
124         quic::QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK;
125   }
126 }
127 
GetTotalReceivedBytes() const128 int64_t URLRequestFailedJob::GetTotalReceivedBytes() const {
129   return total_received_bytes_;
130 }
131 
132 // static
AddUrlHandler()133 void URLRequestFailedJob::AddUrlHandler() {
134   return AddUrlHandlerForHostname(kMockHostname);
135 }
136 
137 // static
AddUrlHandlerForHostname(const std::string & hostname)138 void URLRequestFailedJob::AddUrlHandlerForHostname(
139     const std::string& hostname) {
140   URLRequestFilter* filter = URLRequestFilter::GetInstance();
141   // Add |hostname| to URLRequestFilter for HTTP and HTTPS.
142   filter->AddHostnameInterceptor("http", hostname,
143                                  std::make_unique<MockJobInterceptor>());
144   filter->AddHostnameInterceptor("https", hostname,
145                                  std::make_unique<MockJobInterceptor>());
146 }
147 
148 // static
GetMockHttpUrl(int net_error)149 GURL URLRequestFailedJob::GetMockHttpUrl(int net_error) {
150   return GetMockHttpUrlForHostname(net_error, kMockHostname);
151 }
152 
153 // static
GetMockHttpsUrl(int net_error)154 GURL URLRequestFailedJob::GetMockHttpsUrl(int net_error) {
155   return GetMockHttpsUrlForHostname(net_error, kMockHostname);
156 }
157 
158 // static
GetMockHttpUrlWithFailurePhase(FailurePhase phase,int net_error)159 GURL URLRequestFailedJob::GetMockHttpUrlWithFailurePhase(FailurePhase phase,
160                                                          int net_error) {
161   return GetMockUrl("http", kMockHostname, phase, net_error);
162 }
163 
164 // static
GetMockHttpUrlForHostname(int net_error,const std::string & hostname)165 GURL URLRequestFailedJob::GetMockHttpUrlForHostname(
166     int net_error,
167     const std::string& hostname) {
168   return GetMockUrl("http", hostname, START, net_error);
169 }
170 
171 // static
GetMockHttpsUrlForHostname(int net_error,const std::string & hostname)172 GURL URLRequestFailedJob::GetMockHttpsUrlForHostname(
173     int net_error,
174     const std::string& hostname) {
175   return GetMockUrl("https", hostname, START, net_error);
176 }
177 
StartAsync()178 void URLRequestFailedJob::StartAsync() {
179   if (phase_ == START) {
180     if (net_error_ != ERR_IO_PENDING) {
181       NotifyStartError(net_error_);
182       return;
183     }
184     return;
185   }
186   const std::string headers = "HTTP/1.1 200 OK";
187   response_info_.headers =
188       base::MakeRefCounted<net::HttpResponseHeaders>(headers);
189   total_received_bytes_ = headers.size();
190   NotifyHeadersComplete();
191 }
192 
193 }  // namespace net
194