зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1307456 - Remove packaged app related changes to nsMultiMixedConv r=bagder
MozReview-Commit-ID: Vkt8s9xT5E --HG-- extra : rebase_source : 87f5a990638f65ad568619b504db057c9c05871a
This commit is contained in:
Родитель
e825b942e9
Коммит
6f93776828
|
@ -95,7 +95,6 @@ XPIDL_SOURCES += [
|
|||
'nsIRequestContext.idl',
|
||||
'nsIRequestObserver.idl',
|
||||
'nsIRequestObserverProxy.idl',
|
||||
'nsIResponseHeadProvider.idl',
|
||||
'nsIResumableChannel.idl',
|
||||
'nsISecCheckWrapChannel.idl',
|
||||
'nsISecureBrowserUI.idl',
|
||||
|
|
|
@ -32,15 +32,4 @@ 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;
|
||||
|
||||
/**
|
||||
* The original http response header in each part.
|
||||
*/
|
||||
readonly attribute ACString originalResponseHeader;
|
||||
};
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIHttpHeaderVisitor;
|
||||
|
||||
%{C++
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
class nsHttpResponseHead;
|
||||
}
|
||||
}
|
||||
%}
|
||||
|
||||
[ptr] native nsHttpResponseHeadPtr(mozilla::net::nsHttpResponseHead);
|
||||
|
||||
/**
|
||||
* nsIResponseHeadProvider
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(cd0d0804-2e0c-4bff-aa0a-78a3e3159b69)]
|
||||
interface nsIResponseHeadProvider : nsISupports
|
||||
{
|
||||
/**
|
||||
* Returns a pointer to a nsHttpResponseHead. May return null.
|
||||
*/
|
||||
[notxpcom] nsHttpResponseHeadPtr GetResponseHead();
|
||||
|
||||
/**
|
||||
* May be used to iterate through the response headers
|
||||
*/
|
||||
void visitResponseHeaders(in nsIHttpHeaderVisitor aVisitor);
|
||||
};
|
|
@ -38,6 +38,7 @@
|
|||
#include "nsITransport.h"
|
||||
#include "nsIOService.h"
|
||||
#include "nsIRequestContext.h"
|
||||
#include "nsIHttpAuthenticator.h"
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
|
|
|
@ -51,8 +51,6 @@ nsPartChannel::nsPartChannel(nsIChannel *aMultipartChannel, uint32_t aPartID,
|
|||
mPartID(aPartID),
|
||||
mIsLastPart(false)
|
||||
{
|
||||
mMultipartChannel = aMultipartChannel;
|
||||
|
||||
// Inherit the load flags from the original channel...
|
||||
mMultipartChannel->GetLoadFlags(&mLoadFlags);
|
||||
|
||||
|
@ -115,7 +113,6 @@ NS_INTERFACE_MAP_BEGIN(nsPartChannel)
|
|||
NS_INTERFACE_MAP_ENTRY(nsIChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIByteRangeRequest)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIMultiPartChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIResponseHeadProvider)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
//
|
||||
|
@ -406,25 +403,6 @@ nsPartChannel::GetIsLastPart(bool *aIsLastPart)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// nsIResponseHeadProvider
|
||||
//
|
||||
|
||||
NS_IMETHODIMP_(mozilla::net::nsHttpResponseHead *)
|
||||
nsPartChannel::GetResponseHead()
|
||||
{
|
||||
return mResponseHead;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPartChannel::VisitResponseHeaders(nsIHttpHeaderVisitor *visitor)
|
||||
{
|
||||
if (!mResponseHead)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
return mResponseHead->VisitHeaders(visitor,
|
||||
mozilla::net::nsHttpHeaderArray::eFilterResponse);
|
||||
}
|
||||
|
||||
//
|
||||
// nsIByteRangeRequest implementation...
|
||||
//
|
||||
|
@ -463,32 +441,6 @@ 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;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPartChannel::GetOriginalResponseHeader(nsACString & aOriginalResponseHeader)
|
||||
{
|
||||
aOriginalResponseHeader = mOriginalResponseHeader;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsPartChannel::SetOriginalResponseHeader(const nsACString& aOriginalResponseHeader)
|
||||
{
|
||||
mOriginalResponseHeader = aOriginalResponseHeader;
|
||||
}
|
||||
|
||||
// nsISupports implementation
|
||||
NS_IMPL_ISUPPORTS(nsMultiMixedConv,
|
||||
nsIStreamConverter,
|
||||
|
@ -521,9 +473,6 @@ nsMultiMixedConv::AsyncConvertData(const char *aFromType, const char *aToType,
|
|||
// in the raw stream.
|
||||
mFinalListener = aListener;
|
||||
|
||||
if (NS_LITERAL_CSTRING(APPLICATION_PACKAGE).Equals(aFromType)) {
|
||||
mPackagedApp = true;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -551,49 +500,6 @@ 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,
|
||||
|
@ -653,43 +559,6 @@ nsMultiMixedConv::OnDataAvailable(nsIRequest *request, nsISupports *context,
|
|||
// skip this check, and try again the next time OnData()
|
||||
// is called.
|
||||
mFirstOnData = true;
|
||||
} else if (mPackagedApp) {
|
||||
// We need to check the line starts with --
|
||||
if (!StringBeginsWith(firstBuffer, NS_LITERAL_CSTRING("--"))) {
|
||||
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));
|
||||
|
||||
// Push the cursor to the token so that the while loop below will
|
||||
// find token from the right position.
|
||||
cursor = tokenPos;
|
||||
|
||||
// Update bufLen to exlude the preamble. Otherwise, the first
|
||||
// |SendData| would claim longer buffer length.
|
||||
bufLen -= mPreamble.Length();
|
||||
}
|
||||
} 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();
|
||||
}
|
||||
|
||||
cursor = buffer;
|
||||
}
|
||||
} else if (!PL_strnstr(cursor, token, mTokenLen + 2)) {
|
||||
char *newBuffer = (char *) realloc(buffer, bufLen + mTokenLen + 1);
|
||||
if (!newBuffer)
|
||||
|
@ -709,23 +578,14 @@ nsMultiMixedConv::OnDataAvailable(nsIRequest *request, nsISupports *context,
|
|||
|
||||
char *token = nullptr;
|
||||
|
||||
// This may get initialized by ParseHeaders and the resulting
|
||||
// HttpResponseHead will be passed to nsPartChannel by SendStart
|
||||
|
||||
if (mProcessingHeaders) {
|
||||
// we were not able to process all the headers
|
||||
// for this "part" given the previous buffer given to
|
||||
// us in the previous OnDataAvailable callback.
|
||||
bool done = false;
|
||||
const char* originalCursor = cursor;
|
||||
rv = ParseHeaders(channel, cursor, bufLen, &done);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Append the content to the original header.
|
||||
if (cursor > originalCursor) {
|
||||
mOriginalResponseHeader.Append(originalCursor, cursor - originalCursor);
|
||||
}
|
||||
|
||||
if (done) {
|
||||
mProcessingHeaders = false;
|
||||
rv = SendStart(channel);
|
||||
|
@ -764,15 +624,9 @@ nsMultiMixedConv::OnDataAvailable(nsIRequest *request, nsISupports *context,
|
|||
mNewPart = false;
|
||||
cursor = token;
|
||||
bool done = false;
|
||||
const char* originalCursor = cursor;
|
||||
rv = ParseHeaders(channel, cursor, bufLen, &done);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Append the content to the original header.
|
||||
if (cursor > originalCursor) {
|
||||
mOriginalResponseHeader.Append(originalCursor, cursor - originalCursor);
|
||||
}
|
||||
|
||||
if (done) {
|
||||
rv = SendStart(channel);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
@ -854,51 +708,23 @@ nsMultiMixedConv::OnStartRequest(nsIRequest *request, nsISupports *ctxt) {
|
|||
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsICacheInfoChannel> cacheChan = do_QueryInterface(request);
|
||||
if (cacheChan) {
|
||||
cacheChan->IsFromCache(&mIsFromCache);
|
||||
}
|
||||
|
||||
// ask the HTTP channel for the content-type and extract the boundary from it.
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel, &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("content-type"), delimiter);
|
||||
if (NS_FAILED(rv) && !mPackagedApp) {
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
// try asking the channel directly
|
||||
rv = channel->GetContentType(delimiter);
|
||||
if (NS_FAILED(rv) && !mPackagedApp) {
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// http://www.w3.org/TR/web-packaging/#streamable-package-format
|
||||
// Although it is compatible with multipart/* this format does not require
|
||||
// the boundary to be included in the header, as it can be ascertained from
|
||||
// the content of the file.
|
||||
if (delimiter.Find(NS_LITERAL_CSTRING(APPLICATION_PACKAGE)) != kNotFound) {
|
||||
mPackagedApp = true;
|
||||
mHasAppContentType = true;
|
||||
mToken.Truncate();
|
||||
mTokenLen = 0;
|
||||
}
|
||||
|
||||
bndry = strstr(delimiter.BeginWriting(), "boundary");
|
||||
|
||||
bool requestSucceeded = true;
|
||||
if (httpChannel) {
|
||||
httpChannel->GetRequestSucceeded(&requestSucceeded);
|
||||
}
|
||||
|
||||
// If the package has the appropriate content type, or if it is a successful
|
||||
// packaged app request, without the required content type, there's no need
|
||||
// for a boundary to be included in this header.
|
||||
if (!bndry && (mHasAppContentType || (mPackagedApp && requestSucceeded))) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!bndry) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -919,7 +745,7 @@ nsMultiMixedConv::OnStartRequest(nsIRequest *request, nsISupports *ctxt) {
|
|||
mToken = boundaryString;
|
||||
mTokenLen = boundaryString.Length();
|
||||
|
||||
if (mTokenLen == 0 && !mPackagedApp) {
|
||||
if (mTokenLen == 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -928,22 +754,10 @@ nsMultiMixedConv::OnStartRequest(nsIRequest *request, nsISupports *ctxt) {
|
|||
|
||||
NS_IMETHODIMP
|
||||
nsMultiMixedConv::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
|
||||
nsresult aStatus) {
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// We should definitely have found a token at this point. Not having one
|
||||
// is clearly an error, so we need to pass it to the listener.
|
||||
// However, since packaged apps usually have the boundary token at the
|
||||
// begining of the content, if the package is served from the cache, and
|
||||
// only metadata was saved for said package (meaning no content is available
|
||||
// and `mFirstOnData` is true) then we wouldn't have a boundary even though
|
||||
// no error has occured.
|
||||
if (mToken.IsEmpty() &&
|
||||
NS_SUCCEEDED(rv) && // don't hide channel error results
|
||||
!(mPackagedApp && mIsFromCache && mFirstOnData)) {
|
||||
aStatus = NS_ERROR_FAILURE;
|
||||
rv = NS_ERROR_FAILURE;
|
||||
nsresult aStatus)
|
||||
{
|
||||
if (mToken.IsEmpty()) { // no token, no love.
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (mPartChannel) {
|
||||
|
@ -964,22 +778,16 @@ nsMultiMixedConv::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
|
|||
// underlying data production problem. we should not be in
|
||||
// the middle of sending data. if we were, mPartChannel,
|
||||
// above, would have been true.
|
||||
|
||||
|
||||
// if we send the start, the URI Loader's m_targetStreamListener, may
|
||||
// be pointing at us causing a nice stack overflow. So, don't call
|
||||
// OnStartRequest! - This breaks necko's semantecs.
|
||||
//(void) mFinalListener->OnStartRequest(request, ctxt);
|
||||
|
||||
(void) mFinalListener->OnStopRequest(request, ctxt, aStatus);
|
||||
} else if (mIsFromCache && mFirstOnData) {
|
||||
// `mFirstOnData` is true if the package's cache entry only holds
|
||||
// metadata and no calls to OnDataAvailable are made.
|
||||
// In this case we would not call OnStopRequest for any of the parts,
|
||||
// so we need to call it here.
|
||||
|
||||
(void) mFinalListener->OnStopRequest(request, ctxt, aStatus);
|
||||
}
|
||||
|
||||
return rv;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -997,9 +805,6 @@ nsMultiMixedConv::nsMultiMixedConv() :
|
|||
mByteRangeEnd = 0;
|
||||
mTotalSent = 0;
|
||||
mIsByteRangeRequest = false;
|
||||
mPackagedApp = false;
|
||||
mHasAppContentType = false;
|
||||
mIsFromCache = false;
|
||||
}
|
||||
|
||||
nsMultiMixedConv::~nsMultiMixedConv() {
|
||||
|
@ -1029,9 +834,7 @@ nsMultiMixedConv::SendStart(nsIChannel *aChannel) {
|
|||
nsresult rv = NS_OK;
|
||||
|
||||
nsCOMPtr<nsIStreamListener> partListener(mFinalListener);
|
||||
// For packaged apps that don't have a content type we want to just
|
||||
// go ahead and serve them with an empty content type
|
||||
if (mContentType.IsEmpty() && !mPackagedApp) {
|
||||
if (mContentType.IsEmpty()) {
|
||||
mContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE);
|
||||
nsCOMPtr<nsIStreamConverterService> serv =
|
||||
do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv);
|
||||
|
@ -1066,16 +869,6 @@ nsMultiMixedConv::SendStart(nsIChannel *aChannel) {
|
|||
// Set up the new part channel...
|
||||
mPartChannel = newChannel;
|
||||
|
||||
// Pass preamble to the channel.
|
||||
mPartChannel->SetPreamble(mPreamble);
|
||||
|
||||
// Pass original http header.
|
||||
mPartChannel->SetOriginalResponseHeader(mOriginalResponseHeader);
|
||||
mOriginalResponseHeader = EmptyCString();
|
||||
|
||||
// We pass the headers to the nsPartChannel
|
||||
mPartChannel->SetResponseHead(mResponseHead.forget());
|
||||
|
||||
rv = mPartChannel->SetContentType(mContentType);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
|
@ -1183,13 +976,6 @@ nsMultiMixedConv::ParseHeaders(nsIChannel *aChannel, char *&aPtr,
|
|||
bool done = false;
|
||||
uint32_t lineFeedIncrement = 1;
|
||||
|
||||
// We only create an nsHttpResponseHead for packaged app channels
|
||||
// It may already be initialized, from a previous call of ParseHeaders
|
||||
// since the headers for a single part may come in more then one chunk
|
||||
if (mPackagedApp && !mResponseHead) {
|
||||
mResponseHead = new mozilla::net::nsHttpResponseHead();
|
||||
}
|
||||
|
||||
mContentLength = UINT64_MAX; // XXX what if we were already called?
|
||||
while (cursorLen && (newLine = (char *) memchr(cursor, nsCRT::LF, cursorLen))) {
|
||||
// adjust for linefeeds
|
||||
|
@ -1214,11 +1000,6 @@ nsMultiMixedConv::ParseHeaders(nsIChannel *aChannel, char *&aPtr,
|
|||
char tmpChar = *newLine;
|
||||
*newLine = '\0'; // cursor is now null terminated
|
||||
|
||||
if (mResponseHead) {
|
||||
nsAutoCString tmpHeader(cursor);
|
||||
mResponseHead->ParseHeaderLine(tmpHeader);
|
||||
}
|
||||
|
||||
char *colon = (char *) strchr(cursor, ':');
|
||||
if (colon) {
|
||||
*colon = '\0';
|
||||
|
@ -1232,17 +1013,6 @@ nsMultiMixedConv::ParseHeaders(nsIChannel *aChannel, char *&aPtr,
|
|||
// examine header
|
||||
if (headerStr.LowerCaseEqualsLiteral("content-type")) {
|
||||
mContentType = headerVal;
|
||||
|
||||
// If the HTTP channel doesn't have an application/package
|
||||
// content type we still want to serve the resource, but with the
|
||||
// "application/octet-stream" header, so we prevent execution of
|
||||
// unsafe content
|
||||
if (mPackagedApp && !mHasAppContentType) {
|
||||
mContentType = APPLICATION_OCTET_STREAM;
|
||||
mResponseHead->SetHeader(mozilla::net::nsHttp::Content_Type,
|
||||
mContentType);
|
||||
mResponseHead->SetContentType(mContentType);
|
||||
}
|
||||
} else if (headerStr.LowerCaseEqualsLiteral("content-length")) {
|
||||
mContentLength = nsCRT::atoll(headerVal.get());
|
||||
} else if (headerStr.LowerCaseEqualsLiteral("content-disposition")) {
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "nsIMultiPartChannel.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsIResponseHeadProvider.h"
|
||||
#include "nsHttpResponseHead.h"
|
||||
|
||||
#define NS_MULTIMIXEDCONVERTER_CID \
|
||||
|
@ -34,7 +33,6 @@
|
|||
//
|
||||
class nsPartChannel final : public nsIChannel,
|
||||
public nsIByteRangeRequest,
|
||||
public nsIResponseHeadProvider,
|
||||
public nsIMultiPartChannel
|
||||
{
|
||||
public:
|
||||
|
@ -43,8 +41,6 @@ public:
|
|||
|
||||
void InitializeByteRange(int64_t aStart, int64_t aEnd);
|
||||
void SetIsLastPart() { mIsLastPart = true; }
|
||||
void SetPreamble(const nsACString& aPreamble);
|
||||
void SetOriginalResponseHeader(const nsACString& aOriginalResponseHeader);
|
||||
nsresult SendOnStartRequest(nsISupports* aContext);
|
||||
nsresult SendOnDataAvailable(nsISupports* aContext, nsIInputStream* aStream,
|
||||
uint64_t aOffset, uint32_t aLen);
|
||||
|
@ -58,7 +54,6 @@ public:
|
|||
NS_DECL_NSIREQUEST
|
||||
NS_DECL_NSICHANNEL
|
||||
NS_DECL_NSIBYTERANGEREQUEST
|
||||
NS_DECL_NSIRESPONSEHEADPROVIDER
|
||||
NS_DECL_NSIMULTIPARTCHANNEL
|
||||
|
||||
protected:
|
||||
|
@ -88,11 +83,6 @@ protected:
|
|||
uint32_t mPartID; // unique ID that can be used to identify
|
||||
// this part of the multipart document
|
||||
bool mIsLastPart;
|
||||
|
||||
nsCString mPreamble;
|
||||
|
||||
// The original http response header.
|
||||
nsCString mOriginalResponseHeader;
|
||||
};
|
||||
|
||||
// The nsMultiMixedConv stream converter converts a stream of type "multipart/x-mixed-replace"
|
||||
|
@ -152,7 +142,6 @@ 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?
|
||||
|
@ -182,27 +171,6 @@ protected:
|
|||
bool mIsByteRangeRequest;
|
||||
|
||||
uint32_t mCurrentPartID;
|
||||
|
||||
// If true, it means the packaged app had an "application/package" header
|
||||
// Otherwise, we remove "Content-Type" headers from files in the package
|
||||
bool mHasAppContentType;
|
||||
// This is true if the content-type is application/package
|
||||
// Streamable packages don't require the boundary in the header
|
||||
// as it can be ascertained from the package file.
|
||||
bool mPackagedApp;
|
||||
nsAutoPtr<mozilla::net::nsHttpResponseHead> mResponseHead;
|
||||
// It is necessary to know if the content is coming from the cache
|
||||
// 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;
|
||||
|
||||
// The original http response header of each subresource.
|
||||
nsCString mOriginalResponseHeader;
|
||||
};
|
||||
|
||||
#endif /* __nsmultimixedconv__h__ */
|
||||
|
|
|
@ -1,304 +0,0 @@
|
|||
// Tests:
|
||||
// test_multipart
|
||||
// Loads the multipart file returned by contentHandler()
|
||||
// The boundary is ascertained from the first line in the multipart file
|
||||
// test_multipart_with_boundary
|
||||
// Loads the multipart file returned by contentHandler_with_boundary()
|
||||
// The boundary is given in the Content-Type headers, and is also present
|
||||
// in the first line of the file.
|
||||
// test_multipart_chunked_headers
|
||||
// Tests that the headers are properly passed even when they come in multiple
|
||||
// chunks (several calls to OnDataAvailable). It first passes the first 60
|
||||
// characters, then the rest of the response.
|
||||
|
||||
// testData.token - the multipart file's boundary
|
||||
// Call testData.getData() to get the file contents as a string
|
||||
|
||||
// multipartListener
|
||||
// - a listener that checks that the multipart file is correctly split into multiple parts
|
||||
|
||||
// headerListener
|
||||
// - checks that the headers for each part is set correctly
|
||||
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
var httpserver = null;
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "uri", function() {
|
||||
return "http://localhost:" + httpserver.identity.primaryPort;
|
||||
});
|
||||
|
||||
function make_channel(url) {
|
||||
return NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true});
|
||||
}
|
||||
|
||||
function contentHandler(metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", 'application/package');
|
||||
var body = testData.getData();
|
||||
response.bodyOutputStream.write(body, body.length);
|
||||
}
|
||||
|
||||
function contentHandler_with_boundary(metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", 'application/package; boundary="'+testData.token+'"');
|
||||
var body = testData.getData();
|
||||
response.bodyOutputStream.write(body, body.length);
|
||||
}
|
||||
|
||||
function contentHandler_chunked_headers(metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", 'application/package');
|
||||
var body = testData.getData();
|
||||
|
||||
response.bodyOutputStream.write(body.substring(0,60), 60);
|
||||
response.processAsync();
|
||||
do_timeout(5, function() {
|
||||
response.bodyOutputStream.write(body.substring(60), body.length-60);
|
||||
response.finish();
|
||||
});
|
||||
}
|
||||
|
||||
function contentHandler_type_missing(metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", 'text/plain');
|
||||
var body = testData.getData();
|
||||
response.bodyOutputStream.write(body, body.length);
|
||||
}
|
||||
|
||||
function contentHandler_with_package_header(chunkSize, metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", 'application/package');
|
||||
var body = testData.packageHeader + testData.getData();
|
||||
|
||||
response.bodyOutputStream.write(body.substring(0,chunkSize), chunkSize);
|
||||
response.processAsync();
|
||||
do_timeout(5, function() {
|
||||
response.bodyOutputStream.write(body.substring(chunkSize), body.length-chunkSize);
|
||||
response.finish();
|
||||
});
|
||||
}
|
||||
|
||||
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" },
|
||||
{ headers: ["Content-Location: /scripts/helpers/math.js", "Content-Type: text/javascript"], data: "export function sum(nums) { ... }\r\n...\r\n", type: "text/javascript" }
|
||||
],
|
||||
token : "gc0pJq0M:08jU534c0p",
|
||||
getData: function() {
|
||||
var str = "";
|
||||
for (var i in this.content) {
|
||||
str += "--" + this.token + "\r\n";
|
||||
for (var j in this.content[i].headers) {
|
||||
str += this.content[i].headers[j] + "\r\n";
|
||||
}
|
||||
str += "\r\n";
|
||||
str += this.content[i].data + "\r\n";
|
||||
}
|
||||
|
||||
str += "--" + this.token + "--";
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
function multipartListener(test, badContentType, shouldVerifyPackageHeader) {
|
||||
this._buffer = "";
|
||||
this.testNum = 0;
|
||||
this.test = test;
|
||||
this.numTests = this.test.content.length;
|
||||
// If set to true, that means the package is missing the application/package
|
||||
// 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) {
|
||||
equal(buffer, this.test.content[this.testNum].data);
|
||||
equal(request.QueryInterface(Ci.nsIChannel).contentType,
|
||||
this.badContentType ? "application/octet-stream" : this.test.content[this.testNum].type);
|
||||
if (++this.testNum == this.numTests) {
|
||||
run_next_test();
|
||||
}
|
||||
}
|
||||
|
||||
multipartListener.prototype.QueryInterface = function(iid) {
|
||||
if (iid.equals(Components.interfaces.nsIStreamListener) ||
|
||||
iid.equals(Components.interfaces.nsIRequestObserver) ||
|
||||
iid.equals(Components.interfaces.nsISupports))
|
||||
return this;
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
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);
|
||||
if (headerProvider) {
|
||||
headerProvider.visitResponseHeaders(this.headerListener);
|
||||
}
|
||||
|
||||
// Verify the original header if the request is a multipart channel.
|
||||
let partChannel = request.QueryInterface(Ci.nsIMultiPartChannel);
|
||||
if (partChannel) {
|
||||
let originalHeader = this.test.content[this.testNum].headers.join("\r\n") + "\r\n\r\n";
|
||||
equal(originalHeader, partChannel.originalResponseHeader, "Oringinal header check.");
|
||||
}
|
||||
}
|
||||
|
||||
multipartListener.prototype.onDataAvailable = function(request, context, stream, offset, count) {
|
||||
try {
|
||||
this._buffer = this._buffer.concat(read_stream(stream, count));
|
||||
} catch (ex) {
|
||||
do_throw("Error in onDataAvailable: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
multipartListener.prototype.onStopRequest = function(request, context, status) {
|
||||
try {
|
||||
equal(this.headerListener.index, this.test.content[this.testNum].headers.length);
|
||||
this.responseHandler(request, this._buffer);
|
||||
} catch (ex) {
|
||||
do_throw("Error in closure function: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
function headerListener(headers, badContentType) {
|
||||
this.expectedHeaders = headers;
|
||||
this.badContentType = badContentType;
|
||||
this.index = 0;
|
||||
}
|
||||
|
||||
headerListener.prototype.QueryInterface = function(iid) {
|
||||
if (iid.equals(Components.interfaces.nsIHttpHeaderVisitor) ||
|
||||
iid.equals(Components.interfaces.nsISupports))
|
||||
return this;
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
headerListener.prototype.visitHeader = function(header, value) {
|
||||
ok(this.index <= this.expectedHeaders.length);
|
||||
if (!this.badContentType)
|
||||
equal(header + ": " + value, this.expectedHeaders[this.index]);
|
||||
this.index++;
|
||||
}
|
||||
|
||||
function test_multipart() {
|
||||
var streamConv = Cc["@mozilla.org/streamConverters;1"]
|
||||
.getService(Ci.nsIStreamConverterService);
|
||||
var conv = streamConv.asyncConvertData("application/package",
|
||||
"*/*",
|
||||
new multipartListener(testData),
|
||||
null);
|
||||
|
||||
var chan = make_channel(uri + "/multipart");
|
||||
chan.asyncOpen2(conv);
|
||||
}
|
||||
|
||||
function test_multipart_with_boundary() {
|
||||
var streamConv = Cc["@mozilla.org/streamConverters;1"]
|
||||
.getService(Ci.nsIStreamConverterService);
|
||||
var conv = streamConv.asyncConvertData("application/package",
|
||||
"*/*",
|
||||
new multipartListener(testData),
|
||||
null);
|
||||
|
||||
var chan = make_channel(uri + "/multipart2");
|
||||
chan.asyncOpen2(conv);
|
||||
}
|
||||
|
||||
function test_multipart_chunked_headers() {
|
||||
var streamConv = Cc["@mozilla.org/streamConverters;1"]
|
||||
.getService(Ci.nsIStreamConverterService);
|
||||
var conv = streamConv.asyncConvertData("application/package",
|
||||
"*/*",
|
||||
new multipartListener(testData),
|
||||
null);
|
||||
|
||||
var chan = make_channel(uri + "/multipart3");
|
||||
chan.asyncOpen2(conv);
|
||||
}
|
||||
|
||||
function test_multipart_content_type_other() {
|
||||
var streamConv = Cc["@mozilla.org/streamConverters;1"]
|
||||
.getService(Ci.nsIStreamConverterService);
|
||||
|
||||
var conv = streamConv.asyncConvertData("application/package",
|
||||
"*/*",
|
||||
new multipartListener(testData, true),
|
||||
null);
|
||||
|
||||
var chan = make_channel(uri + "/multipart4");
|
||||
chan.asyncOpen2(conv);
|
||||
}
|
||||
|
||||
function test_multipart_package_header(aChunkSize) {
|
||||
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_" + aChunkSize);
|
||||
chan.asyncOpen2(conv);
|
||||
}
|
||||
|
||||
// Bug 1212223 - Test multipart with package header and different chunk size.
|
||||
// Use explict function name to make the test case log more readable.
|
||||
|
||||
function test_multipart_package_header_50() {
|
||||
return test_multipart_package_header(50);
|
||||
}
|
||||
|
||||
function test_multipart_package_header_100() {
|
||||
return test_multipart_package_header(100);
|
||||
}
|
||||
|
||||
function test_multipart_package_header_150() {
|
||||
return test_multipart_package_header(150);
|
||||
}
|
||||
|
||||
function test_multipart_package_header_200() {
|
||||
return test_multipart_package_header(200);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
httpserver = new HttpServer();
|
||||
httpserver.registerPathHandler("/multipart", contentHandler);
|
||||
httpserver.registerPathHandler("/multipart2", contentHandler_with_boundary);
|
||||
httpserver.registerPathHandler("/multipart3", contentHandler_chunked_headers);
|
||||
httpserver.registerPathHandler("/multipart4", contentHandler_type_missing);
|
||||
|
||||
// Bug 1212223 - Test multipart with package header and different chunk size.
|
||||
httpserver.registerPathHandler("/multipart5_50", contentHandler_with_package_header.bind(null, 50));
|
||||
httpserver.registerPathHandler("/multipart5_100", contentHandler_with_package_header.bind(null, 100));
|
||||
httpserver.registerPathHandler("/multipart5_150", contentHandler_with_package_header.bind(null, 150));
|
||||
httpserver.registerPathHandler("/multipart5_200", contentHandler_with_package_header.bind(null, 200));
|
||||
|
||||
httpserver.start(-1);
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_test(test_multipart);
|
||||
add_test(test_multipart_with_boundary);
|
||||
add_test(test_multipart_chunked_headers);
|
||||
add_test(test_multipart_content_type_other);
|
||||
|
||||
// Bug 1212223 - Test multipart with package header and different chunk size.
|
||||
add_test(test_multipart_package_header_50);
|
||||
add_test(test_multipart_package_header_100);
|
||||
add_test(test_multipart_package_header_150);
|
||||
add_test(test_multipart_package_header_200);
|
|
@ -343,7 +343,6 @@ firefox-appdir = browser
|
|||
# The local cert service used by this test is not currently shipped on Android
|
||||
skip-if = os == "android"
|
||||
[test_1073747.js]
|
||||
[test_multipart_streamconv_application_package.js]
|
||||
[test_safeoutputstream_append.js]
|
||||
[test_suspend_channel_before_connect.js]
|
||||
[test_inhibit_caching.js]
|
||||
|
|
|
@ -505,17 +505,5 @@ ExternalHelperAppParent::GetIsLastPart(bool* aIsLastPart)
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetPreamble(nsACString & aPreamble)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetOriginalResponseHeader(nsACString & aOriginalResponseHeader)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
Загрузка…
Ссылка в новой задаче