Skip to content
This repository was archived by the owner on Sep 3, 2024. It is now read-only.

Commit 87570d2

Browse files
Merge pull request #75 from thefringeninja/special-relativity
Fix Relative URL Problem
2 parents 67571e7 + 699b52b commit 87570d2

File tree

11 files changed

+179
-21
lines changed

11 files changed

+179
-21
lines changed

.travis.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ env:
88
- secure: fKxyki9JzY95G17hNHSy4dgDmH+zXIk50BR6honAz7LmsA9jGv2gg+l1AIUERH3eckdJwxze4K0e5hX88Xfn4j5nN8TnEw7Wwn7c1vjR9FxvRr5cjaJC0SVsOTZj4VC1R9Sqjzrkqv3jJDtDdz9B8aZMdEzJ+BkHwUMFxmuko2p2qabKnAonaGk5VDSTtDyvDMa0aFjKDYuB6MrnrxhfCzLk1ciyGL61SNfz0/u7Hj3xC6v4U0f0BQ9n65l5dIVn+mpuCdQ7GO0HGj0ySo7ffif3qqXXTx7ZWIl3wvf5RCp0PouA8q2dRHYYyGqhhCwuRNU7dfhS/eFtUtcITclZ/DJE86NBQGJ9tpUUhL7BJ3sNJZzbajh1F28paJgi595SKpScp4VGx3iBuDSKH4eb3cRj5TJqCUoscue8/uIZGgR4PGkGF4lbad3b7xexIk1YY/2Rwun1J0N7tqS0rej3ZRZBtipMF64NrVnt9dZzgsIlssZ0W2NvG0vcLX6DUdeZaR0diz8bUl1DXrMFxAUQ/QYxilvaESmCslRElzlb+5eaqQTG5lSP5l6f3ZcKAhvcUGggu9t3vjzpEq3zFa5dorCyK+es1ASNlwZtZr8in9oYkvam9aiDkZD8cEc+9u+qxvnX9w3MsA0P047YCMQGgwRl5dpizoySC3wr52voK7I=
99
- secure: HvSSWjsLR6qFi9/iHMKKoVUT4BDN7h4QjKHLvcrznwpfojrA1+nIlIwgcaIkxi5WClsoPmwW8YInPlyIyV+37+SaNK4sxB2puzwaC3iHBi6Ql38q+olsLdCE8u+DcfEcnzQo8pinNoyBLRjBgHjTAbrwIkLETNOZchss4A4UVhvPSznuNz5imlZxp4LqZ2pW/YcaLeCMQzuJHt5iRM6O4CMu7O4kMP/SPQXIXcqqYWI+o4um1JFO5juXBXtrhcTkOHfvGjqZghwma1F3v7zLHtqrbGBxaTLGNj0EIWPQhQEE5wDpvAqLEZcySl0ZjsPQUJd2Uxi9b8mWM1x6WaZTu9uqIy5t9lkCwUkEAwc/LUXZxwL0oi8HncgJvu7Q5KwVn375sJ0CER0Vn1FO8jphnMbpfkqUmbZmkwoIAUENNNYyGEp6zoNnRvaFQTjEW4bL2huPS0g3BgC2xyh8d5ZsPykIgQXlM8EEA2BZkd+ep2rKjOPT94rs5V5IPuVi9FYzFIsc2kpEkKZO/38j6pEAdCVIZp1m0+KRlLNQ9FeaI+xtil95V5ALIEXpc44o5OuUSoxt5ZirYaGSJtUtxo8E+HqpNL5WrTUeE8+aZos6Tu7jF63U2ehwg5xR6EubvrBjWvSHsQKcwDfdeHK2m15S/mVlahpwyyoCASAJtV7mRJI=
1010
matrix:
11-
- LIBRARY_VERSION=1.2.0-beta.3.21 CONTAINER_RUNTIME_VERSION=2.2.4 CONTAINER_RUNTIME=alpine3.9 RUNTIME=alpine-x64
12-
- LIBRARY_VERSION=1.2.0-beta.3.21 CONTAINER_RUNTIME_VERSION=2.2.4 CONTAINER_RUNTIME=alpine3.8 RUNTIME=alpine-x64
13-
- LIBRARY_VERSION=1.2.0-beta.3.21 CONTAINER_RUNTIME_VERSION=2.2.4 CONTAINER_RUNTIME=bionic RUNTIME=ubuntu.18.04-x64
14-
- LIBRARY_VERSION=1.2.0-beta.3.21 CONTAINER_RUNTIME_VERSION=2.2.4 CONTAINER_RUNTIME=stretch-slim RUNTIME=debian.9-x64
11+
- LIBRARY_VERSION=1.2.0-beta.3.22 CONTAINER_RUNTIME_VERSION=2.2.4 CONTAINER_RUNTIME=alpine3.9 RUNTIME=alpine-x64
12+
- LIBRARY_VERSION=1.2.0-beta.3.22 CONTAINER_RUNTIME_VERSION=2.2.4 CONTAINER_RUNTIME=alpine3.8 RUNTIME=alpine-x64
13+
- LIBRARY_VERSION=1.2.0-beta.3.22 CONTAINER_RUNTIME_VERSION=2.2.4 CONTAINER_RUNTIME=bionic RUNTIME=ubuntu.18.04-x64
14+
- LIBRARY_VERSION=1.2.0-beta.3.22 CONTAINER_RUNTIME_VERSION=2.2.4 CONTAINER_RUNTIME=stretch-slim RUNTIME=debian.9-x64
1515
git:
1616
depth: false

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ ARG CONTAINER_RUNTIME=alpine3.8
33

