diff --git a/netwerk/protocol/http/src/nsHttpChannel.cpp b/netwerk/protocol/http/src/nsHttpChannel.cpp index fe8ff66e6d06..5f267ea883cf 100644 --- a/netwerk/protocol/http/src/nsHttpChannel.cpp +++ b/netwerk/protocol/http/src/nsHttpChannel.cpp @@ -69,6 +69,7 @@ nsHttpChannel::nsHttpChannel() , mCachedContentIsValid(PR_FALSE) , mResponseHeadersModified(PR_FALSE) , mCanceled(PR_FALSE) + , mUploadStreamHasHeaders(PR_FALSE) { LOG(("Creating nsHttpChannel @%x\n", this)); @@ -435,7 +436,7 @@ nsHttpChannel::SetupTransaction() mRequestHead.SetHeader(nsHttp::Cache_Control, "max-age=0"); } - return mTransaction->SetupRequest(&mRequestHead, mUploadStream); + return mTransaction->SetupRequest(&mRequestHead, mUploadStream, mUploadStreamHasHeaders); } void @@ -2171,11 +2172,38 @@ nsHttpChannel::GetUploadStream(nsIInputStream **stream) NS_IMETHODIMP nsHttpChannel::SetUploadStream(nsIInputStream *stream, const char* 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. + + if (mUploadStream) { + if (contentType) { + if (contentLength < 0) { + stream->Available((PRUint32 *) &contentLength); + if (contentLength < 0) { + NS_ERROR("unable to determine content length"); + return NS_ERROR_FAILURE; + } + } + nsCAutoString buf; buf.AppendInt(contentLength); + mRequestHead.SetHeader(nsHttp::Content_Length, buf.get()); + 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 + } + } + else { + mUploadStreamHasHeaders = PR_FALSE; + mRequestHead.SetMethod(nsHttp::Get); // revert to GET request + } mUploadStream = stream; - if (mUploadStream) - mRequestHead.SetMethod(nsHttp::Post); - else - mRequestHead.SetMethod(nsHttp::Get); return NS_OK; } diff --git a/netwerk/protocol/http/src/nsHttpChannel.h b/netwerk/protocol/http/src/nsHttpChannel.h index 6e260d68a8e3..cedb79bba599 100644 --- a/netwerk/protocol/http/src/nsHttpChannel.h +++ b/netwerk/protocol/http/src/nsHttpChannel.h @@ -172,6 +172,7 @@ private: PRPackedBool mCachedContentIsValid; PRPackedBool mResponseHeadersModified; PRPackedBool mCanceled; + PRPackedBool mUploadStreamHasHeaders; }; #endif // nsHttpChannel_h__ diff --git a/netwerk/protocol/http/src/nsHttpResponseHead.h b/netwerk/protocol/http/src/nsHttpResponseHead.h index 346736359cb5..ea6c831da891 100644 --- a/netwerk/protocol/http/src/nsHttpResponseHead.h +++ b/netwerk/protocol/http/src/nsHttpResponseHead.h @@ -62,7 +62,7 @@ public: nsresult GetHeader(nsHttpAtom h, char **v) { return mHeaders.GetHeader(h, v); } void ClearHeaders() { mHeaders.Clear(); } - void SetContentType(const char *s) { CRTFREEIF(mContentType); mContentType = (s ? nsCRT::strdup(s) : 0); } + void SetContentType(const char *s) { CRTFREEIF(mContentType); mContentType = strdup_if(s); } void SetContentLength(PRInt32); // write out the response status line and headers as a single text block, diff --git a/netwerk/protocol/http/src/nsHttpTransaction.cpp b/netwerk/protocol/http/src/nsHttpTransaction.cpp index 48492a79ad3f..3739278414aa 100644 --- a/netwerk/protocol/http/src/nsHttpTransaction.cpp +++ b/netwerk/protocol/http/src/nsHttpTransaction.cpp @@ -118,7 +118,8 @@ nsHttpTransaction::~nsHttpTransaction() nsresult nsHttpTransaction::SetupRequest(nsHttpRequestHead *requestHead, - nsIInputStream *requestStream) + nsIInputStream *requestBody, + PRBool requestBodyHasHeaders) { nsresult rv; @@ -164,9 +165,11 @@ nsHttpTransaction::SetupRequest(nsHttpRequestHead *requestHead, } #endif - mReqUploadStream = requestStream; - if (!mReqUploadStream) - // Write out end-of-headers sequence if NOT uploading data: + mReqUploadStream = requestBody; + + // If the request body does not include headers or if there is no request + // body, then we must add the header/body separator manually. + if (!requestBodyHasHeaders || !requestBody) mReqHeaderBuf.Append("\r\n"); // Create a string stream for the request header buf diff --git a/netwerk/protocol/http/src/nsHttpTransaction.h b/netwerk/protocol/http/src/nsHttpTransaction.h index 9e59aea1bb6c..cfb47b237eb0 100644 --- a/netwerk/protocol/http/src/nsHttpTransaction.h +++ b/netwerk/protocol/http/src/nsHttpTransaction.h @@ -60,7 +60,9 @@ public: virtual ~nsHttpTransaction(); // Called to initialize the transaction - nsresult SetupRequest(nsHttpRequestHead *, nsIInputStream *); + nsresult SetupRequest(nsHttpRequestHead *requestHeaders, + nsIInputStream *requestBody, + PRBool requestBodyIncludesHeaders); nsIStreamListener *Listener() { return mListener; } nsAHttpConnection *Connection() { return mConnection; }