/* * 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: \"", 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 }