44
FROM node:10.12.0-alpine AS build-javascript
55
ARG CLIENT_PACKAGE=@sqlstreamstore/browser
6-
ARG CLIENT_VERSION=0.9.2
6+
ARG CLIENT_VERSION=0.9.3
77
ARG NPM_REGISTRY=https://www.myget.org/F/sqlstreamstore/npm/
88

99
ENV REACT_APP_CLIENT_VERSION=${CLIENT_VERSION}

build.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
set -e
44

55
CONTAINER_RUNTIME=${CONTAINER_RUNTIME:-alpine3.9}
6-
LIBRARY_VERSION=${LIBRARY_VERSION:-1.2.0-beta.3.19}
7-
CLIENT_VERSION=${CLIENT_VERSION:-0.9.2}
6+
LIBRARY_VERSION=${LIBRARY_VERSION:-1.2.0-beta.3.22}
7+
CLIENT_VERSION=${CLIENT_VERSION:-0.9.3}
88

99
LOCAL_IMAGE="sql-stream-store-server"
1010
LOCAL="${LOCAL_IMAGE}:latest"

src/SqlStreamStore.Server/Browser/SqlStreamStoreBrowserMiddleware.cs

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,19 @@ namespace SqlStreamStore.Server.Browser
1212
internal static class SqlStreamStoreBrowserMiddleware
1313
{
1414
public static IApplicationBuilder UseSqlStreamStoreBrowser(
15-
this IApplicationBuilder builder)
15+
this IApplicationBuilder builder,
16+
Type rootType = default)
1617
{
18+
rootType = rootType ?? typeof(SqlStreamStoreBrowserMiddleware);
1719
var sqlStreamStoreBrowserFileProvider = new EmbeddedFileProvider(
18-
typeof(SqlStreamStoreBrowserMiddleware).Assembly,
19-
typeof(SqlStreamStoreBrowserMiddleware).Namespace);
20+
rootType.Assembly,
21+
rootType.Namespace);
2022

21-
var staticFiles = typeof(SqlStreamStoreBrowserMiddleware).Assembly.GetManifestResourceNames()
22-
.Where(name => name.StartsWith(typeof(SqlStreamStoreBrowserMiddleware).Namespace));
23+
var staticFiles = rootType.Assembly.GetManifestResourceNames()
24+
.Where(name => name.StartsWith(rootType.Namespace));
2325

