Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add back support for manually handling POST requests #1744

Merged
merged 2 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions src/Framework/Framework/Hosting/DotvvmPresenter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -478,11 +478,8 @@ async Task RespondWithStaticCommandValidationFailure(ActionInfo action, IDotvvmR
async Task ValidateSecFetchHeaders(IDotvvmRequestContext context)
{
var route = context.Route?.RouteName;
var isPost = context.HttpContext.Request.Method switch {
"POST" => true,
"GET" => false,
_ => throw new NotSupportedException()
};
var requestType = DotvvmRequestContext.DetermineRequestType(context.HttpContext);
var isPost = requestType is DotvvmRequestType.Command or DotvvmRequestType.StaticCommand;
var checksAllowed = (isPost ? SecurityConfiguration.VerifySecFetchForCommands : SecurityConfiguration.VerifySecFetchForPages).IsEnabledForRoute(route);
var dest = context.HttpContext.Request.Headers["Sec-Fetch-Dest"];
var site = context.HttpContext.Request.Headers["Sec-Fetch-Site"];
Expand Down
3 changes: 3 additions & 0 deletions src/Framework/Framework/Hosting/DotvvmRequestContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ public static DotvvmRequestType DetermineRequestType(IHttpContext context)
{
return DotvvmRequestType.Command;
}
// Unknown POST request is treated as a Navigate request
// it is useful for submitting classic <form method=POST> elements (as a no-JS fallback, login forms, etc.)
return DotvvmRequestType.Navigate;
}
return DotvvmRequestType.Unknown;
}
Expand Down
1 change: 1 addition & 0 deletions src/Samples/Common/DotVVM.Samples.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Web" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Views\FeatureSamples\ViewModules\LinkModuleControl.dotcontrol" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using DotVVM.Framework.ViewModel;

namespace DotVVM.Samples.BasicSamples.ViewModels.FeatureSamples.NoJsForm
{
public class NoJsFormViewModel : DotvvmViewModelBase
{
public string Form1Value { get; set; }
public string Form2Value { get; set; }

public override async Task Load()
{
var req = Context.HttpContext.Request;
if (req.Method == "POST")
{
using var body = new StreamReader(req.Body);
var data = HttpUtility.ParseQueryString(await body.ReadToEndAsync());
var submit = data["submit"];
if (submit == "form1")
{
Form1Value = data["text"];
}
else if (submit == "form2")
{
Form2Value = data["text"];
}
}
}
}
}

35 changes: 35 additions & 0 deletions src/Samples/Common/Views/FeatureSamples/NoJsForm/NoJsForm.dothtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@viewModel DotVVM.Samples.BasicSamples.ViewModels.FeatureSamples.NoJsForm.NoJsFormViewModel, DotVVM.Samples.Common

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
<div RenderSettings.Mode=Server>
<fieldset>
<legend>Form 1</legend>
<form method="POST">
<input id=input1 type="text" name="text" />
<button id=submit1 type=submit name=submit value=form1>Submit</button>

<p Visible={value: Form1Value != null}>
Last submitted value: <span id=result1>{{value: Form1Value}}</span>
</p>
</form>
</fieldset>

<fieldset>
<legend>Form 2</legend>
<form method="POST">
<input id=input2 type="text" name="text" />
<button id=submit2 type=submit name=submit value=form2>Submit</button>

<p Visible={value: Form2Value != null}>
Last submitted value: <span id=result2>{{value: Form2Value}}</span>
</p>
</form>
</fieldset>
</div>
</body>
</html>

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions src/Samples/Tests/Tests/Feature/NoJsFormTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Text;
using DotVVM.Samples.Tests.Base;
using DotVVM.Testing.Abstractions;
using Riganti.Selenium.Core;
using Riganti.Selenium.DotVVM;
using Xunit;
using Xunit.Abstractions;

namespace DotVVM.Samples.Tests.Feature
{
public class NoJsFormTests : AppSeleniumTest
{
[Fact]
public void Feature_NoJsForm_NoJsForm()
{
RunInAllBrowsers(browser => {
browser.NavigateToUrl(SamplesRouteUrls.FeatureSamples_NoJsForm_NoJsForm);

browser.SendKeys("#input1", "Q");
browser.Click("#submit1");
AssertUI.InnerTextEquals(browser.First("#result1"), "Q");

browser.SendKeys("#input2", "W");
browser.Click("#submit2");
AssertUI.InnerTextEquals(browser.First("#result2"), "W");
});
}

public NoJsFormTests(ITestOutputHelper output) : base(output)
{
}
}
}
Loading