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