| // Licensed to the Apache Software Foundation (ASF) under one or more |
| // contributor license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright ownership. |
| // The ASF licenses this file to You under the Apache License, Version 2.0 |
| // (the "License"); you may not use this file except in compliance with |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| package http |
| |
| import ( |
| "bytes" |
| "net/http" |
| "sync" |
| |
| "github.com/api7/ext-plugin-proto/go/A6" |
| hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall" |
| flatbuffers "github.com/google/flatbuffers/go" |
| ) |
| |
| type Response struct { |
| hdr http.Header |
| body *bytes.Buffer |
| code int |
| } |
| |
| func (r *Response) Header() http.Header { |
| if r.hdr == nil { |
| r.hdr = http.Header{} |
| } |
| return r.hdr |
| } |
| |
| func (r *Response) Write(b []byte) (int, error) { |
| if r.body == nil { |
| r.body = &bytes.Buffer{} |
| } |
| |
| return r.body.Write(b) |
| } |
| |
| func (r *Response) WriteHeader(statusCode int) { |
| if r.code != 0 { |
| // official WriteHeader can't override written status |
| // keep the same behavior |
| return |
| } |
| r.code = statusCode |
| } |
| |
| func (r *Response) Reset() { |
| r.body = nil |
| r.code = 0 |
| r.hdr = nil |
| } |
| |
| func (r *Response) HasChange() bool { |
| return !(r.body == nil && r.code == 0 && len(r.hdr) == 0) |
| } |
| |
| func (r *Response) FetchChanges(id uint32, builder *flatbuffers.Builder) bool { |
| if !r.HasChange() { |
| return false |
| } |
| |
| hdrLen := len(r.hdr) |
| var hdrVec flatbuffers.UOffsetT |
| if hdrLen > 0 { |
| hdrs := []flatbuffers.UOffsetT{} |
| for n, arr := range r.hdr { |
| for _, v := range arr { |
| name := builder.CreateString(n) |
| value := builder.CreateString(v) |
| A6.TextEntryStart(builder) |
| A6.TextEntryAddName(builder, name) |
| A6.TextEntryAddValue(builder, value) |
| te := A6.TextEntryEnd(builder) |
| hdrs = append(hdrs, te) |
| } |
| } |
| size := len(hdrs) |
| hrc.StopStartHeadersVector(builder, size) |
| for i := size - 1; i >= 0; i-- { |
| te := hdrs[i] |
| builder.PrependUOffsetT(te) |
| } |
| hdrVec = builder.EndVector(size) |
| } |
| |
| var bodyVec flatbuffers.UOffsetT |
| if r.body != nil { |
| b := r.body.Bytes() |
| if len(b) > 0 { |
| bodyVec = builder.CreateByteVector(b) |
| } |
| } |
| |
| hrc.StopStart(builder) |
| if r.code == 0 { |
| hrc.StopAddStatus(builder, 200) |
| } else { |
| hrc.StopAddStatus(builder, uint16(r.code)) |
| } |
| if hdrLen > 0 { |
| hrc.StopAddHeaders(builder, hdrVec) |
| } |
| if r.body != nil { |
| hrc.StopAddBody(builder, bodyVec) |
| } |
| stop := hrc.StopEnd(builder) |
| |
| hrc.RespStart(builder) |
| hrc.RespAddId(builder, id) |
| hrc.RespAddActionType(builder, hrc.ActionStop) |
| hrc.RespAddAction(builder, stop) |
| res := hrc.RespEnd(builder) |
| builder.Finish(res) |
| |
| return true |
| } |
| |
| var respPool = sync.Pool{ |
| New: func() interface{} { |
| return &Response{} |
| }, |
| } |
| |
| func CreateResponse() *Response { |
| return respPool.Get().(*Response) |
| } |
| |
| func ReuseResponse(r *Response) { |
| r.Reset() |
| respPool.Put(r) |
| } |