Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit272895b

Browse files
authored
fix: fix downloading different URLs to same destination (#70)
fixes#69Fixes `Downloader` to remove the `DownloadTask` when it is done via a completion. This will allow changing Coder deployments, which use different URLs but whose files are downloaded to the same place.
1 parent8f60b4d commit272895b

File tree

2 files changed

+66
-39
lines changed

2 files changed

+66
-39
lines changed

‎Tests.Vpn.Service/DownloaderTest.cs

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,34 @@ public async Task Download(CancellationToken ct)
284284
Assert.That(awaitFile.ReadAllTextAsync(destPath,ct),Is.EqualTo("test"));
285285
}
286286

287+
[Test(Description="Perform 2 downloads with the same destination")]
288+
[CancelAfter(30_000)]
289+
publicasyncTaskDownloadSameDest(CancellationTokenct)
290+
{
291+
usingvarhttpServer=EchoServer();
292+
varurl0=newUri(httpServer.BaseUrl+"/test0");
293+
varurl1=newUri(httpServer.BaseUrl+"/test1");
294+
vardestPath=Path.Combine(_tempDir,"test");
295+
296+
varmanager=newDownloader(NullLogger<Downloader>.Instance);
297+
varstartTask0=manager.StartDownloadAsync(newHttpRequestMessage(HttpMethod.Get,url0),destPath,
298+
NullDownloadValidator.Instance,ct);
299+
varstartTask1=manager.StartDownloadAsync(newHttpRequestMessage(HttpMethod.Get,url1),destPath,
300+
NullDownloadValidator.Instance,ct);
301+
vardlTask0=awaitstartTask0;
302+
awaitdlTask0.Task;
303+
Assert.That(dlTask0.TotalBytes,Is.EqualTo(5));
304+
Assert.That(dlTask0.BytesRead,Is.EqualTo(5));
305+
Assert.That(dlTask0.Progress,Is.EqualTo(1));
306+
Assert.That(dlTask0.IsCompleted,Is.True);
307+
vardlTask1=awaitstartTask1;
308+
awaitdlTask1.Task;
309+
Assert.That(dlTask1.TotalBytes,Is.EqualTo(5));
310+
Assert.That(dlTask1.BytesRead,Is.EqualTo(5));
311+
Assert.That(dlTask1.Progress,Is.EqualTo(1));
312+
Assert.That(dlTask1.IsCompleted,Is.True);
313+
}
314+
287315
[Test(Description="Download with custom headers")]
288316
[CancelAfter(30_000)]
289317
publicasyncTaskWithHeaders(CancellationTokenct)
@@ -347,17 +375,17 @@ public async Task DownloadExistingDifferentContent(CancellationToken ct)
347375

348376
[Test(Description="Unexpected response code from server")]
349377
[CancelAfter(30_000)]
350-
publicvoidUnexpectedResponseCode(CancellationTokenct)
378+
publicasyncTaskUnexpectedResponseCode(CancellationTokenct)
351379
{
352380
usingvarhttpServer=newTestHttpServer(ctx=>{ctx.Response.StatusCode=404;});
353381
varurl=newUri(httpServer.BaseUrl+"/test");
354382
vardestPath=Path.Combine(_tempDir,"test");
355383

356384
varmanager=newDownloader(NullLogger<Downloader>.Instance);
357-
// The "outer" Task should fail.
358-
varex=Assert.ThrowsAsync<HttpRequestException>(async()=>
359-
awaitmanager.StartDownloadAsync(newHttpRequestMessage(HttpMethod.Get,url),destPath,
360-
NullDownloadValidator.Instance,ct));
385+
// The "inner" Task should fail.
386+
vardlTask=awaitmanager.StartDownloadAsync(newHttpRequestMessage(HttpMethod.Get,url),destPath,
387+
NullDownloadValidator.Instance,ct);
388+
varex=Assert.ThrowsAsync<HttpRequestException>(async()=>awaitdlTask.Task);
361389
Assert.That(ex.Message,Does.Contain("404"));
362390
}
363391

@@ -384,22 +412,6 @@ public async Task MismatchedETag(CancellationToken ct)
384412
Assert.That(ex.Message,Does.Contain("ETag does not match SHA1 hash of downloaded file").And.Contains("beef"));
385413
}
386414

387-
[Test(Description="Timeout on response headers")]
388-
[CancelAfter(30_000)]
389-
publicvoidCancelledOuter(CancellationTokenct)
390-
{
391-
usingvarhttpServer=newTestHttpServer(async _=>{awaitTask.Delay(TimeSpan.FromSeconds(5),ct);});
392-
varurl=newUri(httpServer.BaseUrl+"/test");
393-
vardestPath=Path.Combine(_tempDir,"test");
394-
395-
varmanager=newDownloader(NullLogger<Downloader>.Instance);
396-
// The "outer" Task should fail.
397-
varsmallerCt=newCancellationTokenSource(TimeSpan.FromSeconds(1)).Token;
398-
Assert.ThrowsAsync<TaskCanceledException>(
399-
async()=>awaitmanager.StartDownloadAsync(newHttpRequestMessage(HttpMethod.Get,url),destPath,
400-
NullDownloadValidator.Instance,smallerCt));
401-
}
402-
403415
[Test(Description="Timeout on response body")]
404416
[CancelAfter(30_000)]
405417
publicasyncTaskCancelledInner(CancellationTokenct)
@@ -451,12 +463,10 @@ public async Task ValidationFailureExistingFile(CancellationToken ct)
451463
awaitFile.WriteAllTextAsync(destPath,"test",ct);
452464

