From 63aa800b324874499cec76522e206590c1e9daa8 Mon Sep 17 00:00:00 2001 From: Vincent Wang Date: Sat, 30 Jun 2018 15:27:56 +0800 Subject: [PATCH 01/12] initial commit for communityWebServer kit --- .../StaticFileWeblet.sedona | 66 +++++++++++++++++++ src/kits/communityWebServer/kit.xml | 25 +++++++ 2 files changed, 91 insertions(+) create mode 100644 src/kits/communityWebServer/StaticFileWeblet.sedona create mode 100644 src/kits/communityWebServer/kit.xml diff --git a/src/kits/communityWebServer/StaticFileWeblet.sedona b/src/kits/communityWebServer/StaticFileWeblet.sedona new file mode 100644 index 0000000..f0c3db1 --- /dev/null +++ b/src/kits/communityWebServer/StaticFileWeblet.sedona @@ -0,0 +1,66 @@ +// +// Copyright (c) 2018 +// Licensed under the Academic Free License version 3.0 +// +// History: +// 30 Jun 18 Vincent Wang Static File Weblet +// + +** +** StaticFileWeblet provides the ability to serve static files(html, css, js, +** images etc), so that user can use sedona as a minimal web server and host +** a static web app just in sedona, without any outside dependency +** +class StaticFileWeblet extends Weblet +{ +//////////////////////////////////////////////////////////////// +// Weblet Registration +//////////////////////////////////////////////////////////////// + + static void _sInit() + { + instance.register() + } + static internal inline StaticFileWeblet instance + +//////////////////////////////////////////////////////////////// +// Weblet +//////////////////////////////////////////////////////////////// + + override Str prefix() { return "statics" } + + override Str description() { return "Sedona Static File Weblet" } + + override void service(WebReq req, WebRes res) + { + Str method = req.method; + if (method.equals("GET")) + get(req, res) + else { + res.writeStatus(HttpCode.methodNotAllowed) + res.writeHeader("Allow", "GET") + } + } + + override void get(WebReq req, WebRes res) + { + // route to static file + Str p = "" + if (req.path.size > 1) p = req.path.names[1] + + index(req, res) + } + +//////////////////////////////////////////////////////////////// +// functions +//////////////////////////////////////////////////////////////// + + public void index(WebReq req, WebRes res) + { + res.html(); + res.w("

Hello World!

