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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
|
// Copyright (c) 2010 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.
//
// Web request notifier implementation.
#ifndef CEEE_IE_PLUGIN_BHO_WEBREQUEST_NOTIFIER_H_
#define CEEE_IE_PLUGIN_BHO_WEBREQUEST_NOTIFIER_H_
#include <atlbase.h>
#include <wininet.h>
#include <map>
#include <string>
#include "app/win/iat_patch_function.h"
#include "base/singleton.h"
#include "ceee/ie/plugin/bho/webrequest_events_funnel.h"
#include "toolband.h"
struct FunctionStub;
// WebRequestNotifier monitors HTTP request/response events via WinINet hooks,
// and sends the events to the broker.
class WebRequestNotifier {
public:
// Starts the service if it hasn't been started.
// @return Returns true if the service is being initialized or has been
// successfully initialized.
bool RequestToStart();
// Stops the service if it is currently running and nobody is interested in
// the service any more. Every call to RequestToStart (even if it failed)
// should be paired with a call to RequestToStop.
void RequestToStop();
protected:
// Information related to an Internet connection.
struct ServerInfo {
ServerInfo() : server_port(INTERNET_INVALID_PORT_NUMBER) {}
// The host name of the server.
std::wstring server_name;
// The port number on the server.
INTERNET_PORT server_port;
};
// Information related to a HTTP request.
struct RequestInfo {
RequestInfo()
: server_handle(NULL),
id(-1),
tab_handle(reinterpret_cast<CeeeWindowHandle>(INVALID_HANDLE_VALUE)),
status_code(0),
state(BEGIN),
content_length(0),
read_progress(0),
length_type(UNKNOWN_MESSAGE_LENGTH_TYPE) {
}
enum State {
// The start state.
// Possible next state: WILL_NOTIFY_BEFORE_REQUEST;
// ERROR_OCCURRED.
BEGIN = 0,
// We are about to fire webRequest.onBeforeRequest.
// Possible next state: NOTIFIED_BEFORE_REQUEST;
// ERROR_OCCURRED.
WILL_NOTIFY_BEFORE_REQUEST = 1,
// The last event fired is webRequest.onBeforeRequest.
// Possible next state: NOTIFIED_REQUEST_SENT;
// ERROR_OCCURRED.
NOTIFIED_BEFORE_REQUEST = 2,
// The last event fired is webRequest.onRequestSent.
// Possible next state: NOTIFIED_HEADERS_RECEIVED;
// ERROR_OCCURRED.
NOTIFIED_REQUEST_SENT = 3,
// The last event fired is webRequest.onHeadersReceived.
// Possible next state: NOTIFIED_BEFORE_REDIRECT;
// NOTIFIED_COMPLETED;
// ERROR_OCCURRED.
NOTIFIED_HEADERS_RECEIVED = 4,
// The last event fired is webRequest.onBeforeRedirect.
// Possible next state: NOTIFIED_REQUEST_SENT;
// ERROR_OCCURRED.
NOTIFIED_BEFORE_REDIRECT = 5,
// One of the two stop states.
// The last event fired is webRequest.onCompleted.
// Possible next state: NOTIFIED_COMPLETED.
NOTIFIED_COMPLETED = 6,
// One of the two stop states.
// Some error has occurred.
// Possible next state: ERROR_OCCURRED.
ERROR_OCCURRED = 7
};
// How the length of a message body is decided.
enum MessageLengthType {
UNKNOWN_MESSAGE_LENGTH_TYPE = 0,
// There is no message body.
NO_MESSAGE_BODY = 1,
// The length is decided by Content-Length header.
CONTENT_LENGTH_HEADER = 2,
// Including:
// (1) a Transfer-Encoding header field is present and has any value
// other than "identity";
// (2) the message uses the media type "multipart/byteranges";
// (3) the length should be decided by the server closing the connection.
VARIABLE_MESSAGE_LENGTH = 3,
};
// The handle of the connection to the server.
HINTERNET server_handle;
// The request ID, which is unique within a browser session.
int id;
// The window handle of the tab which sent the request.
CeeeWindowHandle tab_handle;
// The standard HTTP method, such as "GET" or "POST".
std::string method;
// The URL to retrieve.
std::wstring url;
// The URL before redirection.
std::wstring original_url;
// The server IP.
std::string ip;
// The standard HTTP status code returned by the server.
DWORD status_code;
// The request state to help decide what event should be sent next.
State state;
// When the browser was about to make the request.
base::Time before_request_time;
// The length of the response body. It is meaningful only when length_type
// is set to CONTENT_LENGTH_HEADER.
DWORD content_length;
// The progress of reading the response body.
DWORD read_progress;
// How the length of the response body is decided.
MessageLengthType length_type;
};
WebRequestNotifier();
virtual ~WebRequestNotifier();
// Accessor so that we can mock it in unit tests.
// Currently this method is always called within a lock.
virtual WebRequestEventsFunnel& webrequest_events_funnel() {
return webrequest_events_funnel_;
}
// Gets called before calling InternetSetStatusCallback.
// @param internet The handle for which the callback is set.
// @param callback The real callback function.
// @return A patch for the callback function.
INTERNET_STATUS_CALLBACK HandleBeforeInternetSetStatusCallback(
HINTERNET internet,
INTERNET_STATUS_CALLBACK callback);
// Gets called before calling InternetConnect.
// @param internet Handle returned by InternetOpen.
void HandleBeforeInternetConnect(HINTERNET internet);
// Gets called after calling InternetConnect.
// @param server The sever handle returned by InternetConnect.
// @param server_name The host name of the server.
// @param server_port The port number on the server.
// @param service Type of service to access.
void HandleAfterInternetConnect(HINTERNET server,
const wchar_t* server_name,
INTERNET_PORT server_port,
DWORD service);
// Gets called after calling HttpOpenRequest.
// @param server The server handle.
// @param request The request handle.
// @param method Standard HTTP method, such as "GET" or "POST".
// @param path The path to the target object.
// @param flags Internet options that are passed into HttpOpenRequest.
void HandleAfterHttpOpenRequest(HINTERNET server,
HINTERNET request,
const char* method,
const wchar_t* path,
DWORD flags);
// Gets called before calling HttpSendRequest.
// @param request The request handle.
void HandleBeforeHttpSendRequest(HINTERNET request);
// Gets called before calling InternetStatusCallback.
// @param original The original status callback function.
// @param internet The handle for which the callback function is called.
// @param context The application-defined context value associated with
// the internet parameter.
// @param internet_status A status code that indicates why the callback
// function is called.
// @param status_information A pointer to additional status information.
// @param status_information_length The size, in bytes, of the additional
// status information.
void HandleBeforeInternetStatusCallback(INTERNET_STATUS_CALLBACK original,
HINTERNET internet,
DWORD_PTR context,
DWORD internet_status,
LPVOID status_information,
DWORD status_information_length);
// Gets called after calling InternetReadFile.
// @param request The request handle.
// @param result Whether the read operation is successful or not.
// @param number_of_bytes_read How many bytes have been read.
void HandleAfterInternetReadFile(HINTERNET request,
BOOL result,
LPDWORD number_of_bytes_read);
// InternetSetStatusCallback function patches.
// InternetSetStatusCallback documentation can be found at:
// http://msdn.microsoft.com/en-us/library/aa385120(VS.85).aspx
static INTERNET_STATUS_CALLBACK STDAPICALLTYPE
InternetSetStatusCallbackAPatch(
HINTERNET internet,
INTERNET_STATUS_CALLBACK internet_callback);
static INTERNET_STATUS_CALLBACK STDAPICALLTYPE
InternetSetStatusCallbackWPatch(
HINTERNET internet,
INTERNET_STATUS_CALLBACK internet_callback);
// InternetConnect function patches.
// InternetConnect documentation can be found at:
// http://msdn.microsoft.com/en-us/library/aa384363(VS.85).aspx
static HINTERNET STDAPICALLTYPE InternetConnectAPatch(
HINTERNET internet,
LPCSTR server_name,
INTERNET_PORT server_port,
LPCSTR user_name,
LPCSTR password,
DWORD service,
DWORD flags,
DWORD_PTR context);
static HINTERNET STDAPICALLTYPE InternetConnectWPatch(
HINTERNET internet,
LPCWSTR server_name,
INTERNET_PORT server_port,
LPCWSTR user_name,
LPCWSTR password,
DWORD service,
DWORD flags,
DWORD_PTR context);
// HttpOpenRequest function patches.
// HttpOpenRequest documentation can be found at:
// http://msdn.microsoft.com/en-us/library/aa384233(v=VS.85).aspx
static HINTERNET STDAPICALLTYPE HttpOpenRequestAPatch(HINTERNET connect,
LPCSTR verb,
LPCSTR object_name,
LPCSTR version,
LPCSTR referrer,
LPCSTR* accept_types,
DWORD flags,
DWORD_PTR context);
static HINTERNET STDAPICALLTYPE HttpOpenRequestWPatch(HINTERNET connect,
LPCWSTR verb,
LPCWSTR object_name,
LPCWSTR version,
LPCWSTR referrer,
LPCWSTR* accept_types,
DWORD flags,
DWORD_PTR context);
// HttpSendRequest function patches.
// HttpSendRequest documentation can be found at:
// http://msdn.microsoft.com/en-us/library/aa384247(v=VS.85).aspx
static BOOL STDAPICALLTYPE HttpSendRequestAPatch(HINTERNET request,
LPCSTR headers,
DWORD headers_length,
LPVOID optional,
DWORD optional_length);
static BOOL STDAPICALLTYPE HttpSendRequestWPatch(HINTERNET request,
LPCWSTR headers,
DWORD headers_length,
LPVOID optional,
DWORD optional_length);
// InternetStatusCallback function patch.
// InternetStatusCallback function documentation can be found at:
// http://msdn.microsoft.com/en-us/library/aa385121(v=VS.85).aspx
static void CALLBACK InternetStatusCallbackPatch(
INTERNET_STATUS_CALLBACK original,
HINTERNET internet,
DWORD_PTR context,
DWORD internet_status,
LPVOID status_information,
DWORD status_information_length);
// InternetReadFile function patch.
// InternetReadFile documentation can be found at:
// http://msdn.microsoft.com/en-us/library/aa385103(v=VS.85).aspx
static BOOL STDAPICALLTYPE InternetReadFilePatch(
HINTERNET file,
LPVOID buffer,
DWORD number_of_bytes_to_read,
LPDWORD number_of_bytes_read);
// Patches a WinINet function.
// @param name The name of the function to be intercepted.
// @param patch_function The patching helper. You could check the is_patched
// member of this object to see whether the patching operation is
// successful or not.
// @param handler The new function implementation.
void PatchWinINetFunction(const char* name,
app::win::IATPatchFunction* patch_function,
void* handler);
// Constructs a URL. The method omits the port number if it is the default
// number for the protocol, or it is INTERNET_INVALID_PORT_NUMBER.
// Currently this method is always called within a lock.
// @param https Is it http or https?
// @param server_name The host name of the server.
// @param server_port The port number on the server.
// @param path The path to the target object.
// @param url The returned URL.
// @return Whether the operation is successful or not.
bool ConstructUrl(bool https,
const wchar_t* server_name,
INTERNET_PORT server_port,
const wchar_t* path,
std::wstring* url);
// Retrieves header information as a number.
// Make the method virtual so that we could mock it for unit tests.
// @param request The request handle.
// @param info_flag Query info flags could be found on:
// http://msdn.microsoft.com/en-us/library/aa385351(v=VS.85).aspx
// @param value The returned value.
// @return Whether the operation is successful or not.
virtual bool QueryHttpInfoNumber(HINTERNET request,
DWORD info_flag,
DWORD* value);
// Retrieves header information as a string.
// Make the method virtual so that we could mock it for unit tests.
// @param request The request handle.
// @param info_flag Query info flags could be found on:
// http://msdn.microsoft.com/en-us/library/aa385351(v=VS.85).aspx
// @param value The returned value.
// @return Whether the operation is successful or not.
virtual bool QueryHttpInfoString(HINTERNET request,
DWORD info_flag,
std::wstring* value);
// Determines the length of the response body.
// @param request The request handle.
// @param status_code Standard HTTP status code.
// @param length Returns the length of the response body. It is meaningful
// only when type is set to CONTENT_LENGTH_HEADER.
// @param type Returns how the length of the response body is decided.
// @return Whether the operation is successful or not.
bool DetermineMessageLength(HINTERNET request,
DWORD status_code,
DWORD* length,
RequestInfo::MessageLengthType* type);
// Performs state transition on a request.
// NOTE: this method must be called within a lock.
// @param state The target state. Please note that if it is not a valid
// transition, the request may end up with a state other than the
// target state.
// @param info Information about the request.
void TransitRequestToNextState(RequestInfo::State state, RequestInfo* info);
// Creates a function stub for the status callback function.
// NOTE: this method must be called within a lock.
// @param original_callback The original callback function.
// @return A patch for the callback function.
INTERNET_STATUS_CALLBACK CreateInternetStatusCallbackStub(
INTERNET_STATUS_CALLBACK original_callback);
// NOTE: this method must be called within a lock.
// @return Returns true if the service is not functioning, either because
// nobody is interested in the service or because the initialization
// has failed.
bool IsNotRunning() const {
return start_count_ == 0 || initialize_state_ != SUCCEEDED_TO_INITIALIZE;
}
// Returns true if exactly one (but not both) of the patches has been
// successfully applied.
// @param patch_function_1 A function patch.
// @param patch_function_2 Another function patch.
// @return Returns true if exactly one of them has been successfully applied.
bool HasPatchedOneVersion(
const app::win::IATPatchFunction& patch_function_1,
const app::win::IATPatchFunction& patch_function_2) const {
return (patch_function_1.is_patched() && !patch_function_2.is_patched()) ||
(!patch_function_1.is_patched() && patch_function_2.is_patched());
}
// Function patches that allow us to intercept WinINet functions.
app::win::IATPatchFunction internet_set_status_callback_a_patch_;
app::win::IATPatchFunction internet_set_status_callback_w_patch_;
app::win::IATPatchFunction internet_connect_a_patch_;
app::win::IATPatchFunction internet_connect_w_patch_;
app::win::IATPatchFunction http_open_request_a_patch_;
app::win::IATPatchFunction http_open_request_w_patch_;
app::win::IATPatchFunction http_send_request_a_patch_;
app::win::IATPatchFunction http_send_request_w_patch_;
app::win::IATPatchFunction internet_read_file_patch_;
// The funnel for sending webRequest events to the broker.
WebRequestEventsFunnel webrequest_events_funnel_;
// Used to protect the access to all the following data members.
CComAutoCriticalSection critical_section_;
// Used to intercept InternetStatusCallback function, which is defined by a
// WinINet client to observe status changes.
FunctionStub* internet_status_callback_stub_;
// Maps Internet connection handles to ServerInfo instances.
typedef std::map<HINTERNET, ServerInfo> ServerMap;
ServerMap server_map_;
// Maps HTTP request handles to RequestInfo instances.
typedef std::map<HINTERNET, RequestInfo> RequestMap;
RequestMap request_map_;
// The number of RequestToStart calls minus the number of RequestToStop calls.
// If the number drops to 0, then the service will be stopped.
int start_count_;
// Indicates the progress of initialization.
enum InitializeState {
// Initialization hasn't been started.
NOT_INITIALIZED,
// Initialization is happening.
INITIALIZING,
// Initialization has failed.
FAILED_TO_INITIALIZE,
// Initialization has succeeded.
SUCCEEDED_TO_INITIALIZE
};
InitializeState initialize_state_;
private:
DISALLOW_COPY_AND_ASSIGN(WebRequestNotifier);
};
// A singleton that keeps the WebRequestNotifier used by production code.
class ProductionWebRequestNotifier
: public WebRequestNotifier,
public Singleton<ProductionWebRequestNotifier> {
private:
ProductionWebRequestNotifier() {}
friend struct DefaultSingletonTraits<ProductionWebRequestNotifier>;
DISALLOW_COPY_AND_ASSIGN(ProductionWebRequestNotifier);
};
#endif // CEEE_IE_PLUGIN_BHO_WEBREQUEST_NOTIFIER_H_
|