2426
Log.Debug(
25-
"The following embedded resources were found and will be served as static content: {staticFiles}",
27+
"The following embedded resources were found and will be served as static content: {staticFiles}",
2628
string.Join(", ", staticFiles));
2729

2830
return builder.Use(IndexPage).UseStaticFiles(new StaticFileOptions
@@ -32,11 +34,12 @@ public static IApplicationBuilder UseSqlStreamStoreBrowser(
3234

3335
Task IndexPage(HttpContext context, Func<Task> next)
3436
{
35-
if(GetAcceptHeaders(context.Request).Contains("text/html"))
37+
if (!GetAcceptHeaders(context.Request).Contains("text/html"))
3638
{
37-
context.Request.Path = new PathString("/index.html");
39+
return TryRedirectStaticContent(context, next);
3840
}
3941

42+
context.Request.Path = new PathString("/index.html");
4043
return next();
4144
}
4245
}
@@ -47,5 +50,36 @@ private static string[] GetAcceptHeaders(HttpRequest contextRequest)
4750
value => MediaTypeWithQualityHeaderValue.TryParse(value, out var header)
4851
? header.MediaType
4952
: null);
53+
54+
private static Task TryRedirectStaticContent(HttpContext context, Func<Task> next)
55+
{
56+
if (!context.Request.Path.HasValue)
57+
{
58+
return next();
59+
}
60+
61+
var requestPieces = context.Request.Path.Value.Split('/');
62+
63+
for (var i = 2; i < requestPieces.Length; i++)
64+
{
65+
if (requestPieces[i] != "static")
66+
{
67+
continue;
68+
}
69+
70+
var staticFilePath = new string[requestPieces.Length - i];
71+
for (var j = i; j < requestPieces.Length; j++)
72+
{
73+
staticFilePath[j - i] = requestPieces[j];
74+
}
75+
76+
context.Response.StatusCode = 308;
77+
context.Response.Headers["Location"] =
78+
$"{string.Join("/", Enumerable.Repeat("..", i + 1))}/{string.Join("/", staticFilePath)}";
79+
return Task.CompletedTask;
80+
}
81+
82+
return next();
83+
}
5084
}
5185
}

src/SqlStreamStore.Server/SqlStreamStore.Server.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
66
<LangVersion>latest</LangVersion>
77
<CrossGenDuringPublish>false</CrossGenDuringPublish>
8-
<LibraryVersion Condition="$(LibraryVersion) == ''">1.2.0-beta.3.21</LibraryVersion>
8+
<LibraryVersion Condition="$(LibraryVersion) == ''">1.2.0-beta.3.22</LibraryVersion>
99
</PropertyGroup>
1010
<ItemGroup>
1111
<PackageReference Include="ILLink.Tasks" Version="0.1.5-preview-1841731" />

src/SqlStreamStore.Server/SqlStreamStoreServerStartup.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using Microsoft.AspNetCore.Hosting;
55
using Microsoft.AspNetCore.Http;
66
using Microsoft.Extensions.DependencyInjection;
7-
using Serilog;
87
using SqlStreamStore.HAL;
98
using SqlStreamStore.Server.Browser;
109

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Net;
5+
using System.Net.Http;
6+
using System.Net.Http.Headers;
7+
using System.Threading.Tasks;
8+
using Microsoft.AspNetCore.Hosting;
9+
using Microsoft.AspNetCore.TestHost;
10+
using SqlStreamStore.Server.Browser;
11+
using Xunit;
12+
13+
namespace SqlStreamStore.Server.Tests.Browser
14+
{
15+
public class SqlStreamStoreBrowserTests : IDisposable
16+
{
17+
private readonly TestServer _server;
18+
private readonly HttpClient _httpClient;
19+
20+
public SqlStreamStoreBrowserTests()
21+
{
22+
_server = new TestServer(
23+
new WebHostBuilder()
24+
.Configure(app => app.UseSqlStreamStoreBrowser(typeof(SqlStreamStoreBrowserTests))));
25+
26+
_httpClient = new HttpClient(_server.CreateHandler())
27+
{
28+
BaseAddress = new UriBuilder().Uri
29+
};
30+
}
31+
32+
public static IEnumerable<object[]> IndexPageCases()
33+
{
34+
yield return new object[] {"/"};
35+
yield return new object[] {"/stream"};
36+
yield return new object[] {"/streams/a-stream"};
37+
yield return new object[] {"/streams/a-stream/metadata"};
38+
}
39+
40+
[Theory, MemberData(nameof(IndexPageCases))]
41+
public async Task RequestsForHtmlReturnTheIndexPage(string path)
42+
{
43+
using (var response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, path)
44+
{
45+
Headers = {Accept = {new MediaTypeWithQualityHeaderValue("text/html")}}
46+
}))
47+
{
48+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
49+
Assert.Equal(await GetStaticEmbeddedResource("index.html"), await response.Content.ReadAsStringAsync());
50+
}
51+
}
52+
53+
[Fact]
54+
public async Task RequestsForStaticFilesFromRootAreReturned()
55+
{
56+
using (var response = await _httpClient.SendAsync(
57+
new HttpRequestMessage(HttpMethod.Get, "/static/js/ws.js")
58+
{
59+
Headers = {Accept = {new MediaTypeWithQualityHeaderValue("*/*")}}
60+
}))
61+
{
62+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
63+
Assert.Equal(
64+
await GetStaticEmbeddedResource("static.js.ws.js"),
65+
await response.Content.ReadAsStringAsync());
66+
}
67+
}
68+
69+
public static IEnumerable<object[]> StaticContentCases()
70+
{
71+
yield return new object[] {"/stream/", "../../../"};
72+
yield return new object[] {"/streams/a-stream/", "../../../../"};
73+
yield return new object[] {"/streams/a-stream/metadata/", "../../../../../"};
74+
}
75+
76+
[Theory, MemberData(nameof(StaticContentCases))]
77+
public async Task RequestsForStaticAreRedirectedIfNotAtRoot(string path, string parent)
78+
{
79+
using (var response = await _httpClient.SendAsync(
80+
new HttpRequestMessage(HttpMethod.Get, $"{path}static/js/ws.js")
81+
{
82+
Headers = {Accept = {new MediaTypeWithQualityHeaderValue("*/*")}}
83+
}))
84+
{
85+
Assert.Equal(HttpStatusCode.PermanentRedirect, response.StatusCode);
86+
Assert.Equal($"{parent}static/js/ws.js", response.Headers.Location?.ToString());
87+
}
88+
}
89+
90+
private static async Task<string> GetStaticEmbeddedResource(string resource)
91+
{
92+
using (var stream = typeof(SqlStreamStoreBrowserTests)
93+
.Assembly
94+
.GetManifestResourceStream(typeof(SqlStreamStoreBrowserTests), resource))
95+
using (var reader = new StreamReader(stream))
96+
{
97+
return await reader.ReadToEndAsync();
98+
}
99+
}
100+
101+
public void Dispose()
102+
{
103+
_httpClient?.Dispose();
104+
_server?.Dispose();
105+
}
106+
}
107+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Title</title>
6+
</head>
7+
<body>
8+
9+
</body>
10+
</html>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
(function () {
2+
})();

tests/SqlStreamStore.Server.Tests/SqlStreamStore.Server.Tests.csproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,12 @@
1313
<PackageReference Include="xunit" Version="2.4.1" />
1414
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
1515
</ItemGroup>
16+
<ItemGroup>
17+
<EmbeddedResource Include="Browser\**" Exclude="Browser\**\*.cs">
18+
<Link>Browser\%(RecursiveDir)%(Filename)%(Extension)</Link>
19+
</EmbeddedResource>
20+
</ItemGroup>
21+
<ItemGroup>
22+
<Content Include="Browser\static\js\ws.js" />
23+
</ItemGroup>
1624
</Project>

0 commit comments

Comments
 (0)