Bug 45143: fix <meta http-equiv="refresh" content="X; url=URI"> to accept URI which contain commas. While I'm at it, merging the implementations in nsDocShell.cpp and nsHTMLContentSink.cpp. r=brendan@mozilla.org, sr=rpotts@netscape.com, a=hofmann

This commit is contained in:
disttsc%bart.nl 2001-04-20 08:11:12 +00:00
parent 97e89fd687
commit 5662ed0812
3 changed files with 211 additions and 216 deletions

View File

@ -19,6 +19,7 @@
*
* Contributor(s):
* Pierre Phaneuf <pp@ludusdesign.com>
* Peter Annema <disttsc@bart.nl>
*/
#include "nsCOMPtr.h"
#include "nsXPIDLString.h"
@ -4298,15 +4299,14 @@ HTMLContentSink::ProcessMETATag(const nsIParserNode& aNode)
*getter_AddRefs(nodeInfo));
NS_ENSURE_SUCCESS(rv, rv);
nsIHTMLContent* it;
rv = NS_NewHTMLMetaElement(&it, nodeInfo);
nsCOMPtr<nsIHTMLContent> it;
rv = NS_NewHTMLMetaElement(getter_AddRefs(it), nodeInfo);
if (NS_OK == rv) {
// Add in the attributes and add the meta content object to the
// head container.
it->SetDocument(mDocument, PR_FALSE, PR_TRUE);
rv = AddAttributes(aNode, it);
if (NS_OK != rv) {
NS_RELEASE(it);
if (NS_FAILED(rv)) {
return rv;
}
parent->AppendChildTo(it, PR_FALSE, PR_FALSE);
@ -4328,7 +4328,6 @@ HTMLContentSink::ProcessMETATag(const nsIParserNode& aNode)
}//if (result.Length() > 0)
}//if (header.Length() > 0)
}//if(!mInsideNoXXXTag)
NS_RELEASE(it);
}//if (NS_OK == rv)
}//if (nsnull != parent)
@ -4375,42 +4374,6 @@ HTMLContentSink::ProcessHeaderData(nsIAtom* aHeader,nsString& aValue,nsIHTMLCont
// see if we have a refresh "header".
if (aHeader == nsHTMLAtoms::refresh) {
// Refresh headers are parsed with the following format in mind
// <META HTTP-EQUIV=REFRESH CONTENT="5; URL=http://uri">
// By the time we are here, the following is true:
// header = "REFRESH"
// result = "5; URL=http://uri" // note the URL attribute is
// optional, if it is absent, the currently loaded url is used.
// Also note that the second and URL seperator can be either a ';'
// or a ','. This breaks some websites. The ',' seperator should be
// illegal but CNN is using it.
//
// We need to handle the following strings.
// - X is a set of digits
// - URI is either a relative or absolute URI
// - FOO is any text
//
// ""
// empty string. use the currently loaded URI
// and refresh immediately.
// "X"
// Refresh the currently loaded URI in X milliseconds.
// "X; URI"
// Refresh using URI as the destination in X milliseconds.
// "X; URI; Blah"
// Refresh using URI as the destination in X milliseconds,
// ignoring "Blah"
// "URI"
// Refresh immediately using URI as the destination.
// "URI; Blah"
// Refresh immediately using URI as the destination,
// ignoring "Blah"
//
// Note that we need to remove any tokens wrapping the URI.
// These tokens currently include spaces, double and single
// quotes.
// first get our baseURI
nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(mWebShell, &rv);
if (NS_FAILED(rv)) return rv;
@ -4419,96 +4382,12 @@ HTMLContentSink::ProcessHeaderData(nsIAtom* aHeader,nsString& aValue,nsIHTMLCont
nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(docShell);
rv = webNav->GetCurrentURI(getter_AddRefs(baseURI));
if (NS_FAILED(rv)) return rv;
PRInt32 millis = -1;
nsAutoString uriAttrib;
PRInt32 semiColon = aValue.FindCharInSet(";,");
nsAutoString token;
if (semiColon > -1)
aValue.Left(token, semiColon);
else
token = aValue;
PRBool done = PR_FALSE;
while (!done && !token.IsEmpty()) {
token.CompressWhitespace();
// Ref. bug 22886
// Apparently CONTENT can also start with a period (.).
// Ex: <meta http-equiv = "refresh" content=".1; url=./recommendations1.html">
// So let's relax a little bit otherwise http://www.mozillazine.org/resources/
// wouldn't get redirected to the correct URL.
if (millis == -1 && (nsCRT::IsAsciiDigit(token.First()) || token.First()==PRUnichar('.'))) {
PRBool tokenIsANumber = PR_TRUE;
nsReadingIterator<PRUnichar> doneIterating; token.EndReading(doneIterating);
nsReadingIterator<PRUnichar> iter; token.BeginReading(iter);
while ( iter != doneIterating ) {
if (!(tokenIsANumber = nsCRT::IsAsciiDigit(*iter)) && *iter!=PRUnichar('.'))
break;
++iter;
}
if (tokenIsANumber) {
PRInt32 err;
millis = token.ToInteger(&err) * 1000;
}
else {
done = PR_TRUE;
}
}
else {
done = PR_TRUE;
}
if (done) {
PRInt32 loc = token.FindChar('=');
if (loc > -1)
token.Cut(0, loc+1);
token.Trim(" \"'");
uriAttrib.Assign(token);
}
else {
// Increment to the next token.
if (semiColon > -1) {
semiColon++;
PRInt32 semiColon2 = aValue.FindCharInSet(";,", semiColon);
if (semiColon2 == -1) semiColon2 = aValue.Length();
aValue.Mid(token, semiColon, semiColon2 - semiColon);
semiColon = semiColon2;
}
else {
done = PR_TRUE;
}
}
} // end while
nsCOMPtr<nsIURI> uri;
if (uriAttrib.Length() == 0) {
uri = baseURI;
} else {
rv = NS_NewURI(getter_AddRefs(uri),
uriAttrib, baseURI);
nsCOMPtr<nsIRefreshURI> reefer = do_QueryInterface(mWebShell);
if (reefer) {
rv = reefer->RefreshURIFromHeader(baseURI, aValue);
if (NS_FAILED(rv)) return rv;
}
if (NS_SUCCEEDED(rv)) {
NS_WITH_SERVICE(nsIScriptSecurityManager,
securityManager,
NS_SCRIPTSECURITYMANAGER_CONTRACTID,
&rv);
if (NS_SUCCEEDED(rv)) {
rv = securityManager->CheckLoadURI(baseURI,
uri,
nsIScriptSecurityManager::DISALLOW_FROM_MAIL);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIRefreshURI> reefer =
do_QueryInterface(mWebShell);
if (reefer) {
if (millis == -1) millis = 0;
rv = reefer->RefreshURI(uri, millis,PR_FALSE, PR_TRUE);
if (NS_FAILED(rv)) return rv;
}//if (reefer)
}//if (NS_SUCCEEDED(rv)) {
}//if (NS_SUCCEEDED(rv)) {
}//if (NS_SUCCEEDED(rv)) {
} // END refresh
else if (aHeader == nsHTMLAtoms::setcookie) {
nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(mWebShell, &rv);

View File

@ -19,6 +19,7 @@
* Contributor(s):
* Travis Bogard <travis@netscape.com>
* Pierre Phaneuf <pp@ludusdesign.com>
* Peter Annema <disttsc@bart.nl>
*/
#include "nsIComponentManager.h"
@ -3833,92 +3834,198 @@ nsDocShell::OnNewURI(nsIURI *aURI, nsIChannel *aChannel, PRUint32 aLoadType)
return NS_OK;
}
nsresult
nsDocShell::RefreshURIFromHeader(nsIURI* aBaseURI, const nsAReadableString& aHeader)
{
// Refresh headers are parsed with the following format in mind
// <META HTTP-EQUIV=REFRESH CONTENT="5; URL=http://uri">
// By the time we are here, the following is true:
// header = "REFRESH"
// content = "5; URL=http://uri" // note the URL attribute is
// optional, if it is absent, the currently loaded url is used.
// Also note that the seconds and URL separator can be either
// a ';' or a ','. The ',' separator should be illegal but CNN
// is using it.
//
// We need to handle the following strings, where
// - X is a set of digits
// - URI is either a relative or absolute URI
//
// Note that URI should start with "url=" but we allow omission
//
// "" || ";" || ","
// empty string. use the currently loaded URI
// and refresh immediately.
// "X" || "X;" || "X,"
// Refresh the currently loaded URI in X seconds.
// "X; URI" || "X, URI"
// Refresh using URI as the destination in X seconds.
// "URI" || "; URI" || ", URI"
// Refresh immediately using URI as the destination.
//
// Currently, anything immediately following the URI, if
// seperated by any char in the set "'\"\t\r\n " will be
// ignored. So "10; url=go.html ; foo=bar" will work,
// and so will "10; url='go.html'; foo=bar". However,
// "10; url=go.html; foo=bar" will result in the uri
// "go.html;" since ';' and ',' are valid uri characters.
//
// Note that we need to remove any tokens wrapping the URI.
// These tokens currently include spaces, double and single
// quotes.
// when done, seconds is 0 or the given number of seconds
// uriAttrib is empty or the URI specified
nsAutoString uriAttrib;
PRInt32 seconds = 0;
nsReadingIterator<PRUnichar> iter, tokenStart, doneIterating;
aHeader.BeginReading(iter);
aHeader.EndReading(doneIterating);
// skip leading whitespace
while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
++iter;
tokenStart = iter;
// skip leading + and -
if (iter != doneIterating && (*iter == '-' || *iter == '+'))
++iter;
// parse number
while (iter != doneIterating && (*iter >= '0' && *iter <= '9')) {
seconds = seconds * 10 + (*iter - '0');
++iter;
}
// bug 22886, part 2: allow X to start with or contain a '.'
if (iter != doneIterating && *iter == '.') {
++iter;
// throw away any digits following it
while (iter != doneIterating && (*iter >= '0' && *iter <= '9'))
++iter;
}
if (iter != doneIterating) {
// if this isn't whitespace, a ';' or a ',', we just parsed part of a URI
if (!(nsCRT::IsAsciiSpace(*iter) || *iter == ';' || *iter == ',')) {
// back to square 1
iter = tokenStart;
seconds = 0;
} else {
// if we started with a '-', number is negative
if (*tokenStart == '-')
seconds = -seconds;
// skip whitespace
while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
++iter;
// skip ';' or ','
if (iter != doneIterating && (*iter == ';' || *iter == ',')) {
++iter;
// skip whitespace
while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
++iter;
}
}
}
// possible start of URI
tokenStart = iter;
// skip "url = " to real start of URI
if (iter != doneIterating && (*iter == 'u' || *iter == 'U')) {
++iter;
if (iter != doneIterating && (*iter == 'r' || *iter == 'R')) {
++iter;
if (iter != doneIterating && (*iter == 'l' || *iter == 'L')) {
++iter;
// skip whitespace
while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
++iter;
if (iter != doneIterating && *iter == '=') {
++iter;
// skip whitespace
while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
++iter;
// found real start of URI
tokenStart = iter;
}
}
}
}
// skip a leading '"' (believe it or not, '\'' is a valid URI char)
if (tokenStart != doneIterating && *tokenStart == '"')
++tokenStart;
// set iter to start of URI
iter = tokenStart;
// tokenStart here points to the beginning of URI
// skip anything which isn't whitespace or '"')
while (iter != doneIterating && !(nsCRT::IsAsciiSpace(*iter) || *iter == '"'))
++iter;
// URI is whatever's contained from tokenStart to iter.
// note: if tokenStart == doneIterating, so is iter.
nsresult rv = NS_OK;
nsCOMPtr<nsIURI> uri;
if (tokenStart == iter) {
uri = aBaseURI;
} else {
uriAttrib = Substring(tokenStart, iter);
rv = NS_NewURI(getter_AddRefs(uri), uriAttrib, aBaseURI);
}
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIScriptSecurityManager> securityManager(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
if (NS_SUCCEEDED(rv)) {
rv = securityManager->CheckLoadURI(aBaseURI, uri, nsIScriptSecurityManager::DISALLOW_FROM_MAIL);
if (NS_SUCCEEDED(rv)) {
// since we can't travel back in time yet, just pretend it was meant figuratively
if (seconds < 0)
seconds = 0;
rv = RefreshURI(uri, seconds * 1000, PR_FALSE, PR_TRUE);
}
}
}
return rv;
}
NS_IMETHODIMP
nsDocShell::SetupRefreshURI(nsIChannel * aChannel)
{
nsCOMPtr<nsIHTTPChannel> httpChannel(do_QueryInterface(aChannel));
if(httpChannel)
{
nsCOMPtr<nsIURI> referrer;
httpChannel->GetReferrer(getter_AddRefs(referrer));
nsresult rv;
nsCOMPtr<nsIHTTPChannel> httpChannel(do_QueryInterface(aChannel, &rv));
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIURI> referrer;
rv = httpChannel->GetReferrer(getter_AddRefs(referrer));
if (NS_SUCCEEDED(rv)) {
SetReferrerURI(referrer);
nsCOMPtr<nsIAtom> refreshAtom(dont_AddRef(NS_NewAtom("refresh")));
nsXPIDLCString refreshHeader;
nsCOMPtr<nsIAtom> refreshAtom ( dont_AddRef( NS_NewAtom("refresh") ) );
httpChannel -> GetResponseHeader (refreshAtom, getter_Copies (refreshHeader));
rv = httpChannel->GetResponseHeader(refreshAtom, getter_Copies(refreshHeader));
if (refreshHeader)
{
nsCOMPtr<nsIURI> baseURI = mCurrentURI;
PRInt32 millis = -1;
nsAutoString uriAttrib;
nsString result; result.AssignWithConversion (refreshHeader);
PRInt32 semiColon = result.FindCharInSet(";,");
nsAutoString token;
if (semiColon > -1)
result.Left(token, semiColon);
else
token = result;
PRBool done = PR_FALSE;
while (!done && !token.IsEmpty()) {
token.CompressWhitespace();
if (millis == -1 && nsCRT::IsAsciiDigit(token.First())) {
PRInt32 i = 0;
PRUnichar value = nsnull;
for ( ; i < (PRInt32) token.Length (); i++)
{
value = token[i];
if (!nsCRT::IsAsciiDigit(value)) {
i = -1;
break;
}
}
if (i > -1) {
PRInt32 err;
millis = token.ToInteger(&err) * 1000;
} else {
done = PR_TRUE;
}
} else {
done = PR_TRUE;
}
if (done) {
PRInt32 loc = token.FindChar('=');
if (loc > -1)
token.Cut(0, loc+1);
token.Trim(" \"'");
uriAttrib = token;
} else {
// Increment to the next token.
if (semiColon > -1) {
semiColon++;
PRInt32 semiColon2 = result.FindCharInSet(";,", semiColon);
if (semiColon2 == -1) semiColon2 = result.Length();
result.Mid(token, semiColon, semiColon2 - semiColon);
semiColon = semiColon2;
} else {
done = PR_TRUE;
}
}
} // end while
nsCOMPtr<nsIURI> uri;
if (!uriAttrib.Length()) {
uri = baseURI;
} else {
NS_NewURI(getter_AddRefs(uri), uriAttrib, baseURI);
}
RefreshURI (uri, millis, PR_FALSE, PR_TRUE);
}
}
return NS_OK;
rv = RefreshURIFromHeader(mCurrentURI, NS_ConvertUTF8toUCS2(refreshHeader));
}
}
return rv;
}
NS_IMETHODIMP nsDocShell::OnLoadingSite(nsIChannel* aChannel)
@ -4096,8 +4203,6 @@ NS_IMETHODIMP nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, PRUint32 aLoadTyp
nsCOMPtr<nsIInputStream> postData;
nsCOMPtr<nsIURI> referrerURI;
PRBool repost = PR_TRUE;
NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE);
nsCOMPtr<nsIHistoryEntry> hEntry(do_QueryInterface(aEntry));
NS_ENSURE_TRUE(hEntry, NS_ERROR_FAILURE);
@ -4108,6 +4213,8 @@ NS_IMETHODIMP nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, PRUint32 aLoadTyp
NS_ERROR_FAILURE);
#if 0
PRBool repost = PR_TRUE;
/* Ask whether to repost form post data */
if (postData) {
nsCOMPtr<nsIPrompt> prompter;

View File

@ -33,16 +33,25 @@ interface nsIRefreshURI : nsISupports {
* @param repeat Do you want the uri to be repeatedly refreshed every millis milliseconds.
* @param flag to check if this is for a META refresh
*/
void refreshURI(in nsIURI aURI, in long aMillis, in boolean aRepeat, in boolean aMetaRefresh);
void refreshURI(in nsIURI aURI, in long aMillis, in boolean aRepeat, in boolean aMetaRefresh);
/**
* Checks the passed in channel to see if there is a refresh header, if there is,
* will setup a refreahURI by calling refreshURI
*/
void setupRefreshURI(in nsIChannel aChannel);
* Checks the passed in channel to see if there is a refresh header, if there is,
* will setup a refreahURI by calling refreshURI
*/
void setupRefreshURI(in nsIChannel aChannel);
/**
* Parses the passed in header string and will call refreshURI with
* the parsed values
*
* @param aBaseURI base URI to resolve refresh uri against
* @param aHeader The meta refresh header string
*/
void refreshURIFromHeader(in nsIURI aBaseURI, in AString aHeader);
/**
* Cancels all timer loads.
*/
void cancelRefreshURITimers();
void cancelRefreshURITimers();
};