github.com/cloudwego/dynamicgo@v0.2.6-0.20240519101509-707f41b6b834/conv/t2j/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 t2j 18 19 import ( 20 "context" 21 "fmt" 22 23 "github.com/cloudwego/dynamicgo/conv" 24 "github.com/cloudwego/dynamicgo/http" 25 "github.com/cloudwego/dynamicgo/meta" 26 "github.com/cloudwego/dynamicgo/thrift" 27 ) 28 29 // HTTPConv is a converter from thrift message to http response 30 type HTTPConv struct { 31 proto meta.Encoding 32 st *thrift.StructDescriptor 33 } 34 35 // NewHTTPConv returns a new HTTPConv 36 func NewHTTPConv(proto meta.Encoding, desc *thrift.FunctionDescriptor) *HTTPConv { 37 switch proto { 38 case meta.EncodingThriftBinary: 39 // do nothing 40 default: 41 panic(fmt.Sprintf("protocol %#v is not supported", proto)) 42 } 43 44 if desc.Response().Struct().FieldById(0) == nil { 45 panic("response field is not found in function") 46 } 47 48 return &HTTPConv{ 49 proto: proto, 50 st: desc.Response().Struct(), 51 } 52 } 53 54 // Do converts thrift message (tbytes) into http response. 55 // resp body is set as json protocol if has 56 func (h HTTPConv) Do(ctx context.Context, resp http.ResponseSetter, tbytes []byte, opt conv.Options) (err error) { 57 if h.proto != meta.EncodingThriftBinary { 58 panic("now only support binary protocol") 59 } 60 var stDef *thrift.TypeDescriptor 61 // not a reply struct, cannot be decoded 62 _, rTyp, _, respID, tbytes, err := thrift.UnwrapBinaryMessage(tbytes) 63 if err != nil { 64 return wrapError(meta.ErrRead, "", err) 65 } 66 if rTyp != thrift.REPLY { 67 field := h.st.FieldById(respID) 68 if field == nil { 69 return wrapError(meta.ErrUnknownField, "exception field is not foud in function", nil) 70 } 71 stDef = field.Type() 72 } else { 73 if respID != 0 { 74 return wrapError(meta.ErrInvalidParam, fmt.Sprintf("unexpected response field id %d", respID), nil) 75 } 76 stDef = h.st.FieldById(0).Type() 77 } 78 79 opt.EnableHttpMapping = true 80 cv := NewBinaryConv(opt) 81 // manage buffer 82 buf := conv.NewBytes() 83 // do translation 84 err = cv.do(ctx, tbytes, stDef, buf, resp) 85 if err != nil { 86 return 87 } 88 89 body := make([]byte, len(*buf)) 90 copy(body, *buf) 91 resp.SetRawBody(body) 92 93 conv.FreeBytes(buf) // explicit leak by on panic 94 return 95 } 96 97 // DoInto converts the thrift message (tbytes) to into buf in JSON protocol, as well as other http response arguments. 98 // WARN: This will set buf to resp, thus DONOT reuse the buf afterward. 99 func (h HTTPConv) DoInto(ctx context.Context, resp http.ResponseSetter, tbytes []byte, buf *[]byte, opt conv.Options) (err error) { 100 if h.proto != meta.EncodingThriftBinary { 101 panic("now only support binary protocol") 102 } 103 var stDef *thrift.TypeDescriptor 104 // not a reply struct, cannot be decoded 105 _, rTyp, _, respID, tbytes, err := thrift.UnwrapBinaryMessage(tbytes) 106 if err != nil { 107 return wrapError(meta.ErrRead, "", err) 108 } 109 if rTyp != thrift.REPLY { 110 field := h.st.FieldById(respID) 111 if field == nil { 112 return wrapError(meta.ErrUnknownField, "exception field is not foud in function", nil) 113 } 114 stDef = field.Type() 115 } else { 116 if respID != 0 { 117 return wrapError(meta.ErrInvalidParam, fmt.Sprintf("unexpected response field id %d", respID), nil) 118 } 119 stDef = h.st.FieldById(0).Type() 120 } 121 122 opt.EnableHttpMapping = true 123 cv := NewBinaryConv(opt) 124 err = cv.do(ctx, tbytes, stDef, buf, resp) 125 if err != nil { 126 return 127 } 128 resp.SetRawBody(*buf) 129 return 130 }