Closed Bug 56296 Opened 24 years ago Closed 24 years ago

[RFE] Pref to disable target=_blank

Categories

(Core :: Layout: Images, Video, and HTML Frames, enhancement, P3)

enhancement

Tracking

()

VERIFIED FIXED
mozilla0.9

People

(Reporter: gmiller, Assigned: akkzilla)

References

Details

Attachments

(6 files)

It'd be very nice to have an option to prevent web sites from opening windows on
my computer without my permission. target=_blank is the most common offender.
I like that suggestion.  :)
Severity: normal → enhancement
Status: UNCONFIRMED → ASSIGNED
Ever confirmed: true
Target Milestone: --- → Future
That would be great (and is also discussed in bug 29346).
Clarification: I said "disable" but I really should have said "treat it as
target=_top". Otherwise, framed sites would be even more annoying :)
Here's a patch to put it in docshell, on a preference
"browser.disallowPopupWindows".  It doesn't apply to chrome or resource urls, so
dialogs and new windows can still come up; it doesn't override middleclick or
the context menu to bring up a new window explicitly.  I made it change _blank
and _new to _top since I agree with gmiller's comment.  Reviews and opinions
solicited.
s/user_pref/pref/

Otherwise, looks... simple! :-)
Adding buster: Steve, would you be the right person to super-review this?
I'm not the worst choice, I guess.
1) please send a note out to reviewers@mozilla.org to solicit more feedback.
2) in this code:
+      char* scheme = 0;
+      aURI->GetScheme(&scheme);
+      if (nsCRT::strcmp(scheme, "chrome") && +          nsCRT::strcmp(scheme,
"resource"))
+      {
+          static char* top = "_top";
+          aWindowTarget = top;
+      }
+      nsMemory::Free(scheme);

A) you must check "scheme" for null before passing it to strcmp() or Free()
B) I don't know if nsMemory::Free() is the right de-allocator or not, so this is
just a nag to double-check.
Thanks for looking at it, and for the suggestions.
A) nsCRT::strcmp does check its arguments for null, which I was relying on.  I
have no objection to adding an extra null test, though, in case the
implementation of nsCRT ever changes.
B) GetScheme uses nsCRT::strdup.  Turns out that there's an nsCRT::free with a
CRTFREEIF macro.  I'll change it to use CRTFREEIF, so regardless of the
implementation it'll be right (unless the URI class changes :-).
it's too bad we need to allocate a string here at all.  I wish you could just
get a const ref to the string you need.  Maybe suggest that to whoever owns the
interface?
If you need another reviewer, you can mark this r=pollmann@netscape.  I've
looked over the changes and it all looks good to me!

Akkana, if you would like to take this bug so when it is fixed it goes on your
list, please be my guest.  :)  (FWIW, I've applied the patch and will report
back if I notice anything out of the ordinary - great work!)
Thanks!  Yes, I'll take the bug since it'll make it easier to query (I keep
losing the bug number).
Assignee: pollmann → akkana
Status: ASSIGNED → NEW
Status: NEW → ASSIGNED
Please excuse my interjection of pref name quibbles.

- you aren't disabling "popups", at least not all of them and especially not 
the most hated ones that happen by themselves (i.e. window.open()). You're 
disabling the targeting of a new window in a link.

- prevailing pref style is to use underscores to separate word parts, not 
StudlyCaps

- forms with "enable" are preferred to "disable" 34 to 5; there are a further 9 
"allow" prefs and no "disallow".

maybe something like:
  browser.target_new.enabled
  browser.target_new_allowed

Are there going to be more prefs like this? If so maybe we should invent 
another level to group these under (and if you do that I'd be less averse to 
starting the specific node with the generic enable/disable/allow )
  browser.spamgard.allow_target_new
Interjection excused, and you're probably right about the word "popup".  I have
no objection to changing the pref name.  I'd lean toward
browser.target_new_allowed over the other one because browser.target_new.
implies that there might be other prefs relating to target_new, and I can't
imagine what they would be.  Anyone have any objection to that pref name?

There are already other spam-guarding prefs, but they're scattered to the wind
because they're potentially used for other things as well (like the JS
capability prefs, and the animated image pref, and the various cookie prefs).
Would this work under capability.policy.annoyances, like the pref akkana 
mentioned in bug 29346?

By the way, shouldn't the pref redirect all cases where a link opens in a new 
window to the top of the current window, and not just _new and _blank?  It's 
trivial to set each link on a page to a different target.
I agree, I'd like to see what someone suggested in bug 29346, and block any
target that doesn't have a window currently open.  

That's harder, though, so I was hoping to get this weaker fix in first.

