Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 0x4A6F-master
  • 0x4A6F-rpi4
  • autinerd/experimental-openwrt-24.10
  • experimental
  • feature/addMikrotikwAP
  • master
  • nrb/airmax-test
  • nrb/ar9344-reset-sequence
  • nrb/ex400-remove-wps
  • nrb/gluon-master-cpe510
  • nrb/test-radv-filter
  • nrbffs/fastd-remove-delay
  • nrbffs/netgear-ex6120
  • v2018.2.2-ffs
  • v2018.2.3-ffs
  • v2019.1-ffs
  • v2019.1.1-ffs
  • v2019.1.2-ffs
  • v2020.1-ffs
  • v2020.1.1-ffs
  • v2020.1.3-ffs
  • v2020.2-ffs
  • v2020.2.1-ffs
  • v2020.2.2-ffs
  • v2020.2.3-ffs
  • v2021.1-ffs
  • v2021.1.1-ffs
  • v2021.1.2-ffs
  • v2022.1.1-ffs
  • v2022.1.3-ffs
  • v2022.1.4-ffs
  • v2023.1-ffs
  • v2023.2-ffs
  • v2023.2.2-ffs
  • v2023.2.3-ffs
  • v2023.2.4-ffs
  • v2023.2.5-ffs
  • experimental-2022-09-24
  • experimental-2022-09-24-base
  • experimental-2023-03-11
  • experimental-2023-03-11-base
  • experimental-2023-03-12
  • experimental-2023-03-12-base
  • experimental-2023-03-16
  • experimental-2023-03-16-base
  • experimental-2023-03-20
  • experimental-2023-03-20-base
  • experimental-2023-03-23
  • experimental-2023-03-23-base
  • experimental-2023-03-25
  • experimental-2023-03-25-base
  • experimental-2023-03-26
  • experimental-2023-03-26-base
  • experimental-2023-03-30
  • experimental-2023-03-30-base
  • experimental-2023-03-31
  • experimental-2023-03-31-base
  • experimental-2023-04-01
  • experimental-2023-04-01-base
  • experimental-2023-04-08
  • experimental-2023-04-08-base
  • experimental-2023-04-10
  • experimental-2023-04-10-base
  • experimental-2023-04-13
  • experimental-2023-04-13-base
  • experimental-2023-04-15
  • experimental-2023-04-15-base
  • experimental-2023-04-16
  • experimental-2023-04-16-base
  • experimental-2023-04-18
  • experimental-2023-04-18-base
  • experimental-2023-04-20
  • experimental-2023-04-20-base
  • experimental-2023-04-26
  • experimental-2023-04-26-base
  • experimental-2023-04-28
  • experimental-2023-04-28-base
  • experimental-2023-04-30
  • experimental-2023-04-30-base
  • experimental-2023-05-02
  • experimental-2023-05-02-base
  • experimental-2023-05-03
  • experimental-2023-05-03-base
  • experimental-2023-05-12
  • experimental-2023-05-12-base
  • experimental-2023-05-21
  • experimental-2023-05-21-base
  • experimental-2023-05-25
  • experimental-2023-05-25-base
  • experimental-2023-07-02
  • experimental-2023-07-02-base
  • experimental-2023-07-04
  • experimental-2023-07-04-base
  • experimental-2023-07-12
  • experimental-2023-07-12-base
  • experimental-2023-07-16
  • experimental-2023-07-16-base
  • experimental-2023-08-04
  • experimental-2023-08-04-base
  • experimental-2023-08-10
  • experimental-2023-08-10-base
  • experimental-2023-09-08
  • experimental-2023-09-08-base
  • experimental-2023-09-09
  • experimental-2023-09-09-base
  • experimental-2023-09-10
  • experimental-2023-09-10-base
  • experimental-2023-09-11
  • experimental-2023-09-11-base
  • experimental-2023-09-12
  • experimental-2023-09-12-base
  • experimental-2023-09-13
  • experimental-2023-09-13-base
  • experimental-2023-09-15
  • experimental-2023-09-15-base
  • experimental-2023-09-16
  • experimental-2023-09-16-base
  • experimental-2023-09-18
  • experimental-2023-09-18-base
  • experimental-2023-09-20
  • experimental-2023-09-20-base
  • experimental-2023-09-27
  • experimental-2023-09-27-base
  • experimental-2023-09-28
  • experimental-2023-09-28-base
  • experimental-2023-09-29
  • experimental-2023-09-29-base
  • experimental-2023-10-02
  • experimental-2023-10-02-base
  • experimental-2023-10-13
  • experimental-2023-10-13-base
  • experimental-2023-10-14
  • experimental-2023-10-14-base
  • experimental-2023-10-16
  • experimental-2023-10-16-base
  • experimental-2023-10-23
  • experimental-2023-10-23-base
137 results

Target

Select target project
  • firmware/gluon
  • 0x4A6F/gluon
  • patrick/gluon
3 results
Select Git revision
  • 0x4A6F-master
  • 0x4A6F-rpi4
  • 2014.3.x
  • 2014.4.x
  • babel
  • hoodselector
  • master
  • radv-filterd
  • v2015.1.x
  • v2016.1.x
  • v2016.2.4-batmanbug
  • v2016.2.x
  • v2018.2.2-ffs
  • v2018.2.x
  • v2014.1
  • v2014.2
  • v2014.3
  • v2014.3.1
  • v2014.4
  • v2015.1
  • v2015.1.1
  • v2015.1.2
  • v2016.1
  • v2016.1.1
  • v2016.1.2
  • v2016.1.3
  • v2016.1.4
  • v2016.1.5
  • v2016.1.6
  • v2016.2
  • v2016.2.1
  • v2016.2.2
  • v2016.2.3
  • v2016.2.4
  • v2016.2.5
  • v2016.2.6
  • v2016.2.7
  • v2017.1
  • v2017.1.1
  • v2017.1.2
  • v2017.1.3
  • v2017.1.4
  • v2017.1.5
  • v2017.1.6
  • v2017.1.7
  • v2017.1.8
  • v2018.1
  • v2018.1.1
  • v2018.1.2
  • v2018.1.3
  • v2018.1.4
  • v2018.2
  • v2018.2-ffs0.1
  • v2018.2.1
  • v2018.2.1-ffs0.1
  • v2018.2.2-ffs0.1
