SRC and HREF attributes turned into clickable links in view source. p=cbartley r+sr=mrbkap a=beltzner b=17612

This commit is contained in:
Curtis Bartley 2008-11-10 16:18:39 -05:00
Родитель 505c7e907d
Коммит a20f5060d4
2 изменённых файлов: 310 добавлений и 77 удалений

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

@ -75,6 +75,7 @@
#include "nsIPrefBranch.h"
#include "nsUnicharUtils.h"
#include "nsPrintfCString.h"
#include "nsNetUtil.h"
#include "nsIServiceManager.h"
@ -254,10 +255,10 @@ CViewSourceHTML::~CViewSourceHTML(){
* The parser uses a code sandwich to wrap the parsing process. Before
* the process begins, WillBuildModel() is called. Afterwards the parser
* calls DidBuildModel().
* @update rickg 03.20.2000
* @param aParserContext
* @param aSink
* @return error code (almost always 0)
* @update rickg 03.20.2000
* @param aParserContext
* @param aSink
* @return error code (almost always 0)
*/
nsresult CViewSourceHTML::WillBuildModel(const CParserContext& aParserContext,
nsITokenizer* aTokenizer,
@ -332,9 +333,9 @@ nsresult CViewSourceHTML::WillBuildModel(const CParserContext& aParserContext,
* The parser uses a code sandwich to wrap the parsing process. Before
* the process begins, WillBuildModel() is called. Afterwards the parser
* calls DidBuildModel().
* @update gess5/18/98
* @param aFilename is the name of the file being parsed.
* @return error code (almost always 0)
* @update gess5/18/98
* @param aFilename is the name of the file being parsed.
* @return error code (almost always 0)
*/
NS_IMETHODIMP CViewSourceHTML::BuildModel(nsIParser* aParser,nsITokenizer* aTokenizer,nsITokenObserver* anObserver,nsIContentSink* aSink) {
nsresult result=NS_OK;
@ -541,7 +542,7 @@ void CViewSourceHTML::AddAttrToNode(nsCParserStartNode& aNode,
/**
*
* @update gess5/18/98
* @update gess5/18/98
* @param
* @return
*/
@ -596,7 +597,7 @@ NS_IMETHODIMP CViewSourceHTML::DidBuildModel(nsresult anErrorCode,PRBool aNotify
* It's recommended to use this method in accordance with
* the parser's terminate() method.
*
* @update harishd 07/22/99
* @update harishd 07/22/99
* @param
* @return
*/
@ -611,7 +612,7 @@ CViewSourceHTML::GetType() {
/**
*
* @update gess5/18/98
* @update gess5/18/98
* @param
* @return
*/
@ -625,7 +626,7 @@ NS_IMETHODIMP CViewSourceHTML::WillResumeParse(nsIContentSink* aSink){
/**
*
* @update gess5/18/98
* @update gess5/18/98
* @param
* @return
*/
@ -640,7 +641,7 @@ NS_IMETHODIMP CViewSourceHTML::WillInterruptParse(nsIContentSink* aSink){
/**
* Called by the parser to enable/disable dtd verification of the
* internal context stack.
* @update gess 7/23/98
* @update gess 7/23/98
* @param
* @return
*/
@ -682,7 +683,9 @@ PRBool CViewSourceHTML::IsContainer(PRInt32 aTag) const{
* @param
* @return result status
*/
nsresult CViewSourceHTML::WriteAttributes(PRInt32 attrCount, PRBool aOwnerInError) {
nsresult CViewSourceHTML::WriteAttributes(const nsAString& tagName,
nsTokenAllocator* allocator,
PRInt32 attrCount, PRBool aOwnerInError) {
nsresult result=NS_OK;
if(attrCount){ //go collect the attributes...
@ -706,7 +709,11 @@ nsresult CViewSourceHTML::WriteAttributes(PRInt32 attrCount, PRBool aOwnerInErro
const nsSubstring& theValue = theAttrToken->GetValue();
if(!theValue.IsEmpty() || theAttrToken->mHasEqualWithoutValue){
result = WriteTag(kAttributeValue,theValue,0,attributeInError);
if (IsUrlAttribute(tagName, theKey, theValue)) {
WriteHrefAttribute(allocator, theValue);
} else {
WriteTag(kAttributeValue,theValue,0,attributeInError);
}
}
}
}
@ -816,7 +823,7 @@ nsresult CViewSourceHTML::WriteTag(PRInt32 aTagType,const nsSubstring & aText,PR
}
if(attrCount){
result=WriteAttributes(attrCount, aTagInError);
result=WriteAttributes(aText, theAllocator, attrCount, aTagInError);
}
// Tokens are set in error if their ending > is not there, so don't output
@ -981,3 +988,209 @@ NS_IMETHODIMP CViewSourceHTML::HandleToken(CToken* aToken,nsIParser* aParser)
return result;
}
PRBool CViewSourceHTML::IsUrlAttribute(const nsAString& tagName,
const nsAString& attrName,
const nsAString& attrValue) {
const nsSubstring &trimmedAttrName = TrimTokenValue(attrName);
PRBool isHref = trimmedAttrName.LowerCaseEqualsLiteral("href");
PRBool isSrc = !isHref && trimmedAttrName.LowerCaseEqualsLiteral("src");
// If this is the HREF attribute of a BASE element, then update the base URI.
// This doesn't feel like the ideal place for this, but the alternatives don't
// seem all that nice either.
if (isHref && tagName.LowerCaseEqualsLiteral("base")) {
const nsSubstring& baseSpec = TrimTokenValue(attrValue);
SetBaseURI(baseSpec);
}
return isHref || isSrc;
}
void CViewSourceHTML::WriteHrefAttribute(nsTokenAllocator* allocator,
const nsAString& href) {
// The "href" will typically contain not only the href proper, but the single
// or double quotes and often some surrounding whitespace as well. Find the
// location of the href proper inside the string.
nsAString::const_iterator startProper, endProper;
href.BeginReading(startProper);
href.EndReading(endProper);
TrimTokenValue(startProper, endProper);
// Break the href into three parts, the preceding text, the href proper, and
// the succeeding text.
nsAString::const_iterator start, end;
href.BeginReading(start);
href.EndReading(end);
const nsAString &precedingText = Substring(start, startProper);
const nsAString &hrefProper = Substring(startProper, endProper);
const nsAString &succeedingText = Substring(endProper, end);
nsAutoString fullPrecedingText;
fullPrecedingText.Assign(kEqual);
fullPrecedingText.Append(precedingText);
// Regular URLs and view-source URLs work the same way for .js and .css files.
// However, if the user follows a link in the view source window to a .html
// file (i.e. the HREF in an A tag), then presumably they will expect to see
// the *source* of that new page, not the rendered version. So for now we
// just slap a "view-source:" at the beginning of each URL. There are two
// big downsides to doing it this way -- we must make relative URLs into
// absolute URLs before we can turn them into view-source URLs, and links
// to images don't work right -- nobody wants to see the bytes constituting a
// PNG rendered as text. A smarter view-source handler might be able to deal
// with the latter problem.
// Construct a "view-source" URL for the HREF.
nsAutoString viewSourceUrl;
CreateViewSourceURL(hrefProper, viewSourceUrl);
// Construct the HTML that will represent the HREF.
NS_NAMED_LITERAL_STRING(HREF, "href");
if (fullPrecedingText.Length() > 0) {
WriteTextInSpan(fullPrecedingText, allocator, EmptyString(), EmptyString());
}
WriteTextInAnchor(hrefProper, allocator, HREF, viewSourceUrl);
if (succeedingText.Length() > 0) {
WriteTextInSpan(succeedingText, allocator, EmptyString(), EmptyString());
}
}
nsresult CViewSourceHTML::CreateViewSourceURL(const nsAString& linkUrl,
nsString& viewSourceUrl) {
nsCOMPtr<nsIURI> baseURI;
nsCOMPtr<nsIURI> hrefURI;
nsresult rv;
// Default the view source URL to the empty string in case we fail. Links
// with empty HREFs are essentially non-functional, at least as of Firefox
// 3.03. This is preferrable behavior to links that look good but then 404.
viewSourceUrl.Truncate();
// Get the character set.
nsCString charset;
PRInt32 source;
mParser->GetDocumentCharset(charset, source);
// Get the BaseURI.
rv = GetBaseURI(getter_AddRefs(baseURI));
NS_ENSURE_SUCCESS(rv, rv);
// Use the link URL and the base URI to build a URI for the link.
rv = NS_NewURI(getter_AddRefs(hrefURI), linkUrl, charset.get(), baseURI);
NS_ENSURE_SUCCESS(rv, rv);
// Get the absolute URL from the link URI.
nsCString absoluteLinkUrl;
hrefURI->GetSpec(absoluteLinkUrl);
// Prepend "view-source:" onto the absolute URL and store it in the out param.
viewSourceUrl.AssignLiteral("view-source:");
viewSourceUrl.AppendWithConversion(absoluteLinkUrl);
return NS_OK;
}
void CViewSourceHTML::WriteTextInSpan(const nsAString& text,
nsTokenAllocator* allocator,
const nsAString& attrName,
const nsAString& attrValue) {
NS_NAMED_LITERAL_STRING(SPAN, "SPAN");
WriteTextInElement(SPAN, eHTMLTag_span, text, allocator, attrName, attrValue);
}
void CViewSourceHTML::WriteTextInAnchor(const nsAString& text,
nsTokenAllocator* allocator,
const nsAString& attrName,
const nsAString& attrValue) {
NS_NAMED_LITERAL_STRING(ANCHOR, "A");
WriteTextInElement(ANCHOR, eHTMLTag_a, text, allocator, attrName, attrValue);
}
void CViewSourceHTML::WriteTextInElement(const nsAString& tagName,
eHTMLTags tagType, const nsAString& text,
nsTokenAllocator* allocator,
const nsAString& attrName,
const nsAString& attrValue) {
// Open the element, supplying the attribute, if any.
CStartToken startToken(tagName, tagType);
nsCParserStartNode startNode(&startToken, 0/*stack token*/);
if (!attrName.IsEmpty()) {
AddAttrToNode(startNode, allocator, attrName, attrValue);
}
mSink->OpenContainer(startNode);
// Add the text node.
CTextToken textToken(text);
nsCParserNode textNode(&textToken, 0/*stack token*/);
mSink->AddLeaf(textNode);
// Close the element.
mSink->CloseContainer(tagType);
}
const nsDependentSubstring CViewSourceHTML::TrimTokenValue(const nsAString& tokenValue) {
nsAString::const_iterator start, end;
tokenValue.BeginReading(start);
tokenValue.EndReading(end);
TrimTokenValue(start, end);
return Substring(start, end);
}
void CViewSourceHTML::TrimTokenValue(nsAString::const_iterator& start,
nsAString::const_iterator& end) {
// Token values -- tag names, attribute names, and attribute values --
// generally contain adjacent whitespace and, in the case of attribute values,
// the surrounding double or single quotes. Return a new string with this
// adjacent text stripped off, so only the value proper remains.
// Skip past any whitespace or quotes on the left.
while (start != end) {
if (!IsTokenValueTrimmableCharacter(*start)) break;
++start;
}
// Skip past any whitespace or quotes on the right. Note that the interval
// start..end is half-open. That means the last character of the interval is
// at *(end - 1).
while (end != start) {
--end;
if (!IsTokenValueTrimmableCharacter(*end)) {
++end; // we've actually gone one too far at this point, so adjust.
break;
}
}
}
PRBool CViewSourceHTML::IsTokenValueTrimmableCharacter(char ch) {
if (ch == ' ') return PR_TRUE;
if (ch == '\t') return PR_TRUE;
if (ch == '\r') return PR_TRUE;
if (ch == '\t') return PR_TRUE;
if (ch == '\'') return PR_TRUE;
if (ch == '"') return PR_TRUE;
return PR_FALSE;
}
nsresult CViewSourceHTML::GetBaseURI(nsIURI **result) {
nsresult rv = NS_OK;
if (!mBaseURI) {
rv = SetBaseURI(mFilename);
}
NS_IF_ADDREF(*result = mBaseURI);
return rv;
}
nsresult CViewSourceHTML::SetBaseURI(const nsAString& baseSpec) {
// Get the character set.
nsCString charset;
PRInt32 source;
mParser->GetDocumentCharset(charset, source);
// Create a new base URI and store it in mBaseURI.
nsCOMPtr<nsIURI> baseURI;
nsresult rv = NS_NewURI(getter_AddRefs(baseURI), baseSpec, charset.get());
NS_ENSURE_SUCCESS(rv, rv);
mBaseURI = baseURI;
return NS_OK;
}

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

@ -88,7 +88,7 @@ public:
/**
* Set this to TRUE if you want the DTD to verify its
* context stack.
* @update gess 7/23/98
* @update gess 7/23/98
* @param
* @return
*/
@ -100,7 +100,8 @@ private:
PRInt32 attrCount,
PRBool aTagInError);
nsresult WriteAttributes(PRInt32 attrCount, PRBool aOwnerInError);
nsresult WriteAttributes(const nsAString& tagName,
nsTokenAllocator* allocator, PRInt32 attrCount, PRBool aOwnerInError);
void StartNewPreBlock(void);
// Utility method for adding attributes to the nodes we generate
void AddAttrToNode(nsCParserStartNode& aNode,
@ -108,6 +109,24 @@ private:
const nsAString& aAttrName,
const nsAString& aAttrValue);
PRBool IsUrlAttribute(const nsAString& tagName,
const nsAString& attrName, const nsAString& attrValue);
void WriteHrefAttribute(nsTokenAllocator* allocator, const nsAString& href);
nsresult CreateViewSourceURL(const nsAString& linkUrl, nsString& viewSourceUrl);
void WriteTextInSpan(const nsAString& text, nsTokenAllocator* allocator,
const nsAString& attrName, const nsAString& attrValue);
void WriteTextInAnchor(const nsAString& text, nsTokenAllocator* allocator,
const nsAString& attrName, const nsAString &attrValue);
void WriteTextInElement(const nsAString& tagName, eHTMLTags tagType,
const nsAString& text, nsTokenAllocator* allocator,
const nsAString& attrName, const nsAString& attrValue);
const nsDependentSubstring TrimTokenValue(const nsAString& tokenValue);
void TrimTokenValue(nsAString::const_iterator& start,
nsAString::const_iterator& end);
PRBool IsTokenValueTrimmableCharacter(char ch);
nsresult GetBaseURI(nsIURI **result);
nsresult SetBaseURI(const nsAString& baseSpec);
protected:
nsParser* mParser;
@ -126,6 +145,7 @@ protected:
nsCString mMimeType;
nsString mFilename;
nsCOMPtr<nsIURI> mBaseURI; // lazy -- always use GetBaseURI().
PRUint32 mTokenCount;