michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0:
michael@0: /* Here is the list, from beppe and glazman:
michael@0: href >> A, AREA, BASE, LINK
michael@0: src >> FRAME, IFRAME, IMG, INPUT, SCRIPT
michael@0:
michael@0: longdesc >> FRAME, IFRAME, IMG
michael@0: usemap >> IMG, INPUT, OBJECT
michael@0: action >> FORM
michael@0: background >> BODY
michael@0: codebase >> OBJECT, APPLET
michael@0: classid >> OBJECT
michael@0: data >> OBJECT
michael@0: cite >> BLOCKQUOTE, DEL, INS, Q
michael@0: profile >> HEAD
michael@0: ARCHIVE attribute on APPLET ; warning, it contains a list of URIs.
michael@0:
michael@0: Easier way of organizing the list:
michael@0: a: href
michael@0: area: href
michael@0: base: href
michael@0: body: background
michael@0: blockquote: cite (not normally rewritable)
michael@0: link: href
michael@0: frame: src, longdesc
michael@0: iframe: src, longdesc
michael@0: input: src, usemap
michael@0: form: action
michael@0: img: src, longdesc, usemap
michael@0: script: src
michael@0: applet: codebase, archive
michael@0: object: codebase, data, classid, usemap
michael@0: head: profile
michael@0: del: cite
michael@0: ins: cite
michael@0: q: cite
michael@0: */
michael@0:
michael@0: /* Here is how to open a channel for testing
michael@0: (from embed/qa/testembed/Tests.cpp):
michael@0:
michael@0: nsCOMPtr theChannel;
michael@0: nsCString uri;
michael@0: nsCOMPtr theURI;
michael@0: rv = NS_NewURI(getter_AddRefs(theURI), theSpec);
michael@0: if (!theURI)
michael@0: error;
michael@0: rv = NS_OpenURI(getter_AddRefs(theChannel), theURI, nullptr, theLoadGroup);
michael@0: if (!theChannel)
michael@0: error;
michael@0: nsCOMPtr theLoadGroup(do_CreateInstance(NS_LOADGROUP_CONTRACTID));
michael@0: if (!theLoadGroup)
michael@0: error;
michael@0: nsCOMPtr listener(static_cast(qaBrowserImpl));
michael@0: //nsCOMPtr thisListener(do_GetWeakReference(listener));
michael@0: //qaWebBrowser->AddWebBrowserListener(thisListener, NS_GET_IID(nsIStreamListener));
michael@0:
michael@0: // this calls nsIStreamListener::OnDataAvailable()
michael@0: rv = theChannel->AsyncOpen(listener, nullptr);
michael@0:
michael@0: nsCOMPtr theRequest = do_QueryInterface(theChannel);
michael@0: // Now we can do things on nsIRequest (like what?)
michael@0: */
michael@0:
michael@0: #include "mozilla/mozalloc.h"
michael@0: #include "nsAString.h"
michael@0: #include "nsDebug.h"
michael@0: #include "nsError.h"
michael@0: #include "nsHTMLURIRefObject.h"
michael@0: #include "nsID.h"
michael@0: #include "nsIDOMAttr.h"
michael@0: #include "nsIDOMElement.h"
michael@0: #include "nsIDOMMozNamedAttrMap.h"
michael@0: #include "nsIDOMNode.h"
michael@0: #include "nsISupportsUtils.h"
michael@0: #include "nsString.h"
michael@0:
michael@0: // String classes change too often and I can't keep up.
michael@0: // Set this macro to this week's approved case-insensitive compare routine.
michael@0: #define MATCHES(tagName, str) tagName.EqualsIgnoreCase(str)
michael@0:
michael@0: nsHTMLURIRefObject::nsHTMLURIRefObject()
michael@0: {
michael@0: mCurAttrIndex = mAttributeCnt = 0;
michael@0: }
michael@0:
michael@0: nsHTMLURIRefObject::~nsHTMLURIRefObject()
michael@0: {
michael@0: }
michael@0:
michael@0: //Interfaces for addref and release and queryinterface
michael@0: NS_IMPL_ISUPPORTS(nsHTMLURIRefObject, nsIURIRefObject)
michael@0:
michael@0: NS_IMETHODIMP
michael@0: nsHTMLURIRefObject::Reset()
michael@0: {
michael@0: mCurAttrIndex = 0;
michael@0: return NS_OK;
michael@0: }
michael@0:
michael@0: NS_IMETHODIMP
michael@0: nsHTMLURIRefObject::GetNextURI(nsAString & aURI)
michael@0: {
michael@0: NS_ENSURE_TRUE(mNode, NS_ERROR_NOT_INITIALIZED);
michael@0:
michael@0: nsAutoString tagName;
michael@0: nsresult rv = mNode->GetNodeName(tagName);
michael@0: NS_ENSURE_SUCCESS(rv, rv);
michael@0:
michael@0: // Loop over attribute list:
michael@0: if (!mAttributes)
michael@0: {
michael@0: nsCOMPtr element (do_QueryInterface(mNode));
michael@0: NS_ENSURE_TRUE(element, NS_ERROR_INVALID_ARG);
michael@0:
michael@0: mCurAttrIndex = 0;
michael@0: element->GetAttributes(getter_AddRefs(mAttributes));
michael@0: NS_ENSURE_TRUE(mAttributes, NS_ERROR_NOT_INITIALIZED);
michael@0:
michael@0: rv = mAttributes->GetLength(&mAttributeCnt);
michael@0: NS_ENSURE_SUCCESS(rv, rv);
michael@0: NS_ENSURE_TRUE(mAttributeCnt, NS_ERROR_FAILURE);
michael@0: mCurAttrIndex = 0;
michael@0: }
michael@0: #ifdef DEBUG_akkana
michael@0: printf("Looking at tag '%s'\n",
michael@0: NS_LossyConvertUTF16toASCII(tagName).get());
michael@0: #endif
michael@0: while (mCurAttrIndex < mAttributeCnt)
michael@0: {
michael@0: nsCOMPtr attrNode;
michael@0: rv = mAttributes->Item(mCurAttrIndex++, getter_AddRefs(attrNode));
michael@0: NS_ENSURE_SUCCESS(rv, rv);
michael@0: NS_ENSURE_ARG_POINTER(attrNode);
michael@0: nsString curAttr;
michael@0: rv = attrNode->GetName(curAttr);
michael@0: NS_ENSURE_SUCCESS(rv, rv);
michael@0:
michael@0: // href >> A, AREA, BASE, LINK
michael@0: #ifdef DEBUG_akkana
michael@0: printf("Trying to match attribute '%s'\n",
michael@0: NS_LossyConvertUTF16toASCII(curAttr).get());
michael@0: #endif
michael@0: if (MATCHES(curAttr, "href"))
michael@0: {
michael@0: if (!MATCHES(tagName, "a") && !MATCHES(tagName, "area")
michael@0: && !MATCHES(tagName, "base") && !MATCHES(tagName, "link"))
michael@0: continue;
michael@0: rv = attrNode->GetValue(aURI);
michael@0: NS_ENSURE_SUCCESS(rv, rv);
michael@0: nsString uri (aURI);
michael@0: // href pointing to a named anchor doesn't count
michael@0: if (aURI.First() != char16_t('#'))
michael@0: return NS_OK;
michael@0: aURI.Truncate();
michael@0: return NS_ERROR_INVALID_ARG;
michael@0: }
michael@0: // src >> FRAME, IFRAME, IMG, INPUT, SCRIPT
michael@0: else if (MATCHES(curAttr, "src"))
michael@0: {
michael@0: if (!MATCHES(tagName, "img")
michael@0: && !MATCHES(tagName, "frame") && !MATCHES(tagName, "iframe")
michael@0: && !MATCHES(tagName, "input") && !MATCHES(tagName, "script"))
michael@0: continue;
michael@0: return attrNode->GetValue(aURI);
michael@0: }
michael@0: //
michael@0: else if (MATCHES(curAttr, "content"))
michael@0: {
michael@0: if (!MATCHES(tagName, "meta"))
michael@0: continue;
michael@0: }
michael@0: // longdesc >> FRAME, IFRAME, IMG
michael@0: else if (MATCHES(curAttr, "longdesc"))
michael@0: {
michael@0: if (!MATCHES(tagName, "img")
michael@0: && !MATCHES(tagName, "frame") && !MATCHES(tagName, "iframe"))
michael@0: continue;
michael@0: }
michael@0: // usemap >> IMG, INPUT, OBJECT
michael@0: else if (MATCHES(curAttr, "usemap"))
michael@0: {
michael@0: if (!MATCHES(tagName, "img")
michael@0: && !MATCHES(tagName, "input") && !MATCHES(tagName, "object"))
michael@0: continue;
michael@0: }
michael@0: // action >> FORM
michael@0: else if (MATCHES(curAttr, "action"))
michael@0: {
michael@0: if (!MATCHES(tagName, "form"))
michael@0: continue;
michael@0: }
michael@0: // background >> BODY
michael@0: else if (MATCHES(curAttr, "background"))
michael@0: {
michael@0: if (!MATCHES(tagName, "body"))
michael@0: continue;
michael@0: }
michael@0: // codebase >> OBJECT, APPLET
michael@0: else if (MATCHES(curAttr, "codebase"))
michael@0: {
michael@0: if (!MATCHES(tagName, "meta"))
michael@0: continue;
michael@0: }
michael@0: // classid >> OBJECT
michael@0: else if (MATCHES(curAttr, "classid"))
michael@0: {
michael@0: if (!MATCHES(tagName, "object"))
michael@0: continue;
michael@0: }
michael@0: // data >> OBJECT
michael@0: else if (MATCHES(curAttr, "data"))
michael@0: {
michael@0: if (!MATCHES(tagName, "object"))
michael@0: continue;
michael@0: }
michael@0: // cite >> BLOCKQUOTE, DEL, INS, Q
michael@0: else if (MATCHES(curAttr, "cite"))
michael@0: {
michael@0: if (!MATCHES(tagName, "blockquote") && !MATCHES(tagName, "q")
michael@0: && !MATCHES(tagName, "del") && !MATCHES(tagName, "ins"))
michael@0: continue;
michael@0: }
michael@0: // profile >> HEAD
michael@0: else if (MATCHES(curAttr, "profile"))
michael@0: {
michael@0: if (!MATCHES(tagName, "head"))
michael@0: continue;
michael@0: }
michael@0: // archive attribute on APPLET; warning, it contains a list of URIs.
michael@0: else if (MATCHES(curAttr, "archive"))
michael@0: {
michael@0: if (!MATCHES(tagName, "applet"))
michael@0: continue;
michael@0: }
michael@0: }
michael@0: // Return a code to indicate that there are no more,
michael@0: // to distinguish that case from real errors.
michael@0: return NS_ERROR_NOT_AVAILABLE;
michael@0: }
michael@0:
michael@0: NS_IMETHODIMP
michael@0: nsHTMLURIRefObject::RewriteAllURIs(const nsAString & aOldPat,
michael@0: const nsAString & aNewPat,
michael@0: bool aMakeRel)
michael@0: {
michael@0: #ifdef DEBUG_akkana
michael@0: printf("Can't rewrite URIs yet\n");
michael@0: #endif
michael@0: return NS_ERROR_NOT_IMPLEMENTED;
michael@0: }
michael@0:
michael@0: NS_IMETHODIMP
michael@0: nsHTMLURIRefObject::GetNode(nsIDOMNode** aNode)
michael@0: {
michael@0: NS_ENSURE_TRUE(mNode, NS_ERROR_NOT_INITIALIZED);
michael@0: NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
michael@0: *aNode = mNode.get();
michael@0: NS_ADDREF(*aNode);
michael@0: return NS_OK;
michael@0: }
michael@0:
michael@0: NS_IMETHODIMP
michael@0: nsHTMLURIRefObject::SetNode(nsIDOMNode *aNode)
michael@0: {
michael@0: mNode = aNode;
michael@0: nsAutoString dummyURI;
michael@0: if (NS_SUCCEEDED(GetNextURI(dummyURI)))
michael@0: {
michael@0: mCurAttrIndex = 0; // Reset so we'll get the first node next time
michael@0: return NS_OK;
michael@0: }
michael@0:
michael@0: // If there weren't any URIs in the attributes,
michael@0: // then don't accept this node.
michael@0: mNode = 0;
michael@0: return NS_ERROR_INVALID_ARG;
michael@0: }
michael@0:
michael@0: nsresult NS_NewHTMLURIRefObject(nsIURIRefObject** aResult, nsIDOMNode* aNode)
michael@0: {
michael@0: nsHTMLURIRefObject* refObject = new nsHTMLURIRefObject();
michael@0: nsresult rv = refObject->SetNode(aNode);
michael@0: if (NS_FAILED(rv)) {
michael@0: *aResult = 0;
michael@0: delete refObject;
michael@0: return rv;
michael@0: }
michael@0: return refObject->QueryInterface(NS_GET_IID(nsIURIRefObject),
michael@0: (void**)aResult);
michael@0: }
michael@0: