Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 5bb6088

Browse files
jamesqostephentoub
authored andcommitted
Avoid string.Split allocations in ContentDispositionHeaderValue (#7468)
* Avoid string.Split allocations in ContentDispositionHeaderValue * Add tests for changes in ContentDispositionHeaderValue
1 parent 67d719a commit 5bb6088

File tree

2 files changed

+33
-8
lines changed

2 files changed

+33
-8
lines changed

src/System.Net.Http/src/System/Net/Http/Headers/ContentDispositionHeaderValue.cs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public string DispositionType
3535
get { return _dispositionType; }
3636
set
3737
{
38-
CheckDispositionTypeFormat(value, "value");
38+
CheckDispositionTypeFormat(value, nameof(value));
3939
_dispositionType = value;
4040
}
4141
}
@@ -157,7 +157,7 @@ protected ContentDispositionHeaderValue(ContentDispositionHeaderValue source)
157157

158158
public ContentDispositionHeaderValue(string dispositionType)
159159
{
160-
CheckDispositionTypeFormat(dispositionType, "dispositionType");
160+
CheckDispositionTypeFormat(dispositionType, nameof(dispositionType));
161161
_dispositionType = dispositionType;
162162
}
163163

@@ -501,6 +501,7 @@ private bool TryDecodeMime(string input, out string output)
501501
{
502502
return false;
503503
}
504+
504505
string[] parts = processedInput.Split('?');
505506
// "=, encodingName, encodingType, encodedData, ="
506507
if (parts.Length != 5 || parts[0] != "\"=" || parts[4] != "=\"" || parts[2].ToLowerInvariant() != "b")
@@ -564,18 +565,27 @@ private string Encode5987(string input)
564565
private bool TryDecode5987(string input, out string output)
565566
{
566567
output = null;
567-
string[] parts = input.Split('\'');
568-
if (parts.Length != 3)
568+
569+
int quoteIndex = input.IndexOf('\'');
570+
if (quoteIndex == -1)
569571
{
570572
return false;
571573
}
574+
575+
int lastQuoteIndex = input.LastIndexOf('\'');
576+
if (quoteIndex == lastQuoteIndex || input.IndexOf('\'', quoteIndex + 1) != lastQuoteIndex)
577+
{
578+
return false;
579+
}
580+
581+
string encodingString = input.Substring(0, quoteIndex);
582+
string dataString = input.Substring(lastQuoteIndex + 1, input.Length - (lastQuoteIndex + 1));
572583

573584
StringBuilder decoded = new StringBuilder();
574585
try
575586
{
576-
Encoding encoding = Encoding.GetEncoding(parts[0]);
587+
Encoding encoding = Encoding.GetEncoding(encodingString);
577588

578-
string dataString = parts[2];
579589
byte[] unescapedBytes = new byte[dataString.Length];
580590
int unescapedBytesCount = 0;
581591
for (int index = 0; index < dataString.Length; index++)

src/System.Net.Http/tests/UnitTests/Headers/ContentDispositionHeaderValueTest.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,22 @@ public void FileNameStar_AddNameParameterThenUseProperty_ParametersEntryIsOverwr
188188
contentDisposition.Parameters.Remove(fileNameStar);
189189
Assert.Null(contentDisposition.FileNameStar);
190190
}
191+
192+
[Theory]
193+
[InlineData("no_quotes")]
194+
[InlineData("one'quote")]
195+
[InlineData("'triple'quotes'")]
196+
public void FileNameStar_NotTwoQuotes_IsNull(string value)
197+
{
198+
ContentDispositionHeaderValue contentDisposition = new ContentDispositionHeaderValue("inline");
199+
200+
// Note that uppercase letters are used. Comparison should happen case-insensitive.
201+
NameValueHeaderValue fileNameStar = new NameValueHeaderValue("FILENAME*", value);
202+
contentDisposition.Parameters.Add(fileNameStar);
203+
Assert.Equal(1, contentDisposition.Parameters.Count);
204+
Assert.Same(fileNameStar, contentDisposition.Parameters.First());
205+
Assert.Null(contentDisposition.FileNameStar); // Decode failure
206+
}
191207

192208
[Fact]
193209
public void FileNameStar_NeedsEncoding_EncodedAndDecodedCorrectly()
@@ -213,8 +229,7 @@ public void FileNameStar_UnknownOrBadEncoding_PropertyFails()
213229
NameValueHeaderValue fileNameStar = new NameValueHeaderValue("FILENAME*", "utf-99'lang'File%CZName.bat");
214230
contentDisposition.Parameters.Add(fileNameStar);
215231
Assert.Equal(1, contentDisposition.Parameters.Count);
216-
Assert.Equal("FILENAME*", contentDisposition.Parameters.First().Name);
217-
Assert.Equal("utf-99'lang'File%CZName.bat", contentDisposition.Parameters.First().Value);
232+
Assert.Same(fileNameStar, contentDisposition.Parameters.First());
218233
Assert.Null(contentDisposition.FileNameStar); // Decode failure
219234

220235
contentDisposition.FileNameStar = "new_name";

0 commit comments

Comments
 (0)