зеркало из https://github.com/mozilla/gecko-dev.git
Bug 536279 (send request headers to chrome channel) and bug 536283 (send full nsHttpResponseHead in OnStartRequest) a=jae-seong r=dwitte,jduell
This commit is contained in:
Родитель
40d5c21556
Коммит
3898298861
|
@ -209,6 +209,16 @@ struct ParamTraits<nsCString> : ParamTraits<nsACString>
|
|||
typedef nsCString paramType;
|
||||
};
|
||||
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
|
||||
template<>
|
||||
struct ParamTraits<nsCAutoString> : ParamTraits<nsCString>
|
||||
{
|
||||
typedef nsCAutoString paramType;
|
||||
};
|
||||
|
||||
#endif // MOZILLA_INTERNAL_API
|
||||
|
||||
template <>
|
||||
struct ParamTraits<nsString> : ParamTraits<nsAString>
|
||||
{
|
||||
|
|
|
@ -47,6 +47,9 @@ MODULE = necko
|
|||
LIBRARY_NAME = neckobase_s
|
||||
LIBXUL_LIBRARY = 1
|
||||
|
||||
ifdef MOZ_IPC
|
||||
EXPORTS = nsURLHelper.h
|
||||
endif
|
||||
|
||||
CPPSRCS = \
|
||||
nsTransportUtils.cpp \
|
||||
|
|
|
@ -210,19 +210,13 @@ NS_INTERFACE_MAP_END_INHERITING(nsHashPropertyBag)
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool
|
||||
HttpChannelChild::RecvOnStartRequest(const PRInt32& HACK_ContentLength,
|
||||
const nsCString& HACK_ContentType,
|
||||
const PRUint32& HACK_Status,
|
||||
const nsCString& HACK_StatusText)
|
||||
HttpChannelChild::RecvOnStartRequest(const nsHttpResponseHead& responseHead)
|
||||
{
|
||||
LOG(("HttpChannelChild::RecvOnStartRequest [this=%x]\n", this));
|
||||
|
||||
mState = HCC_ONSTART;
|
||||
|
||||
mContentLength_HACK = HACK_ContentLength;
|
||||
mContentType_HACK = HACK_ContentType;
|
||||
mResponseStatus_HACK = HACK_Status;
|
||||
mResponseStatusText_HACK = HACK_StatusText;
|
||||
mResponseHead = new nsHttpResponseHead(responseHead);
|
||||
|
||||
nsresult rv = mChildListener->OnStartRequest(this, mChildListenerContext);
|
||||
if (!NS_SUCCEEDED(rv)) {
|
||||
|
@ -453,38 +447,82 @@ HttpChannelChild::GetSecurityInfo(nsISupports **aSecurityInfo)
|
|||
NS_IMETHODIMP
|
||||
HttpChannelChild::GetContentType(nsACString& value)
|
||||
{
|
||||
if (mState < HCC_ONSTART) {
|
||||
if (!mResponseHead) {
|
||||
value.Truncate();
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
if (mContentType_HACK.IsEmpty()) {
|
||||
if (mResponseHead->ContentType().IsEmpty()) {
|
||||
value.AssignLiteral(UNKNOWN_CONTENT_TYPE);
|
||||
} else {
|
||||
value = mContentType_HACK;
|
||||
value = mResponseHead->ContentType();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HttpChannelChild::SetContentType(const nsACString& aContentType)
|
||||
{
|
||||
DROP_DEAD();
|
||||
return BaseClassSetContentType_HACK(aContentType);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HttpChannelChild::BaseClassSetContentType_HACK(const nsACString &value)
|
||||
{
|
||||
if (mChildListener || mWasOpened) {
|
||||
if (!mResponseHead)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
nsCAutoString contentTypeBuf, charsetBuf;
|
||||
PRBool hadCharset;
|
||||
net_ParseContentType(value, contentTypeBuf, charsetBuf, &hadCharset);
|
||||
|
||||
mResponseHead->SetContentType(contentTypeBuf);
|
||||
|
||||
// take care not to stomp on an existing charset
|
||||
if (hadCharset)
|
||||
mResponseHead->SetContentCharset(charsetBuf);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HttpChannelChild::GetContentCharset(nsACString& aContentCharset)
|
||||
{
|
||||
DROP_DEAD();
|
||||
return BaseClassGetContentCharset_HACK(aContentCharset);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HttpChannelChild::BaseClassGetContentCharset_HACK(nsACString &value)
|
||||
{
|
||||
if (!mResponseHead)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
value = mResponseHead->ContentCharset();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HttpChannelChild::SetContentCharset(const nsACString& aContentCharset)
|
||||
{
|
||||
DROP_DEAD();
|
||||
return BaseClassSetContentCharset_HACK(aContentCharset);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HttpChannelChild::BaseClassSetContentCharset_HACK(const nsACString &value)
|
||||
{
|
||||
if (mChildListener) {
|
||||
if (!mResponseHead)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
mResponseHead->SetContentCharset(value);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HttpChannelChild::GetContentLength(PRInt32 *aContentLength)
|
||||
{
|
||||
*aContentLength = mContentLength_HACK;
|
||||
*aContentLength = mResponseHead->ContentLength();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -551,7 +589,7 @@ HttpChannelChild::AsyncOpen(nsIStreamListener *listener, nsISupports *aContext)
|
|||
}
|
||||
|
||||
if (!SendAsyncOpen(mSpec, charset, originalSpec, originalCharset,
|
||||
docSpec, docCharset, mLoadFlags)) {
|
||||
docSpec, docCharset, mLoadFlags, mRequestHeaders)) {
|
||||
// IPDL error: our destructor will be called automatically
|
||||
// -- TODO: verify that that's the case :)
|
||||
mChildListener = 0;
|
||||
|
@ -616,7 +654,21 @@ HttpChannelChild::SetReferrer(nsIURI *aReferrer)
|
|||
NS_IMETHODIMP
|
||||
HttpChannelChild::GetRequestHeader(const nsACString& hdr, nsACString& val)
|
||||
{
|
||||
DROP_DEAD();
|
||||
return BaseClassGetRequestHeader_HACK(hdr, val);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HttpChannelChild::BaseClassGetRequestHeader_HACK(const nsACString &header,
|
||||
nsACString &value)
|
||||
{
|
||||
// XXX might be better to search the header list directly instead of
|
||||
// hitting the http atom hash table.
|
||||
|
||||
nsHttpAtom atom = nsHttp::ResolveAtom(header);
|
||||
if (!atom)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
return mRequestHead.GetHeader(atom, value);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -624,7 +676,55 @@ HttpChannelChild::SetRequestHeader(const nsACString& aHeader,
|
|||
const nsACString& aValue,
|
||||
PRBool aMerge)
|
||||
{
|
||||
DROP_DEAD();
|
||||
ENSURE_CALLED_BEFORE_ASYNC_OPEN();
|
||||
|
||||
nsresult rv = BaseClassSetRequestHeader_HACK(aHeader, aValue, aMerge);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
RequestHeaderTuple* tuple = mRequestHeaders.AppendElement();
|
||||
if (!tuple)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
tuple->mHeader = aHeader;
|
||||
tuple->mValue = aValue;
|
||||
tuple->mMerge = aMerge;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HttpChannelChild::BaseClassSetRequestHeader_HACK(const nsACString &header,
|
||||
const nsACString &value,
|
||||
PRBool merge)
|
||||
{
|
||||
NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
|
||||
|
||||
const nsCString &flatHeader = PromiseFlatCString(header);
|
||||
const nsCString &flatValue = PromiseFlatCString(value);
|
||||
|
||||
LOG(("nsHttpChannel::SetRequestHeader [this=%x header=\"%s\" value=\"%s\" merge=%u]\n",
|
||||
this, flatHeader.get(), flatValue.get(), merge));
|
||||
|
||||
// Header names are restricted to valid HTTP tokens.
|
||||
if (!nsHttp::IsValidToken(flatHeader))
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
// Header values MUST NOT contain line-breaks. RFC 2616 technically
|
||||
// permits CTL characters, including CR and LF, in header values provided
|
||||
// they are quoted. However, this can lead to problems if servers do not
|
||||
// interpret quoted strings properly. Disallowing CR and LF here seems
|
||||
// reasonable and keeps things simple. We also disallow a null byte.
|
||||
if (flatValue.FindCharInSet("\r\n") != kNotFound ||
|
||||
flatValue.Length() != strlen(flatValue.get()))
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
nsHttpAtom atom = nsHttp::ResolveAtom(flatHeader.get());
|
||||
if (!atom) {
|
||||
NS_WARNING("failed to resolve atom");
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return mRequestHead.SetHeader(atom, flatValue, merge);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -659,18 +759,18 @@ NS_IMETHODIMP
|
|||
HttpChannelChild::GetResponseStatus(PRUint32 *value)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(value);
|
||||
if (mState < HCC_ONSTART)
|
||||
if (!mResponseHead)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
*value = mResponseStatus_HACK;
|
||||
*value = mResponseHead->Status();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HttpChannelChild::GetResponseStatusText(nsACString& value)
|
||||
{
|
||||
if (mState < HCC_ONSTART)
|
||||
if (!mResponseHead)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
value = mResponseStatusText_HACK;
|
||||
value = mResponseHead->StatusText();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -678,9 +778,9 @@ NS_IMETHODIMP
|
|||
HttpChannelChild::GetRequestSucceeded(PRBool *value)
|
||||
{
|
||||
NS_PRECONDITION(value, "Don't ever pass a null arg to this function");
|
||||
if (mState < HCC_ONSTART)
|
||||
if (!mResponseHead)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
PRUint32 status = mResponseStatus_HACK;
|
||||
PRUint32 status = mResponseHead->Status();
|
||||
*value = (status / 100 == 2);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -688,7 +788,19 @@ HttpChannelChild::GetRequestSucceeded(PRBool *value)
|
|||
NS_IMETHODIMP
|
||||
HttpChannelChild::GetResponseHeader(const nsACString& header, nsACString& val)
|
||||
{
|
||||
DROP_DEAD();
|
||||
return BaseClassGetResponseHeader_HACK(header, val);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HttpChannelChild::BaseClassGetResponseHeader_HACK(const nsACString &header,
|
||||
nsACString &value)
|
||||
{
|
||||
if (!mResponseHead)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
nsHttpAtom atom = nsHttp::ResolveAtom(header);
|
||||
if (!atom)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
return mResponseHead->GetHeader(atom, value);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -696,7 +808,32 @@ HttpChannelChild::SetResponseHeader(const nsACString& header,
|
|||
const nsACString& value,
|
||||
PRBool merge)
|
||||
{
|
||||
DROP_DEAD();
|
||||
return BaseClassSetResponseHeader_HACK(header, value, merge);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HttpChannelChild::BaseClassSetResponseHeader_HACK(const nsACString &header,
|
||||
const nsACString &value,
|
||||
PRBool merge)
|
||||
{
|
||||
LOG(("nsHttpChannel::SetResponseHeader [this=%x header=\"%s\" value=\"%s\" merge=%u]\n",
|
||||
this, PromiseFlatCString(header).get(), PromiseFlatCString(value).get(), merge));
|
||||
|
||||
if (!mResponseHead)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
nsHttpAtom atom = nsHttp::ResolveAtom(header);
|
||||
if (!atom)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
// these response headers must not be changed
|
||||
if (atom == nsHttp::Content_Type ||
|
||||
atom == nsHttp::Content_Length ||
|
||||
atom == nsHttp::Content_Encoding ||
|
||||
atom == nsHttp::Trailer ||
|
||||
atom == nsHttp::Transfer_Encoding)
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
|
||||
return mResponseHead->SetHeader(atom, value, merge);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -116,24 +116,33 @@ public:
|
|||
nsresult Init(nsIURI *uri);
|
||||
|
||||
protected:
|
||||
bool RecvOnStartRequest(const PRInt32& HACK_ContentLength,
|
||||
const nsCString& HACK_ContentType,
|
||||
const PRUint32& HACK_Status,
|
||||
const nsCString& HACK_StatusText);
|
||||
bool RecvOnStartRequest(const nsHttpResponseHead& responseHead);
|
||||
bool RecvOnDataAvailable(const nsCString& data,
|
||||
const PRUint32& offset,
|
||||
const PRUint32& count);
|
||||
bool RecvOnStopRequest(const nsresult& statusCode);
|
||||
|
||||
private:
|
||||
nsresult BaseClassSetContentType_HACK(const nsACString &value);
|
||||
nsresult BaseClassGetContentCharset_HACK(nsACString &value);
|
||||
nsresult BaseClassSetContentCharset_HACK(const nsACString &value);
|
||||
nsresult BaseClassSetRequestHeader_HACK(const nsACString &header,
|
||||
const nsACString &value,
|
||||
PRBool merge);
|
||||
nsresult BaseClassGetRequestHeader_HACK(const nsACString &header,
|
||||
nsACString &value);
|
||||
nsresult BaseClassGetResponseHeader_HACK(const nsACString &header,
|
||||
nsACString &value);
|
||||
nsresult BaseClassSetResponseHeader_HACK(const nsACString &header,
|
||||
const nsACString &value,
|
||||
PRBool merge);
|
||||
|
||||
nsCOMPtr<nsIStreamListener> mChildListener;
|
||||
nsCOMPtr<nsISupports> mChildListenerContext;
|
||||
|
||||
// FIXME: copy full ResponseHead (bug 536283)
|
||||
PRInt32 mContentLength_HACK;
|
||||
nsCString mContentType_HACK;
|
||||
PRUint32 mResponseStatus_HACK;
|
||||
nsCString mResponseStatusText_HACK;
|
||||
RequestHeaderTuples mRequestHeaders;
|
||||
|
||||
nsAutoPtr<nsHttpResponseHead> mResponseHead;
|
||||
|
||||
// FIXME: replace with IPDL states (bug 536319)
|
||||
enum HttpChannelChildState mState;
|
||||
|
|
|
@ -69,13 +69,14 @@ NS_IMPL_ISUPPORTS3(HttpChannelParent,
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool
|
||||
HttpChannelParent::RecvAsyncOpen(const nsCString& uriSpec,
|
||||
const nsCString& charset,
|
||||
const nsCString& originalUriSpec,
|
||||
const nsCString& originalCharset,
|
||||
const nsCString& docUriSpec,
|
||||
const nsCString& docCharset,
|
||||
const PRUint32& loadFlags)
|
||||
HttpChannelParent::RecvAsyncOpen(const nsCString& uriSpec,
|
||||
const nsCString& charset,
|
||||
const nsCString& originalUriSpec,
|
||||
const nsCString& originalCharset,
|
||||
const nsCString& docUriSpec,
|
||||
const nsCString& docCharset,
|
||||
const PRUint32& loadFlags,
|
||||
const RequestHeaderTuples& requestHeaders)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
|
@ -117,7 +118,13 @@ HttpChannelParent::RecvAsyncOpen(const nsCString& uriSpec,
|
|||
}
|
||||
if (loadFlags != nsIRequest::LOAD_NORMAL)
|
||||
chan->SetLoadFlags(loadFlags);
|
||||
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
|
||||
for (PRUint32 i = 0; i < requestHeaders.Length(); i++)
|
||||
httpChan->SetRequestHeader(requestHeaders[i].mHeader,
|
||||
requestHeaders[i].mValue,
|
||||
requestHeaders[i].mMerge);
|
||||
|
||||
// TODO: implement needed interfaces, and either proxy calls back to child
|
||||
// process, or rig up appropriate hacks.
|
||||
// chan->SetNotificationCallbacks(this);
|
||||
|
@ -139,26 +146,11 @@ HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
|
|||
{
|
||||
LOG(("HttpChannelParent::OnStartRequest [this=%x]\n", this));
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> chan(do_QueryInterface(aRequest));
|
||||
NS_ENSURE_TRUE(chan, NS_ERROR_FAILURE);
|
||||
nsHttpChannel *chan = static_cast<nsHttpChannel *>(aRequest);
|
||||
nsHttpResponseHead *responseHead = chan->GetResponseHead();
|
||||
NS_ABORT_IF_FALSE(responseHead, "Missing HTTP responseHead!");
|
||||
|
||||
/*
|
||||
* - TODO: Need to send all or most of mResponseHead
|
||||
* - TODO: if getting vals fails, still need to call OnStartRequest on child,
|
||||
* not just fail here?
|
||||
*/
|
||||
PRInt32 contentLength_HACK;
|
||||
chan->GetContentLength(&contentLength_HACK);
|
||||
nsCAutoString contentType_HACK;
|
||||
chan->GetContentType(contentType_HACK);
|
||||
PRUint32 status_HACK;
|
||||
chan->GetResponseStatus(&status_HACK);
|
||||
nsCAutoString statusText_HACK;
|
||||
chan->GetResponseStatusText(statusText_HACK);
|
||||
|
||||
if (!SendOnStartRequest(contentLength_HACK, contentType_HACK,
|
||||
status_HACK, statusText_HACK))
|
||||
{
|
||||
if (!SendOnStartRequest(*responseHead)) {
|
||||
// IPDL error--child dead/dying & our own destructor will be called
|
||||
// automatically
|
||||
// -- TODO: verify that that's the case :)
|
||||
|
|
|
@ -65,13 +65,14 @@ public:
|
|||
virtual ~HttpChannelParent();
|
||||
|
||||
protected:
|
||||
virtual bool RecvAsyncOpen(const nsCString& uriSpec,
|
||||
const nsCString& charset,
|
||||
const nsCString& originalUriSpec,
|
||||
const nsCString& originalCharset,
|
||||
const nsCString& docUriSpec,
|
||||
const nsCString& docCharset,
|
||||
const PRUint32& loadFlags);
|
||||
virtual bool RecvAsyncOpen(const nsCString& uriSpec,
|
||||
const nsCString& charset,
|
||||
const nsCString& originalUriSpec,
|
||||
const nsCString& originalCharset,
|
||||
const nsCString& docUriSpec,
|
||||
const nsCString& docCharset,
|
||||
const PRUint32& loadFlags,
|
||||
const RequestHeaderTuples& requestHeaders);
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
|
|
@ -52,6 +52,14 @@ EXPORTS_NAMESPACES = mozilla/net
|
|||
EXPORTS_mozilla/net = \
|
||||
HttpChannelParent.h \
|
||||
HttpChannelChild.h \
|
||||
PHttpChannelParams.h \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = \
|
||||
nsHttpResponseHead.h \
|
||||
nsHttpHeaderArray.h \
|
||||
nsHttp.h \
|
||||
nsHttpAtomList.h \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
|
|
|
@ -40,6 +40,11 @@
|
|||
|
||||
include protocol "PNecko.ipdl";
|
||||
|
||||
include "mozilla/net/PHttpChannelParams.h";
|
||||
|
||||
using RequestHeaderTuples;
|
||||
using nsHttpResponseHead;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
|
@ -51,23 +56,21 @@ protocol PHttpChannel
|
|||
parent:
|
||||
__delete__();
|
||||
|
||||
AsyncOpen(nsCString uriSpec,
|
||||
nsCString charset,
|
||||
AsyncOpen(nsCString uriSpec,
|
||||
nsCString charset,
|
||||
// - TODO: unclear if any HTTP channel clients ever set
|
||||
// originalURI != uri (about:credits?); also not clear if chrome
|
||||
// channel would ever need to know. Can we get rid of next two
|
||||
// args?
|
||||
nsCString originalUriSpec,
|
||||
nsCString originalCharset,
|
||||
nsCString docUriSpec,
|
||||
nsCString docCharset,
|
||||
PRUint32 loadFlags);
|
||||
nsCString originalUriSpec,
|
||||
nsCString originalCharset,
|
||||
nsCString docUriSpec,
|
||||
nsCString docCharset,
|
||||
PRUint32 loadFlags,
|
||||
RequestHeaderTuples requestHeaders);
|
||||
|
||||
child:
|
||||
OnStartRequest(PRInt32 HACK_ContentLength,
|
||||
nsCString HACK_ContentType,
|
||||
PRUint32 HACK_Status,
|
||||
nsCString HACK_StatusText);
|
||||
OnStartRequest(nsHttpResponseHead responseHead);
|
||||
|
||||
OnDataAvailable(nsCString data,
|
||||
PRUint32 offset,
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
|
||||
/* ***** 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
|
||||
* The Mozilla Foundation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jae-Seong Lee-Russo <lusian@gmail.com>
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
#ifndef mozilla_net_PHttpChannelParams_h
|
||||
#define mozilla_net_PHttpChannelParams_h
|
||||
|
||||
#define ALLOW_LATE_NSHTTP_H_INCLUDE 1
|
||||
#include "base/basictypes.h"
|
||||
|
||||
#include "IPC/IPCMessageUtils.h"
|
||||
#include "nsHttp.h"
|
||||
#include "nsHttpHeaderArray.h"
|
||||
#include "nsHttpResponseHead.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
struct RequestHeaderTuple {
|
||||
nsCString mHeader;
|
||||
nsCString mValue;
|
||||
PRBool mMerge;
|
||||
};
|
||||
|
||||
typedef nsTArray<RequestHeaderTuple> RequestHeaderTuples;
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template<>
|
||||
struct ParamTraits<mozilla::net::RequestHeaderTuple>
|
||||
{
|
||||
typedef mozilla::net::RequestHeaderTuple paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mHeader);
|
||||
WriteParam(aMsg, aParam.mValue);
|
||||
WriteParam(aMsg, aParam.mMerge);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->mHeader)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mValue)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mMerge)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParamTraits<nsHttpAtom>
|
||||
{
|
||||
typedef nsHttpAtom paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
// aParam.get() cannot be null.
|
||||
NS_ASSERTION(aParam.get(), "null nsHTTPAtom value");
|
||||
nsCAutoString value(aParam.get());
|
||||
WriteParam(aMsg, value);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
nsCAutoString value;
|
||||
if (!ReadParam(aMsg, aIter, &value))
|
||||
return false;
|
||||
|
||||
*aResult = nsHttp::ResolveAtom(value.get());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParamTraits<nsHttpHeaderArray::nsEntry>
|
||||
{
|
||||
typedef nsHttpHeaderArray::nsEntry paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.header);
|
||||
WriteParam(aMsg, aParam.value);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->header)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->value)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParamTraits<nsHttpHeaderArray>
|
||||
{
|
||||
typedef nsHttpHeaderArray paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
paramType& p = const_cast<paramType&>(aParam);
|
||||
|
||||
WriteParam(aMsg, p.Headers());
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->Headers())))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParamTraits<nsHttpResponseHead>
|
||||
{
|
||||
typedef nsHttpResponseHead paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mHeaders);
|
||||
WriteParam(aMsg, aParam.mVersion);
|
||||
WriteParam(aMsg, aParam.mStatus);
|
||||
WriteParam(aMsg, aParam.mStatusText);
|
||||
WriteParam(aMsg, aParam.mContentLength);
|
||||
WriteParam(aMsg, aParam.mContentType);
|
||||
WriteParam(aMsg, aParam.mContentCharset);
|
||||
WriteParam(aMsg, aParam.mCacheControlNoStore);
|
||||
WriteParam(aMsg, aParam.mCacheControlNoCache);
|
||||
WriteParam(aMsg, aParam.mPragmaNoCache);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->mHeaders)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mVersion)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mStatus)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mStatusText)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mContentLength)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mContentType)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mContentCharset)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mCacheControlNoStore)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mCacheControlNoCache)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mPragmaNoCache)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
#endif // mozilla_net_PHttpChannelParams_h
|
|
@ -146,7 +146,7 @@ public:
|
|||
|
||||
public: /* internal; workaround lame compilers */
|
||||
typedef void (nsHttpChannel:: *nsAsyncCallback)(void);
|
||||
|
||||
nsHttpResponseHead * GetResponseHead() const { return mResponseHead; }
|
||||
private:
|
||||
|
||||
// Helper function to simplify getting notification callbacks.
|
||||
|
|
|
@ -83,7 +83,6 @@ public:
|
|||
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
struct nsEntry
|
||||
{
|
||||
nsEntry() {}
|
||||
|
@ -98,10 +97,12 @@ private:
|
|||
};
|
||||
};
|
||||
|
||||
nsTArray<nsEntry> &Headers() { return mHeaders; }
|
||||
|
||||
private:
|
||||
PRInt32 LookupEntry(nsHttpAtom header, nsEntry **);
|
||||
PRBool CanAppendToHeader(nsHttpAtom header);
|
||||
|
||||
private:
|
||||
nsTArray<nsEntry> mHeaders;
|
||||
};
|
||||
|
||||
|
|
|
@ -149,6 +149,10 @@ private:
|
|||
PRPackedBool mCacheControlNoStore;
|
||||
PRPackedBool mCacheControlNoCache;
|
||||
PRPackedBool mPragmaNoCache;
|
||||
|
||||
#ifdef MOZ_IPC
|
||||
friend struct IPC::ParamTraits<nsHttpResponseHead>;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // nsHttpResponseHead_h__
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
//
|
||||
// HTTP headers test
|
||||
//
|
||||
|
||||
// Note: sets Cc and Ci variables
|
||||
do_load_httpd_js();
|
||||
|
||||
var httpserver = new nsHttpServer();
|
||||
var testpath = "/simple";
|
||||
var httpbody = "0123456789";
|
||||
var channel;
|
||||
|
||||
var dbg=0
|
||||
if (dbg) { print("============== START =========="); }
|
||||
|
||||
function run_test() {
|
||||
setup_test();
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function setup_test() {
|
||||
if (dbg) { print("============== setup_test: in"); }
|
||||
|
||||
httpserver.registerPathHandler(testpath, serverHandler);
|
||||
httpserver.start(4444);
|
||||
|
||||
channel = setupChannel(testpath);
|
||||
|
||||
channel.setRequestHeader("ReplaceMe", "initial value", true);
|
||||
var setOK = channel.getRequestHeader("ReplaceMe");
|
||||
do_check_eq(setOK, "initial value");
|
||||
channel.setRequestHeader("ReplaceMe", "replaced", false);
|
||||
setOK = channel.getRequestHeader("ReplaceMe");
|
||||
do_check_eq(setOK, "replaced");
|
||||
|
||||
channel.setRequestHeader("MergeMe", "foo1", true);
|
||||
channel.setRequestHeader("MergeMe", "foo2", true);
|
||||
channel.setRequestHeader("MergeMe", "foo3", true);
|
||||
setOK = channel.getRequestHeader("MergeMe");
|
||||
do_check_eq(setOK, "foo1, foo2, foo3");
|
||||
|
||||
// ChannelListener defined in head_channels.js
|
||||
channel.asyncOpen(new ChannelListener(checkRequestResponse, channel), null);
|
||||
|
||||
if (dbg) { print("============== setup_test: out"); }
|
||||
}
|
||||
|
||||
function setupChannel(path) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
var chan = ios.newChannel("http://localhost:4444" + path, "", null);
|
||||
chan.QueryInterface(Ci.nsIHttpChannel);
|
||||
chan.requestMethod = "GET";
|
||||
return chan;
|
||||
}
|
||||
|
||||
function serverHandler(metadata, response) {
|
||||
if (dbg) { print("============== serverHandler: in"); }
|
||||
|
||||
var setOK = metadata.getHeader("ReplaceMe");
|
||||
do_check_eq(setOK, "replaced");
|
||||
setOK = metadata.getHeader("MergeMe");
|
||||
do_check_eq(setOK, "foo1, foo2, foo3");
|
||||
|
||||
response.setHeader("Content-Type", "text/plain", false);
|
||||
response.setStatusLine("1.1", 200, "OK");
|
||||
|
||||
// note: httpd.js' "Response" class uses ',' (no space) for merge.
|
||||
response.setHeader("httpdMerge", "bar1", false);
|
||||
response.setHeader("httpdMerge", "bar2", true);
|
||||
response.setHeader("httpdMerge", "bar3", true);
|
||||
// Some special headers like Proxy-Authenticate merge with \n
|
||||
response.setHeader("Proxy-Authenticate", "line 1", true);
|
||||
response.setHeader("Proxy-Authenticate", "line 2", true);
|
||||
response.setHeader("Proxy-Authenticate", "line 3", true);
|
||||
|
||||
response.bodyOutputStream.write(httpbody, httpbody.length);
|
||||
|
||||
if (dbg) { print("============== serverHandler: out"); }
|
||||
}
|
||||
|
||||
function checkRequestResponse(request, data, context) {
|
||||
if (dbg) { print("============== checkRequestResponse: in"); }
|
||||
|
||||
do_check_eq(channel.responseStatus, 200);
|
||||
do_check_eq(channel.responseStatusText, "OK");
|
||||
do_check_true(channel.requestSucceeded);
|
||||
|
||||
var response = channel.getResponseHeader("httpdMerge");
|
||||
do_check_eq(response, "bar1,bar2,bar3");
|
||||
channel.setResponseHeader("httpdMerge", "bar", true);
|
||||
do_check_eq(channel.getResponseHeader("httpdMerge"), "bar1,bar2,bar3, bar");
|
||||
|
||||
response = channel.getResponseHeader("Proxy-Authenticate");
|
||||
do_check_eq(response, "line 1\nline 2\nline 3");
|
||||
|
||||
channel.contentCharset = "UTF-8";
|
||||
do_check_eq(channel.contentCharset, "UTF-8");
|
||||
do_check_eq(channel.contentType, "text/plain");
|
||||
do_check_eq(channel.contentLength, httpbody.length);
|
||||
do_check_eq(data, httpbody);
|
||||
|
||||
httpserver.stop(do_test_finished);
|
||||
if (dbg) { print("============== checkRequestResponse: out"); }
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
//
|
||||
// Run test script in content process instead of chrome (xpcshell's default)
|
||||
//
|
||||
|
||||
function run_test() {
|
||||
run_test_in_child("../unit/test_head.js");
|
||||
}
|
Загрузка…
Ссылка в новой задаче