diff --git a/src/Microsoft.AspNetCore.WebUtilities/WebEncoders.cs b/src/Microsoft.AspNetCore.WebUtilities/WebEncoders.cs
deleted file mode 100644
index 50f2eefb..00000000
--- a/src/Microsoft.AspNetCore.WebUtilities/WebEncoders.cs
+++ /dev/null
@@ -1,374 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Diagnostics;
-using System.Globalization;
-
-namespace Microsoft.AspNetCore.WebUtilities
-{
- ///
- /// Contains utility APIs to assist with common encoding and decoding operations.
- ///
- public static class WebEncoders
- {
- private static readonly byte[] EmptyBytes = new byte[0];
-
- ///
- /// Decodes a base64url-encoded string.
- ///
- /// The base64url-encoded input to decode.
- /// The base64url-decoded form of the input.
- ///
- /// The input must not contain any whitespace or padding characters.
- /// Throws if the input is malformed.
- ///
- public static byte[] Base64UrlDecode(string input)
- {
- if (input == null)
- {
- throw new ArgumentNullException(nameof(input));
- }
-
- return Base64UrlDecode(input, offset: 0, count: input.Length);
- }
-
- ///
- /// Decodes a base64url-encoded substring of a given string.
- ///
- /// A string containing the base64url-encoded input to decode.
- /// The position in at which decoding should begin.
- /// The number of characters in to decode.
- /// The base64url-decoded form of the input.
- ///
- /// The input must not contain any whitespace or padding characters.
- /// Throws if the input is malformed.
- ///
- public static byte[] Base64UrlDecode(string input, int offset, int count)
- {
- if (input == null)
- {
- throw new ArgumentNullException(nameof(input));
- }
-
- ValidateParameters(input.Length, nameof(input), offset, count);
-
- // Special-case empty input
- if (count == 0)
- {
- return EmptyBytes;
- }
-
- // Create array large enough for the Base64 characters, not just shorter Base64-URL-encoded form.
- var buffer = new char[GetArraySizeRequiredToDecode(count)];
-
- return Base64UrlDecode(input, offset, buffer, bufferOffset: 0, count: count);
- }
-
- ///
- /// Decodes a base64url-encoded into a byte[].
- ///
- /// A string containing the base64url-encoded input to decode.
- /// The position in at which decoding should begin.
- ///
- /// Scratch buffer to hold the s to decode. Array must be large enough to hold
- /// and characters as well as Base64 padding
- /// characters. Content is not preserved.
- ///
- ///
- /// The offset into at which to begin writing the s to decode.
- ///
- /// The number of characters in to decode.
- /// The base64url-decoded form of the .
- ///
- /// The input must not contain any whitespace or padding characters.
- /// Throws if the input is malformed.
- ///
- public static byte[] Base64UrlDecode(string input, int offset, char[] buffer, int bufferOffset, int count)
- {
- if (input == null)
- {
- throw new ArgumentNullException(nameof(input));
- }
- if (buffer == null)
- {
- throw new ArgumentNullException(nameof(buffer));
- }
-
- ValidateParameters(input.Length, nameof(input), offset, count);
- if (bufferOffset < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(bufferOffset));
- }
-
- if (count == 0)
- {
- return EmptyBytes;
- }
-
- // Assumption: input is base64url encoded without padding and contains no whitespace.
-
- var paddingCharsToAdd = GetNumBase64PaddingCharsToAddForDecode(count);
- var arraySizeRequired = checked(count + paddingCharsToAdd);
- Debug.Assert(arraySizeRequired % 4 == 0, "Invariant: Array length must be a multiple of 4.");
-
- if (buffer.Length - bufferOffset < arraySizeRequired)
- {
- throw new ArgumentException(
- string.Format(
- CultureInfo.CurrentCulture,
- Resources.WebEncoders_InvalidCountOffsetOrLength,
- nameof(count),
- nameof(bufferOffset),
- nameof(input)),
- nameof(count));
- }
-
- // Copy input into buffer, fixing up '-' -> '+' and '_' -> '/'.
- var i = bufferOffset;
- for (var j = offset; i - bufferOffset < count; i++, j++)
- {
- var ch = input[j];
- if (ch == '-')
- {
- buffer[i] = '+';
- }
- else if (ch == '_')
- {
- buffer[i] = '/';
- }
- else
- {
- buffer[i] = ch;
- }
- }
-
- // Add the padding characters back.
- for (; paddingCharsToAdd > 0; i++, paddingCharsToAdd--)
- {
- buffer[i] = '=';
- }
-
- // Decode.
- // If the caller provided invalid base64 chars, they'll be caught here.
- return Convert.FromBase64CharArray(buffer, bufferOffset, arraySizeRequired);
- }
-
- ///
- /// Gets the minimum char[] size required for decoding of characters
- /// with the method.
- ///
- /// The number of characters to decode.
- ///
- /// The minimum char[] size required for decoding of characters.
- ///
- public static int GetArraySizeRequiredToDecode(int count)
- {
- if (count < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(count));
- }
-
- if (count == 0)
- {
- return 0;
- }
-
- var numPaddingCharsToAdd = GetNumBase64PaddingCharsToAddForDecode(count);
-
- return checked(count + numPaddingCharsToAdd);
- }
-
- ///
- /// Encodes using base64url encoding.
- ///
- /// The binary input to encode.
- /// The base64url-encoded form of .
- public static string Base64UrlEncode(byte[] input)
- {
- if (input == null)
- {
- throw new ArgumentNullException(nameof(input));
- }
-
- return Base64UrlEncode(input, offset: 0, count: input.Length);
- }
-
- ///
- /// Encodes using base64url encoding.
- ///
- /// The binary input to encode.
- /// The offset into at which to begin encoding.
- /// The number of bytes from to encode.
- /// The base64url-encoded form of .
- public static string Base64UrlEncode(byte[] input, int offset, int count)
- {
- if (input == null)
- {
- throw new ArgumentNullException(nameof(input));
- }
-
- ValidateParameters(input.Length, nameof(input), offset, count);
-
- // Special-case empty input
- if (count == 0)
- {
- return string.Empty;
- }
-
- var buffer = new char[GetArraySizeRequiredToEncode(count)];
- var numBase64Chars = Base64UrlEncode(input, offset, buffer, outputOffset: 0, count: count);
-
- return new String(buffer, startIndex: 0, length: numBase64Chars);
- }
-
- ///
- /// Encodes using base64url encoding.
- ///
- /// The binary input to encode.
- /// The offset into at which to begin encoding.
- ///
- /// Buffer to receive the base64url-encoded form of . Array must be large enough to
- /// hold characters and the full base64-encoded form of
- /// , including padding characters.
- ///
- ///
- /// The offset into at which to begin writing the base64url-encoded form of
- /// .
- ///
- /// The number of bytes from to encode.
- ///
- /// The number of characters written to , less any padding characters.
- ///
- public static int Base64UrlEncode(byte[] input, int offset, char[] output, int outputOffset, int count)
- {
- if (input == null)
- {
- throw new ArgumentNullException(nameof(input));
- }
- if (output == null)
- {
- throw new ArgumentNullException(nameof(output));
- }
-
- ValidateParameters(input.Length, nameof(input), offset, count);
- if (outputOffset < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(outputOffset));
- }
-
- var arraySizeRequired = GetArraySizeRequiredToEncode(count);
- if (output.Length - outputOffset < arraySizeRequired)
- {
- throw new ArgumentException(
- string.Format(
- CultureInfo.CurrentCulture,
- Resources.WebEncoders_InvalidCountOffsetOrLength,
- nameof(count),
- nameof(outputOffset),
- nameof(output)),
- nameof(count));
- }
-
- // Special-case empty input.
- if (count == 0)
- {
- return 0;
- }
-
- // Use base64url encoding with no padding characters. See RFC 4648, Sec. 5.
-
- // Start with default Base64 encoding.
- var numBase64Chars = Convert.ToBase64CharArray(input, offset, count, output, outputOffset);
-
- // Fix up '+' -> '-' and '/' -> '_'. Drop padding characters.
- for (var i = outputOffset; i - outputOffset < numBase64Chars; i++)
- {
- var ch = output[i];
- if (ch == '+')
- {
- output[i] = '-';
- }
- else if (ch == '/')
- {
- output[i] = '_';
- }
- else if (ch == '=')
- {
- // We've reached a padding character; truncate the remainder.
- return i - outputOffset;
- }
- }
-
- return numBase64Chars;
- }
-
- ///
- /// Get the minimum output char[] size required for encoding
- /// s with the method.
- ///
- /// The number of characters to encode.
- ///
- /// The minimum output char[] size required for encoding s.
- ///
- public static int GetArraySizeRequiredToEncode(int count)
- {
- var numWholeOrPartialInputBlocks = checked(count + 2) / 3;
- return checked(numWholeOrPartialInputBlocks * 4);
- }
-
- private static int GetNumBase64PaddingCharsInString(string str)
- {
- // Assumption: input contains a well-formed base64 string with no whitespace.
-
- // base64 guaranteed have 0 - 2 padding characters.
- if (str[str.Length - 1] == '=')
- {
- if (str[str.Length - 2] == '=')
- {
- return 2;
- }
- return 1;
- }
- return 0;
- }
-
- private static int GetNumBase64PaddingCharsToAddForDecode(int inputLength)
- {
- switch (inputLength % 4)
- {
- case 0:
- return 0;
- case 2:
- return 2;
- case 3:
- return 1;
- default:
- throw new FormatException("TODO: Malformed input.");
- }
- }
-
- private static void ValidateParameters(int bufferLength, string inputName, int offset, int count)
- {
- if (offset < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(offset));
- }
- if (count < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(count));
- }
- if (bufferLength - offset < count)
- {
- throw new ArgumentException(
- string.Format(
- CultureInfo.CurrentCulture,
- Resources.WebEncoders_InvalidCountOffsetOrLength,
- nameof(count),
- nameof(offset),
- inputName),
- nameof(count));
- }
- }
- }
-}
diff --git a/src/Microsoft.AspNetCore.WebUtilities/project.json b/src/Microsoft.AspNetCore.WebUtilities/project.json
index fbf32d14..043063c9 100644
--- a/src/Microsoft.AspNetCore.WebUtilities/project.json
+++ b/src/Microsoft.AspNetCore.WebUtilities/project.json
@@ -11,15 +11,20 @@
]
},
"buildOptions": {
- "warningsAsErrors": true,
+ "define": [ "WebEncoders_In_WebUtilities" ],
"keyFile": "../../tools/Key.snk",
"nowarn": [
"CS1591"
],
+ "warningsAsErrors": true,
"xmlDoc": true
},
"dependencies": {
"Microsoft.Extensions.Primitives": "1.1.0-*",
+ "Microsoft.Extensions.WebEncoders.Sources": {
+ "type": "build",
+ "version": "1.1.0-*"
+ },
"System.Buffers": "4.0.0-*",
"System.Text.Encodings.Web": "4.0.0-*"
},
diff --git a/test/Microsoft.AspNetCore.WebUtilities.Tests/WebEncodersTests.cs b/test/Microsoft.AspNetCore.WebUtilities.Tests/WebEncodersTests.cs
index c781805f..a4c4d155 100644
--- a/test/Microsoft.AspNetCore.WebUtilities.Tests/WebEncodersTests.cs
+++ b/test/Microsoft.AspNetCore.WebUtilities.Tests/WebEncodersTests.cs
@@ -24,74 +24,6 @@ public void Base64UrlDecode_BadOffsets(string input, int offset, int count)
});
}
- [Theory]
- [InlineData("x")]
- [InlineData("(x)")]
- public void Base64UrlDecode_MalformedInput(string input)
- {
- // Act & assert
- Assert.Throws(() =>
- {
- var retVal = WebEncoders.Base64UrlDecode(input);
- });
- }
-
- [Theory]
- [InlineData("", "")]
- [InlineData("123456qwerty++//X+/x", "123456qwerty--__X-_x")]
- [InlineData("123456qwerty++//X+/xxw==", "123456qwerty--__X-_xxw")]
- [InlineData("123456qwerty++//X+/xxw0=", "123456qwerty--__X-_xxw0")]
- public void Base64UrlEncode_And_Decode(string base64Input, string expectedBase64Url)
- {
- // Arrange
- byte[] input = new byte[3].Concat(Convert.FromBase64String(base64Input)).Concat(new byte[2]).ToArray();
-
- // Act & assert - 1
- string actualBase64Url = WebEncoders.Base64UrlEncode(input, 3, input.Length - 5); // also helps test offsets
- Assert.Equal(expectedBase64Url, actualBase64Url);
-
- // Act & assert - 2
- // Verify that values round-trip
- byte[] roundTripped = WebEncoders.Base64UrlDecode("xx" + actualBase64Url + "yyy", 2, actualBase64Url.Length); // also helps test offsets
- string roundTrippedAsBase64 = Convert.ToBase64String(roundTripped);
- Assert.Equal(roundTrippedAsBase64, base64Input);
- }
-
- [Theory]
- [InlineData("", "")]
- [InlineData("123456qwerty++//X+/x", "123456qwerty--__X-_x")]
- [InlineData("123456qwerty++//X+/xxw==", "123456qwerty--__X-_xxw")]
- [InlineData("123456qwerty++//X+/xxw0=", "123456qwerty--__X-_xxw0")]
- public void Base64UrlEncode_And_Decode_WithBufferOffsets(string base64Input, string expectedBase64Url)
- {
- // Arrange
- var input = new byte[3].Concat(Convert.FromBase64String(base64Input)).Concat(new byte[2]).ToArray();
- var buffer = new char[30];
- var output = new char[30];
- for (var i = 0; i < buffer.Length; i++)
- {
- buffer[i] = '^';
- output[i] = '^';
- }
-
- // Act 1
- var numEncodedChars =
- WebEncoders.Base64UrlEncode(input, offset: 3, output: output, outputOffset: 4, count: input.Length - 5);
-
- // Assert 1
- var encodedString = new string(output, startIndex: 4, length: numEncodedChars);
- Assert.Equal(expectedBase64Url, encodedString);
-
- // Act 2
- var roundTripInput = new string(output);
- var roundTripped =
- WebEncoders.Base64UrlDecode(roundTripInput, offset: 4, buffer: buffer, bufferOffset: 5, count: numEncodedChars);
-
- // Assert 2, verify that values round-trip
- var roundTrippedAsBase64 = Convert.ToBase64String(roundTripped);
- Assert.Equal(roundTrippedAsBase64, base64Input);
- }
-
[Theory]
[InlineData(0, 1, 0)]
[InlineData(0, 0, 1)]