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