blob: e2b540e6f6aeb76c60d8da76ce7f1bfa02114abe [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
Csaba Ringhofer37c79102025-09-15 14:40:17 +020020#define PY_SSIZE_T_CLEAN
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090021#include <Python.h>
22#include "types.h"
23#include "binary.h"
24#include "compact.h"
Nobuaki Sukegawaf7a8d942016-03-01 01:41:47 +090025#include <limits>
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090026#include <stdint.h>
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090027
28// TODO(dreiss): defval appears to be unused. Look into removing it.
29// TODO(dreiss): Make parse_spec_args recursive, and cache the output
30// permanently in the object. (Malloc and orphan.)
31// TODO(dreiss): Why do we need cStringIO for reading, why not just char*?
32// Can cStringIO let us work with a BufferedTransport?
33// TODO(dreiss): Don't ignore the rv from cwrite (maybe).
34
35// Doing a benchmark shows that interning actually makes a difference, amazingly.
36
37/** Pointer to interned string to speed up attribute lookup. */
38PyObject* INTERN_STRING(TFrozenDict);
39PyObject* INTERN_STRING(cstringio_buf);
40PyObject* INTERN_STRING(cstringio_refill);
Carel Combrinka715bdf2025-10-30 07:44:21 +010041PyObject* INTERN_STRING(UUID);
42PyObject* INTERN_STRING(bytes);
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090043static PyObject* INTERN_STRING(string_length_limit);
44static PyObject* INTERN_STRING(container_length_limit);
45static PyObject* INTERN_STRING(trans);
46
47namespace apache {
48namespace thrift {
49namespace py {
50
51template <typename T>
52static PyObject* encode_impl(PyObject* args) {
53 if (!args)
zeshuai00726681fb2020-06-03 17:24:38 +080054 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090055
zeshuai00726681fb2020-06-03 17:24:38 +080056 PyObject* enc_obj = nullptr;
57 PyObject* type_args = nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090058 if (!PyArg_ParseTuple(args, "OO", &enc_obj, &type_args)) {
zeshuai00726681fb2020-06-03 17:24:38 +080059 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090060 }
61 if (!enc_obj || !type_args) {
zeshuai00726681fb2020-06-03 17:24:38 +080062 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090063 }
64
65 T protocol;
66 if (!protocol.prepareEncodeBuffer() || !protocol.encodeValue(enc_obj, T_STRUCT, type_args)) {
zeshuai00726681fb2020-06-03 17:24:38 +080067 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090068 }
69
70 return protocol.getEncodedValue();
71}
72
73static inline long as_long_then_delete(PyObject* value, long default_value) {
74 ScopedPyObject scope(value);
75 long v = PyInt_AsLong(value);
76 if (INT_CONV_ERROR_OCCURRED(v)) {
77 PyErr_Clear();
78 return default_value;
79 }
80 return v;
81}
82
83template <typename T>
84static PyObject* decode_impl(PyObject* args) {
zeshuai00726681fb2020-06-03 17:24:38 +080085 PyObject* output_obj = nullptr;
86 PyObject* oprot = nullptr;
87 PyObject* typeargs = nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090088 if (!PyArg_ParseTuple(args, "OOO", &output_obj, &oprot, &typeargs)) {
zeshuai00726681fb2020-06-03 17:24:38 +080089 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090090 }
91
92 T protocol;
James E. King, III07f59972017-03-10 06:18:33 -050093 int32_t default_limit = (std::numeric_limits<int32_t>::max)();
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090094 protocol.setStringLengthLimit(
Nobuaki Sukegawaf7a8d942016-03-01 01:41:47 +090095 as_long_then_delete(PyObject_GetAttr(oprot, INTERN_STRING(string_length_limit)),
96 default_limit));
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090097 protocol.setContainerLengthLimit(
98 as_long_then_delete(PyObject_GetAttr(oprot, INTERN_STRING(container_length_limit)),
Nobuaki Sukegawaf7a8d942016-03-01 01:41:47 +090099 default_limit));
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900100 ScopedPyObject transport(PyObject_GetAttr(oprot, INTERN_STRING(trans)));
101 if (!transport) {
zeshuai00726681fb2020-06-03 17:24:38 +0800102 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900103 }
104
105 StructTypeArgs parsedargs;
106 if (!parse_struct_args(&parsedargs, typeargs)) {
zeshuai00726681fb2020-06-03 17:24:38 +0800107 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900108 }
109
110 if (!protocol.prepareDecodeBufferFromTransport(transport.get())) {
zeshuai00726681fb2020-06-03 17:24:38 +0800111 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900112 }
113
114 return protocol.readStruct(output_obj, parsedargs.klass, parsedargs.spec);
115}
116}
117}
118}
119
120using namespace apache::thrift::py;
121
122/* -- PYTHON MODULE SETUP STUFF --- */
123
124extern "C" {
125
126static PyObject* encode_binary(PyObject*, PyObject* args) {
127 return encode_impl<BinaryProtocol>(args);
128}
129
130static PyObject* decode_binary(PyObject*, PyObject* args) {
131 return decode_impl<BinaryProtocol>(args);
132}
133
134static PyObject* encode_compact(PyObject*, PyObject* args) {
135 return encode_impl<CompactProtocol>(args);
136}
137
138static PyObject* decode_compact(PyObject*, PyObject* args) {
139 return decode_impl<CompactProtocol>(args);
140}
141
142static PyMethodDef ThriftFastBinaryMethods[] = {
143 {"encode_binary", encode_binary, METH_VARARGS, ""},
144 {"decode_binary", decode_binary, METH_VARARGS, ""},
145 {"encode_compact", encode_compact, METH_VARARGS, ""},
146 {"decode_compact", decode_compact, METH_VARARGS, ""},
zeshuai00726681fb2020-06-03 17:24:38 +0800147 {nullptr, nullptr, 0, nullptr} /* Sentinel */
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900148};
149
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900150#if PY_MAJOR_VERSION >= 3
151
152static struct PyModuleDef ThriftFastBinaryDef = {PyModuleDef_HEAD_INIT,
153 "thrift.protocol.fastbinary",
zeshuai00726681fb2020-06-03 17:24:38 +0800154 nullptr,
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900155 0,
156 ThriftFastBinaryMethods,
zeshuai00726681fb2020-06-03 17:24:38 +0800157 nullptr,
158 nullptr,
159 nullptr,
160 nullptr};
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900161
zeshuai00726681fb2020-06-03 17:24:38 +0800162#define INITERROR return nullptr;
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900163
164PyObject* PyInit_fastbinary() {
165
166#else
167
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900168#define INITERROR return;
169
170void initfastbinary() {
171
172 PycString_IMPORT;
zeshuai00726681fb2020-06-03 17:24:38 +0800173 if (PycStringIO == nullptr)
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900174 INITERROR
175
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900176#endif
177
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900178#define INIT_INTERN_STRING(value) \
179 do { \
180 INTERN_STRING(value) = PyString_InternFromString(#value); \
181 if (!INTERN_STRING(value)) \
182 INITERROR \
183 } while (0)
184
185 INIT_INTERN_STRING(TFrozenDict);
186 INIT_INTERN_STRING(cstringio_buf);
187 INIT_INTERN_STRING(cstringio_refill);
188 INIT_INTERN_STRING(string_length_limit);
189 INIT_INTERN_STRING(container_length_limit);
190 INIT_INTERN_STRING(trans);
Carel Combrinka715bdf2025-10-30 07:44:21 +0100191 INIT_INTERN_STRING(UUID);
192 INIT_INTERN_STRING(bytes);
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900193#undef INIT_INTERN_STRING
194
195 PyObject* module =
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900196#if PY_MAJOR_VERSION >= 3
197 PyModule_Create(&ThriftFastBinaryDef);
198#else
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900199 Py_InitModule("thrift.protocol.fastbinary", ThriftFastBinaryMethods);
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900200#endif
zeshuai00726681fb2020-06-03 17:24:38 +0800201 if (module == nullptr)
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900202 INITERROR;
203
Lysandros Nikolaouc5a37122025-07-25 15:11:44 +0200204#ifdef Py_GIL_DISABLED
205 PyUnstable_Module_SetGIL(module, Py_MOD_GIL_NOT_USED);
206#endif
207
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900208#if PY_MAJOR_VERSION >= 3
209 return module;
210#endif
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900211}
212}