-
Notifications
You must be signed in to change notification settings - Fork 97
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Block postbacks for 5s after redirects
The page does not unload right after we perform a navigation, and allows the user to hit the submit button a second time. In the past, we used to disable all postbacks after a redirect, but that also blocks the page after a file is returned. There probably isn't a 100% reliable way to detect if the location change is a navigation or a file return. With this patch, we will block the page again, but only for a limited time (5 seconds). We also only only block the postback queue, which means that only postbacks with Concurrency=Deny or Queue will be affected. Standard file returns as provided by DotVVM are excluded from this, but it should also work acceptably with custom file returns (some buttons will not work for 5 seconds after the file return)
- Loading branch information
Showing
11 changed files
with
227 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 6 additions & 1 deletion
7
src/Framework/Framework/Resources/Scripts/utils/magic-navigator.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,15 @@ | ||
let fakeAnchor: HTMLAnchorElement | undefined; | ||
export function navigate(url: string) { | ||
export function navigate(url: string, downloadName: string | null | undefined = null) { | ||
if (!fakeAnchor) { | ||
fakeAnchor = <HTMLAnchorElement> document.createElement("a"); | ||
fakeAnchor.style.display = "none"; | ||
document.body.appendChild(fakeAnchor); | ||
} | ||
if (downloadName == null) { | ||
fakeAnchor.removeAttribute("download"); | ||
} else { | ||
fakeAnchor.download = downloadName | ||
} | ||
fakeAnchor.href = url; | ||
fakeAnchor.click(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
/** Runs the callback in the next event loop cycle */ | ||
export const defer = <T>(callback: () => T) => Promise.resolve().then(callback) | ||
export const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
65 changes: 65 additions & 0 deletions
65
...Samples/Common/ViewModels/FeatureSamples/Redirect/RedirectPostbackConcurrencyViewModel.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
using System.Diagnostics.Metrics; | ||
using System.IO; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using DotVVM.Core.Storage; | ||
using DotVVM.Framework.ViewModel; | ||
|
||
namespace DotVVM.Samples.BasicSamples.ViewModels.FeatureSamples.Redirect | ||
{ | ||
class RedirectPostbackConcurrencyViewModel : DotvvmViewModelBase | ||
{ | ||
public static int GlobalCounter = 0; | ||
private readonly IReturnedFileStorage returnedFileStorage; | ||
|
||
[Bind(Direction.ServerToClient)] | ||
public int Counter { get; set; } = GlobalCounter; | ||
|
||
public int MiniCounter { get; set; } = 0; | ||
|
||
[FromQuery("empty")] | ||
public bool IsEmptyPage { get; set; } = false; | ||
[FromQuery("loadDelay")] | ||
public int LoadDelay { get; set; } = 0; | ||
|
||
public RedirectPostbackConcurrencyViewModel(IReturnedFileStorage returnedFileStorage) | ||
{ | ||
this.returnedFileStorage = returnedFileStorage; | ||
} | ||
public override async Task Init() | ||
{ | ||
await Task.Delay(LoadDelay); // delay to enable user to click DelayIncrement button between it succeeding and loading the next page | ||
await base.Init(); | ||
} | ||
|
||
public async Task DelayIncrement() | ||
{ | ||
await Task.Delay(1000); | ||
|
||
Interlocked.Increment(ref GlobalCounter); | ||
|
||
Context.RedirectToRoute(Context.Route.RouteName, query: new { empty = true, loadDelay = 2000 }); | ||
} | ||
|
||
public async Task GetFileStandard() | ||
{ | ||
await Context.ReturnFileAsync("test file"u8.ToArray(), "test.txt", "text/plain"); | ||
} | ||
|
||
public async Task GetFileCustom() | ||
{ | ||
var metadata = new ReturnedFileMetadata() | ||
{ | ||
FileName = "test_custom.txt", | ||
MimeType = "text/plain", | ||
AttachmentDispositionType = "attachment" | ||
}; | ||
|
||
var stream = new MemoryStream("test custom file"u8.ToArray()); | ||
var generatedFileId = await returnedFileStorage.StoreFileAsync(stream, metadata).ConfigureAwait(false); | ||
|
||
var url = Context.TranslateVirtualPath("~/dotvvmReturnedFile?id=" + generatedFileId); | ||
Context.RedirectToUrl(url); | ||
} | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
src/Samples/Common/Views/FeatureSamples/Redirect/RedirectPostbackConcurrency.dothtml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
@viewModel DotVVM.Samples.BasicSamples.ViewModels.FeatureSamples.Redirect.RedirectPostbackConcurrencyViewModel, DotVVM.Samples.Common | ||
<html xmlns="http://www.w3.org/1999/xhtml"> | ||
<head> | ||
<title>Hello from DotVVM!</title> | ||
</head> | ||
<body> | ||
<div IncludeInPage={resource: IsEmptyPage}> | ||
<dot:RouteLink RouteName={resource: Context.Route.RouteName} Query-empty=false>Back</dot:RouteLink> | ||
</div> | ||
<div class="container" IncludeInPage={resource: !IsEmptyPage}> | ||
<h1>Redirect and postback concurrency test</h1> | ||
<p> | ||
Testing Concurrency=Deny / Concurrency=Queue with redirect and file returns. | ||
</p> | ||
<p>First, we have a set of buttons incrementing a static variable, each takes about 2sec and redirects to a blank page afterwards</p> | ||
<p>GlobalCounter = <span data-ui="counter" InnerText={value: Counter} /></p> | ||
<p>MiniCounter(Concurrency=Deny) = <dot:Button data-ui=minicounter Text={value: MiniCounter} PostBack.Concurrency=Deny Click={staticCommand: MiniCounter = MiniCounter + 1} /></p> | ||
|
||
<p> | ||
<dot:Button data-ui="inc-default" Click={command: DelayIncrement()} PostBack.Concurrency=Default>Increment (Concurrency=Default)</dot:Button> | ||
<dot:Button data-ui="inc-deny" Click={command: DelayIncrement()} PostBack.Concurrency=Deny>Increment (Concurrency=Deny)</dot:Button> | ||
<dot:Button data-ui="inc-queue" Click={command: DelayIncrement()} PostBack.Concurrency=Queue>Increment (Concurrency=Queue)</dot:Button> | ||
</p> | ||
|
||
<p>We also test that returning files does not block the page forever, </p> | ||
|
||
<p> | ||
<dot:Button data-ui="file-std" Click={command: GetFileStandard()}>Standard return file</dot:Button> | ||
<dot:Button data-ui="file-custom" Click={command: GetFileCustom()}>Custom return file (will have delay before page works)</dot:Button> | ||
</p> | ||
</div> | ||
</body> | ||
</html> |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters