11namespace SqlStreamStore . HAL . DevServer
22{
33 using System ;
4+ using System . Linq ;
5+ using System . Net . Http ;
6+ using System . Net . Http . Headers ;
47 using System . Threading . Tasks ;
58 using Microsoft . AspNetCore . Builder ;
69 using Microsoft . AspNetCore . Hosting ;
710 using Microsoft . AspNetCore . Http ;
811 using Microsoft . Extensions . DependencyInjection ;
12+ using Microsoft . Extensions . Primitives ;
913 using MidFunc = System . Func <
1014 Microsoft . AspNetCore . Http . HttpContext ,
1115 System . Func < System . Threading . Tasks . Task > ,
1519 internal class DevServerStartup : IStartup
1620 {
1721 private readonly IStreamStore _streamStore ;
22+ private readonly HttpClient _httpClient ;
1823
1924 public DevServerStartup ( IStreamStore streamStore )
2025 {
2126 _streamStore = streamStore ;
27+ _httpClient = new HttpClient ( ) ;
2228 }
2329
2430 public IServiceProvider ConfigureServices ( IServiceCollection services ) => services
@@ -29,6 +35,8 @@ public void Configure(IApplicationBuilder app) => app
2935 . UseResponseCompression ( )
3036 . Use ( CatchAndDisplayErrors )
3137 . Use ( AllowAllOrigins )
38+ . Use ( SqlStreamStreamBrowserJavascript )
39+ . Use ( SqlStreamStreamBrowserHtml )
3240 . UseSqlStreamStoreHal ( _streamStore ) ;
3341
3442 private static MidFunc CatchAndDisplayErrors => async ( context , next ) =>
@@ -57,5 +65,49 @@ public void Configure(IApplicationBuilder app) => app
5765
5866 return next ( ) ;
5967 } ;
68+
69+ private static string [ ] GetAcceptHeaders ( HttpRequest contextRequest )
70+ => Array . ConvertAll (
71+ contextRequest . Headers . GetCommaSeparatedValues ( "Accept" ) ,
72+ value => MediaTypeWithQualityHeaderValue . TryParse ( value , out var header )
73+ ? header . MediaType
74+ : null ) ;
75+
76+ private MidFunc SqlStreamStreamBrowserJavascript => ( context , next )
77+ => context . Request . Path . Value ? . EndsWith ( ".js" ) ?? false
78+ ? ForwardToClientDevServer (
79+ context ,
80+ $ "{ context . Request . PathBase . ToUriComponent ( ) } { context . Request . Path . ToUriComponent ( ) } ")
81+ : next ( ) ;
82+
83+ private MidFunc SqlStreamStreamBrowserHtml => ( context , next )
84+ => GetAcceptHeaders ( context . Request )
85+ . Any ( header => header == "text/html" )
86+ ? ForwardToClientDevServer ( context , context . Request . PathBase . ToUriComponent ( ) )
87+ : next ( ) ;
88+
89+ private async Task ForwardToClientDevServer ( HttpContext context , string path )
90+ {
91+ using ( var request = new HttpRequestMessage (
92+ new HttpMethod ( context . Request . Method ) ,
93+ new UriBuilder
94+ {
95+ Port = 3000 ,
96+ Host = "localhost" ,
97+ Path = path ,
98+ Query = context . Request . QueryString . ToUriComponent ( )
99+ } . Uri ) )
100+ using ( var response = await _httpClient . SendAsync ( request ) )
101+ using ( var stream = await response . Content . ReadAsStreamAsync ( ) )
102+ {
103+ context . Response . StatusCode = ( int ) response . StatusCode ;
104+ foreach ( var header in response . Headers . Concat ( response . Content . Headers ) )
105+ {
106+ context . Response . Headers . Add ( header . Key , new StringValues ( header . Value . ToArray ( ) ) ) ;
107+ }
108+
109+ await stream . CopyToAsync ( context . Response . Body , 8192 , context . RequestAborted ) ;
110+ }
111+ }
60112 }
61113}
0 commit comments