public void Ctor_WithNoParameters_DefaultsToBasicLatin()
        {
            // Arrange
            UrlEncoder encoder = new UrlEncoder();

            // Act & assert
            Assert.Equal("a", encoder.UrlEncode("a"));
            Assert.Equal("%C3%A9", encoder.UrlEncode("\u00E9" /* LATIN SMALL LETTER E WITH ACUTE */));
            Assert.Equal("%E2%98%81", encoder.UrlEncode("\u2601" /* CLOUD */));
        }
        public void Ctor_WithUnicodeRanges()
        {
            // Arrange
            UrlEncoder encoder = new UrlEncoder(UnicodeRanges.Latin1Supplement, UnicodeRanges.MiscellaneousSymbols);

            // Act & assert
            Assert.Equal("%61", encoder.UrlEncode("a"));
            Assert.Equal("\u00E9", encoder.UrlEncode("\u00E9" /* LATIN SMALL LETTER E WITH ACUTE */));
            Assert.Equal("\u2601", encoder.UrlEncode("\u2601" /* CLOUD */));
        }
        public void Ctor_WithNoParameters_DefaultsToBasicLatin()
        {
            // Arrange
            UrlEncoder encoder = new UrlEncoder();

            // Act & assert
            Assert.Equal("a", encoder.UrlEncode("a"));
            Assert.Equal("%C3%A9", encoder.UrlEncode("\u00E9" /* LATIN SMALL LETTER E WITH ACUTE */));
            Assert.Equal("%E2%98%81", encoder.UrlEncode("\u2601" /* CLOUD */));
        }
        public void Ctor_WithUnicodeRanges()
        {
            // Arrange
            UrlEncoder encoder = new UrlEncoder(UnicodeRanges.Latin1Supplement, UnicodeRanges.MiscellaneousSymbols);

            // Act & assert
            Assert.Equal("%61", encoder.UrlEncode("a"));
            Assert.Equal("\u00E9", encoder.UrlEncode("\u00E9" /* LATIN SMALL LETTER E WITH ACUTE */));
            Assert.Equal("\u2601", encoder.UrlEncode("\u2601" /* CLOUD */));
        }
        public void UrlEncode_EmptyStringInput_ReturnsEmptyString()
        {
            // Arrange
            UrlEncoder encoder = new UrlEncoder();

            // Act & assert
            Assert.Equal("", encoder.UrlEncode(""));
        }
        public void UrlEncode_NullInput_ReturnsNull()
        {
            // Arrange
            UrlEncoder encoder = new UrlEncoder();

            // Act & assert
            Assert.Null(encoder.UrlEncode(null));
        }
        public void UrlEncode_InputDoesNotRequireEncoding_ReturnsOriginalStringInstance()
        {
            // Arrange
            UrlEncoder encoder = new UrlEncoder();
            string     input   = "Hello,there!";

            // Act & assert
            Assert.Same(input, encoder.UrlEncode(input));
        }
        public void UrlEncode_PositiveTestCase()
        {
            // Arrange
            IUrlEncoder encoder = new UrlEncoder(UnicodeRanges.All);
            StringWriter writer = new StringWriter();

            // Act
            encoder.UrlEncode("Hello+there!", writer);

            // Assert
            Assert.Equal("Hello%2Bthere!", writer.ToString());
        }
Example #9
0
        public void UrlEncode_PositiveTestCase()
        {
            // Arrange
            IUrlEncoder  encoder = new UrlEncoder(UnicodeRanges.All);
            StringWriter writer  = new StringWriter();

            // Act
            encoder.UrlEncode("Hello+there!", writer);

            // Assert
            Assert.Equal("Hello%2Bthere!", writer.ToString());
        }
        public void UrlEncode_StringSubstring()
        {
            // Arrange
            UrlEncoder encoder = new UrlEncoder();
            var        output  = new StringWriter();

            // Act
            encoder.UrlEncode("Hello+world!", 3, 5, output);

            // Assert
            Assert.Equal("lo%2Bwo", output.ToString());
        }
        public void UrlEncode_BadSurrogates_ReturnsUnicodeReplacementChar()
        {
            // Arrange
            UrlEncoder encoder = new UrlEncoder(UnicodeRanges.All); // allow all codepoints

            // "a<unpaired leading>b<unpaired trailing>c<trailing before leading>d<unpaired trailing><valid>e<high at end of string>"
            const string input    = "a\uD800b\uDFFFc\uDFFF\uD800d\uDFFF\uD800\uDFFFe\uD800";
            const string expected = "a%EF%BF%BDb%EF%BF%BDc%EF%BF%BD%EF%BF%BDd%EF%BF%BD%F0%90%8F%BFe%EF%BF%BD"; // 'D800' 'DFFF' was preserved since it's valid

            // Act
            string retVal = encoder.UrlEncode(input);

            // Assert
            Assert.Equal(expected, retVal);
        }
        public void Default_EquivalentToBasicLatin()
        {
            // Arrange
            UrlEncoder controlEncoder = new UrlEncoder(UnicodeRanges.BasicLatin);
            UrlEncoder testEncoder    = UrlEncoder.Default;

            // Act & assert
            for (int i = 0; i <= Char.MaxValue; i++)
            {
                if (!IsSurrogateCodePoint(i))
                {
                    string input = new String((char)i, 1);
                    Assert.Equal(controlEncoder.UrlEncode(input), testEncoder.UrlEncode(input));
                }
            }
        }
        public void Default_EquivalentToBasicLatin()
        {
            // Arrange
            UrlEncoder controlEncoder = new UrlEncoder(UnicodeRanges.BasicLatin);
            UrlEncoder testEncoder = UrlEncoder.Default;

            // Act & assert
            for (int i = 0; i <= Char.MaxValue; i++)
            {
                if (!IsSurrogateCodePoint(i))
                {
                    string input = new String((char)i, 1);
                    Assert.Equal(controlEncoder.UrlEncode(input), testEncoder.UrlEncode(input));
                }
            }
        }
        public void Ctor_WithCodePointFilter()
        {
            // Arrange
            var filter = new CodePointFilter().AllowChars("ab").AllowChars('\0', '&', '\uFFFF', 'd');
            UrlEncoder encoder = new UrlEncoder(filter);

            // Act & assert
            Assert.Equal("a", encoder.UrlEncode("a"));
            Assert.Equal("b", encoder.UrlEncode("b"));
            Assert.Equal("%63", encoder.UrlEncode("c"));
            Assert.Equal("d", encoder.UrlEncode("d"));
            Assert.Equal("%00", encoder.UrlEncode("\0")); // we still always encode control chars
            Assert.Equal("%26", encoder.UrlEncode("&")); // we still always encode HTML-special chars
            Assert.Equal("%EF%BF%BF", encoder.UrlEncode("\uFFFF")); // we still always encode non-chars and other forbidden chars
        }
        public void Ctor_WithCodePointFilter()
        {
            // Arrange
            var        filter  = new CodePointFilter().AllowChars("ab").AllowChars('\0', '&', '\uFFFF', 'd');
            UrlEncoder encoder = new UrlEncoder(filter);

            // Act & assert
            Assert.Equal("a", encoder.UrlEncode("a"));
            Assert.Equal("b", encoder.UrlEncode("b"));
            Assert.Equal("%63", encoder.UrlEncode("c"));
            Assert.Equal("d", encoder.UrlEncode("d"));
            Assert.Equal("%00", encoder.UrlEncode("\0"));           // we still always encode control chars
            Assert.Equal("%26", encoder.UrlEncode("&"));            // we still always encode HTML-special chars
            Assert.Equal("%EF%BF%BF", encoder.UrlEncode("\uFFFF")); // we still always encode non-chars and other forbidden chars
        }
        public void UrlEncode_DoesNotOutputHtmlSensitiveCharacters()
        {
            // Per the design document, we provide additional defense-in-depth
            // by never emitting HTML-sensitive characters unescaped.

            // Arrange
            UrlEncoder  urlEncoder  = new UrlEncoder(UnicodeRanges.All);
            HtmlEncoder htmlEncoder = new HtmlEncoder(UnicodeRanges.All);

            // Act & assert
            for (int i = 0; i <= 0x10FFFF; i++)
            {
                if (IsSurrogateCodePoint(i))
                {
                    continue; // surrogates don't matter here
                }

                string urlEncoded      = urlEncoder.UrlEncode(Char.ConvertFromUtf32(i));
                string thenHtmlEncoded = htmlEncoder.HtmlEncode(urlEncoded);
                Assert.Equal(urlEncoded, thenHtmlEncoded); // should have contained no HTML-sensitive characters
            }
        }
        public void UrlEncode_AllRangesAllowed_StillEncodesForbiddenChars()
        {
            // Arrange
            UrlEncoder encoder = new UrlEncoder(UnicodeRanges.All);

            // Act & assert - BMP chars
            for (int i = 0; i <= 0xFFFF; i++)
            {
                string input = new String((char)i, 1);
                string expected;
                if (IsSurrogateCodePoint(i))
                {
                    expected = "%EF%BF%BD"; // unpaired surrogate -> Unicode replacement char
                }
                else
                {
                    bool mustEncode = true;

                    // RFC 3987, Sec. 2.2 gives the list of allowed chars
                    // (We allow 'ipchar' except for "'", "&", "+", "%", and "="
                    if (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z') || ('0' <= i && i <= '9'))
                    {
                        mustEncode = false; // ALPHA / DIGIT
                    }
                    else if ((0x00A0 <= i && i <= 0xD7FF) | (0xF900 <= i && i <= 0xFDCF) | (0xFDF0 <= i && i <= 0xFFEF))
                    {
                        mustEncode = !UnicodeHelpers.IsCharacterDefined((char)i); // 'ucschar'
                    }
                    else
                    {
                        switch (i)
                        {
                        // iunreserved
                        case '-':
                        case '.':
                        case '_':
                        case '~':

                        // isegment-nz-nc
                        case '@':

                        // sub-delims
                        case '!':
                        case '$':
                        case '(':
                        case ')':
                        case '*':
                        case ',':
                        case ';':
                            mustEncode = false;
                            break;
                        }
                    }

                    if (mustEncode)
                    {
                        expected = GetKnownGoodPercentEncodedValue(i);
                    }
                    else
                    {
                        expected = input; // no encoding
                    }
                }

                string retVal = encoder.UrlEncode(input);
                Assert.Equal(expected, retVal);
            }

            // Act & assert - astral chars
            for (int i = 0x10000; i <= 0x10FFFF; i++)
            {
                string input    = Char.ConvertFromUtf32(i);
                string expected = GetKnownGoodPercentEncodedValue(i);
                string retVal   = encoder.UrlEncode(input);
                Assert.Equal(expected, retVal);
            }
        }
        public void UrlEncode_EmptyStringInput_ReturnsEmptyString()
        {
            // Arrange
            UrlEncoder encoder = new UrlEncoder();

            // Act & assert
            Assert.Equal("", encoder.UrlEncode(""));
        }
        public void UrlEncode_InputDoesNotRequireEncoding_ReturnsOriginalStringInstance()
        {
            // Arrange
            UrlEncoder encoder = new UrlEncoder();
            string input = "Hello,there!";

            // Act & assert
            Assert.Same(input, encoder.UrlEncode(input));
        }
        public void UrlEncode_NullInput_ReturnsNull()
        {
            // Arrange
            UrlEncoder encoder = new UrlEncoder();

            // Act & assert
            Assert.Null(encoder.UrlEncode(null));
        }
        public void UrlEncode_StringSubstring()
        {
            // Arrange
            UrlEncoder encoder = new UrlEncoder();
            var output = new StringWriter();

            // Act
            encoder.UrlEncode("Hello+world!", 3, 5, output);

            // Assert
            Assert.Equal("lo%2Bwo", output.ToString());
        }
        public void UrlEncode_BadSurrogates_ReturnsUnicodeReplacementChar()
        {
            // Arrange
            UrlEncoder encoder = new UrlEncoder(UnicodeRanges.All); // allow all codepoints

            // "a<unpaired leading>b<unpaired trailing>c<trailing before leading>d<unpaired trailing><valid>e<high at end of string>"
            const string input = "a\uD800b\uDFFFc\uDFFF\uD800d\uDFFF\uD800\uDFFFe\uD800";
            const string expected = "a%EF%BF%BDb%EF%BF%BDc%EF%BF%BD%EF%BF%BDd%EF%BF%BD%F0%90%8F%BFe%EF%BF%BD"; // 'D800' 'DFFF' was preserved since it's valid

            // Act
            string retVal = encoder.UrlEncode(input);

            // Assert
            Assert.Equal(expected, retVal);
        }
        public void UrlEncode_AllRangesAllowed_StillEncodesForbiddenChars()
        {
            // Arrange
            UrlEncoder encoder = new UrlEncoder(UnicodeRanges.All);

            // Act & assert - BMP chars
            for (int i = 0; i <= 0xFFFF; i++)
            {
                string input = new String((char)i, 1);
                string expected;
                if (IsSurrogateCodePoint(i))
                {
                    expected = "%EF%BF%BD"; // unpaired surrogate -> Unicode replacement char
                }
                else
                {
                    bool mustEncode = true;

                    // RFC 3987, Sec. 2.2 gives the list of allowed chars
                    // (We allow 'ipchar' except for "'", "&", "+", "%", and "="
                    if (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z') || ('0' <= i && i <= '9'))
                    {
                        mustEncode = false; // ALPHA / DIGIT
                    }
                    else if ((0x00A0 <= i && i <= 0xD7FF) | (0xF900 <= i && i <= 0xFDCF) | (0xFDF0 <= i && i <= 0xFFEF))
                    {
                        mustEncode = !UnicodeHelpers.IsCharacterDefined((char)i); // 'ucschar'
                    }
                    else
                    {
                        switch (i)
                        {
                            // iunreserved
                            case '-':
                            case '.':
                            case '_':
                            case '~':

                            // isegment-nz-nc
                            case '@':

                            // sub-delims
                            case '!':
                            case '$':
                            case '(':
                            case ')':
                            case '*':
                            case ',':
                            case ';':
                                mustEncode = false;
                                break;
                        }
                    }

                    if (mustEncode)
                    {
                        expected = GetKnownGoodPercentEncodedValue(i);
                    }
                    else
                    {
                        expected = input; // no encoding
                    }
                }

                string retVal = encoder.UrlEncode(input);
                Assert.Equal(expected, retVal);
            }

            // Act & assert - astral chars
            for (int i = 0x10000; i <= 0x10FFFF; i++)
            {
                string input = Char.ConvertFromUtf32(i);
                string expected = GetKnownGoodPercentEncodedValue(i);
                string retVal = encoder.UrlEncode(input);
                Assert.Equal(expected, retVal);
            }
        }
        public void UrlEncode_DoesNotOutputHtmlSensitiveCharacters()
        {
            // Per the design document, we provide additional defense-in-depth
            // by never emitting HTML-sensitive characters unescaped.

            // Arrange
            UrlEncoder urlEncoder = new UrlEncoder(UnicodeRanges.All);
            HtmlEncoder htmlEncoder = new HtmlEncoder(UnicodeRanges.All);

            // Act & assert
            for (int i = 0; i <= 0x10FFFF; i++)
            {
                if (IsSurrogateCodePoint(i))
                {
                    continue; // surrogates don't matter here
                }

                string urlEncoded = urlEncoder.UrlEncode(Char.ConvertFromUtf32(i));
                string thenHtmlEncoded = htmlEncoder.HtmlEncode(urlEncoded);
                Assert.Equal(urlEncoded, thenHtmlEncoded); // should have contained no HTML-sensitive characters
            }
        }