Note, the pref name browser.target_new_allowed still fits since the stronger
behavior would still look for any new target (as opposed to targets matching the
string "_new").  Though browser.new_target_allowed might be a little clearer.

The capability.* prefs are an elaborate and general JS mechanism and I don't
think this pref should get mixed up with them even if it has behavior vaguely
similar to one of the capability prefs.
Target Milestone: Future → mozilla0.9
+  if (mDisallowPopupWindows &&
+      (!nsCRT::strcmp(aWindowTarget, "_blank") ||
+       !nsCRT::strcmp(aWindowTarget, "_new")))
+  {
+      char* scheme = 0;
+      aURI->GetScheme(&scheme);

       nsXPIDLCString scheme;
       rv = aURI->GetScheme(getter_Copies(scheme));

and maybe check rv?

+      if (scheme &&
+          nsCRT::strcmp(scheme, "chrome") &&
+          nsCRT::strcmp(scheme, "resource"))
+      {
+          static char* top = "_top";
+          aWindowTarget = top;

Why burn four bytes on a static char *?  If you want a string constant, use
const char top[], not a mutable pointer.  But if there is only one use of
"_top", there is no gain in making a string constant.  Just use "_top".

+      }
+      CRTFREEIF(scheme);

It seems best to me to use nsXPIDLCString, but if not, then move the nsCRT::free
inside the then statement governed by just if (scheme) {...}.

It is too bad that we can't test URI scheme without making a copy.  Two years
ago in porkjockeys, I recall we talked about a hasScheme method into which one
could pass a string owned by the caller.  Cc'ing Necko buddies.

Is there a different way that we could distinguish chrome: and resource: URIs
here?  Cc'ing hyatt.

/be

+  }
+
hasScheme? what would it look like?  

something like, in C++:

nsResult nsIURI::IsScheme(const char* urlScheme, PRBool **retval)?
IDL first:

    boolean hasScheme(in string scheme);

C++ generated by xpidl (modulo cosmetics):

    NS_IMETHOD HasScheme(const char *aScheme, PRBool *_retval);

I suggested 'has' rather than 'is', because 'is' seems too close to OOP is-a,
and implies an equivalence relation -- but maybe I'm splitting hairs.

/be
if i recall, gagan was preparing a patch for this... there are lots of places
where we are forced to do the extra string copy.  i don't know if there is
already a bug open for this change... gagan?
I already have these changes sitting with me for the longest time... I had of 
course used isScheme and I agree that hasScheme makes more sense. I will clean 
that up and check in the changes soon. I had another bug which talked only about 
optimizing the scheme compares but I can't find it now. 
The CRTFREEIF(scheme) call was where it was because otherwise there would have
been a memory leak in the chrome/resource case.  But the nsXPIDLCString model
sounds better, so I've changed it to that, removed the CRTFREEIF, and eliminated
the static char*.

When gagan's new API goes in, we should change this code to use it and eliminate
the copy, but I hope we can check this one in in the meantime.  Do we have a bug
number for the scheme checking API?  There are a few other calls which should
also be changed when that becomes available.
Sorry to pick nits, I'll stop after this round:

+  if (mDisallowPopupWindows &&
+      (!nsCRT::strcmp(aWindowTarget, "_blank") ||
+       !nsCRT::strcmp(aWindowTarget, "_new")))
+  {
+      nsXPIDLCString scheme;

Switching from two-space to four-space indentation(c-basic-offset)?  Modeline
violation alert!

+      nsresult rv = aURI->GetScheme(getter_Copies(scheme));
+      if (NS_SUCCEEDED(rv) && scheme &&

I believe scheme must be non-null (or convert to a non-null char pointer, I
mean) if NS_SUCCEEDED(rv).  Robustification can be appropriate when dealing with
buggy implementations, but it leads to overcomplicated, obfuscated code.  I say
one test here should suffice -- Necko guys school me if I'm wrong.

+          nsCRT::strcmp(scheme, "chrome") &&
+          nsCRT::strcmp(scheme, "resource"))
+      {
+          aWindowTarget = "_top";
+      }
+  }
+

(BTW, my argument against CRTFREEIF last time was that you could split the if
condition, making 'if (scheme) { if (...) {...}; nsCRT::free(scheme); }' to
minimize the logic.  But nsXPIDLCString rules.)

/be
I agree. We don't want to hold this bug hostage for my checkins to go in. Since 
it is being tracked in a separate bug, I'd say go ahead with this one. Whenever 
I find the bug number I will add it here. 
Four-space indentation: I agree with you in principle, but it's how the rest of
that method (and most of the methods around it) are formatted, and I always try
to adapt to the existing formatting of files I don't own.  Won't it hurt
readability to format this clause inconsistently with the rest of the routine? 
Should I reformat the whole method?  (To 4-space tabs, to be consistent with the
emacs mode line?)  I'll do whatever you think best; I'm format agnostic as long
as you don't tell me to use tabs. :-)