453465
varmanager=newDownloader(NullLogger<Downloader>.Instance);
454-
// The "outer" Task should fail because the inner task never starts.
455-
varex=Assert.ThrowsAsync<Exception>(async()=>
456-
{
457-
awaitmanager.StartDownloadAsync(newHttpRequestMessage(HttpMethod.Get,url),destPath,
458-
newTestDownloadValidator(newException("test exception")),ct);
459-
});
466+
vardlTask=awaitmanager.StartDownloadAsync(newHttpRequestMessage(HttpMethod.Get,url),destPath,
467+
newTestDownloadValidator(newException("test exception")),ct);
468+
// The "inner" Task should fail.
469+
varex=Assert.ThrowsAsync<Exception>(async()=>{awaitdlTask.Task;});
460470
Assert.That(ex.Message,Does.Contain("Existing file failed validation"));
461471
Assert.That(ex.InnerException,Is.Not.Null);
462472
Assert.That(ex.InnerException!.Message,Is.EqualTo("test exception"));

‎Vpn.Service/Downloader.cs

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
usingSystem.Formats.Asn1;
44
usingSystem.Net;
55
usingSystem.Runtime.CompilerServices;
6+
usingSystem.Runtime.ExceptionServices;
67
usingSystem.Security.Cryptography;
78
usingSystem.Security.Cryptography.X509Certificates;
89
usingCoder.Desktop.Vpn.Utilities;
@@ -288,7 +289,26 @@ public async Task<DownloadTask> StartDownloadAsync(HttpRequestMessage req, strin
288289
{
289290
vartask=_downloads.GetOrAdd(destinationPath,
290291
_=>newDownloadTask(_logger,req,destinationPath,validator));
291-
awaittask.EnsureStartedAsync(ct);
292+
// EnsureStarted is a no-op if we didn't create a new DownloadTask.
293+
// So, we will only remove the destination once for each time we start a new task.
294+
task.EnsureStarted(tsk=>
295+
{
296+
// remove the key first, before checking the exception, to ensure
297+
// we still clean up.
298+
_downloads.TryRemove(destinationPath,out_);
299+
if(tsk.Exception==null)
300+
{
301+
return;
302+
}
303+
304+
if(tsk.Exception.InnerException!=null)
305+
{
306+
ExceptionDispatchInfo.Capture(tsk.Exception.InnerException).Throw();
307+
}
308+
309+
// not sure if this is hittable, but just in case:
310+
throwtsk.Exception;
311+
},ct);
292312

293313
// If the existing (or new) task is for the same URL, return it.
294314
if(task.Request.RequestUri==req.RequestUri)
@@ -357,21 +377,19 @@ internal DownloadTask(ILogger logger, HttpRequestMessage req, string destination
357377
".download-"+Path.GetRandomFileName());
358378
}
359379

360-
internalasyncTask<Task>EnsureStartedAsync(CancellationTokenct=default)
380+
internalvoidEnsureStarted(Action<Task>continuation,CancellationTokenct=default)
361381
{
362-
usingvar_=await_semaphore.LockAsync(ct);
382+
usingvar_=_semaphore.Lock();
363383
if(Task==null!)
364-
Task=awaitStartDownloadAsync(ct);
365-
366-
returnTask;
384+
Task=Start(ct).ContinueWith(continuation,ct);
367385
}
368386

369387
/// <summary>
370388
/// Starts downloading the file. The request will be performed in this task, but once started, the task will complete
371389
/// and the download will continue in the background. The provided CancellationToken can be used to cancel the
372390
/// download.
373391
/// </summary>
374-
privateasyncTask<Task>StartDownloadAsync(CancellationTokenct=default)
392+
privateasyncTaskStart(CancellationTokenct=default)
375393
{
376394
Directory.CreateDirectory(_destinationDirectory);
377395

@@ -398,8 +416,7 @@ private async Task<Task> StartDownloadAsync(CancellationToken ct = default)
398416
thrownewException("Existing file failed validation after 304 Not Modified",e);
399417
}
400418

401-
Task=Task.CompletedTask;
402-
returnTask;
419+
return;
403420
}
404421

405422
if(res.StatusCode!=HttpStatusCode.OK)
@@ -432,11 +449,11 @@ private async Task<Task> StartDownloadAsync(CancellationToken ct = default)
432449
throw;
433450
}
434451

435-
Task=DownloadAsync(res,tempFile,ct);
436-
returnTask;
452+
awaitDownload(res,tempFile,ct);
453+
return;
437454
}
438455

439-
privateasyncTaskDownloadAsync(HttpResponseMessageres,FileStreamtempFile,CancellationTokenct)
456+
privateasyncTaskDownload(HttpResponseMessageres,FileStreamtempFile,CancellationTokenct)
440457
{
441458
try
442459
{

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp