Prevent double submission of forms (bug 72906). r=darin@netscape.com, r=alexsavulov@netscape.com, sr=alecf@netscape.com, a=asa

This commit is contained in:
jkeiser%netscape.com 2002-03-13 06:08:56 +00:00
parent a38050b457
commit aeb4d3fdbb
11 changed files with 309 additions and 102 deletions

View File

@ -48,8 +48,10 @@ class nsIPresContext;
class nsIContent;
class nsIFormControl;
class nsIDOMHTMLElement;
class nsIDocShell;
class nsIRequest;
#define NS_IFORMSUBMITTER_IID \
#define NS_IFORMSUBMISSION_IID \
{ 0x7ee38e3a, 0x1dd2, 0x11b2, \
{0x89, 0x6f, 0xab, 0x28, 0x03, 0x96, 0x25, 0xa9} }
@ -61,7 +63,7 @@ class nsIFormSubmission : public nsISupports
{
public:
NS_DEFINE_STATIC_IID_ACCESSOR(NS_IFORMSUBMITTER_IID)
NS_DEFINE_STATIC_IID_ACCESSOR(NS_IFORMSUBMISSION_IID)
/**
* Find out whether or not this form submission accepts files
@ -77,9 +79,13 @@ public:
* @param aTarget the target window
* @param aSource the element responsible for the submission (for web shell)
* @param aPresContext the presentation context
* @param aDocShell (out param) the DocShell in which the submission was
* loaded
* @param aRequest (out param) the Request for the submission
*/
NS_IMETHOD SubmitTo(nsIURI* aActionURL, const nsAString& aTarget,
nsIContent* aSource, nsIPresContext* aPresContext) = 0;
nsIContent* aSource, nsIPresContext* aPresContext,
nsIDocShell** aDocShell, nsIRequest** aRequest) = 0;
/**
* Submit a name/value pair

View File

@ -38,6 +38,7 @@ REQUIRES = xpcom \
locale \
unicharutil \
webshell \
uriloader \
htmlparser \
necko \
view \

View File

@ -32,6 +32,7 @@ REQUIRES = xpcom \
webshell \
htmlparser \
necko \
uriloader \
view \
pref \
docshell \

View File

@ -98,7 +98,8 @@ public:
// nsIFormSubmission
//
NS_IMETHOD SubmitTo(nsIURI* aActionURL, const nsAString& aTarget,
nsIContent* aSource, nsIPresContext* aPresContext);
nsIContent* aSource, nsIPresContext* aPresContext,
nsIDocShell** aDocShell, nsIRequest** aRequest);
NS_IMETHOD Init() = 0;
@ -719,7 +720,8 @@ GetSubmissionFromForm(nsIForm* aForm,
NS_IMETHODIMP
nsFormSubmission::SubmitTo(nsIURI* aActionURL, const nsAString& aTarget,
nsIContent* aSource, nsIPresContext* aPresContext)
nsIContent* aSource, nsIPresContext* aPresContext,
nsIDocShell** aDocShell, nsIRequest** aRequest)
{
nsresult rv;
@ -739,9 +741,11 @@ nsFormSubmission::SubmitTo(nsIURI* aActionURL, const nsAString& aTarget,
nsCAutoString actionURLSpec;
aActionURL->GetSpec(actionURLSpec);
handler->OnLinkClick(aSource, eLinkVerb_Replace,
NS_ConvertUTF8toUCS2(actionURLSpec).get(),
PromiseFlatString(aTarget).get(), postDataStream);
handler->OnLinkClickSync(aSource, eLinkVerb_Replace,
NS_ConvertUTF8toUCS2(actionURLSpec).get(),
PromiseFlatString(aTarget).get(),
postDataStream, nsnull,
aDocShell, aRequest);
}
return rv;

View File

@ -75,6 +75,10 @@
#include "nsRange.h"
#include "nsIScriptSecurityManager.h"
#include "nsNetUtil.h"
#include "nsIWebProgress.h"
#include "nsIDocShell.h"
#include "nsIWebProgressListener.h"
#include "nsWeakReference.h"
// radio buttons
#include "nsIDOMHTMLInputElement.h"
@ -88,15 +92,20 @@ class nsFormControlList;
// nsHTMLFormElement
class nsHTMLFormElement : public nsGenericHTMLContainerElement,
public nsSupportsWeakReference,
public nsIDOMHTMLFormElement,
public nsIDOMNSHTMLFormElement,
public nsIWebProgressListener,
public nsIForm
{
public:
nsHTMLFormElement() :
mGeneratingSubmit(PR_FALSE),
mGeneratingReset(PR_FALSE),
mDemotingForm(PR_FALSE) { };
mDemotingForm(PR_FALSE),
mIsSubmitting(PR_FALSE),
mSubmittingRequest(nsnull) { }
virtual ~nsHTMLFormElement();
@ -120,6 +129,9 @@ public:
// nsIDOMNSHTMLFormElement
NS_DECL_NSIDOMNSHTMLFORMELEMENT
// nsIWebProgressListener
NS_DECL_NSIWEBPROGRESSLISTENER
// nsIForm
NS_IMETHOD AddElement(nsIFormControl* aElement);
NS_IMETHOD AddElementToTable(nsIFormControl* aChild,
@ -217,6 +229,8 @@ protected:
PRPackedBool mGeneratingSubmit;
PRPackedBool mGeneratingReset;
PRPackedBool mDemotingForm;
PRPackedBool mIsSubmitting;
nsCOMPtr<nsIRequest> mSubmittingRequest;
protected:
// Detection of first form to notify observers
@ -393,9 +407,11 @@ NS_IMPL_RELEASE_INHERITED(nsHTMLFormElement, nsGenericElement)
// QueryInterface implementation for nsHTMLFormElement
NS_HTML_CONTENT_INTERFACE_MAP_BEGIN(nsHTMLFormElement,
nsGenericHTMLContainerElement)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY(nsIDOMHTMLFormElement)
NS_INTERFACE_MAP_ENTRY(nsIDOMNSHTMLFormElement)
NS_INTERFACE_MAP_ENTRY(nsIForm)
NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(HTMLFormElement)
NS_HTML_CONTENT_INTERFACE_MAP_END
@ -652,9 +668,26 @@ nsHTMLFormElement::DoReset()
return NS_OK;
}
#define NS_ENSURE_SUBMIT_SUCCESS(rv) \
if (NS_FAILED(rv)) { \
mIsSubmitting = PR_FALSE; \
return rv; \
}
nsresult
nsHTMLFormElement::DoSubmit(nsIPresContext* aPresContext, nsEvent* aEvent)
{
NS_ASSERTION(!mIsSubmitting, "Either two people are trying to submit or the "
"previous submit was not properly cancelled by the DocShell");
if (mIsSubmitting) {
// XXX Should this return an error?
return NS_OK;
}
// Mark us as submitting so that we don't try to submit again
mIsSubmitting = PR_TRUE;
mSubmittingRequest = nsnull;
nsIContent *originatingElement = nsnull;
// Get the originating frame (failure is non-fatal)
@ -670,42 +703,54 @@ nsHTMLFormElement::DoSubmit(nsIPresContext* aPresContext, nsEvent* aEvent)
nsCOMPtr<nsIFormSubmission> submission;
nsresult rv = GetSubmissionFromForm(this, aPresContext,
getter_AddRefs(submission));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_SUBMIT_SUCCESS(rv);
//
// Dump the data into the submission object
//
rv = WalkFormElements(submission, originatingElement);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_SUBMIT_SUCCESS(rv);
//
// Get the action and target
//
nsCOMPtr<nsIURI> actionURI;
rv = GetActionURL(getter_AddRefs(actionURI));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_SUBMIT_SUCCESS(rv);
if (actionURI) {
nsAutoString target;
rv = GetTarget(target);
NS_ENSURE_SUCCESS(rv, rv);
//
// Notify observers of submit
//
PRBool aCancelSubmit = PR_FALSE;
rv = NotifySubmitObservers(actionURI, &aCancelSubmit);
NS_ENSURE_SUCCESS(rv, rv);
if (!aCancelSubmit) {
//
// Submit
//
rv = submission->SubmitTo(actionURI, target, this, aPresContext);
}
if (!actionURI) {
mIsSubmitting = PR_FALSE;
return NS_OK;
}
return rv;
nsAutoString target;
rv = GetTarget(target);
NS_ENSURE_SUBMIT_SUCCESS(rv);
//
// Notify observers of submit
//
PRBool aCancelSubmit = PR_FALSE;
rv = NotifySubmitObservers(actionURI, &aCancelSubmit);
NS_ENSURE_SUBMIT_SUCCESS(rv);
if (aCancelSubmit) {
mIsSubmitting = PR_FALSE;
return NS_OK;
}
//
// Submit
//
nsCOMPtr<nsIDocShell> docShell;
rv = submission->SubmitTo(actionURI, target, this, aPresContext,
getter_AddRefs(docShell),
getter_AddRefs(mSubmittingRequest));
NS_ENSURE_SUBMIT_SUCCESS(rv);
nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
NS_ASSERTION(webProgress, "nsIDocShell null or not converted to nsIWebProgress!");
return webProgress->AddProgressListener(this);
}
@ -1104,6 +1149,69 @@ nsHTMLFormElement::GetLength(PRInt32* aLength)
return NS_OK;
}
// nsIWebProgressListener
NS_IMETHODIMP
nsHTMLFormElement::OnStateChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
PRInt32 aStateFlags,
PRUint32 aStatus)
{
// If STATE_STOP is never fired for any reason (redirect? Failed state
// change?) the form element will leak. It will be kept around by the
// nsIWebProgressListener (assuming it keeps a strong pointer). We will
// consequently leak the request.
if (aRequest == mSubmittingRequest &&
aStateFlags & nsIWebProgressListener::STATE_STOP) {
mIsSubmitting = PR_FALSE;
mSubmittingRequest = nsnull;
aWebProgress->RemoveProgressListener(this);
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFormElement::OnProgressChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
PRInt32 aCurSelfProgress,
PRInt32 aMaxSelfProgress,
PRInt32 aCurTotalProgress,
PRInt32 aMaxTotalProgress)
{
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFormElement::OnLocationChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
nsIURI* location)
{
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFormElement::OnStatusChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
nsresult aStatus,
const PRUnichar* aMessage)
{
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFormElement::OnSecurityChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
PRInt32 state)
{
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFormElement::IndexOfControl(nsIFormControl* aControl, PRInt32* aIndex)
{

View File

@ -648,7 +648,9 @@ nsDocShell::LoadURI(nsIURI * aURI,
nsnull, // No headers stream
loadType,
nsnull, // No SHEntry
firstParty);
firstParty,
nsnull, // No nsIDocShell
nsnull); // No nsIRequest
}
return rv;
@ -2417,8 +2419,10 @@ nsDocShell::Reload(PRUint32 aReloadFlags)
nsnull, // No post data
nsnull, // No headers data
type, // Load type
nsnull, // No SHEntry
PR_TRUE);
nsnull, // No SHEntry
PR_TRUE,
nsnull, // No nsIDocShell
nsnull); // No nsIRequest
return rv;
}
@ -4285,9 +4289,19 @@ nsDocShell::InternalLoad(nsIURI * aURI,
nsIInputStream * aHeadersData,
PRUint32 aLoadType,
nsISHEntry * aSHEntry,
PRBool firstParty)
PRBool firstParty,
nsIDocShell** aDocShell,
nsIRequest** aRequest)
{
nsresult rv;
nsresult rv = NS_OK;
// Initialize aDocShell/aRequest
if (aDocShell) {
*aDocShell = nsnull;
}
if (aRequest) {
*aRequest = nsnull;
}
nsCOMPtr<nsISupports> owner(aOwner);
//
@ -4334,8 +4348,9 @@ nsDocShell::InternalLoad(nsIURI * aURI,
extProtService->ExternalProtocolHandlerExists(urlScheme.get(),
&haveHandler);
if (haveHandler)
if (haveHandler) {
return extProtService->LoadUrl(aURI);
}
}
}
}
@ -4397,7 +4412,9 @@ nsDocShell::InternalLoad(nsIURI * aURI,
aHeadersData,
aLoadType,
aSHEntry,
firstParty);
firstParty,
aDocShell,
aRequest);
if (rv == NS_ERROR_NO_CONTENT) {
if (bIsNewWindow) {
//
@ -4512,7 +4529,8 @@ nsDocShell::InternalLoad(nsIURI * aURI,
// been called.
mLSHE = aSHEntry;
rv = DoURILoad(aURI, aReferrer, owner, aPostData, aHeadersData, firstParty);
rv = DoURILoad(aURI, aReferrer, owner, aPostData, aHeadersData, firstParty,
aDocShell, aRequest);
return rv;
}
@ -4583,12 +4601,15 @@ nsDocShell::GetCurrentDocumentOwner(nsISupports ** aOwner)
return rv;
}
nsresult nsDocShell::DoURILoad(nsIURI * aURI,
nsIURI * aReferrerURI,
nsISupports * aOwner,
nsIInputStream * aPostData,
nsIInputStream * aHeadersData,
PRBool firstParty)
nsresult
nsDocShell::DoURILoad(nsIURI * aURI,
nsIURI * aReferrerURI,
nsISupports * aOwner,
nsIInputStream * aPostData,
nsIInputStream * aHeadersData,
PRBool firstParty,
nsIDocShell ** aDocShell,
nsIRequest ** aRequest)
{
nsresult rv;
nsCOMPtr<nsIURILoader> uriLoader;
@ -4716,6 +4737,20 @@ nsresult nsDocShell::DoURILoad(nsIURI * aURI,
}
rv = DoChannelLoad(channel, uriLoader);
//
// If the channel load failed, we failed and nsIWebProgress just ain't
// gonna happen.
//
if (NS_SUCCEEDED(rv)) {
if (aDocShell) {
*aDocShell = this;
NS_ADDREF(*aDocShell);
}
if (aRequest) {
CallQueryInterface(channel, aRequest);
}
}
return rv;
}
@ -5497,7 +5532,9 @@ nsDocShell::LoadHistoryEntry(nsISHEntry * aEntry, PRUint32 aLoadType)
nsnull, // No headers stream
aLoadType, // Load type
aEntry, // SHEntry
PR_TRUE);
PR_TRUE,
nsnull, // No nsIDocShell
nsnull); // No nsIRequest
return rv;
}

View File

@ -209,7 +209,9 @@ protected:
nsISupports * aOwner,
nsIInputStream * aPostData,
nsIInputStream * aHeadersData,
PRBool firstParty);
PRBool firstParty,
nsIDocShell ** aDocShell,
nsIRequest ** aRequest);
NS_IMETHOD AddHeadersToChannel(nsIInputStream * aHeadersData,
nsIChannel * aChannel);
virtual nsresult DoChannelLoad(nsIChannel * aChannel,

View File

@ -44,6 +44,7 @@ interface nsIDocumentCharsetInfo;
interface nsIWebNavigation;
interface nsISimpleEnumerator;
interface nsIInputStream;
interface nsIRequest;
interface nsISHEntry;
[scriptable, uuid(69E5DE00-7B8B-11d3-AF61-00A024FFC08C)]
@ -123,7 +124,9 @@ interface nsIDocShell : nsISupports
in nsIInputStream aHeadersStream,
in unsigned long aLoadFlags,
in nsISHEntry aSHEntry,
in boolean firstParty);
in boolean firstParty,
out nsIDocShell aDocShell,
out nsIRequest aRequest);
/**
* Creates a DocShellLoadInfo object that you can manipulate and then pass

View File

@ -455,17 +455,18 @@ struct OnLinkClickEvent : public PLEvent {
~OnLinkClickEvent();
void HandleEvent() {
mHandler->HandleLinkClickEvent(mContent, mVerb, mURLSpec->get(),
mTargetSpec->get(), mPostDataStream,
mHeadersDataStream);
mHandler->OnLinkClickSync(mContent, mVerb, mURLSpec.get(),
mTargetSpec.get(), mPostDataStream,
mHeadersDataStream,
nsnull, nsnull);
}
nsWebShell* mHandler;
nsString* mURLSpec;
nsString* mTargetSpec;
nsIInputStream* mPostDataStream;
nsIInputStream* mHeadersDataStream;
nsIContent* mContent;
nsWebShell* mHandler;
nsString mURLSpec;
nsString mTargetSpec;
nsCOMPtr<nsIInputStream> mPostDataStream;
nsCOMPtr<nsIInputStream> mHeadersDataStream;
nsCOMPtr<nsIContent> mContent;
nsLinkVerb mVerb;
};
@ -489,14 +490,11 @@ OnLinkClickEvent::OnLinkClickEvent(nsWebShell* aHandler,
{
mHandler = aHandler;
NS_ADDREF(aHandler);
mURLSpec = new nsString(aURLSpec);
mTargetSpec = new nsString(aTargetSpec);
mURLSpec.Assign(aURLSpec);
mTargetSpec.Assign(aTargetSpec);
mPostDataStream = aPostDataStream;
NS_IF_ADDREF(mPostDataStream);
mHeadersDataStream = aHeadersDataStream;
NS_IF_ADDREF(mHeadersDataStream);
mContent = aContent;
NS_IF_ADDREF(mContent);
mVerb = aVerb;
PL_InitEvent(this, nsnull,
@ -512,13 +510,7 @@ OnLinkClickEvent::OnLinkClickEvent(nsWebShell* aHandler,
OnLinkClickEvent::~OnLinkClickEvent()
{
NS_IF_RELEASE(mContent);
NS_IF_RELEASE(mHandler);
NS_IF_RELEASE(mPostDataStream);
NS_IF_RELEASE(mHeadersDataStream);
if (nsnull != mURLSpec) delete mURLSpec;
if (nsnull != mTargetSpec) delete mTargetSpec;
}
//----------------------------------------
@ -554,17 +546,27 @@ nsWebShell::GetEventQueue(nsIEventQueue **aQueue)
return *aQueue ? NS_OK : NS_ERROR_FAILURE;
}
void
nsWebShell::HandleLinkClickEvent(nsIContent *aContent,
nsLinkVerb aVerb,
const PRUnichar* aURLSpec,
const PRUnichar* aTargetSpec,
nsIInputStream* aPostDataStream,
nsIInputStream* aHeadersDataStream)
NS_IMETHODIMP
nsWebShell::OnLinkClickSync(nsIContent *aContent,
nsLinkVerb aVerb,
const PRUnichar* aURLSpec,
const PRUnichar* aTargetSpec,
nsIInputStream* aPostDataStream,
nsIInputStream* aHeadersDataStream,
nsIDocShell** aDocShell,
nsIRequest** aRequest)
{
nsresult rv;
nsAutoString target(aTargetSpec);
// Initialize the DocShell / Request
if (aDocShell) {
*aDocShell = nsnull;
}
if (aRequest) {
*aRequest = nsnull;
}
switch(aVerb) {
case eLinkVerb_New:
target.Assign(NS_LITERAL_STRING("_blank"));
@ -599,19 +601,21 @@ nsWebShell::HandleLinkClickEvent(nsIContent *aContent,
listener->OnStartURIOpen(uri, &abort);
}
}
return;
return rv;
}
rv = InternalLoad(uri, // New URI
mCurrentURI, // Referer URI
nsnull, // No onwer
PR_TRUE, // Inherit owner from document
target.get(), // Window target
aPostDataStream, // Post data stream
aHeadersDataStream, // Headers stream
LOAD_LINK, // Load type
nsnull, // No SHEntry
PR_TRUE); // first party site
return InternalLoad(uri, // New URI
mCurrentURI, // Referer URI
nsnull, // No onwer
PR_TRUE, // Inherit owner from document
target.get(), // Window target
aPostDataStream, // Post data stream
aHeadersDataStream, // Headers stream
LOAD_LINK, // Load type
nsnull, // No SHEntry
PR_TRUE, // first party site
aDocShell, // DocShell out-param
aRequest); // Request out-param
}
break;
case eLinkVerb_Embed:
@ -619,6 +623,7 @@ nsWebShell::HandleLinkClickEvent(nsIContent *aContent,
// in NS 4.x
default:
NS_ABORT_IF_FALSE(0,"unexpected link verb");
return NS_ERROR_UNEXPECTED;
}
}
@ -997,7 +1002,9 @@ nsresult nsWebShell::EndPageLoad(nsIWebProgress *aProgress,
nsnull, // No headers stream
LOAD_RELOAD_BYPASS_PROXY_AND_CACHE,// Load type
nsnull, // No SHEntry
PR_TRUE); // first party site
PR_TRUE, // first party site
nsnull, // No nsIDocShell
nsnull); // No nsIRequest
}
}
}

View File

@ -71,6 +71,14 @@ public:
const PRUnichar* aTargetSpec,
nsIInputStream* aPostDataStream = 0,
nsIInputStream* aHeadersDataStream = 0);
NS_IMETHOD OnLinkClickSync(nsIContent* aContent,
nsLinkVerb aVerb,
const PRUnichar* aURLSpec,
const PRUnichar* aTargetSpec,
nsIInputStream* aPostDataStream = 0,
nsIInputStream* aHeadersDataStream = 0,
nsIDocShell** aDocShell = 0,
nsIRequest** aRequest = 0);
NS_IMETHOD OnOverLink(nsIContent* aContent,
const PRUnichar* aURLSpec,
const PRUnichar* aTargetSpec);
@ -81,12 +89,6 @@ public:
// nsWebShell
nsresult GetEventQueue(nsIEventQueue **aQueue);
void HandleLinkClickEvent(nsIContent *aContent,
nsLinkVerb aVerb,
const PRUnichar* aURLSpec,
const PRUnichar* aTargetSpec,
nsIInputStream* aPostDataStream = 0,
nsIInputStream* aHeadersDataStream = 0);
static nsEventStatus PR_CALLBACK HandleEvent(nsGUIEvent *aEvent);

View File

@ -40,6 +40,8 @@
#include "nsISupports.h"
class nsIInputStream;
class nsIDocShell;
class nsIRequest;
class nsIContent;
class nsString;
struct nsGUIEvent;
@ -73,11 +75,16 @@ public:
NS_DEFINE_STATIC_IID_ACCESSOR(NS_ILINKHANDLER_IID)
/**
* Process a click on a link. aContent is the content for the frame
* that generated the trigger. aURLSpec is an absolute url spec that
* defines the destination for the link. aTargetSpec indicates where
* the link is targeted (it may be an empty string). aVerb indicates
* the verb to use when the link is triggered.
* Process a click on a link.
*
* @param aContent the content for the frame that generated the trigger
* @param aVerb the verb to use when the link is triggered
* @param aURLSpec an absolute URL spec that defines the destination for the
* link
* @param aTargetSpec indicates where the link is targeted (may be an empty
* string)
* @param aPostDataStream the POST data to send
* @param aHeadersDataStream ???
*/
NS_IMETHOD OnLinkClick(nsIContent* aContent,
nsLinkVerb aVerb,
@ -87,10 +94,39 @@ public:
nsIInputStream* aHeadersDataStream = 0) = 0;
/**
* Process a mouse-over a link. aContent is the
* linked content. aURLSpec is an absolute url spec that defines the
* destination for the link. aTargetSpec indicates where the link is
* targeted (it may be an empty string).
* Process a click on a link.
*
* Works the same as OnLinkClick() except it happens immediately rather than
* through an event.
*
* @param aContent the content for the frame that generated the trigger
* @param aVerb the verb to use when the link is triggered
* @param aURLSpec an absolute URL spec that defines the destination for the
* link
* @param aTargetSpec indicates where the link is targeted (may be an empty
* string)
* @param aPostDataStream the POST data to send
* @param aHeadersDataStream ???
* @param aDocShell (out-param) the DocShell that the request was opened on
* @param aRequest the request that was opened
*/
NS_IMETHOD OnLinkClickSync(nsIContent* aContent,
nsLinkVerb aVerb,
const PRUnichar* aURLSpec,
const PRUnichar* aTargetSpec,
nsIInputStream* aPostDataStream = 0,
nsIInputStream* aHeadersDataStream = 0,
nsIDocShell** aDocShell = 0,
nsIRequest** aRequest = 0) = 0;
/**
* Process a mouse-over a link.
*
* @param aContent the linked content.
* @param aURLSpec an absolute url spec that defines the destination for the
* link
* @param aTargetSpec indicates where the link is targeted (it may be an empty
* string)
*/
NS_IMETHOD OnOverLink(nsIContent* aContent,
const PRUnichar* aURLSpec,