summaryrefslogtreecommitdiffstats
path: root/src/jaegertracing/thrift/lib/lua/TJsonProtocol.lua
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/jaegertracing/thrift/lib/lua/TJsonProtocol.lua727
1 files changed, 727 insertions, 0 deletions
diff --git a/src/jaegertracing/thrift/lib/lua/TJsonProtocol.lua b/src/jaegertracing/thrift/lib/lua/TJsonProtocol.lua
new file mode 100644
index 000000000..db08eecf1
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/lua/TJsonProtocol.lua
@@ -0,0 +1,727 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you 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.
+--
+
+require 'TProtocol'
+require 'libluabpack'
+require 'libluabitwise'
+
+TJSONProtocol = __TObject.new(TProtocolBase, {
+ __type = 'TJSONProtocol',
+ THRIFT_JSON_PROTOCOL_VERSION = 1,
+ jsonContext = {},
+ jsonContextVal = {first = true, colon = true, ttype = 2, null = true},
+ jsonContextIndex = 1,
+ hasReadByte = ""
+})
+
+TTypeToString = {}
+TTypeToString[TType.BOOL] = "tf"
+TTypeToString[TType.BYTE] = "i8"
+TTypeToString[TType.I16] = "i16"
+TTypeToString[TType.I32] = "i32"
+TTypeToString[TType.I64] = "i64"
+TTypeToString[TType.DOUBLE] = "dbl"
+TTypeToString[TType.STRING] = "str"
+TTypeToString[TType.STRUCT] = "rec"
+TTypeToString[TType.LIST] = "lst"
+TTypeToString[TType.SET] = "set"
+TTypeToString[TType.MAP] = "map"
+
+StringToTType = {
+ tf = TType.BOOL,
+ i8 = TType.BYTE,
+ i16 = TType.I16,
+ i32 = TType.I32,
+ i64 = TType.I64,
+ dbl = TType.DOUBLE,
+ str = TType.STRING,
+ rec = TType.STRUCT,
+ map = TType.MAP,
+ set = TType.SET,
+ lst = TType.LIST
+}
+
+JSONNode = {
+ ObjectBegin = '{',
+ ObjectEnd = '}',
+ ArrayBegin = '[',
+ ArrayEnd = ']',
+ PairSeparator = ':',
+ ElemSeparator = ',',
+ Backslash = '\\',
+ StringDelimiter = '"',
+ ZeroChar = '0',
+ EscapeChar = 'u',
+ Nan = 'NaN',
+ Infinity = 'Infinity',
+ NegativeInfinity = '-Infinity',
+ EscapeChars = "\"\\bfnrt",
+ EscapePrefix = "\\u00"
+}
+
+EscapeCharVals = {
+ '"', '\\', '\b', '\f', '\n', '\r', '\t'
+}
+
+JSONCharTable = {
+ --0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 0, 0, 0, 0, 0, 0, 0, 0, 98,116,110, 0,102,114, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1,34, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+}
+
+-- character table string
+local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
+
+-- encoding
+function base64_encode(data)
+ return ((data:gsub('.', function(x)
+ local r,b='',x:byte()
+ for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
+ return r;
+ end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
+ if (#x < 6) then return '' end
+ local c=0
+ for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
+ return b:sub(c+1,c+1)
+ end)..({ '', '==', '=' })[#data%3+1])
+end
+
+-- decoding
+function base64_decode(data)
+ data = string.gsub(data, '[^'..b..'=]', '')
+ return (data:gsub('.', function(x)
+ if (x == '=') then return '' end
+ local r,f='',(b:find(x)-1)
+ for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
+ return r;
+ end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
+ if (#x ~= 8) then return '' end
+ local c=0
+ for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
+ return string.char(c)
+ end))
+end
+
+function TJSONProtocol:resetContext()
+ self.jsonContext = {}
+ self.jsonContextVal = {first = true, colon = true, ttype = 2, null = true}
+ self.jsonContextIndex = 1
+end
+
+function TJSONProtocol:contextPush(context)
+ self.jsonContextIndex = self.jsonContextIndex + 1
+ self.jsonContext[self.jsonContextIndex] = self.jsonContextVal
+ self.jsonContextVal = context
+end
+
+function TJSONProtocol:contextPop()
+ self.jsonContextVal = self.jsonContext[self.jsonContextIndex]
+ self.jsonContextIndex = self.jsonContextIndex - 1
+end
+
+function TJSONProtocol:escapeNum()
+ if self.jsonContextVal.ttype == 1 then
+ return self.jsonContextVal.colon
+ else
+ return false
+ end
+end
+
+function TJSONProtocol:writeElemSeparator()
+ if self.jsonContextVal.null then
+ return
+ end
+ if self.jsonContextVal.first then
+ self.jsonContextVal.first = false
+ else
+ if self.jsonContextVal.ttype == 1 then
+ if self.jsonContextVal.colon then
+ self.trans:write(JSONNode.PairSeparator)
+ self.jsonContextVal.colon = false
+ else
+ self.trans:write(JSONNode.ElemSeparator)
+ self.jsonContextVal.colon = true
+ end
+ else
+ self.trans:write(JSONNode.ElemSeparator)
+ end
+ end
+end
+
+function TJSONProtocol:hexChar(val)
+ val = libluabitwise.band(val, 0x0f)
+ if val < 10 then
+ return val + 48
+ else
+ return val + 87
+ end
+end
+
+function TJSONProtocol:writeJSONEscapeChar(ch)
+ self.trans:write(JSONNode.EscapePrefix)
+ local outCh = hexChar(libluabitwise.shiftr(ch, 4))
+ local buff = libluabpack.bpack('c', outCh)
+ self.trans:write(buff)
+ outCh = hexChar(ch)
+ buff = libluabpack.bpack('c', outCh)
+ self.trans:write(buff)
+end
+
+function TJSONProtocol:writeJSONChar(byte)
+ ch = string.byte(byte)
+ if ch >= 0x30 then
+ if ch == JSONNode.Backslash then
+ self.trans:write(JSONNode.Backslash)
+ self.trans:write(JSONNode.Backslash)
+ else
+ self.trans:write(byte)
+ end
+ else
+ local outCh = JSONCharTable[ch+1]
+ if outCh == 1 then
+ self.trans:write(byte)
+ elseif outCh > 1 then
+ self.trans:write(JSONNode.Backslash)
+ local buff = libluabpack.bpack('c', outCh)
+ self.trans:write(buff)
+ else
+ self:writeJSONEscapeChar(ch)
+ end
+ end
+end
+
+function TJSONProtocol:writeJSONString(str)
+ self:writeElemSeparator()
+ self.trans:write(JSONNode.StringDelimiter)
+ -- TODO escape special characters
+ local length = string.len(str)
+ local ii = 1
+ while ii <= length do
+ self:writeJSONChar(string.sub(str, ii, ii))
+ ii = ii + 1
+ end
+ self.trans:write(JSONNode.StringDelimiter)
+end
+
+function TJSONProtocol:writeJSONBase64(str)
+ self:writeElemSeparator()
+ self.trans:write(JSONNode.StringDelimiter)
+ local length = string.len(str)
+ local offset = 1
+ while length >= 3 do
+ -- Encode 3 bytes at a time
+ local bytes = base64_encode(string.sub(str, offset, offset+3))
+ self.trans:write(bytes)
+ length = length - 3
+ offset = offset + 3
+ end
+ if length > 0 then
+ local bytes = base64_encode(string.sub(str, offset, offset+length))
+ self.trans:write(bytes)
+ end
+ self.trans:write(JSONNode.StringDelimiter)
+end
+
+function TJSONProtocol:writeJSONInteger(num)
+ self:writeElemSeparator()
+ if self:escapeNum() then
+ self.trans:write(JSONNode.StringDelimiter)
+ end
+ local numstr = "" .. num
+ numstr = string.sub(numstr, string.find(numstr, "^[+-]?%d+"))
+ self.trans:write(numstr)
+ if self:escapeNum() then
+ self.trans:write(JSONNode.StringDelimiter)
+ end
+end
+
+function TJSONProtocol:writeJSONDouble(dub)
+ self:writeElemSeparator()
+ local val = "" .. dub
+ local prefix = string.sub(val, 1, 1)
+ local special = false
+ if prefix == 'N' or prefix == 'n' then
+ val = JSONNode.Nan
+ special = true
+ elseif prefix == 'I' or prefix == 'i' then
+ val = JSONNode.Infinity
+ special = true
+ elseif prefix == '-' then
+ local secondByte = string.sub(val, 2, 2)
+ if secondByte == 'I' or secondByte == 'i' then
+ val = JSONNode.NegativeInfinity
+ special = true
+ end
+ end
+
+ if special or self:escapeNum() then
+ self.trans:write(JSONNode.StringDelimiter)
+ end
+ self.trans:write(val)
+ if special or self:escapeNum() then
+ self.trans:write(JSONNode.StringDelimiter)
+ end
+end
+
+function TJSONProtocol:writeJSONObjectBegin()
+ self:writeElemSeparator()
+ self.trans:write(JSONNode.ObjectBegin)
+ self:contextPush({first = true, colon = true, ttype = 1, null = false})
+end
+
+function TJSONProtocol:writeJSONObjectEnd()
+ self:contextPop()
+ self.trans:write(JSONNode.ObjectEnd)
+end
+
+function TJSONProtocol:writeJSONArrayBegin()
+ self:writeElemSeparator()
+ self.trans:write(JSONNode.ArrayBegin)
+ self:contextPush({first = true, colon = true, ttype = 2, null = false})
+end
+
+function TJSONProtocol:writeJSONArrayEnd()
+ self:contextPop()
+ self.trans:write(JSONNode.ArrayEnd)
+end
+
+function TJSONProtocol:writeMessageBegin(name, ttype, seqid)
+ self:resetContext()
+ self:writeJSONArrayBegin()
+ self:writeJSONInteger(TJSONProtocol.THRIFT_JSON_PROTOCOL_VERSION)
+ self:writeJSONString(name)
+ self:writeJSONInteger(ttype)
+ self:writeJSONInteger(seqid)
+end
+
+function TJSONProtocol:writeMessageEnd()
+ self:writeJSONArrayEnd()
+end
+
+function TJSONProtocol:writeStructBegin(name)
+ self:writeJSONObjectBegin()
+end
+
+function TJSONProtocol:writeStructEnd()
+ self:writeJSONObjectEnd()
+end
+
+function TJSONProtocol:writeFieldBegin(name, ttype, id)
+ self:writeJSONInteger(id)
+ self:writeJSONObjectBegin()
+ self:writeJSONString(TTypeToString[ttype])
+end
+
+function TJSONProtocol:writeFieldEnd()
+ self:writeJSONObjectEnd()
+end
+
+function TJSONProtocol:writeFieldStop()
+end
+
+function TJSONProtocol:writeMapBegin(ktype, vtype, size)
+ self:writeJSONArrayBegin()
+ self:writeJSONString(TTypeToString[ktype])
+ self:writeJSONString(TTypeToString[vtype])
+ self:writeJSONInteger(size)
+ return self:writeJSONObjectBegin()
+end
+
+function TJSONProtocol:writeMapEnd()
+ self:writeJSONObjectEnd()
+ self:writeJSONArrayEnd()
+end
+
+function TJSONProtocol:writeListBegin(etype, size)
+ self:writeJSONArrayBegin()
+ self:writeJSONString(TTypeToString[etype])
+ self:writeJSONInteger(size)
+end
+
+function TJSONProtocol:writeListEnd()
+ self:writeJSONArrayEnd()
+end
+
+function TJSONProtocol:writeSetBegin(etype, size)
+ self:writeJSONArrayBegin()
+ self:writeJSONString(TTypeToString[etype])
+ self:writeJSONInteger(size)
+end
+
+function TJSONProtocol:writeSetEnd()
+ self:writeJSONArrayEnd()
+end
+
+function TJSONProtocol:writeBool(bool)
+ if bool then
+ self:writeJSONInteger(1)
+ else
+ self:writeJSONInteger(0)
+ end
+end
+
+function TJSONProtocol:writeByte(byte)
+ local buff = libluabpack.bpack('c', byte)
+ local val = libluabpack.bunpack('c', buff)
+ self:writeJSONInteger(val)
+end
+
+function TJSONProtocol:writeI16(i16)
+ local buff = libluabpack.bpack('s', i16)
+ local val = libluabpack.bunpack('s', buff)
+ self:writeJSONInteger(val)
+end
+
+function TJSONProtocol:writeI32(i32)
+ local buff = libluabpack.bpack('i', i32)
+ local val = libluabpack.bunpack('i', buff)
+ self:writeJSONInteger(val)
+end
+
+function TJSONProtocol:writeI64(i64)
+ local buff = libluabpack.bpack('l', i64)
+ local val = libluabpack.bunpack('l', buff)
+ self:writeJSONInteger(tostring(val))
+end
+
+function TJSONProtocol:writeDouble(dub)
+ self:writeJSONDouble(string.format("%.16f", dub))
+end
+
+function TJSONProtocol:writeString(str)
+ self:writeJSONString(str)
+end
+
+function TJSONProtocol:writeBinary(str)
+ -- Should be utf-8
+ self:writeJSONBase64(str)
+end
+
+function TJSONProtocol:readJSONSyntaxChar(ch)
+ local ch2 = ""
+ if self.hasReadByte ~= "" then
+ ch2 = self.hasReadByte
+ self.hasReadByte = ""
+ else
+ ch2 = self.trans:readAll(1)
+ end
+ if ch2 ~= ch then
+ terror(TProtocolException:new{message = "Expected ".. ch .. ", got " .. ch2})
+ end
+end
+
+function TJSONProtocol:readElemSeparator()
+ if self.jsonContextVal.null then
+ return
+ end
+ if self.jsonContextVal.first then
+ self.jsonContextVal.first = false
+ else
+ if self.jsonContextVal.ttype == 1 then
+ if self.jsonContextVal.colon then
+ self:readJSONSyntaxChar(JSONNode.PairSeparator)
+ self.jsonContextVal.colon = false
+ else
+ self:readJSONSyntaxChar(JSONNode.ElemSeparator)
+ self.jsonContextVal.colon = true
+ end
+ else
+ self:readJSONSyntaxChar(JSONNode.ElemSeparator)
+ end
+ end
+end
+
+function TJSONProtocol:hexVal(ch)
+ local val = string.byte(ch)
+ if val >= 48 and val <= 57 then
+ return val - 48
+ elseif val >= 97 and val <= 102 then
+ return val - 87
+ else
+ terror(TProtocolException:new{message = "Expected hex val ([0-9a-f]); got " .. ch})
+ end
+end
+
+function TJSONProtocol:readJSONEscapeChar(ch)
+ self:readJSONSyntaxChar(JSONNode.ZeroChar)
+ self:readJSONSyntaxChar(JSONNode.ZeroChar)
+ local b1 = self.trans:readAll(1)
+ local b2 = self.trans:readAll(1)
+ return libluabitwise.shiftl(self:hexVal(b1), 4) + self:hexVal(b2)
+end
+
+
+function TJSONProtocol:readJSONString()
+ self:readElemSeparator()
+ self:readJSONSyntaxChar(JSONNode.StringDelimiter)
+ local result = ""
+ while true do
+ local ch = self.trans:readAll(1)
+ if ch == JSONNode.StringDelimiter then
+ break
+ end
+ if ch == JSONNode.Backslash then
+ ch = self.trans:readAll(1)
+ if ch == JSONNode.EscapeChar then
+ self:readJSONEscapeChar(ch)
+ else
+ local pos, _ = string.find(JSONNode.EscapeChars, ch)
+ if pos == nil then
+ terror(TProtocolException:new{message = "Expected control char, got " .. ch})
+ end
+ ch = EscapeCharVals[pos]
+ end
+ end
+ result = result .. ch
+ end
+ return result
+end
+
+function TJSONProtocol:readJSONBase64()
+ local result = self:readJSONString()
+ local length = string.len(result)
+ local str = ""
+ local offset = 1
+ while length >= 4 do
+ local bytes = string.sub(result, offset, offset+4)
+ str = str .. base64_decode(bytes)
+ offset = offset + 4
+ length = length - 4
+ end
+ if length >= 0 then
+ str = str .. base64_decode(string.sub(result, offset, offset + length))
+ end
+ return str
+end
+
+function TJSONProtocol:readJSONNumericChars()
+ local result = ""
+ while true do
+ local ch = self.trans:readAll(1)
+ if string.find(ch, '[-+0-9.Ee]') then
+ result = result .. ch
+ else
+ self.hasReadByte = ch
+ break
+ end
+ end
+ return result
+end
+
+function TJSONProtocol:readJSONLongInteger()
+ self:readElemSeparator()
+ if self:escapeNum() then
+ self:readJSONSyntaxChar(JSONNode.StringDelimiter)
+ end
+ local result = self:readJSONNumericChars()
+ if self:escapeNum() then
+ self:readJSONSyntaxChar(JSONNode.StringDelimiter)
+ end
+ return result
+end
+
+function TJSONProtocol:readJSONInteger()
+ return tonumber(self:readJSONLongInteger())
+end
+
+function TJSONProtocol:readJSONDouble()
+ self:readElemSeparator()
+ local delimiter = self.trans:readAll(1)
+ local num = 0.0
+ if delimiter == JSONNode.StringDelimiter then
+ local str = self:readJSONString()
+ if str == JSONNode.Nan then
+ num = 1.0
+ elseif str == JSONNode.Infinity then
+ num = math.maxinteger
+ elseif str == JSONNode.NegativeInfinity then
+ num = math.mininteger
+ else
+ num = tonumber(str)
+ end
+ else
+ if self:escapeNum() then
+ self:readJSONSyntaxChar(JSONNode.StringDelimiter)
+ end
+ local result = self:readJSONNumericChars()
+ num = tonumber(delimiter.. result)
+ end
+ return num
+end
+
+function TJSONProtocol:readJSONObjectBegin()
+ self:readElemSeparator()
+ self:readJSONSyntaxChar(JSONNode.ObjectBegin)
+ self:contextPush({first = true, colon = true, ttype = 1, null = false})
+end
+
+function TJSONProtocol:readJSONObjectEnd()
+ self:readJSONSyntaxChar(JSONNode.ObjectEnd)
+ self:contextPop()
+end
+
+function TJSONProtocol:readJSONArrayBegin()
+ self:readElemSeparator()
+ self:readJSONSyntaxChar(JSONNode.ArrayBegin)
+ self:contextPush({first = true, colon = true, ttype = 2, null = false})
+end
+
+function TJSONProtocol:readJSONArrayEnd()
+ self:readJSONSyntaxChar(JSONNode.ArrayEnd)
+ self:contextPop()
+end
+
+function TJSONProtocol:readMessageBegin()
+ self:resetContext()
+ self:readJSONArrayBegin()
+ local version = self:readJSONInteger()
+ if version ~= self.THRIFT_JSON_PROTOCOL_VERSION then
+ terror(TProtocolException:new{message = "Message contained bad version."})
+ end
+ local name = self:readJSONString()
+ local ttype = self:readJSONInteger()
+ local seqid = self:readJSONInteger()
+ return name, ttype, seqid
+end
+
+function TJSONProtocol:readMessageEnd()
+ self:readJSONArrayEnd()
+end
+
+function TJSONProtocol:readStructBegin()
+ self:readJSONObjectBegin()
+ return nil
+end
+
+function TJSONProtocol:readStructEnd()
+ self:readJSONObjectEnd()
+end
+
+function TJSONProtocol:readFieldBegin()
+ local ttype = TType.STOP
+ local id = 0
+ local ch = self.trans:readAll(1)
+ self.hasReadByte = ch
+ if ch ~= JSONNode.ObjectEnd then
+ id = self:readJSONInteger()
+ self:readJSONObjectBegin()
+ local typeName = self:readJSONString()
+ ttype = StringToTType[typeName]
+ end
+ return nil, ttype, id
+end
+
+function TJSONProtocol:readFieldEnd()
+ self:readJSONObjectEnd()
+end
+
+function TJSONProtocol:readMapBegin()
+ self:readJSONArrayBegin()
+ local typeName = self:readJSONString()
+ local ktype = StringToTType[typeName]
+ typeName = self:readJSONString()
+ local vtype = StringToTType[typeName]
+ local size = self:readJSONInteger()
+ self:readJSONObjectBegin()
+ return ktype, vtype, size
+end
+
+function TJSONProtocol:readMapEnd()
+ self:readJSONObjectEnd()
+ self:readJSONArrayEnd()
+end
+
+function TJSONProtocol:readListBegin()
+ self:readJSONArrayBegin()
+ local typeName = self:readJSONString()
+ local etype = StringToTType[typeName]
+ local size = self:readJSONInteger()
+ return etype, size
+end
+
+function TJSONProtocol:readListEnd()
+ return self:readJSONArrayEnd()
+end
+
+function TJSONProtocol:readSetBegin()
+ return self:readListBegin()
+end
+
+function TJSONProtocol:readSetEnd()
+ return self:readJSONArrayEnd()
+end
+
+function TJSONProtocol:readBool()
+ local result = self:readJSONInteger()
+ if result == 1 then
+ return true
+ else
+ return false
+ end
+end
+
+function TJSONProtocol:readByte()
+ local result = self:readJSONInteger()
+ if result >= 256 then
+ terror(TProtocolException:new{message = "UnExpected Byte " .. result})
+ end
+ return result
+end
+
+function TJSONProtocol:readI16()
+ return self:readJSONInteger()
+end
+
+function TJSONProtocol:readI32()
+ return self:readJSONInteger()
+end
+
+function TJSONProtocol:readI64()
+ local long = liblualongnumber.new
+ return long(self:readJSONLongInteger())
+end
+
+function TJSONProtocol:readDouble()
+ return self:readJSONDouble()
+end
+
+function TJSONProtocol:readString()
+ return self:readJSONString()
+end
+
+function TJSONProtocol:readBinary()
+ return self:readJSONBase64()
+end
+
+TJSONProtocolFactory = TProtocolFactory:new{
+ __type = 'TJSONProtocolFactory',
+}
+
+function TJSONProtocolFactory:getProtocol(trans)
+ -- TODO Enforce that this must be a transport class (ie not a bool)
+ if not trans then
+ terror(TProtocolException:new{
+ message = 'Must supply a transport to ' .. ttype(self)
+ })
+ end
+ return TJSONProtocol:new{
+ trans = trans
+ }
+end