github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/transports/standard/convert.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  	"bytes"
    22  	"github.com/aacfactory/errors"
    23  	"github.com/aacfactory/fns/commons/bytex"
    24  	"github.com/aacfactory/fns/transports"
    25  	"io"
    26  	"net/http"
    27  	"net/url"
    28  )
    29  
    30  func ConvertHttpHandlerFunc(h http.HandlerFunc) transports.Handler {
    31  	return ConvertHttpHandler(h)
    32  }
    33  
    34  func ConvertHttpHandler(h http.Handler) transports.Handler {
    35  	return transports.HandlerFunc(func(writer transports.ResponseWriter, request transports.Request) {
    36  		var r http.Request
    37  		if err := ConvertRequest(request, &r, true); err != nil {
    38  			writer.Failed(errors.Warning("fns: convert to http.Request failed").WithCause(err))
    39  			return
    40  		}
    41  		w := netHTTPResponseWriter{w: writer}
    42  		h.ServeHTTP(&w, r.WithContext(request))
    43  		writer.SetStatus(w.StatusCode())
    44  		haveContentType := false
    45  		for k, vv := range w.Header() {
    46  			if k == bytex.ToString(transports.ContentTypeHeaderName) {
    47  				haveContentType = true
    48  			}
    49  
    50  			for _, v := range vv {
    51  				writer.Header().Add(bytex.FromString(k), bytex.FromString(v))
    52  			}
    53  		}
    54  		if !haveContentType {
    55  			l := 512
    56  			b := writer.Body()
    57  			if len(b) < 512 {
    58  				l = len(b)
    59  			}
    60  			writer.Header().Set(transports.ContentTypeHeaderName, bytex.FromString(http.DetectContentType(b[:l])))
    61  		}
    62  	})
    63  }
    64  
    65  func ConvertRequest(ctx transports.Request, r *http.Request, forServer bool) error {
    66  	body, bodyErr := ctx.Body()
    67  	if bodyErr != nil {
    68  		return bodyErr
    69  	}
    70  	strRequestURI := bytex.ToString(ctx.RequestURI())
    71  
    72  	rURL, err := url.ParseRequestURI(strRequestURI)
    73  	if err != nil {
    74  		return err
    75  	}
    76  
    77  	r.Method = bytex.ToString(ctx.Method())
    78  	r.Proto = bytex.ToString(ctx.Proto())
    79  	if r.Proto == "HTTP/2" {
    80  		r.ProtoMajor = 2
    81  	} else {
    82  		r.ProtoMajor = 1
    83  	}
    84  	r.ProtoMinor = 1
    85  	r.ContentLength = int64(len(body))
    86  	r.RemoteAddr = bytex.ToString(ctx.RemoteAddr())
    87  	r.Host = bytex.ToString(ctx.Host())
    88  	r.TLS = ctx.TLSConnectionState()
    89  	r.Body = io.NopCloser(bytes.NewReader(body))
    90  	r.URL = rURL
    91  
    92  	if forServer {
    93  		r.RequestURI = strRequestURI
    94  	}
    95  
    96  	if r.Header == nil {
    97  		r.Header = make(http.Header)
    98  	} else if len(r.Header) > 0 {
    99  		for k := range r.Header {
   100  			delete(r.Header, k)
   101  		}
   102  	}
   103  
   104  	ctx.Header().Foreach(func(k []byte, vv [][]byte) {
   105  		sk := bytex.ToString(k)
   106  		for _, v := range vv {
   107  			sv := bytex.ToString(v)
   108  			switch sk {
   109  			case "Transfer-Encoding":
   110  				r.TransferEncoding = append(r.TransferEncoding, sv)
   111  			default:
   112  				r.Header.Add(sk, sv)
   113  			}
   114  		}
   115  	})
   116  
   117  	return nil
   118  }
   119  
   120  type netHTTPResponseWriter struct {
   121  	statusCode int
   122  	h          http.Header
   123  	w          io.Writer
   124  }
   125  
   126  func (w *netHTTPResponseWriter) StatusCode() int {
   127  	if w.statusCode == 0 {
   128  		return http.StatusOK
   129  	}
   130  	return w.statusCode
   131  }
   132  
   133  func (w *netHTTPResponseWriter) Header() http.Header {
   134  	if w.h == nil {
   135  		w.h = make(http.Header)
   136  	}
   137  	return w.h
   138  }
   139  
   140  func (w *netHTTPResponseWriter) WriteHeader(statusCode int) {
   141  	w.statusCode = statusCode
   142  }
   143  
   144  func (w *netHTTPResponseWriter) Write(p []byte) (int, error) {
   145  	return w.w.Write(p)
   146  }
   147  
   148  func (w *netHTTPResponseWriter) Flush() {}