github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/transports/standard/adaptor.go (about)

     1  /*
     2   * Copyright 2023 Wang Min Xiang
     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  
    18  package standard
    19  
    20  import (
    21  	"github.com/aacfactory/fns/commons/bytex"
    22  	"github.com/aacfactory/fns/context"
    23  	"github.com/aacfactory/fns/transports"
    24  	"net/http"
    25  	"sync"
    26  	"time"
    27  )
    28  
    29  var (
    30  	requestPool  = sync.Pool{}
    31  	responsePool = sync.Pool{}
    32  )
    33  
    34  func HttpTransportHandlerAdaptor(h transports.Handler, maxRequestBody int, writeTimeout time.Duration) http.Handler {
    35  	return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
    36  		ctx := context.Acquire(request.Context())
    37  
    38  		var r *Request
    39  		cr := requestPool.Get()
    40  		if cr == nil {
    41  			r = new(Request)
    42  		} else {
    43  			r = cr.(*Request)
    44  		}
    45  		r.Context = ctx
    46  		r.maxBodySize = maxRequestBody
    47  		r.request = request
    48  
    49  		var w *ResponseWriter
    50  		cw := responsePool.Get()
    51  		if cw == nil {
    52  			w = new(ResponseWriter)
    53  		} else {
    54  			w = cw.(*ResponseWriter)
    55  		}
    56  		w.Context = ctx
    57  		w.writer = writer
    58  		w.header = WrapHttpHeader(writer.Header())
    59  		w.result = transports.AcquireResultResponseWriter(writeTimeout, r.Header().Get(transports.ContentTypeHeaderName))
    60  
    61  		h.Handle(w, r)
    62  		w.result.Header().Foreach(func(key []byte, values [][]byte) {
    63  			for _, value := range values {
    64  				writer.Header().Add(bytex.ToString(key), bytex.ToString(value))
    65  			}
    66  		})
    67  		writer.WriteHeader(w.Status())
    68  		if bodyLen := w.BodyLen(); bodyLen > 0 {
    69  			body := w.Body()
    70  			n := 0
    71  			for n < bodyLen {
    72  				nn, writeErr := writer.Write(body[n:])
    73  				if writeErr != nil {
    74  					break
    75  				}
    76  				n += nn
    77  			}
    78  		}
    79  
    80  		if !w.Hijacked() {
    81  			transports.ReleaseResultResponseWriter(w.result)
    82  			w.Context = nil
    83  			w.writer = nil
    84  			w.header = nil
    85  			w.result = nil
    86  			w.hijacked = false
    87  			responsePool.Put(w)
    88  
    89  			r.Context = nil
    90  			r.maxBodySize = 0
    91  			r.request = nil
    92  			requestPool.Put(r)
    93  
    94  			context.Release(ctx)
    95  		}
    96  
    97  	})
    98  }