56 results
Show changes
Showing
with 569 additions and 135 deletions
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Project-Id-Version: PACKAGE VERSION\n"
"PO-Revision-Date: 2015-08-19 23:30+0100\n"
"Last-Translator:Tobias Bernot <tqbs@airmail.cc>\n"
"Language-Team: French\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgid "(default)"
msgstr "(défaut)"
......@@ -18,14 +19,28 @@ msgstr "2,4GHz Wi-Fi"
msgid "5GHz WLAN"
msgstr "5GHz Wi-Fi"
msgid ""
"Configuring the node for outdoor use tunes the 5 GHz radio to a frequency "
"and transmission power that conforms with the local regulatory requirements. "
"It also enables dynamic frequency selection (DFS; radar detection). At the "
"same time, mesh functionality is disabled as it requires neighbouring nodes "
"to stay on the same channel permanently."
msgstr ""
msgid "Enable client network (access point)"
msgstr "Activer le réseau client (Access Point)"
msgid "Enable mesh network (802.11s)"
msgstr "Activer le réseau MESH (802.11s)"
msgid "Enable mesh network (IBSS)"
msgstr "Activer le réseau MESH (IBSS)"
msgid "HT Mode"
msgstr "Mode HT"
msgid "Node will be installed outdoors"
msgstr ""
msgid "Outdoor Installation"
msgstr "Installation extérieure"
msgid "Transmission power"
msgstr "Puissance d'émission"
......@@ -36,13 +51,14 @@ msgstr "Wi-Fi"
msgid ""
"You can enable or disable your node's client and mesh network SSIDs here. "
"Please don't disable the mesh network without a good reason, so other nodes "
"can mesh with yours.<br /><br />It is also possible to configure the WLAN "
"can mesh with yours.<br><br>It is also possible to configure the WLAN "
"adapters transmission power here. Please note that the transmission power "
"values include the antenna gain where available, but there are many devices "
"for which the gain is unavailable or inaccurate."
msgstr ""
"Ici vous pouvez activer ou désactiver la SSID du client ou MESH. "
"Pensez a laisser la SSID du MESH activée pour que les autres nœuds puissent se connecter. "
"<br /><br />Ici vous pouvez aussi configurer la puissance d'émmission se votre Wi-Fi. "
"Prenez note que les valeurs fournies pour la puissance de transmission prennent "
"en compte les gains fournis par l'antenne, et que ces valeurs ne sont pas toujours disponibles ou exactes."
"Ici vous pouvez activer ou désactiver la SSID du client ou MESH. Pensez a "
"laisser la SSID du MESH activée pour que les autres nœuds puissent se "
"connecter. <br><br>Ici vous pouvez aussi configurer la puissance "
"d'émmission se votre Wi-Fi. Prenez note que les valeurs fournies pour la "
"puissance de transmission prennent en compte les gains fournis par "
"l'antenne, et que ces valeurs ne sont pas toujours disponibles ou exactes."
......@@ -10,13 +10,27 @@ msgstr ""
msgid "5GHz WLAN"
msgstr ""
msgid ""
"Configuring the node for outdoor use tunes the 5 GHz radio to a frequency "
"and transmission power that conforms with the local regulatory requirements. "
"It also enables dynamic frequency selection (DFS; radar detection). At the "
"same time, mesh functionality is disabled as it requires neighbouring nodes "
"to stay on the same channel permanently."
msgstr ""
msgid "Enable client network (access point)"
msgstr ""
msgid "Enable mesh network (802.11s)"
msgstr ""
msgid "Enable mesh network (IBSS)"
msgid "HT Mode"
msgstr ""
msgid "Node will be installed outdoors"
msgstr ""
msgid "Outdoor Installation"
msgstr ""
msgid "Transmission power"
......@@ -28,7 +42,7 @@ msgstr ""
msgid ""
"You can enable or disable your node's client and mesh network SSIDs here. "
"Please don't disable the mesh network without a good reason, so other nodes "
"can mesh with yours.<br /><br />It is also possible to configure the WLAN "
"can mesh with yours.<br><br>It is also possible to configure the WLAN "
"adapters transmission power here. Please note that the transmission power "
"values include the antenna gain where available, but there are many devices "
"for which the gain is unavailable or inaccurate."
......
local uci = require("simple-uci").cursor()
local wireless = require 'gluon.wireless'
package 'gluon-web-wifi-config'
if wireless.device_uses_wlan(uci) then
entry({"admin", "wifi-config"}, model("admin/wifi-config"), _("WLAN"), 20)
end
local iwinfo = require 'iwinfo'
local uci = require("simple-uci").cursor()
local util = require 'gluon.util'
local site = require 'gluon.site'
local wireless = require 'gluon.wireless'
local function txpower_list(phy)
......@@ -8,7 +9,6 @@ local function txpower_list(phy)
local off = tonumber(iwinfo.nl80211.txpower_offset(phy)) or 0
local new = { }
local prev = -1
local _, val
for _, val in ipairs(list) do
local dbm = val.dbm + off
local mw = math.floor(10 ^ (dbm / 10))
......@@ -24,26 +24,30 @@ local function txpower_list(phy)
return new
end
local f = Form(translate("WLAN"))
f:section(Section, nil, translate(
"You can enable or disable your node's client and mesh network "
.. "SSIDs here. Please don't disable the mesh network without "
.. "a good reason, so other nodes can mesh with yours.<br /><br />"
.. "a good reason, so other nodes can mesh with yours.<br><br>"
.. "It is also possible to configure the WLAN adapters transmission power "
.. "here. Please note that the transmission power values include the antenna gain "
.. "where available, but there are many devices for which the gain is unavailable or inaccurate."
))
local mesh_vifs_5ghz = {}
uci:foreach('wireless', 'wifi-device', function(config)
local radio = config['.name']
local is_5ghz = false
local title
if config.hwmode == '11g' or config.hwmode == '11ng' then
if config.band == '2g' then
title = translate("2.4GHz WLAN")
elseif config.hwmode == '11a' or config.hwmode == '11na' then
elseif config.band == '5g' then
is_5ghz = true
title = translate("5GHz WLAN")
else
return
......@@ -51,24 +55,52 @@ uci:foreach('wireless', 'wifi-device', function(config)
local p = f:section(Section, title)
local function vif_option(t, msg)
if not uci:get('wireless', t .. '_' .. radio) then
local function filter_existing_interfaces(interfaces)
local out = {}
for _, interface in ipairs(interfaces) do
if uci:get('wireless', interface .. '_' .. radio) then
table.insert(out, interface)
end
end
return out
end
local function has_active_interfaces(interfaces)
for _, interface in ipairs(interfaces) do
if not uci:get_bool('wireless', interface .. '_' .. radio, 'disabled') then
return true
end
end
return false
end
local function vif_option(name, interfaces, msg)
local existing_interfaces = filter_existing_interfaces(interfaces)
if #existing_interfaces == 0 then
return
end
local o = p:option(Flag, radio .. '_' .. t .. '_enabled', msg)
o.default = not uci:get_bool('wireless', t .. '_' .. radio, 'disabled')
local o = p:option(Flag, radio .. '_' .. name .. '_enabled', msg)
o.default = has_active_interfaces(existing_interfaces)
function o:write(data)
uci:set('wireless', t .. '_' .. radio, 'disabled', not data)
for _, interface in ipairs(existing_interfaces) do
uci:set('wireless', interface .. '_' .. radio, 'disabled', not data)
end
end
return o
end
vif_option('client', translate('Enable client network (access point)'))
vif_option('mesh', translate("Enable mesh network (802.11s)"))
vif_option('ibss', translate("Enable mesh network (IBSS)"))
vif_option('client', {'client', 'owe'}, translate('Enable client network (access point)'))
local phy = util.find_phy(config)
local mesh_vif = vif_option('mesh', {'mesh'}, translate("Enable mesh network (802.11s)"))
if is_5ghz then
table.insert(mesh_vifs_5ghz, mesh_vif)
end
local phy = wireless.find_phy(config)
if not phy then
return
end
......@@ -97,7 +129,65 @@ uci:foreach('wireless', 'wifi-device', function(config)
end
end)
if wireless.device_uses_11a(uci) and not wireless.preserve_channels(uci) then
local r = f:section(Section, translate("Outdoor Installation"), translate(
"Configuring the node for outdoor use tunes the 5 GHz radio to a frequency "
.. "and transmission power that conforms with the local regulatory requirements. "
.. "It also enables dynamic frequency selection (DFS; radar detection). At the "
.. "same time, mesh functionality is disabled as it requires neighbouring nodes "
.. "to stay on the same channel permanently."
))
local outdoor = r:option(Flag, 'outdoor', translate("Node will be installed outdoors"))
outdoor.default = uci:get_bool('gluon', 'wireless', 'outdoor')
for _, mesh_vif in ipairs(mesh_vifs_5ghz) do
mesh_vif:depends(outdoor, false)
if outdoor.default then
mesh_vif.default = not site.wifi5.mesh.disabled(false)
end
end
function outdoor:write(data)
uci:set('gluon', 'wireless', 'outdoor', data)
end
uci:foreach('wireless', 'wifi-device', function(config)
local radio = config['.name']
local band = uci:get('wireless', radio, 'band')
if band ~= '5g' then
return
end
local phy = wireless.find_phy(config)
local ht = r:option(ListValue, 'outdoor_htmode', translate('HT Mode') .. ' (' .. radio .. ')')
ht:depends(outdoor, true)
ht.default = uci:get('gluon', 'wireless', 'outdoor_' .. radio .. '_htmode') or 'default'
ht:value('default', translate("(default)"))
for mode, available in pairs(iwinfo.nl80211.htmodelist(phy)) do
if available then
ht:value(mode, mode)
end
end
function ht:write(data)
if data == 'default' then
data = nil
end
uci:set('gluon', 'wireless', 'outdoor_' .. radio .. '_htmode', data)
end
end)
end
function f:write()
uci:commit('gluon')
os.execute('/lib/gluon/upgrade/200-wireless')
uci:commit('network')
uci:commit('wireless')
end
......
include $(TOPDIR)/rules.mk
PKG_NAME:=gluon-web
PKG_VERSION:=1
PKG_INSTALL:=1
include ../gluon.mk
include $(INCLUDE_DIR)/host-build.mk
define Package/gluon-web
TITLE:=Minimal Lua web framework derived from LuCI
......@@ -24,4 +24,18 @@ define Package/gluon-web/config
$(foreach lang,$(GLUON_SUPPORTED_LANGS),$(call lang-config,$(lang)))
endef
define Host/Prepare
$(CP) ./src/* $(HOST_BUILD_DIR)
endef
define Host/Compile
$(call Host/Compile/Default,gluon-po2lmo)
endef
define Host/Install
$(INSTALL_DIR) $(1)/bin
$(INSTALL_BIN) $(HOST_BUILD_DIR)/gluon-po2lmo $(1)/bin/
endef
$(eval $(call BuildPackageGluon,gluon-web))
$(eval $(call HostBuild))
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
SPDX-FileCopyrightText: 2008 Steven Barth <steven@midlink.org>
SPDX-FileCopyrightText: 2008 Jo-Philipp Wich <jow@openwrt.org>
SPDX-License-Identifier: Apache-2.0
-%>
<h2 name="content">404 <%:Not Found%></h2>
......
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
SPDX-FileCopyrightText: 2008 Steven Barth <steven@midlink.org>
SPDX-FileCopyrightText: 2008 Jo-Philipp Wich <jow@openwrt.org>
SPDX-License-Identifier: Apache-2.0
-%>
<h2 name="content">500 <%:Internal Server Error%></h2>
......
......@@ -17,7 +17,7 @@ msgid "Not Found"
msgstr "Nicht Gefunden"
msgid "Sorry, the object you requested was not found."
msgstr "Entschuldigung, das anfgeforderte Objekt wurde nicht gefunden."
msgstr "Entschuldigung, das angeforderte Objekt wurde nicht gefunden."
msgid "Sorry, the server encountered an unexpected error."
msgstr ""
......
......@@ -87,6 +87,7 @@ local function dispatch(config, http, request)
pcdata = util.pcdata,
urlencode = proto.urlencode,
attr = attr,
json = json.stringify,
url = function(path) return build_url(http, path) end,
}, { __index = _G }))
......@@ -108,8 +109,8 @@ local function dispatch(config, http, request)
return _node({...})
end,
entry = function(path, target, title, order)
local c = _node(path, true)
entry = function(entry_path, target, title, order)
local c = _node(entry_path, true)
c.target = target
c.title = title
......@@ -158,10 +159,10 @@ local function dispatch(config, http, request)
ctl()
end
for _, path in ipairs(glob.glob(base .. "*.lua") or {}) do
for _, path in ipairs(glob.glob(base .. "*.lua", 0) or {}) do
load_ctl(path)
end
for _, path in ipairs(glob.glob(base .. "*/*.lua") or {}) do
for _, path in ipairs(glob.glob(base .. "*/*.lua", 0) or {}) do
load_ctl(path)
end
end
......@@ -183,9 +184,15 @@ local function dispatch(config, http, request)
return
end
http:parse_input(node.filehandler)
local ok, err = pcall(http.parse_input, http, node.filehandler)
if not ok then
http:status(400, "Bad request")
http:prepare_content("text/plain")
http:write(err .. "\r\n")
return
end
local ok, err = pcall(node.target)
ok, err = pcall(node.target)
if not ok then
http:status(500, "Internal Server Error")
renderer.render_layout("error/500", {
......@@ -203,10 +210,10 @@ return function(config, http)
table.insert(request, node)
end
ok, err = pcall(dispatch, config, http, request)
local ok, err = pcall(dispatch, config, http, request)
if not ok then
http:status(500, "Internal Server Error")
http:prepare_content("text/plain")
http:write(err)
http:write(err .. "\r\n")
end
end
......@@ -2,17 +2,15 @@
-- Copyright 2017 Matthias Schiffer <mschiffer@universe-factory.net>
-- Licensed to the public under the Apache License 2.0.
local string = string
local table = table
local protocol = require "gluon.web.http.protocol"
local util = require "gluon.web.util"
local ipairs, pairs, tostring = ipairs, pairs, tostring
module "gluon.web.http"
local M = {}
local Http = util.class()
M.Http = Http
Http = util.class()
function Http:__init__(env, input, output)
self.input = input
self.output = output
......@@ -55,8 +53,8 @@ end
function Http:getcookie(name)
local c = string.gsub(";" .. (self:getenv("HTTP_COOKIE") or "") .. ";", "%s*;%s*", ";")
local p = ";" .. name .. "=(.-);"
local i, j, value = c:find(p)
return value and urldecode(value)
local _, _, value = c:find(p)
return value and protocol.urldecode(value)
end
function Http:getenv(name)
......@@ -80,13 +78,6 @@ end
function Http:prepare_content(mime)
if self.headers["content-type"] then return end
if mime == "application/xhtml+xml" then
local accept = self:getenv("HTTP_ACCEPT")
if not accept or not accept:find("application/xhtml+xml", nil, true) then
mime = "text/html; charset=UTF-8"
end
self:header("Vary", "Accept")
end
self:header("Content-Type", mime)
end
......@@ -120,3 +111,5 @@ function Http:redirect(url)
self:header("Location", url)
self:close()
end
return M
......@@ -3,12 +3,9 @@
-- Licensed to the public under the Apache License 2.0.
-- This class contains several functions useful for http message- and content
-- decoding and to retrive form data from raw http messages.
module("gluon.web.http.protocol", package.seeall)
HTTP_MAX_CONTENT = 1024*8 -- 8 kB maximum content size
-- decoding and to retrieve form data from raw http messages.
local M = {}
local function pump(src, snk)
while true do
......@@ -26,7 +23,7 @@ local function pump(src, snk)
end
end
function urlencode(s)
function M.urlencode(s)
return (string.gsub(s, '[^a-zA-Z0-9%-_%.~]',
function(c)
local ret = ''
......@@ -41,7 +38,7 @@ function urlencode(s)
end
-- the "+" sign to " " - and return the decoded string.
function urldecode(str, no_plus)
function M.urldecode(str, no_plus)
local function chrdec(hex)
return string.char(tonumber(hex, 16))
......@@ -75,7 +72,7 @@ end
-- Simple parameters are stored as string values associated with the parameter
-- name within the table. Parameters with multiple values are stored as array
-- containing the corresponding values.
function urldecode_params(url)
function M.urldecode_params(url)
local params = {}
if url:find("?") then
......@@ -85,8 +82,8 @@ function urldecode_params(url)
for pair in url:gmatch("[^&;]+") do
-- find key and value
local key = urldecode(pair:match("^([^=]+)"))
local val = urldecode(pair:match("^[^=]+=(.+)$"))
local key = M.urldecode(pair:match("^([^=]+)"))
local val = M.urldecode(pair:match("^[^=]+=(.+)$"))
-- store
if key and key:len() > 0 then
......@@ -101,39 +98,34 @@ function urldecode_params(url)
end
-- Content-Type. Stores all extracted data associated with its parameter name
-- in the params table withing the given message object. Multiple parameter
-- in the params table within the given message object. Multiple parameter
-- values are stored as tables, ordinary ones as strings.
-- If an optional file callback function is given then it is feeded with the
-- If an optional file callback function is given then it is fed with the
-- file contents chunk by chunk and only the extracted file name is stored
-- within the params table. The callback function will be called subsequently
-- with three arguments:
-- o Table containing decoded (name, file) and raw (headers) mime header data
-- o String value containing a chunk of the file data
-- o Boolean which indicates wheather the current chunk is the last one (eof)
function mimedecode_message_body(src, msg, filecb)
if msg and msg.env.CONTENT_TYPE then
msg.mime_boundary = msg.env.CONTENT_TYPE:match("^multipart/form%-data; boundary=(.+)$")
-- o Boolean which indicates whether the current chunk is the last one (eof)
local function mimedecode_message_body(src, msg, filecb)
local mime_boundary = (msg.env.CONTENT_TYPE or ''):match("^multipart/form%-data; boundary=(.+)$")
if not mime_boundary then
error("Invalid Content-Type found")
end
if not msg.mime_boundary then
return nil, "Invalid Content-Type found"
end
local tlen = 0
local inhdr = false
local field = nil
local store = nil
local lchunk = nil
local function parse_headers(chunk, field)
local function parse_headers(chunk, pfield)
local stat
repeat
chunk, stat = chunk:gsub(
"^([A-Z][A-Za-z0-9%-_]+): +([^\r\n]+)\r\n",
function(k,v)
field.headers[k] = v
pfield.headers[k] = v
return ""
end
)
......@@ -143,26 +135,26 @@ function mimedecode_message_body(src, msg, filecb)
-- End of headers
if stat > 0 then
if field.headers["Content-Disposition"] then
if field.headers["Content-Disposition"]:match("^form%-data; ") then
field.name = field.headers["Content-Disposition"]:match('name="(.-)"')
field.file = field.headers["Content-Disposition"]:match('filename="(.+)"$')
if pfield.headers["Content-Disposition"] then
if pfield.headers["Content-Disposition"]:match("^form%-data; ") then
pfield.name = pfield.headers["Content-Disposition"]:match('name="(.-)"')
pfield.file = pfield.headers["Content-Disposition"]:match('filename="(.+)"$')
end
end
if not field.headers["Content-Type"] then
field.headers["Content-Type"] = "text/plain"
if not pfield.headers["Content-Type"] then
pfield.headers["Content-Type"] = "text/plain"
end
if field.name then
initval(msg.params, field.name)
if field.file then
appendval(msg.params, field.name, field.file)
if pfield.name then
initval(msg.params, pfield.name)
if pfield.file then
appendval(msg.params, pfield.name, pfield.file)
store = filecb
else
store = function(hdr, buf, eof)
appendval(msg.params, field.name, buf)
store = function(_, buf, _)
appendval(msg.params, pfield.name, buf)
end
end
else
......@@ -191,15 +183,16 @@ function mimedecode_message_body(src, msg, filecb)
local spos, epos, found
repeat
spos, epos = data:find("\r\n--" .. msg.mime_boundary .. "\r\n", 1, true)
spos, epos = data:find("\r\n--" .. mime_boundary .. "\r\n", 1, true)
if not spos then
spos, epos = data:find("\r\n--" .. msg.mime_boundary .. "--\r\n", 1, true)
spos, epos = data:find("\r\n--" .. mime_boundary .. "--\r\n", 1, true)
end
if spos then
local predata = data:sub(1, spos - 1)
local eof
if inhdr then
predata, eof = parse_headers(predata, field)
......@@ -228,11 +221,12 @@ function mimedecode_message_body(src, msg, filecb)
-- We found at least some boundary. Save
-- the unparsed remaining data for the
-- next chunk.
lchunk, data = data, nil
lchunk = data
else
-- There was a complete chunk without a boundary. Parse it as headers or
-- append it as data, depending on our current state.
if inhdr then
local eof
lchunk, eof = parse_headers(data, field)
inhdr = not eof
else
......@@ -243,7 +237,7 @@ function mimedecode_message_body(src, msg, filecb)
if store then
store(field, lchunk, false)
end
lchunk, chunk = chunk, nil
lchunk = chunk
end
end
end
......@@ -251,18 +245,61 @@ function mimedecode_message_body(src, msg, filecb)
return true
end
return pump(src, snk)
assert(pump(src, snk))
end
local function check_post_origin(msg)
local default_port = '80'
local request_scheme = 'http'
if msg.env.HTTPS then
default_port = '443'
request_scheme = 'https'
end
local request_host = msg.env.HTTP_HOST
if not request_host then
error('POST request without Host header')
end
if not request_host:match(':[0-9]+$') then
request_host = request_host .. ':' .. default_port
end
local origin = msg.env.HTTP_ORIGIN
if not origin then
error('POST request without Origin header')
end
local origin_scheme, origin_host = origin:match('^([^:]*)://(.*)$')
if not origin_host then
error('POST request with invalid Origin header')
end
if not origin_host:match(':[0-9]+$') then
local origin_port
if origin_scheme == 'http' then
origin_port = '80'
elseif origin_scheme == 'https' then
origin_port = '443'
else
error('POST request with invalid Origin header')
end
origin_host = origin_host .. ':' .. origin_port
end
if request_scheme ~= origin_scheme or request_host ~= origin_host then
error('Invalid cross-origin POST')
end
end
-- This function will examine the Content-Type within the given message object
-- to select the appropriate content decoder.
-- Currently only the multipart/form-data mime type is supported.
function parse_message_body(src, msg, filecb)
if not (msg.env.REQUEST_METHOD == "POST" and msg.env.CONTENT_TYPE) then
function M.parse_message_body(src, msg, filecb)
if msg.env.REQUEST_METHOD ~= "POST" then
return
end
if msg.env.CONTENT_TYPE:match("^multipart/form%-data") then
return mimedecode_message_body(src, msg, filecb)
end
check_post_origin(msg)
mimedecode_message_body(src, msg, filecb)
end
return M
......@@ -13,7 +13,7 @@ return function(config)
return string.format('%s/%s.%s.lmo', i18ndir, pkg, lang)
end
local function no_translation(key)
local function no_translation()
return nil
end
......
......@@ -44,13 +44,13 @@ return function(config, env)
translate = t.translate,
translatef = t.translatef,
_translate = t._translate,
include = function(name)
ctx.render(name, scope, pkg)
include = function(include_name)
ctx.render(include_name, scope, pkg)
end,
}
setfenv(template, setmetatable({}, {
__index = function(tbl, key)
__index = function(_, key)
return scope[key] or locals[key] or env[key]
end
}))
......@@ -58,7 +58,7 @@ return function(config, env)
-- Now finally render the thing
local stat, err = pcall(template)
assert(stat, "Failed to execute template '" .. name .. "'.\n" ..
"A runtime error occured: " .. tostring(err or "(nil)"))
"A runtime error occurred: " .. tostring(err or "(nil)"))
end
--- Render a certain template.
......
......@@ -4,10 +4,8 @@
local tparser = require "gluon.web.template.parser"
local getmetatable, setmetatable = getmetatable, setmetatable
local tostring = tostring
module "gluon.web.util"
local M = {}
--
-- Class helper routines
......@@ -33,14 +31,14 @@ end
-- to the __init__ function of this class - if such a function exists.
-- The __init__ function must be used to set any object parameters that are not shared
-- with other objects of this class. Any return values will be ignored.
function class(base)
function M.class(base)
return setmetatable({}, {
__call = _instantiate,
__index = base
})
end
function instanceof(object, class)
function M.instanceof(object, class)
while object do
if object == class then
return true
......@@ -56,6 +54,8 @@ end
-- String and data manipulation routines
--
function pcdata(value)
function M.pcdata(value)
return value and tparser.pcdata(tostring(value))
end
return M
......@@ -9,6 +9,8 @@ clean:
parser.so: template_parser.o template_utils.o template_lmo.o template_lualib.o
$(CC) $(LDFLAGS) -shared -o $@ $^
gluon-po2lmo: gluon-po2lmo.o template_lmo.o
compile: parser.so
install: compile
......
/*
* lmo - Lua Machine Objects - PO to LMO conversion tool
*
* Copyright (C) 2009-2012 Jo-Philipp Wich <jow@openwrt.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "template_lmo.h"
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
__attribute__((noreturn))
static void die(const char *msg)
{
fprintf(stderr, "Error: %s\n", msg);
exit(1);
}
__attribute__((noreturn))
static void usage(const char *name)
{
fprintf(stderr, "Usage: %s input.po output.lmo\n", name);
exit(1);
}
static void print(const void *ptr, size_t size, size_t nmemb, FILE *stream)
{
if( fwrite(ptr, size, nmemb, stream) == 0 )
die("Failed to write stdout");
}
static ssize_t extract_string(const char *src, char *dest, size_t len)
{
size_t pos = 0;
int esc = 0;
int off = -1;
for( pos = 0; (pos < strlen(src)) && (pos < len); pos++ )
{
if( (off == -1) && (src[pos] == '"') )
{
off = pos + 1;
}
else if( off >= 0 )
{
if( esc == 1 )
{
switch (src[pos])
{
case '"':
case '\\':
off++;
break;
}
dest[pos-off] = src[pos];
esc = 0;
}
else if( src[pos] == '\\' )
{
dest[pos-off] = src[pos];
esc = 1;
}
else if( src[pos] != '"' )
{
dest[pos-off] = src[pos];
}
else
{
dest[pos-off] = '\0';
break;
}
}
}
return (off > -1) ? (ssize_t) strlen(dest) : -1;
}
static int cmp_index(const void *a, const void *b)
{
uint32_t x = ((const lmo_entry_t *)a)->key_id;
uint32_t y = ((const lmo_entry_t *)b)->key_id;
if (x < y)
return -1;
else if (x > y)
return 1;
return 0;
}
static void print_uint32(uint32_t x, FILE *out)
{
uint32_t y = htonl(x);
print(&y, sizeof(uint32_t), 1, out);
}
static void print_index(void *array, int n, FILE *out)
{
lmo_entry_t *e;
qsort(array, n, sizeof(*e), cmp_index);
for (e = array; n > 0; n--, e++)
{
print_uint32(e->key_id, out);
print_uint32(e->val_id, out);
print_uint32(e->offset, out);
print_uint32(e->length, out);
}
}
int main(int argc, char *argv[])
{
char line[4096];
char key[4096];
char val[4096];
char tmp[4096];
int state = 0;
int offset = 0;
int length = 0;
int n_entries = 0;
void *array = NULL;
lmo_entry_t *entry = NULL;
uint32_t key_id, val_id;
FILE *in;
FILE *out;
if( (argc != 3) || ((in = fopen(argv[1], "r")) == NULL) || ((out = fopen(argv[2], "w")) == NULL) )
usage(argv[0]);
memset(line, 0, sizeof(key));
memset(key, 0, sizeof(val));
memset(val, 0, sizeof(val));
while( (NULL != fgets(line, sizeof(line), in)) || (state >= 2 && feof(in)) )
{
if( state == 0 && strstr(line, "msgid \"") == line )
{
switch(extract_string(line, key, sizeof(key)))
{
case -1:
die("Syntax error in msgid");
case 0:
state = 1;
break;
default:
state = 2;
}
}
else if( state == 1 || state == 2 )
{
if( strstr(line, "msgstr \"") == line || state == 2 )
{
switch(extract_string(line, val, sizeof(val)))
{
case -1:
state = 4;
break;
default:
state = 3;
}
}
else
{
switch(extract_string(line, tmp, sizeof(tmp)))
{
case -1:
state = 2;
break;
default:
strcat(key, tmp);
}
}
}
else if( state == 3 )
{
switch(extract_string(line, tmp, sizeof(tmp)))
{
case -1:
state = 4;
break;
default:
strcat(val, tmp);
}
}
if( state == 4 )
{
if( strlen(key) > 0 && strlen(val) > 0 )
{
key_id = sfh_hash(key, strlen(key));
val_id = sfh_hash(val, strlen(val));
if( key_id != val_id )
{
n_entries++;
array = realloc(array, n_entries * sizeof(lmo_entry_t));
entry = (lmo_entry_t *)array + n_entries - 1;
if (!array)
die("Out of memory");
entry->key_id = key_id;
entry->val_id = val_id;
entry->offset = offset;
entry->length = strlen(val);
length = strlen(val) + ((4 - (strlen(val) % 4)) % 4);
print(val, length, 1, out);
offset += length;
}
}
state = 0;
memset(key, 0, sizeof(key));
memset(val, 0, sizeof(val));
}
memset(line, 0, sizeof(line));
}
print_index(array, n_entries, out);
if( offset > 0 )
{
print_uint32(offset, out);
fsync(fileno(out));
fclose(out);
}
else
{
fclose(out);
unlink(argv[2]);
}
fclose(in);
return(0);
}
......@@ -25,20 +25,11 @@
#include <arpa/inet.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct lmo_entry {
uint32_t key_id;
uint32_t val_id;
uint32_t offset;
uint32_t length;
} __attribute__((packed));
static inline uint16_t get_le16(const void *data) {
const uint8_t *d = data;
return (((uint16_t)d[1]) << 8) | d[0];
......@@ -56,7 +47,7 @@ static inline uint32_t get_be32(const void *data) {
* Hash function from http://www.azillionmonkeys.com/qed/hash.html
* Copyright (C) 2004-2008 by Paul Hsieh
*/
static uint32_t sfh_hash(const void *input, size_t len)
uint32_t sfh_hash(const void *input, size_t len)
{
const uint8_t *data = input;
uint32_t hash = len, tmp;
......
......@@ -22,8 +22,15 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
struct lmo_entry {
uint32_t key_id;
uint32_t val_id;
uint32_t offset;
uint32_t length;
} __attribute__((packed));
typedef struct lmo_entry lmo_entry_t;
......@@ -37,6 +44,8 @@ struct lmo_catalog {
typedef struct lmo_catalog lmo_catalog_t;
uint32_t sfh_hash(const void *input, size_t len);
bool lmo_load(lmo_catalog_t *cat, const char *file);
void lmo_unload(lmo_catalog_t *cat);
bool lmo_translate(const lmo_catalog_t *cat, const char *key, size_t keylen, const char **out, size_t *outlen);
......