configuration.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  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. package thrift
  20. import (
  21. "crypto/tls"
  22. "fmt"
  23. "time"
  24. )
  25. // Default TConfiguration values.
  26. const (
  27. DEFAULT_MAX_MESSAGE_SIZE = 100 * 1024 * 1024
  28. DEFAULT_MAX_FRAME_SIZE = 16384000
  29. DEFAULT_TBINARY_STRICT_READ = false
  30. DEFAULT_TBINARY_STRICT_WRITE = true
  31. DEFAULT_CONNECT_TIMEOUT = 0
  32. DEFAULT_SOCKET_TIMEOUT = 0
  33. )
  34. // TConfiguration defines some configurations shared between TTransport,
  35. // TProtocol, TTransportFactory, TProtocolFactory, and other implementations.
  36. //
  37. // When constructing TConfiguration, you only need to specify the non-default
  38. // fields. All zero values have sane default values.
  39. //
  40. // Not all configurations defined are applicable to all implementations.
  41. // Implementations are free to ignore the configurations not applicable to them.
  42. //
  43. // All functions attached to this type are nil-safe.
  44. //
  45. // See [1] for spec.
  46. //
  47. // NOTE: When using TConfiguration, fill in all the configurations you want to
  48. // set across the stack, not only the ones you want to set in the immediate
  49. // TTransport/TProtocol.
  50. //
  51. // For example, say you want to migrate this old code into using TConfiguration:
  52. //
  53. // sccket := thrift.NewTSocketTimeout("host:port", time.Second)
  54. // transFactory := thrift.NewTFramedTransportFactoryMaxLength(
  55. // thrift.NewTTransportFactory(),
  56. // 1024 * 1024 * 256,
  57. // )
  58. // protoFactory := thrift.NewTBinaryProtocolFactory(true, true)
  59. //
  60. // This is the wrong way to do it because in the end the TConfiguration used by
  61. // socket and transFactory will be overwritten by the one used by protoFactory
  62. // because of TConfiguration propagation:
  63. //
  64. // // bad example, DO NOT USE
  65. // sccket := thrift.NewTSocketConf("host:port", &thrift.TConfiguration{
  66. // ConnectTimeout: time.Second,
  67. // SocketTimeout: time.Second,
  68. // })
  69. // transFactory := thrift.NewTFramedTransportFactoryConf(
  70. // thrift.NewTTransportFactory(),
  71. // &thrift.TConfiguration{
  72. // MaxFrameSize: 1024 * 1024 * 256,
  73. // },
  74. // )
  75. // protoFactory := thrift.NewTBinaryProtocolFactoryConf(&thrift.TConfiguration{
  76. // TBinaryStrictRead: thrift.BoolPtr(true),
  77. // TBinaryStrictWrite: thrift.BoolPtr(true),
  78. // })
  79. //
  80. // This is the correct way to do it:
  81. //
  82. // conf := &thrift.TConfiguration{
  83. // ConnectTimeout: time.Second,
  84. // SocketTimeout: time.Second,
  85. //
  86. // MaxFrameSize: 1024 * 1024 * 256,
  87. //
  88. // TBinaryStrictRead: thrift.BoolPtr(true),
  89. // TBinaryStrictWrite: thrift.BoolPtr(true),
  90. // }
  91. // sccket := thrift.NewTSocketConf("host:port", conf)
  92. // transFactory := thrift.NewTFramedTransportFactoryConf(thrift.NewTTransportFactory(), conf)
  93. // protoFactory := thrift.NewTBinaryProtocolFactoryConf(conf)
  94. //
  95. // [1]: https://github.com/apache/thrift/blob/master/doc/specs/thrift-tconfiguration.md
  96. type TConfiguration struct {
  97. // If <= 0, DEFAULT_MAX_MESSAGE_SIZE will be used instead.
  98. MaxMessageSize int32
  99. // If <= 0, DEFAULT_MAX_FRAME_SIZE will be used instead.
  100. //
  101. // Also if MaxMessageSize < MaxFrameSize,
  102. // MaxMessageSize will be used instead.
  103. MaxFrameSize int32
  104. // Connect and socket timeouts to be used by TSocket and TSSLSocket.
  105. //
  106. // 0 means no timeout.
  107. //
  108. // If <0, DEFAULT_CONNECT_TIMEOUT and DEFAULT_SOCKET_TIMEOUT will be
  109. // used.
  110. ConnectTimeout time.Duration
  111. SocketTimeout time.Duration
  112. // TLS config to be used by TSSLSocket.
  113. TLSConfig *tls.Config
  114. // Strict read/write configurations for TBinaryProtocol.
  115. //
  116. // BoolPtr helper function is available to use literal values.
  117. TBinaryStrictRead *bool
  118. TBinaryStrictWrite *bool
  119. // The wrapped protocol id to be used in THeader transport/protocol.
  120. //
  121. // THeaderProtocolIDPtr and THeaderProtocolIDPtrMust helper functions
  122. // are provided to help filling this value.
  123. THeaderProtocolID *THeaderProtocolID
  124. // Used internally by deprecated constructors, to avoid overriding
  125. // underlying TTransport/TProtocol's cfg by accidental propagations.
  126. //
  127. // For external users this is always false.
  128. noPropagation bool
  129. }
  130. // GetMaxMessageSize returns the max message size an implementation should
  131. // follow.
  132. //
  133. // It's nil-safe. DEFAULT_MAX_MESSAGE_SIZE will be returned if tc is nil.
  134. func (tc *TConfiguration) GetMaxMessageSize() int32 {
  135. if tc == nil || tc.MaxMessageSize <= 0 {
  136. return DEFAULT_MAX_MESSAGE_SIZE
  137. }
  138. return tc.MaxMessageSize
  139. }
  140. // GetMaxFrameSize returns the max frame size an implementation should follow.
  141. //
  142. // It's nil-safe. DEFAULT_MAX_FRAME_SIZE will be returned if tc is nil.
  143. //
  144. // If the configured max message size is smaller than the configured max frame
  145. // size, the smaller one will be returned instead.
  146. func (tc *TConfiguration) GetMaxFrameSize() int32 {
  147. if tc == nil {
  148. return DEFAULT_MAX_FRAME_SIZE
  149. }
  150. maxFrameSize := tc.MaxFrameSize
  151. if maxFrameSize <= 0 {
  152. maxFrameSize = DEFAULT_MAX_FRAME_SIZE
  153. }
  154. if maxMessageSize := tc.GetMaxMessageSize(); maxMessageSize < maxFrameSize {
  155. return maxMessageSize
  156. }
  157. return maxFrameSize
  158. }
  159. // GetConnectTimeout returns the connect timeout should be used by TSocket and
  160. // TSSLSocket.
  161. //
  162. // It's nil-safe. If tc is nil, DEFAULT_CONNECT_TIMEOUT will be returned instead.
  163. func (tc *TConfiguration) GetConnectTimeout() time.Duration {
  164. if tc == nil || tc.ConnectTimeout < 0 {
  165. return DEFAULT_CONNECT_TIMEOUT
  166. }
  167. return tc.ConnectTimeout
  168. }
  169. // GetSocketTimeout returns the socket timeout should be used by TSocket and
  170. // TSSLSocket.
  171. //
  172. // It's nil-safe. If tc is nil, DEFAULT_SOCKET_TIMEOUT will be returned instead.
  173. func (tc *TConfiguration) GetSocketTimeout() time.Duration {
  174. if tc == nil || tc.SocketTimeout < 0 {
  175. return DEFAULT_SOCKET_TIMEOUT
  176. }
  177. return tc.SocketTimeout
  178. }
  179. // GetTLSConfig returns the tls config should be used by TSSLSocket.
  180. //
  181. // It's nil-safe. If tc is nil, nil will be returned instead.
  182. func (tc *TConfiguration) GetTLSConfig() *tls.Config {
  183. if tc == nil {
  184. return nil
  185. }
  186. return tc.TLSConfig
  187. }
  188. // GetTBinaryStrictRead returns the strict read configuration TBinaryProtocol
  189. // should follow.
  190. //
  191. // It's nil-safe. DEFAULT_TBINARY_STRICT_READ will be returned if either tc or
  192. // tc.TBinaryStrictRead is nil.
  193. func (tc *TConfiguration) GetTBinaryStrictRead() bool {
  194. if tc == nil || tc.TBinaryStrictRead == nil {
  195. return DEFAULT_TBINARY_STRICT_READ
  196. }
  197. return *tc.TBinaryStrictRead
  198. }
  199. // GetTBinaryStrictWrite returns the strict read configuration TBinaryProtocol
  200. // should follow.
  201. //
  202. // It's nil-safe. DEFAULT_TBINARY_STRICT_WRITE will be returned if either tc or
  203. // tc.TBinaryStrictWrite is nil.
  204. func (tc *TConfiguration) GetTBinaryStrictWrite() bool {
  205. if tc == nil || tc.TBinaryStrictWrite == nil {
  206. return DEFAULT_TBINARY_STRICT_WRITE
  207. }
  208. return *tc.TBinaryStrictWrite
  209. }
  210. // GetTHeaderProtocolID returns the THeaderProtocolID should be used by
  211. // THeaderProtocol clients (for servers, they always use the same one as the
  212. // client instead).
  213. //
  214. // It's nil-safe. If either tc or tc.THeaderProtocolID is nil,
  215. // THeaderProtocolDefault will be returned instead.
  216. // THeaderProtocolDefault will also be returned if configured value is invalid.
  217. func (tc *TConfiguration) GetTHeaderProtocolID() THeaderProtocolID {
  218. if tc == nil || tc.THeaderProtocolID == nil {
  219. return THeaderProtocolDefault
  220. }
  221. protoID := *tc.THeaderProtocolID
  222. if err := protoID.Validate(); err != nil {
  223. return THeaderProtocolDefault
  224. }
  225. return protoID
  226. }
  227. // THeaderProtocolIDPtr validates and returns the pointer to id.
  228. //
  229. // If id is not a valid THeaderProtocolID, a pointer to THeaderProtocolDefault
  230. // and the validation error will be returned.
  231. func THeaderProtocolIDPtr(id THeaderProtocolID) (*THeaderProtocolID, error) {
  232. err := id.Validate()
  233. if err != nil {
  234. id = THeaderProtocolDefault
  235. }
  236. return &id, err
  237. }
  238. // THeaderProtocolIDPtrMust validates and returns the pointer to id.
  239. //
  240. // It's similar to THeaderProtocolIDPtr, but it panics on validation errors
  241. // instead of returning them.
  242. func THeaderProtocolIDPtrMust(id THeaderProtocolID) *THeaderProtocolID {
  243. ptr, err := THeaderProtocolIDPtr(id)
  244. if err != nil {
  245. panic(err)
  246. }
  247. return ptr
  248. }
  249. // TConfigurationSetter is an optional interface TProtocol, TTransport,
  250. // TProtocolFactory, TTransportFactory, and other implementations can implement.
  251. //
  252. // It's intended to be called during intializations.
  253. // The behavior of calling SetTConfiguration on a TTransport/TProtocol in the
  254. // middle of a message is undefined:
  255. // It may or may not change the behavior of the current processing message,
  256. // and it may even cause the current message to fail.
  257. //
  258. // Note for implementations: SetTConfiguration might be called multiple times
  259. // with the same value in quick successions due to the implementation of the
  260. // propagation. Implementations should make SetTConfiguration as simple as
  261. // possible (usually just overwrite the stored configuration and propagate it to
  262. // the wrapped TTransports/TProtocols).
  263. type TConfigurationSetter interface {
  264. SetTConfiguration(*TConfiguration)
  265. }
  266. // PropagateTConfiguration propagates cfg to impl if impl implements
  267. // TConfigurationSetter and cfg is non-nil, otherwise it does nothing.
  268. //
  269. // NOTE: nil cfg is not propagated. If you want to propagate a TConfiguration
  270. // with everything being default value, use &TConfiguration{} explicitly instead.
  271. func PropagateTConfiguration(impl interface{}, cfg *TConfiguration) {
  272. if cfg == nil || cfg.noPropagation {
  273. return
  274. }
  275. if setter, ok := impl.(TConfigurationSetter); ok {
  276. setter.SetTConfiguration(cfg)
  277. }
  278. }
  279. func checkSizeForProtocol(size int32, cfg *TConfiguration) error {
  280. if size < 0 {
  281. return NewTProtocolExceptionWithType(
  282. NEGATIVE_SIZE,
  283. fmt.Errorf("negative size: %d", size),
  284. )
  285. }
  286. if size > cfg.GetMaxMessageSize() {
  287. return NewTProtocolExceptionWithType(
  288. SIZE_LIMIT,
  289. fmt.Errorf("size exceeded max allowed: %d", size),
  290. )
  291. }
  292. return nil
  293. }
  294. type tTransportFactoryConf struct {
  295. delegate TTransportFactory
  296. cfg *TConfiguration
  297. }
  298. func (f *tTransportFactoryConf) GetTransport(orig TTransport) (TTransport, error) {
  299. trans, err := f.delegate.GetTransport(orig)
  300. if err == nil {
  301. PropagateTConfiguration(orig, f.cfg)
  302. PropagateTConfiguration(trans, f.cfg)
  303. }
  304. return trans, err
  305. }
  306. func (f *tTransportFactoryConf) SetTConfiguration(cfg *TConfiguration) {
  307. PropagateTConfiguration(f.delegate, f.cfg)
  308. f.cfg = cfg
  309. }
  310. // TTransportFactoryConf wraps a TTransportFactory to propagate
  311. // TConfiguration on the factory's GetTransport calls.
  312. func TTransportFactoryConf(delegate TTransportFactory, conf *TConfiguration) TTransportFactory {
  313. return &tTransportFactoryConf{
  314. delegate: delegate,
  315. cfg: conf,
  316. }
  317. }
  318. type tProtocolFactoryConf struct {
  319. delegate TProtocolFactory
  320. cfg *TConfiguration
  321. }
  322. func (f *tProtocolFactoryConf) GetProtocol(trans TTransport) TProtocol {
  323. proto := f.delegate.GetProtocol(trans)
  324. PropagateTConfiguration(trans, f.cfg)
  325. PropagateTConfiguration(proto, f.cfg)
  326. return proto
  327. }
  328. func (f *tProtocolFactoryConf) SetTConfiguration(cfg *TConfiguration) {
  329. PropagateTConfiguration(f.delegate, f.cfg)
  330. f.cfg = cfg
  331. }
  332. // TProtocolFactoryConf wraps a TProtocolFactory to propagate
  333. // TConfiguration on the factory's GetProtocol calls.
  334. func TProtocolFactoryConf(delegate TProtocolFactory, conf *TConfiguration) TProtocolFactory {
  335. return &tProtocolFactoryConf{
  336. delegate: delegate,
  337. cfg: conf,
  338. }
  339. }
  340. var (
  341. _ TConfigurationSetter = (*tTransportFactoryConf)(nil)
  342. _ TConfigurationSetter = (*tProtocolFactoryConf)(nil)
  343. )