1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 *   http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20package thrift
21
22import (
23	"context"
24	"encoding/base64"
25	"fmt"
26)
27
28const (
29	THRIFT_JSON_PROTOCOL_VERSION = 1
30)
31
32// for references to _ParseContext see tsimplejson_protocol.go
33
34// JSON protocol implementation for thrift.
35// Utilizes Simple JSON protocol
36type TJSONProtocol struct {
37	*TSimpleJSONProtocol
38}
39
40// Constructor
41func NewTJSONProtocol(t TTransport) *TJSONProtocol {
42	v := &TJSONProtocol{TSimpleJSONProtocol: NewTSimpleJSONProtocol(t)}
43	v.parseContextStack.push(_CONTEXT_IN_TOPLEVEL)
44	v.dumpContext.push(_CONTEXT_IN_TOPLEVEL)
45	return v
46}
47
48// Factory
49type TJSONProtocolFactory struct{}
50
51func (p *TJSONProtocolFactory) GetProtocol(trans TTransport) TProtocol {
52	return NewTJSONProtocol(trans)
53}
54
55func NewTJSONProtocolFactory() *TJSONProtocolFactory {
56	return &TJSONProtocolFactory{}
57}
58
59func (p *TJSONProtocol) WriteMessageBegin(ctx context.Context, name string, typeId TMessageType, seqId int32) error {
60	p.resetContextStack() // THRIFT-3735
61	if e := p.OutputListBegin(); e != nil {
62		return e
63	}
64	if e := p.WriteI32(ctx, THRIFT_JSON_PROTOCOL_VERSION); e != nil {
65		return e
66	}
67	if e := p.WriteString(ctx, name); e != nil {
68		return e
69	}
70	if e := p.WriteByte(ctx, int8(typeId)); e != nil {
71		return e
72	}
73	if e := p.WriteI32(ctx, seqId); e != nil {
74		return e
75	}
76	return nil
77}
78
79func (p *TJSONProtocol) WriteMessageEnd(ctx context.Context) error {
80	return p.OutputListEnd()
81}
82
83func (p *TJSONProtocol) WriteStructBegin(ctx context.Context, name string) error {
84	if e := p.OutputObjectBegin(); e != nil {
85		return e
86	}
87	return nil
88}
89
90func (p *TJSONProtocol) WriteStructEnd(ctx context.Context) error {
91	return p.OutputObjectEnd()
92}
93
94func (p *TJSONProtocol) WriteFieldBegin(ctx context.Context, name string, typeId TType, id int16) error {
95	if e := p.WriteI16(ctx, id); e != nil {
96		return e
97	}
98	if e := p.OutputObjectBegin(); e != nil {
99		return e
100	}
101	s, e1 := p.TypeIdToString(typeId)
102	if e1 != nil {
103		return e1
104	}
105	if e := p.WriteString(ctx, s); e != nil {
106		return e
107	}
108	return nil
109}
110
111func (p *TJSONProtocol) WriteFieldEnd(ctx context.Context) error {
112	return p.OutputObjectEnd()
113}
114
115func (p *TJSONProtocol) WriteFieldStop(ctx context.Context) error { return nil }
116
117func (p *TJSONProtocol) WriteMapBegin(ctx context.Context, keyType TType, valueType TType, size int) error {
118	if e := p.OutputListBegin(); e != nil {
119		return e
120	}
121	s, e1 := p.TypeIdToString(keyType)
122	if e1 != nil {
123		return e1
124	}
125	if e := p.WriteString(ctx, s); e != nil {
126		return e
127	}
128	s, e1 = p.TypeIdToString(valueType)
129	if e1 != nil {
130		return e1
131	}
132	if e := p.WriteString(ctx, s); e != nil {
133		return e
134	}
135	if e := p.WriteI64(ctx, int64(size)); e != nil {
136		return e
137	}
138	return p.OutputObjectBegin()
139}
140
141func (p *TJSONProtocol) WriteMapEnd(ctx context.Context) error {
142	if e := p.OutputObjectEnd(); e != nil {
143		return e
144	}
145	return p.OutputListEnd()
146}
147
148func (p *TJSONProtocol) WriteListBegin(ctx context.Context, elemType TType, size int) error {
149	return p.OutputElemListBegin(elemType, size)
150}
151
152func (p *TJSONProtocol) WriteListEnd(ctx context.Context) error {
153	return p.OutputListEnd()
154}
155
156func (p *TJSONProtocol) WriteSetBegin(ctx context.Context, elemType TType, size int) error {
157	return p.OutputElemListBegin(elemType, size)
158}
159
160func (p *TJSONProtocol) WriteSetEnd(ctx context.Context) error {
161	return p.OutputListEnd()
162}
163
164func (p *TJSONProtocol) WriteBool(ctx context.Context, b bool) error {
165	if b {
166		return p.WriteI32(ctx, 1)
167	}
168	return p.WriteI32(ctx, 0)
169}
170
171func (p *TJSONProtocol) WriteByte(ctx context.Context, b int8) error {
172	return p.WriteI32(ctx, int32(b))
173}
174
175func (p *TJSONProtocol) WriteI16(ctx context.Context, v int16) error {
176	return p.WriteI32(ctx, int32(v))
177}
178
179func (p *TJSONProtocol) WriteI32(ctx context.Context, v int32) error {
180	return p.OutputI64(int64(v))
181}
182
183func (p *TJSONProtocol) WriteI64(ctx context.Context, v int64) error {
184	return p.OutputI64(int64(v))
185}
186
187func (p *TJSONProtocol) WriteDouble(ctx context.Context, v float64) error {
188	return p.OutputF64(v)
189}
190
191func (p *TJSONProtocol) WriteString(ctx context.Context, v string) error {
192	return p.OutputString(v)
193}
194
195func (p *TJSONProtocol) WriteBinary(ctx context.Context, v []byte) error {
196	// JSON library only takes in a string,
197	// not an arbitrary byte array, to ensure bytes are transmitted
198	// efficiently we must convert this into a valid JSON string
199	// therefore we use base64 encoding to avoid excessive escaping/quoting
200	if e := p.OutputPreValue(); e != nil {
201		return e
202	}
203	if _, e := p.write(JSON_QUOTE_BYTES); e != nil {
204		return NewTProtocolException(e)
205	}
206	writer := base64.NewEncoder(base64.StdEncoding, p.writer)
207	if _, e := writer.Write(v); e != nil {
208		p.writer.Reset(p.trans) // THRIFT-3735
209		return NewTProtocolException(e)
210	}
211	if e := writer.Close(); e != nil {
212		return NewTProtocolException(e)
213	}
214	if _, e := p.write(JSON_QUOTE_BYTES); e != nil {
215		return NewTProtocolException(e)
216	}
217	return p.OutputPostValue()
218}
219
220// Reading methods.
221func (p *TJSONProtocol) ReadMessageBegin(ctx context.Context) (name string, typeId TMessageType, seqId int32, err error) {
222	p.resetContextStack() // THRIFT-3735
223	if isNull, err := p.ParseListBegin(); isNull || err != nil {
224		return name, typeId, seqId, err
225	}
226	version, err := p.ReadI32(ctx)
227	if err != nil {
228		return name, typeId, seqId, err
229	}
230	if version != THRIFT_JSON_PROTOCOL_VERSION {
231		e := fmt.Errorf("Unknown Protocol version %d, expected version %d", version, THRIFT_JSON_PROTOCOL_VERSION)
232		return name, typeId, seqId, NewTProtocolExceptionWithType(INVALID_DATA, e)
233
234	}
235	if name, err = p.ReadString(ctx); err != nil {
236		return name, typeId, seqId, err
237	}
238	bTypeId, err := p.ReadByte(ctx)
239	typeId = TMessageType(bTypeId)
240	if err != nil {
241		return name, typeId, seqId, err
242	}
243	if seqId, err = p.ReadI32(ctx); err != nil {
244		return name, typeId, seqId, err
245	}
246	return name, typeId, seqId, nil
247}
248
249func (p *TJSONProtocol) ReadMessageEnd(ctx context.Context) error {
250	err := p.ParseListEnd()
251	return err
252}
253
254func (p *TJSONProtocol) ReadStructBegin(ctx context.Context) (name string, err error) {
255	_, err = p.ParseObjectStart()
256	return "", err
257}
258
259func (p *TJSONProtocol) ReadStructEnd(ctx context.Context) error {
260	return p.ParseObjectEnd()
261}
262
263func (p *TJSONProtocol) ReadFieldBegin(ctx context.Context) (string, TType, int16, error) {
264	b, _ := p.reader.Peek(1)
265	if len(b) < 1 || b[0] == JSON_RBRACE[0] || b[0] == JSON_RBRACKET[0] {
266		return "", STOP, -1, nil
267	}
268	fieldId, err := p.ReadI16(ctx)
269	if err != nil {
270		return "", STOP, fieldId, err
271	}
272	if _, err = p.ParseObjectStart(); err != nil {
273		return "", STOP, fieldId, err
274	}
275	sType, err := p.ReadString(ctx)
276	if err != nil {
277		return "", STOP, fieldId, err
278	}
279	fType, err := p.StringToTypeId(sType)
280	return "", fType, fieldId, err
281}
282
283func (p *TJSONProtocol) ReadFieldEnd(ctx context.Context) error {
284	return p.ParseObjectEnd()
285}
286
287func (p *TJSONProtocol) ReadMapBegin(ctx context.Context) (keyType TType, valueType TType, size int, e error) {
288	if isNull, e := p.ParseListBegin(); isNull || e != nil {
289		return VOID, VOID, 0, e
290	}
291
292	// read keyType
293	sKeyType, e := p.ReadString(ctx)
294	if e != nil {
295		return keyType, valueType, size, e
296	}
297	keyType, e = p.StringToTypeId(sKeyType)
298	if e != nil {
299		return keyType, valueType, size, e
300	}
301
302	// read valueType
303	sValueType, e := p.ReadString(ctx)
304	if e != nil {
305		return keyType, valueType, size, e
306	}
307	valueType, e = p.StringToTypeId(sValueType)
308	if e != nil {
309		return keyType, valueType, size, e
310	}
311
312	// read size
313	iSize, err := p.ReadI64(ctx)
314	if err != nil {
315		return keyType, valueType, size, err
316	}
317	err = checkSizeForProtocol(int32(iSize), p.cfg)
318	if err != nil {
319		return keyType, valueType, 0, err
320	}
321	size = int(iSize)
322
323	_, e = p.ParseObjectStart()
324	return keyType, valueType, size, e
325}
326
327func (p *TJSONProtocol) ReadMapEnd(ctx context.Context) error {
328	e := p.ParseObjectEnd()
329	if e != nil {
330		return e
331	}
332	return p.ParseListEnd()
333}
334
335func (p *TJSONProtocol) ReadListBegin(ctx context.Context) (elemType TType, size int, e error) {
336	return p.ParseElemListBegin()
337}
338
339func (p *TJSONProtocol) ReadListEnd(ctx context.Context) error {
340	return p.ParseListEnd()
341}
342
343func (p *TJSONProtocol) ReadSetBegin(ctx context.Context) (elemType TType, size int, e error) {
344	return p.ParseElemListBegin()
345}
346
347func (p *TJSONProtocol) ReadSetEnd(ctx context.Context) error {
348	return p.ParseListEnd()
349}
350
351func (p *TJSONProtocol) ReadBool(ctx context.Context) (bool, error) {
352	value, err := p.ReadI32(ctx)
353	return (value != 0), err
354}
355
356func (p *TJSONProtocol) ReadByte(ctx context.Context) (int8, error) {
357	v, err := p.ReadI64(ctx)
358	return int8(v), err
359}
360
361func (p *TJSONProtocol) ReadI16(ctx context.Context) (int16, error) {
362	v, err := p.ReadI64(ctx)
363	return int16(v), err
364}
365
366func (p *TJSONProtocol) ReadI32(ctx context.Context) (int32, error) {
367	v, err := p.ReadI64(ctx)
368	return int32(v), err
369}
370
371func (p *TJSONProtocol) ReadI64(ctx context.Context) (int64, error) {
372	v, _, err := p.ParseI64()
373	return v, err
374}
375
376func (p *TJSONProtocol) ReadDouble(ctx context.Context) (float64, error) {
377	v, _, err := p.ParseF64()
378	return v, err
379}
380
381func (p *TJSONProtocol) ReadString(ctx context.Context) (string, error) {
382	var v string
383	if err := p.ParsePreValue(); err != nil {
384		return v, err
385	}
386	f, _ := p.reader.Peek(1)
387	if len(f) > 0 && f[0] == JSON_QUOTE {
388		p.reader.ReadByte()
389		value, err := p.ParseStringBody()
390		v = value
391		if err != nil {
392			return v, err
393		}
394	} else if len(f) > 0 && f[0] == JSON_NULL[0] {
395		b := make([]byte, len(JSON_NULL))
396		_, err := p.reader.Read(b)
397		if err != nil {
398			return v, NewTProtocolException(err)
399		}
400		if string(b) != string(JSON_NULL) {
401			e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(b))
402			return v, NewTProtocolExceptionWithType(INVALID_DATA, e)
403		}
404	} else {
405		e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(f))
406		return v, NewTProtocolExceptionWithType(INVALID_DATA, e)
407	}
408	return v, p.ParsePostValue()
409}
410
411func (p *TJSONProtocol) ReadBinary(ctx context.Context) ([]byte, error) {
412	var v []byte
413	if err := p.ParsePreValue(); err != nil {
414		return nil, err
415	}
416	f, _ := p.reader.Peek(1)
417	if len(f) > 0 && f[0] == JSON_QUOTE {
418		p.reader.ReadByte()
419		value, err := p.ParseBase64EncodedBody()
420		v = value
421		if err != nil {
422			return v, err
423		}
424	} else if len(f) > 0 && f[0] == JSON_NULL[0] {
425		b := make([]byte, len(JSON_NULL))
426		_, err := p.reader.Read(b)
427		if err != nil {
428			return v, NewTProtocolException(err)
429		}
430		if string(b) != string(JSON_NULL) {
431			e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(b))
432			return v, NewTProtocolExceptionWithType(INVALID_DATA, e)
433		}
434	} else {
435		e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(f))
436		return v, NewTProtocolExceptionWithType(INVALID_DATA, e)
437	}
438
439	return v, p.ParsePostValue()
440}
441
442func (p *TJSONProtocol) Flush(ctx context.Context) (err error) {
443	err = p.writer.Flush()
444	if err == nil {
445		err = p.trans.Flush(ctx)
446	}
447	return NewTProtocolException(err)
448}
449
450func (p *TJSONProtocol) Skip(ctx context.Context, fieldType TType) (err error) {
451	return SkipDefaultDepth(ctx, p, fieldType)
452}
453
454func (p *TJSONProtocol) Transport() TTransport {
455	return p.trans
456}
457
458func (p *TJSONProtocol) OutputElemListBegin(elemType TType, size int) error {
459	if e := p.OutputListBegin(); e != nil {
460		return e
461	}
462	s, e1 := p.TypeIdToString(elemType)
463	if e1 != nil {
464		return e1
465	}
466	if e := p.OutputString(s); e != nil {
467		return e
468	}
469	if e := p.OutputI64(int64(size)); e != nil {
470		return e
471	}
472	return nil
473}
474
475func (p *TJSONProtocol) ParseElemListBegin() (elemType TType, size int, e error) {
476	if isNull, e := p.ParseListBegin(); isNull || e != nil {
477		return VOID, 0, e
478	}
479	// We don't really use the ctx in ReadString implementation,
480	// so this is safe for now.
481	// We might want to add context to ParseElemListBegin if we start to use
482	// ctx in ReadString implementation in the future.
483	sElemType, err := p.ReadString(context.Background())
484	if err != nil {
485		return VOID, size, err
486	}
487	elemType, err = p.StringToTypeId(sElemType)
488	if err != nil {
489		return elemType, size, err
490	}
491	nSize, _, err := p.ParseI64()
492	if err != nil {
493		return elemType, 0, err
494	}
495	err = checkSizeForProtocol(int32(nSize), p.cfg)
496	if err != nil {
497		return elemType, 0, err
498	}
499	size = int(nSize)
500	return elemType, size, nil
501}
502
503func (p *TJSONProtocol) TypeIdToString(fieldType TType) (string, error) {
504	switch byte(fieldType) {
505	case BOOL:
506		return "tf", nil
507	case BYTE:
508		return "i8", nil
509	case I16:
510		return "i16", nil
511	case I32:
512		return "i32", nil
513	case I64:
514		return "i64", nil
515	case DOUBLE:
516		return "dbl", nil
517	case STRING:
518		return "str", nil
519	case STRUCT:
520		return "rec", nil
521	case MAP:
522		return "map", nil
523	case SET:
524		return "set", nil
525	case LIST:
526		return "lst", nil
527	case UUID:
528		return "uid", nil
529	}
530
531	e := fmt.Errorf("Unknown fieldType: %d", int(fieldType))
532	return "", NewTProtocolExceptionWithType(INVALID_DATA, e)
533}
534
535func (p *TJSONProtocol) StringToTypeId(fieldType string) (TType, error) {
536	switch fieldType {
537	case "tf":
538		return TType(BOOL), nil
539	case "i8":
540		return TType(BYTE), nil
541	case "i16":
542		return TType(I16), nil
543	case "i32":
544		return TType(I32), nil
545	case "i64":
546		return TType(I64), nil
547	case "dbl":
548		return TType(DOUBLE), nil
549	case "str":
550		return TType(STRING), nil
551	case "rec":
552		return TType(STRUCT), nil
553	case "map":
554		return TType(MAP), nil
555	case "set":
556		return TType(SET), nil
557	case "lst":
558		return TType(LIST), nil
559	case "uid":
560		return TType(UUID), nil
561	}
562
563	e := fmt.Errorf("Unknown type identifier: %s", fieldType)
564	return TType(STOP), NewTProtocolExceptionWithType(INVALID_DATA, e)
565}
566
567var _ TConfigurationSetter = (*TJSONProtocol)(nil)
568