github.com/cloudwego/dynamicgo@v0.2.6-0.20240519101509-707f41b6b834/conv/j2t/http_conv.go (about) 1 /** 2 * Copyright 2023 CloudWeGo Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package j2t 18 19 import ( 20 "context" 21 22 "github.com/cloudwego/dynamicgo/conv" 23 "github.com/cloudwego/dynamicgo/http" 24 "github.com/cloudwego/dynamicgo/meta" 25 "github.com/cloudwego/dynamicgo/thrift" 26 ) 27 28 // HTTPConv is a converter from http request to thrift message 29 type HTTPConv struct { 30 proto meta.Encoding 31 st *thrift.TypeDescriptor 32 top, bottom []byte 33 } 34 35 // NewHTTPConv returns a new HTTPConv, which contains the thrift message header and footer 36 // 37 // proto is specified thrift encoding protocol (meta.EncodingThriftBinary|meta.EncodingThriftCompact) 38 // fnDesc is the thrift method descriptor corresponding to the http request url 39 func NewHTTPConv(proto meta.Encoding, fnDesc *thrift.FunctionDescriptor) *HTTPConv { 40 firstField := fnDesc.Request().Struct().Fields()[0] // TODO: some idl may have more than one request 41 if firstField.Type().Type() != thrift.STRUCT { 42 panic("first request field doesn't have struct kind") 43 } 44 45 if proto != meta.EncodingThriftBinary { 46 panic("now only support binary protocol") 47 } 48 49 header, footer, err := thrift.GetBinaryMessageHeaderAndFooter(fnDesc.Name(), thrift.CALL, firstField.ID(), 0) 50 if err != nil { 51 panic(err) 52 } 53 54 return &HTTPConv{ 55 proto: proto, 56 // if here is not exist, should panic, we don't have better solution 57 st: firstField.Type(), 58 top: header, 59 bottom: footer, 60 } 61 } 62 63 // Do converts http request into thrift message. 64 // req body must be one of following: 65 // - json (application/json) 66 // - url encoded form (application/x-www-form-urlencoded) 67 // - empty 68 func (h HTTPConv) Do(ctx context.Context, req http.RequestGetter, opt conv.Options) (tbytes []byte, err error) { 69 if h.proto != meta.EncodingThriftBinary { 70 panic("now only support binary protocol") 71 } 72 cv := NewBinaryConv(opt) 73 cv.opts.EnableHttpMapping = true 74 // dealing with http request 75 jbytes := req.GetBody() 76 // manage buffer 77 buf := conv.NewBytes() 78 // do translation 79 err = cv.do(ctx, jbytes, h.st, buf, req) 80 if err != nil { 81 return nil, err 82 } 83 // wrap the thrift message header and first fields' message 84 topLen := len(h.top) 85 bottomLen := len(h.bottom) 86 bufLen := len(*buf) 87 tbytes = make([]byte, topLen+bufLen+bottomLen) 88 copy(tbytes[:topLen], h.top) 89 copy(tbytes[topLen:topLen+bufLen], *buf) 90 copy(tbytes[topLen+bufLen:], h.bottom) 91 // reuse the buf buffer 92 conv.FreeBytes(buf) 93 return tbytes, nil 94 } 95 96 func (h HTTPConv) DoInto(ctx context.Context, req http.RequestGetter, buf *[]byte, opt conv.Options) (err error) { 97 if h.proto != meta.EncodingThriftBinary { 98 panic("now only support binary protocol") 99 } 100 cv := NewBinaryConv(opt) 101 cv.opts.EnableHttpMapping = true 102 // dealing with http request 103 jbytes := req.GetBody() 104 // write message header 105 *buf = append(*buf, h.top...) 106 // do translation 107 err = cv.do(ctx, jbytes, h.st, buf, req) 108 if err != nil { 109 return err 110 } 111 // write thrift message end and first fields' message 112 *buf = append(*buf, h.bottom...) 113 return nil 114 }