blob: fbee51d167e22564c74bf2c961dc80dfc90670fb [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);
41static PyObject* INTERN_STRING(string_length_limit);
42static PyObject* INTERN_STRING(container_length_limit);
43static PyObject* INTERN_STRING(trans);
44
45namespace apache {
46namespace thrift {
47namespace py {
48
49template <typename T>
50static PyObject* encode_impl(PyObject* args) {
51 if (!args)
zeshuai00726681fb2020-06-03 17:24:38 +080052 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090053
zeshuai00726681fb2020-06-03 17:24:38 +080054 PyObject* enc_obj = nullptr;
55 PyObject* type_args = nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090056 if (!PyArg_ParseTuple(args, "OO", &enc_obj, &type_args)) {
zeshuai00726681fb2020-06-03 17:24:38 +080057 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090058 }
59 if (!enc_obj || !type_args) {
zeshuai00726681fb2020-06-03 17:24:38 +080060 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090061 }
62
63 T protocol;
64 if (!protocol.prepareEncodeBuffer() || !protocol.encodeValue(enc_obj, T_STRUCT, type_args)) {
zeshuai00726681fb2020-06-03 17:24:38 +080065 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090066 }
67
68 return protocol.getEncodedValue();
69}
70
71static inline long as_long_then_delete(PyObject* value, long default_value) {
72 ScopedPyObject scope(value);
73 long v = PyInt_AsLong(value);
74 if (INT_CONV_ERROR_OCCURRED(v)) {
75 PyErr_Clear();
76 return default_value;
77 }
78 return v;
79}
80
81template <typename T>
82static PyObject* decode_impl(PyObject* args) {
zeshuai00726681fb2020-06-03 17:24:38 +080083 PyObject* output_obj = nullptr;
84 PyObject* oprot = nullptr;
85 PyObject* typeargs = nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090086 if (!PyArg_ParseTuple(args, "OOO", &output_obj, &oprot, &typeargs)) {
zeshuai00726681fb2020-06-03 17:24:38 +080087 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090088 }
89
90 T protocol;
James E. King, III07f59972017-03-10 06:18:33 -050091 int32_t default_limit = (std::numeric_limits<int32_t>::max)();
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090092 protocol.setStringLengthLimit(
Nobuaki Sukegawaf7a8d942016-03-01 01:41:47 +090093 as_long_then_delete(PyObject_GetAttr(oprot, INTERN_STRING(string_length_limit)),
94 default_limit));
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090095 protocol.setContainerLengthLimit(
96 as_long_then_delete(PyObject_GetAttr(oprot, INTERN_STRING(container_length_limit)),
Nobuaki Sukegawaf7a8d942016-03-01 01:41:47 +090097 default_limit));
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +090098 ScopedPyObject transport(PyObject_GetAttr(oprot, INTERN_STRING(trans)));
99 if (!transport) {
zeshuai00726681fb2020-06-03 17:24:38 +0800100 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900101 }
102
103 StructTypeArgs parsedargs;
104 if (!parse_struct_args(&parsedargs, typeargs)) {
zeshuai00726681fb2020-06-03 17:24:38 +0800105 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900106 }
107
108 if (!protocol.prepareDecodeBufferFromTransport(transport.get())) {
zeshuai00726681fb2020-06-03 17:24:38 +0800109 return nullptr;
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900110 }
111
112 return protocol.readStruct(output_obj, parsedargs.klass, parsedargs.spec);
113}
114}
115}
116}
117
118using namespace apache::thrift::py;
119
120/* -- PYTHON MODULE SETUP STUFF --- */
121
122extern "C" {
123
124static PyObject* encode_binary(PyObject*, PyObject* args) {
125 return encode_impl<BinaryProtocol>(args);
126}
127
128static PyObject* decode_binary(PyObject*, PyObject* args) {
129 return decode_impl<BinaryProtocol>(args);
130}
131
132static PyObject* encode_compact(PyObject*, PyObject* args) {
133 return encode_impl<CompactProtocol>(args);
134}
135
136static PyObject* decode_compact(PyObject*, PyObject* args) {
137 return decode_impl<CompactProtocol>(args);
138}
139
140static PyMethodDef ThriftFastBinaryMethods[] = {
141 {"encode_binary", encode_binary, METH_VARARGS, ""},
142 {"decode_binary", decode_binary, METH_VARARGS, ""},
143 {"encode_compact", encode_compact, METH_VARARGS, ""},
144 {"decode_compact", decode_compact, METH_VARARGS, ""},
zeshuai00726681fb2020-06-03 17:24:38 +0800145 {nullptr, nullptr, 0, nullptr} /* Sentinel */
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900146};
147
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900148#if PY_MAJOR_VERSION >= 3
149
150static struct PyModuleDef ThriftFastBinaryDef = {PyModuleDef_HEAD_INIT,
151 "thrift.protocol.fastbinary",
zeshuai00726681fb2020-06-03 17:24:38 +0800152 nullptr,
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900153 0,
154 ThriftFastBinaryMethods,
zeshuai00726681fb2020-06-03 17:24:38 +0800155 nullptr,
156 nullptr,
157 nullptr,
158 nullptr};
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900159
zeshuai00726681fb2020-06-03 17:24:38 +0800160#define INITERROR return nullptr;
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900161
162PyObject* PyInit_fastbinary() {
163
164#else
165
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900166#define INITERROR return;
167
168void initfastbinary() {
169
170 PycString_IMPORT;
zeshuai00726681fb2020-06-03 17:24:38 +0800171 if (PycStringIO == nullptr)
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900172 INITERROR
173
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900174#endif
175
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900176#define INIT_INTERN_STRING(value) \
177 do { \
178 INTERN_STRING(value) = PyString_InternFromString(#value); \
179 if (!INTERN_STRING(value)) \
180 INITERROR \
181 } while (0)
182
183 INIT_INTERN_STRING(TFrozenDict);
184 INIT_INTERN_STRING(cstringio_buf);
185 INIT_INTERN_STRING(cstringio_refill);
186 INIT_INTERN_STRING(string_length_limit);
187 INIT_INTERN_STRING(container_length_limit);
188 INIT_INTERN_STRING(trans);
189#undef INIT_INTERN_STRING
190
191 PyObject* module =
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900192#if PY_MAJOR_VERSION >= 3
193 PyModule_Create(&ThriftFastBinaryDef);
194#else
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900195 Py_InitModule("thrift.protocol.fastbinary", ThriftFastBinaryMethods);
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900196#endif
zeshuai00726681fb2020-06-03 17:24:38 +0800197 if (module == nullptr)
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900198 INITERROR;
199
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900200#if PY_MAJOR_VERSION >= 3
201 return module;
202#endif
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900203}
204}