summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/SMAPI.Web/Framework/RewriteRules/ConditionalRedirectToHttpsRule.cs62
-rw-r--r--src/SMAPI.Web/Framework/RewriteRules/ConditionalRewriteSubdomainRule.cs4
-rw-r--r--src/SMAPI.Web/Startup.cs7
3 files changed, 71 insertions, 2 deletions
diff --git a/src/SMAPI.Web/Framework/RewriteRules/ConditionalRedirectToHttpsRule.cs b/src/SMAPI.Web/Framework/RewriteRules/ConditionalRedirectToHttpsRule.cs
new file mode 100644
index 00000000..d6a56bb7
--- /dev/null
+++ b/src/SMAPI.Web/Framework/RewriteRules/ConditionalRedirectToHttpsRule.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Net;
+using System.Text;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Rewrite;
+
+namespace StardewModdingAPI.Web.Framework.RewriteRules
+{
+ /// <summary>Redirect requests to HTTPS.</summary>
+ /// <remarks>Derived from <a href="https://stackoverflow.com/a/44526747/262123" /> and <see cref="Microsoft.AspNetCore.Rewrite.Internal.RedirectToHttpsRule"/>.</remarks>
+ internal class ConditionalRedirectToHttpsRule : IRule
+ {
+ /*********
+ ** Properties
+ *********/
+ /// <summary>A predicate which indicates when the rule should be applied.</summary>
+ private readonly Func<HttpRequest, bool> ShouldRewrite;
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Construct an instance.</summary>
+ /// <param name="shouldRewrite">A predicate which indicates when the rule should be applied.</param>
+ public ConditionalRedirectToHttpsRule(Func<HttpRequest, bool> shouldRewrite = null)
+ {
+ this.ShouldRewrite = shouldRewrite ?? (req => true);
+ }
+
+ /// <summary>Applies the rule. Implementations of ApplyRule should set the value for <see cref="RewriteContext.Result" /> (defaults to RuleResult.ContinueRules).</summary>
+ /// <param name="context">The rewrite context.</param>
+ public void ApplyRule(RewriteContext context)
+ {
+ HttpRequest request = context.HttpContext.Request;
+
+ // check condition
+ if (this.IsSecure(request) || !this.ShouldRewrite(request))
+ return;
+
+ // redirect request
+ HttpResponse response = context.HttpContext.Response;
+ response.StatusCode = (int)HttpStatusCode.RedirectKeepVerb;
+ response.Headers["Location"] = new StringBuilder()
+ .Append("https://")
+ .Append(request.Host.Host)
+ .Append(request.PathBase)
+ .Append(request.Path)
+ .Append(request.QueryString)
+ .ToString();
+ context.Result = RuleResult.EndResponse;
+ }
+
+ /// <summary>Get whether the request was received over HTTPS.</summary>
+ /// <param name="request">The request to check.</param>
+ public bool IsSecure(HttpRequest request)
+ {
+ return
+ request.IsHttps // HTTPS to server
+ || string.Equals(request.Headers["x-forwarded-proto"], "HTTPS", StringComparison.OrdinalIgnoreCase); // HTTPS to AWS load balancer
+ }
+ }
+}
diff --git a/src/SMAPI.Web/Framework/RewriteRules/ConditionalRewriteSubdomainRule.cs b/src/SMAPI.Web/Framework/RewriteRules/ConditionalRewriteSubdomainRule.cs
index 83f23058..920632ab 100644
--- a/src/SMAPI.Web/Framework/RewriteRules/ConditionalRewriteSubdomainRule.cs
+++ b/src/SMAPI.Web/Framework/RewriteRules/ConditionalRewriteSubdomainRule.cs
@@ -22,7 +22,7 @@ namespace StardewModdingAPI.Web.Framework.RewriteRules
/// <param name="shouldRewrite">A predicate which indicates when the rule should be applied.</param>
public ConditionalRewriteSubdomainRule(Func<HttpRequest, bool> shouldRewrite = null)
{
- this.ShouldRewrite = shouldRewrite;
+ this.ShouldRewrite = shouldRewrite ?? (req => true);
}
/// <summary>Applies the rule. Implementations of ApplyRule should set the value for <see cref="RewriteContext.Result" /> (defaults to RuleResult.ContinueRules).</summary>
@@ -32,7 +32,7 @@ namespace StardewModdingAPI.Web.Framework.RewriteRules
HttpRequest request = context.HttpContext.Request;
// check condition
- if (this.ShouldRewrite != null && !this.ShouldRewrite(request))
+ if (!this.ShouldRewrite(request))
return;
// get host parts
diff --git a/src/SMAPI.Web/Startup.cs b/src/SMAPI.Web/Startup.cs
index 0f656e55..b27ff9a5 100644
--- a/src/SMAPI.Web/Startup.cs
+++ b/src/SMAPI.Web/Startup.cs
@@ -66,6 +66,13 @@ namespace StardewModdingAPI.Web
loggerFactory.AddDebug();
app
.UseRewriter(new RewriteOptions()
+ // redirect to HTTPS (except API for Linux/Mac Mono compatibility)
+ .Add(new ConditionalRedirectToHttpsRule(
+ shouldRewrite: req =>
+ req.Host.Host != "localhost"
+ && !req.Path.StartsWithSegments("/api")
+ ))
+
// convert subdomain.smapi.io => smapi.io/subdomain for routing
.Add(new ConditionalRewriteSubdomainRule(
shouldRewrite: req =>