From de2844edd840c6f49af7bee4d203149fb8a9ed89 Mon Sep 17 00:00:00 2001 From: yu ben Date: Sun, 10 May 2026 19:41:34 +0800 Subject: [PATCH 1/4] Fix ArgumentOutOfRangeException when validating Basic Authorization header --- Tests/HttpUnitTests/HttpListenerRequest.cs | 31 +++++++++++++++++++ Tests/HttpUnitTests/HttpUnitTests.nfproj | 1 + .../Http/System.Net.HttpListenerRequest.cs | 29 ++++++++++------- 3 files changed, 49 insertions(+), 12 deletions(-) create mode 100644 Tests/HttpUnitTests/HttpListenerRequest.cs diff --git a/Tests/HttpUnitTests/HttpListenerRequest.cs b/Tests/HttpUnitTests/HttpListenerRequest.cs new file mode 100644 index 00000000..fa0b1439 --- /dev/null +++ b/Tests/HttpUnitTests/HttpListenerRequest.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Net; +using nanoFramework.TestFramework; + +namespace HttpUnitTests +{ + internal class HttpListenerRequestTests + { + // Verifies that malformed Authorization header (no space) does not cause a crash + [TestMethod] + public void Add_Authorization_NoSpaceMultipleChars_ShouldNotThrow() + { + var headers = new WebHeaderCollection(); + headers.Add("Authorization: a111111"); + string value = headers["Authorization"]; + Assert.AreEqual("a111111", value); + } + + // Verifies that a properly formatted Authorization header (with space) is parsed and stored correctly + [TestMethod] + public void Add_Authorization_ValidBasicToken_ShouldSucceed() + { + var headers = new WebHeaderCollection(); + headers.Add("Authorization: Basic a111111"); + string value = headers["Authorization"]; + Assert.AreEqual("Basic a111111", value); + } + } +} diff --git a/Tests/HttpUnitTests/HttpUnitTests.nfproj b/Tests/HttpUnitTests/HttpUnitTests.nfproj index 7e9aa7f3..3ee060a9 100644 --- a/Tests/HttpUnitTests/HttpUnitTests.nfproj +++ b/Tests/HttpUnitTests/HttpUnitTests.nfproj @@ -26,6 +26,7 @@ + diff --git a/nanoFramework.System.Net.Http/Http/System.Net.HttpListenerRequest.cs b/nanoFramework.System.Net.Http/Http/System.Net.HttpListenerRequest.cs index c959518f..ad85743b 100644 --- a/nanoFramework.System.Net.Http/Http/System.Net.HttpListenerRequest.cs +++ b/nanoFramework.System.Net.Http/Http/System.Net.HttpListenerRequest.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) .NET Foundation and Contributors // Portions Copyright (c) Microsoft Corporation. All rights reserved. // See LICENSE file in the project root for full license information. @@ -206,21 +206,26 @@ internal void ParseHTTPRequest() if (headerName == "authorization") { int sepSpace = headerValue.IndexOf(' '); - string authType = headerValue.Substring(0, sepSpace); - if (authType.ToLower() == "basic") + // Authorization header value must be in format "type credentials". If not, ignore. + if (sepSpace > 0) { - string authInfo = headerValue.Substring(sepSpace + 1); - // authInfo is base64 encoded username and password. - byte[] authInfoDecoded = Convert.FromBase64String(authInfo); - char[] authInfoDecChar = System.Text.Encoding.UTF8.GetChars(authInfoDecoded); - string strAuthInfo = new string(authInfoDecChar); - // The strAuthInfo comes in format username:password. Parse it. - int sepColon = strAuthInfo.IndexOf(':'); - if (sepColon != -1) + string authType = headerValue.Substring(0, sepSpace); + if (authType.ToLower() == "basic") { - m_NetworkCredentials = new NetworkCredential(strAuthInfo.Substring(0, sepColon), strAuthInfo.Substring(sepColon + 1)); + string authInfo = headerValue.Substring(sepSpace + 1); + // authInfo is base64 encoded username and password. + byte[] authInfoDecoded = Convert.FromBase64String(authInfo); + char[] authInfoDecChar = System.Text.Encoding.UTF8.GetChars(authInfoDecoded); + string strAuthInfo = new string(authInfoDecChar); + // The strAuthInfo comes in format username:password. Parse it. + int sepColon = strAuthInfo.IndexOf(':'); + if (sepColon != -1) + { + m_NetworkCredentials = new NetworkCredential(strAuthInfo.Substring(0, sepColon), strAuthInfo.Substring(sepColon + 1)); + } } } + } } From 4bd82ac6141dba6a8e0f78660105f78271ebe07c Mon Sep 17 00:00:00 2001 From: benyuz <305378604@qq.com> Date: Mon, 11 May 2026 22:13:20 +0800 Subject: [PATCH 2/4] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- Tests/HttpUnitTests/HttpListenerRequest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/HttpUnitTests/HttpListenerRequest.cs b/Tests/HttpUnitTests/HttpListenerRequest.cs index fa0b1439..147bfab5 100644 --- a/Tests/HttpUnitTests/HttpListenerRequest.cs +++ b/Tests/HttpUnitTests/HttpListenerRequest.cs @@ -23,9 +23,9 @@ public void Add_Authorization_NoSpaceMultipleChars_ShouldNotThrow() public void Add_Authorization_ValidBasicToken_ShouldSucceed() { var headers = new WebHeaderCollection(); - headers.Add("Authorization: Basic a111111"); + headers.Add("Authorization: Basic dXNlcjpwYXNz"); string value = headers["Authorization"]; - Assert.AreEqual("Basic a111111", value); + Assert.AreEqual("Basic dXNlcjpwYXNz", value); } } } From 39b3e14502e3f33b61c7aa2391623087fcc189db Mon Sep 17 00:00:00 2001 From: benyuz <305378604@qq.com> Date: Tue, 12 May 2026 06:41:53 +0800 Subject: [PATCH 3/4] Update nanoFramework.System.Net.Http/Http/System.Net.HttpListenerRequest.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: José Simões --- .../Http/System.Net.HttpListenerRequest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nanoFramework.System.Net.Http/Http/System.Net.HttpListenerRequest.cs b/nanoFramework.System.Net.Http/Http/System.Net.HttpListenerRequest.cs index ad85743b..54d9c6d5 100644 --- a/nanoFramework.System.Net.Http/Http/System.Net.HttpListenerRequest.cs +++ b/nanoFramework.System.Net.Http/Http/System.Net.HttpListenerRequest.cs @@ -206,7 +206,7 @@ internal void ParseHTTPRequest() if (headerName == "authorization") { int sepSpace = headerValue.IndexOf(' '); - // Authorization header value must be in format "type credentials". If not, ignore. + // Authorization header value must contain an auth scheme followed by a space and its parameter(s), e.g. "Basic xxx" or "Bearer xxx". If not, ignore. if (sepSpace > 0) { string authType = headerValue.Substring(0, sepSpace); From 414c0295ab5215089bd3229241038e4c096372e8 Mon Sep 17 00:00:00 2001 From: yu ben Date: Tue, 12 May 2026 06:57:42 +0800 Subject: [PATCH 4/4] rename file to HttpListenerRequestTests --- ...{HttpListenerRequest.cs => HttpListenerRequestTests.cs} | 7 +++++-- Tests/HttpUnitTests/HttpUnitTests.nfproj | 2 +- .../Http/System.Net.HttpListenerRequest.cs | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) rename Tests/HttpUnitTests/{HttpListenerRequest.cs => HttpListenerRequestTests.cs} (87%) diff --git a/Tests/HttpUnitTests/HttpListenerRequest.cs b/Tests/HttpUnitTests/HttpListenerRequestTests.cs similarity index 87% rename from Tests/HttpUnitTests/HttpListenerRequest.cs rename to Tests/HttpUnitTests/HttpListenerRequestTests.cs index fa0b1439..8f6dec2c 100644 --- a/Tests/HttpUnitTests/HttpListenerRequest.cs +++ b/Tests/HttpUnitTests/HttpListenerRequestTests.cs @@ -1,5 +1,8 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + using System.Net; using nanoFramework.TestFramework; diff --git a/Tests/HttpUnitTests/HttpUnitTests.nfproj b/Tests/HttpUnitTests/HttpUnitTests.nfproj index 3ee060a9..b67072ab 100644 --- a/Tests/HttpUnitTests/HttpUnitTests.nfproj +++ b/Tests/HttpUnitTests/HttpUnitTests.nfproj @@ -26,7 +26,7 @@ - + diff --git a/nanoFramework.System.Net.Http/Http/System.Net.HttpListenerRequest.cs b/nanoFramework.System.Net.Http/Http/System.Net.HttpListenerRequest.cs index ad85743b..54d9c6d5 100644 --- a/nanoFramework.System.Net.Http/Http/System.Net.HttpListenerRequest.cs +++ b/nanoFramework.System.Net.Http/Http/System.Net.HttpListenerRequest.cs @@ -206,7 +206,7 @@ internal void ParseHTTPRequest() if (headerName == "authorization") { int sepSpace = headerValue.IndexOf(' '); - // Authorization header value must be in format "type credentials". If not, ignore. + // Authorization header value must contain an auth scheme followed by a space and its parameter(s), e.g. "Basic xxx" or "Bearer xxx". If not, ignore. if (sepSpace > 0) { string authType = headerValue.Substring(0, sepSpace);