Files
kata-containers/vendor/github.com/uber/jaeger-client-go/thrift/simple_json_protocol.go
James O. D. Hunt 3a1bbd0271 tracing: Add initial opentracing support
Add initial support for opentracing by using the `jaeger` package.
Since opentracing uses the `context` package, add a `context.Context`
as the first parameter to all the functions that we might want to
trace. Trace "spans" (trace points) are then added by extracting the
trace details from the specified context parameter.

Notes:

- Although the tracer is created in `main()`, the "root span"
  (aka the first trace point) is not added until `beforeSubcommands()`.

  This is by design and is a compromise: by delaying the creation of the
  root span, the spans become much more readable since using the web-based
  JaegerUI, you will see traces like this:

  ```
  kata-runtime: kata-runtime create
  ------------  -------------------
       ^                ^
       |                |
  Trace name        First span name
                    (which clearly shows the CLI command that was run)
  ```

  Creating the span earlier means it is necessary to expand 'n' spans in
  the UI before you get to see the name of the CLI command that was run.
  In adding support, this became very tedious, hence my design decision to
  defer the creation of the root span until after signal handling has been
  setup and after CLI options have been parsed, but still very early in
  the code path.

  - At this stage, the tracing stops at the `virtcontainers` call
  boundary.

- Tracing is "always on" as there doesn't appear to be a way to toggle
  it. However, its resolves to a "nop" unless the tracer can talk to a
  jaeger agent.

Note that this commit required a bit of rework to `beforeSubcommands()`
to reduce the cyclomatic complexity.

Fixes #557.

Signed-off-by: James O. D. Hunt <james.o.hunt@intel.com>
2018-08-10 16:13:48 +01:00

1338 lines
35 KiB
Go

/*
* 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.
*/
package thrift
import (
"bufio"
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"math"
"strconv"
)
type _ParseContext int
const (
_CONTEXT_IN_TOPLEVEL _ParseContext = 1
_CONTEXT_IN_LIST_FIRST _ParseContext = 2
_CONTEXT_IN_LIST _ParseContext = 3
_CONTEXT_IN_OBJECT_FIRST _ParseContext = 4
_CONTEXT_IN_OBJECT_NEXT_KEY _ParseContext = 5
_CONTEXT_IN_OBJECT_NEXT_VALUE _ParseContext = 6
)
func (p _ParseContext) String() string {
switch p {
case _CONTEXT_IN_TOPLEVEL:
return "TOPLEVEL"
case _CONTEXT_IN_LIST_FIRST:
return "LIST-FIRST"
case _CONTEXT_IN_LIST:
return "LIST"
case _CONTEXT_IN_OBJECT_FIRST:
return "OBJECT-FIRST"
case _CONTEXT_IN_OBJECT_NEXT_KEY:
return "OBJECT-NEXT-KEY"
case _CONTEXT_IN_OBJECT_NEXT_VALUE:
return "OBJECT-NEXT-VALUE"
}
return "UNKNOWN-PARSE-CONTEXT"
}
// JSON protocol implementation for thrift.
//
// This protocol produces/consumes a simple output format
// suitable for parsing by scripting languages. It should not be
// confused with the full-featured TJSONProtocol.
//
type TSimpleJSONProtocol struct {
trans TTransport
parseContextStack []int
dumpContext []int
writer *bufio.Writer
reader *bufio.Reader
}
// Constructor
func NewTSimpleJSONProtocol(t TTransport) *TSimpleJSONProtocol {
v := &TSimpleJSONProtocol{trans: t,
writer: bufio.NewWriter(t),
reader: bufio.NewReader(t),
}
v.parseContextStack = append(v.parseContextStack, int(_CONTEXT_IN_TOPLEVEL))
v.dumpContext = append(v.dumpContext, int(_CONTEXT_IN_TOPLEVEL))
return v
}
// Factory
type TSimpleJSONProtocolFactory struct{}
func (p *TSimpleJSONProtocolFactory) GetProtocol(trans TTransport) TProtocol {
return NewTSimpleJSONProtocol(trans)
}
func NewTSimpleJSONProtocolFactory() *TSimpleJSONProtocolFactory {
return &TSimpleJSONProtocolFactory{}
}
var (
JSON_COMMA []byte
JSON_COLON []byte
JSON_LBRACE []byte
JSON_RBRACE []byte
JSON_LBRACKET []byte
JSON_RBRACKET []byte
JSON_QUOTE byte
JSON_QUOTE_BYTES []byte
JSON_NULL []byte
JSON_TRUE []byte
JSON_FALSE []byte
JSON_INFINITY string
JSON_NEGATIVE_INFINITY string
JSON_NAN string
JSON_INFINITY_BYTES []byte
JSON_NEGATIVE_INFINITY_BYTES []byte
JSON_NAN_BYTES []byte
json_nonbase_map_elem_bytes []byte
)
func init() {
JSON_COMMA = []byte{','}
JSON_COLON = []byte{':'}
JSON_LBRACE = []byte{'{'}
JSON_RBRACE = []byte{'}'}
JSON_LBRACKET = []byte{'['}
JSON_RBRACKET = []byte{']'}
JSON_QUOTE = '"'
JSON_QUOTE_BYTES = []byte{'"'}
JSON_NULL = []byte{'n', 'u', 'l', 'l'}
JSON_TRUE = []byte{'t', 'r', 'u', 'e'}
JSON_FALSE = []byte{'f', 'a', 'l', 's', 'e'}
JSON_INFINITY = "Infinity"
JSON_NEGATIVE_INFINITY = "-Infinity"
JSON_NAN = "NaN"
JSON_INFINITY_BYTES = []byte{'I', 'n', 'f', 'i', 'n', 'i', 't', 'y'}
JSON_NEGATIVE_INFINITY_BYTES = []byte{'-', 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y'}
JSON_NAN_BYTES = []byte{'N', 'a', 'N'}
json_nonbase_map_elem_bytes = []byte{']', ',', '['}
}
func jsonQuote(s string) string {
b, _ := json.Marshal(s)
s1 := string(b)
return s1
}
func jsonUnquote(s string) (string, bool) {
s1 := new(string)
err := json.Unmarshal([]byte(s), s1)
return *s1, err == nil
}
func mismatch(expected, actual string) error {
return fmt.Errorf("Expected '%s' but found '%s' while parsing JSON.", expected, actual)
}
func (p *TSimpleJSONProtocol) WriteMessageBegin(name string, typeId TMessageType, seqId int32) error {
p.resetContextStack() // THRIFT-3735
if e := p.OutputListBegin(); e != nil {
return e
}
if e := p.WriteString(name); e != nil {
return e
}
if e := p.WriteByte(int8(typeId)); e != nil {
return e
}
if e := p.WriteI32(seqId); e != nil {
return e
}
return nil
}
func (p *TSimpleJSONProtocol) WriteMessageEnd() error {
return p.OutputListEnd()
}
func (p *TSimpleJSONProtocol) WriteStructBegin(name string) error {
if e := p.OutputObjectBegin(); e != nil {
return e
}
return nil
}
func (p *TSimpleJSONProtocol) WriteStructEnd() error {
return p.OutputObjectEnd()
}
func (p *TSimpleJSONProtocol) WriteFieldBegin(name string, typeId TType, id int16) error {
if e := p.WriteString(name); e != nil {
return e
}
return nil
}
func (p *TSimpleJSONProtocol) WriteFieldEnd() error {
//return p.OutputListEnd()
return nil
}
func (p *TSimpleJSONProtocol) WriteFieldStop() error { return nil }
func (p *TSimpleJSONProtocol) WriteMapBegin(keyType TType, valueType TType, size int) error {
if e := p.OutputListBegin(); e != nil {
return e
}
if e := p.WriteByte(int8(keyType)); e != nil {
return e
}
if e := p.WriteByte(int8(valueType)); e != nil {
return e
}
return p.WriteI32(int32(size))
}
func (p *TSimpleJSONProtocol) WriteMapEnd() error {
return p.OutputListEnd()
}
func (p *TSimpleJSONProtocol) WriteListBegin(elemType TType, size int) error {
return p.OutputElemListBegin(elemType, size)
}
func (p *TSimpleJSONProtocol) WriteListEnd() error {
return p.OutputListEnd()
}
func (p *TSimpleJSONProtocol) WriteSetBegin(elemType TType, size int) error {
return p.OutputElemListBegin(elemType, size)
}
func (p *TSimpleJSONProtocol) WriteSetEnd() error {
return p.OutputListEnd()
}
func (p *TSimpleJSONProtocol) WriteBool(b bool) error {
return p.OutputBool(b)
}
func (p *TSimpleJSONProtocol) WriteByte(b int8) error {
return p.WriteI32(int32(b))
}
func (p *TSimpleJSONProtocol) WriteI16(v int16) error {
return p.WriteI32(int32(v))
}
func (p *TSimpleJSONProtocol) WriteI32(v int32) error {
return p.OutputI64(int64(v))
}
func (p *TSimpleJSONProtocol) WriteI64(v int64) error {
return p.OutputI64(int64(v))
}
func (p *TSimpleJSONProtocol) WriteDouble(v float64) error {
return p.OutputF64(v)
}
func (p *TSimpleJSONProtocol) WriteString(v string) error {
return p.OutputString(v)
}
func (p *TSimpleJSONProtocol) WriteBinary(v []byte) error {
// JSON library only takes in a string,
// not an arbitrary byte array, to ensure bytes are transmitted
// efficiently we must convert this into a valid JSON string
// therefore we use base64 encoding to avoid excessive escaping/quoting
if e := p.OutputPreValue(); e != nil {
return e
}
if _, e := p.write(JSON_QUOTE_BYTES); e != nil {
return NewTProtocolException(e)
}
writer := base64.NewEncoder(base64.StdEncoding, p.writer)
if _, e := writer.Write(v); e != nil {
p.writer.Reset(p.trans) // THRIFT-3735
return NewTProtocolException(e)
}
if e := writer.Close(); e != nil {
return NewTProtocolException(e)
}
if _, e := p.write(JSON_QUOTE_BYTES); e != nil {
return NewTProtocolException(e)
}
return p.OutputPostValue()
}
// Reading methods.
func (p *TSimpleJSONProtocol) ReadMessageBegin() (name string, typeId TMessageType, seqId int32, err error) {
p.resetContextStack() // THRIFT-3735
if isNull, err := p.ParseListBegin(); isNull || err != nil {
return name, typeId, seqId, err
}
if name, err = p.ReadString(); err != nil {
return name, typeId, seqId, err
}
bTypeId, err := p.ReadByte()
typeId = TMessageType(bTypeId)
if err != nil {
return name, typeId, seqId, err
}
if seqId, err = p.ReadI32(); err != nil {
return name, typeId, seqId, err
}
return name, typeId, seqId, nil
}
func (p *TSimpleJSONProtocol) ReadMessageEnd() error {
return p.ParseListEnd()
}
func (p *TSimpleJSONProtocol) ReadStructBegin() (name string, err error) {
_, err = p.ParseObjectStart()
return "", err
}
func (p *TSimpleJSONProtocol) ReadStructEnd() error {
return p.ParseObjectEnd()
}
func (p *TSimpleJSONProtocol) ReadFieldBegin() (string, TType, int16, error) {
if err := p.ParsePreValue(); err != nil {
return "", STOP, 0, err
}
b, _ := p.reader.Peek(1)
if len(b) > 0 {
switch b[0] {
case JSON_RBRACE[0]:
return "", STOP, 0, nil
case JSON_QUOTE:
p.reader.ReadByte()
name, err := p.ParseStringBody()
// simplejson is not meant to be read back into thrift
// - see http://wiki.apache.org/thrift/ThriftUsageJava
// - use JSON instead
if err != nil {
return name, STOP, 0, err
}
return name, STOP, -1, p.ParsePostValue()
/*
if err = p.ParsePostValue(); err != nil {
return name, STOP, 0, err
}
if isNull, err := p.ParseListBegin(); isNull || err != nil {
return name, STOP, 0, err
}
bType, err := p.ReadByte()
thetype := TType(bType)
if err != nil {
return name, thetype, 0, err
}
id, err := p.ReadI16()
return name, thetype, id, err
*/
}
e := fmt.Errorf("Expected \"}\" or '\"', but found: '%s'", string(b))
return "", STOP, 0, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
return "", STOP, 0, NewTProtocolException(io.EOF)
}
func (p *TSimpleJSONProtocol) ReadFieldEnd() error {
return nil
//return p.ParseListEnd()
}
func (p *TSimpleJSONProtocol) ReadMapBegin() (keyType TType, valueType TType, size int, e error) {
if isNull, e := p.ParseListBegin(); isNull || e != nil {
return VOID, VOID, 0, e
}
// read keyType
bKeyType, e := p.ReadByte()
keyType = TType(bKeyType)
if e != nil {
return keyType, valueType, size, e
}
// read valueType
bValueType, e := p.ReadByte()
valueType = TType(bValueType)
if e != nil {
return keyType, valueType, size, e
}
// read size
iSize, err := p.ReadI64()
size = int(iSize)
return keyType, valueType, size, err
}
func (p *TSimpleJSONProtocol) ReadMapEnd() error {
return p.ParseListEnd()
}
func (p *TSimpleJSONProtocol) ReadListBegin() (elemType TType, size int, e error) {
return p.ParseElemListBegin()
}
func (p *TSimpleJSONProtocol) ReadListEnd() error {
return p.ParseListEnd()
}
func (p *TSimpleJSONProtocol) ReadSetBegin() (elemType TType, size int, e error) {
return p.ParseElemListBegin()
}
func (p *TSimpleJSONProtocol) ReadSetEnd() error {
return p.ParseListEnd()
}
func (p *TSimpleJSONProtocol) ReadBool() (bool, error) {
var value bool
if err := p.ParsePreValue(); err != nil {
return value, err
}
f, _ := p.reader.Peek(1)
if len(f) > 0 {
switch f[0] {
case JSON_TRUE[0]:
b := make([]byte, len(JSON_TRUE))
_, err := p.reader.Read(b)
if err != nil {
return false, NewTProtocolException(err)
}
if string(b) == string(JSON_TRUE) {
value = true
} else {
e := fmt.Errorf("Expected \"true\" but found: %s", string(b))
return value, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
break
case JSON_FALSE[0]:
b := make([]byte, len(JSON_FALSE))
_, err := p.reader.Read(b)
if err != nil {
return false, NewTProtocolException(err)
}
if string(b) == string(JSON_FALSE) {
value = false
} else {
e := fmt.Errorf("Expected \"false\" but found: %s", string(b))
return value, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
break
case JSON_NULL[0]:
b := make([]byte, len(JSON_NULL))
_, err := p.reader.Read(b)
if err != nil {
return false, NewTProtocolException(err)
}
if string(b) == string(JSON_NULL) {
value = false
} else {
e := fmt.Errorf("Expected \"null\" but found: %s", string(b))
return value, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
default:
e := fmt.Errorf("Expected \"true\", \"false\", or \"null\" but found: %s", string(f))
return value, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
}
return value, p.ParsePostValue()
}
func (p *TSimpleJSONProtocol) ReadByte() (int8, error) {
v, err := p.ReadI64()
return int8(v), err
}
func (p *TSimpleJSONProtocol) ReadI16() (int16, error) {
v, err := p.ReadI64()
return int16(v), err
}
func (p *TSimpleJSONProtocol) ReadI32() (int32, error) {
v, err := p.ReadI64()
return int32(v), err
}
func (p *TSimpleJSONProtocol) ReadI64() (int64, error) {
v, _, err := p.ParseI64()
return v, err
}
func (p *TSimpleJSONProtocol) ReadDouble() (float64, error) {
v, _, err := p.ParseF64()
return v, err
}
func (p *TSimpleJSONProtocol) ReadString() (string, error) {
var v string
if err := p.ParsePreValue(); err != nil {
return v, err
}
f, _ := p.reader.Peek(1)
if len(f) > 0 && f[0] == JSON_QUOTE {
p.reader.ReadByte()
value, err := p.ParseStringBody()
v = value
if err != nil {
return v, err
}
} else if len(f) > 0 && f[0] == JSON_NULL[0] {
b := make([]byte, len(JSON_NULL))
_, err := p.reader.Read(b)
if err != nil {
return v, NewTProtocolException(err)
}
if string(b) != string(JSON_NULL) {
e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(b))
return v, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
} else {
e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(f))
return v, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
return v, p.ParsePostValue()
}
func (p *TSimpleJSONProtocol) ReadBinary() ([]byte, error) {
var v []byte
if err := p.ParsePreValue(); err != nil {
return nil, err
}
f, _ := p.reader.Peek(1)
if len(f) > 0 && f[0] == JSON_QUOTE {
p.reader.ReadByte()
value, err := p.ParseBase64EncodedBody()
v = value
if err != nil {
return v, err
}
} else if len(f) > 0 && f[0] == JSON_NULL[0] {
b := make([]byte, len(JSON_NULL))
_, err := p.reader.Read(b)
if err != nil {
return v, NewTProtocolException(err)
}
if string(b) != string(JSON_NULL) {
e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(b))
return v, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
} else {
e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(f))
return v, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
return v, p.ParsePostValue()
}
func (p *TSimpleJSONProtocol) Flush() (err error) {
return NewTProtocolException(p.writer.Flush())
}
func (p *TSimpleJSONProtocol) Skip(fieldType TType) (err error) {
return SkipDefaultDepth(p, fieldType)
}
func (p *TSimpleJSONProtocol) Transport() TTransport {
return p.trans
}
func (p *TSimpleJSONProtocol) OutputPreValue() error {
cxt := _ParseContext(p.dumpContext[len(p.dumpContext)-1])
switch cxt {
case _CONTEXT_IN_LIST, _CONTEXT_IN_OBJECT_NEXT_KEY:
if _, e := p.write(JSON_COMMA); e != nil {
return NewTProtocolException(e)
}
break
case _CONTEXT_IN_OBJECT_NEXT_VALUE:
if _, e := p.write(JSON_COLON); e != nil {
return NewTProtocolException(e)
}
break
}
return nil
}
func (p *TSimpleJSONProtocol) OutputPostValue() error {
cxt := _ParseContext(p.dumpContext[len(p.dumpContext)-1])
switch cxt {
case _CONTEXT_IN_LIST_FIRST:
p.dumpContext = p.dumpContext[:len(p.dumpContext)-1]
p.dumpContext = append(p.dumpContext, int(_CONTEXT_IN_LIST))
break
case _CONTEXT_IN_OBJECT_FIRST:
p.dumpContext = p.dumpContext[:len(p.dumpContext)-1]
p.dumpContext = append(p.dumpContext, int(_CONTEXT_IN_OBJECT_NEXT_VALUE))
break
case _CONTEXT_IN_OBJECT_NEXT_KEY:
p.dumpContext = p.dumpContext[:len(p.dumpContext)-1]
p.dumpContext = append(p.dumpContext, int(_CONTEXT_IN_OBJECT_NEXT_VALUE))
break
case _CONTEXT_IN_OBJECT_NEXT_VALUE:
p.dumpContext = p.dumpContext[:len(p.dumpContext)-1]
p.dumpContext = append(p.dumpContext, int(_CONTEXT_IN_OBJECT_NEXT_KEY))
break
}
return nil
}
func (p *TSimpleJSONProtocol) OutputBool(value bool) error {
if e := p.OutputPreValue(); e != nil {
return e
}
var v string
if value {
v = string(JSON_TRUE)
} else {
v = string(JSON_FALSE)
}
switch _ParseContext(p.dumpContext[len(p.dumpContext)-1]) {
case _CONTEXT_IN_OBJECT_FIRST, _CONTEXT_IN_OBJECT_NEXT_KEY:
v = jsonQuote(v)
default:
}
if e := p.OutputStringData(v); e != nil {
return e
}
return p.OutputPostValue()
}
func (p *TSimpleJSONProtocol) OutputNull() error {
if e := p.OutputPreValue(); e != nil {
return e
}
if _, e := p.write(JSON_NULL); e != nil {
return NewTProtocolException(e)
}
return p.OutputPostValue()
}
func (p *TSimpleJSONProtocol) OutputF64(value float64) error {
if e := p.OutputPreValue(); e != nil {
return e
}
var v string
if math.IsNaN(value) {
v = string(JSON_QUOTE) + JSON_NAN + string(JSON_QUOTE)
} else if math.IsInf(value, 1) {
v = string(JSON_QUOTE) + JSON_INFINITY + string(JSON_QUOTE)
} else if math.IsInf(value, -1) {
v = string(JSON_QUOTE) + JSON_NEGATIVE_INFINITY + string(JSON_QUOTE)
} else {
v = strconv.FormatFloat(value, 'g', -1, 64)
switch _ParseContext(p.dumpContext[len(p.dumpContext)-1]) {
case _CONTEXT_IN_OBJECT_FIRST, _CONTEXT_IN_OBJECT_NEXT_KEY:
v = string(JSON_QUOTE) + v + string(JSON_QUOTE)
default:
}
}
if e := p.OutputStringData(v); e != nil {
return e
}
return p.OutputPostValue()
}
func (p *TSimpleJSONProtocol) OutputI64(value int64) error {
if e := p.OutputPreValue(); e != nil {
return e
}
v := strconv.FormatInt(value, 10)
switch _ParseContext(p.dumpContext[len(p.dumpContext)-1]) {
case _CONTEXT_IN_OBJECT_FIRST, _CONTEXT_IN_OBJECT_NEXT_KEY:
v = jsonQuote(v)
default:
}
if e := p.OutputStringData(v); e != nil {
return e
}
return p.OutputPostValue()
}
func (p *TSimpleJSONProtocol) OutputString(s string) error {
if e := p.OutputPreValue(); e != nil {
return e
}
if e := p.OutputStringData(jsonQuote(s)); e != nil {
return e
}
return p.OutputPostValue()
}
func (p *TSimpleJSONProtocol) OutputStringData(s string) error {
_, e := p.write([]byte(s))
return NewTProtocolException(e)
}
func (p *TSimpleJSONProtocol) OutputObjectBegin() error {
if e := p.OutputPreValue(); e != nil {
return e
}
if _, e := p.write(JSON_LBRACE); e != nil {
return NewTProtocolException(e)
}
p.dumpContext = append(p.dumpContext, int(_CONTEXT_IN_OBJECT_FIRST))
return nil
}
func (p *TSimpleJSONProtocol) OutputObjectEnd() error {
if _, e := p.write(JSON_RBRACE); e != nil {
return NewTProtocolException(e)
}
p.dumpContext = p.dumpContext[:len(p.dumpContext)-1]
if e := p.OutputPostValue(); e != nil {
return e
}
return nil
}
func (p *TSimpleJSONProtocol) OutputListBegin() error {
if e := p.OutputPreValue(); e != nil {
return e
}
if _, e := p.write(JSON_LBRACKET); e != nil {
return NewTProtocolException(e)
}
p.dumpContext = append(p.dumpContext, int(_CONTEXT_IN_LIST_FIRST))
return nil
}
func (p *TSimpleJSONProtocol) OutputListEnd() error {
if _, e := p.write(JSON_RBRACKET); e != nil {
return NewTProtocolException(e)
}
p.dumpContext = p.dumpContext[:len(p.dumpContext)-1]
if e := p.OutputPostValue(); e != nil {
return e
}
return nil
}
func (p *TSimpleJSONProtocol) OutputElemListBegin(elemType TType, size int) error {
if e := p.OutputListBegin(); e != nil {
return e
}
if e := p.WriteByte(int8(elemType)); e != nil {
return e
}
if e := p.WriteI64(int64(size)); e != nil {
return e
}
return nil
}
func (p *TSimpleJSONProtocol) ParsePreValue() error {
if e := p.readNonSignificantWhitespace(); e != nil {
return NewTProtocolException(e)
}
cxt := _ParseContext(p.parseContextStack[len(p.parseContextStack)-1])
b, _ := p.reader.Peek(1)
switch cxt {
case _CONTEXT_IN_LIST:
if len(b) > 0 {
switch b[0] {
case JSON_RBRACKET[0]:
return nil
case JSON_COMMA[0]:
p.reader.ReadByte()
if e := p.readNonSignificantWhitespace(); e != nil {
return NewTProtocolException(e)
}
return nil
default:
e := fmt.Errorf("Expected \"]\" or \",\" in list context, but found \"%s\"", string(b))
return NewTProtocolExceptionWithType(INVALID_DATA, e)
}
}
break
case _CONTEXT_IN_OBJECT_NEXT_KEY:
if len(b) > 0 {
switch b[0] {
case JSON_RBRACE[0]:
return nil
case JSON_COMMA[0]:
p.reader.ReadByte()
if e := p.readNonSignificantWhitespace(); e != nil {
return NewTProtocolException(e)
}
return nil
default:
e := fmt.Errorf("Expected \"}\" or \",\" in object context, but found \"%s\"", string(b))
return NewTProtocolExceptionWithType(INVALID_DATA, e)
}
}
break
case _CONTEXT_IN_OBJECT_NEXT_VALUE:
if len(b) > 0 {
switch b[0] {
case JSON_COLON[0]:
p.reader.ReadByte()
if e := p.readNonSignificantWhitespace(); e != nil {
return NewTProtocolException(e)
}
return nil
default:
e := fmt.Errorf("Expected \":\" in object context, but found \"%s\"", string(b))
return NewTProtocolExceptionWithType(INVALID_DATA, e)
}
}
break
}
return nil
}
func (p *TSimpleJSONProtocol) ParsePostValue() error {
if e := p.readNonSignificantWhitespace(); e != nil {
return NewTProtocolException(e)
}
cxt := _ParseContext(p.parseContextStack[len(p.parseContextStack)-1])
switch cxt {
case _CONTEXT_IN_LIST_FIRST:
p.parseContextStack = p.parseContextStack[:len(p.parseContextStack)-1]
p.parseContextStack = append(p.parseContextStack, int(_CONTEXT_IN_LIST))
break
case _CONTEXT_IN_OBJECT_FIRST, _CONTEXT_IN_OBJECT_NEXT_KEY:
p.parseContextStack = p.parseContextStack[:len(p.parseContextStack)-1]
p.parseContextStack = append(p.parseContextStack, int(_CONTEXT_IN_OBJECT_NEXT_VALUE))
break
case _CONTEXT_IN_OBJECT_NEXT_VALUE:
p.parseContextStack = p.parseContextStack[:len(p.parseContextStack)-1]
p.parseContextStack = append(p.parseContextStack, int(_CONTEXT_IN_OBJECT_NEXT_KEY))
break
}
return nil
}
func (p *TSimpleJSONProtocol) readNonSignificantWhitespace() error {
for {
b, _ := p.reader.Peek(1)
if len(b) < 1 {
return nil
}
switch b[0] {
case ' ', '\r', '\n', '\t':
p.reader.ReadByte()
continue
default:
break
}
break
}
return nil
}
func (p *TSimpleJSONProtocol) ParseStringBody() (string, error) {
line, err := p.reader.ReadString(JSON_QUOTE)
if err != nil {
return "", NewTProtocolException(err)
}
l := len(line)
// count number of escapes to see if we need to keep going
i := 1
for ; i < l; i++ {
if line[l-i-1] != '\\' {
break
}
}
if i&0x01 == 1 {
v, ok := jsonUnquote(string(JSON_QUOTE) + line)
if !ok {
return "", NewTProtocolException(err)
}
return v, nil
}
s, err := p.ParseQuotedStringBody()
if err != nil {
return "", NewTProtocolException(err)
}
str := string(JSON_QUOTE) + line + s
v, ok := jsonUnquote(str)
if !ok {
e := fmt.Errorf("Unable to parse as JSON string %s", str)
return "", NewTProtocolExceptionWithType(INVALID_DATA, e)
}
return v, nil
}
func (p *TSimpleJSONProtocol) ParseQuotedStringBody() (string, error) {
line, err := p.reader.ReadString(JSON_QUOTE)
if err != nil {
return "", NewTProtocolException(err)
}
l := len(line)
// count number of escapes to see if we need to keep going
i := 1
for ; i < l; i++ {
if line[l-i-1] != '\\' {
break
}
}
if i&0x01 == 1 {
return line, nil
}
s, err := p.ParseQuotedStringBody()
if err != nil {
return "", NewTProtocolException(err)
}
v := line + s
return v, nil
}
func (p *TSimpleJSONProtocol) ParseBase64EncodedBody() ([]byte, error) {
line, err := p.reader.ReadBytes(JSON_QUOTE)
if err != nil {
return line, NewTProtocolException(err)
}
line2 := line[0 : len(line)-1]
l := len(line2)
if (l % 4) != 0 {
pad := 4 - (l % 4)
fill := [...]byte{'=', '=', '='}
line2 = append(line2, fill[:pad]...)
l = len(line2)
}
output := make([]byte, base64.StdEncoding.DecodedLen(l))
n, err := base64.StdEncoding.Decode(output, line2)
return output[0:n], NewTProtocolException(err)
}
func (p *TSimpleJSONProtocol) ParseI64() (int64, bool, error) {
if err := p.ParsePreValue(); err != nil {
return 0, false, err
}
var value int64
var isnull bool
if p.safePeekContains(JSON_NULL) {
p.reader.Read(make([]byte, len(JSON_NULL)))
isnull = true
} else {
num, err := p.readNumeric()
isnull = (num == nil)
if !isnull {
value = num.Int64()
}
if err != nil {
return value, isnull, err
}
}
return value, isnull, p.ParsePostValue()
}
func (p *TSimpleJSONProtocol) ParseF64() (float64, bool, error) {
if err := p.ParsePreValue(); err != nil {
return 0, false, err
}
var value float64
var isnull bool
if p.safePeekContains(JSON_NULL) {
p.reader.Read(make([]byte, len(JSON_NULL)))
isnull = true
} else {
num, err := p.readNumeric()
isnull = (num == nil)
if !isnull {
value = num.Float64()
}
if err != nil {
return value, isnull, err
}
}
return value, isnull, p.ParsePostValue()
}
func (p *TSimpleJSONProtocol) ParseObjectStart() (bool, error) {
if err := p.ParsePreValue(); err != nil {
return false, err
}
var b []byte
b, err := p.reader.Peek(1)
if err != nil {
return false, err
}
if len(b) > 0 && b[0] == JSON_LBRACE[0] {
p.reader.ReadByte()
p.parseContextStack = append(p.parseContextStack, int(_CONTEXT_IN_OBJECT_FIRST))
return false, nil
} else if p.safePeekContains(JSON_NULL) {
return true, nil
}
e := fmt.Errorf("Expected '{' or null, but found '%s'", string(b))
return false, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
func (p *TSimpleJSONProtocol) ParseObjectEnd() error {
if isNull, err := p.readIfNull(); isNull || err != nil {
return err
}
cxt := _ParseContext(p.parseContextStack[len(p.parseContextStack)-1])
if (cxt != _CONTEXT_IN_OBJECT_FIRST) && (cxt != _CONTEXT_IN_OBJECT_NEXT_KEY) {
e := fmt.Errorf("Expected to be in the Object Context, but not in Object Context (%d)", cxt)
return NewTProtocolExceptionWithType(INVALID_DATA, e)
}
line, err := p.reader.ReadString(JSON_RBRACE[0])
if err != nil {
return NewTProtocolException(err)
}
for _, char := range line {
switch char {
default:
e := fmt.Errorf("Expecting end of object \"}\", but found: \"%s\"", line)
return NewTProtocolExceptionWithType(INVALID_DATA, e)
case ' ', '\n', '\r', '\t', '}':
break
}
}
p.parseContextStack = p.parseContextStack[:len(p.parseContextStack)-1]
return p.ParsePostValue()
}
func (p *TSimpleJSONProtocol) ParseListBegin() (isNull bool, err error) {
if e := p.ParsePreValue(); e != nil {
return false, e
}
var b []byte
b, err = p.reader.Peek(1)
if err != nil {
return false, err
}
if len(b) >= 1 && b[0] == JSON_LBRACKET[0] {
p.parseContextStack = append(p.parseContextStack, int(_CONTEXT_IN_LIST_FIRST))
p.reader.ReadByte()
isNull = false
} else if p.safePeekContains(JSON_NULL) {
isNull = true
} else {
err = fmt.Errorf("Expected \"null\" or \"[\", received %q", b)
}
return isNull, NewTProtocolExceptionWithType(INVALID_DATA, err)
}
func (p *TSimpleJSONProtocol) ParseElemListBegin() (elemType TType, size int, e error) {
if isNull, e := p.ParseListBegin(); isNull || e != nil {
return VOID, 0, e
}
bElemType, err := p.ReadByte()
elemType = TType(bElemType)
if err != nil {
return elemType, size, err
}
nSize, err2 := p.ReadI64()
size = int(nSize)
return elemType, size, err2
}
func (p *TSimpleJSONProtocol) ParseListEnd() error {
if isNull, err := p.readIfNull(); isNull || err != nil {
return err
}
cxt := _ParseContext(p.parseContextStack[len(p.parseContextStack)-1])
if cxt != _CONTEXT_IN_LIST {
e := fmt.Errorf("Expected to be in the List Context, but not in List Context (%d)", cxt)
return NewTProtocolExceptionWithType(INVALID_DATA, e)
}
line, err := p.reader.ReadString(JSON_RBRACKET[0])
if err != nil {
return NewTProtocolException(err)
}
for _, char := range line {
switch char {
default:
e := fmt.Errorf("Expecting end of list \"]\", but found: \"%s\"", line)
return NewTProtocolExceptionWithType(INVALID_DATA, e)
case ' ', '\n', '\r', '\t', rune(JSON_RBRACKET[0]):
break
}
}
p.parseContextStack = p.parseContextStack[:len(p.parseContextStack)-1]
if _ParseContext(p.parseContextStack[len(p.parseContextStack)-1]) == _CONTEXT_IN_TOPLEVEL {
return nil
}
return p.ParsePostValue()
}
func (p *TSimpleJSONProtocol) readSingleValue() (interface{}, TType, error) {
e := p.readNonSignificantWhitespace()
if e != nil {
return nil, VOID, NewTProtocolException(e)
}
b, e := p.reader.Peek(1)
if len(b) > 0 {
c := b[0]
switch c {
case JSON_NULL[0]:
buf := make([]byte, len(JSON_NULL))
_, e := p.reader.Read(buf)
if e != nil {
return nil, VOID, NewTProtocolException(e)
}
if string(JSON_NULL) != string(buf) {
e = mismatch(string(JSON_NULL), string(buf))
return nil, VOID, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
return nil, VOID, nil
case JSON_QUOTE:
p.reader.ReadByte()
v, e := p.ParseStringBody()
if e != nil {
return v, UTF8, NewTProtocolException(e)
}
if v == JSON_INFINITY {
return INFINITY, DOUBLE, nil
} else if v == JSON_NEGATIVE_INFINITY {
return NEGATIVE_INFINITY, DOUBLE, nil
} else if v == JSON_NAN {
return NAN, DOUBLE, nil
}
return v, UTF8, nil
case JSON_TRUE[0]:
buf := make([]byte, len(JSON_TRUE))
_, e := p.reader.Read(buf)
if e != nil {
return true, BOOL, NewTProtocolException(e)
}
if string(JSON_TRUE) != string(buf) {
e := mismatch(string(JSON_TRUE), string(buf))
return true, BOOL, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
return true, BOOL, nil
case JSON_FALSE[0]:
buf := make([]byte, len(JSON_FALSE))
_, e := p.reader.Read(buf)
if e != nil {
return false, BOOL, NewTProtocolException(e)
}
if string(JSON_FALSE) != string(buf) {
e := mismatch(string(JSON_FALSE), string(buf))
return false, BOOL, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
return false, BOOL, nil
case JSON_LBRACKET[0]:
_, e := p.reader.ReadByte()
return make([]interface{}, 0), LIST, NewTProtocolException(e)
case JSON_LBRACE[0]:
_, e := p.reader.ReadByte()
return make(map[string]interface{}), STRUCT, NewTProtocolException(e)
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'e', 'E', '.', '+', '-', JSON_INFINITY[0], JSON_NAN[0]:
// assume numeric
v, e := p.readNumeric()
return v, DOUBLE, e
default:
e := fmt.Errorf("Expected element in list but found '%s' while parsing JSON.", string(c))
return nil, VOID, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
}
e = fmt.Errorf("Cannot read a single element while parsing JSON.")
return nil, VOID, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
func (p *TSimpleJSONProtocol) readIfNull() (bool, error) {
cont := true
for cont {
b, _ := p.reader.Peek(1)
if len(b) < 1 {
return false, nil
}
switch b[0] {
default:
return false, nil
case JSON_NULL[0]:
cont = false
break
case ' ', '\n', '\r', '\t':
p.reader.ReadByte()
break
}
}
if p.safePeekContains(JSON_NULL) {
p.reader.Read(make([]byte, len(JSON_NULL)))
return true, nil
}
return false, nil
}
func (p *TSimpleJSONProtocol) readQuoteIfNext() {
b, _ := p.reader.Peek(1)
if len(b) > 0 && b[0] == JSON_QUOTE {
p.reader.ReadByte()
}
}
func (p *TSimpleJSONProtocol) readNumeric() (Numeric, error) {
isNull, err := p.readIfNull()
if isNull || err != nil {
return NUMERIC_NULL, err
}
hasDecimalPoint := false
nextCanBeSign := true
hasE := false
MAX_LEN := 40
buf := bytes.NewBuffer(make([]byte, 0, MAX_LEN))
continueFor := true
inQuotes := false
for continueFor {
c, err := p.reader.ReadByte()
if err != nil {
if err == io.EOF {
break
}
return NUMERIC_NULL, NewTProtocolException(err)
}
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
buf.WriteByte(c)
nextCanBeSign = false
case '.':
if hasDecimalPoint {
e := fmt.Errorf("Unable to parse number with multiple decimal points '%s.'", buf.String())
return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
if hasE {
e := fmt.Errorf("Unable to parse number with decimal points in the exponent '%s.'", buf.String())
return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
buf.WriteByte(c)
hasDecimalPoint, nextCanBeSign = true, false
case 'e', 'E':
if hasE {
e := fmt.Errorf("Unable to parse number with multiple exponents '%s%c'", buf.String(), c)
return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
buf.WriteByte(c)
hasE, nextCanBeSign = true, true
case '-', '+':
if !nextCanBeSign {
e := fmt.Errorf("Negative sign within number")
return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
buf.WriteByte(c)
nextCanBeSign = false
case ' ', 0, '\t', '\n', '\r', JSON_RBRACE[0], JSON_RBRACKET[0], JSON_COMMA[0], JSON_COLON[0]:
p.reader.UnreadByte()
continueFor = false
case JSON_NAN[0]:
if buf.Len() == 0 {
buffer := make([]byte, len(JSON_NAN))
buffer[0] = c
_, e := p.reader.Read(buffer[1:])
if e != nil {
return NUMERIC_NULL, NewTProtocolException(e)
}
if JSON_NAN != string(buffer) {
e := mismatch(JSON_NAN, string(buffer))
return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
if inQuotes {
p.readQuoteIfNext()
}
return NAN, nil
} else {
e := fmt.Errorf("Unable to parse number starting with character '%c'", c)
return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
case JSON_INFINITY[0]:
if buf.Len() == 0 || (buf.Len() == 1 && buf.Bytes()[0] == '+') {
buffer := make([]byte, len(JSON_INFINITY))
buffer[0] = c
_, e := p.reader.Read(buffer[1:])
if e != nil {
return NUMERIC_NULL, NewTProtocolException(e)
}
if JSON_INFINITY != string(buffer) {
e := mismatch(JSON_INFINITY, string(buffer))
return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
if inQuotes {
p.readQuoteIfNext()
}
return INFINITY, nil
} else if buf.Len() == 1 && buf.Bytes()[0] == JSON_NEGATIVE_INFINITY[0] {
buffer := make([]byte, len(JSON_NEGATIVE_INFINITY))
buffer[0] = JSON_NEGATIVE_INFINITY[0]
buffer[1] = c
_, e := p.reader.Read(buffer[2:])
if e != nil {
return NUMERIC_NULL, NewTProtocolException(e)
}
if JSON_NEGATIVE_INFINITY != string(buffer) {
e := mismatch(JSON_NEGATIVE_INFINITY, string(buffer))
return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
if inQuotes {
p.readQuoteIfNext()
}
return NEGATIVE_INFINITY, nil
} else {
e := fmt.Errorf("Unable to parse number starting with character '%c' due to existing buffer %s", c, buf.String())
return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
case JSON_QUOTE:
if !inQuotes {
inQuotes = true
} else {
break
}
default:
e := fmt.Errorf("Unable to parse number starting with character '%c'", c)
return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
}
if buf.Len() == 0 {
e := fmt.Errorf("Unable to parse number from empty string ''")
return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e)
}
return NewNumericFromJSONString(buf.String(), false), nil
}
// Safely peeks into the buffer, reading only what is necessary
func (p *TSimpleJSONProtocol) safePeekContains(b []byte) bool {
for i := 0; i < len(b); i++ {
a, _ := p.reader.Peek(i + 1)
if len(a) == 0 || a[i] != b[i] {
return false
}
}
return true
}
// Reset the context stack to its initial state.
func (p *TSimpleJSONProtocol) resetContextStack() {
p.parseContextStack = []int{int(_CONTEXT_IN_TOPLEVEL)}
p.dumpContext = []int{int(_CONTEXT_IN_TOPLEVEL)}
}
func (p *TSimpleJSONProtocol) write(b []byte) (int, error) {
n, err := p.writer.Write(b)
if err != nil {
p.writer.Reset(p.trans) // THRIFT-3735
}
return n, err
}