blob: b517c381eeb21c68dd1498eedb0bff419e029ddf [file] [log] [blame]
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +09001/*
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
20#ifndef THRIFT_PY_PROTOCOL_TCC
21#define THRIFT_PY_PROTOCOL_TCC
22
Nobuaki Sukegawaf7a8d942016-03-01 01:41:47 +090023#include <iterator>
24
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090025#define CHECK_RANGE(v, min, max) (((v) <= (max)) && ((v) >= (min)))
26#define INIT_OUTBUF_SIZE 128
27
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +090028#if PY_MAJOR_VERSION < 3
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090029#include <cStringIO.h>
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +090030#else
31#include <algorithm>
32#endif
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090033
34namespace apache {
35namespace thrift {
36namespace py {
37
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +090038#if PY_MAJOR_VERSION < 3
39
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090040namespace detail {
41
42inline bool input_check(PyObject* input) {
43 return PycStringIO_InputCheck(input);
44}
45
46inline EncodeBuffer* new_encode_buffer(size_t size) {
47 if (!PycStringIO) {
48 PycString_IMPORT;
49 }
50 if (!PycStringIO) {
zeshuai00726681fb2020-06-03 17:24:38 +080051 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090052 }
53 return PycStringIO->NewOutput(size);
54}
55
56inline int read_buffer(PyObject* buf, char** output, int len) {
57 if (!PycStringIO) {
58 PycString_IMPORT;
59 }
60 if (!PycStringIO) {
61 PyErr_SetString(PyExc_ImportError, "failed to import native cStringIO");
62 return -1;
63 }
64 return PycStringIO->cread(buf, output, len);
65}
66}
67
68template <typename Impl>
69inline ProtocolBase<Impl>::~ProtocolBase() {
70 if (output_) {
71 Py_CLEAR(output_);
72 }
73}
74
75template <typename Impl>
76inline bool ProtocolBase<Impl>::isUtf8(PyObject* typeargs) {
77 return PyString_Check(typeargs) && !strncmp(PyString_AS_STRING(typeargs), "UTF8", 4);
78}
79
80template <typename Impl>
81PyObject* ProtocolBase<Impl>::getEncodedValue() {
82 if (!PycStringIO) {
83 PycString_IMPORT;
84 }
85 if (!PycStringIO) {
zeshuai00726681fb2020-06-03 17:24:38 +080086 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090087 }
88 return PycStringIO->cgetvalue(output_);
89}
90
91template <typename Impl>
92inline bool ProtocolBase<Impl>::writeBuffer(char* data, size_t size) {
93 if (!PycStringIO) {
94 PycString_IMPORT;
95 }
96 if (!PycStringIO) {
97 PyErr_SetString(PyExc_ImportError, "failed to import native cStringIO");
98 return false;
99 }
100 int len = PycStringIO->cwrite(output_, data, size);
101 if (len < 0) {
102 PyErr_SetString(PyExc_IOError, "failed to write to cStringIO object");
103 return false;
104 }
James E. King, III0ad20bd2017-09-30 15:44:16 -0700105 if (static_cast<size_t>(len) != size) {
Nobuaki Sukegawa7efa4fb2016-02-19 00:59:57 +0900106 PyErr_Format(PyExc_EOFError, "write length mismatch: expected %lu got %d", size, len);
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900107 return false;
108 }
109 return true;
110}
111
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900112#else
113
114namespace detail {
115
116inline bool input_check(PyObject* input) {
117 // TODO: Check for BytesIO type
118 return true;
119}
120
121inline EncodeBuffer* new_encode_buffer(size_t size) {
122 EncodeBuffer* buffer = new EncodeBuffer;
123 buffer->buf.reserve(size);
124 buffer->pos = 0;
125 return buffer;
126}
127
128struct bytesio {
129 PyObject_HEAD
130#if PY_MINOR_VERSION < 5
131 char* buf;
132#else
133 PyObject* buf;
134#endif
135 Py_ssize_t pos;
136 Py_ssize_t string_size;
137};
138
139inline int read_buffer(PyObject* buf, char** output, int len) {
140 bytesio* buf2 = reinterpret_cast<bytesio*>(buf);
141#if PY_MINOR_VERSION < 5
142 *output = buf2->buf + buf2->pos;
143#else
144 *output = PyBytes_AS_STRING(buf2->buf) + buf2->pos;
145#endif
146 Py_ssize_t pos0 = buf2->pos;
James E. King III9b75e4f2018-12-17 16:21:14 -0500147 buf2->pos = (std::min)(buf2->pos + static_cast<Py_ssize_t>(len), buf2->string_size);
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900148 return static_cast<int>(buf2->pos - pos0);
149}
150}
151
152template <typename Impl>
153inline ProtocolBase<Impl>::~ProtocolBase() {
154 if (output_) {
155 delete output_;
156 }
157}
158
159template <typename Impl>
160inline bool ProtocolBase<Impl>::isUtf8(PyObject* typeargs) {
161 // while condition for py2 is "arg == 'UTF8'", it should be "arg != 'BINARY'" for py3.
162 // HACK: check the length and don't bother reading the value
163 return !PyUnicode_Check(typeargs) || PyUnicode_GET_LENGTH(typeargs) != 6;
164}
165
166template <typename Impl>
167PyObject* ProtocolBase<Impl>::getEncodedValue() {
168 return PyBytes_FromStringAndSize(output_->buf.data(), output_->buf.size());
169}
170
171template <typename Impl>
172inline bool ProtocolBase<Impl>::writeBuffer(char* data, size_t size) {
173 size_t need = size + output_->pos;
174 if (output_->buf.capacity() < need) {
175 try {
176 output_->buf.reserve(need);
Kevin Wojniakcf73b662019-11-02 22:01:56 -0700177 } catch (std::bad_alloc&) {
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900178 PyErr_SetString(PyExc_MemoryError, "Failed to allocate write buffer");
179 return false;
180 }
181 }
182 std::copy(data, data + size, std::back_inserter(output_->buf));
183 return true;
184}
185
186#endif
187
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900188namespace detail {
189
190#define DECLARE_OP_SCOPE(name, op) \
191 template <typename Impl> \
192 struct name##Scope { \
193 Impl* impl; \
194 bool valid; \
195 name##Scope(Impl* thiz) : impl(thiz), valid(impl->op##Begin()) {} \
196 ~name##Scope() { \
197 if (valid) \
198 impl->op##End(); \
199 } \
200 operator bool() { return valid; } \
201 }; \
202 template <typename Impl, template <typename> class T> \
203 name##Scope<Impl> op##Scope(T<Impl>* thiz) { \
204 return name##Scope<Impl>(static_cast<Impl*>(thiz)); \
205 }
206DECLARE_OP_SCOPE(WriteStruct, writeStruct)
207DECLARE_OP_SCOPE(ReadStruct, readStruct)
208#undef DECLARE_OP_SCOPE
209
210inline bool check_ssize_t_32(Py_ssize_t len) {
211 // error from getting the int
212 if (INT_CONV_ERROR_OCCURRED(len)) {
213 return false;
214 }
James E. King III9b75e4f2018-12-17 16:21:14 -0500215 if (!CHECK_RANGE(len, 0, (std::numeric_limits<int32_t>::max)())) {
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900216 PyErr_SetString(PyExc_OverflowError, "size out of range: exceeded INT32_MAX");
217 return false;
218 }
219 return true;
220}
221}
222
223template <typename T>
224bool parse_pyint(PyObject* o, T* ret, int32_t min, int32_t max) {
225 long val = PyInt_AsLong(o);
226
227 if (INT_CONV_ERROR_OCCURRED(val)) {
228 return false;
229 }
230 if (!CHECK_RANGE(val, min, max)) {
231 PyErr_SetString(PyExc_OverflowError, "int out of range");
232 return false;
233 }
234
235 *ret = static_cast<T>(val);
236 return true;
237}
238
239template <typename Impl>
240inline bool ProtocolBase<Impl>::checkType(TType got, TType expected) {
241 if (expected != got) {
242 PyErr_SetString(PyExc_TypeError, "got wrong ttype while reading field");
243 return false;
244 }
245 return true;
246}
247
248template <typename Impl>
249bool ProtocolBase<Impl>::checkLengthLimit(int32_t len, long limit) {
250 if (len < 0) {
Nobuaki Sukegawa7efa4fb2016-02-19 00:59:57 +0900251 PyErr_Format(PyExc_OverflowError, "negative length: %ld", limit);
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900252 return false;
253 }
254 if (len > limit) {
Nobuaki Sukegawa7efa4fb2016-02-19 00:59:57 +0900255 PyErr_Format(PyExc_OverflowError, "size exceeded specified limit: %ld", limit);
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900256 return false;
257 }
258 return true;
259}
260
261template <typename Impl>
262bool ProtocolBase<Impl>::readBytes(char** output, int len) {
263 if (len < 0) {
264 PyErr_Format(PyExc_ValueError, "attempted to read negative length: %d", len);
265 return false;
266 }
267 // TODO(dreiss): Don't fear the malloc. Think about taking a copy of
268 // the partial read instead of forcing the transport
269 // to prepend it to its buffer.
270
271 int rlen = detail::read_buffer(input_.stringiobuf.get(), output, len);
272
273 if (rlen == len) {
274 return true;
275 } else if (rlen == -1) {
276 return false;
277 } else {
278 // using building functions as this is a rare codepath
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900279 ScopedPyObject newiobuf(PyObject_CallFunction(input_.refill_callable.get(), refill_signature,
zeshuai00726681fb2020-06-03 17:24:38 +0800280 *output, rlen, len, nullptr));
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900281 if (!newiobuf) {
282 return false;
283 }
284
285 // must do this *AFTER* the call so that we don't deref the io buffer
286 input_.stringiobuf.reset(newiobuf.release());
287
288 rlen = detail::read_buffer(input_.stringiobuf.get(), output, len);
289
290 if (rlen == len) {
291 return true;
292 } else if (rlen == -1) {
293 return false;
294 } else {
295 // TODO(dreiss): This could be a valid code path for big binary blobs.
296 PyErr_SetString(PyExc_TypeError, "refill claimed to have refilled the buffer, but didn't!!");
297 return false;
298 }
299 }
300}
301
302template <typename Impl>
303bool ProtocolBase<Impl>::prepareDecodeBufferFromTransport(PyObject* trans) {
304 if (input_.stringiobuf) {
305 PyErr_SetString(PyExc_ValueError, "decode buffer is already initialized");
306 return false;
307 }
308
309 ScopedPyObject stringiobuf(PyObject_GetAttr(trans, INTERN_STRING(cstringio_buf)));
310 if (!stringiobuf) {
311 return false;
312 }
313 if (!detail::input_check(stringiobuf.get())) {
314 PyErr_SetString(PyExc_TypeError, "expecting stringio input_");
315 return false;
316 }
317
318 ScopedPyObject refill_callable(PyObject_GetAttr(trans, INTERN_STRING(cstringio_refill)));
319 if (!refill_callable) {
320 return false;
321 }
322 if (!PyCallable_Check(refill_callable.get())) {
323 PyErr_SetString(PyExc_TypeError, "expecting callable");
324 return false;
325 }
326
327 input_.stringiobuf.swap(stringiobuf);
328 input_.refill_callable.swap(refill_callable);
329 return true;
330}
331
332template <typename Impl>
333bool ProtocolBase<Impl>::prepareEncodeBuffer() {
334 output_ = detail::new_encode_buffer(INIT_OUTBUF_SIZE);
zeshuai00726681fb2020-06-03 17:24:38 +0800335 return output_ != nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900336}
337
338template <typename Impl>
339bool ProtocolBase<Impl>::encodeValue(PyObject* value, TType type, PyObject* typeargs) {
340 /*
341 * Refcounting Strategy:
342 *
343 * We assume that elements of the thrift_spec tuple are not going to be
344 * mutated, so we don't ref count those at all. Other than that, we try to
345 * keep a reference to all the user-created objects while we work with them.
346 * encodeValue assumes that a reference is already held. The *caller* is
347 * responsible for handling references
348 */
349
350 switch (type) {
351
352 case T_BOOL: {
353 int v = PyObject_IsTrue(value);
354 if (v == -1) {
355 return false;
356 }
357 impl()->writeBool(v);
358 return true;
359 }
360 case T_I08: {
361 int8_t val;
362
James E. King III9b75e4f2018-12-17 16:21:14 -0500363 if (!parse_pyint(value, &val, (std::numeric_limits<int8_t>::min)(),
364 (std::numeric_limits<int8_t>::max)())) {
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900365 return false;
366 }
367
368 impl()->writeI8(val);
369 return true;
370 }
371 case T_I16: {
372 int16_t val;
373
James E. King III9b75e4f2018-12-17 16:21:14 -0500374 if (!parse_pyint(value, &val, (std::numeric_limits<int16_t>::min)(),
375 (std::numeric_limits<int16_t>::max)())) {
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900376 return false;
377 }
378
379 impl()->writeI16(val);
380 return true;
381 }
382 case T_I32: {
383 int32_t val;
384
James E. King III9b75e4f2018-12-17 16:21:14 -0500385 if (!parse_pyint(value, &val, (std::numeric_limits<int32_t>::min)(),
386 (std::numeric_limits<int32_t>::max)())) {
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900387 return false;
388 }
389
390 impl()->writeI32(val);
391 return true;
392 }
393 case T_I64: {
394 int64_t nval = PyLong_AsLongLong(value);
395
396 if (INT_CONV_ERROR_OCCURRED(nval)) {
397 return false;
398 }
399
James E. King III9b75e4f2018-12-17 16:21:14 -0500400 if (!CHECK_RANGE(nval, (std::numeric_limits<int64_t>::min)(),
401 (std::numeric_limits<int64_t>::max)())) {
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900402 PyErr_SetString(PyExc_OverflowError, "int out of range");
403 return false;
404 }
405
406 impl()->writeI64(nval);
407 return true;
408 }
409
410 case T_DOUBLE: {
411 double nval = PyFloat_AsDouble(value);
412 if (nval == -1.0 && PyErr_Occurred()) {
413 return false;
414 }
415
416 impl()->writeDouble(nval);
417 return true;
418 }
419
420 case T_STRING: {
Chandler May6657b832016-03-27 22:47:06 -0400421 ScopedPyObject nval;
422
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900423 if (PyUnicode_Check(value)) {
Chandler May6657b832016-03-27 22:47:06 -0400424 nval.reset(PyUnicode_AsUTF8String(value));
425 if (!nval) {
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900426 return false;
427 }
Chandler May6657b832016-03-27 22:47:06 -0400428 } else {
429 Py_INCREF(value);
430 nval.reset(value);
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900431 }
432
Chandler May6657b832016-03-27 22:47:06 -0400433 Py_ssize_t len = PyBytes_Size(nval.get());
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900434 if (!detail::check_ssize_t_32(len)) {
435 return false;
436 }
437
Chandler May6657b832016-03-27 22:47:06 -0400438 impl()->writeString(nval.get(), static_cast<int32_t>(len));
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900439 return true;
440 }
441
442 case T_LIST:
443 case T_SET: {
444 SetListTypeArgs parsedargs;
445 if (!parse_set_list_args(&parsedargs, typeargs)) {
446 return false;
447 }
448
449 Py_ssize_t len = PyObject_Length(value);
450 if (!detail::check_ssize_t_32(len)) {
451 return false;
452 }
453
454 if (!impl()->writeListBegin(value, parsedargs, static_cast<int32_t>(len)) || PyErr_Occurred()) {
455 return false;
456 }
457 ScopedPyObject iterator(PyObject_GetIter(value));
458 if (!iterator) {
459 return false;
460 }
461
462 while (PyObject* rawItem = PyIter_Next(iterator.get())) {
463 ScopedPyObject item(rawItem);
464 if (!encodeValue(item.get(), parsedargs.element_type, parsedargs.typeargs)) {
465 return false;
466 }
467 }
468
469 return true;
470 }
471
472 case T_MAP: {
473 Py_ssize_t len = PyDict_Size(value);
474 if (!detail::check_ssize_t_32(len)) {
475 return false;
476 }
477
478 MapTypeArgs parsedargs;
479 if (!parse_map_args(&parsedargs, typeargs)) {
480 return false;
481 }
482
483 if (!impl()->writeMapBegin(value, parsedargs, static_cast<int32_t>(len)) || PyErr_Occurred()) {
484 return false;
485 }
486 Py_ssize_t pos = 0;
zeshuai00726681fb2020-06-03 17:24:38 +0800487 PyObject* k = nullptr;
488 PyObject* v = nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900489 // TODO(bmaurer): should support any mapping, not just dicts
490 while (PyDict_Next(value, &pos, &k, &v)) {
491 if (!encodeValue(k, parsedargs.ktag, parsedargs.ktypeargs)
492 || !encodeValue(v, parsedargs.vtag, parsedargs.vtypeargs)) {
493 return false;
494 }
495 }
496 return true;
497 }
498
499 case T_STRUCT: {
500 StructTypeArgs parsedargs;
501 if (!parse_struct_args(&parsedargs, typeargs)) {
502 return false;
503 }
504
505 Py_ssize_t nspec = PyTuple_Size(parsedargs.spec);
506 if (nspec == -1) {
507 PyErr_SetString(PyExc_TypeError, "spec is not a tuple");
508 return false;
509 }
510
511 detail::WriteStructScope<Impl> scope = detail::writeStructScope(this);
512 if (!scope) {
513 return false;
514 }
515 for (Py_ssize_t i = 0; i < nspec; i++) {
516 PyObject* spec_tuple = PyTuple_GET_ITEM(parsedargs.spec, i);
517 if (spec_tuple == Py_None) {
518 continue;
519 }
520
521 StructItemSpec parsedspec;
522 if (!parse_struct_item_spec(&parsedspec, spec_tuple)) {
523 return false;
524 }
525
526 ScopedPyObject instval(PyObject_GetAttr(value, parsedspec.attrname));
527
528 if (!instval) {
529 return false;
530 }
531
532 if (instval.get() == Py_None) {
533 continue;
534 }
535
536 bool res = impl()->writeField(instval.get(), parsedspec);
537 if (!res) {
538 return false;
539 }
540 }
541 impl()->writeFieldStop();
542 return true;
543 }
544
Carel Combrinka715bdf2025-10-30 07:44:21 +0100545 case T_UUID: {
546 ScopedPyObject instval(PyObject_GetAttr(value, INTERN_STRING(bytes)));
547 if (!instval) {
548 return false;
549 }
550
551 Py_ssize_t size;
552 char* buffer;
553 if (PyBytes_AsStringAndSize(instval.get(), &buffer, &size) < 0) {
554 return false;
555 }
556 if (size != 16) {
557 PyErr_SetString(PyExc_TypeError, "uuid.bytes must be exactly 16 bytes long");
558 return false;
559 }
560 impl()->writeUuid(buffer);
561 return true;
562 }
563
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900564 case T_STOP:
565 case T_VOID:
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900566 case T_U64:
567 default:
568 PyErr_Format(PyExc_TypeError, "Unexpected TType for encodeValue: %d", type);
569 return false;
570 }
571
572 return true;
573}
574
575template <typename Impl>
576bool ProtocolBase<Impl>::skip(TType type) {
577 switch (type) {
578 case T_BOOL:
579 return impl()->skipBool();
580 case T_I08:
581 return impl()->skipByte();
582 case T_I16:
583 return impl()->skipI16();
584 case T_I32:
585 return impl()->skipI32();
586 case T_I64:
587 return impl()->skipI64();
588 case T_DOUBLE:
589 return impl()->skipDouble();
590
591 case T_STRING: {
592 return impl()->skipString();
593 }
594
595 case T_LIST:
596 case T_SET: {
597 TType etype = T_STOP;
598 int32_t len = impl()->readListBegin(etype);
599 if (len < 0) {
600 return false;
601 }
602 for (int32_t i = 0; i < len; i++) {
603 if (!skip(etype)) {
604 return false;
605 }
606 }
607 return true;
608 }
609
610 case T_MAP: {
611 TType ktype = T_STOP;
612 TType vtype = T_STOP;
613 int32_t len = impl()->readMapBegin(ktype, vtype);
614 if (len < 0) {
615 return false;
616 }
617 for (int32_t i = 0; i < len; i++) {
618 if (!skip(ktype) || !skip(vtype)) {
619 return false;
620 }
621 }
622 return true;
623 }
624
625 case T_STRUCT: {
626 detail::ReadStructScope<Impl> scope = detail::readStructScope(this);
627 if (!scope) {
628 return false;
629 }
630 while (true) {
631 TType type = T_STOP;
632 int16_t tag;
633 if (!impl()->readFieldBegin(type, tag)) {
634 return false;
635 }
636 if (type == T_STOP) {
637 return true;
638 }
639 if (!skip(type)) {
640 return false;
641 }
642 }
643 return true;
644 }
Carel Combrinka715bdf2025-10-30 07:44:21 +0100645 case T_UUID: {
646 return impl()->skipUuid();
647 }
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900648
649 case T_STOP:
650 case T_VOID:
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900651 case T_U64:
652 default:
653 PyErr_Format(PyExc_TypeError, "Unexpected TType for skip: %d", type);
654 return false;
655 }
656
657 return true;
658}
659
660// Returns a new reference.
661template <typename Impl>
662PyObject* ProtocolBase<Impl>::decodeValue(TType type, PyObject* typeargs) {
663 switch (type) {
664
665 case T_BOOL: {
666 bool v = 0;
667 if (!impl()->readBool(v)) {
zeshuai00726681fb2020-06-03 17:24:38 +0800668 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900669 }
670 if (v) {
671 Py_RETURN_TRUE;
672 } else {
673 Py_RETURN_FALSE;
674 }
675 }
676 case T_I08: {
677 int8_t v = 0;
678 if (!impl()->readI8(v)) {
zeshuai00726681fb2020-06-03 17:24:38 +0800679 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900680 }
681 return PyInt_FromLong(v);
682 }
683 case T_I16: {
684 int16_t v = 0;
685 if (!impl()->readI16(v)) {
zeshuai00726681fb2020-06-03 17:24:38 +0800686 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900687 }
688 return PyInt_FromLong(v);
689 }
690 case T_I32: {
691 int32_t v = 0;
692 if (!impl()->readI32(v)) {
zeshuai00726681fb2020-06-03 17:24:38 +0800693 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900694 }
695 return PyInt_FromLong(v);
696 }
697
698 case T_I64: {
699 int64_t v = 0;
700 if (!impl()->readI64(v)) {
zeshuai00726681fb2020-06-03 17:24:38 +0800701 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900702 }
703 // TODO(dreiss): Find out if we can take this fastpath always when
704 // sizeof(long) == sizeof(long long).
705 if (CHECK_RANGE(v, LONG_MIN, LONG_MAX)) {
706 return PyInt_FromLong((long)v);
707 }
708 return PyLong_FromLongLong(v);
709 }
710
711 case T_DOUBLE: {
712 double v = 0.0;
713 if (!impl()->readDouble(v)) {
zeshuai00726681fb2020-06-03 17:24:38 +0800714 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900715 }
716 return PyFloat_FromDouble(v);
717 }
718
719 case T_STRING: {
zeshuai00726681fb2020-06-03 17:24:38 +0800720 char* buf = nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900721 int len = impl()->readString(&buf);
722 if (len < 0) {
zeshuai00726681fb2020-06-03 17:24:38 +0800723 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900724 }
725 if (isUtf8(typeargs)) {
stiga-huang05bb5512020-10-30 20:07:31 +0800726 return PyUnicode_DecodeUTF8(buf, len, "replace");
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900727 } else {
728 return PyBytes_FromStringAndSize(buf, len);
729 }
730 }
731
732 case T_LIST:
733 case T_SET: {
734 SetListTypeArgs parsedargs;
735 if (!parse_set_list_args(&parsedargs, typeargs)) {
zeshuai00726681fb2020-06-03 17:24:38 +0800736 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900737 }
738
739 TType etype = T_STOP;
740 int32_t len = impl()->readListBegin(etype);
741 if (len < 0) {
zeshuai00726681fb2020-06-03 17:24:38 +0800742 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900743 }
744 if (len > 0 && !checkType(etype, parsedargs.element_type)) {
zeshuai00726681fb2020-06-03 17:24:38 +0800745 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900746 }
747
748 bool use_tuple = type == T_LIST && parsedargs.immutable;
749 ScopedPyObject ret(use_tuple ? PyTuple_New(len) : PyList_New(len));
750 if (!ret) {
zeshuai00726681fb2020-06-03 17:24:38 +0800751 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900752 }
753
754 for (int i = 0; i < len; i++) {
755 PyObject* item = decodeValue(etype, parsedargs.typeargs);
756 if (!item) {
zeshuai00726681fb2020-06-03 17:24:38 +0800757 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900758 }
759 if (use_tuple) {
760 PyTuple_SET_ITEM(ret.get(), i, item);
761 } else {
762 PyList_SET_ITEM(ret.get(), i, item);
763 }
764 }
765
766 // TODO(dreiss): Consider biting the bullet and making two separate cases
767 // for list and set, avoiding this post facto conversion.
768 if (type == T_SET) {
769 PyObject* setret;
770 setret = parsedargs.immutable ? PyFrozenSet_New(ret.get()) : PySet_New(ret.get());
771 return setret;
772 }
773 return ret.release();
774 }
775
776 case T_MAP: {
777 MapTypeArgs parsedargs;
778 if (!parse_map_args(&parsedargs, typeargs)) {
zeshuai00726681fb2020-06-03 17:24:38 +0800779 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900780 }
781
782 TType ktype = T_STOP;
783 TType vtype = T_STOP;
784 uint32_t len = impl()->readMapBegin(ktype, vtype);
785 if (len > 0 && (!checkType(ktype, parsedargs.ktag) || !checkType(vtype, parsedargs.vtag))) {
zeshuai00726681fb2020-06-03 17:24:38 +0800786 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900787 }
788
789 ScopedPyObject ret(PyDict_New());
790 if (!ret) {
zeshuai00726681fb2020-06-03 17:24:38 +0800791 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900792 }
793
794 for (uint32_t i = 0; i < len; i++) {
795 ScopedPyObject k(decodeValue(ktype, parsedargs.ktypeargs));
796 if (!k) {
zeshuai00726681fb2020-06-03 17:24:38 +0800797 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900798 }
799 ScopedPyObject v(decodeValue(vtype, parsedargs.vtypeargs));
800 if (!v) {
zeshuai00726681fb2020-06-03 17:24:38 +0800801 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900802 }
803 if (PyDict_SetItem(ret.get(), k.get(), v.get()) == -1) {
zeshuai00726681fb2020-06-03 17:24:38 +0800804 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900805 }
806 }
807
808 if (parsedargs.immutable) {
809 if (!ThriftModule) {
810 ThriftModule = PyImport_ImportModule("thrift.Thrift");
811 }
812 if (!ThriftModule) {
zeshuai00726681fb2020-06-03 17:24:38 +0800813 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900814 }
815
816 ScopedPyObject cls(PyObject_GetAttr(ThriftModule, INTERN_STRING(TFrozenDict)));
817 if (!cls) {
zeshuai00726681fb2020-06-03 17:24:38 +0800818 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900819 }
820
821 ScopedPyObject arg(PyTuple_New(1));
822 PyTuple_SET_ITEM(arg.get(), 0, ret.release());
823 ret.reset(PyObject_CallObject(cls.get(), arg.get()));
824 }
825
826 return ret.release();
827 }
828
829 case T_STRUCT: {
830 StructTypeArgs parsedargs;
831 if (!parse_struct_args(&parsedargs, typeargs)) {
zeshuai00726681fb2020-06-03 17:24:38 +0800832 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900833 }
834 return readStruct(Py_None, parsedargs.klass, parsedargs.spec);
835 }
836
Carel Combrinka715bdf2025-10-30 07:44:21 +0100837 case T_UUID: {
838 char* buf = nullptr;
839 if(!impl()->readUuid(&buf)) {
840 return nullptr;
841 }
842
843 if(!UuidModule) {
844 UuidModule = PyImport_ImportModule("uuid");
845 if (!UuidModule)
846 return nullptr;
847 }
848
849 ScopedPyObject cls(PyObject_GetAttr(UuidModule, INTERN_STRING(UUID)));
850 if (!cls) {
851 return nullptr;
852 }
853
854 ScopedPyObject pyBytes(PyBytes_FromStringAndSize(buf, 16));
855 if (!pyBytes) {
856 return nullptr;
857 }
858
859 ScopedPyObject args(PyTuple_New(0));
860 ScopedPyObject kwargs(Py_BuildValue("{O:O}", INTERN_STRING(bytes), pyBytes.get()));
861 ScopedPyObject ret(PyObject_Call(cls.get(), args.get(), kwargs.get()));
862 return ret.release();
863 }
864
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900865 case T_STOP:
866 case T_VOID:
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900867 case T_U64:
868 default:
869 PyErr_Format(PyExc_TypeError, "Unexpected TType for decodeValue: %d", type);
zeshuai00726681fb2020-06-03 17:24:38 +0800870 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900871 }
872}
873
874template <typename Impl>
875PyObject* ProtocolBase<Impl>::readStruct(PyObject* output, PyObject* klass, PyObject* spec_seq) {
876 int spec_seq_len = PyTuple_Size(spec_seq);
877 bool immutable = output == Py_None;
878 ScopedPyObject kwargs;
879 if (spec_seq_len == -1) {
zeshuai00726681fb2020-06-03 17:24:38 +0800880 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900881 }
882
883 if (immutable) {
884 kwargs.reset(PyDict_New());
885 if (!kwargs) {
886 PyErr_SetString(PyExc_TypeError, "failed to prepare kwargument storage");
zeshuai00726681fb2020-06-03 17:24:38 +0800887 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900888 }
889 }
890
891 detail::ReadStructScope<Impl> scope = detail::readStructScope(this);
892 if (!scope) {
zeshuai00726681fb2020-06-03 17:24:38 +0800893 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900894 }
895 while (true) {
896 TType type = T_STOP;
897 int16_t tag;
898 if (!impl()->readFieldBegin(type, tag)) {
zeshuai00726681fb2020-06-03 17:24:38 +0800899 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900900 }
901 if (type == T_STOP) {
902 break;
903 }
904 if (tag < 0 || tag >= spec_seq_len) {
905 if (!skip(type)) {
906 PyErr_SetString(PyExc_TypeError, "Error while skipping unknown field");
zeshuai00726681fb2020-06-03 17:24:38 +0800907 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900908 }
909 continue;
910 }
911
912 PyObject* item_spec = PyTuple_GET_ITEM(spec_seq, tag);
913 if (item_spec == Py_None) {
914 if (!skip(type)) {
915 PyErr_SetString(PyExc_TypeError, "Error while skipping unknown field");
zeshuai00726681fb2020-06-03 17:24:38 +0800916 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900917 }
918 continue;
919 }
920 StructItemSpec parsedspec;
921 if (!parse_struct_item_spec(&parsedspec, item_spec)) {
zeshuai00726681fb2020-06-03 17:24:38 +0800922 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900923 }
924 if (parsedspec.type != type) {
925 if (!skip(type)) {
926 PyErr_Format(PyExc_TypeError, "struct field had wrong type: expected %d but got %d",
927 parsedspec.type, type);
zeshuai00726681fb2020-06-03 17:24:38 +0800928 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900929 }
930 continue;
931 }
932
933 ScopedPyObject fieldval(decodeValue(parsedspec.type, parsedspec.typeargs));
934 if (!fieldval) {
zeshuai00726681fb2020-06-03 17:24:38 +0800935 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900936 }
937
938 if ((immutable && PyDict_SetItem(kwargs.get(), parsedspec.attrname, fieldval.get()) == -1)
939 || (!immutable && PyObject_SetAttr(output, parsedspec.attrname, fieldval.get()) == -1)) {
zeshuai00726681fb2020-06-03 17:24:38 +0800940 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900941 }
942 }
943 if (immutable) {
944 ScopedPyObject args(PyTuple_New(0));
945 if (!args) {
946 PyErr_SetString(PyExc_TypeError, "failed to prepare argument storage");
zeshuai00726681fb2020-06-03 17:24:38 +0800947 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900948 }
949 return PyObject_Call(klass, args.get(), kwargs.get());
950 }
951 Py_INCREF(output);
952 return output;
953}
954}
955}
956}
957#endif // THRIFT_PY_PROTOCOL_H