1

I'm a chinese internet user. Google/Yahoo search engines are very unstable in my country.
When I click a yahoo search result link, I often get this error page:

ERROR
The requested URL could not be retrieved    
While trying to retrieve the URL: http://search.yahoo.com/r/_ylt=A0oGdUY7FbNQFQsA5rZXNyoA;_ylu=X3oDMTE0ODJ2YTduBHNlYwNzcgRwb3MDMQRjb2xvA3NrMQR2dGlkA1ZJUDA1MV83Ng--/SIG=11ac0sa5q/EXP=1353942459/**http%3a//www.google.com/

The following error was encountered:    
    Access Denied.    
    Access control configuration prevents your request from being allowed at this time. Please contact your service provider if you feel this is incorrect. 

Your cache administrator is noc_admin@163.com.
by DXT-GZ-APP02 

I notice that yahoo will change the value of href to dirtyhref automatically when I click a link.
I try to $('a[id|=link]').unbind('click mousedown'), but it doesn't work.
How to stop yahoo doing it?


Currently, I use this firefox greasemonkey code:

// ==UserScript==
// @name        Clean URL
// @namespace   http://hjkl.me
// @include     https://www.google.com/search*
// @include     http://search.yahoo.com/search*
// @require     http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
// @version     1
// ==/UserScript==

// GOOGLE
$('h3.r>a').removeAttr('onmousedown');

// YAHOO
$('a[id|=link]').on('click', function(){
    var url = $(this).attr('dirtyhref').split('**')[1];
    url = decodeURIComponent(url);
    $(this).attr('href', url);  //<-- yahoo will change it back!
    window.open(url, '_blank');
    return false;
});

The problem is: I cannot use the middle-mouse-click function. (Open tabpage silently)

kev
  • 155,172
  • 47
  • 273
  • 272

3 Answers3

2

Usually, people just copy the "good" href value to the bad/tracking dirtyhref attribute and then let Yahoo do it's thing.

Nowadays, just sanitize both values.

Here's an AJAX-handling script that seems to work for me:

// ==UserScript==
// @name        Clean URL
// @namespace   http://hjkl.me
// @include     http://search.yahoo.com/search*
// @require     http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
// @require     https://gist.github.com/raw/2625891/waitForKeyElements.js
// @version     1
// @grant       GM_addStyle
// ==/UserScript==
/*- The @grant directive is needed to work around a design change
    introduced in GM 1.0.   It restores the sandbox.
*/

// GOOGLE
$('h3.r>a').removeAttr('onmousedown');

// YAHOO
waitForKeyElements ("a[id|=link]", fixDirtyLinks);

function fixDirtyLinks (jNode) {
    var url = jNode.attr('dirtyhref').split('**');
    if (url.length > 1) {
        var goodURL = decodeURIComponent (url[1]);
        jNode.attr ('href', goodURL);
        jNode.attr ('dirtyhref', goodURL);
    }
}
Brock Adams
  • 90,639
  • 22
  • 233
  • 295
1

IE9+, Opera and Firefox define the DOMAttrModified event. Sadly, current versions of Webkit do not define this event.

This will override the href attribute of a[id|=link] to the value of dirtyhref whenever any of its attributes change. Note that assigning an attribute its current value does not count as a change:

$('a[id|=link]').on('DOMAttrModified', function(){
    $(this).attr("href", $(this).attr("dirtyhref"));
});

Test: http://jsfiddle.net/ZzJae/

You also need to override the links on page load.

If new links may appear continuously (say, AutoPager is present), you may also need to bind DOMNodeInserted and use event delegation: $(document).on("DOM...", "a[id|=link]", handler)

IE9+, Chrome+Safari and Firefox define DOMSubtreeModified, but Opera doesn't. If you want to add Webkit support, you will need to listen to this event as well.

A sketch of the final solution (firefox only):

(function(){
  function overrideOne(){
    var dirty = $(this).attr("dirtyhref");
    var clean = dirty.split("**")[1];
    $(this).attr("href", clean);
  }
  function overrideAll(){
    $("a[id|=link]").each(overrideOne)
  }

  $(document).on("ready DOMNodeInserted", overrideAll);
  $(document).on("DOMAttrChanged", "a[id|=link]", overrideOne);
  $(document).on("click", "a[id|=link]",function(){
     ...
  }
}
John Dvorak
  • 26,799
  • 13
  • 69
  • 83
  • [Mutation events are deprecated](http://www.w3.org/TR/DOM-Level-3-Events/#events-mutationevents). This approach will be buggy, and tend to suck up CPU cycles and memory. (And it will not work with some future release of FF.) – Brock Adams Nov 26 '12 at 08:49
  • @BrockAdams Thanks for the link. Note that it _only_ says the `MutationEvent` interface is deprecated - the events themselves seem to stay, at least until DOM4 is introduced. I don't use the interface (perhaps I should?), I only listen to the events. – John Dvorak Nov 26 '12 at 08:54
  • 2
    The events are part of the MutationEvent interface; they are obsoleted along with it. [Mutation Observers](http://stackoverflow.com/a/11106031/331508) are the replacement. – Brock Adams Nov 26 '12 at 09:02
1

Basically, what you need to do is remove the dirtyhref attribute. In order to prevent href from becoming dirty, your dirtyhref removal function has to run before Yahoo!'s function. To do this, use event capturing with the mouse events.

Here is my user JS that I use in Opera:

Disable Yahoo! Search rewrite:

https://gist.github.com/XP1/5008515/

// ==UserScript==
// @name Disable Yahoo! Search rewrite
// @version 1.00
// @description Disables the rewrite of links in Yahoo! Search results.
// @namespace https://gist.github.com/XP1/5008515/
// @copyright 2013
// @author XP1
// @homepage https://github.com/XP1/
// @license Apache License, Version 2.0; http://www.apache.org/licenses/LICENSE-2.0
// @include http*://search.yahoo.*/search?*
// @include http*://*.search.yahoo.*/search?*
// ==/UserScript==

/*
 * Copyright 2013 XP1
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*jslint browser: true, vars: true, maxerr: 50, indent: 4 */
(function (window, MouseEvent, HTMLElement) {
    "use strict";

    function disableRewrite(event) {
        if (!(event instanceof MouseEvent)) {
            return;
        }

        var target = event.target;

        var current = null;
        for (current = target; current instanceof HTMLElement; current = current.parentNode) {
            if (current.hasAttribute("dirtyhref")) {
                current.removeAttribute("dirtyhref");
                return;
            }
        }
    }

    window.addEventListener("mousedown", disableRewrite, true);
    window.addEventListener("click", disableRewrite, true);
}(this, this.MouseEvent, this.HTMLElement));
XP1
  • 6,910
  • 8
  • 54
  • 61