diff --git a/src/Umbraco.Cms.Api.Delivery/Services/RoutingServiceBase.cs b/src/Umbraco.Cms.Api.Delivery/Services/RoutingServiceBase.cs index 4a05521b22..8168d296db 100644 --- a/src/Umbraco.Cms.Api.Delivery/Services/RoutingServiceBase.cs +++ b/src/Umbraco.Cms.Api.Delivery/Services/RoutingServiceBase.cs @@ -36,7 +36,7 @@ internal abstract class RoutingServiceBase } protected static string GetContentRoute(DomainAndUri domainAndUri, Uri contentRoute) - => $"{domainAndUri.ContentId}{DomainUtilities.PathRelativeToDomain(domainAndUri.Uri, contentRoute.AbsolutePath)}"; + => $"{domainAndUri.ContentId}{DomainUtilities.PathRelativeToDomain(domainAndUri.Uri, contentRoute.LocalPath)}"; // Use LocalPath over AbsolutePath to keep the path decoded. protected DomainAndUri? GetDomainAndUriForRoute(Uri contentUrl) { diff --git a/src/Umbraco.Cms.Api.Delivery/Umbraco.Cms.Api.Delivery.csproj b/src/Umbraco.Cms.Api.Delivery/Umbraco.Cms.Api.Delivery.csproj index 37816e2f6e..b275c6ad14 100644 --- a/src/Umbraco.Cms.Api.Delivery/Umbraco.Cms.Api.Delivery.csproj +++ b/src/Umbraco.Cms.Api.Delivery/Umbraco.Cms.Api.Delivery.csproj @@ -22,6 +22,9 @@ <_Parameter1>Umbraco.Tests.UnitTests + + <_Parameter1>Umbraco.Tests.Integration + <_Parameter1>DynamicProxyGenAssembly2 diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Core/DeliveryApi/RequestRoutingServiceTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Core/DeliveryApi/RequestRoutingServiceTests.cs new file mode 100644 index 0000000000..3c1586181d --- /dev/null +++ b/tests/Umbraco.Tests.Integration/Umbraco.Core/DeliveryApi/RequestRoutingServiceTests.cs @@ -0,0 +1,66 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using NUnit.Framework; +using Umbraco.Cms.Api.Delivery.Services; +using Umbraco.Cms.Core.Cache; +using Umbraco.Cms.Core.DeliveryApi; +using Umbraco.Cms.Core.PublishedCache; +using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Tests.Common.Testing; +using Umbraco.Cms.Tests.Integration.Testing; + +namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.DeliveryApi; + +[TestFixture] +[UmbracoTest( + Database = UmbracoTestOptions.Database.NewSchemaPerFixture, + WithApplication = true)] +public class RequestRoutingServiceTests : UmbracoIntegrationTest +{ + private IRequestRoutingService RequestRoutingService => GetRequiredService(); + + protected override void CustomTestSetup(IUmbracoBuilder builder) + { + builder.Services.AddUnique(); + + var elementCache = new FastDictionaryAppCache(); + var snapshotCache = new FastDictionaryAppCache(); + + var domainCacheMock = new Mock(); + domainCacheMock.Setup(x => x.GetAll(It.IsAny())) + .Returns( + [ + new Domain(1, "localhost/en", 1000, "en-us", false, 0), + new Domain(2, "localhost/jp", 1000, "ja-jp", false, 1), + ]); + builder.Services.AddSingleton(provider => domainCacheMock.Object); + } + + [TestCase(null, "")] + [TestCase("", "")] + [TestCase("/", "/")] + [TestCase("/en/test/", "1000/test/")] // Verifies matching a domain. + [TestCase("/da/test/", "/da/test/")] // Verifies that with no matching domain, so route will be returned as is. + [TestCase("/jp/オフィス/", "1000/オフィス/")] // Verifies that with a URL segment containing special characters, the route remains decoded. + public void GetContentRoute_ReturnsExpectedRoute(string? requestedRoute, string expectedResult) + { + if (!string.IsNullOrEmpty(requestedRoute)) + { + var httpContextAccessor = GetRequiredService(); + + httpContextAccessor.HttpContext = new DefaultHttpContext + { + Request = + { + Scheme = "https", + Host = new HostString("localhost"), + Path = requestedRoute, + }, + }; + } + + var result = RequestRoutingService.GetContentRoute(requestedRoute); + Assert.AreEqual(expectedResult, result); + } +}