\n"); + res.htmlEnd(); + } + +} + diff --git a/src/kits/communityWebServer/kit.xml b/src/kits/communityWebServer/kit.xml new file mode 100644 index 0000000..f1b9e68 --- /dev/null +++ b/src/kits/communityWebServer/kit.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + From 8394ff66a8e8038a5188d4f65168fe869339ae89 Mon Sep 17 00:00:00 2001 From: Vincent Wang Date: Sat, 30 Jun 2018 18:11:22 +0800 Subject: [PATCH 02/12] can serve static files with correct headers --- .gitignore | 1 + .../StaticFileWeblet.sedona | 109 +++++++++++++++++- 2 files changed, 105 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index adbd930..3f432f7 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ sedona-*.zip *.log *.swo .DS_Store +statics/* diff --git a/src/kits/communityWebServer/StaticFileWeblet.sedona b/src/kits/communityWebServer/StaticFileWeblet.sedona index f0c3db1..3cbb4bb 100644 --- a/src/kits/communityWebServer/StaticFileWeblet.sedona +++ b/src/kits/communityWebServer/StaticFileWeblet.sedona @@ -44,15 +44,105 @@ class StaticFileWeblet extends Weblet override void get(WebReq req, WebRes res) { - // route to static file - Str p = "" - if (req.path.size > 1) p = req.path.names[1] + reset() - index(req, res) + prepareFile(req) + serveFile(res) + } + + internal void reset() + { + filePath.set(0, 0) + } + + internal void serveFile(WebRes res) + { + if (file.name==null || !file.exists()) { + res.writeStatus(HttpCode.notFound).finishHeaders() + return + } + + if (!file.open("r")) { + res.writeStatus(HttpCode.internalError).finishHeaders() + return + } + + App.log.message("Serving File: " + file.name); + + res.writeStatusOk() + + //write headers + //TODO: support Content-Encoding: gzip + res.writeContentType(getContentType(file.name)) + .writeHeader("Cache-Control", "max-age=604800") + .writeHeader("Server", "Sedona Web Server") + .writeHeader("Content-Length", Sys.intStr(file.size())) + .finishHeaders() + + file.seek(0) + while(true) { + int readed = file.in.readBytes(readBuf, 0, bufLen) + if (readed <= 0) + break + + res.writeBytes(readBuf, 0, readed) + } + + file.close() + } + + static public bool endsWith(Str str, Str suffix) { + return suffix.equalsRegion(str, str.length()-suffix.length(), str.length()+1) + } + + internal Str getContentType(Str fileName) + { + if (endsWith(fileName, ".html")) + return "text/html" + else if (endsWith(fileName, ".css")) + return "text/css" + else if (endsWith(fileName, ".txt")) + return "text/plain" + else if (endsWith(fileName, ".js")) + return "application/javascript" + else if (endsWith(fileName, ".json")) + return "application/json" + else if (endsWith(fileName, ".xml")) + return "application/xml" + else if (endsWith(fileName, ".pdf")) + return "application/pdf" + else if (endsWith(fileName, ".jpg")) + return "image/jpeg" + else if (endsWith(fileName, ".png")) + return "image/png" + else + return "text/plain" + } + + internal void prepareFile(WebReq req) + { + if (req.path.size <= 1) + return + else if (req.path.size == 1) + filePath.copyFromStr("./index.html", pathStrLen) + else { + filePath.copyFromStr(".", pathStrLen); + int index = filePath.length() + byte[] fileBuf = filePath.toBytes() + for(int i=0; i Date: Sat, 30 Jun 2018 18:51:06 +0800 Subject: [PATCH 03/12] support gzip Content-Encoding --- .../StaticFileWeblet.sedona | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/src/kits/communityWebServer/StaticFileWeblet.sedona b/src/kits/communityWebServer/StaticFileWeblet.sedona index 3cbb4bb..a772879 100644 --- a/src/kits/communityWebServer/StaticFileWeblet.sedona +++ b/src/kits/communityWebServer/StaticFileWeblet.sedona @@ -57,22 +57,36 @@ class StaticFileWeblet extends Weblet internal void serveFile(WebRes res) { - if (file.name==null || !file.exists()) { + if (file.name==null) { res.writeStatus(HttpCode.notFound).finishHeaders() return } + if (!file.exists()) { + //try gzipped content + int index = file.name.length() + file.name.set(index++, '.') + file.name.set(index++, 'g') + file.name.set(index++, 'z') + file.name.set(index, 0) + if (!file.exists()) { + res.writeStatus(HttpCode.notFound).finishHeaders() + return + } + } + if (!file.open("r")) { res.writeStatus(HttpCode.internalError).finishHeaders() return } App.log.message("Serving File: " + file.name); - res.writeStatusOk() //write headers - //TODO: support Content-Encoding: gzip + if (endsWith(file.name, ".gz", 0)) + res.writeHeader("Content-Encoding", "gzip"); + res.writeContentType(getContentType(file.name)) .writeHeader("Cache-Control", "max-age=604800") .writeHeader("Server", "Sedona Web Server") @@ -91,29 +105,33 @@ class StaticFileWeblet extends Weblet file.close() } - static public bool endsWith(Str str, Str suffix) { - return suffix.equalsRegion(str, str.length()-suffix.length(), str.length()+1) + static public bool endsWith(Str str, Str suffix, int endOffset) { + return suffix.equalsRegion(str, str.length()-suffix.length()-endOffset, str.length()-endOffset) } internal Str getContentType(Str fileName) { - if (endsWith(fileName, ".html")) + int endOffset = 0 + if (endsWith(fileName, ".gz", 0)) + endOffset = 3 + + if (endsWith(fileName, ".html", endOffset) || endsWith(fileName, ".htm", endOffset)) return "text/html" - else if (endsWith(fileName, ".css")) + else if (endsWith(fileName, ".css", endOffset)) return "text/css" - else if (endsWith(fileName, ".txt")) + else if (endsWith(fileName, ".txt", endOffset)) return "text/plain" - else if (endsWith(fileName, ".js")) + else if (endsWith(fileName, ".js", endOffset)) return "application/javascript" - else if (endsWith(fileName, ".json")) + else if (endsWith(fileName, ".json", endOffset)) return "application/json" - else if (endsWith(fileName, ".xml")) + else if (endsWith(fileName, ".xml", endOffset)) return "application/xml" - else if (endsWith(fileName, ".pdf")) + else if (endsWith(fileName, ".pdf", endOffset)) return "application/pdf" - else if (endsWith(fileName, ".jpg")) + else if (endsWith(fileName, ".jpg", endOffset)) return "image/jpeg" - else if (endsWith(fileName, ".png")) + else if (endsWith(fileName, ".png", endOffset)) return "image/png" else return "text/plain" From 2ecc3140dfd425d22e638da73bd1c1e318586a0e Mon Sep 17 00:00:00 2001 From: Vincent Wang Date: Sun, 1 Jul 2018 08:52:03 +0800 Subject: [PATCH 04/12] append index.html to dir url; fix buf overflow --- .../StaticFileWeblet.sedona | 78 ++++++++++++++++--- 1 file changed, 69 insertions(+), 9 deletions(-) diff --git a/src/kits/communityWebServer/StaticFileWeblet.sedona b/src/kits/communityWebServer/StaticFileWeblet.sedona index a772879..e15e604 100644 --- a/src/kits/communityWebServer/StaticFileWeblet.sedona +++ b/src/kits/communityWebServer/StaticFileWeblet.sedona @@ -47,6 +47,20 @@ class StaticFileWeblet extends Weblet reset() prepareFile(req) + + if (isDir(filePath)) { + //TODO: do http redirects + // if (!endsWith(filePath, "/", 0)) { + // res.writeStatus(HttpCode.movedPermanently) + // .w("Location").w(":").w(filePath).w("/") + // .finishHeaders() + // .finishHeaders() + // return + // } + + tryAppendIndex(filePath) + } + serveFile(res) } @@ -65,10 +79,13 @@ class StaticFileWeblet extends Weblet if (!file.exists()) { //try gzipped content int index = file.name.length() - file.name.set(index++, '.') - file.name.set(index++, 'g') - file.name.set(index++, 'z') - file.name.set(index, 0) + if (index+4 < pathStrLen) { + file.name.set(index++, '.') + file.name.set(index++, 'g') + file.name.set(index++, 'z') + file.name.set(index, 0) + } + if (!file.exists()) { res.writeStatus(HttpCode.notFound).finishHeaders() return @@ -105,6 +122,49 @@ class StaticFileWeblet extends Weblet file.close() } + bool isDir(Str fileName) { + if (endsWith(fileName, "/", 0)) + return true + + int len = fileName.length() + //check if there is a file extention + for(int i=len-3; i>0 && i>len-6; --i) { + if (fileName.get(i) != '.') + continue + + return false + } + + return true + } + + bool tryAppendIndex(Str fileName) { + int len = fileName.length() + if (len <= 0) + return false + + //try to append index.html to path end + byte[] buf = fileName.toBytes() + if (len+11 < pathStrLen) { + if (!endsWith(fileName, "/", 0)) + buf[len++] = '/' + buf[len++] = 'i' + buf[len++] = 'n' + buf[len++] = 'd' + buf[len++] = 'e' + buf[len++] = 'x' + buf[len++] = '.' + buf[len++] = 'h' + buf[len++] = 't' + buf[len++] = 'm' + buf[len++] = 'l' + buf[len++] = 0 + return true + } + + return false + } + static public bool endsWith(Str str, Str suffix, int endOffset) { return suffix.equalsRegion(str, str.length()-suffix.length()-endOffset, str.length()-endOffset) } @@ -139,23 +199,23 @@ class StaticFileWeblet extends Weblet internal void prepareFile(WebReq req) { - if (req.path.size <= 1) + if (req.path.size < 1) return - else if (req.path.size == 1) - filePath.copyFromStr("./index.html", pathStrLen) else { + //TODO: process path to avoid security issues filePath.copyFromStr(".", pathStrLen); int index = filePath.length() byte[] fileBuf = filePath.toBytes() - for(int i=0; i Date: Tue, 10 Jul 2018 20:36:43 +0800 Subject: [PATCH 05/12] remove unused codes --- src/kits/communityWebServer/StaticFileWeblet.sedona | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/kits/communityWebServer/StaticFileWeblet.sedona b/src/kits/communityWebServer/StaticFileWeblet.sedona index e15e604..d00b07b 100644 --- a/src/kits/communityWebServer/StaticFileWeblet.sedona +++ b/src/kits/communityWebServer/StaticFileWeblet.sedona @@ -49,15 +49,6 @@ class StaticFileWeblet extends Weblet prepareFile(req) if (isDir(filePath)) { - //TODO: do http redirects - // if (!endsWith(filePath, "/", 0)) { - // res.writeStatus(HttpCode.movedPermanently) - // .w("Location").w(":").w(filePath).w("/") - // .finishHeaders() - // .finishHeaders() - // return - // } - tryAppendIndex(filePath) } From 351c3bd025fb4244d3eb8f2661325682ff238abb Mon Sep 17 00:00:00 2001 From: Vincent Wang Date: Sat, 28 Jul 2018 12:01:18 +0800 Subject: [PATCH 06/12] add comments --- .../StaticFileWeblet.sedona | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/kits/communityWebServer/StaticFileWeblet.sedona b/src/kits/communityWebServer/StaticFileWeblet.sedona index d00b07b..0f67957 100644 --- a/src/kits/communityWebServer/StaticFileWeblet.sedona +++ b/src/kits/communityWebServer/StaticFileWeblet.sedona @@ -8,8 +8,11 @@ ** ** StaticFileWeblet provides the ability to serve static files(html, css, js, -** images etc), so that user can use sedona as a minimal web server and host -** a static web app just in sedona, without any outside dependency +** images etc) through http, so that user can use sedona as a minimal web +** server and host a static web app just in sedona, without any outside +** dependency. +** to save space on sedona, gzipped file is supported and I recommend to use it +** since that will be more efficient(less bytes to be loaded and transferred) ** class StaticFileWeblet extends Weblet { @@ -27,10 +30,16 @@ class StaticFileWeblet extends Weblet // Weblet //////////////////////////////////////////////////////////////// + ** + ** all static files to be served must be put under 'statics' folder + ** and the url will start with 'statics', too override Str prefix() { return "statics" } override Str description() { return "Sedona Static File Weblet" } + ** + ** since we only serve static file here, so only 'GET' method is supported + ** override void service(WebReq req, WebRes res) { Str method = req.method; @@ -42,6 +51,9 @@ class StaticFileWeblet extends Weblet } } + ** + ** handle 'GET' request, try to find the static file and return it + ** override void get(WebReq req, WebRes res) { reset() @@ -129,6 +141,9 @@ class StaticFileWeblet extends Weblet return true } + ** + ** if the URL ends with '/', then append 'index.html' and try serve it + ** bool tryAppendIndex(Str fileName) { int len = fileName.length() if (len <= 0) From c184d703c3c239975f678555c361c5e6040f1534 Mon Sep 17 00:00:00 2001 From: Vincent Wang Date: Sat, 28 Jul 2018 22:46:06 +0800 Subject: [PATCH 07/12] refactoring; add tests for string operation --- .../StaticFileWeblet.sedona | 62 +++++++++++-------- src/kits/communityWebServer/kit.xml | 1 + .../test/StrUtilTest.sedona | 35 +++++++++++ 3 files changed, 72 insertions(+), 26 deletions(-) create mode 100644 src/kits/communityWebServer/test/StrUtilTest.sedona diff --git a/src/kits/communityWebServer/StaticFileWeblet.sedona b/src/kits/communityWebServer/StaticFileWeblet.sedona index 0f67957..c821051 100644 --- a/src/kits/communityWebServer/StaticFileWeblet.sedona +++ b/src/kits/communityWebServer/StaticFileWeblet.sedona @@ -33,6 +33,7 @@ class StaticFileWeblet extends Weblet ** ** all static files to be served must be put under 'statics' folder ** and the url will start with 'statics', too + ** override Str prefix() { return "statics" } override Str description() { return "Sedona Static File Weblet" } @@ -81,13 +82,7 @@ class StaticFileWeblet extends Weblet if (!file.exists()) { //try gzipped content - int index = file.name.length() - if (index+4 < pathStrLen) { - file.name.set(index++, '.') - file.name.set(index++, 'g') - file.name.set(index++, 'z') - file.name.set(index, 0) - } + appendStr(file.name, ".gz", pathStrLen) if (!file.exists()) { res.writeStatus(HttpCode.notFound).finishHeaders() @@ -146,35 +141,50 @@ class StaticFileWeblet extends Weblet ** bool tryAppendIndex(Str fileName) { int len = fileName.length() - if (len <= 0) + if (len <= 0 || len+1>=pathStrLen) return false //try to append index.html to path end - byte[] buf = fileName.toBytes() - if (len+11 < pathStrLen) { - if (!endsWith(fileName, "/", 0)) - buf[len++] = '/' - buf[len++] = 'i' - buf[len++] = 'n' - buf[len++] = 'd' - buf[len++] = 'e' - buf[len++] = 'x' - buf[len++] = '.' - buf[len++] = 'h' - buf[len++] = 't' - buf[len++] = 'm' - buf[len++] = 'l' - buf[len++] = 0 - return true - } + if (!endsWith(fileName, "/", 0)) + appendStr(fileName, "/", pathStrLen) - return false + return appendStr(fileName, "index.html", pathStrLen) } + ** + ** check if str ends with suffix. + ** if endOffset is not 0, then check the suffix after + ** that offset. for example, to check if 'index.html.gz' + ** ends with '.html': + ** // buf equals "index.html.gz", offset is 3(len of ".gz") + ** endsWith(buf, ".html", 3) + ** static public bool endsWith(Str str, Str suffix, int endOffset) { return suffix.equalsRegion(str, str.length()-suffix.length()-endOffset, str.length()-endOffset) } + ** + ** append suffix to the end of dst. + ** return: + ** true if managed to append suffix to dst + ** false if dst's buffer is not big enough + ** + static public bool appendStr(Str dst, Str suffix, int bufMaxLen) + { + int dstLen = dst.length() + int suffixLen = suffix.length() + //return early if buffer is not big enough + if (dstLen + suffixLen + 1 > bufMaxLen) + return false + + byte[] dstBuf = dst.toBytes() + byte[] suffixBuf = suffix.toBytes() + for(int i=0; i + diff --git a/src/kits/communityWebServer/test/StrUtilTest.sedona b/src/kits/communityWebServer/test/StrUtilTest.sedona new file mode 100644 index 0000000..ba4fb54 --- /dev/null +++ b/src/kits/communityWebServer/test/StrUtilTest.sedona @@ -0,0 +1,35 @@ +@palette=false +public class StrUtilTest extends Test +{ + static void testEndsWith() + { + assert(!StaticFileWeblet.endsWith("/foo/bar", "/", 0)) + assert(StaticFileWeblet.endsWith("/foo/bar/", "/", 0)) + assert(StaticFileWeblet.endsWith("/foo/bar/index.html", ".html", 0)) + + assert(StaticFileWeblet.endsWith("/foo/bar/vue.min.js.gz", ".js", 3)) + } + + static void testAppendStr() + { + assert(StaticFileWeblet.appendStr(buf, "/foo/bar", bufLen)) + assert(buf.equals("/foo/bar")) + + assert(StaticFileWeblet.appendStr(buf, "/", bufLen)) + assert(buf.equals("/foo/bar/")) + + assert(StaticFileWeblet.appendStr(buf, "index.html", bufLen)) + assert(buf.equals("/foo/bar/index.html")) + + assert(StaticFileWeblet.appendStr(buf, ".gz", bufLen)) + assert(buf.equals("/foo/bar/index.html.gz")) + + //test buffer overflow + assert(!StaticFileWeblet.appendStr(buf, "1234567890", bufLen)) + //under this case, buf should not be modified + assert(buf.equals("/foo/bar/index.html.gz")) + } + + define int bufLen = 32 + inline static Str(bufLen) buf +} From 7f844c48139b6e4ec0ba95d578ea991e061c156c Mon Sep 17 00:00:00 2001 From: Vincent Wang Date: Wed, 1 Aug 2018 22:34:22 +0800 Subject: [PATCH 08/12] improve wireshark sox dissector * load 'bit32' when 'bit' module is missing * add 'ack', 'ackMore', 'errorCode' display filter * clean up --- tools/wireshark/sox.lua | 60 ++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/tools/wireshark/sox.lua b/tools/wireshark/sox.lua index 3884e35..10307b9 100644 --- a/tools/wireshark/sox.lua +++ b/tools/wireshark/sox.lua @@ -1,4 +1,13 @@ -require ("bit") +-- to survive in different version of lua, try 'bit' module first, if fails, +-- try load 'bit32'. refers: http://lua-users.org/wiki/BitwiseOperators +local status, bit = pcall(require, "bit") +if not (status) then + status, bit = pcall(require, "bit32") + if not (status) then + print("sox dissector: bitop module not found") + return + end +end dasp_proto = Proto("dasp", "Dasp Protocol") sox_proto = Proto("sox", "Sox Protocol") @@ -6,19 +15,17 @@ sox_proto = Proto("sox", "Sox Protocol") dasp_proto.prefs["udp_port"] = Pref.uint("UDP Port", 1876, "UDP Port for Dasp") -- dasp fields -local f_sessionId = ProtoField.uint16("dasp.sessionId", "SessionId", base.HEX) +local f_sessionId = ProtoField.uint16("dasp.sessionId", "sessionId", base.HEX) local f_seqNum = ProtoField.uint16("dasp.seqNum", "seqNum", base.DEC) local f_msgType = ProtoField.uint16("dasp.msgType", "msgType", base.HEX) local f_headerFieldNum = ProtoField.uint16("dasp.numFields", "numFields", base.DEC) --- local f_headerId = ProtoField.uint8("dasp.headerId", "headerId", base.HEX) --- local f_headerDataType = ProtoField.uint8("dasp.headerDataType", "headerDataType", base.HEX) -local f_headerU2Val = ProtoField.uint16("dasp.headerU2Val", "headerU2Val", base.Hex) -local f_headerStrVal = ProtoField.stringz("dasp.headerStrVal", "headerStrVal") -local f_headerByteVal = ProtoField.bytes("dasp.headerByteVal", "headerByteVal") + +local f_headerAck = ProtoField.uint16("dasp.ack", "ack", base.DEC) +local f_headerAckMore = ProtoField.bytes("dasp.ackMore", "ackMore") +local f_headerErrorCode = ProtoField.uint16("dasp.errorCode", "errorCode", base.Hex) dasp_proto.fields = {f_sessionId, f_seqNum, f_msgType, f_headerFieldNum, - -- f_headerId, f_headerDataType, - f_headerU2Val, f_headerStrVal, f_headerByteVal} + f_headerAck, f_headerAckMore, f_headerErrorCode} -- sox fields local f_soxCmd = ProtoField.string("sox.cmd", "cmd") @@ -345,7 +352,7 @@ local sox_handlers = { offset = add_string(tree, f_fileUri, buf, offset) - tree:add(f_fileSize, buf(offset, 4)) + tree:add(f_fileSize, buf(offset, 4):uint()) offset = offset + 4 tree:add(buf(offset, 2), "suggestedChunkSize", buf(offset, 2):uint()) @@ -356,7 +363,7 @@ local sox_handlers = { return offset end, ["F"] = function (tree, buf, offset) - tree:add(f_fileSize, buf(offset, 4)) + tree:add(f_fileSize, buf(offset, 4):uint()) offset = offset + 4 tree:add(buf(offset, 2), "actualChunkSize", buf(offset, 2):uint()) @@ -614,19 +621,32 @@ function add_header(tree, buf, offset) local headerTypeVal = headerVal:bitfield(6, 2) local headerName = '' - if header_mappings[headerVal:uint()] ~= nil then - headerName = header_mappings[headerVal:uint()] + if header_ids[headerIdVal] ~= nil then + headerName = header_ids[headerIdVal] end + -- if header_mappings[headerVal:uint()] ~= nil then + -- headerName = header_mappings[headerVal:uint()] + -- end if headerTypeVal == 0 then - local elem = tree:add(buf(offset, 1), headerName) - offset = offset + 1 - if headerIdVal == 0x0d then + local elem = tree:add(f_headerErrorCode, buf(offset, 1)) elem:append_text(" (" .. error_codes[headerVal:uint()] .. ")") + else + tree:add(buf(offset, 1), headerName) end + offset = offset + 1 elseif headerTypeVal == 1 then - tree:add(buf(offset, 3), headerName, buf(offset+1, 2):uint()) + if headerName == "ack" then + tree:add(f_headerAck, buf(offset, 3), buf(offset+1, 2):uint()) + elseif headerName == "ackMore" then + -- GOTCHA: there is a bug in old version of sox, ackMore is set as u2, + -- but encoded in bytes(only 1 byte). here is a workaround to + -- make this case work + local elem = tree:add(f_headerAckMore, buf(offset+2, 1)); + else + tree:add(buf(offset, 3), headerName, buf(offset+1, 2):uint()) + end offset = offset + 3 elseif headerTypeVal == 2 then local str = buf(offset+1):stringz() @@ -640,7 +660,11 @@ function add_header(tree, buf, offset) baStr = baStr .. string.format("%02x", ba:get_index(i)) end - tree:add(buf(offset, len+2), headerName, baStr) + if headerName == "ackMore" then + tree:add(f_headerAckMore, buf(offset+2, len)) + else + tree:add(buf(offset, len+2), headerName, baStr) + end offset = offset + len + 2 end From 6dd026bc0ccea1567028b324ef11b8eace974c47 Mon Sep 17 00:00:00 2001 From: Vincent Wang Date: Thu, 2 Aug 2018 17:34:06 +0800 Subject: [PATCH 09/12] several improvements/fixes * fix compData handler bugs * more sox filter fields support * define fields for stream, but no implementation yet --- tools/wireshark/sox.lua | 83 +++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 36 deletions(-) diff --git a/tools/wireshark/sox.lua b/tools/wireshark/sox.lua index 10307b9..ea89f44 100644 --- a/tools/wireshark/sox.lua +++ b/tools/wireshark/sox.lua @@ -1,3 +1,5 @@ +-- TODO: stream support + -- to survive in different version of lua, try 'bit' module first, if fails, -- try load 'bit32'. refers: http://lua-users.org/wiki/BitwiseOperators local status, bit = pcall(require, "bit") @@ -24,8 +26,16 @@ local f_headerAck = ProtoField.uint16("dasp.ack", "ack", base.DEC) local f_headerAckMore = ProtoField.bytes("dasp.ackMore", "ackMore") local f_headerErrorCode = ProtoField.uint16("dasp.errorCode", "errorCode", base.Hex) -dasp_proto.fields = {f_sessionId, f_seqNum, f_msgType, f_headerFieldNum, - f_headerAck, f_headerAckMore, f_headerErrorCode} +-- dasp stream support +local f_daspFrameRequest = ProtoField.framenum("dasp.request", "request", base.NONE, frametype.REQUEST, 0) +local f_daspFrameRequestDup = ProtoField.framenum("dasp.requestDup", "dasp requestDup", base.NONE, frametype.REQUEST, 0) +local f_daspFrameRequestAck = ProtoField.framenum("dasp.requestAck", "requestAck", base.NONE, frametype.ACK, 0) + +dasp_proto.fields = { + f_sessionId, f_seqNum, f_msgType, f_headerFieldNum, + f_headerAck, f_headerAckMore, f_headerErrorCode, + f_daspFrameRequest, f_daspFrameRequestDup, f_daspFrameRequestAck +} -- sox fields local f_soxCmd = ProtoField.string("sox.cmd", "cmd") @@ -46,23 +56,26 @@ local f_linkFromSlotId = ProtoField.uint8("sox.linkFromSlotId", "linkFromSlotId" local f_linkToCompId = ProtoField.uint16("sox.linkToCompId", "linkToCompId", base.DEC) local f_linkToSlotId = ProtoField.uint8("sox.linkToSlotId", "linkToSlotId", base.DEC) -local f_fileOpenMethod = ProtoField.string("sox.fileOpenMethod", "fileOpenMethod") +local f_fileOpenMethod = ProtoField.stringz("sox.fileOpenMethod", "fileOpenMethod") local f_fileUri = ProtoField.stringz("sox.fileUri", "fileUri") local f_fileSize = ProtoField.uint32("sox.fileSize", "fileSize", base.DEC) local f_chunkNum = ProtoField.uint16("sox.chunkNum", "chunkNum", base.DEC) local f_chunkSize = ProtoField.uint16("sox.chunkSize", "chunkSize", base.DEC) -local f_soxBytes = ProtoField.bytes("sox.byteVal", "bytesVal") -local f_soxStr = ProtoField.stringz("sox.strVal", "strVal") +local f_soxRenameFrom = ProtoField.stringz("sox.renameFrom", "renameFrom") +local f_soxRenameTo = ProtoField.stringz("sox.renameTo", "renameTo") local f_soxPlatformId = ProtoField.stringz("sox.platformId", "platformId") local f_soxError = ProtoField.stringz("sox.errorStr", "errorStr") +local f_soxBytes = ProtoField.bytes("sox.byteVal", "byteVal") + sox_proto.fields = {f_soxCmd, f_soxReplyNum, f_soxCompId, f_soxSlotId, f_parentCompId, f_kitId, f_typeId, f_compName, f_compWhat, f_linkAction, f_linkFromCompId, + f_fileOpenMethod, f_fileUri, f_fileSize, f_linkFromSlotId, f_linkToCompId, f_linkToSlotId, f_chunkNum, - f_chunkSize, f_soxBytes, f_soxStr, f_soxPlatformId, f_soxError} + f_chunkSize, f_soxBytes, f_soxRenameFrom, f_soxRenameTo, f_soxPlatformId, f_soxError} local msg_types = { [0] = {"discover", "Discover"}, @@ -189,8 +202,8 @@ function add_whatMask(tree, buf, offset) end function add_file_headers(tree, buf, offset) - local byte = buf(offset, 1) - while byte ~= '\0' do + local byte = buf(offset, 1):uint() + while byte ~= 0 do local start = offset local name = buf(offset):stringz() offset = offset + string.len(name) + 1 @@ -199,7 +212,7 @@ function add_file_headers(tree, buf, offset) offset = offset + string.len(value) + 1 tree:add(buf(start, offset-start), name, value) - byte = buf(offset, 1) + byte = buf(offset, 1):uint() end offset = offset + 1 @@ -207,7 +220,7 @@ function add_file_headers(tree, buf, offset) end function parse_comp_tree(tree, buf, offset) - local subtree = tree:add(f_compWhat, buf(offset, 1), buf(offset, 1):string(), "Tree") + local subtree = tree:add(f_compWhat, buf(offset, 1), buf(offset, 1):string(), "compTree") offset = offset + 1 subtree:add(f_kitId, buf(offset, 1)) @@ -234,7 +247,7 @@ function parse_comp_tree(tree, buf, offset) end function parse_comp_links(tree, buf, offset) - local subtree = tree:add(f_compWhat, buf(offset, 1), buf(offset, 1):string(), "Links") + local subtree = tree:add(f_compWhat, buf(offset, 1), buf(offset, 1):string(), "compLink") offset = offset + 1 local index = 1 @@ -257,12 +270,12 @@ function parse_comp_links(tree, buf, offset) end function parse_comp_props(tree, buf, offset) - local typeChar = buf(offset, 1):uint() + local typeChar = buf(offset, 1):string() local subtree = nil - if typeChar == 'c' or typeChar == 'C' then - subtree = tree:add(f_compWhat, buf(offset, 1), buf(offset, 1):string(), "Config Props") - elseif typeChar == 'r' or typeChar == 'R' then - subtree = tree:add(f_compWhat, buf(offset, 1), buf(offset, 1):string(), "Runtime Props") + if typeChar == "c" or typeChar == "C" then + subtree = tree:add(f_compWhat, buf(offset, 1), buf(offset, 1):string(), "configProps") + elseif typeChar == "r" or typeChar == "R" then + subtree = tree:add(f_compWhat, buf(offset, 1), buf(offset, 1):string(), "runtimeProps") end offset = offset + 1 @@ -293,8 +306,8 @@ local sox_handlers = { -- fileRename ["b"] = function (tree, buf, offset) - offset = add_string(tree, f_soxStr, buf, offset) - offset = add_string(tree, f_soxStr, buf, offset) + offset = add_string(tree, f_soxRenameFrom, buf, offset) + offset = add_string(tree, f_soxRenameTo, buf, offset) return offset end, @@ -302,9 +315,9 @@ local sox_handlers = { ["c"] = function (tree, buf, offset) offset = add_compId(tree, buf, offset) + local mapping = {t = "tree", c = "config", r = "runtime", l = "links"} local whatElem = tree:add(f_compWhat, buf(offset, 1)) local whatChar = buf(offset, 1):string() - local mapping = {t = "tree", c = "config", r = "runtime", l = "links"} whatElem:append_text("(" .. mapping[whatChar] .. ")") offset = offset + 1 @@ -314,11 +327,11 @@ local sox_handlers = { offset = add_compId(tree, buf, offset) local compDataChar = buf(offset, 1):string() - if compDataChar == 't' then + if compDataChar == "t" then offset = parse_comp_tree(tree, buf, offset) - elseif compDataChar == 'l' then + elseif compDataChar == "l" then offset = parse_comp_links(tree, buf, offset) - elseif compDataChar == 'c' or compDataChar == 'r' or compDataChar == 'C' or compDataChar == 'R' then + elseif compDataChar == "c" or compDataChar == "r" or compDataChar == "C" or compDataChar == "R" then offset = parse_comp_props(tree, buf, offset) end return offset @@ -335,11 +348,11 @@ local sox_handlers = { offset = add_compId(tree, buf, offset) local compDataChar = buf(offset, 1):string() - if compDataChar == 't' then + if compDataChar == "t" then offset = parse_comp_tree(tree, buf, offset) - elseif compDataChar == 'l' then + elseif compDataChar == "l" then offset = parse_comp_links(tree, buf, offset) - elseif compDataChar == 'c' or compDataChar == 'r' or compDataChar == 'C' or compDataChar == 'R' then + elseif compDataChar == "c" or compDataChar == "r" or compDataChar == "C" or compDataChar == "R" then offset = parse_comp_props(tree, buf, offset) end return offset @@ -347,12 +360,10 @@ local sox_handlers = { -- fileOpen ["f"] = function (tree, buf, offset) - tree:add(f_fileOpenMethod, buf(offset, 1)) - offset = offset + 1 - + offset = add_string(tree, f_fileOpenMethod, buf, offset) offset = add_string(tree, f_fileUri, buf, offset) - tree:add(f_fileSize, buf(offset, 4):uint()) + tree:add(f_fileSize, buf(offset, 4)) offset = offset + 4 tree:add(buf(offset, 2), "suggestedChunkSize", buf(offset, 2):uint()) @@ -363,7 +374,7 @@ local sox_handlers = { return offset end, ["F"] = function (tree, buf, offset) - tree:add(f_fileSize, buf(offset, 4):uint()) + tree:add(f_fileSize, buf(offset, 4)) offset = offset + 4 tree:add(buf(offset, 2), "actualChunkSize", buf(offset, 2):uint()) @@ -421,7 +432,7 @@ local sox_handlers = { offset = offset + 1 local label = "" .. fromCompId .. "." .. fromSlotId .. " -> " .. toCompId .. "." .. toSlotId - if string.char(linkType:uint()) == 'a' then + if string.char(linkType:uint()) == "a" then linkTypeElem:append_text("(add link: " .. label .. ")") else linkTypeElem:append_text("(delete link: " .. label .. ")") @@ -605,7 +616,7 @@ function parse_sox(tree, buf, offset) if handler ~= nil then offset = handler(tree, buf, offset) end - + -- output all pending bytes if offset < buf:len() then tree:add(f_soxBytes, buf(offset)) @@ -624,9 +635,6 @@ function add_header(tree, buf, offset) if header_ids[headerIdVal] ~= nil then headerName = header_ids[headerIdVal] end - -- if header_mappings[headerVal:uint()] ~= nil then - -- headerName = header_mappings[headerVal:uint()] - -- end if headerTypeVal == 0 then if headerIdVal == 0x0d then @@ -643,7 +651,7 @@ function add_header(tree, buf, offset) -- GOTCHA: there is a bug in old version of sox, ackMore is set as u2, -- but encoded in bytes(only 1 byte). here is a workaround to -- make this case work - local elem = tree:add(f_headerAckMore, buf(offset+2, 1)); + tree:add(f_headerAckMore, buf(offset+2, 1)); else tree:add(buf(offset, 3), headerName, buf(offset+1, 2):uint()) end @@ -693,6 +701,9 @@ function dasp_proto.dissector(buf, pinfo, tree) local msgType = subtree:add(f_msgType, buf(4, 1), typeVal) if msg_types[typeVal] ~= nil then msgType:append_text(" (" .. msg_types[typeVal][1] .. ")") + pinfo.cols.info = string.format("seqNum: %5d msgType: %-12s %s", buf(2, 2):uint(), msg_types[typeVal][1], pinfo.cols.info) + else + pinfo.cols.info = string.format("seqNum: %5d %-12s", buf(2, 2):uint(), pinfo.cols.info) end local headerNum = buf(4, 1):bitfield(4, 4) From 95ebb004e2431dd5a25dd6acaaff9e3f3d6e11ab Mon Sep 17 00:00:00 2001 From: Vincent Wang Date: Sat, 10 Nov 2018 17:57:08 +0800 Subject: [PATCH 10/12] support configurable url prefix don't create StaticFileWeblet in static method '_sInit' like what SpyWeblet does, let user to decide when to enable/disable it. The current SpyWeblet is not possible to disable it unless uninstall the web kit. I think we should modify it to be the same as StaticFileWeblet. I will do it later to avoid this branch bloated. --- .../StaticFileWeblet.sedona | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/kits/communityWebServer/StaticFileWeblet.sedona b/src/kits/communityWebServer/StaticFileWeblet.sedona index c821051..6879131 100644 --- a/src/kits/communityWebServer/StaticFileWeblet.sedona +++ b/src/kits/communityWebServer/StaticFileWeblet.sedona @@ -9,22 +9,35 @@ ** ** StaticFileWeblet provides the ability to serve static files(html, css, js, ** images etc) through http, so that user can use sedona as a minimal web -** server and host a static web app just in sedona, without any outside -** dependency. -** to save space on sedona, gzipped file is supported and I recommend to use it +** server and host a static web app(SPA for example) just in sedona, without +** any outside dependency. +** +** To enable this weblet, you need to create an object of this component as a +** child of WebService. Deleting the object will disable the weblet. This is +** different comparing to SpyWeblet. +** +** You can create multiple objects of StaticFileWeblet and every object uses +** different urlPrefix, so that sedona is possible to host multiple web apps. +** +** To save space on sedona, gzipped file is supported and I recommend to use it ** since that will be more efficient(less bytes to be loaded and transferred) ** class StaticFileWeblet extends Weblet { + @config @asStr property Buf(12) urlPrefix = "statics" //////////////////////////////////////////////////////////////// // Weblet Registration //////////////////////////////////////////////////////////////// - static void _sInit() + override void start() { - instance.register() + register() + } + + override void stop() + { + unregister() } - static internal inline StaticFileWeblet instance //////////////////////////////////////////////////////////////// // Weblet @@ -32,9 +45,10 @@ class StaticFileWeblet extends Weblet ** ** all static files to be served must be put under 'statics' folder - ** and the url will start with 'statics', too + ** and the url will start with 'statics', too. If you want to use other + ** name, config it by urlPrefix slot, Note: the max length is 11 chars ** - override Str prefix() { return "statics" } + override Str prefix() { return urlPrefix.toStr() } override Str description() { return "Sedona Static File Weblet" } From 5d354a9499148311df20bae8a2f72a621d3e2e2f Mon Sep 17 00:00:00 2001 From: Vincent Wang Date: Sat, 24 Nov 2018 20:21:03 +0800 Subject: [PATCH 11/12] add webServer demo app --- apps/webServer.sax | 88 +++++++++++++++++++++++++++++++++++++++++++++ scode/webServer.xml | 39 ++++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 apps/webServer.sax create mode 100644 scode/webServer.xml diff --git a/apps/webServer.sax b/apps/webServer.sax new file mode 100644 index 0000000..58d8e6b --- /dev/null +++ b/apps/webServer.sax @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scode/webServer.xml b/scode/webServer.xml new file mode 100644 index 0000000..541617f --- /dev/null +++ b/scode/webServer.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 63227cca5ef367be6ba658add119105aa7cfc104 Mon Sep 17 00:00:00 2001 From: Vincent Wang Date: Mon, 3 Dec 2018 21:41:21 +0800 Subject: [PATCH 12/12] use WebService logger, change log level to trace --- src/kits/communityWebServer/StaticFileWeblet.sedona | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kits/communityWebServer/StaticFileWeblet.sedona b/src/kits/communityWebServer/StaticFileWeblet.sedona index 6879131..dc90c08 100644 --- a/src/kits/communityWebServer/StaticFileWeblet.sedona +++ b/src/kits/communityWebServer/StaticFileWeblet.sedona @@ -109,7 +109,7 @@ class StaticFileWeblet extends Weblet return } - App.log.message("Serving File: " + file.name); + WebService.log.trace("Serving File: " + file.name); res.writeStatusOk() //write headers