Bug 783878 - Part 1: Make nsXMLHttpRequest aware of the length of uploads. r=sicking

This commit is contained in:
Josh Matthews 2012-09-19 18:15:32 -04:00
parent da637b19df
commit e15a71d66a
7 changed files with 67 additions and 34 deletions

View File

@ -388,6 +388,7 @@ interface nsIXMLHttpRequest : nsISupports
[scriptable, uuid(840d0d00-e83e-4a29-b3c7-67e96e90a499)]
interface nsIXHRSendable : nsISupports {
void getSendInfo(out nsIInputStream body,
out uint64_t contentLength,
out ACString contentType,
out ACString charset);
};

View File

@ -374,6 +374,7 @@ nsDOMFileBase::GetFileInfo(indexedDB::FileManager* aFileManager)
NS_IMETHODIMP
nsDOMFileBase::GetSendInfo(nsIInputStream** aBody,
uint64_t* aContentLength,
nsACString& aContentType,
nsACString& aCharset)
{
@ -383,6 +384,9 @@ nsDOMFileBase::GetSendInfo(nsIInputStream** aBody,
rv = this->GetInternalStream(getter_AddRefs(stream));
NS_ENSURE_SUCCESS(rv, rv);
rv = this->GetSize(aContentLength);
NS_ENSURE_SUCCESS(rv, rv);
nsString contentType;
rv = this->GetType(contentType);
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -103,8 +103,8 @@ nsFormData::Append(const nsAString& aName, nsIVariant* aValue)
// nsIXHRSendable
NS_IMETHODIMP
nsFormData::GetSendInfo(nsIInputStream** aBody, nsACString& aContentType,
nsACString& aCharset)
nsFormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
nsACString& aContentType, nsACString& aCharset)
{
nsFSMultipartFormData fs(NS_LITERAL_CSTRING("UTF-8"), nullptr);
@ -119,7 +119,8 @@ nsFormData::GetSendInfo(nsIInputStream** aBody, nsACString& aContentType,
fs.GetContentType(aContentType);
aCharset.Truncate();
NS_ADDREF(*aBody = fs.GetSubmissionBody());
*aContentLength = 0;
NS_ADDREF(*aBody = fs.GetSubmissionBody(aContentLength));
return NS_OK;
}

View File

@ -2421,7 +2421,7 @@ nsXMLHttpRequest::SendAsBinary(const nsAString &aBody,
}
static nsresult
GetRequestBody(nsIDOMDocument* aDoc, nsIInputStream** aResult,
GetRequestBody(nsIDOMDocument* aDoc, nsIInputStream** aResult, uint64* aContentLength,
nsACString& aContentType, nsACString& aCharset)
{
aContentType.AssignLiteral("application/xml");
@ -2455,46 +2455,57 @@ GetRequestBody(nsIDOMDocument* aDoc, nsIInputStream** aResult,
output->Close();
uint32_t length;
rv = storStream->GetLength(&length);
NS_ENSURE_SUCCESS(rv, rv);
*aContentLength = length;
return storStream->NewInputStream(0, aResult);
}
static nsresult
GetRequestBody(const nsAString& aString, nsIInputStream** aResult,
GetRequestBody(const nsAString& aString, nsIInputStream** aResult, uint64* aContentLength,
nsACString& aContentType, nsACString& aCharset)
{
aContentType.AssignLiteral("text/plain");
aCharset.AssignLiteral("UTF-8");
return NS_NewCStringInputStream(aResult, NS_ConvertUTF16toUTF8(aString));
nsCString converted = NS_ConvertUTF16toUTF8(aString);
*aContentLength = converted.Length();
return NS_NewCStringInputStream(aResult, converted);
}
static nsresult
GetRequestBody(nsIInputStream* aStream, nsIInputStream** aResult,
GetRequestBody(nsIInputStream* aStream, nsIInputStream** aResult, uint64* aContentLength,
nsACString& aContentType, nsACString& aCharset)
{
aContentType.AssignLiteral("text/plain");
aCharset.Truncate();
nsresult rv = aStream->Available(aContentLength);
NS_ENSURE_SUCCESS(rv, rv);
NS_ADDREF(*aResult = aStream);
return NS_OK;
}
static nsresult
GetRequestBody(nsIXHRSendable* aSendable, nsIInputStream** aResult,
GetRequestBody(nsIXHRSendable* aSendable, nsIInputStream** aResult, uint64_t* aContentLength,
nsACString& aContentType, nsACString& aCharset)
{
return aSendable->GetSendInfo(aResult, aContentType, aCharset);
return aSendable->GetSendInfo(aResult, aContentLength, aContentType, aCharset);
}
static nsresult
GetRequestBody(ArrayBuffer* aArrayBuffer, nsIInputStream** aResult,
GetRequestBody(ArrayBuffer* aArrayBuffer, nsIInputStream** aResult, uint64_t* aContentLength,
nsACString& aContentType, nsACString& aCharset)
{
aContentType.SetIsVoid(true);
aCharset.Truncate();
int32_t length = aArrayBuffer->Length();
*aContentLength = length;
char* data = reinterpret_cast<char*>(aArrayBuffer->Data());
nsCOMPtr<nsIInputStream> stream;
@ -2508,7 +2519,7 @@ GetRequestBody(ArrayBuffer* aArrayBuffer, nsIInputStream** aResult,
}
static nsresult
GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult,
GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult, uint64_t* aContentLength,
nsACString& aContentType, nsACString& aCharset)
{
*aResult = nullptr;
@ -2529,7 +2540,7 @@ GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult,
// document?
nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(supports);
if (doc) {
return GetRequestBody(doc, aResult, aContentType, aCharset);
return GetRequestBody(doc, aResult, aContentLength, aContentType, aCharset);
}
// nsISupportsString?
@ -2538,19 +2549,19 @@ GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult,
nsAutoString string;
wstr->GetData(string);
return GetRequestBody(string, aResult, aContentType, aCharset);
return GetRequestBody(string, aResult, aContentLength, aContentType, aCharset);
}
// nsIInputStream?
nsCOMPtr<nsIInputStream> stream = do_QueryInterface(supports);
if (stream) {
return GetRequestBody(stream, aResult, aContentType, aCharset);
return GetRequestBody(stream, aResult, aContentLength, aContentType, aCharset);
}
// nsIXHRSendable?
nsCOMPtr<nsIXHRSendable> sendable = do_QueryInterface(supports);
if (sendable) {
return GetRequestBody(sendable, aResult, aContentType, aCharset);
return GetRequestBody(sendable, aResult, aContentLength, aContentType, aCharset);
}
// ArrayBuffer?
@ -2575,7 +2586,7 @@ GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult,
ac.construct(cx, obj);
if (JS_IsArrayBufferObject(obj, cx)) {
ArrayBuffer buf(cx, obj);
return GetRequestBody(&buf, aResult, aContentType, aCharset);
return GetRequestBody(&buf, aResult, aContentLength, aContentType, aCharset);
}
}
}
@ -2584,6 +2595,7 @@ GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult,
// Makes us act as if !aBody, don't upload anything
aContentType.AssignLiteral("text/plain");
aCharset.AssignLiteral("UTF-8");
*aContentLength = 0;
return NS_OK;
}
@ -2596,18 +2608,18 @@ GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult,
nsString string;
string.Adopt(data, len);
return GetRequestBody(string, aResult, aContentType, aCharset);
return GetRequestBody(string, aResult, aContentLength, aContentType, aCharset);
}
/* static */
nsresult
nsXMLHttpRequest::GetRequestBody(nsIVariant* aVariant,
const Nullable<RequestBody>& aBody,
nsIInputStream** aResult,
nsIInputStream** aResult, uint64* aContentLength,
nsACString& aContentType, nsACString& aCharset)
{
if (aVariant) {
return ::GetRequestBody(aVariant, aResult, aContentType, aCharset);
return ::GetRequestBody(aVariant, aResult, aContentLength, aContentType, aCharset);
}
const RequestBody& body = aBody.Value();
@ -2615,7 +2627,8 @@ nsXMLHttpRequest::GetRequestBody(nsIVariant* aVariant,
switch (body.GetType()) {
case nsXMLHttpRequest::RequestBody::ArrayBuffer:
{
return ::GetRequestBody(value.mArrayBuffer, aResult, aContentType, aCharset);
return ::GetRequestBody(value.mArrayBuffer, aResult, aContentLength,
aContentType, aCharset);
}
case nsXMLHttpRequest::RequestBody::Blob:
{
@ -2623,16 +2636,17 @@ nsXMLHttpRequest::GetRequestBody(nsIVariant* aVariant,
nsCOMPtr<nsIXHRSendable> sendable = do_QueryInterface(value.mBlob, &rv);
NS_ENSURE_SUCCESS(rv, rv);
return ::GetRequestBody(sendable, aResult, aContentType, aCharset);
return ::GetRequestBody(sendable, aResult, aContentLength, aContentType, aCharset);
}
case nsXMLHttpRequest::RequestBody::Document:
{
nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(value.mDocument);
return ::GetRequestBody(document, aResult, aContentType, aCharset);
return ::GetRequestBody(document, aResult, aContentLength, aContentType, aCharset);
}
case nsXMLHttpRequest::RequestBody::DOMString:
{
return ::GetRequestBody(*value.mString, aResult, aContentType, aCharset);
return ::GetRequestBody(*value.mString, aResult, aContentLength,
aContentType, aCharset);
}
case nsXMLHttpRequest::RequestBody::FormData:
{
@ -2640,11 +2654,12 @@ nsXMLHttpRequest::GetRequestBody(nsIVariant* aVariant,
nsCOMPtr<nsIXHRSendable> sendable = do_QueryInterface(value.mFormData, &rv);
NS_ENSURE_SUCCESS(rv, rv);
return ::GetRequestBody(sendable, aResult, aContentType, aCharset);
return ::GetRequestBody(sendable, aResult, aContentLength, aContentType, aCharset);
}
case nsXMLHttpRequest::RequestBody::InputStream:
{
return ::GetRequestBody(value.mStream, aResult, aContentType, aCharset);
return ::GetRequestBody(value.mStream, aResult, aContentLength,
aContentType, aCharset);
}
default:
{
@ -2788,7 +2803,7 @@ nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable<RequestBody>& aBody)
nsCOMPtr<nsIInputStream> postDataStream;
rv = GetRequestBody(aVariant, aBody, getter_AddRefs(postDataStream),
defaultContentType, charset);
&mUploadTotal, defaultContentType, charset);
NS_ENSURE_SUCCESS(rv, rv);
if (postDataStream) {
@ -2851,9 +2866,6 @@ nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable<RequestBody>& aBody)
}
mUploadComplete = false;
uint64_t uploadTotal = 0;
postDataStream->Available(&uploadTotal);
mUploadTotal = uploadTotal;
// We want to use a newer version of the upload channel that won't
// ignore the necessary headers for an empty Content-Type.
@ -2862,7 +2874,7 @@ nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable<RequestBody>& aBody)
NS_ASSERTION(uploadChannel2, "http must support nsIUploadChannel2");
if (uploadChannel2) {
uploadChannel2->ExplicitSetUploadStream(postDataStream, contentType,
-1, method, false);
mUploadTotal, method, false);
}
else {
// http channel doesn't support the new nsIUploadChannel2. Emulate
@ -2872,7 +2884,7 @@ nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable<RequestBody>& aBody)
}
nsCOMPtr<nsIUploadChannel> uploadChannel =
do_QueryInterface(httpChannel);
uploadChannel->SetUploadStream(postDataStream, contentType, -1);
uploadChannel->SetUploadStream(postDataStream, contentType, mUploadTotal);
// Reset the method to its original value
httpChannel->SetRequestMethod(method);
}

View File

@ -345,6 +345,7 @@ private:
static nsresult GetRequestBody(nsIVariant* aVariant,
const Nullable<RequestBody>& aBody,
nsIInputStream** aResult,
uint64_t* aContentLength,
nsACString& aContentType,
nsACString& aCharset);

View File

@ -169,7 +169,7 @@ public:
NS_LITERAL_CSTRING("multipart/form-data; boundary=") + mBoundary;
}
nsIInputStream* GetSubmissionBody();
nsIInputStream* GetSubmissionBody(uint64_t* aContentLength);
protected:
@ -201,6 +201,11 @@ private:
* submission.
*/
nsCString mBoundary;
/**
* The total length in bytes of the streams that make up mPostDataStream
*/
uint64_t mTotalLength;
};
/**

View File

@ -378,6 +378,7 @@ nsFSMultipartFormData::nsFSMultipartFormData(const nsACString& aCharset,
{
mPostDataStream =
do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
mTotalLength = 0;
mBoundary.AssignLiteral("---------------------------");
mBoundary.AppendInt(rand());
@ -391,7 +392,7 @@ nsFSMultipartFormData::~nsFSMultipartFormData()
}
nsIInputStream*
nsFSMultipartFormData::GetSubmissionBody()
nsFSMultipartFormData::GetSubmissionBody(uint64_t* aContentLength)
{
// Finish data
mPostDataChunk += NS_LITERAL_CSTRING("--") + mBoundary
@ -400,6 +401,7 @@ nsFSMultipartFormData::GetSubmissionBody()
// Add final data input stream
AddPostDataStream();
*aContentLength = mTotalLength;
return mPostDataStream;
}
@ -513,6 +515,11 @@ nsFSMultipartFormData::AddNameFilePair(const nsAString& aName,
AddPostDataStream();
mPostDataStream->AppendStream(fileStream);
uint64_t size;
nsresult rv = aBlob->GetSize(&size);
NS_ENSURE_SUCCESS(rv, rv);
mTotalLength += size;
}
// CRLF after file
@ -536,7 +543,8 @@ nsFSMultipartFormData::GetEncodedSubmission(nsIURI* aURI,
GetContentType(contentType);
mimeStream->AddHeader("Content-Type", contentType.get());
mimeStream->SetAddContentLength(true);
mimeStream->SetData(GetSubmissionBody());
uint64_t unused;
mimeStream->SetData(GetSubmissionBody(&unused));
*aPostDataStream = mimeStream.forget().get();
@ -554,6 +562,7 @@ nsFSMultipartFormData::AddPostDataStream()
NS_ASSERTION(postDataChunkStream, "Could not open a stream for POST!");
if (postDataChunkStream) {
mPostDataStream->AppendStream(postDataChunkStream);
mTotalLength += mPostDataChunk.Length();
}
mPostDataChunk.Truncate();