Introduction
Starting with Gecko
1.8.1 (Firefox 2
), it is possible to create sandboxed HTTP
connections which don't affect the user's cookies. This article will
cover the basics of doing HTTP connections from XPCOM JavaScript, and
should easily translate to C++ XPCOM.
Setting up an HTTP connection
The first step in setting up an HTTP connection from an URL (stored in a string) is to create an nsIURI
out of it. nsIURI
is an XPCOM representation of an URI, with useful methods to query and manipulate the URI. To create an nsIURI
from an string, we use the newURI
method of nsIIOService
:
2
|
var
ioService = Components.classes[
"@mozilla.org/network/io-service;1"
]
|
3
|
.getService(Components.interfaces.nsIIOService);
|
6
|
var
uri = ioService.newURI(myURLString,
null
,
null
);
|
Once the nsIURI
has been created, a nsIChannel
can be generated from it using nsIIOService
's newChannelFromURI
method:
2
|
var
channel = ioService.newChannelFromURI(uri);
|
To initiate the connection, the asyncOpen
method is called. It takes two arguments: a listener and a context that is passed to the listener's methods.
1
|
channel.asyncOpen(listener,
null
);
|
HTTP notifications
The above mentioned listener is a nsIStreamListener
, which gets notified about events such as HTTP redirects and data availability.
-
onStartRequest
- gets called when a new request is initiated.
-
onDataAvailable
- new data is available. Since this is a stream, it could be called
multiple times (depending on the size of the returned data, networking
conditions, etc).
-
onStopRequest
- the request has finished.
-
onChannelRedirect
- when a redirect happens, a new nsIChannel
is created, and both the old and new ones are passed in as arguments.
Since nsIStreamListener
does not cover cookies, the
current channel being used will need to be stored as a global, since
another listener will be used for cookie notifications (covered in the
next section). It is usually best to use a JavaScript wrapper that
implements all the required methods and calls the specified callback
function when the connection has completed. Below is an example:
07
|
var
ioService = Components.classes[
"@mozilla.org/network/io-service;1"
]
|
08
|
.getService(Components.interfaces.nsIIOService);
|
11
|
var
uri = ioService.newURI(myURLString,
null
,
null
);
|
14
|
gChannel = ioService.newChannelFromURI(uri);
|
17
|
var
listener =
new
StreamListener(callbackFunc);
|
19
|
gChannel.notificationCallbacks = listener;
|
20
|
gChannel.asyncOpen(listener,
null
);
|
22
|
function
StreamListener(aCallbackFunc) {
|
23
|
this
.mCallbackFunc = aCallbackFunc;
|
26
|
StreamListener.prototype = {
|
30
|
onStartRequest:
function
(aRequest, aContext) {
|
34
|
onDataAvailable:
function
(aRequest, aContext, aStream, aSourceOffset, aLength) {
|
35
|
var
scriptableInputStream =
|
36
|
Components.classes[
"@mozilla.org/scriptableinputstream;1"
]
|
37
|
.createInstance(Components.interfaces.nsIScriptableInputStream);
|
38
|
scriptableInputStream.init(aStream);
|
40
|
this
.mData += scriptableInputStream.read(aLength);
|
43
|
onStopRequest:
function
(aRequest, aContext, aStatus) {
|
44
|
if
(Components.isSuccessCode(aStatus)) {
|
46
|
this
.mCallbackFunc(
this
.mData);
|
49
|
this
.mCallbackFunc(
null
);
|
56
|
onChannelRedirect:
function
(aOldChannel, aNewChannel, aFlags) {
|
58
|
gChannel = aNewChannel;
|
62
|
getInterface:
function
(aIID) {
|
64
|
return
this
.QueryInterface(aIID);
|
66
|
throw
Components.results.NS_NOINTERFACE;
|
71
|
onProgress :
function
(aRequest, aContext, aProgress, aProgressMax) { },
|
72
|
onStatus :
function
(aRequest, aContext, aStatus, aStatusArg) { },
|
75
|
onRedirect :
function
(aOldChannel, aNewChannel) { },
|
78
|
QueryInterface :
function
(aIID) {
|
79
|
if
(aIID.equals(Components.interfaces.nsISupports) ||
|
80
|
aIID.equals(Components.interfaces.nsIInterfaceRequestor) ||
|
81
|
aIID.equals(Components.interfaces.nsIChannelEventSink) ||
|
82
|
aIID.equals(Components.interfaces.nsIProgressEventSink) ||
|
83
|
aIID.equals(Components.interfaces.nsIHttpEventSink) ||
|
84
|
aIID.equals(Components.interfaces.nsIStreamListener))
|
87
|
throw
Components.results.NS_NOINTERFACE;
|
Quick note: storing the channel in a global (especially in an
extension) isn't a good idea, but was done to make the code easier to
read. It would be better to have the entire implementation inside a
class and storing the channel as a member:
02
|
this
.mChannel =
null
;
|
04
|
var
listener =
new
this
.StreamListener(callbackFunc);
|
08
|
myClass.prototype.StreamListener =
function
(aCallbackFunc) {
|
Handling cookies
When sending a request, cookies that apply to the URL are sent with
the HTTP request. The HTTP response can also contain cookies, which the
browser processes. As of Mozilla 1.8.1 (Firefox 2
), it is now possible to intercept those two cases.
For example, this means that if the user was logged into an webmail
account, another account on the same domain could be checked without
changing the user's cookies.
The observer service (nsIObserverService
) is used to send general notifications, including the two cookie ones. The addObserver
method is used to add an observer for a certain topic and takes in three agruments:
- an object than implements
nsIObserver
- the topic to listen for. For cookies, the two topics are:
-
http-on-modify-request
- happens after the cookie data has been loaded into the request, but before the request is sent.
-
http-on-examine-response
- happens after the response is received, but before the cookies are processed
- whether to hold a weak reference to the observer argument. Use
false
.
In order to avoid memory leaks
, the observer needs to be removed at one point. The removeObserver
method takes in the listener object and the topic and removes it from the notification list.
As with the above stream listener, an nsIObserver
implementing object is needed, which only needs to implement one method, observe
. The observe
method gets passed in three arguments, which for the two cookie topics are:
-
aSubject
: the channel (nsIChannel
) that caused this notification to happen.
-
aTopic
: the notification topic.
-
aData
: null
for the two topics.
Since the observers get notified for the registered topic for any
connection, the listener needs to make sure that the notification is for
the HTTP connection our code created. Since the channel that causes the
notification is passed in as the first argument, comparing it to the
globally stored channel (gChannel
) in the previous section (which also gets updated each time a redirect happens).
03
|
observe :
function
(aSubject, aTopic, aData) {
|
05
|
if
(aSubject == gChannel) {
|
06
|
var
httpChannel = aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
|
07
|
if
(aTopic ==
"http-on-modify-request"
) {
|
09
|
}
else
if
(aTopic ==
"http-on-examine-response"
) {
|
15
|
QueryInterface :
function
(aIID) {
|
16
|
if
(aIID.equals(Components.interfaces.nsISupports) ||
|
17
|
aIID.equals(Components.interfaces.nsIObserver))
|
19
|
throw
Components.results.NS_NOINTERFACE;
|
24
|
var
observerService = Components.classes[
"@mozilla.org/observer-service;1"
]
|
25
|
.getService(Components.interfaces.nsIObserverService);
|
26
|
observerService.addObserver(listener,
"http-on-modify-request"
,
false
);
|
27
|
observerService.addObserver(listener,
"http-on-examine-response"
,
false
);
|
The final piece is to manipulate the cookies. In order to manipulate cookies, the nsIChannel
needs to be converted into a nsIHttpChannel
by using QueryInterface
(QI):
1
|
var
httpChannel = aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
|
Cookies are actually part of the HTTP header, nsIHttpChannel
provides four methods for working with headers: two for getting and
setting request headers, and two for getting and setting response
headers. The cookie header for requests is called "Cookie", while for
responses it is "Set-Cookie".
-
getRequestHeader(aHeader)
- returns the request header value for the requested header.
-
setRequestHeader(aHeader, aValue, aMerge)
- sets the request header's value. If aMerge
is true
, the new value is appened, otherwise the old value is overwritten.
-
getResponseHeader(aHeader)
- returns the response header value for the requested header.
-
setResponseHeader(aHeader, aValue, aMerge)
- sets the response header's value. If aMerge
is true
, the new value is appened, otherwise the old value is overwritten.
These methods provide all the required functionality needed to modify
cookies before they are processed/sent, allowing for sandboxed cookie
connections that don't affect the user's cookies.
HTTP referrer
If the HTTP request needs to have a referrer set, two additional steps are needed after the nsIChannel
is created, but before it is opened. First, a nsIURI
needs to be generated for the referrer URL. Like before, the nsIIOService
is used:
1
|
var
referrerURI = ioService.newURI(referrerURL,
null
,
null
);
|
Next, the nsIChannel
is QIed to nsIHttpChannel
and the referrer
property is set to the generated nsIURI
:
1
|
var
httpChannel = channel.QueryInterface(Components.interfaces.nsIHttpChannel);
|
2
|
httpChannel.referrer = referrerURI;
|
Creating HTTP POSTs
To create an HTTP POST, a few additional steps are required after the nsIChannel
is created.
First, a nsIInputStream
instance is created, after which the setData
method is called. The first argument is the POST data as a string,
while the second argument is the length of that data. In this case, the
data is URL encoded, meaning that the string should look like this: foo=bar&baz=eek
.
1
|
var
inputStream = Components.classes[
"@mozilla.org/io/string-input-stream;1"
]
|
2
|
.createInstance(Components.interfaces.nsIStringInputStream);
|
3
|
inputStream.setData(postData, postData.length);
|
Next, the nsIChannel
is QIed to an nsIUploadChannel
. Its setUploadStream
method is called, passing in the nsIInputStream
and the type (in this case, "application/x-www-form-urlencoded"):
1
|
var
uploadChannel = gChannel.QueryInterface(Components.interfaces.nsIUploadChannel);
|
2
|
uploadChannel.setUploadStream(inputStream,
"application/x-www-form-urlencoded"
, -1);
|
Due to a bug, calling setUploadStream
will reset the nsIHttpChannel
to be a PUT request, so now the request type is set to POST:
2
|
httpChannel.requestMethod =
"POST"
;
|
分享到:
相关推荐
"cpp-SandboxedAPI自动为CC库生成沙箱" 指的是一个C++项目或工具,它使用Sandboxed API技术,专门为C/C++编写的库提供自动化沙箱环境的生成。沙箱是一种安全机制,允许程序在受限的环境中运行,以防止潜在的恶意代码...
:information: 如果您使用的... git clone https://github.com/openshift/sandboxed-containers-operator git checkout -b master --track origin/master 在集群上安装沙盒容器运算符, make install && make deploy
通过反编译flash插件,去除显示"not sandboxed"的cmd窗口逻辑。
沙盒 Android应用程序可对环境进行指纹识别。 该项目是对最近对环境敏感的Android应用程序检查它们是否在模拟器或设备中运行的回应。 如果恶意软件将其运行环境检测为模拟器,则很有可能在沙箱中对其进行分析。...
版权所有2019-2021 Google LLC。 什么是沙盒API? 沙盒API项目( SAPI )减轻了C / C ++库的沙盒负担:在安全策略的初始设置和库接口的生成之后,将生成存根API,使用自定义RPC层将调用透明地转发到运行在A / C ++...
npm install sandboxed-module 用法 var SandboxedModule = require ( 'sandboxed-module' ) ; var user = SandboxedModule . require ( './user' , { requires : { 'mysql' : { fake : 'mysql module' } } , ...
Sandboxed 是 Google Chrome 的部分 fork,仅封装了 Chrome Sandbox 代码,使其他应用程序可以重用 IPC 框架。 注意:这段代码现在已经很老了,一直在维护,仅供参考。 这是针对所有有兴趣将方法(使用 Broker/...
vantage-repl-sandboxed 面向vantage.js的高级REPL扩展 每次运行/ REPL启动时都会重新生成上下文 提供具有新创建的上下文基础的沙箱(请参阅initCtx,允许在沙箱中覆盖这些功能) 仅options.context提供的对象实际...
沙盒正则表达式利用Rust的强大功能,在JavaScript中处理不受信任的正则表达式...使用它像这样: const { SandboxedRegExp } = require('sandboxed-regexp');// Problematic regex example from http://www.rexegg.com/r
层次导航器此扩展使您可以在Tableau仪表板的Tree / Hierarchy扩展中可视化平面/维或递归数据。它有什么作用? 创建一个树形菜单供选择启用跨树搜索允许双向参数同步启用对原始工作表的过滤,而不会影响扩展名在原始...
WebApps Sandboxed browser Android app This Android app is a fork of the GoogleApps Sandboxed browser. The idea behind it is to provide a secure way to browse popular webapps by eliminating referrers...
GET http://localhost:8732/chains/main/blocks/genesis/protocols { "protocol": "ProtoGenesisGenesisGenesisGenesisGenesisGenesk612im", "next_protocol": "ProtoGenesisGenesisGenesisGenesisGenesisGenesk612...
- **Managing Sandboxed Solutions**: Scripts can be created to manage sandboxed solutions in SharePoint site collections, ensuring security and compliance. Throughout the book, the author provides ...
Chromium 自带一套完整的网络堆栈,负责处理 HTTP/HTTPS 请求、TCP/IP 协议、缓存策略等。在 Android 上,这部分与 Android 的网络框架相集成,提供跨平台兼容性和优化。 5. **Android 特性集成**: Chromium 与 ...
不和谐沙箱 开源的Sandbox Discord客户端,专为保护隐私而设计。 对侵入式数据收集说不。 您是否担心Discord在不按即按即说键的情况下观看正在打开的程序或正在收听的麦克风? Discord-Sandbox通过在内运行将...
Tor - 沙盒用户创建一个只能访问 Tor 网络的用户。 她对本地网络的访问被拒绝。
c#毕业设计源码下载 版权所有2019-2021 Google LLC。 什么是沙盒API? 沙盒API项目( SAPI )减轻了C ...++库的沙盒负担:在安全策略的初始设置和库接口的生成之后,将生成存根API,使用自定义RPC层将调用透明地转发到...
谷歌浏览器74.0.3729.108 彻底禁用Chrome的“请停用以开发者模式运行的扩展程序”提示 修改后的dll文件,使用前请备份原文件,以免出错。