Index: trunk/phase3/includes/CategoryPage.php |
— | — | @@ -36,6 +36,19 @@ |
37 | 37 | $this->closeShowCategory(); |
38 | 38 | } |
39 | 39 | } |
| 40 | + |
| 41 | + /** |
| 42 | + * Don't return a 404 for categories in use. |
| 43 | + */ |
| 44 | + function hasViewableContent() { |
| 45 | + if( parent::hasViewableContent() ) { |
| 46 | + return true; |
| 47 | + } else { |
| 48 | + $cat = Category::newFromTitle( $this->mTitle ); |
| 49 | + return $cat->getId() != 0; |
| 50 | + } |
| 51 | + |
| 52 | + } |
40 | 53 | |
41 | 54 | function openShowCategory() { |
42 | 55 | # For overloading |
Index: trunk/phase3/includes/Article.php |
— | — | @@ -508,6 +508,18 @@ |
509 | 509 | public function exists() { |
510 | 510 | return $this->getId() > 0; |
511 | 511 | } |
| 512 | + |
| 513 | + /** |
| 514 | + * Check if this page is something we're going to be showing |
| 515 | + * some sort of sensible content for. If we return false, page |
| 516 | + * views (plain action=view) will return an HTTP 404 response, |
| 517 | + * so spiders and robots can know they're following a bad link. |
| 518 | + * |
| 519 | + * @return bool |
| 520 | + */ |
| 521 | + public function hasViewableContent() { |
| 522 | + return $this->exists() || $this->mTitle->isAlwaysKnown(); |
| 523 | + } |
512 | 524 | |
513 | 525 | /** |
514 | 526 | * @return int The view count for the page |
— | — | @@ -714,6 +726,7 @@ |
715 | 727 | $rdfrom = $wgRequest->getVal( 'rdfrom' ); |
716 | 728 | $diffOnly = $wgRequest->getBool( 'diffonly', $wgUser->getOption( 'diffonly' ) ); |
717 | 729 | $purge = $wgRequest->getVal( 'action' ) == 'purge'; |
| 730 | + $return404 = false; |
718 | 731 | |
719 | 732 | $wgOut->setArticleFlag( true ); |
720 | 733 | |
— | — | @@ -813,12 +826,22 @@ |
814 | 827 | $text = wfMsg( 'noarticletext' ); |
815 | 828 | } |
816 | 829 | } |
| 830 | + |
817 | 831 | # Non-existent pages |
818 | 832 | if( $this->getID() === 0 ) { |
819 | 833 | $wgOut->setRobotPolicy( 'noindex,nofollow' ); |
820 | 834 | $text = "<div class='noarticletext'>\n$text\n</div>"; |
| 835 | + if( !$this->hasViewableContent() ) { |
| 836 | + // If there's no backing content, send a 404 Not Found |
| 837 | + // for better machine handling of broken links. |
| 838 | + $return404 = true; |
| 839 | + } |
821 | 840 | } |
822 | 841 | |
| 842 | + if( $return404 ) { |
| 843 | + $wgRequest->response()->header( "HTTP/1.x 404 Not Found" ); |
| 844 | + } |
| 845 | + |
823 | 846 | # Another whitelist check in case oldid is altering the title |
824 | 847 | if( !$this->mTitle->userCanRead() ) { |
825 | 848 | $wgOut->loginToUse(); |
Index: trunk/phase3/RELEASE-NOTES |
— | — | @@ -241,8 +241,9 @@ |
242 | 242 | * (bug 16760) Add CSS-class to action links of Special:Log |
243 | 243 | * (bug 505) Time zones can now be specified by location in user preferences, |
244 | 244 | avoiding the need to manually update for DST. Patch by Brad Jorsch. |
| 245 | +* (bug 2585) HTTP 404 return code is now given for a page view if the page |
| 246 | + does not exist, allowing spiders and link checkers to detect broken links. |
245 | 247 | |
246 | | - |
247 | 248 | === Bug fixes in 1.14 === |
248 | 249 | |
249 | 250 | * (bug 14907) DatabasePostgres::fieldType now defined. |