summaryrefslogtreecommitdiff
path: root/chromium/content/browser/devtools/devtools_url_interceptor_request_job.h
blob: 961cf901c6baf90f25822ee860063b5fc5177342 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_URL_INTERCEPTOR_REQUEST_JOB_H_
#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_URL_INTERCEPTOR_REQUEST_JOB_H_

#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/unguessable_token.h"
#include "content/browser/devtools/devtools_url_request_interceptor.h"
#include "content/browser/devtools/protocol/network.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/resource_type.h"
#include "net/http/http_raw_request_headers.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_job.h"

namespace net {
class AuthChallengeInfo;
class UploadDataStream;
}

namespace content {

// A URLRequestJob that allows programmatic request blocking / modification or
// response mocking.  This class should only be accessed on the IO thread.
class DevToolsURLInterceptorRequestJob : public net::URLRequestJob {
 public:
  DevToolsURLInterceptorRequestJob(
      DevToolsURLRequestInterceptor* interceptor,
      const std::string& interception_id,
      intptr_t owning_entry_id,
      net::URLRequest* original_request,
      net::NetworkDelegate* original_network_delegate,
      const base::UnguessableToken& devtools_token,
      DevToolsNetworkInterceptor::RequestInterceptedCallback callback,
      bool is_redirect,
      ResourceType resource_type,
      DevToolsNetworkInterceptor::InterceptionStage stage_to_intercept);

  ~DevToolsURLInterceptorRequestJob() override;

  // net::URLRequestJob implementation:
  void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
  void Start() override;
  void Kill() override;
  int ReadRawData(net::IOBuffer* buf, int buf_size) override;
  int GetResponseCode() const override;
  void GetResponseInfo(net::HttpResponseInfo* info) override;
  bool GetMimeType(std::string* mime_type) const override;
  bool GetCharset(std::string* charset) override;
  void GetLoadTimingInfo(net::LoadTimingInfo* load_timing_info) const override;
  bool NeedsAuth() override;
  void GetAuthChallengeInfo(
      scoped_refptr<net::AuthChallengeInfo>* auth_info) override;

  void SetAuth(const net::AuthCredentials& credentials) override;
  void CancelAuth() override;
  void SetRequestHeadersCallback(net::RequestHeadersCallback callback) override;
  void SetResponseHeadersCallback(
      net::ResponseHeadersCallback callback) override;

  // Must be called on IO thread.
  void StopIntercepting();

  using ContinueInterceptedRequestCallback =
      protocol::Network::Backend::ContinueInterceptedRequestCallback;
  using GetResponseBodyForInterceptionCallback =
      protocol::Network::Backend::GetResponseBodyForInterceptionCallback;
  using InterceptionStage = DevToolsNetworkInterceptor::InterceptionStage;

  // Must be called only once per interception. Must be called on IO thread.
  void ContinueInterceptedRequest(
      std::unique_ptr<DevToolsNetworkInterceptor::Modifications> modifications,
      std::unique_ptr<ContinueInterceptedRequestCallback> callback);
  void GetResponseBody(
      std::unique_ptr<GetResponseBodyForInterceptionCallback> callback);

  intptr_t owning_entry_id() const { return owning_entry_id_; }

 private:
  std::unique_ptr<InterceptedRequestInfo> BuildRequestInfo();

  class SubRequest;
  class InterceptedRequest;
  class MockResponseDetails;

  // We keep a copy of the original request details to facilitate the
  // Network.modifyRequest command which could potentially change any of these
  // fields.
  struct RequestDetails {
    RequestDetails(const GURL& url,
                   const std::string& method,
                   std::unique_ptr<net::UploadDataStream> post_data,
                   const net::HttpRequestHeaders& extra_request_headers,
                   const std::string& referrer,
                   net::URLRequest::ReferrerPolicy referrer_policy,
                   const net::RequestPriority& priority,
                   const net::URLRequestContext* url_request_context);
    ~RequestDetails();

    GURL url;
    std::string method;
    std::unique_ptr<net::UploadDataStream> post_data;
    net::HttpRequestHeaders extra_request_headers;
    std::string referrer;
    net::URLRequest::ReferrerPolicy referrer_policy;
    net::RequestPriority priority;
    const net::URLRequestContext* url_request_context;
  };

  // Callbacks from SubRequest.
  void OnSubRequestAuthRequired(net::AuthChallengeInfo* auth_info);
  void OnSubRequestRedirectReceived(const net::URLRequest& request,
                                    const net::RedirectInfo& redirectinfo,
                                    bool* defer_redirect);
  void OnSubRequestResponseStarted(const net::Error& net_error);
  void OnSubRequestHeadersReceived(const net::Error& net_error);

  // Callbacks from InterceptedRequest.
  void OnInterceptedRequestResponseStarted(const net::Error& net_error);
  void OnInterceptedRequestResponseReady(const net::IOBuffer& buf, int result);

  // Retrieves the response headers from either the |sub_request_| or the
  // |mock_response_|.  In some cases (e.g. file access) this may be null.
  const net::HttpResponseHeaders* GetHttpResponseHeaders() const;

  void ProcessRedirect(int status_code, const std::string& new_url);
  void ProcessInterceptionRespose(
      std::unique_ptr<DevToolsNetworkInterceptor::Modifications> modification);

  bool ProcessAuthRespose(
      std::unique_ptr<DevToolsNetworkInterceptor::Modifications> modification);

  enum class WaitingForUserResponse {
    NOT_WAITING,
    WAITING_FOR_REQUEST_ACK,
    WAITING_FOR_RESPONSE_ACK,
    WAITING_FOR_AUTH_ACK,
  };

  DevToolsURLRequestInterceptor* const interceptor_;
  RequestDetails request_details_;
  std::unique_ptr<SubRequest> sub_request_;
  std::unique_ptr<MockResponseDetails> mock_response_details_;
  std::unique_ptr<net::RedirectInfo> redirect_;
  WaitingForUserResponse waiting_for_user_response_;
  scoped_refptr<net::AuthChallengeInfo> auth_info_;

  const std::string interception_id_;
  const intptr_t owning_entry_id_;
  const base::UnguessableToken devtools_token_;
  DevToolsNetworkInterceptor::RequestInterceptedCallback callback_;
  const bool is_redirect_;
  const ResourceType resource_type_;
  InterceptionStage stage_to_intercept_;
  std::vector<std::unique_ptr<GetResponseBodyForInterceptionCallback>>
      pending_body_requests_;

  net::RequestHeadersCallback request_headers_callback_;
  net::ResponseHeadersCallback response_headers_callback_;
  base::WeakPtrFactory<DevToolsURLInterceptorRequestJob> weak_ptr_factory_;

  DISALLOW_COPY_AND_ASSIGN(DevToolsURLInterceptorRequestJob);
};

}  // namespace content

#endif  // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_URL_INTERCEPTOR_REQUEST_JOB_H_