From 4a4110664c8452b5615c671bb349e8c729c43a21 Mon Sep 17 00:00:00 2001 From: Julian Reschke Date: Sat, 23 Jul 2011 14:31:49 +0200 Subject: [PATCH] Bug 666562. fix quoted-string unescaping in HTTP link header fields, r=bzbarsky --- content/base/src/nsContentSink.cpp | 53 ++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/content/base/src/nsContentSink.cpp b/content/base/src/nsContentSink.cpp index e09ff33db984..fcb2fdf0830c 100644 --- a/content/base/src/nsContentSink.cpp +++ b/content/base/src/nsContentSink.cpp @@ -557,13 +557,6 @@ nsContentSink::DoProcessLinkHeader() ProcessLinkHeader(nsnull, value); } -static const PRUnichar kSemiCh = PRUnichar(';'); -static const PRUnichar kCommaCh = PRUnichar(','); -static const PRUnichar kEqualsCh = PRUnichar('='); -static const PRUnichar kLessThanCh = PRUnichar('<'); -static const PRUnichar kGreaterThanCh = PRUnichar('>'); - - // check whether the Link header field applies to the context resource // see @@ -642,22 +635,31 @@ nsContentSink::ProcessLinkHeader(nsIContent* aElement, end = start; last = end - 1; + PRBool needsUnescape = PR_FALSE; + // look for semicolon or comma - while (*end != kNullCh && *end != kSemiCh && *end != kCommaCh) { + while (*end != kNullCh && *end != kSemicolon && *end != kComma) { PRUnichar ch = *end; - if (ch == kApostrophe || ch == kQuote || ch == kLessThanCh) { + if (ch == kApostrophe || ch == kQuote || ch == kLessThan) { // quoted string - PRUnichar quote = *end; - if (quote == kLessThanCh) { - quote = kGreaterThanCh; + PRUnichar quote = ch; + if (quote == kLessThan) { + quote = kGreaterThan; } - + + needsUnescape = (ch == kQuote); + PRUnichar* closeQuote = (end + 1); // seek closing quote while (*closeQuote != kNullCh && quote != *closeQuote) { + // in quoted-string, "\" is an escape character + if (needsUnescape && *closeQuote == kBackSlash && *(closeQuote + 1) != kNullCh) { + ++closeQuote; + } + ++closeQuote; } @@ -671,14 +673,14 @@ nsContentSink::ProcessLinkHeader(nsIContent* aElement, ch = *(end + 1); - if (ch != kNullCh && ch != kSemiCh && ch != kCommaCh) { + if (ch != kNullCh && ch != kSemicolon && ch != kComma) { // end string here *(++end) = kNullCh; ch = *(end + 1); // keep going until semi or comma - while (ch != kNullCh && ch != kSemiCh && ch != kCommaCh) { + while (ch != kNullCh && ch != kSemicolon && ch != kComma) { ++end; ch = *end; @@ -697,7 +699,7 @@ nsContentSink::ProcessLinkHeader(nsIContent* aElement, *end = kNullCh; if (start < end) { - if ((*start == kLessThanCh) && (*last == kGreaterThanCh)) { + if ((*start == kLessThan) && (*last == kGreaterThan)) { *last = kNullCh; if (href.IsEmpty()) { // first one wins @@ -707,7 +709,7 @@ nsContentSink::ProcessLinkHeader(nsIContent* aElement, } else { PRUnichar* equals = start; - while ((*equals != kNullCh) && (*equals != kEqualsCh)) { + while ((*equals != kNullCh) && (*equals != kEqual)) { equals++; } @@ -727,6 +729,21 @@ nsContentSink::ProcessLinkHeader(nsIContent* aElement, value++; } + if (needsUnescape) { + // unescape in-place + PRUnichar* unescaped = value; + PRUnichar *src = value; + + while (*src != kNullCh) { + if (*src == kBackSlash && *(src + 1) != kNullCh) { + src++; + } + *unescaped++ = *src++; + } + + *unescaped = kNullCh; + } + if (attr.LowerCaseEqualsLiteral("rel")) { if (rel.IsEmpty()) { rel = value; @@ -759,7 +776,7 @@ nsContentSink::ProcessLinkHeader(nsIContent* aElement, } } - if (endCh == kCommaCh) { + if (endCh == kComma) { // hit a comma, process what we've got so far href.Trim(" \t\n\r\f"); // trim HTML5 whitespace