Forum module's link is just flat out broken :)

The others are OK when printed by the theme, but not when output into the HTML header; they are not actual URLs. So for example, when Firefox displays a feed icon in the address bar, clicking on that does not take you to the correct location and results in a 404 error.

This patch should fix it.

Comments

bleen’s picture

Issue tags: +Needs tests

we should probably add tests for this, huh?

rfay’s picture

StatusFileSize
new3.24 KB

So this is broken in most callers of drupal_add_feed() because of confusion over whether it takes a path or a URL. The docs say it takes a URL. So then most calls (not all - node was OK, and views had this right) need to do url() around it.

This patch fixes Forum's bug the same way as #0, but adds the url() in the other places where it's missing.

@bleen18, got ideas how to add tests for correctness on the feed URLs? Do a drupal_http_request() on them and parse the results to make sure it has related content?

This is a pretty serious brokenness, so I think it's correctly marked major.

/me almost deployed a D7 version of randyfay.com with a broken drupal planet taxo feed :-)

David_Rothstein’s picture

Status: Needs review » Needs work

Can't do it that way, because then when drupal_add_feed() passes that parameter into theme('feed_icon'), it has url() called on it a second time... so the feed icon link (when printed by the theme) is broken, even though the one in the Firefox address bar is OK.

I believe my approach is the only way to fix both at the same time - but yes, the fact that this parameter is called 'url' then makes no sense.

Yuk :)

rfay’s picture

@David, there are already several callers who are already passing it through url() before calling, including node module.

If it's *not* going to be a URL that we're passing in, we'll have to do an API change... Or at least one that looks like that because it will certainly change the docs from "URL" to "path". And the problem with that is you might want a feed that is external (like a feedburner feed).

David_Rothstein’s picture

It looks like the way node module gets around this is by specifying 'absolute' => TRUE for the URL. That's the only way it manages to produce something that doesn't break either the icon or the address bar.

So I think that means an external URL (like your feedburner feed example) would work fine too with my approach.

It also seems to mean that the only way to do this without changing the internals of drupal_add_feed() would be to document that all callers of this function must pass in absolute URLs?

Pick your poison :)

rfay’s picture

I would actually prefer to do it by changing the internals (and the defined API). But it seems a little late for that. The documentation clearly says that you're to pass a URL. It does *not* say that you should have to do an absolute URL.

I haven't gone down the path of looking carefully at how the icon is generated.

Sure do hate to be mucking with things. The least "official" mucking is to change drupal_add_feed's documentation to say it requires an absolute URL, and then fix the callers in core.

I guess I should go back and try your #0. I originally took a casual look and thought it only fixed forums. But if it fixes everything maybe it's fine (even though a minor API change).

rfay’s picture

#0 works for me; If we're going that way we'll have to clean up the callers so they don't call url() before calling. It will break views, so I assume it will break other callers. It is an API change.

webchick’s picture

Yeah, we can't do the API change at this point, IMO. This argument has been the way it is since Drupal 5, and this isn't a serious enough problem to warrant the breakage. But let's definitely do for Drupal 8.

Randy's patch reverts to the D6 code, and that's what we should do. Plus an amendment to documentation of the args in drupal_add_feed() here so it's clear what we expect there.

I can't quite fathom how this got broken, though. In Drupal 6 these calls are fine: http://api.drupal.org/api/function/aggregator_page_category/6 Weird.

David_Rothstein’s picture

@webchick, this is actually a new problem in Drupal 7. There was already an API change to this function introduced earlier in the Drupal 7 cycle, but it looks like the function documentation was never changed to reflect that. That's why it looks like this argument has been this way since Drupal 5 :)

I think it's ultimately because of theme_feed_icon(), which is called from within drupal_add_feed(). Compare these:
http://api.drupal.org/api/function/theme_feed_icon/6
http://api.drupal.org/api/function/theme_feed_icon/7

In D7, the passed in "url" is forced through url() again, via l(), but that did not happen in D6.

So I'm guessing what happened is that whenever the above change was made, someone went and updated all (or at least most) of the calls to drupal_add_feed() in Drupal core to pass in a path rather than a URL (that's the original API change), but did not document it, and also did not realize that doing that would break the HTML headers that drupal_add_feed() also outputs... hence we now have this bug.

