Author Topic: Access to premium feed from iOS Podcasts app (and other picky apps)  (Read 4098 times)

thebrew

  • Full Member
  • **
  • Posts: 10
Hello good people of Blubrry!

You may have noticed that users of the current Podcasts app for iOS (v2.1.2) can't just tap a feed://server.com/?feed=premium link and have the app ask for the username and password.

It'll work if you force the user credentials like so: feed://user:pass@server.com/?feed=premium

But that work-around will not work in the Podcasts app that comes bundled with iOS 8 (v2.2).

The reason for this issue is, that the Podcasts app starts out asking for the HEAD of the feed URL before moving on.

If the URL needs authentication, the HEAD request should return status code 401 if none is passed, but in the current Blubrry version (v5.0.9) it detects that it's a HEAD request - and just returns 200. Not good. ;)

My suggestion for a fix in powerpress.php:

Addition to the powerpress_exit_on_http_head($return) function, at line 401 (what are the odds?) just before the "// Set the content type for HTTP headers..." line, append:

Code: [Select]
  // Needs authentication?
  $GeneralSettings = get_option('powerpress_general');
  if( isset($GeneralSettings['premium_caps']) && $GeneralSettings['premium_caps'] )
  {
    $feed_slug = get_query_var('feed');
    $FeedSettings = get_option('powerpress_feed_'.$feed_slug);
    if( !empty($FeedSettings['premium']) )
    {
      require_once( POWERPRESS_ABSPATH.'/powerpress-feed-auth.php');
      powerpress_feed_auth( $feed_slug );
    }
  }

Thanks for a great plugin!

angelo

  • CIO, RawVoice
  • Administrator
  • Hero Member
  • *****
  • Posts: 4483
Re: Access to premium feed from iOS Podcasts app (and other picky apps)
« Reply #1 on: September 01, 2014, 01:00:33 pm »
Sounds like a good idea, but Blubrry is not what is returning the 200, this is a WordPress "feature" (I don't call it that). I will look at my notes, but I recall there's no way to stop this as it's a feature built into WordPress, as stupid as it sounds.

angelo

  • CIO, RawVoice
  • Administrator
  • Hero Member
  • *****
  • Posts: 4483
Re: Access to premium feed from iOS Podcasts app (and other picky apps)
« Reply #2 on: September 01, 2014, 01:49:00 pm »
Look at line 24 in template-loader.php of WordPress source. I see there is a filter "exit_on_http_head", so you could add to your theme something like...

Code: [Select]
function my_exit_on_http_head($value)
{
 return false;
}
add_filter('exit_on_http_head', 'my_exit_on_http_head');

This is pseudo code, you will need to debug this.
« Last Edit: September 01, 2014, 01:50:56 pm by angelo »

thebrew

  • Full Member
  • **
  • Posts: 10
Re: Access to premium feed from iOS Podcasts app (and other picky apps)
« Reply #3 on: September 01, 2014, 04:56:18 pm »
I'm sorry, I think you've misunderstood. I'm not authoring a theme. I'm offering a fix for your bug.

The problem is that your script powerpress.php isn't returning 401 if the HEAD request is for a protected feed.

The fix I posted will make it behave correctly.

angelo

  • CIO, RawVoice
  • Administrator
  • Hero Member
  • *****
  • Posts: 4483
Re: Access to premium feed from iOS Podcasts app (and other picky apps)
« Reply #4 on: September 01, 2014, 05:09:40 pm »
Test your fix, you will find that WordPress is handling it at the line I quoted. Head requests never make it to the plugins.

thebrew

  • Full Member
  • **
  • Posts: 10
Re: Access to premium feed from iOS Podcasts app (and other picky apps)
« Reply #5 on: September 01, 2014, 06:01:03 pm »
Do you think I wouldn't have tested before posting? ;)

It's tested and working here. Spent about a day tracking the bug down and verifying the fix.

thebrew

  • Full Member
  • **
  • Posts: 10
Re: Access to premium feed from iOS Podcasts app (and other picky apps)
« Reply #6 on: September 01, 2014, 06:28:07 pm »
Head requests never make it to the plugins.

In powerpress.php you run

Code: [Select]
add_filter('exit_on_http_head', 'powerpress_exit_on_http_head' );

The template-loader.php runs

Code: [Select]
if ( 'HEAD' === $_SERVER['REQUEST_METHOD'] && apply_filters( 'exit_on_http_head', true ) )
exit();

So on a HEAD request, this powerpress.php function is run:

Code: [Select]
function powerpress_exit_on_http_head($return)
{
  if( is_feed() )
  {
    // Set the content type for HTTP headers...
    header('Content-Type: ' . feed_content_type('rss-http') . '; charset=' . get_option('blog_charset'), true);
  }
  return $return;
}

If the URL is for a password protected feed, your current implementation will simply exit and thus return status code 200.

My suggestion is to check if it's password protected and return 401 if no authentication is passed in the request header. All I've done is re-use that check from a little further down in your code. My suggested change:

Code: [Select]
function powerpress_exit_on_http_head($return)
{
  if( is_feed() )
  {
    // Needs authentication?
    $GeneralSettings = get_option('powerpress_general');
    if( isset($GeneralSettings['premium_caps']) && $GeneralSettings['premium_caps'] )
    {
      $feed_slug = get_query_var('feed');
      $FeedSettings = get_option('powerpress_feed_'.$feed_slug);
      if( !empty($FeedSettings['premium']) )
      {
        require_once( POWERPRESS_ABSPATH.'/powerpress-feed-auth.php');
        powerpress_feed_auth( $feed_slug );
      }
    }
    // Set the content type for HTTP headers...
    header('Content-Type: ' . feed_content_type('rss-http') . '; charset=' . get_option('blog_charset'), true);
  }
  return $return;
}

angelo

  • CIO, RawVoice
  • Administrator
  • Hero Member
  • *****
  • Posts: 4483
Re: Access to premium feed from iOS Podcasts app (and other picky apps)
« Reply #7 on: September 02, 2014, 09:16:59 am »
What I can do is make this an option, a define in your wp-config.php for example. What I am trying to explain though is this is not what the WordPress folks intended and I recommend putting the solution in your themes functions.php rather than make everyone who uses PowerPress override default WordPress behavior, as stupid as it may be.

angelo

  • CIO, RawVoice
  • Administrator
  • Hero Member
  • *****
  • Posts: 4483
Re: Access to premium feed from iOS Podcasts app (and other picky apps)
« Reply #8 on: September 02, 2014, 09:26:32 am »
Never mind you are right, I already filter the head requests for feeds, my bad. This is one of those WordPress features I got chewed out for the sake of iTunes and have since only remembered that some wp folks like the head logic and will get mad if I override it. I am ready override it, so oh well. Will get this added to next release.

It may be better though to let the script execute for authentication, it is possible a head request is being used to check for changes and already has the correct username/password supplied.

thebrew

  • Full Member
  • **
  • Posts: 10
Re: Access to premium feed from iOS Podcasts app (and other picky apps)
« Reply #9 on: September 02, 2014, 09:39:30 am »
Will get this added to next release.

It may be better though to let the script execute for authentication, it is possible a head request is being used to check for changes and already has the correct username/password supplied.

Awesome, thank you!

My suggested solution will not fail (401) if the correct authentication is supplied on the HEAD request, so all should be peachy. :)

