--- a/content/base/public/Makefile.in
+++ b/content/base/public/Makefile.in
@@ -88,16 +88,17 @@ SDK_XPIDLSRCS = \
nsISelection.idl \
$(NULL)
XPIDLSRCS = \
nsIChromeRegistry.idl \
nsIContentPolicy.idl \
nsIDocumentEncoder.idl \
nsIDOMFile.idl \
+ nsIDOMFileInternal.idl \
nsIDOMFileList.idl \
nsIDOMFileException.idl \
nsIDOMParser.idl \
nsIDOMSerializer.idl \
nsISelection2.idl \
nsISelectionController.idl \
nsISelectionDisplay.idl \
nsISelectionListener.idl \
--- a/content/base/public/nsDOMFile.h
+++ b/content/base/public/nsDOMFile.h
@@ -36,32 +36,35 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsDOMFile_h__
#define nsDOMFile_h__
#include "nsICharsetDetectionObserver.h"
#include "nsIDOMFile.h"
+#include "nsIDOMFileInternal.h"
#include "nsIDOMFileList.h"
#include "nsIInputStream.h"
#include "nsCOMArray.h"
#include "nsCOMPtr.h"
#include "nsString.h"
class nsIDOMDocument;
class nsIFile;
class nsIInputStream;
class nsDOMFile : public nsIDOMFile,
+ public nsIDOMFileInternal,
public nsICharsetDetectionObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMFILE
+ NS_DECL_NSIDOMFILEINTERNAL
nsDOMFile(nsIFile *aFile)
: mFile(aFile)
{}
~nsDOMFile() {}
// from nsICharsetDetectionObserver
NS_IMETHOD Notify(const char *aCharset, nsDetectionConfident aConf);
new file mode 100644
--- /dev/null
+++ b/content/base/public/nsIDOMFileInternal.idl
@@ -0,0 +1,46 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "domstubs.idl"
+
+interface nsIFile;
+
+[scriptable, uuid(047CA6C4-52B3-46F1-8976-E198B724F72F)]
+interface nsIDOMFileInternal : nsISupports
+{
+ attribute nsIFile internalFile;
+};
--- a/content/base/src/nsDOMFile.cpp
+++ b/content/base/src/nsDOMFile.cpp
@@ -63,16 +63,17 @@
#include "plbase64.h"
#include "prmem.h"
// nsDOMFile implementation
NS_INTERFACE_MAP_BEGIN(nsDOMFile)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
NS_INTERFACE_MAP_ENTRY(nsIDOMFile)
+ NS_INTERFACE_MAP_ENTRY(nsIDOMFileInternal)
NS_INTERFACE_MAP_ENTRY(nsICharsetDetectionObserver)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(File)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsDOMFile)
NS_IMPL_RELEASE(nsDOMFile)
static nsresult
@@ -142,16 +143,30 @@ nsDOMFile::GetAsText(const nsAString &aC
rv = alias->GetPreferred(charsetGuess, charset);
NS_ENSURE_SUCCESS(rv, rv);
return ConvertStream(stream, charset.get(), aResult);
}
NS_IMETHODIMP
+nsDOMFile::GetInternalFile(nsIFile **aFile)
+{
+ NS_IF_ADDREF(*aFile = mFile);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMFile::SetInternalFile(nsIFile *aFile)
+{
+ mFile = aFile;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
nsDOMFile::GetAsDataURL(nsAString &aResult)
{
aResult.AssignLiteral("data:");
nsresult rv;
nsCOMPtr<nsIMIMEService> mimeService =
do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -40,34 +40,39 @@
#include "nsIXPConnect.h"
#include "nsICharsetConverterManager.h"
#include "nsLayoutCID.h"
#include "nsXPIDLString.h"
#include "nsReadableUtils.h"
#include "nsIURI.h"
#include "nsILoadGroup.h"
#include "nsNetUtil.h"
+#include "nsStreamUtils.h"
#include "nsThreadUtils.h"
#include "nsIUploadChannel.h"
+#include "nsIUploadChannel2.h"
#include "nsIDOMSerializer.h"
#include "nsXPCOM.h"
#include "nsISupportsPrimitives.h"
#include "nsGUIEvent.h"
#include "nsIPrivateDOMEvent.h"
#include "prprf.h"
#include "nsIDOMEventListener.h"
#include "nsIJSContextStack.h"
#include "nsJSEnvironment.h"
#include "nsIScriptSecurityManager.h"
#include "nsWeakPtr.h"
#include "nsICharsetAlias.h"
#include "nsIScriptGlobalObject.h"
#include "nsIDOMClassInfo.h"
#include "nsIDOMElement.h"
+#include "nsIDOMFileInternal.h"
#include "nsIDOMWindow.h"
+#include "nsIMIMEService.h"
+#include "nsCExternalHandlerService.h"
#include "nsIVariant.h"
#include "nsVariant.h"
#include "nsIParser.h"
#include "nsLoadListenerProxy.h"
#include "nsStringStream.h"
#include "nsIStreamConverterService.h"
#include "nsICachingChannel.h"
#include "nsContentUtils.h"
@@ -2353,16 +2358,47 @@ nsXMLHttpRequest::Send(nsIVariant *aBody
wstr->GetData(serial);
} else {
// stream?
nsCOMPtr<nsIInputStream> stream(do_QueryInterface(supports));
if (stream) {
postDataStream = stream;
charset.Truncate();
}
+ else {
+ // nsIDOMFile?
+ nsCOMPtr<nsIDOMFileInternal> file(do_QueryInterface(supports));
+
+ if (file) {
+ nsCOMPtr<nsIFile> internalFile;
+ rv = file->GetInternalFile(getter_AddRefs(internalFile));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIInputStream> stream;
+ rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), internalFile);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Feed local file input stream into our upload channel
+ if (stream) {
+ postDataStream = stream;
+ charset.Truncate();
+ defaultContentType.Truncate();
+
+ nsCOMPtr<nsIMIMEService> mimeService =
+ do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCAutoString mediaType;
+ rv = mimeService->GetTypeFromFile(internalFile, mediaType);
+ if (NS_SUCCEEDED(rv)) {
+ defaultContentType = mediaType;
+ }
+ }
+ }
+ }
}
}
}
break;
case nsIDataType::VTYPE_VOID:
case nsIDataType::VTYPE_EMPTY:
// Makes us act as if !aBody, don't upload anything
break;
@@ -2383,17 +2419,17 @@ nsXMLHttpRequest::Send(nsIVariant *aBody
NS_ENSURE_SUCCESS(rv, rv);
rv = converter->ConvertToInputStream(serial,
getter_AddRefs(postDataStream));
NS_ENSURE_SUCCESS(rv, rv);
}
if (postDataStream) {
- nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
+ nsCOMPtr<nsIUploadChannel2> uploadChannel(do_QueryInterface(httpChannel));
NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel");
// If no content type header was set by the client, we set it to
// application/xml.
nsCAutoString contentType;
if (NS_FAILED(httpChannel->
GetRequestHeader(NS_LITERAL_CSTRING("Content-Type"),
contentType)) ||
@@ -2422,25 +2458,36 @@ nsXMLHttpRequest::Send(nsIVariant *aBody
nsCAutoString newCharset("; charset=");
newCharset.Append(charset);
contentType.Replace(charsetStart, charsetEnd - charsetStart,
newCharset);
}
}
}
+ // If necessary, wrap the stream in a buffered stream so as to guarantee
+ // support for our upload when calling ExplicitSetUploadStream.
+ if (!NS_InputStreamIsBuffered(postDataStream)) {
+ nsCOMPtr<nsIInputStream> bufferedStream;
+ rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
+ postDataStream,
+ 4096);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ postDataStream = bufferedStream;
+ }
+
mUploadComplete = PR_FALSE;
PRUint32 uploadTotal = 0;
postDataStream->Available(&uploadTotal);
mUploadTotal = uploadTotal;
- rv = uploadChannel->SetUploadStream(postDataStream, contentType, -1);
- // Reset the method to its original value
- if (httpChannel) {
- httpChannel->SetRequestMethod(method);
- }
+
+ // We want to use a newer version of the upload channel that won't
+ // ignore the necessary headers for an empty Content-Type.
+ rv = uploadChannel->ExplicitSetUploadStream(postDataStream, contentType, -1, method, PR_FALSE);
}
}
// Reset responseBody
mResponseBody.Truncate();
// Reset responseXML
mResponseXML = nsnull;
--- a/content/base/test/file_XHRSendData.sjs
+++ b/content/base/test/file_XHRSendData.sjs
@@ -13,10 +13,18 @@ function handleRequest(request, response
var body = new BinaryInputStream(request.bodyInputStream);
var avail;
var bytes = [];
while ((avail = body.available()) > 0)
Array.prototype.push.apply(bytes, body.readByteArray(avail));
var data = String.fromCharCode.apply(null, bytes);
- response.write(data);
-}
\ No newline at end of file
+ response.setHeader("Result-Content-Length", "" + data.length);
+ if (data.indexOf("TEST_REDIRECT_STR") >= 0) {
+ var newURL = "http://" + data.split("&url=")[1];
+ response.setStatusLine(null, 307, "redirect");
+ response.setHeader("Location", newURL, false);
+ }
+ else {
+ response.write(data);
+ }
+}
--- a/content/base/test/test_XHRSendData.html
+++ b/content/base/test/test_XHRSendData.html
@@ -8,16 +8,17 @@ https://bugzilla.mozilla.org/show_bug.cg
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=464848">Mozilla Bug 464848</a>
<p id="display">
+ <input id="fileList" type="file"></input>
</p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.8">
xhr = new XMLHttpRequest();
@@ -27,16 +28,42 @@ testDoc1 = xhr.responseXML;
is(testDoc1.inputEncoding, "ISO-8859-1", "wrong encoding");
testDoc2 = document.implementation.createDocument("", "", null);
testDoc2.appendChild(testDoc2.createComment(" doc 2 "));
testDoc2.appendChild(testDoc2.createElement("res"));
testDoc2.documentElement.appendChild(testDoc2.createTextNode("text"));
is(testDoc2.inputEncoding, null, "wrong encoding");
+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+var testData = "blahblahblahblahblahblahblaaaaaaaah. blah.";
+testFileTxt = createFileWithDataExt(testData, ".txt");
+testFilePng = createFileWithDataExt(testData, ".png");
+testFileJpg = createFileWithDataExt(testData, ".jpg");
+testFileGif = createFileWithDataExt(testData, ".gif");
+testFilePdf = createFileWithDataExt(testData, ".pdf");
+testFileXml = createFileWithDataExt(testData, ".xml");
+testFileUnknown = createFileWithDataExt(testData, "noext");
+
+function createFileWithDataExt(fileData, extension) {
+ var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties);
+ var testFile = dirSvc.get("ProfD", Components.interfaces.nsIFile);
+ testFile.append("testfile" + extension);
+ var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
+ outStream.init(testFile, 0x02 | 0x08 | 0x20, 0666, 0);
+ outStream.write(fileData, fileData.length);
+ outStream.close();
+
+ var fileList = document.getElementById('fileList');
+ fileList.value = testFile.path;
+
+ return fileList.files[0];
+}
+
tests = [{ body: null,
resBody: "",
},
{ body: undefined,
resBody: "",
},
{ body: "hi",
resBody: "hi",
@@ -104,37 +131,112 @@ tests = [{ body: null,
resBody: "<!-- doc 2 -->\n<res>text</res>",
resContentType: "foo/bar; charset=UTF-8; baz=bin",
},
{ body: testDoc2,
contentType: "foo/bar; charset=uTf-8",
resBody: "<!-- doc 2 -->\n<res>text</res>",
resContentType: "foo/bar; charset=uTf-8",
},
+ { body: testFileTxt,
+ resBody: testData,
+ resContentType: testFileTxt.mediaType,
+ resContentLength: testData.length,
+ },
+ { body: testFilePng,
+ resBody: testData,
+ resContentType: testFilePng.mediaType,
+ resContentLength: testData.length,
+ },
+ { body: testFileJpg,
+ resBody: testData,
+ resContentType: testFileJpg.mediaType,
+ resContentLength: testData.length,
+ },
+ { body: testFileGif,
+ resBody: testData,
+ resContentType: testFileGif.mediaType,
+ resContentLength: testData.length,
+ },
+ { body: testFilePdf,
+ resBody: testData,
+ resContentType: testFilePdf.mediaType,
+ resContentLength: testData.length,
+ },
+ { body: testFileXml,
+ resBody: testData,
+ resContentType: testFileXml.mediaType,
+ resContentLength: testData.length,
+ },
+ { body: testFileUnknown,
+ resBody: testData,
+ resContentType: "",
+ resContentLength: testData.length,
+ },
+ { //will trigger a redirect test server-side
+ body: ("TEST_REDIRECT_STR&url=" + window.location.host + window.location.pathname),
+ redirect: true,
+ },
];
-for each(test in tests) {
- xhr = new XMLHttpRequest;
- xhr.open("POST", "file_XHRSendData.sjs", false);
- if (test.contentType)
- xhr.setRequestHeader("Content-Type", test.contentType);
- xhr.send(test.body);
+try {
+ for each(test in tests) {
+ xhr = new XMLHttpRequest;
+ xhr.open("POST", "file_XHRSendData.sjs", false);
+ if (test.contentType)
+ xhr.setRequestHeader("Content-Type", test.contentType);
+ xhr.send(test.body);
+
+ if (test.resContentType) {
+ is(xhr.getResponseHeader("Result-Content-Type"), test.resContentType,
+ "Wrong Content-Type sent");
+ }
+ else {
+ is(xhr.getResponseHeader("Result-Content-Type"), null);
+ }
- if (test.resContentType) {
- is(xhr.getResponseHeader("Result-Content-Type"), test.resContentType,
- "Wrong Content-Type sent");
- }
- else {
- is(xhr.getResponseHeader("Result-Content-Type"), null);
- }
+ if (test.resContentLength) {
+ is(xhr.getResponseHeader("Result-Content-Length"), test.resContentLength, "Wrong Content-Length sent");
+ }
- if (test.body instanceof Document) {
- is(xhr.responseText.replace("\r\n", "\n"), test.resBody, "Wrong body");
- }
- else {
- is(xhr.responseText, test.resBody, "Wrong body");
+ if (test.body instanceof Document) {
+ is(xhr.responseText.replace("\r\n", "\n"), test.resBody, "Wrong body");
+ }
+ else if (!test.redirect) {
+ is(xhr.responseText, test.resBody, "Wrong body");
+ }
+ else {
+ // If we're testing redirect, determine whether the body is
+ // this document by looking for the relevant bug url
+ is(xhr.responseText.indexOf("https://bugzilla.mozilla.org/show_bug.cgi?id=464848") >= 0, true,
+ "Wrong page for redirect");
+ }
}
}
+finally {
+ cleanUpData();
+}
+
+function cleanUpData() {
+ removeFileWithExt(".txt");
+ removeFileWithExt(".png");
+ removeFileWithExt(".jpg");
+ removeFileWithExt(".gif");
+ removeFileWithExt(".pdf");
+ removeFileWithExt(".xml");
+ removeFileWithExt("noext");
+}
+
+function removeFileWithExt(extension)
+{
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties);
+ var testFile = dirSvc.get("ProfD", Components.interfaces.nsIFile);
+
+ testFile.append("testfile" + extension);
+ testFile.remove(false);
+}
+
</script>
</pre>
</body>
</html>
--- a/netwerk/base/public/Makefile.in
+++ b/netwerk/base/public/Makefile.in
@@ -106,16 +106,17 @@ XPIDLSRCS = \
nsISecurityInfoProvider.idl \
nsIStreamListenerTee.idl \
nsISimpleStreamListener.idl \
nsIStreamTransportService.idl \
nsIStreamLoader.idl \
nsISyncStreamListener.idl \
nsISystemProxySettings.idl \
nsIUnicharStreamLoader.idl \
+ nsIUploadChannel2.idl \
nsIStandardURL.idl \
nsINestedURI.idl \
nsIURLParser.idl \
nsIURIChecker.idl \
nsISecurityEventSink.idl \
nsISecretDecoderRing.idl \
nsISecureBrowserUI.idl \
nsICryptoFIPSInfo.idl \
new file mode 100644
--- /dev/null
+++ b/netwerk/base/public/nsIUploadChannel2.idl
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface nsIInputStream;
+
+[scriptable, uuid(8821E259-7252-4464-B874-A55D8EF6B222)]
+interface nsIUploadChannel2 : nsISupports
+{
+ /**
+ * Sets a stream to be uploaded by this channel with the specified
+ * Content-Type and Content-Length header values.
+ *
+ * Most implementations of this interface require that the stream:
+ * (1) implement threadsafe addRef and release
+ * (2) implement nsIInputStream::readSegments
+ * (3) implement nsISeekableStream::seek
+ *
+ * @param aStream
+ * The stream to be uploaded by this channel.
+ * @param aContentType
+ * This value will replace any existing Content-Type
+ * header on the HTTP request, regardless of whether
+ * or not its empty.
+ * @param aContentLength
+ * A value of -1 indicates that the length of the stream should be
+ * determined by calling the stream's |available| method.
+ * @param aMethod
+ * The HTTP request method to set on the stream.
+ * @param aStreamHasHeaders
+ * True if the stream already contains headers for the HTTP request.
+ */
+ void explicitSetUploadStream(in nsIInputStream aStream,
+ in ACString aContentType,
+ in long long aContentLength,
+ in ACString aMethod,
+ in boolean aStreamHasHeaders);
+};
--- a/netwerk/protocol/http/src/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/src/nsHttpChannel.cpp
@@ -2766,38 +2766,36 @@ nsHttpChannel::SetupReplacementChannel(n
newChannel->SetNotificationCallbacks(mCallbacks);
newChannel->SetLoadFlags(newLoadFlags);
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel);
if (!httpChannel)
return NS_OK; // no other options to set
if (preserveMethod) {
- nsCOMPtr<nsIUploadChannel> uploadChannel = do_QueryInterface(httpChannel);
+ nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(httpChannel);
if (mUploadStream && uploadChannel) {
// rewind upload stream
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mUploadStream);
if (seekable)
seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
// replicate original call to SetUploadStream...
- if (mUploadStreamHasHeaders)
- uploadChannel->SetUploadStream(mUploadStream, EmptyCString(), -1);
- else {
- const char *ctype = mRequestHead.PeekHeader(nsHttp::Content_Type);
- const char *clen = mRequestHead.PeekHeader(nsHttp::Content_Length);
- if (ctype && clen)
- uploadChannel->SetUploadStream(mUploadStream,
- nsDependentCString(ctype),
- atoi(clen));
- }
+ const char *ctype = mRequestHead.PeekHeader(nsHttp::Content_Type);
+ if (!ctype)
+ ctype = "";
+ const char *clen = mRequestHead.PeekHeader(nsHttp::Content_Length);
+ if (clen)
+ uploadChannel->ExplicitSetUploadStream(
+ mUploadStream,
+ nsDependentCString(ctype),
+ nsCRT::atoll(clen),
+ nsDependentCString(mRequestHead.Method()),
+ mUploadStreamHasHeaders);
}
- // must happen after setting upload stream since SetUploadStream
- // may change the request method.
- httpChannel->SetRequestMethod(nsDependentCString(mRequestHead.Method()));
}
// convey the referrer if one was used for this channel to the next one
if (mReferrer)
httpChannel->SetReferrer(mReferrer);
// convey the mAllowPipelining flag
httpChannel->SetAllowPipelining(mAllowPipelining);
// convey the new redirection limit
httpChannel->SetRedirectionLimit(mRedirectionLimit - 1);
@@ -4073,16 +4071,17 @@ NS_IMPL_RELEASE_INHERITED(nsHttpChannel,
NS_INTERFACE_MAP_BEGIN(nsHttpChannel)
NS_INTERFACE_MAP_ENTRY(nsIRequest)
NS_INTERFACE_MAP_ENTRY(nsIChannel)
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
NS_INTERFACE_MAP_ENTRY(nsIHttpChannel)
NS_INTERFACE_MAP_ENTRY(nsICachingChannel)
NS_INTERFACE_MAP_ENTRY(nsIUploadChannel)
+ NS_INTERFACE_MAP_ENTRY(nsIUploadChannel2)
NS_INTERFACE_MAP_ENTRY(nsICacheListener)
NS_INTERFACE_MAP_ENTRY(nsIEncodedChannel)
NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal)
NS_INTERFACE_MAP_ENTRY(nsIResumableChannel)
NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
NS_INTERFACE_MAP_ENTRY(nsIProtocolProxyCallback)
NS_INTERFACE_MAP_ENTRY(nsIProxiedChannel)
@@ -4680,17 +4679,19 @@ nsHttpChannel::GetUploadStream(nsIInputS
{
NS_ENSURE_ARG_POINTER(stream);
*stream = mUploadStream;
NS_IF_ADDREF(*stream);
return NS_OK;
}
NS_IMETHODIMP
-nsHttpChannel::SetUploadStream(nsIInputStream *stream, const nsACString &contentType, PRInt32 contentLength)
+nsHttpChannel::SetUploadStream(nsIInputStream *stream,
+ const nsACString &contentType,
+ PRInt32 contentLength)
{
// NOTE: for backwards compatibility and for compatibility with old style
// plugins, |stream| may include headers, specifically Content-Type and
// Content-Length headers. in this case, |contentType| and |contentLength|
// would be unspecified. this is traditionally the case of a POST request,
// and so we select POST as the request method if contentType and
// contentLength are unspecified.
@@ -4698,17 +4699,18 @@ nsHttpChannel::SetUploadStream(nsIInputS
if (!contentType.IsEmpty()) {
if (contentLength < 0) {
stream->Available((PRUint32 *) &contentLength);
if (contentLength < 0) {
NS_ERROR("unable to determine content length");
return NS_ERROR_FAILURE;
}
}
- mRequestHead.SetHeader(nsHttp::Content_Length, nsPrintfCString("%d", contentLength));
+ mRequestHead.SetHeader(nsHttp::Content_Length,
+ nsPrintfCString("%d", contentLength));
mRequestHead.SetHeader(nsHttp::Content_Type, contentType);
mUploadStreamHasHeaders = PR_FALSE;
mRequestHead.SetMethod(nsHttp::Put); // PUT request
}
else {
mUploadStreamHasHeaders = PR_TRUE;
mRequestHead.SetMethod(nsHttp::Post); // POST request
}
@@ -4717,16 +4719,47 @@ nsHttpChannel::SetUploadStream(nsIInputS
mUploadStreamHasHeaders = PR_FALSE;
mRequestHead.SetMethod(nsHttp::Get); // revert to GET request
}
mUploadStream = stream;
return NS_OK;
}
NS_IMETHODIMP
+nsHttpChannel::ExplicitSetUploadStream(nsIInputStream *aStream,
+ const nsACString &aContentType,
+ PRInt64 aContentLength,
+ const nsACString &aMethod,
+ PRBool aStreamHasHeaders)
+{
+ // Ensure stream is set and method is valid
+ NS_ENSURE_TRUE(aStream, NS_ERROR_FAILURE);
+
+ if (aContentLength < 0) {
+ PRUint32 streamLength;
+ aStream->Available(&streamLength);
+ aContentLength = streamLength;
+ if (aContentLength < 0) {
+ NS_ERROR("unable to determine content length");
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ nsresult rv = SetRequestMethod(aMethod);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ mRequestHead.SetHeader(nsHttp::Content_Length, nsPrintfCString("%lld", aContentLength));
+ mRequestHead.SetHeader(nsHttp::Content_Type, aContentType);
+
+ mUploadStreamHasHeaders = aStreamHasHeaders;
+ mUploadStream = aStream;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
nsHttpChannel::GetResponseStatus(PRUint32 *value)
{
NS_ENSURE_ARG_POINTER(value);
if (!mResponseHead)
return NS_ERROR_NOT_AVAILABLE;
*value = mResponseHead->Status();
return NS_OK;
}
--- a/netwerk/protocol/http/src/nsHttpChannel.h
+++ b/netwerk/protocol/http/src/nsHttpChannel.h
@@ -69,16 +69,17 @@
#include "nsICacheSession.h"
#include "nsICacheEntryDescriptor.h"
#include "nsICacheListener.h"
#include "nsIApplicationCache.h"
#include "nsIApplicationCacheChannel.h"
#include "nsIEncodedChannel.h"
#include "nsITransport.h"
#include "nsIUploadChannel.h"
+#include "nsIUploadChannel2.h"
#include "nsIStringEnumerator.h"
#include "nsIOutputStream.h"
#include "nsIAsyncInputStream.h"
#include "nsIPrompt.h"
#include "nsIResumableChannel.h"
#include "nsISupportsPriority.h"
#include "nsIProtocolProxyCallback.h"
#include "nsICancelable.h"
@@ -96,16 +97,17 @@ class nsProxyInfo;
//-----------------------------------------------------------------------------
class nsHttpChannel : public nsHashPropertyBag
, public nsIHttpChannel
, public nsIHttpChannelInternal
, public nsIStreamListener
, public nsICachingChannel
, public nsIUploadChannel
+ , public nsIUploadChannel2
, public nsICacheListener
, public nsIEncodedChannel
, public nsITransportEventSink
, public nsIResumableChannel
, public nsISupportsPriority
, public nsIProtocolProxyCallback
, public nsIProxiedChannel
, public nsITraceableChannel
@@ -116,16 +118,17 @@ public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIREQUEST
NS_DECL_NSICHANNEL
NS_DECL_NSIHTTPCHANNEL
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSICACHINGCHANNEL
NS_DECL_NSIUPLOADCHANNEL
+ NS_DECL_NSIUPLOADCHANNEL2
NS_DECL_NSICACHELISTENER
NS_DECL_NSIENCODEDCHANNEL
NS_DECL_NSIHTTPCHANNELINTERNAL
NS_DECL_NSITRANSPORTEVENTSINK
NS_DECL_NSIRESUMABLECHANNEL
NS_DECL_NSISUPPORTSPRIORITY
NS_DECL_NSIPROTOCOLPROXYCALLBACK
NS_DECL_NSIPROXIEDCHANNEL