问题描述
在阅读File API并希望将数据直接从indexedDB数据库写入客户端磁盘,而不是先在RAM中建立并持有一个大blob以便下载到磁盘时,有一些我不了解的基本项目
在MDN文档中找到以下两个语句:
- 一个人在哪里写Chrome代码和/或Gecko特权代码?这超出了Web扩展范围吗?我已经阅读并尝试了扩展程序;因此,我并没有特别询问如何访问它们.
我不担心正常"网页和服务器访问客户端磁盘.我知道,为了保护个人是不允许的.
我对个人可以通过浏览器脱机完成什么感兴趣-借助Web扩展和/或单独的配置文件授予特殊权限,但没有node.js,electron等.想要使用浏览器来完成他们应该在操作系统中构建的功能,而不是浏览器.
-
采用另一种方式,如果我只想使用浏览器来运行javascript代码以在自己的计算机上离线执行所有任务,那么编写的特权代码在哪里,这些代码可以访问以下类型的API:会遇到普通网页的安全性问题吗?
-
在这些区域中仍是javascript还是C ++?
谢谢.
此旧问题提供了指向其扩展名,其中包括File API,它以一种似乎可以绕开创建大数据块的方式写入磁盘.它已经六岁了,但似乎包含了至少开始需要的东西.
我并不是指他们试图使用indexedDB解决问题,只是使用这种扩展名可以允许将数据库中的每个对象直接写入客户端磁盘,而无需先生成大的blob进行下载.
尝试采用安德鲁·斯旺的建议
我正在尝试将各个部分放在一起,但是到了不确定如何继续的地步.我在扩展的后台脚本中编写了以下代码.在尝试采用Andrew Swan的建议时,计划是启动对text/csv文件的GET请求,该请求将被从数据库中提取的数据截取并替换,并由流过滤器写入GET请求.
首先,向伪造的url发出GET请求,并听取响应,如下所示:
let request = new XMLHttpRequest();
request.open("GET", url );
request.setRequestHeader( "Content-Type", "text/csv" );
request.send(null);
request.onreadystatechange = () =>
{
portFromCS.postMessage( { 'func' : 'disp_result', 'args' : { 'msg' : "request.status :", 'value' : request.status + ' : ' + request.statusText} } );
};
第二,拦截请求并写入GET,如下所示:
browser.webRequest.onBeforeRequest.addListener(
listener,
{ urls : ["<all_urls>"] },
["blocking"] );
function listener( details )
{
let filter = browser.webRequest.filterResponseData(details.requestId);
let decoder = new TextDecoder("utf-8");
let encoder = new TextEncoder();
filter.onstart = event =>
{
let str = decoder.decode(event.data, {stream: true});
str = '' +
'HTTP/1.1 200 OK \r\n' +
'Content-Length: 17 \r\n' +
'Content-Type: text/csv \r\n\r\n\r\n' +
'This is a string.';
filter.write(encoder.encode(str));
filter.disconnect();
};
}
内容脚本中接收到来自request.onreadystatechange函数中的后台脚本发送的消息,并且request.status为'0'.
之所以使用filter.onstart,是因为URL是虚假的,因此ondata事件将永远不会触发.同样,这意味着将不会从url转换数据,而只会通过过滤器写入新数据.
str数据由请求写入和接收,但仅作为responseText而不是响应标头. request.status保持为'0'而不是'200'.
看来,除非伪造的URL出现在onHeadersReceived中,否则它将无法更改响应标头.但是,我在真实的url上尝试了此操作,即使触发了该事件,也不会引发webRequest.HttpHeaders错误.那时,我在webRequest extraInfoSpec中有"responseHeaders".
我的问题是:
-
是否可以编写响应标头以将request.status设置为'200',然后通过异步函数开始在检索到的小块中开始写入数据库数据?
-
是否可以设置标题响应的内容处理"部分,使其自动开始下载response.text,并允许用户选择文件名和保存位置,并在保持写入状态下保持打开"状态数据从数据库中提取出来并通过filter.write()传递给GET请求?
谢谢.
结论
这是个好主意,但由于至少两个原因,我认为这是不可能的.
一个是webRequest似乎根本没有拦截downloads.download()函数或任何下载事件;因此,您无法拦截下载,并且甚至需要尝试使用流向其写入内容附件为"attachment"的事件.我可以拦截对锚标记href的强制单击,但没有触发onBeforeRequest之外的其他事件.
另一种情况是,只有在onHeadersReceived事件发生之前,才能修改响应标头,这意味着伪造的URL必须返回某些内容.您不能只在onBeforeRequest中取消它.因此,这将无法离线工作.但是,即使您让它在线处理到返回响应标头的现有URL,也不会接受修改.我反复尝试修改响应头,但无法正常工作.我尝试了XMLHttpRequest GET,它可以拦截触发的事件,但是不能修改响应头.因此,无论有没有文件,都无法将内容处置"设置为附件"以开始下载.我可以写它,但是除非它要下载写的东西,否则它是不好的.如果书面内容要转到网页上就可以了.
此外,如果您沿URL重定向到除webRequest可接受URL以外的任何其他地址,其他事件将不会被拦截.因此,如果重定向到onBeforeRequest中的对象URL,您将不会在webRequest中拦截响应标头阶段,但可以在XMLHttpRequest的onreadystatechange事件中查看threm.
因此,结果是,即使MDN Web文档说可以,也无法修改响应头.而且,与构建一个大型Blob进行下载相反,使用awebRequest流过滤器流式传输客户端生成的数据或从indexedDB数据库提取的数据的想法行不通,因为它无法拦截下载或将响应标头更改为通过流过滤器触发要写入的下载.
这是一个有趣的想法.我仍然想知道,在将数据写入客户端并以块或块的形式传递数据时,下载是否会保持打开"状态.也许,如果修改了响应标头中说明如何传递和接收数据的那部分,那么它也会起作用.
就目前而言,我不再追求这种方法. Web文档或错误记录之一表明,已计划允许拦截数据URL.也许,对于脱机下载到客户端,最好使用假URL.
如果有人可以使用它,请告诉我们.谢谢.
几个术语:
- "Gecko"是在其上构建Firefox(以及Thunderbird等其他一些应用程序)的呈现引擎
- 在此上下文中,"Chrome"是指浏览器的用户界面和功能,与浏览器显示的网页内容相反.
在Firefox中,许多浏览器镶边都是使用Javascript实现的.实现用户界面的代码需要能够执行普通网页无法执行的操作(例如,读取和写入本地文件系统).因此,此代码以与作为网页一部分运行的Javascript不同的特权运行.术语特权代码","chrome特权代码","Gecko特权代码"是描述同一事物的所有不同方式:内置于浏览器中并可以访问网页所没有的功能的Javascript代码. /p>
在Firefox Quantum(版本57)发行之前,允许Firefox扩展运行特权Javascript代码.就像您想象的那样,其中充满了安全性,性能和稳定性等问题.使用WebExtensions,扩展现在可以以与常规Web内容相同的特权级别运行(即,它们不以提升的特权执行).某些浏览器功能通过扩展API 公开. /p>
因此,如果您对扩展可以做什么感兴趣,则MDN上任何引用特权代码的文档实际上都是无关紧要的.当前没有可用于WebExtensions的API允许您直接访问文件系统,但是有一个打开错误以添加一些此功能. (该错误已经存在了很长一段时间,但是我怀疑会有相对较快的进展……)
In reading about the File API and wanting to write data directly from an indexedDB database to the client disk instead of first building and holding a large blob in RAM to download to disk, there are a few basic items I'm not understanding.
In the MDN documents these two statements are found:
- Where exactly does one write chrome code and/or Gecko priveleged code? Is this beyond a web extension? I've read and experimented with extensions; so, I'm not asking specifically about how to access them.
I'm not concerned about a 'normal' web page and server accessing the client disk. I know that it's not permitted inorder to protect the individual.
I'm interested in what can be done offline through the browser--with the aid of web extensions and/or a separate profile granting special permissions but without node.js, electron, etc.-- by an individual who knowingly wants to use the browser to do maybe what they should have built in the OS rather than the browser.
Put another way, if I want to use the browser just to run my javascript code to perform tasks all offline on my own machine, where is the privileged code written that gives access to these types of APIs that aren't subject to the security issues of a normal web page?
Is it still javascript or C++ in these areas?
Thank you.
This old question provides a link to their extension which includes the File API that writes to disk in a way that appears to provide a means to bypass the creation of a large blob of data. It's six years old but appears to contain what is needed, at least to get started.
I'm not referring to their trying to get around using indexedDB, but just that using this type of extension could allow for writing each object from the database directly to the client disk without first having to generate a large blob to download.
Attempt at employing Andrew Swan's suggestion
I'm trying to put the pieces together but have reached a point where am not sure how to continue. I wrote the code below in the background script of an extension. In attempting to employ Andrew Swan's suggestion, the plan is to intitiate a GET request for a text/csv file, which is intercepted and replaced by data extracted from database and written to the GET request by the stream filter.
First, make a GET request to a bogus url and listen for response, as follows:
let request = new XMLHttpRequest();
request.open("GET", url );
request.setRequestHeader( "Content-Type", "text/csv" );
request.send(null);
request.onreadystatechange = () =>
{
portFromCS.postMessage( { 'func' : 'disp_result', 'args' : { 'msg' : "request.status :", 'value' : request.status + ' : ' + request.statusText} } );
};
Second, intercept the request and write to the GET, as follows:
browser.webRequest.onBeforeRequest.addListener(
listener,
{ urls : ["<all_urls>"] },
["blocking"] );
function listener( details )
{
let filter = browser.webRequest.filterResponseData(details.requestId);
let decoder = new TextDecoder("utf-8");
let encoder = new TextEncoder();
filter.onstart = event =>
{
let str = decoder.decode(event.data, {stream: true});
str = '' +
'HTTP/1.1 200 OK \r\n' +
'Content-Length: 17 \r\n' +
'Content-Type: text/csv \r\n\r\n\r\n' +
'This is a string.';
filter.write(encoder.encode(str));
filter.disconnect();
};
}
The message sent from the background script in the request.onreadystatechange function is received in the content script, and the request.status is '0'.
The filter.onstart is used because the ondata event will never fire since the url is bogus. Also, that means there will be no converting of data from the url, but only the writing of new data through the filter.
The str data is written and received by the request, but only as responseText and not as a response header. The request.status remains '0' instead of '200'.
It seems that can't change the response header unless in onHeadersReceived which will never take place, it appears, for a bogus url. However, I tried this on a real url and, even though the event fired, an error of webRequest.HttpHeaders is not a function was thrown. I had "responseHeaders" in the webRequest extraInfoSpec at that time.
My questions are:
Can a response header be written to set the request.status to '200' and then start writing the database data through an async function in small blocks as retrieved?
Can the Content Disposition section of the header response be set such that it automatically starts the download of the response.text and allows the user to select the file name and save location, and stay "open" as keep writing to the file as the data is extracted from the database and passed to the GET request through the filter.write()?
Thank you.
Conclusion
It was a good idea but I don't think it is possible for at least two reasons.
One is that webRequest doesn't appear to intercept a downloads.download() function at all, or any download event; so, you can't intercept a download, and an event with a Content Disposition of 'attachment' is needed to even try to write to it with a stream. I could intercept a forced click to an anchor tag href but no other events fired beyond onBeforeRequest.
The other is that a response header can't be modified until an onHeadersReceived event, which means the fake URL has to return something. You can't just cancel it in onBeforeRequest. So, this wouldn't work offline. But, even if you let it process online to an existing URL that returns a reponse header, it won't accept a modification. I tried repeatedly to modify the response header and it just won't work. I tried an XMLHttpRequest GET and can intercept the events that fire but can't modify the response header; so, can't set Content Disposition to 'attachment', with or without file, to start a download. I can write to it but it's no good unless it is going to download what is written. It would be ok if the written content was going to a web page.
Also, if you redirect the URL along the way to anything other than a webRequest acceptable URL, the other events won't be interceptable. So, if redirect to an object URL in onBeforeRequest, you won't intercept the response headers stage in webRequest but can view threm in the onreadystatechange event of the XMLHttpRequest.
So, the upshot is that it appears the response headers cannot be modified even though the MDN Web Docs say it is possible. And, this idea of using awebRequest stream filter to stream data generated on the client or extracted from an indexedDB database, as opposed to building one large blob for download, won't work because can't intercept a download or change the response headers to trigger a download into which to write via the stream filter.
It was an interesting idea though. I still wonder whether or not the download would remain 'open', so to speak, while the data was being written on the client and passed in blocks or chunks. Perhaps, if that part of the response headers that states how data is to be passed and received was modified also it would work.
For now, I am no longer pursuing this approach. One of the Web Docs or a bug records stated that it is planned to allow a data URL to be intercepted. Perhaps, for an offline download to the client, that would be preferrable to a fake URL.
If anyone gets this to work, please let us know. Thank you.
A couple of terms:
- "Gecko" is the rendering engine on which Firefox (and a few other applications like Thunderbird) is built
- "Chrome" in this context means the browser user interface and features, as opposed to the contents of a web page being displayed by the browser.
In Firefox, much of the browser chrome is implemented in Javascript. The code that implements the user interface needs to be able to do things that normal web pages cannot do (such as reading and writing the local filesystem). Therefore, this code runs with different privileges than Javascript that runs as part of a web page. The terms "privileged code", "chrome privileged code", "Gecko privileged code" are all different ways to describe the same thing: Javascript code that is built in to the browser and has access to capabilities that web pages do not have.
Prior to the Firefox Quantum (version 57) release, Firefox extensions were allowed to run privileged Javascript code. As you might imagine, this was fraught with problems for security, performance, and stability, among other things. With WebExtensions, extensions now run with the same level of privilege as regular web content (ie, they do not execute with elevated privileges). Some browser features are exposed to extensions through extension APIs.
So, if you're interested in what you can do from an extension, any documents on MDN that reference privileged code, are effectively irrelevant. There are not currently any APIs available to WebExtensions that would allow you to directly access the filesystem, but there is an open bug to add some this capability. (that bug has existed for quite some time, but I suspect there will be progress relatively soon...)
这篇关于特权代码,chrome代码,Gecko到底在什么地方?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!