Thanks again for a great plugin!

angelo

  • CIO, RawVoice
  • Administrator
  • Hero Member
  • *****
  • Posts: 4483
Re: Access to premium feed from iOS Podcasts app (and other picky apps)
« Reply #10 on: September 02, 2014, 10:57:06 am »
The original problem solved by powerpress_exit_on_http_head was to set the correct content type to application/xml (otherwise it will be text/html). That will still need to be handled before the authentication portion. What do you think of this version?

Code: [Select]
function powerpress_exit_on_http_head($return)
{
  if( is_feed() )
  {
    // Set the content type for HTTP headers...
    header('Content-Type: ' . feed_content_type('rss-http') . '; charset=' . get_option('blog_charset'), true);

    // Needs authentication?
    $GeneralSettings = get_option('powerpress_general');
    if( isset($GeneralSettings['premium_caps']) && $GeneralSettings['premium_caps'] )
    {
      $feed_slug = get_query_var('feed');
      $FeedSettings = get_option('powerpress_feed_'.$feed_slug);
      if( !empty($FeedSettings['premium']) )
      {
        return false; // Let the logic further into PowerPress authenticate this HEAD request
      }
    }
  }
  return $return;
}

My biggest complaint with this logic WordPress added is that HEAD requests cannot truly function for caching and/or content validation purposes, which is what HEAD request were intended for.

thebrew

  • Full Member
  • **
  • Posts: 10
Re: Access to premium feed from iOS Podcasts app (and other picky apps)
« Reply #11 on: September 02, 2014, 02:41:22 pm »
Beautiful. That'll do it (and better). :)

Side note: I noticed that a GET request, without supplying auth credentials, will return a 401 with Content-Type "text/html". If feed-readers are thrown off it's not /xml, maybe you need to also add the

Code: [Select]
header('Content-Type: ' . feed_content_type('rss-http') . '; charset=' . get_option('blog_charset'), true);
line to powerpress-feed-auth.php (at line ~39)?

angelo

  • CIO, RawVoice
  • Administrator
  • Hero Member
  • *****
  • Posts: 4483
Re: Access to premium feed from iOS Podcasts app (and other picky apps)
« Reply #12 on: September 02, 2014, 02:56:58 pm »
Is that with your version or my version of the powerpress_exit_on_http_head() function? That is why I put the "header('Content-Type: ' . feed_content_type('rss-http') . '; charset=' . get_option('blog_charset'), true);" at the top of the function.

thebrew

  • Full Member
  • **
  • Posts: 10
Re: Access to premium feed from iOS Podcasts app (and other picky apps)
« Reply #13 on: September 02, 2014, 03:11:04 pm »
It's in the powerpress-feed-auth.php file.

Currently it only does this:

Code: [Select]
  header('HTTP/1.0 401 Unauthorized');
  header('WWW-Authenticate: Basic realm="'. str_replace('"', '', $realm_name).'"');

And then exit;s.

thebrew

  • Full Member
  • **
  • Posts: 10
Re: Access to premium feed from iOS Podcasts app (and other picky apps)
« Reply #14 on: September 02, 2014, 03:37:56 pm »
Is that with your version or my version of the powerpress_exit_on_http_head() function? That is why I put the "header('Content-Type: ' . feed_content_type('rss-http') . '; charset=' . get_option('blog_charset'), true);" at the top of the function.

Sorry, I misread. (And sorry for the delay, I'm only allowed to post once every 20 minutes.)

With your version of powerpress.php, yes.

This happens with a GET request for a premium feed if no authentication is supplied.

In this case the powerpress_exit_on_http_head() is never called because it's not a HEAD request.