Skip to content

Commit

Permalink
feat(downloads) add a downloads plugin
Browse files Browse the repository at this point in the history
It can use the same (or different) files from the web root and
will send them as downloads to the browser.

See the example updates.
  • Loading branch information
Tieske committed Feb 22, 2023
1 parent 325e911 commit 5fe93a5
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 5 deletions.
13 changes: 10 additions & 3 deletions example/app.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@ package.path = './src/?.lua;./src/?/init.lua;' .. package.path

local Pegasus = require 'pegasus'
local Compress = require 'pegasus.plugins.compress'
local Downloads = require 'pegasus.plugins.downloads'

local server = Pegasus:new({
port='9090',
location='/example/root/',
plugins = { Compress:new() }
port = '9090',
location = '/example/root/',
plugins = {
Downloads:new {
prefix = "downloads",
stripPrefix = true,
},
Compress:new(),
}
})

server:start(function(req)
Expand Down
8 changes: 7 additions & 1 deletion example/copas.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ package.path = "./src/?.lua;./src/?/init.lua;"..package.path
local Handler = require 'pegasus.handler'
local copas = require('copas')
local socket = require('socket')
local Downloads = require 'pegasus.plugins.downloads'

--- Creates a new server within the Copas scheduler.
-- @tparam table opts options table.
Expand Down Expand Up @@ -81,7 +82,12 @@ assert(newPegasusServer{
},
location = '/example/root/',
callback = nil,
plugins = {},
plugins = {
Downloads:new {
prefix = "downloads",
stripPrefix = true,
},
},
})

-- Start
Expand Down
4 changes: 3 additions & 1 deletion example/root/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
<link href="style.css" media="all" rel="stylesheet">
</head>
<body>
<img src="1.jpg">
<a href="downloads/1.jpg">
<img src="1.jpg" />
</a><p>Click the image to download it!</p>
<form method="POST">
Name: <input type="text" name="name">
Age: <input type="text" name="age">
Expand Down
1 change: 1 addition & 0 deletions rockspecs/pegasus-dev-1.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@ build = {
['pegasus.response'] = 'src/pegasus/response.lua',
['pegasus.compress'] = 'src/pegasus/compress.lua',
['pegasus.plugins.compress'] = 'src/pegasus/plugins/compress.lua',
['pegasus.plugins.downloads'] = 'src/pegasus/plugins/downloads.lua'
}
}
63 changes: 63 additions & 0 deletions src/pegasus/plugins/downloads.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
--- A plugin that allows to download files via a browser.
local Downloads = {}
Downloads.__index = Downloads

--- Creates a new plugin instance.
-- The plugin will only respond to `GET` requests. The files will be served from the
-- same `location` setting as defined in the `Handler`. The `prefix` is a virtual folder
-- that triggers the plugin, but will be removed from the filepath if `stripPrefix` is truthy.
-- If `stripPrefix` is falsy, then it should be a real folder.
-- @tparam options table the options table with the following fields;
-- @tparam[opt="downloads/"] options.prefix string the path prefix that triggers the plugin
-- @tparam options.stripPrefix bool whether to strip the prefix from the file path when looking
-- for the file in the filesystem. Defaults to `false`, unless `options.prefix` is omitted,
-- then it defaults to `true`.
function Downloads:new(options)
options = options or {}
self = {}

if not options.prefix then
self.prefix = "downloads/"
if options.stripPrefix == nil then
self.stripPrefix = true
else
self.stripPrefix = not not options.stripPrefix
end
else
self.prefix = options.prefix
self.stripPrefix = not not options.stripPrefix
end

self.prefix = "/" .. self.prefix .. "/"
while self.prefix:find("//") do
self.prefix = self.prefix:gsub("//", "/")
end

setmetatable(self, Downloads)

return self
end

function Downloads:newRequestResponse(request, response)
local stop = false
if request:method() ~= "GET" then
return stop -- we only handle GET requests
end

local path = request:path()
if path:find(self.prefix, nil, true) ~= 1 then
return stop -- doesn't match our prefix
end

local location = response._writeHandler.location or ""
local filename = path
if self.stripPrefix then
filename = path:sub(#self.prefix + 1, -1)
end

stop = not response:sendFile('.' .. location .. filename)
return stop
end


return Downloads

0 comments on commit 5fe93a5

Please sign in to comment.