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