summaryrefslogtreecommitdiffstatshomepage
path: root/plugins/weblit
diff options
context:
space:
mode:
author ImJezze <jezze@gmx.net>2016-03-12 12:31:13 +0100
committer ImJezze <jezze@gmx.net>2016-03-12 12:31:13 +0100
commita026a582f1a0ea8c1ede3acaddacef506ef3f3b0 (patch)
treee31573822f2359677de519f9f3b600d98e8764cd /plugins/weblit
parent477d2abd43984f076b7e45f5527591fa8fd0d241 (diff)
parentdcab55bf53b94713a6f72e9633f5101c8dd6c08c (diff)
Merge pull request #15 from mamedev/master
Sync to base master
Diffstat (limited to 'plugins/weblit')
-rw-r--r--plugins/weblit/LICENSE22
-rw-r--r--plugins/weblit/README.md239
-rw-r--r--plugins/weblit/app.lua261
-rw-r--r--plugins/weblit/auto-headers.lua92
-rw-r--r--plugins/weblit/etag-cache.lua39
-rw-r--r--plugins/weblit/init.lua8
-rw-r--r--plugins/weblit/logger.lua10
-rw-r--r--plugins/weblit/plugin.json8
-rw-r--r--plugins/weblit/static.lua62
-rw-r--r--plugins/weblit/websocket.lua82
10 files changed, 0 insertions, 823 deletions
diff --git a/plugins/weblit/LICENSE b/plugins/weblit/LICENSE
deleted file mode 100644
index 5789b767285..00000000000
--- a/plugins/weblit/LICENSE
+++ /dev/null
@@ -1,22 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2015 Tim Caswell
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
diff --git a/plugins/weblit/README.md b/plugins/weblit/README.md
deleted file mode 100644
index 55d6085d22b..00000000000
--- a/plugins/weblit/README.md
+++ /dev/null
@@ -1,239 +0,0 @@
-# weblit
-
-A web framework for luv (ported from luvit/lit)
-
-Weblit is a collection of lit packages that together form a nice web framework.
-
-## weblit/app
-
-This is the core of the framework. It's export value is the app itself. The
-config functions can be chained off this config for super terse syntax.
-
-```lua
-require('weblit/app')
-
- .bind({
- host = "0.0.0.0",
- port = 8080
- })
-
- .use(require('weblit/logger'))
- .use(require('weblit/auto-headers'))
- .use(require('weblit/etag-cache'))
-
- .route({
- method = "GET",
- path = "/do/:user/:action",
- domain = "*.myapp.io"
- }, function (req, res, go)
- -- Handle route
- end)
-
- .start()
-
-```
-
-### bind(options)
-
-Use this to configure your server. You can bind to multiple addresses and
-ports. For example, the same server can listen on port `8080` using normal HTTP
-while also listening on port `8443` using HTTPS.
-
-```lua
--- Listen on port 8080 internally using plain HTTP.
-.bind({
- host = "127.0.0.1",
- port = 8080
-})
-
--- Also listen on port 8443 externally using encrypted HTTPS.
-.bind({
- host = "0.0.0.0",
- port = 8443,
- tls = {
- cert = module:load("cert.pem"),
- key = module:load("key.pem",
- }
-})
-```
-
-The `host` option defaults to `"127.0.0.1"`. The default port depends on if
-you're running as root and if the connection is TLS encrypted.
-
- | Root | User
-------|-----:|------:
-HTTP | 80 | 8080
-HTTPS | 442 | 8443
-
-
-### use(middleware)
-
-This adds a raw middleware to the chain. It's signature is:
-
-```lua
-.use(function (req, res, go)
- -- Log the request table
- p("request", req)
- -- Hand off to the next layer.
- return go()
-end)
-```
-
-The `req` table will contain information about the HTTP request. This includes
-several fields:
-
- - `socket` - The raw libuv `uv_tty_t` socket.
- - `method` - The HTTP request method verb like `GET` or `POST`.
- - `path` - The raw HTTP request path (including query string).
- - `headers` - A list of headers. Each header is a table with two entries for
- key and value. For convenience, there are special `__index` and
- `__newindex` metamethods that let you treat this like a case insensitive
- key/value store.
- - `version` - The HTTP version (Usually either `1.0` or `1.1`).
- - `keepAlive` - A flag telling you if this should be a keepalive connection.
- - `body` - The request body as a string. In the future, this may also be a stream.
-
-The `res` table also has some conventions used to form the response a piece at a
-time. Initially it contains:
-
- - `code` - The response status code. Initially contains `404`.
- - `headers` - Another special headers table like in `req`.
- - `body` - The response body to send. Initially contains `"Not Found\n"`.
-
-The `go` function is to be called if you wish to not handle a request. This
-allows other middleware layers to get a chance to respond to the request. Use a
-tail call if there is nothing more to do.
-
-Otherwise do further processing after `go` returns. At this point, all inner
-layers have finished and a response is ready in `res`.
-
-### route(options, middleware)
-
-Route is like use, but allows you to pre-filter the requests before the middleware
-is called.
-
-```lua
-.route({
- method = "PUT",
- path = "/upload/:username"
-}, function (req, res, go)
- local url = saveFile(req.params.username, req.body)
- res.code = 201
- res.headers.Location = url
-end)
-```
-
-The route options accept several parameters:
-
- - `method` - This is a simple filter on a specific HTTP method verb.
- - `path` - This is either an exact match or can contain patterns. Segments
- looking like `:name` will match single path segments while `:name:` will
- match multiple segments. The matches will go into `req.params`. Also any
- query string will be stripped off, parsed out, and stored in `req.query`.
- - `host` - Will filter against the `Host` header. This can be an exact match
- or a glob match like `*.mydomain.org`.
- - `filter` - Filter is a custom lua function that accepts `req` and returns
- `true` or `false`.
-
-If the request matches all the requirements, then the middleware is called the
-same as with `use`.
-
-### start
-
-Bind to the port(s), listen on the socket(s) and start accepting connections.
-
-## weblit/logger
-
-This is a simple middleware that logs the request method, url and user agent.
-It also includes the response status code.
-
-Make sure to use it at the top of your middleware chain so that it's able to see
-the final response code sent to the client.
-
-```lua
-.use(require('weblit/logger'))
-```
-
-## weblit/auto-headers
-
-This implements lots of conventions and useful defaults that help your app
-implement a proper HTTP server.
-
-You should always use this near the top of the list. The only middleware that
-goes before this is the logger.
-
-
-```lua
-.use(require('weblit/auto-headers'))
-```
-
-## weblit/etag-cache
-
-This caches responses in memory keyed by etag. If there is no etag, but there
-is a response body, it will use the body to generate an etag.
-
-Put this in your list after auto-headers, but before custom server logic.
-
-```lua
-.use(require('weblit/etag-cache'))
-```
-
-## weblit/static
-
-This middleware serves static files to the user. Use this to serve your client-
-side web assets.
-
-Usage is pretty simplistic for now.
-
-```lua
-local static = require('weblit/static')
-app.use(static("path/to/static/assets"))
-```
-
-If you want to only match a sub-path, use the router.
-
-```lua
-app.route({
- path = "/blog/:path:"
-}, static(pathJoin(module.dir, "articles")))
-```
-
-The `path` param will be used if it exists and the full path will be used
-otherwise.
-
-## weblit/websocket
-
-This implements a websocket upgrade handler. You can choose the subprotocol and
-other routing information.
-
-```lua
-app.websocket({
- path = "/v2/socket", -- Prefix for matching
- protocol = "virgo/2.0", -- Restrict to a websocket sub-protocol
-}, function (req, read, write)
- -- Log the request headers
- p(req)
- -- Log and echo all messages
- for message in read do
- write(message)
- end
- -- End the stream
- write()
-end)
-```
-
-
-## weblit
-
-This is the metapackage that simply includes the other modules.
-
-It exposes the other modules as a single exports table.
-
-```lua
-exports.app = require('weblit/app')
-exports.autoHeaders = require('weblit/auto-headers')
-exports.etagCache = require('weblit/etag-cache')
-exports.logger = require('weblit/logger')
-exports.static = require('weblit/static')
-exports.websocket = require('weblit/websocket')
-```
diff --git a/plugins/weblit/app.lua b/plugins/weblit/app.lua
deleted file mode 100644
index d3839c1df8e..00000000000
--- a/plugins/weblit/app.lua
+++ /dev/null
@@ -1,261 +0,0 @@
-
-
-local createServer = require('coro-net').createServer
-local wrapper = require('coro-wrapper')
-local readWrap, writeWrap = wrapper.reader, wrapper.writer
-local httpCodec = require('http-codec')
---local tlsWrap = require('coro-tls').wrap
-local parseQuery = require('querystring').parse
-
--- Ignore SIGPIPE if it exists on platform
-local uv = require('luv')
-if uv.constants.SIGPIPE then
- uv.new_signal():start("sigpipe")
-end
-
-local server = {}
-local handlers = {}
-local bindings = {}
-
--- Provide a nice case insensitive interface to headers.
-local headerMeta = {
- __index = function (list, name)
- if type(name) ~= "string" then
- return rawget(list, name)
- end
- name = name:lower()
- for i = 1, #list do
- local key, value = unpack(list[i])
- if key:lower() == name then return value end
- end
- end,
- __newindex = function (list, name, value)
- -- non-string keys go through as-is.
- if type(name) ~= "string" then
- return rawset(list, name, value)
- end
- -- First remove any existing pairs with matching key
- local lowerName = name:lower()
- for i = #list, 1, -1 do
- if list[i][1]:lower() == lowerName then
- table.remove(list, i)
- end
- end
- -- If value is nil, we're done
- if value == nil then return end
- -- Otherwise, set the key(s)
- if (type(value) == "table") then
- -- We accept a table of strings
- for i = 1, #value do
- rawset(list, #list + 1, {name, tostring(value[i])})
- end
- else
- -- Or a single value interperted as string
- rawset(list, #list + 1, {name, tostring(value)})
- end
- end,
-}
-
-local function handleRequest(head, input, socket)
- local req = {
- socket = socket,
- method = head.method,
- path = head.path,
- headers = setmetatable({}, headerMeta),
- version = head.version,
- keepAlive = head.keepAlive,
- body = input
- }
- for i = 1, #head do
- req.headers[i] = head[i]
- end
-
- local res = {
- code = 404,
- headers = setmetatable({}, headerMeta),
- body = "Not Found\n",
- }
-
- local function run(i)
- local success, err = pcall(function ()
- i = i or 1
- local go = i < #handlers
- and function ()
- return run(i + 1)
- end
- or function () end
- return handlers[i](req, res, go)
- end)
- if not success then
- res.code = 500
- res.headers = setmetatable({}, headerMeta)
- res.body = err
- print(err)
- end
- end
- run(1)
-
- local out = {
- code = res.code,
- keepAlive = res.keepAlive,
- }
- for i = 1, #res.headers do
- out[i] = res.headers[i]
- end
- return out, res.body, res.upgrade
-end
-
-local function handleConnection(rawRead, rawWrite, socket)
-
- -- Speak in HTTP events
- local read, updateDecoder = readWrap(rawRead, httpCodec.decoder())
- local write, updateEncoder = writeWrap(rawWrite, httpCodec.encoder())
-
- for head in read do
- local parts = {}
- for chunk in read do
- if #chunk > 0 then
- parts[#parts + 1] = chunk
- else
- break
- end
- end
- local res, body, upgrade = handleRequest(head, #parts > 0 and table.concat(parts) or nil, socket)
- write(res)
- if upgrade then
- return upgrade(read, write, updateDecoder, updateEncoder, socket)
- end
- write(body)
- if not (res.keepAlive and head.keepAlive) then
- break
- end
- end
- write()
-
-end
-
-function server.bind(options)
- if not options.host then
- options.host = "127.0.0.1"
- end
- if not options.port then
- options.port = require('uv').getuid() == 0 and
- (options.tls and 443 or 80) or
- (options.tls and 8443 or 8080)
- end
- bindings[#bindings + 1] = options
- return server
-end
-
-function server.use(handler)
- handlers[#handlers + 1] = handler
- return server
-end
-
-
-function server.start()
- if #bindings == 0 then
- server.bind({})
- end
- for i = 1, #bindings do
- local options = bindings[i]
- createServer(options, function (rawRead, rawWrite, socket)
- --local tls = options.tls
- --if tls then
- --rawRead, rawWrite = tlsWrap(rawRead, rawWrite, {
- -- server = true,
- --key = assert(tls.key, "tls key required"),
- --cert = assert(tls.cert, "tls cert required"),
- --})
- --end
- return handleConnection(rawRead, rawWrite, socket)
- end)
- print("HTTP server listening at http" .. (options.tls and "s" or "") .. "://" .. options.host .. (options.port == (options.tls and 443 or 80) and "" or ":" .. options.port) .. "/")
- end
- return server
-end
-
-local quotepattern = '(['..("%^$().[]*+-?"):gsub("(.)", "%%%1")..'])'
-local function escape(str)
- return str:gsub(quotepattern, "%%%1")
-end
-
-local function compileGlob(glob)
- local parts = {"^"}
- for a, b in glob:gmatch("([^*]*)(%**)") do
- if #a > 0 then
- parts[#parts + 1] = escape(a)
- end
- if #b > 0 then
- parts[#parts + 1] = "(.*)"
- end
- end
- parts[#parts + 1] = "$"
- local pattern = table.concat(parts)
- return function (string)
- return string and string:match(pattern)
- end
-end
-
-local function compileRoute(route)
- local parts = {"^"}
- local names = {}
- for a, b, c, d in route:gmatch("([^:]*):([_%a][_%w]*)(:?)([^:]*)") do
- if #a > 0 then
- parts[#parts + 1] = escape(a)
- end
- if #c > 0 then
- parts[#parts + 1] = "(.*)"
- else
- parts[#parts + 1] = "([^/]*)"
- end
- names[#names + 1] = b
- if #d > 0 then
- parts[#parts + 1] = escape(d)
- end
- end
- if #parts == 1 then
- return function (string)
- if string == route then return {} end
- end
- end
- parts[#parts + 1] = "$"
- local pattern = table.concat(parts)
- return function (string)
- local matches = {string:match(pattern)}
- if #matches > 0 then
- local results = {}
- for i = 1, #matches do
- results[i] = matches[i]
- results[names[i]] = matches[i]
- end
- return results
- end
- end
-end
-
-function server.route(options, handler)
- local method = options.method
- local path = options.path and compileRoute(options.path)
- local host = options.host and compileGlob(options.host)
- local filter = options.filter
- server.use(function (req, res, go)
- if method and req.method ~= method then return go() end
- if host and not host(req.headers.host) then return go() end
- if filter and not filter(req) then return go() end
- local params
- if path then
- local pathname, query = req.path:match("^([^?]*)%??(.*)")
- params = path(pathname)
- if not params then return go() end
- if #query > 0 then
- req.query = parseQuery(query)
- end
- end
- req.params = params or {}
- return handler(req, res, go)
- end)
- return server
-end
-
-return server
diff --git a/plugins/weblit/auto-headers.lua b/plugins/weblit/auto-headers.lua
deleted file mode 100644
index 44ad65779e9..00000000000
--- a/plugins/weblit/auto-headers.lua
+++ /dev/null
@@ -1,92 +0,0 @@
-
-
---[[
-
-Response automatic values:
- - Auto Server header
- - Auto Date Header
- - code defaults to 404 with body "Not Found\n"
- - if there is a string body add Content-Length and ETag if missing
- - if string body and no Content-Type, use text/plain for valid utf-8, application/octet-stream otherwise
- - Auto add "; charset=utf-8" to Content-Type when body is known to be valid utf-8
- - Auto 304 responses for if-none-match requests
- - Auto strip body with HEAD requests
- - Auto chunked encoding if body with unknown length
- - if Connection header set and not keep-alive, set res.keepAlive to false
- - Add Connection Keep-Alive/Close if not found based on res.keepAlive
-
---TODO: utf8 scanning
-
-]]
-
---local digest = require('openssl').digest.digest
-local date = require('os').date
-
-return function (req, res, go)
- local isHead = false
- if req.method == "HEAD" then
- req.method = "GET"
- isHead = true
- end
-
- local requested = req.headers["if-none-match"]
-
- go()
-
- -- We could use the fancy metatable, but this is much faster
- local lowerHeaders = {}
- local headers = res.headers
- for i = 1, #headers do
- local key, value = unpack(headers[i])
- lowerHeaders[key:lower()] = value
- end
-
-
- if not lowerHeaders.server then
- headers[#headers + 1] = {"Server", serverName}
- end
- if not lowerHeaders.date then
- headers[#headers + 1] = {"Date", date("!%a, %d %b %Y %H:%M:%S GMT")}
- end
-
- if not lowerHeaders.connection then
- if req.keepAlive then
- lowerHeaders.connection = "Keep-Alive"
- headers[#headers + 1] = {"Connection", "Keep-Alive"}
- else
- headers[#headers + 1] = {"Connection", "Close"}
- end
- end
- res.keepAlive = lowerHeaders.connection and lowerHeaders.connection:lower() == "keep-alive"
-
- local body = res.body
- if body then
- local needLength = not lowerHeaders["content-length"] and not lowerHeaders["transfer-encoding"]
- if type(body) == "string" then
- if needLength then
- headers[#headers + 1] = {"Content-Length", #body}
- end
- -- if not lowerHeaders.etag then
- -- local etag = '"' .. digest("sha1", body) .. '"'
- -- lowerHeaders.etag = etag
- --headers[#headers + 1] = {"ETag", etag}
- -- end
- else
- if needLength then
- headers[#headers + 1] = {"Transfer-Encoding", "chunked"}
- end
- end
- if not lowerHeaders["content-type"] then
- headers[#headers + 1] = {"Content-Type", "text/plain"}
- end
- end
-
- local etag = lowerHeaders.etag
- if requested and res.code >= 200 and res.code < 300 and requested == etag then
- res.code = 304
- body = nil
- end
-
- if isHead then body = nil end
- res.body = body
-end
diff --git a/plugins/weblit/etag-cache.lua b/plugins/weblit/etag-cache.lua
deleted file mode 100644
index e8c5d149b35..00000000000
--- a/plugins/weblit/etag-cache.lua
+++ /dev/null
@@ -1,39 +0,0 @@
-
-local function clone(headers)
- local copy = setmetatable({}, getmetatable(headers))
- for i = 1, #headers do
- copy[i] = headers[i]
- end
- return copy
-end
-
-local cache = {}
-return function (req, res, go)
- local requested = req.headers["If-None-Match"]
- local host = req.headers.Host
- local key = host and host .. "|" .. req.path or req.path
- local cached = cache[key]
- if not requested and cached then
- req.headers["If-None-Match"] = cached.etag
- end
- go()
- local etag = res.headers.ETag
- if not etag then return end
- if res.code >= 200 and res.code < 300 then
- local body = res.body
- if not body or type(body) == "string" then
- cache[key] = {
- etag = etag,
- code = res.code,
- headers = clone(res.headers),
- body = body
- }
- end
- elseif res.code == 304 then
- if not requested and cached and etag == cached.etag then
- res.code = cached.code
- res.headers = clone(cached.headers)
- res.body = cached.body
- end
- end
-end
diff --git a/plugins/weblit/init.lua b/plugins/weblit/init.lua
deleted file mode 100644
index f9224b7880c..00000000000
--- a/plugins/weblit/init.lua
+++ /dev/null
@@ -1,8 +0,0 @@
-local exports = {}
-exports.app = require('weblit/app')
-exports.autoHeaders = require('weblit/auto-headers')
-exports.etagCache = require('weblit/etag-cache')
-exports.logger = require('weblit/logger')
-exports.static = require('weblit/static')
-exports.websocket = require('weblit/websocket')
-return exports
diff --git a/plugins/weblit/logger.lua b/plugins/weblit/logger.lua
deleted file mode 100644
index 912b4eed768..00000000000
--- a/plugins/weblit/logger.lua
+++ /dev/null
@@ -1,10 +0,0 @@
-
-return function (req, res, go)
- -- Skip this layer for clients who don't send User-Agent headers.
- local userAgent = req.headers["user-agent"]
- if not userAgent then return go() end
- -- Run all inner layers first.
- go()
- -- And then log after everything is done
- --print(string.format("%s %s %s %s", req.method, req.path, userAgent, res.code))
-end
diff --git a/plugins/weblit/plugin.json b/plugins/weblit/plugin.json
deleted file mode 100644
index 69dd45ccc0e..00000000000
--- a/plugins/weblit/plugin.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "plugin": {
- "name": "weblit",
- "version": "1.0.0",
- "author": "Tim Caswell",
- "type": "library",
- }
-} \ No newline at end of file
diff --git a/plugins/weblit/static.lua b/plugins/weblit/static.lua
deleted file mode 100644
index b34ea638fa1..00000000000
--- a/plugins/weblit/static.lua
+++ /dev/null
@@ -1,62 +0,0 @@
-
-local getType = require("mime").getType
-local jsonStringify = require('json').stringify
-
-local makeChroot = require('coro-fs').chroot
-
-return function (rootPath)
-
- local fs = makeChroot(rootPath)
-
- return function (req, res, go)
- if req.method ~= "GET" then return go() end
- local path = (req.params and req.params.path) or req.path
- path = path:match("^[^?#]*")
- if path:byte(1) == 47 then
- path = path:sub(2)
- end
- local stat = fs.stat(path)
- if not stat then return go() end
-
- local function renderFile()
- local body = assert(fs.readFile(path))
- res.code = 200
- res.headers["Content-Type"] = getType(path)
- res.body = body
- return
- end
-
- local function renderDirectory()
- if req.path:byte(-1) ~= 47 then
- res.code = 301
- res.headers.Location = req.path .. '/'
- return
- end
- local files = {}
- for entry in fs.scandir(path) do
- if entry.name == "index.html" and entry.type == "file" then
- path = (#path > 0 and path .. "/" or "") .. "index.html"
- return renderFile()
- end
- files[#files + 1] = entry
- entry.url = "http://" .. req.headers.host .. req.path .. entry.name
- end
- local body = jsonStringify(files) .. "\n"
- res.code = 200
- res.headers["Content-Type"] = "application/json"
- res.body = body
- return
- end
-
- if stat.type == "directory" then
- return renderDirectory()
- elseif stat.type == "file" then
- if req.path:byte(-1) == 47 then
- res.code = 301
- res.headers.Location = req.path:match("^(.*[^/])/+$")
- return
- end
- return renderFile()
- end
- end
-end
diff --git a/plugins/weblit/websocket.lua b/plugins/weblit/websocket.lua
deleted file mode 100644
index d5dfe572ea6..00000000000
--- a/plugins/weblit/websocket.lua
+++ /dev/null
@@ -1,82 +0,0 @@
-
-local websocketCodec = require('websocket-codec')
-
-local function websocketHandler(options, handler)
- return function (req, res, go)
- -- Websocket connections must be GET requests
- -- with 'Upgrade: websocket'
- -- and 'Connection: Upgrade' headers
- local headers = req.headers
- local connection = headers.connection
- local upgrade = headers.upgrade
- if not (
- req.method == "GET" and
- upgrade and upgrade:lower():find("websocket", 1, true) and
- connection and connection:lower():find("upgrade", 1, true)
- ) then
- return go()
- end
-
- if options.filter and not options.filter(req) then
- return go()
- end
-
- -- If there is a sub-protocol specified, filter on it.
- local protocol = options.protocol
- if protocol then
- local list = headers["sec-websocket-protocol"]
- local foundProtocol
- if list then
- for item in list:gmatch("[^, ]+") do
- if item == protocol then
- foundProtocol = true
- break
- end
- end
- end
- if not foundProtocol then
- return go()
- end
- end
-
- -- Make sure it's a new client speaking v13 of the protocol
- assert(tonumber(headers["sec-websocket-version"]) >= 13, "only websocket protocol v13 supported")
-
- -- Get the security key
- local key = assert(headers["sec-websocket-key"], "websocket security required")
-
- res.code = 101
- headers = res.headers
- headers.Upgrade = "websocket"
- headers.Connection = "Upgrade"
- headers["Sec-WebSocket-Accept"] = websocketCodec.acceptKey(key)
- if protocol then
- headers["Sec-WebSocket-Protocol"] = protocol
- end
- function res.upgrade(read, write, updateDecoder, updateEncoder)
- updateDecoder(websocketCodec.decode)
- updateEncoder(websocketCodec.encode)
- local success, err = pcall(handler, req, read, write)
- if not success then
- print(err)
- write({
- opcode = 1,
- payload = err,
- })
- return write()
- end
- end
- end
-end
-
-local server = require('weblit-app')
-function server.websocket(options, handler)
- server.route({
- method = "GET",
- path = options.path,
- host = options.host,
- }, websocketHandler(options, handler))
- return server
-end
-
-return websocketHandler