[server] Try to optimize memory allocations for FastHTTP to Go HTTP bridging (it involves heavy "magic").
This commit is contained in:
parent
e817765cfd
commit
01586f506d
3 changed files with 125 additions and 11 deletions
|
@ -503,27 +503,29 @@ func (_server *server) ServeHTTP (_response http.ResponseWriter, _request *http.
|
||||||
|
|
||||||
_server.Serve (_context)
|
_server.Serve (_context)
|
||||||
|
|
||||||
_responseHeaders := _response.Header ()
|
_responseHeaders := HttpResponseWriterHeaderDoMagic (_response)
|
||||||
_responseHeaders["Date"] = nil
|
|
||||||
_context.Response.Header.VisitAll (
|
_context.Response.Header.VisitAll (
|
||||||
func (_key_0 []byte, _value_0 []byte) () {
|
func (_key_0 []byte, _value_0 []byte) () {
|
||||||
switch string (_key_0) {
|
switch string (_key_0) {
|
||||||
case "Connection", "Content-Length", "Date" :
|
case "Connection", "Content-Length", "Date" :
|
||||||
// NOP
|
// NOP
|
||||||
default :
|
default :
|
||||||
_key := string (_key_0)
|
_key := CanonicalHeaderNameFromBytes (_key_0)
|
||||||
_value := string (_value_0)
|
if _values, _ := _responseHeaders[_key]; _values == nil {
|
||||||
_responseHeaders[_key] = append (_responseHeaders[_key], _value)
|
_values = CanonicalHeaderValueArrayFromBytes (_value_0)
|
||||||
|
_responseHeaders[_key] = _values
|
||||||
|
} else {
|
||||||
|
_value := CanonicalHeaderValueFromBytes (_value_0)
|
||||||
|
_values = append (_values, _value)
|
||||||
|
_responseHeaders[_key] = _values
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
_responseHeaders["Date"] = nil
|
||||||
_responseBody := _context.Response.Body ()
|
|
||||||
if len (_responseBody) > 0 {
|
|
||||||
_responseHeaders["Content-Length"] = []string { fmt.Sprintf ("%d", len (_responseBody)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
_response.WriteHeader (_context.Response.Header.StatusCode ())
|
_response.WriteHeader (_context.Response.Header.StatusCode ())
|
||||||
_response.Write (_responseBody)
|
|
||||||
|
_response.Write (_context.Response.Body ())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -724,6 +726,7 @@ func main_0 () (error) {
|
||||||
} else {
|
} else {
|
||||||
AbortError (nil, "[1a5476b1] HTTP/3 Alt-Svc is invalid!")
|
AbortError (nil, "[1a5476b1] HTTP/3 Alt-Svc is invalid!")
|
||||||
}
|
}
|
||||||
|
CanonicalHeaderValueRegister (_http3AltSvc)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !_dummy {
|
if !_dummy {
|
||||||
|
|
98
sources/lib/server/headers-magic.go
Normal file
98
sources/lib/server/headers-magic.go
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
|
||||||
|
|
||||||
|
package server
|
||||||
|
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
import "net/http"
|
||||||
|
import "log"
|
||||||
|
import "reflect"
|
||||||
|
import "sync/atomic"
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func HttpResponseWriterHeaderDoMagic (_response http.ResponseWriter) (http.Header) {
|
||||||
|
|
||||||
|
|
||||||
|
if !_httpResponseWriteHeaderMagic_enabled {
|
||||||
|
return _response.Header ()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE: Because we don't modify the headers after calling `WriteHeader`,
|
||||||
|
// the following code tricks `net/http` into believing it didn't gave us the headers.
|
||||||
|
// This eliminates the `http.Header.Clone()` call on `WriteHeader`.
|
||||||
|
|
||||||
|
_responseReflect := reflect.ValueOf (_response) .Elem ()
|
||||||
|
_responseAddress := unsafe.Pointer (_responseReflect.UnsafeAddr ())
|
||||||
|
_responseType := _responseReflect.Type ()
|
||||||
|
_responsePackage := _responseType.PkgPath ()
|
||||||
|
_responseTypeName := _responseType.Name ()
|
||||||
|
|
||||||
|
var _header http.Header
|
||||||
|
|
||||||
|
switch {
|
||||||
|
|
||||||
|
case (_responsePackage == "net/http") && (_responseTypeName == "response") : {
|
||||||
|
|
||||||
|
_handlerHeaderOffset := atomic.LoadInt32 (&_httpResponseWriteHeaderMagic_netHttp_handlerHeaderOffset)
|
||||||
|
_cwHeaderOffset := atomic.LoadInt32 (&_httpResponseWriteHeaderMagic_netHttp_cwHeaderOffset)
|
||||||
|
|
||||||
|
if (_handlerHeaderOffset == 0) || (_cwHeaderOffset == 0) {
|
||||||
|
|
||||||
|
_handlerHeaderReflect := _responseReflect.FieldByName ("handlerHeader")
|
||||||
|
_handlerHeaderAddress := unsafe.Pointer (_handlerHeaderReflect.UnsafeAddr ())
|
||||||
|
|
||||||
|
_cwHeaderReflect := _responseReflect.FieldByName ("cw") .FieldByName ("header")
|
||||||
|
_cwHeaderAddress := unsafe.Pointer (_cwHeaderReflect.UnsafeAddr ())
|
||||||
|
|
||||||
|
_handlerHeaderOffset = int32 (int64 (uintptr (_handlerHeaderAddress)) - int64 (uintptr (_responseAddress)))
|
||||||
|
_cwHeaderOffset = int32 (int64 (uintptr (_cwHeaderAddress)) - int64 (uintptr (_responseAddress)))
|
||||||
|
|
||||||
|
atomic.StoreInt32 (&_httpResponseWriteHeaderMagic_netHttp_handlerHeaderOffset, _handlerHeaderOffset)
|
||||||
|
atomic.StoreInt32 (&_httpResponseWriteHeaderMagic_netHttp_cwHeaderOffset, _cwHeaderOffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
_handlerHeaderValue := (*http.Header) (unsafe.Add (_responseAddress, _handlerHeaderOffset))
|
||||||
|
_cwHeaderValue := (*http.Header) (unsafe.Add (_responseAddress, _cwHeaderOffset))
|
||||||
|
|
||||||
|
_header = make (map[string][]string, 16)
|
||||||
|
|
||||||
|
*_handlerHeaderValue = _header
|
||||||
|
*_cwHeaderValue = _header
|
||||||
|
}
|
||||||
|
|
||||||
|
case (_responsePackage == "net/http") && (_responseTypeName == "http2responseWriter") : {
|
||||||
|
|
||||||
|
_header = _response.Header ()
|
||||||
|
}
|
||||||
|
|
||||||
|
case (_responsePackage == "github.com/lucas-clemente/quic-go/http3") && (_responseTypeName == "responseWriter") : {
|
||||||
|
|
||||||
|
_header = _response.Header ()
|
||||||
|
}
|
||||||
|
|
||||||
|
default : {
|
||||||
|
|
||||||
|
log.Printf ("[ee] [64583df9] unsupported HTTP ResponseWriter `%s.%s`!\n", _responsePackage, _responseTypeName)
|
||||||
|
|
||||||
|
if _httpResponseWriteHeaderMagic_panic {
|
||||||
|
panic (fmt.Sprintf ("[09274c17] unsupported HTTP ResponseWriter `%s.%s`!", _responsePackage, _responseTypeName))
|
||||||
|
}
|
||||||
|
|
||||||
|
_header = _response.Header ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _header
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var _httpResponseWriteHeaderMagic_enabled = true
|
||||||
|
var _httpResponseWriteHeaderMagic_panic = true
|
||||||
|
|
||||||
|
var _httpResponseWriteHeaderMagic_netHttp_handlerHeaderOffset int32
|
||||||
|
var _httpResponseWriteHeaderMagic_netHttp_cwHeaderOffset int32
|
||||||
|
|
|
@ -22,6 +22,8 @@ func CanonicalHeaderNameFromBytes (_header []byte) (string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func CanonicalHeaderValueFromBytes (_value []byte) (string) {
|
func CanonicalHeaderValueFromBytes (_value []byte) (string) {
|
||||||
if _canonical, _found := CanonicalHeaderValuesMap[BytesToString (*NoEscapeBytes (&_value))]; _found {
|
if _canonical, _found := CanonicalHeaderValuesMap[BytesToString (*NoEscapeBytes (&_value))]; _found {
|
||||||
return _canonical
|
return _canonical
|
||||||
|
@ -30,6 +32,14 @@ func CanonicalHeaderValueFromBytes (_value []byte) (string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CanonicalHeaderValueArrayFromBytes (_value []byte) ([]string) {
|
||||||
|
if _canonical, _found := CanonicalHeaderValuesArraysMap[BytesToString (*NoEscapeBytes (&_value))]; _found {
|
||||||
|
return _canonical
|
||||||
|
} else {
|
||||||
|
return []string { string (_value) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func CanonicalHeaderValueRegister (_value string) () {
|
func CanonicalHeaderValueRegister (_value string) () {
|
||||||
CanonicalHeaderValues = append (CanonicalHeaderValues, _value)
|
CanonicalHeaderValues = append (CanonicalHeaderValues, _value)
|
||||||
|
@ -41,6 +51,7 @@ func CanonicalHeaderValueRegister (_value string) () {
|
||||||
|
|
||||||
var CanonicalHeaderNamesMap map[string]string
|
var CanonicalHeaderNamesMap map[string]string
|
||||||
var CanonicalHeaderValuesMap map[string]string
|
var CanonicalHeaderValuesMap map[string]string
|
||||||
|
var CanonicalHeaderValuesArraysMap map[string][]string
|
||||||
|
|
||||||
|
|
||||||
var CanonicalHeaderNames = []string {
|
var CanonicalHeaderNames = []string {
|
||||||
|
@ -218,8 +229,10 @@ func init () {
|
||||||
CanonicalHeaderValues = append (CanonicalHeaderValues, MimeTypes ...)
|
CanonicalHeaderValues = append (CanonicalHeaderValues, MimeTypes ...)
|
||||||
|
|
||||||
CanonicalHeaderValuesMap = make (map[string]string, len (CanonicalHeaderValues))
|
CanonicalHeaderValuesMap = make (map[string]string, len (CanonicalHeaderValues))
|
||||||
|
CanonicalHeaderValuesArraysMap = make (map[string][]string, len (CanonicalHeaderValues))
|
||||||
for _, _value := range CanonicalHeaderValues {
|
for _, _value := range CanonicalHeaderValues {
|
||||||
CanonicalHeaderValuesMap[_value] = _value
|
CanonicalHeaderValuesMap[_value] = _value
|
||||||
|
CanonicalHeaderValuesArraysMap[_value] = []string { _value }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue