mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1185439 - Add preamble to nsIMultiPartChannel for MIME type application/package. r=valentin
This commit is contained in:
parent
eb8e021e09
commit
f5137c494d
@ -12,7 +12,7 @@ interface nsIChannel;
|
||||
* associated with a MultiPartChannel.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(4b04e835-d131-42af-8bf0-74289f99374f)]
|
||||
[scriptable, uuid(3c329c90-2ee0-11e5-a2cb-0800200c9a66)]
|
||||
interface nsIMultiPartChannel : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -32,4 +32,10 @@ interface nsIMultiPartChannel : nsISupports
|
||||
* whether more data can be expected.
|
||||
*/
|
||||
readonly attribute boolean isLastPart;
|
||||
|
||||
/**
|
||||
* ASCII-encoding content prior to the first resource. Only valid for
|
||||
* content-type=application/package.
|
||||
*/
|
||||
readonly attribute ACString preamble;
|
||||
};
|
||||
|
@ -459,6 +459,18 @@ nsPartChannel::GetBaseChannel(nsIChannel ** aReturn)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPartChannel::GetPreamble(nsACString & aPreamble)
|
||||
{
|
||||
aPreamble = mPreamble;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsPartChannel::SetPreamble(const nsACString& aPreamble)
|
||||
{
|
||||
mPreamble = aPreamble;
|
||||
}
|
||||
|
||||
// nsISupports implementation
|
||||
NS_IMPL_ISUPPORTS(nsMultiMixedConv,
|
||||
@ -522,6 +534,49 @@ private:
|
||||
char *mBuffer;
|
||||
};
|
||||
|
||||
char*
|
||||
nsMultiMixedConv::ProbeToken(char* aBuffer, uint32_t& aTokenLen)
|
||||
{
|
||||
// To sign a packaged web app in the new security model, we need
|
||||
// to add the signature to the package header. The header is the
|
||||
// data before the first token and the header format is
|
||||
//
|
||||
// [field-name]: [field-value] CR LF
|
||||
//
|
||||
// So the package may look like:
|
||||
//
|
||||
// manifest-signature: MRjdkly...
|
||||
// --gc0pJq0M:08jU534c0p
|
||||
// Content-Location: /someapp.webmanifest
|
||||
// Content-Type: application/manifest
|
||||
//
|
||||
// {
|
||||
// "name": "My App",
|
||||
// "description":"A great app!"
|
||||
// ...
|
||||
//
|
||||
//
|
||||
// We search for the first '\r\n--' and assign the subsquent chars
|
||||
// to the token until another '\r\n'. '--' will be included in the
|
||||
// token we probed. If the second '\r\n' is not found, we still treat
|
||||
// the token is not found and more data will be requested.
|
||||
|
||||
char* posCRLFDashDash = PL_strstr(aBuffer, "\r\n--");
|
||||
if (!posCRLFDashDash) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char* tokenStart = posCRLFDashDash + 2; // Skip "\r\n".
|
||||
char* tokenEnd = PL_strstr(tokenStart, "\r\n");
|
||||
if (!tokenEnd) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aTokenLen = tokenEnd - tokenStart;
|
||||
|
||||
return tokenStart;
|
||||
}
|
||||
|
||||
// nsIStreamListener implementation
|
||||
NS_IMETHODIMP
|
||||
nsMultiMixedConv::OnDataAvailable(nsIRequest *request, nsISupports *context,
|
||||
@ -584,24 +639,36 @@ nsMultiMixedConv::OnDataAvailable(nsIRequest *request, nsISupports *context,
|
||||
} else if (mPackagedApp) {
|
||||
// We need to check the line starts with --
|
||||
if (!StringBeginsWith(firstBuffer, NS_LITERAL_CSTRING("--"))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
char* tokenPos = ProbeToken(buffer, mTokenLen);
|
||||
if (!tokenPos) {
|
||||
// No token is found. We need more data.
|
||||
mFirstOnData = true;
|
||||
} else {
|
||||
// Token is probed.
|
||||
mToken = Substring(tokenPos, mTokenLen);
|
||||
mPreamble = nsCString(Substring(buffer, tokenPos));
|
||||
|
||||
// If the boundary was set in the header,
|
||||
// we need to check it matches with the one in the file.
|
||||
if (mTokenLen &&
|
||||
!StringBeginsWith(Substring(firstBuffer, 2), mToken)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Push the cursor to the token so that the while loop below will
|
||||
// find token from the right position.
|
||||
cursor = tokenPos;
|
||||
}
|
||||
} else {
|
||||
// If the boundary was set in the header,
|
||||
// we need to check it matches with the one in the file.
|
||||
if (mTokenLen &&
|
||||
!StringBeginsWith(Substring(firstBuffer, 2), mToken)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Save the token.
|
||||
if (!mTokenLen) {
|
||||
mToken = nsCString(Substring(firstBuffer, 2).BeginReading(),
|
||||
posCR - 2);
|
||||
mTokenLen = mToken.Length();
|
||||
}
|
||||
// Save the token.
|
||||
if (!mTokenLen) {
|
||||
mToken = nsCString(Substring(firstBuffer, 2).BeginReading(),
|
||||
posCR - 2);
|
||||
mTokenLen = mToken.Length();
|
||||
}
|
||||
|
||||
cursor = buffer;
|
||||
cursor = buffer;
|
||||
}
|
||||
} else if (!PL_strnstr(cursor, token, mTokenLen + 2)) {
|
||||
char *newBuffer = (char *) realloc(buffer, bufLen + mTokenLen + 1);
|
||||
if (!newBuffer)
|
||||
@ -965,6 +1032,9 @@ nsMultiMixedConv::SendStart(nsIChannel *aChannel) {
|
||||
// Set up the new part channel...
|
||||
mPartChannel = newChannel;
|
||||
|
||||
// Pass preamble to the channel.
|
||||
mPartChannel->SetPreamble(mPreamble);
|
||||
|
||||
// We pass the headers to the nsPartChannel
|
||||
mPartChannel->SetResponseHead(mResponseHead.forget());
|
||||
|
||||
|
@ -43,6 +43,7 @@ public:
|
||||
|
||||
void InitializeByteRange(int64_t aStart, int64_t aEnd);
|
||||
void SetIsLastPart() { mIsLastPart = true; }
|
||||
void SetPreamble(const nsACString& aPreamble);
|
||||
nsresult SendOnStartRequest(nsISupports* aContext);
|
||||
nsresult SendOnDataAvailable(nsISupports* aContext, nsIInputStream* aStream,
|
||||
uint64_t aOffset, uint32_t aLen);
|
||||
@ -86,6 +87,8 @@ protected:
|
||||
uint32_t mPartID; // unique ID that can be used to identify
|
||||
// this part of the multipart document
|
||||
bool mIsLastPart;
|
||||
|
||||
nsCString mPreamble;
|
||||
};
|
||||
|
||||
// The nsMultiMixedConv stream converter converts a stream of type "multipart/x-mixed-replace"
|
||||
@ -145,6 +148,7 @@ protected:
|
||||
int32_t PushOverLine(char *&aPtr, uint32_t &aLen);
|
||||
char *FindToken(char *aCursor, uint32_t aLen);
|
||||
nsresult BufferData(char *aData, uint32_t aLen);
|
||||
char* ProbeToken(char* aBuffer, uint32_t& aTokenLen);
|
||||
|
||||
// member data
|
||||
bool mNewPart; // Are we processing the beginning of a part?
|
||||
@ -187,6 +191,11 @@ protected:
|
||||
// for packaged apps, in the case that only metadata is saved in the cache
|
||||
// entry and OnDataAvailable never gets called.
|
||||
bool mIsFromCache;
|
||||
|
||||
// Preamble is defined as the ASCII-encoding string which appears before the
|
||||
// first boundary. It's only supported by 'application/package' content type
|
||||
// and requires the boundary is defined in the HTTP header.
|
||||
nsCString mPreamble;
|
||||
};
|
||||
|
||||
#endif /* __nsmultimixedconv__h__ */
|
||||
|
@ -76,7 +76,15 @@ function contentHandler_type_missing(metadata, response)
|
||||
response.bodyOutputStream.write(body, body.length);
|
||||
}
|
||||
|
||||
function contentHandler_with_package_header(metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", 'application/package');
|
||||
var body = testData.packageHeader + testData.getData();
|
||||
response.bodyOutputStream.write(body, body.length);
|
||||
}
|
||||
|
||||
var testData = {
|
||||
packageHeader: 'manifest-signature: dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk\r\n',
|
||||
content: [
|
||||
{ headers: ["Content-Location: /index.html", "Content-Type: text/html"], data: "<html>\r\n <head>\r\n <script src=\"/scripts/app.js\"></script>\r\n ...\r\n </head>\r\n ...\r\n</html>\r\n", type: "text/html" },
|
||||
{ headers: ["Content-Location: /scripts/app.js", "Content-Type: text/javascript"], data: "module Math from '/scripts/helpers/math.js';\r\n...\r\n", type: "text/javascript" },
|
||||
@ -99,7 +107,7 @@ var testData = {
|
||||
}
|
||||
}
|
||||
|
||||
function multipartListener(test, badContentType) {
|
||||
function multipartListener(test, badContentType, shouldVerifyPackageHeader) {
|
||||
this._buffer = "";
|
||||
this.testNum = 0;
|
||||
this.test = test;
|
||||
@ -108,6 +116,7 @@ function multipartListener(test, badContentType) {
|
||||
// content type. If so, resources will have their content type set to
|
||||
// application/octet-stream
|
||||
this.badContentType = badContentType == undefined ? false : badContentType;
|
||||
this.shouldVerifyPackageHeader = shouldVerifyPackageHeader;
|
||||
}
|
||||
|
||||
multipartListener.prototype.responseHandler = function(request, buffer) {
|
||||
@ -128,6 +137,12 @@ multipartListener.prototype.QueryInterface = function(iid) {
|
||||
}
|
||||
|
||||
multipartListener.prototype.onStartRequest = function(request, context) {
|
||||
if (this.shouldVerifyPackageHeader) {
|
||||
let partChannel = request.QueryInterface(Ci.nsIMultiPartChannel);
|
||||
ok(!!partChannel, 'Should be multipart channel');
|
||||
equal(partChannel.preamble, this.test.packageHeader);
|
||||
}
|
||||
|
||||
this._buffer = "";
|
||||
this.headerListener = new headerListener(this.test.content[this.testNum].headers, this.badContentType);
|
||||
let headerProvider = request.QueryInterface(Ci.nsIResponseHeadProvider);
|
||||
@ -222,6 +237,18 @@ function test_multipart_content_type_other() {
|
||||
chan.asyncOpen(conv, null);
|
||||
}
|
||||
|
||||
function test_multipart_package_header() {
|
||||
var streamConv = Cc["@mozilla.org/streamConverters;1"]
|
||||
.getService(Ci.nsIStreamConverterService);
|
||||
|
||||
var conv = streamConv.asyncConvertData("application/package",
|
||||
"*/*",
|
||||
new multipartListener(testData, false, true),
|
||||
null);
|
||||
|
||||
var chan = make_channel(uri + "/multipart5");
|
||||
chan.asyncOpen(conv, null);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
@ -230,6 +257,7 @@ function run_test()
|
||||
httpserver.registerPathHandler("/multipart2", contentHandler_with_boundary);
|
||||
httpserver.registerPathHandler("/multipart3", contentHandler_chunked_headers);
|
||||
httpserver.registerPathHandler("/multipart4", contentHandler_type_missing);
|
||||
httpserver.registerPathHandler("/multipart5", contentHandler_with_package_header);
|
||||
httpserver.start(-1);
|
||||
|
||||
run_next_test();
|
||||
@ -239,3 +267,4 @@ add_test(test_multipart);
|
||||
add_test(test_multipart_with_boundary);
|
||||
add_test(test_multipart_chunked_headers);
|
||||
add_test(test_multipart_content_type_other);
|
||||
add_test(test_multipart_package_header);
|
||||
|
@ -493,5 +493,11 @@ ExternalHelperAppParent::GetIsLastPart(bool* aIsLastPart)
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetPreamble(nsACString & aPreamble)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
Loading…
Reference in New Issue
Block a user