Skip to content

Commit

Permalink
#243: Logic for static routes to download files
Browse files Browse the repository at this point in the history
  • Loading branch information
Badgerati committed May 6, 2019
1 parent 5006308 commit 7b79583
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 36 deletions.
13 changes: 9 additions & 4 deletions src/Tools/Middleware.ps1
Expand Up @@ -127,8 +127,8 @@ function Get-PodePublicMiddleware
param($e)

# get the static file path
$path = Get-PodeStaticRoutePath -Route $e.Path -Protocol $e.Protocol -Endpoint $e.Endpoint
if ($null -eq $path) {
$info = Get-PodeStaticRoutePath -Route $e.Path -Protocol $e.Protocol -Endpoint $e.Endpoint
if (Test-Empty $info.Path) {
return $true
}

Expand All @@ -147,8 +147,13 @@ function Get-PodePublicMiddleware
}
}

# write the file to the response
File -Path $path -MaxAge $PodeContext.Server.Web.Static.Cache.MaxAge -Cache:$caching
# write, or attach, the file to the response
if ($info.Download) {
Attach -Path $info.Path -Literal
}
else {
File -Path $info.Path -MaxAge $PodeContext.Server.Web.Static.Cache.MaxAge -Cache:$caching
}

# static content found, stop
return $false
Expand Down
44 changes: 26 additions & 18 deletions src/Tools/Responses.ps1
Expand Up @@ -144,14 +144,19 @@ function Attach
{
param (
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[Alias('p')]
[string]
$Path
$Path,

[switch]
[Alias('l')]
$Literal
)

# only attach files from public/static-route directories
$Path = Get-PodeStaticRoutePath -Route $Path
# only attach files from public/static-route directories when path is relative
if (!$Literal) {
$Path = (Get-PodeStaticRoutePath -Route $Path).Path
}

# test the file path, and set status accordingly
if (!(Test-PodePath $Path)) {
Expand All @@ -161,24 +166,27 @@ function Attach
$filename = Get-PodeFileName -Path $Path
$ext = Get-PodeFileExtension -Path $Path -TrimPeriod

# open up the file as a stream
$fs = (Get-Item $Path).OpenRead()
try {
# open up the file as a stream
$fs = (Get-Item $Path).OpenRead()

# setup the response details and headers
$WebEvent.Response.ContentLength64 = $fs.Length
$WebEvent.Response.SendChunked = $false
$WebEvent.Response.ContentType = (Get-PodeContentType -Extension $ext)
$WebEvent.Response.AddHeader('Content-Disposition', "attachment; filename=$($filename)")
# setup the response details and headers
$WebEvent.Response.ContentLength64 = $fs.Length
$WebEvent.Response.SendChunked = $false
$WebEvent.Response.ContentType = (Get-PodeContentType -Extension $ext)
$WebEvent.Response.AddHeader('Content-Disposition', "attachment; filename=$($filename)")

# set file as an attachment on the response
$buffer = [byte[]]::new(64 * 1024)
$read = 0
# set file as an attachment on the response
$buffer = [byte[]]::new(64 * 1024)
$read = 0

while (($read = $fs.Read($buffer, 0, $buffer.Length)) -gt 0) {
$WebEvent.Response.OutputStream.Write($buffer, 0, $read)
while (($read = $fs.Read($buffer, 0, $buffer.Length)) -gt 0) {
$WebEvent.Response.OutputStream.Write($buffer, 0, $read)
}
}
finally {
dispose $fs
}

dispose $fs
}

function Save
Expand Down
38 changes: 29 additions & 9 deletions src/Tools/Routes.ps1
Expand Up @@ -77,6 +77,7 @@ function Get-PodeRoute
'Defaults' = $found.Defaults;
'Protocol' = $found.Protocol;
'Endpoint' = $found.Endpoint;
'Download' = $found.Download;
'File' = $Matches['file'];
}
}
Expand Down Expand Up @@ -113,11 +114,19 @@ function Get-PodeStaticRoutePath

# attempt to get a static route for the path
$found = Get-PodeRoute -HttpMethod 'static' -Route $Route -Protocol $Protocol -Endpoint $Endpoint
$path = $null
$download = $false

# if we have a defined static route, use that
if ($null -ne $found) {
# is the found route set as download only?
if ($found.Download) {
$download = $true
$path = (Join-Path $found.Path (coalesce $found.File ([string]::Empty)))
}

# if there's no file, we need to check defaults
if (!(Test-PodePathIsFile $found.File) -and (Get-PodeCount @($found.Defaults)) -gt 0)
elseif (!(Test-PodePathIsFile $found.File) -and (Get-PodeCount @($found.Defaults)) -gt 0)
{
$found.File = (coalesce $found.File ([string]::Empty))

Expand All @@ -134,16 +143,19 @@ function Get-PodeStaticRoutePath
}
}

return (Join-Path $found.Path $found.File)
$path = (Join-Path $found.Path $found.File)
}

# else, use the public static directory (but only if path is a file, and a public dir is present)
if ((Test-PodePathIsFile $Route) -and !(Test-Empty $PodeContext.Server.InbuiltDrives['public'])) {
return (Join-Path $PodeContext.Server.InbuiltDrives['public'] $Route)
elseif ((Test-PodePathIsFile $Route) -and !(Test-Empty $PodeContext.Server.InbuiltDrives['public'])) {
$path = (Join-Path $PodeContext.Server.InbuiltDrives['public'] $Route)
}

# otherwise, just return null
return $null
# return the route details
return @{
'Path' = $path;
'Download' = $download;
}
}

function Get-PodeRouteByUrl
Expand Down Expand Up @@ -228,7 +240,11 @@ function Route

[switch]
[Alias('rm')]
$Remove
$Remove,

[switch]
[Alias('do')]
$DownloadOnly
)

# uppercase the method
Expand Down Expand Up @@ -262,7 +278,7 @@ function Route
# add a new dynamic or static route
if ($HttpMethod -ieq 'static') {
Add-PodeStaticRoute -Route $Route -Path ([string](@($Middleware))[0]) -Protocol $Protocol `
-Endpoint $Endpoint -Defaults $Defaults
-Endpoint $Endpoint -Defaults $Defaults -DownloadOnly:$DownloadOnly
}
else {
if ((Get-PodeCount $Defaults) -gt 0) {
Expand Down Expand Up @@ -479,7 +495,10 @@ function Add-PodeStaticRoute

[Parameter()]
[string]
$Endpoint
$Endpoint,

[switch]
$DownloadOnly
)

# store the route method
Expand Down Expand Up @@ -523,6 +542,7 @@ function Add-PodeStaticRoute
'Defaults' = $Defaults;
'Protocol' = $Protocol;
'Endpoint' = $Endpoint.Trim();
'Download' = $DownloadOnly;
})
}

Expand Down
10 changes: 5 additions & 5 deletions tests/unit/Tools/Middleware.Tests.ps1
Expand Up @@ -451,7 +451,7 @@ Describe 'Get-PodePublicMiddleware' {
$r.Name | Should Be '@public'
$r.Logic | Should Not Be $null

Mock Get-PodeStaticRoutePath { return $null }
Mock Get-PodeStaticRoutePath { return @{ 'Path' = $null } }
(. $r.Logic @{
'Path' = '/'; 'Protocol' = 'http'; 'Endpoint' = '';
}) | Should Be $true
Expand All @@ -470,7 +470,7 @@ Describe 'Get-PodePublicMiddleware' {
}}
}}

Mock Get-PodeStaticRoutePath { return '/' }
Mock Get-PodeStaticRoutePath { return @{ 'Path' = '/' } }
Mock File { }
(. $r.Logic @{
'Path' = '/'; 'Protocol' = 'http'; 'Endpoint' = '';
Expand All @@ -491,7 +491,7 @@ Describe 'Get-PodePublicMiddleware' {
}}
}}

Mock Get-PodeStaticRoutePath { return '/' }
Mock Get-PodeStaticRoutePath { return @{ 'Path' = '/' } }
Mock File { }
(. $r.Logic @{
'Path' = '/'; 'Protocol' = 'http'; 'Endpoint' = '';
Expand All @@ -512,7 +512,7 @@ Describe 'Get-PodePublicMiddleware' {
}}
}}

Mock Get-PodeStaticRoutePath { return '/' }
Mock Get-PodeStaticRoutePath { return @{ 'Path' = '/' } }
Mock File { }
(. $r.Logic @{
'Path' = '/'; 'Protocol' = 'http'; 'Endpoint' = '';
Expand All @@ -532,7 +532,7 @@ Describe 'Get-PodePublicMiddleware' {
}}
}}

Mock Get-PodeStaticRoutePath { return '/' }
Mock Get-PodeStaticRoutePath { return @{ 'Path' = '/' } }
Mock File { }
(. $r.Logic @{
'Path' = '/'; 'Protocol' = 'http'; 'Endpoint' = '';
Expand Down

0 comments on commit 7b79583

Please sign in to comment.