Index: trunk/phase3/tests/phpunit/includes/FindIE6ExtensionTest.php |
— | — | @@ -6,97 +6,113 @@ |
7 | 7 | class FindIE6ExtensionTest extends MediaWikiTestCase { |
8 | 8 | function testSimple() { |
9 | 9 | $this->assertEquals( |
| 10 | + 'y', |
10 | 11 | WebRequest::findIE6Extension( 'x.y' ), |
11 | | - 'y', |
12 | 12 | 'Simple extension' |
13 | 13 | ); |
14 | 14 | } |
15 | 15 | |
16 | 16 | function testSimpleNoExt() { |
17 | 17 | $this->assertEquals( |
| 18 | + '', |
18 | 19 | WebRequest::findIE6Extension( 'x' ), |
19 | | - '', |
20 | 20 | 'No extension' |
21 | 21 | ); |
22 | 22 | } |
23 | 23 | |
24 | 24 | function testEmpty() { |
25 | 25 | $this->assertEquals( |
| 26 | + '', |
26 | 27 | WebRequest::findIE6Extension( '' ), |
27 | | - '', |
28 | 28 | 'Empty string' |
29 | 29 | ); |
30 | 30 | } |
31 | 31 | |
32 | 32 | function testQuestionMark() { |
33 | 33 | $this->assertEquals( |
| 34 | + '', |
34 | 35 | WebRequest::findIE6Extension( '?' ), |
35 | | - '', |
36 | 36 | 'Question mark only' |
37 | 37 | ); |
38 | 38 | } |
39 | 39 | |
40 | 40 | function testExtQuestionMark() { |
41 | 41 | $this->assertEquals( |
| 42 | + 'x', |
42 | 43 | WebRequest::findIE6Extension( '.x?' ), |
43 | | - 'x', |
44 | 44 | 'Extension then question mark' |
45 | 45 | ); |
46 | 46 | } |
47 | 47 | |
48 | 48 | function testQuestionMarkExt() { |
49 | 49 | $this->assertEquals( |
| 50 | + 'x', |
50 | 51 | WebRequest::findIE6Extension( '?.x' ), |
51 | | - 'x', |
52 | 52 | 'Question mark then extension' |
53 | 53 | ); |
54 | 54 | } |
55 | 55 | |
56 | 56 | function testInvalidChar() { |
57 | 57 | $this->assertEquals( |
| 58 | + '', |
58 | 59 | WebRequest::findIE6Extension( '.x*' ), |
59 | | - '', |
60 | 60 | 'Extension with invalid character' |
61 | 61 | ); |
62 | 62 | } |
63 | 63 | |
| 64 | + function testInvalidCharThenExtension() { |
| 65 | + $this->assertEquals( |
| 66 | + 'x', |
| 67 | + WebRequest::findIE6Extension( '*.x' ), |
| 68 | + 'Invalid character followed by an extension' |
| 69 | + ); |
| 70 | + } |
| 71 | + |
64 | 72 | function testMultipleQuestionMarks() { |
65 | 73 | $this->assertEquals( |
| 74 | + 'c', |
66 | 75 | WebRequest::findIE6Extension( 'a?b?.c?.d?e?f' ), |
67 | | - 'c', |
68 | 76 | 'Multiple question marks' |
69 | 77 | ); |
70 | 78 | } |
71 | 79 | |
72 | 80 | function testExeException() { |
73 | 81 | $this->assertEquals( |
| 82 | + 'd', |
74 | 83 | WebRequest::findIE6Extension( 'a?b?.exe?.d?.e' ), |
75 | | - 'd', |
76 | 84 | '.exe exception' |
77 | 85 | ); |
78 | 86 | } |
79 | 87 | |
80 | 88 | function testExeException2() { |
81 | 89 | $this->assertEquals( |
| 90 | + 'exe', |
82 | 91 | WebRequest::findIE6Extension( 'a?b?.exe' ), |
83 | | - 'exe', |
84 | 92 | '.exe exception 2' |
85 | 93 | ); |
86 | 94 | } |
87 | 95 | |
88 | 96 | function testHash() { |
89 | 97 | $this->assertEquals( |
| 98 | + '', |
90 | 99 | WebRequest::findIE6Extension( 'a#b.c' ), |
91 | | - '', |
92 | 100 | 'Hash character preceding extension' |
93 | 101 | ); |
94 | 102 | } |
95 | 103 | |
96 | 104 | function testHash2() { |
97 | 105 | $this->assertEquals( |
| 106 | + '', |
98 | 107 | WebRequest::findIE6Extension( 'a?#b.c' ), |
99 | | - '', |
100 | 108 | 'Hash character preceding extension 2' |
101 | 109 | ); |
102 | 110 | } |
| 111 | + |
| 112 | + function testDotAtEnd() { |
| 113 | + $this->assertEquals( |
| 114 | + '', |
| 115 | + WebRequest::findIE6Extension( '.' ), |
| 116 | + 'Dot at end of string' |
| 117 | + ); |
| 118 | + } |
103 | 119 | } |
Index: trunk/phase3/includes/WebRequest.php |
— | — | @@ -814,44 +814,52 @@ |
815 | 815 | * insecure. |
816 | 816 | * |
817 | 817 | * The criteria for finding an extension are as follows: |
818 | | - * * a possible extension is a dot followed by one or more characters not in <>\"/:|?.# |
819 | | - * * if we find a possible extension followed by the end of the string or a #, that's our extension |
820 | | - * * if we find a possible extension followed by a ?, that's our extension |
821 | | - * ** UNLESS it's exe, dll or cgi, in which case we ignore it and continue searching for another possible extension |
822 | | - * * if we find a possible extension followed by a dot or another illegal character, we ignore it and continue searching |
| 818 | + * - a possible extension is a dot followed by one or more characters not |
| 819 | + * in <>\"/:|?.# |
| 820 | + * - if we find a possible extension followed by the end of the string or |
| 821 | + * a #, that's our extension |
| 822 | + * - if we find a possible extension followed by a ?, that's our extension |
| 823 | + * - UNLESS it's exe, dll or cgi, in which case we ignore it and continue |
| 824 | + * searching for another possible extension |
| 825 | + * - if we find a possible extension followed by a dot or another illegal |
| 826 | + * character, we ignore it and continue searching |
823 | 827 | * |
824 | 828 | * @param $url string URL |
825 | 829 | * @return mixed Detected extension (string), or false if none found |
826 | 830 | */ |
827 | 831 | public static function findIE6Extension( $url ) { |
828 | | - $remaining = $url; |
829 | | - while ( $remaining !== '' ) { |
| 832 | + $pos = 0; |
| 833 | + $hashPos = strpos( $url, '#' ); |
| 834 | + if ( $hashPos !== false ) { |
| 835 | + $urlLength = $hashPos; |
| 836 | + } else { |
| 837 | + $urlLength = strlen( $url ); |
| 838 | + } |
| 839 | + $remainingLength = $urlLength; |
| 840 | + while ( $remainingLength > 0 ) { |
830 | 841 | // Skip ahead to the next dot |
831 | | - $pos = strcspn( $remaining, '.' ); |
832 | | - if ( $pos === strlen( $remaining ) || $remaining[$pos] === '#' ) { |
| 842 | + $pos += strcspn( $url, '.', $pos, $remainingLength ); |
| 843 | + if ( $pos >= $urlLength ) { |
833 | 844 | // End of string, we're done |
834 | 845 | return false; |
835 | 846 | } |
836 | 847 | |
837 | 848 | // We found a dot. Skip past it |
838 | | - $remaining = substr( $remaining, $pos + 1 ); |
| 849 | + $pos++; |
| 850 | + $remainingLength = $urlLength - $pos; |
| 851 | + |
839 | 852 | // Check for illegal characters in our prospective extension, |
840 | | - // or for another dot, or for a hash sign |
841 | | - $pos = strcspn( $remaining, "<>\\\"/:|?*.#" ); |
842 | | - if ( $pos === strlen( $remaining ) ) { |
843 | | - // No illegal character or next dot or hash |
| 853 | + // or for another dot |
| 854 | + $nextPos = $pos + strcspn( $url, "<>\\\"/:|?*.", $pos, $remainingLength ); |
| 855 | + if ( $nextPos >= $urlLength ) { |
| 856 | + // No illegal character or next dot |
844 | 857 | // We have our extension |
845 | | - return $remaining; |
| 858 | + return substr( $url, $pos, $urlLength - $pos ); |
846 | 859 | } |
847 | | - if ( $remaining[$pos] === '#' ) { |
848 | | - // We've found a legal extension followed by a hash |
849 | | - // Trim the hash and everything after it, then return that |
850 | | - return substr( $remaining, 0, $pos ); |
851 | | - } |
852 | | - if ( $remaining[$pos] === '?' ) { |
| 860 | + if ( $url[$nextPos] === '?' ) { |
853 | 861 | // We've found a legal extension followed by a question mark |
854 | 862 | // If the extension is NOT exe, dll or cgi, return it |
855 | | - $extension = substr( $remaining, 0, $pos ); |
| 863 | + $extension = substr( $url, $pos, $nextPos - $pos ); |
856 | 864 | if ( strcasecmp( $extension, 'exe' ) && strcasecmp( $extension, 'dll' ) && |
857 | 865 | strcasecmp( $extension, 'cgi' ) ) |
858 | 866 | { |
— | — | @@ -861,7 +869,8 @@ |
862 | 870 | } |
863 | 871 | // We found an illegal character or another dot |
864 | 872 | // Skip to that character and continue the loop |
865 | | - $remaining = substr( $remaining, $pos ); |
| 873 | + $pos = $nextPos + 1; |
| 874 | + $remainingLength = $urlLength - $pos; |
866 | 875 | } |
867 | 876 | return false; |
868 | 877 | } |