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:
Jason Duell 2010-03-23 08:14:36 -07:00
Родитель 40d5c21556
Коммит 3898298861
14 изменённых файлов: 559 добавлений и 83 удалений

Просмотреть файл

@ -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");
}