So the conclusion is that there is no way to fix this bug without some kind of API change. We can either

  1. document the API change that already sort-of-exists in Drupal 7 (but was never documented),
  2. require that everyone passing in a url() to this function also force 'absolute => TRUE' (also an API change, and kind of bizarre), or
  3. let people go back to passing in url('some/path') like they did in Drupal 6 - but then we'd need to change the behavior of theme_feed_icon() instead, also reverting that function to the way it worked in Drupal 6.

As far as I know, there are no other solutions on the table :)

David_Rothstein’s picture

I agree, though, that probably the least intrusive thing we could do here is just revert the behavior of both functions to the way they worked in Drupal 6 - that way, at least, the behavior of the functions would match the way they have been documented all along (although not the way anyone who looked at the code, or at core's use of the code, would have been using them in Drupal 7 so far).

I don't know when the change to theme_feed_icon() was introduced, though, or why. We'd probably want to look that up before reverting it.

rfay’s picture

Ironically, the change to theme_feed_icon() was done in #715142: [beta blocker blocker] Various URLs escaped twice, since check_url() resp. filter_xss_bad_protocol() calls check_plain()

The intent was to fix URLs being double-url'ed, apparently.

@webchick, we may be dealing here with an API change that was already done, but that we have to finish now.

rfay’s picture

Issue tags: +API change

I explained the contradiction here to webchick in IRC, and that we probably have to do with @David's option 1 in #9.

She sez "Documentation is good" and gave her hearty (distracted?) support to the original approach here. So let's fix this up to make clear what the API change is, fix the stuff around it, and see if we can make it fly.

IMO we still need to make sure that drupal_add_feed() can still add an external URL though. Hmm.

tim.plunkett’s picture

I think #877986: RSS link in Syndicate block has path of //rss.xml was an example of this in action.

rfay’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests, -API change
StatusFileSize
new6.92 KB

OK, this patch fixes it in a way that I think resolves all the issues.

1. With the addition of a small test we can tell whether a URL was passed in or not. That resolves the API change problem: Now we can handle both URLs and paths. And this is important, because if we had gone with paths only we would not be able to use an external feed here (like a feedburner feed).

2. This patch adds a test for the various permutations of drupal_add_feed().

Removing the "Needs tests" and "API change" markers, as I don't think it needs either.

Issue summary:
The bugs:

  • the feed icon and the HEAD feed link were relative to the current page if a path was passed to drupal_get_feed(); they were completely broken if a URL was passed. There wasn't a way to reconcile the behavior of theme_feed_icon() and drupal_get_feed() to fix this.
  • There was a minor error in forum.module in doing the drupal_add_feed().

Diagnosis:
There was a (probably unintended) shift in the drupal_add_feed() and theme_feed_icon() functions to favor paths instead of URLs. However, this was not fully implemented, and both the feed icon and the HEAD feed link were broken (they were relative to the current page instead of being absolute).

The fix here is to allow both fully qualified URLs and paths to be passed into drupal_add_feed().

Status: Needs review » Needs work

The last submitted patch, drupal.bad_feeds_917730_14.patch, failed testing.

rfay’s picture

Fails with clean urls turned off :-(

rfay’s picture

Status: Needs work » Needs review
StatusFileSize
new7.1 KB

The problem was that '?' is a meta-character the regular expression used to match, so had to be escaped. The problem was with the test when not using clean urls, not with the code.

Status: Needs review » Needs work

The last submitted patch, drupal.bad_feeds_917730_17.patch, failed testing.

rfay’s picture

Status: Needs work » Needs review

This #fail was caused by #808560: Node comment statistics are only partially exposed in node_load() and are missing last_comment_uid and doesn't have to do with this issue. Retesting.

rfay’s picture

#17 is ready for review - The details, proposed resolution, and issue summary are in #14.

rfay’s picture

StatusFileSize
new7.02 KB

Whoops, noticed a debug() in there.
Details and issue summary in #14.

David_Rothstein’s picture

This patch seems to force all URLs produced by drupal_add_feed() and theme_feed_icon() to always be absolute URLs (and then assert that they must be in the tests). Maybe I'm missing something, but why is that the desired behavior - is there some reason we don't want relative paths in the <link> tag? (And even if there is, I especially don't understand why the icon needs to be an absolute URL.)

In other words, I don't think I understand what was wrong with my original patch in this issue; under what scenario does that simpler change not work?

Other comments:

+    $href = url_is_external($path_or_external_url) ? $path_or_external_url : url($path_or_external_url, array('absolute' => TRUE));

Instead of doing the url_is_external() check, why not just do $href = url(...) all the time? The url() function is smart enough to figure out if a URL is external or not on its own.

The tests themselves look very nice. My only question about them is here:

+      $this->assert((bool)preg_match($this->urlToRSSLinkPattern($feed_info['output_url'], $feed_info['title']), $head_with_path), t('Found correct feed header for %description', array('%description' => $description)), 'System');

Can't we use $this->assertPattern()? (Actually, the purists would probably say we should be using XPaths here rather than regular expressions altogether - so as not to have the tests make any assumptions about the order of the attributes inside the HTML tag - but I think that part is probably fine as is :)

rfay’s picture

@David, thanks for taking the time to look at this.

The (only) problem with the original patch is that it allows *only* drupal paths to be passed in, or they get url() called twice on them. But that doesn't allow both path and URL to work.

In D6, this was supposed to be a URL. In D7, it was mostly converted to just be a path. Your patch made the path approach work completely and correctly, but the slight change in this patch allows both path and URL to work, meaning that the various callers won't be broken and that you can still do a drupal_add_feed() of an external URL (like a feedburner URL).

Why not use both relative and absolute links? Because it's easier to have one goal :-)

The whole purpose (I think) of the patch that introduced the problem we're trying to fix here is that url() was being called twice on paths in some cases. So that's why I was trying to finesse the choice of when to use it.

As far as the test: I actually tried to switch to assertPattern(), but had some problem I don't remember and switched back to just testing the HEAD. I can't remember why or think of any good reason, but I believe the test is correct and tests what it ought to test.

David_Rothstein’s picture

StatusFileSize
new8.05 KB

Why do you think my approach wouldn't have worked with external URLs? I thought it did. Now that we have tests we can find out for sure :)

Regarding the absolute URLs, yeah, it does seem that all other <link> tags in Drupal use them; I doubt it's intentional, but for consistency I agree we can do that too. However, I don't think the link on the the icon itself should be forced absolute, that's just a regular <a> tag generated by l(), and we never force those to be absolute in general.

Let's see if the attached patch will pass the tests. (I also tried switching to assertPattern() - it turns out if you call drupalSetContent() first you can do it.)

David_Rothstein’s picture

Oh... maybe your motivation in forcing the second one to absolute was to avoid this?

  * @param $variables
  *   An associative array containing:
- *   - url: The url of the feed.
+ *   - url: The internal path or external URL of the feed. This should be
+ *     either a raw path (not having passed through url()) or an external URL.
  *   - title: A descriptive title of the feed.
  */
 function theme_feed_icon($variables) {

We would ideally change the name of that parameter to $variables['path_or_external_url'] like the other one, but that would be an API change because it's used as an array key by the callers.

So maybe the idea is we should lie a little bit in the documentation (pretend it must always be an absolute URL even though it technically doesn't have to be), in order to avoid some confusion? :)

David_Rothstein’s picture

Issue tags: +API change

Adding the "API change" tag here out of an abundance of caution, although it's really more of an API documentation fix.

So, how to proceed? For the case of theme_feed_icon(), I do think it's best if we correctly document the parameter the way it actually works, even though the variable name 'url' is not well-matched to that. We can at least fix the variable name in Drupal 8.

So in that case, is #24 the one we should go with?

rfay’s picture

Sorry - hoped to get to this on the plane today and didn't. One of these is going in :-) They'll work. I'm not holding #24 back. Just wanted to give it a spin before RTBC'ing it.

rfay’s picture

Status: Needs review » Reviewed & tested by the community

OK, #24 works fine and let's go with it. I tried it out manually in addition to the tests provided. Tried it with clean URLs and without. Works.

Views still uses a relative url() before calling drupal_add_feed() so it breaks with that, so we'll have to follow up with a views3 patch when this goes in.

Let's go for it.

The issue summary in #14 still holds.

rfay’s picture

Just for the sake of not having to do this over, attaching the views patch that will need to be done. (or at least this is one way of doing it).

rfay’s picture

It's always better when one attaches a longer-than-zero-length file. Intended vews future patch for #29 is here.

Issue summary is still in #14. Committable patch is still in #24.

sun’s picture

StatusFileSize
new5.43 KB

Remove the argument name change. $url is either an internal path or external URL, everywhere in Drupal. The actual fix is to pass $url through url().

webchick’s picture

Status: Reviewed & tested by the community » Needs review

Sounds like this still needs discussion.

rfay’s picture

Status: Needs review » Needs work
StatusFileSize
new3.05 KB

Sorry - I can't agree that taking explicit documentation about a sensitive difference out improves this patch. One *must* pass in to drupal_add_feed *either* a path *or* a fully-qualified external URL (or one that looks external, with a scheme on it). The documentation here and variable naming were to make this explicit.

@David: #31 also removes your forum patch; sun says it was correct the way it was.

Attached is the interdiff between #24 and #31

David_Rothstein’s picture

@David: #31 also removes your forum patch; sun says it was correct the way it was.

That depends. Do you like it when you click on an RSS feed link and don't get an actual RSS feed? :) I double-checked, and the change to forum.module in #24 was correct, so it needs to go back in.

***

I also agree we need to put the documentation changes back. The previous documentation - "A url for the feed" - is just wrong. If you pass in url('somepath') to the function it won't work correctly.

Whether we change the variable name or not I don't care so much. I think @rfay's idea of $path_or_external_url was better, although it's also true (as mentioned above) that 'url' is used many other places that have the same issue, many of which we can't fix at this point because they are keys of the $variables array and it would break the API, etc. So for consistency's sake, I'm not opposed to leaving it at $url. I don't think there's anything wrong with using a more descriptive name either, though.

rfay’s picture

It may be that we are discovering an additional bug in the taxonomy/term feed URL. Sun's opinion was that it should *have* the /0 because that "has worked since Drupal 4". But maybe it doesn't work any more.

I propose:

* Use $url (sigh)
* Keep the appropriate documentation that goes with it explaining what the allowed uses are.
* Determine whether the taxonomy/term issue is a new bug in D7 and we're accidentally working around that bug. (The /0 is supposed to be a depth selector, according to sun)

David_Rothstein’s picture

Pretty sure that depth stuff was removed from core a long time ago: #503456: Remove multiple tid and depth handling for core taxonomy paths

So all we are doing here is making the forum.module feed URL consistent with the one already used in the taxonomy module itself (e.g. http://api.drupal.org/api/drupal/modules--taxonomy--taxonomy.pages.inc/f...). I think it is just an oversight that this URL was not changed before, when the depth handling was ripped out.

rfay’s picture

One option is to just make #24 RTBC again. Sun had his own personal opinions, but nobody else seemed to object at all to what's in #24. @sun, can you live with that, now that this has played out?

rfay’s picture

Status: Needs work » Reviewed & tested by the community

OK, then, I propose #24 as RTBC again. Nobody but sun had an issue with it, and some of that didn't pan out.

sun’s picture

Status: Reviewed & tested by the community » Needs review
StatusFileSize
new7.18 KB

Clarified @param $url description.

rfay’s picture

Status: Needs review » Reviewed & tested by the community
StatusFileSize
new2.95 KB

OK, works for me, thanks, @sun. Marking #39 RTBC. Interdiff from 24 to 39 is attached.

+++ modules/node/node.module	27 Nov 2010 16:48:38 -0000
@@ -2552,8 +2552,8 @@ function node_page_default() {
+    // @see node_menu()

I wasn't quite sure where this comment came from, but fine with me.

Powered by Dreditor

sun’s picture

Added that @see in order to clarify that rss.xml is registered menu path and not an actual file in the filesystem. If it was a real file, then it would have to be

url($GLOBALS['base_url'] . '/rss.xml', array('external' => TRUE))
dries’s picture

I did not immediately understood the @see without reading comment #41. Can we either take out the @see or explain it better in the code? Thanks!

David_Rothstein’s picture

Also, a minor point, but @see should not be used in inline code comments (only in PHPDoc). So it should say "See..." instead.

The rest looks good to me also.

webchick’s picture

Status: Reviewed & tested by the community » Needs work
rfay’s picture

Status: Needs work » Needs review
StatusFileSize
new6.38 KB

OK, here it is with the comment rewritten as

+    // 'rss.xml' is a path, not a file, registered in node_menu().
+    drupal_add_feed('rss.xml', variable_get('site_name', 'Drupal') . ' ' . t('RSS'));
sun’s picture

Status: Needs review » Reviewed & tested by the community
webchick’s picture

Status: Reviewed & tested by the community » Fixed

Committed to HEAD. Thanks!

Status: Fixed » Closed (fixed)
Issue tags: -API change

Automatically closed -- issue fixed for 2 weeks with no activity.