Not checking scheme: it makes me nervous to assume things like that.  The last
time I removed a null check based on a review comment that it could never
happen, it haunted me for many months and at least three crash bugs.  I'll take
it out if you really want me to, but only if I can add a comment saying
something like "Necko group [or Brendan?] says this can never be null" so people
know where to assign the bugs if the impossible happens.
"supposedly redundant" checks is what assert/PR_ASSERT/NS_ASSERTION/etc are 
for, right? :-)
No tabs, period.

I don't see other functions using two spaces for the first tabstop, then
indenting by four space units.  Rather, I see lots of travis three-space
insanity, but we're all trying to get rid of that.  Who owns nsDocShell.cpp now?
mscott?

I think the modeline should establish a norm that patches then implement,
piecemeal or all at once.  Don't keep doing random indentation just because
someone who no longer works on Mozilla did.

What dveditz said.  If GetScheme returns null with NS_OK, it's a bug.  If
GetScheme returns a garbage pointer, there's no defense.  Practically speaking,
we have time to shake out bad impls with assertions.

/be
Okay.  In fact, the null check turns out not to matter because nsCRT doesn't do
anything bad if its argument is null.  I retract my opposition and will remove
the null check.  I didn't put an assert in because I'd have to rewrite the logic
of the if clause to do that and the failure mode turns out not to be a problem.
 And I'll indent the whole new clause consistently with four spaces (in line
with the emacs mode line and most of the indentation in the file).
For those interested, I created bug 66577 since I couldn't find the orig one.
This new bug deals with the scheme comparison changes.
In those patches I never changed the pref name.  How about
"browser.target_new_blocked" (instead of _allowed, so as not to change the logic
and to make the default false)?  Then the only changes needed to the patch are
the two lines, in all.js and nsDocShell::Create(), which reference the pref name.
The proposed prefname browser.target_new_blocked sounds fine
I couldn't resist (and it turned out to be easy): I added the extra code to
disable all target= if it refers to a window that doesn't exist.  It's only a
small addition (though the logic has been changed slightly to accomodate the new
clause), and I couldn't stand all the warnings any more (there were some new
ones today), so I also made some warning fixes for all the warnings that were
fixable without changing logic (I'll file a bug on the remaining warnings).
BTW, it seems like a bummer that FindItemWithName requires a unicode string when
it's doing most of it's comparing against ascii strings using
EqualsWithConversion, so all of its callers have to convert to unicode just so
that the strings can be converted back at compare time.  It's awfully tempting
to change it to use ascii.  Who owns docshell and might be able to rule on this?
 Should I file a separate bug?
mscott and rpotts know docshell.

In the classic codebase, window (target) names were constrained to be ASCII,
IIRC -- maybe even alphanumeric, with no underscores anywhere.  Anyone remember?

/be
Filed bug 66746 on the FindItemWithName issue.  It's a bug either way.
Now that you mention "_top" twice, may as well label a static const char array
holding those bytes.  Do that, and r/sr=brendan@mozilla.org, whichever helps.

/be
r=dveditz for the 1/26 patch. Changing FindItemByName() doesn't belong in this 
patch, it's a separate issue.
Fix is in!  And I updated the customizing document with the new pref.
Status: ASSIGNED → RESOLVED
Closed: 24 years ago
Resolution: --- → FIXED
I realize that this is fixed, but I was wondering if we might do some
unification of like items here and have the target-opens-new-window behaviour
keyed off the same security policy item as the window.open DOM-manipulation control?

Maybe people want it to be different, but I've always thought that it should be
"content can't open new windows", rather than "just disable window.open for
DOM-manipulating things".
I want those to be different prefs (because I'd have window.open disabled and 
target="_blank" enabled), but I would like them to sit next to each other in 
the prefs wnidow.
Marking verified per last comments.
Status: RESOLVED → VERIFIED
See also bug 70990, "need 'open in the same window' option in context menu."
*** Bug 39401 has been marked as a duplicate of this bug. ***
It looks like this preference is being renamed to
browser.block.target_new_window, from Bugzilla Bug 78037
  [RFE] Ability to prevent link from opening in new window.
*** Bug 240581 has been marked as a duplicate of this bug. ***
Product: Core → Core Graveyard
Component: Layout: HTML Frames → Layout: Images
Product: Core Graveyard → Core
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: