Ejemplo n.º 1
0
        /// <summary>
        /// Escapes a <see cref="StringSegment"/> as a quoted-string, which is defined by
        /// <see href="https://tools.ietf.org/html/rfc7230#section-3.2.6">the RFC specification</see>.
        /// </summary>
        /// <remarks>
        /// This will add a backslash before each backslash and quote and add quotes
        /// around the input. Assumes that the input does not have quotes around it,
        /// as this method will add them. Throws if the input contains any invalid escape characters,
        /// as defined by rfc7230.
        /// </remarks>
        /// <param name="input">The input to be escaped.</param>
        /// <returns>An escaped version of the quoted-string.</returns>
        public static StringSegment EscapeAsQuotedString(StringSegment input)
        {
            // By calling this, we know that the string requires quotes around it to be a valid token.
            var backSlashCount = CountAndCheckCharactersNeedingBackslashesWhenEncoding(input);

            var stringBuilder = new InplaceStringBuilder(input.Length + backSlashCount + 2); // 2 for quotes

            stringBuilder.Append('\"');

            for (var i = 0; i < input.Length; i++)
            {
                if (input[i] == '\\' || input[i] == '\"')
                {
                    stringBuilder.Append('\\');
                }
                else if ((input[i] <= 0x1F || input[i] == 0x7F) && input[i] != 0x09)
                {
                    // Control characters are not allowed in a quoted-string, which include all characters
                    // below 0x1F (except for 0x09 (TAB)) and 0x7F.
                    throw new FormatException($"Invalid control character '{input[i]}' in input.");
                }
                stringBuilder.Append(input[i]);
            }
            stringBuilder.Append('\"');
            return(stringBuilder.ToString());
        }
Ejemplo n.º 2
0
        public static string ToHexString(this Span <byte> bytes)
        {
            if (HexLookupLowercase == null)
            {
                lock (HexLookupLock)
                {
                    if (HexLookupLowercase == null)
                    {
                        HexLookupLowercase = new string[256];
                        for (byte b = 0; b <= 255; b++)
                        {
                            HexLookupLowercase[b] = b.ToString("x2");

                            if (b == 255)
                            {
                                break;
                            }
                        }
                    }
                }
            }

            var sb = new InplaceStringBuilder(bytes.Length * 2);

            foreach (var b in bytes)
            {
                sb.Append(HexLookupLowercase[b]);
            }

            return(sb.ToString());
        }
Ejemplo n.º 3
0
        public static string ToRfc1123String(this DateTimeOffset dateTime, bool quoted)
        {
            var universal = dateTime.UtcDateTime;

            var length = quoted ? QuotedRfc1123DateLength : Rfc1123DateLength;
            var target = new InplaceStringBuilder(length);

            if (quoted)
            {
                target.Append(Quote);
            }

            target.Append(DayNames[(int)universal.DayOfWeek]);
            target.Append(Comma);
            target.Append(Space);
            AppendNumber(ref target, universal.Day);
            target.Append(Space);
            target.Append(MonthNames[universal.Month - 1]);
            target.Append(Space);
            AppendYear(ref target, universal.Year);
            target.Append(Space);
            AppendTimeOfDay(ref target, universal.TimeOfDay);
            target.Append(Space);
            target.Append(Gmt);

            if (quoted)
            {
                target.Append(Quote);
            }

            return(target.ToString());
        }
Ejemplo n.º 4
0
        // To enable unit testing
        internal static string DecodeToBase64String(string text)
        {
            if (string.IsNullOrEmpty(text))
            {
                return(text);
            }

            var padLength            = 3 - ((text.Length + 3) % 4);
            var inplaceStringBuilder = new InplaceStringBuilder(capacity: text.Length + padLength);

            for (var i = 0; i < text.Length; i++)
            {
                if (text[i] == '-')
                {
                    inplaceStringBuilder.Append('+');
                }
                else if (text[i] == '_')
                {
                    inplaceStringBuilder.Append('/');
                }
                else
                {
                    inplaceStringBuilder.Append(text[i]);
                }
            }

            for (var i = 0; i < padLength; i++)
            {
                inplaceStringBuilder.Append('=');
            }

            return(inplaceStringBuilder.ToString());
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Given a quoted-string as defined by <see href="https://tools.ietf.org/html/rfc7230#section-3.2.6">the RFC specification</see>,
        /// removes quotes and unescapes backslashes and quotes. This assumes that the input is a valid quoted-string.
        /// </summary>
        /// <param name="input">The quoted-string to be unescaped.</param>
        /// <returns>An unescaped version of the quoted-string.</returns>
        public static StringSegment UnescapeAsQuotedString(StringSegment input)
        {
            input = RemoveQuotes(input);

            // First pass to calculate the size of the InplaceStringBuilder
            var backSlashCount = CountBackslashesForDecodingQuotedString(input);

            if (backSlashCount == 0)
            {
                return(input);
            }

            var stringBuilder = new InplaceStringBuilder(input.Length - backSlashCount);

            for (var i = 0; i < input.Length; i++)
            {
                if (i < input.Length - 1 && input[i] == '\\')
                {
                    // If there is an backslash character as the last character in the string,
                    // we will assume that it should be included literally in the unescaped string
                    // Ex: "hello\\" => "hello\\"
                    // Also, if a sender adds a quoted pair like '\\''n',
                    // we will assume it is over escaping and just add a n to the string.
                    // Ex: "he\\llo" => "hello"
                    stringBuilder.Append(input[i + 1]);
                    i++;
                    continue;
                }
                stringBuilder.Append(input[i]);
            }

            return(stringBuilder.ToString());
        }
Ejemplo n.º 6
0
 private static void AppendYear(ref InplaceStringBuilder target, int year)
 {
     target.Append(GetAsciiChar(year / 1000));
     target.Append(GetAsciiChar(year % 1000 / 100));
     target.Append(GetAsciiChar(year % 100 / 10));
     target.Append(GetAsciiChar(year % 10));
 }
Ejemplo n.º 7
0
        // To enable unit testing
        internal static string EncodeInternal(string base64EncodedString)
        {
            var length = base64EncodedString.Length;

            while (length > 0 && base64EncodedString[length - 1] == '=')
            {
                length--;
            }

            if (length == 0)
            {
                return(string.Empty);
            }

            var inplaceStringBuilder = new InplaceStringBuilder(length);

            for (var i = 0; i < length; i++)
            {
                if (base64EncodedString[i] == '+')
                {
                    inplaceStringBuilder.Append('-');
                }
                else if (base64EncodedString[i] == '/')
                {
                    inplaceStringBuilder.Append('_');
                }
                else
                {
                    inplaceStringBuilder.Append(base64EncodedString[i]);
                }
            }

            return(inplaceStringBuilder.ToString());
        }
Ejemplo n.º 8
0
 private static void AppendTimeOfDay(ref InplaceStringBuilder target, TimeSpan timeOfDay)
 {
     AppendNumber(ref target, timeOfDay.Hours);
     target.Append(Colon);
     AppendNumber(ref target, timeOfDay.Minutes);
     target.Append(Colon);
     AppendNumber(ref target, timeOfDay.Seconds);
 }
Ejemplo n.º 9
0
        public void Append_ThrowsIfNotEnoughSpace()
        {
            var formatter = new InplaceStringBuilder(1);

            var exception = Assert.Throws <InvalidOperationException>(() => formatter.Append("123"));

            Assert.Equal("Not enough capacity to write '3' characters, only '1' left.", exception.Message);
        }
Ejemplo n.º 10
0
        public void Build_ThrowsIfNotEnoughWritten()
        {
            var formatter = new InplaceStringBuilder(5);

            formatter.Append("123");
            var exception = Assert.Throws <InvalidOperationException>(() => formatter.ToString());

            Assert.Equal("Entire reserved capacity was not used. Capacity: '5', written '3'.", exception.Message);
        }
Ejemplo n.º 11
0
        public static string HexEncode(this byte[] bytes)
        {
            var sb = new InplaceStringBuilder(bytes.Length * 2);

            foreach (var _byte in bytes)
            {
                sb.Append($"{_byte:x2}");
            }
            return(sb.ToString());
        }
Ejemplo n.º 12
0
        public void Capacity_ThrowsIfAppendWasCalled()
        {
            var formatter = new InplaceStringBuilder(3);

            formatter.Append("123");

            var exception = Assert.Throws <InvalidOperationException>(() => formatter.Capacity = 5);

            Assert.Equal("Cannot change capacity after write started.", exception.Message);
        }
 private static void AppendSegment(ref InplaceStringBuilder builder, StringSegment name, StringSegment value)
 {
     builder.Append(SeparatorToken);
     builder.Append(name);
     if (value != null)
     {
         builder.Append(EqualsToken);
         builder.Append(value);
     }
 }
Ejemplo n.º 14
0
        public void ToString_ReturnsStringWithAllAppendedValues()
        {
            var s1  = "123";
            var c1  = '4';
            var s2  = "56789";
            var seg = new StringSegment("890123", 2, 2);

            var formatter = new InplaceStringBuilder();

            formatter.Capacity += s1.Length + 1 + s2.Length + seg.Length;
            formatter.Append(s1);
            formatter.Append(c1);
            formatter.Append(s2, 0, 2);
            formatter.Append(s2, 2, 2);
            formatter.Append(s2, 4, 1);
            formatter.Append(seg);
            Assert.Equal("12345678901", formatter.ToString());
        }
Ejemplo n.º 15
0
        protected string NormalizeKey(string templateKey)
        {
            if (!(_razorProject is FileSystemRazorProject))
            {
                return(templateKey);
            }

            var addLeadingSlash  = templateKey[0] != '\\' && templateKey[0] != '/';
            var transformSlashes = templateKey.IndexOf('\\') != -1;

            if (!addLeadingSlash && !transformSlashes)
            {
                return(templateKey);
            }

            var length = templateKey.Length;

            if (addLeadingSlash)
            {
                length++;
            }

            var builder = new InplaceStringBuilder(length);

            if (addLeadingSlash)
            {
                builder.Append('/');
            }

            for (var i = 0; i < templateKey.Length; i++)
            {
                var ch = templateKey[i];
                if (ch == '\\')
                {
                    ch = '/';
                }
                builder.Append(ch);
            }

            return(builder.ToString());
        }
Ejemplo n.º 16
0
        public static string NormalizePath(string path)
        {
            var addLeadingSlash  = path[0] != '\\' && path[0] != '/';
            var transformSlashes = path.IndexOf('\\') != -1;

            if (!addLeadingSlash && !transformSlashes)
            {
                return(path);
            }

            var length = path.Length;

            if (addLeadingSlash)
            {
                length++;
            }

            var builder = new InplaceStringBuilder(length);

            if (addLeadingSlash)
            {
                builder.Append('/');
            }

            for (var i = 0; i < path.Length; i++)
            {
                var ch = path[i];
                if (ch == '\\')
                {
                    ch = '/';
                }
                builder.Append(ch);
            }

            return(builder.ToString());
        }
Ejemplo n.º 17
0
        private void RewriteStyleAttributes(ResponseAnalysisContext context, string html)
        {
            var headIndex = html.IndexOf("</head>", StringComparison.OrdinalIgnoreCase);

            if (headIndex == -1)
            {
                return;
            }

            SortedList <string, StringSegment> inlineStyles = null;

            foreach (var index in FastHtmlParser.FindAllAttributeIndexes(html, "style"))
            {
                // get content
                var inner = FastHtmlParser.GetAttributeValueAtName(html, "style", index);
                if (inner.Length == 0)
                {
                    continue;
                }

                if (inlineStyles == null)
                {
                    inlineStyles = new SortedList <string, StringSegment>();
                }

                // compute hash
                var hash = ComputeHash(inner.Trim());

                if (!inlineStyles.ContainsKey(hash))
                {
                    inlineStyles.Add(hash, inner);
                }

                // add change
                context.AddChange(TextChange.Remove(html, index, inner.Offset + inner.Length + 1 - index));

                var tagIndex       = FastHtmlParser.FindOpenTagAtAttribute(html, index);
                var classAttribute = FastHtmlParser.GetAttributeValueAtTag(html, "class", tagIndex);
                if (classAttribute.Length > 0)
                {
                    context.AddChange(TextChange.Insert(html, classAttribute.Offset + classAttribute.Length, "_" + hash));
                }
                else
                {
                    context.AddChange(FastHtmlParser.CreateInsertAttributeChange(html, tagIndex, "class", "_" + hash));
                }
            }

            // assemble inline styles
            if (inlineStyles != null && inlineStyles.Count > 0)
            {
                var hashBuilder = new InplaceStringBuilder(inlineStyles.Count * HashBytes * 2);
                foreach (var entry in inlineStyles)
                {
                    hashBuilder.Append(entry.Key);
                }

                var hash = ComputeHash(hashBuilder.ToString());
                if (!InlineContentService.ContainsStyleByHash(hash))
                {
                    var contentBuilder = StringBuilderPool.Get();
                    foreach (var entry in inlineStyles)
                    {
                        contentBuilder.Append('.');
                        contentBuilder.Append('_');
                        contentBuilder.Append(entry.Key);
                        contentBuilder.Append('{');
                        contentBuilder.Append(entry.Value.Value);
                        contentBuilder.Append('}');
                    }
                    InlineContentService.TryAddStyleByHash(hash, contentBuilder.ToString());
                    StringBuilderPool.Return(contentBuilder);
                }

                var tag = $"<link rel=\"stylesheet\" href=\"/.waf/styles/{hash}\" type=\"text/css\" />";
                context.AddChange(TextChange.Insert(html, headIndex, tag));
            }
        }
Ejemplo n.º 18
0
 private static void AppendNumber(ref InplaceStringBuilder target, int number)
 {
     target.Append(GetAsciiChar(number / 10));
     target.Append(GetAsciiChar(number % 10));
 }
Ejemplo n.º 19
0
            static string GetJoinedStringValueFromArray(string[] values)
            {
                // Calculate final length
                var length = 0;

                for (var i = 0; i < values.Length; i++)
                {
                    var value = values[i];
                    // Skip null and empty values
                    if (value != null && value.Length > 0)
                    {
                        if (length > 0)
                        {
                            // Add seperator
                            length++;
                        }

                        length += value.Length;
                    }
                }
#if NETCOREAPP
                // Create the new string
                return(string.Create(length, values, (span, strings) => {
                    var offset = 0;
                    // Skip null and empty values
                    for (var i = 0; i < strings.Length; i++)
                    {
                        var value = strings[i];
                        if (value != null && value.Length > 0)
                        {
                            if (offset > 0)
                            {
                                // Add seperator
                                span[offset] = ',';
                                offset++;
                            }

                            value.AsSpan().CopyTo(span.Slice(offset));
                            offset += value.Length;
                        }
                    }
                }));
#else
#pragma warning disable CS0618
                var sb = new InplaceStringBuilder(length);
#pragma warning restore CS0618
                var hasAdded = false;
                // Skip null and empty values
                for (var i = 0; i < values.Length; i++)
                {
                    var value = values[i];
                    if (value != null && value.Length > 0)
                    {
                        if (hasAdded)
                        {
                            // Add seperator
                            sb.Append(',');
                        }

                        sb.Append(value);
                        hasAdded = true;
                    }
                }

                return(sb.ToString());
#endif
            }
        // name="value"; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite={Strict|Lax}; httponly
        public override string ToString()
        {
            var length = _name.Length + EqualsToken.Length + _value.Length;

            string expires  = null;
            string maxAge   = null;
            string sameSite = null;

            if (Expires.HasValue)
            {
                expires = HeaderUtilities.FormatDate(Expires.Value);
                length += SeparatorToken.Length + ExpiresToken.Length + EqualsToken.Length + expires.Length;
            }

            if (MaxAge.HasValue)
            {
                maxAge  = HeaderUtilities.FormatNonNegativeInt64((long)MaxAge.Value.TotalSeconds);
                length += SeparatorToken.Length + MaxAgeToken.Length + EqualsToken.Length + maxAge.Length;
            }

            if (Domain != null)
            {
                length += SeparatorToken.Length + DomainToken.Length + EqualsToken.Length + Domain.Length;
            }

            if (Path != null)
            {
                length += SeparatorToken.Length + PathToken.Length + EqualsToken.Length + Path.Length;
            }

            if (Secure)
            {
                length += SeparatorToken.Length + SecureToken.Length;
            }

            if (SameSite != SameSiteMode.None)
            {
                sameSite = SameSite == SameSiteMode.Lax ? SameSiteLaxToken : SameSiteStrictToken;
                length  += SeparatorToken.Length + SameSiteToken.Length + EqualsToken.Length + sameSite.Length;
            }

            if (HttpOnly)
            {
                length += SeparatorToken.Length + HttpOnlyToken.Length;
            }

            var sb = new InplaceStringBuilder(length);

            sb.Append(_name);
            sb.Append(EqualsToken);
            sb.Append(_value);

            if (expires != null)
            {
                AppendSegment(ref sb, ExpiresToken, expires);
            }

            if (maxAge != null)
            {
                AppendSegment(ref sb, MaxAgeToken, maxAge);
            }

            if (Domain != null)
            {
                AppendSegment(ref sb, DomainToken, Domain);
            }

            if (Path != null)
            {
                AppendSegment(ref sb, PathToken, Path);
            }

            if (Secure)
            {
                AppendSegment(ref sb, SecureToken, null);
            }

            if (SameSite != SameSiteMode.None)
            {
                AppendSegment(ref sb, SameSiteToken, sameSite);
            }

            if (HttpOnly)
            {
                AppendSegment(ref sb, HttpOnlyToken, null);
            }

            return(sb.ToString());
        }