2021-12-17 19:58:36 +00:00
|
|
|
|
|
|
|
|
|
|
|
package server
|
|
|
|
|
|
|
|
|
|
|
|
import "fmt"
|
|
|
|
import "net/http"
|
|
|
|
import "log"
|
|
|
|
import "reflect"
|
|
|
|
import "sync/atomic"
|
|
|
|
import "unsafe"
|
|
|
|
|
|
|
|
|
2021-12-18 00:02:46 +00:00
|
|
|
import . "github.com/volution/kawipiko/lib/common"
|
|
|
|
|
|
|
|
|
2021-12-17 19:58:36 +00:00
|
|
|
|
|
|
|
|
2021-12-17 20:18:47 +00:00
|
|
|
type HttpResponseWriterHeadersBuffer struct {
|
|
|
|
status int
|
|
|
|
headers [128][2][]byte
|
|
|
|
headersCount int
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func NewHttpResponseWriterHeadersBuffer (_status int) (HttpResponseWriterHeadersBuffer) {
|
|
|
|
|
|
|
|
return HttpResponseWriterHeadersBuffer {
|
|
|
|
status : _status,
|
|
|
|
headersCount : 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-12-18 00:02:46 +00:00
|
|
|
func (_buffer *HttpResponseWriterHeadersBuffer) IncludeBytes (_name []byte, _value []byte) () {
|
2021-12-17 20:18:47 +00:00
|
|
|
|
|
|
|
if _buffer.headersCount == 128 {
|
2021-12-18 01:17:59 +00:00
|
|
|
panic ("[ca806ede] [magic] too many headers!")
|
2021-12-17 20:18:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
_buffer.headers[_buffer.headersCount] = [2][]byte {_name, _value}
|
|
|
|
_buffer.headersCount += 1
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-12-18 00:02:46 +00:00
|
|
|
func (_buffer *HttpResponseWriterHeadersBuffer) IncludeString (_name string, _value string) () {
|
|
|
|
_buffer.IncludeBytes (StringToBytes (_name), StringToBytes (_value))
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-12-17 20:56:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
func (_buffer *HttpResponseWriterHeadersBuffer) WriteToGenericResponse (_response http.ResponseWriter) () {
|
|
|
|
|
|
|
|
_headers := _response.Header ()
|
2021-12-17 20:18:47 +00:00
|
|
|
|
2021-12-17 20:56:07 +00:00
|
|
|
_buffer.WriteToGenericHeaders (_headers)
|
|
|
|
|
|
|
|
_response.WriteHeader (_buffer.status)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (_buffer *HttpResponseWriterHeadersBuffer) WriteToGenericHeaders (_headers http.Header) () {
|
2021-12-17 20:18:47 +00:00
|
|
|
|
|
|
|
for _index := 0; _index < _buffer.headersCount; _index += 1 {
|
|
|
|
|
|
|
|
_nameAndValue_0 := _buffer.headers[_index]
|
|
|
|
_name_0 := _nameAndValue_0[0]
|
|
|
|
_value_0 := _nameAndValue_0[1]
|
|
|
|
|
|
|
|
_name := CanonicalHeaderNameFromBytes (_name_0)
|
|
|
|
if _values, _ := _headers[_name]; _values == nil {
|
|
|
|
_values = CanonicalHeaderValueArrayFromBytes (_value_0)
|
|
|
|
_headers[_name] = _values
|
|
|
|
} else {
|
|
|
|
_value := CanonicalHeaderValueFromBytes (_value_0)
|
|
|
|
_values = append (_values, _value)
|
|
|
|
_headers[_name] = _values
|
|
|
|
}
|
|
|
|
}
|
2021-12-17 20:56:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (_buffer *HttpResponseWriterHeadersBuffer) WriteTo (_response http.ResponseWriter) () {
|
2021-12-17 20:18:47 +00:00
|
|
|
|
2021-12-17 20:56:07 +00:00
|
|
|
|
|
|
|
if !_httpResponseWriterHeadersMagic_enabled {
|
|
|
|
_buffer.WriteToGenericResponse (_response)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-12-18 00:51:45 +00:00
|
|
|
_responseRaw := * ((*[2]uintptr) (unsafe.Pointer (&_response)))
|
2021-12-17 20:56:07 +00:00
|
|
|
_responseType := _responseRaw[0]
|
|
|
|
|
|
|
|
|
|
|
|
_redo :
|
|
|
|
|
|
|
|
_netHttp1Type := atomic.LoadUintptr (&_httpResponseWriterHeadersMagic_netHttp1_type)
|
|
|
|
if _responseType == _netHttp1Type {
|
|
|
|
_buffer.WriteToNetHttp1 (_response)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
_netHttp2Type := atomic.LoadUintptr (&_httpResponseWriterHeadersMagic_netHttp2_type)
|
|
|
|
if _responseType == _netHttp2Type {
|
|
|
|
_buffer.WriteToNetHttp2 (_response)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
_quicHttp3Type := atomic.LoadUintptr (&_httpResponseWriterHeadersMagic_quicHttp3_type)
|
|
|
|
if _responseType == _quicHttp3Type {
|
|
|
|
_buffer.WriteToQuicHttp3 (_response)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-12-18 01:17:59 +00:00
|
|
|
if _httpResponseWriterHeadersMagic_detect (_response) {
|
|
|
|
goto _redo
|
|
|
|
} else {
|
|
|
|
_buffer.WriteToGenericResponse (_response)
|
|
|
|
return
|
|
|
|
}
|
2021-12-17 20:18:47 +00:00
|
|
|
}
|
|
|
|
|
2021-12-17 20:56:07 +00:00
|
|
|
var _httpResponseWriterHeadersMagic_netHttp1_type uintptr
|
|
|
|
var _httpResponseWriterHeadersMagic_netHttp2_type uintptr
|
|
|
|
var _httpResponseWriterHeadersMagic_quicHttp3_type uintptr
|
2021-12-17 20:18:47 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2021-12-17 20:56:07 +00:00
|
|
|
|
|
|
|
func (_buffer *HttpResponseWriterHeadersBuffer) WriteToNetHttp1 (_response http.ResponseWriter) () {
|
|
|
|
|
2021-12-18 00:51:45 +00:00
|
|
|
_responseRaw := * ((*[2]uintptr) (unsafe.Pointer (&_response)))
|
2021-12-17 20:56:07 +00:00
|
|
|
_responseAddress := unsafe.Pointer (_responseRaw[1])
|
2021-12-17 19:58:36 +00:00
|
|
|
|
2021-12-18 01:17:59 +00:00
|
|
|
_headers := make (map[string][]string, _buffer.headersCount)
|
2021-12-17 19:58:36 +00:00
|
|
|
|
2021-12-18 00:51:45 +00:00
|
|
|
_buffer.WriteToGenericHeaders (_headers)
|
|
|
|
|
|
|
|
// NOTE: It seems if `Content-Type` is missing, then Go HTTP divines a value...
|
|
|
|
if _, _exists := _headers["Content-Type"]; !_exists {
|
|
|
|
_headers["Content-Type"] = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: It seems that Go HTTP always divines a `Date` value...
|
|
|
|
_headers["Date"] = nil
|
|
|
|
|
2021-12-17 20:56:07 +00:00
|
|
|
{
|
|
|
|
_handlerHeaderOffset := atomic.LoadInt32 (&_httpResponseWriterHeadersMagic_netHttp1_handlerHeaderOffset)
|
|
|
|
_cwHeaderOffset := atomic.LoadInt32 (&_httpResponseWriterHeadersMagic_netHttp1_cwHeaderOffset)
|
|
|
|
|
|
|
|
_handlerHeaderValue := (*http.Header) (unsafe.Add (_responseAddress, _handlerHeaderOffset))
|
|
|
|
_cwHeaderValue := (*http.Header) (unsafe.Add (_responseAddress, _cwHeaderOffset))
|
|
|
|
|
|
|
|
*_handlerHeaderValue = _headers
|
|
|
|
*_cwHeaderValue = _headers
|
2021-12-17 19:58:36 +00:00
|
|
|
}
|
|
|
|
|
2021-12-18 00:51:45 +00:00
|
|
|
_response.WriteHeader (_buffer.status)
|
2021-12-17 20:56:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (_buffer *HttpResponseWriterHeadersBuffer) WriteToNetHttp2 (_response http.ResponseWriter) () {
|
|
|
|
|
2021-12-18 00:51:45 +00:00
|
|
|
_responseRaw := * ((*[2]uintptr) (unsafe.Pointer (&_response)))
|
|
|
|
_responseAddress := unsafe.Pointer (_responseRaw[1])
|
|
|
|
_responseAddress = unsafe.Pointer (* ((*uintptr) (_responseAddress)))
|
|
|
|
|
2021-12-18 01:17:59 +00:00
|
|
|
_headers := make (map[string][]string, _buffer.headersCount)
|
2021-12-18 00:51:45 +00:00
|
|
|
|
|
|
|
_buffer.WriteToGenericHeaders (_headers)
|
|
|
|
|
|
|
|
// NOTE: It seems if `Content-Type` is missing, then Go HTTP divines a value...
|
|
|
|
if _, _exists := _headers["Content-Type"]; !_exists {
|
|
|
|
_headers["Content-Type"] = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: It seems that Go HTTP always divines a `Date` value...
|
|
|
|
_headers["Date"] = nil
|
|
|
|
|
|
|
|
_response.WriteHeader (_buffer.status)
|
|
|
|
|
|
|
|
{
|
|
|
|
_handlerHeaderOffset := atomic.LoadInt32 (&_httpResponseWriterHeadersMagic_netHttp2_handlerHeaderOffset)
|
|
|
|
_snapHeaderOffset := atomic.LoadInt32 (&_httpResponseWriterHeadersMagic_netHttp2_snapHeaderOffset)
|
|
|
|
|
|
|
|
_handlerHeaderValue := (*http.Header) (unsafe.Add (_responseAddress, _handlerHeaderOffset))
|
|
|
|
_snapHeaderValue := (*http.Header) (unsafe.Add (_responseAddress, _snapHeaderOffset))
|
|
|
|
|
|
|
|
*_handlerHeaderValue = _headers
|
|
|
|
*_snapHeaderValue = _headers
|
|
|
|
}
|
2021-12-17 20:56:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (_buffer *HttpResponseWriterHeadersBuffer) WriteToQuicHttp3 (_response http.ResponseWriter) () {
|
|
|
|
|
|
|
|
_buffer.WriteToGenericResponse (_response)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-12-18 01:17:59 +00:00
|
|
|
func _httpResponseWriterHeadersMagic_detect (_response http.ResponseWriter) (bool) {
|
2021-12-17 20:56:07 +00:00
|
|
|
|
2021-12-17 19:58:36 +00:00
|
|
|
|
|
|
|
// 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 ()
|
|
|
|
_responseType := _responseReflect.Type ()
|
|
|
|
_responsePackage := _responseType.PkgPath ()
|
|
|
|
_responseTypeName := _responseType.Name ()
|
|
|
|
|
2021-12-18 00:51:45 +00:00
|
|
|
_responseRaw := * ((*[2]uintptr) (unsafe.Pointer (&_response)))
|
2021-12-17 20:56:07 +00:00
|
|
|
_responseRawType := _responseRaw[0]
|
2021-12-17 19:58:36 +00:00
|
|
|
|
|
|
|
switch {
|
|
|
|
|
|
|
|
case (_responsePackage == "net/http") && (_responseTypeName == "response") : {
|
|
|
|
|
2021-12-17 21:27:55 +00:00
|
|
|
log.Printf ("[dd] [73f6be95] [magic...] detected NetHttp1 (`%s.%s`) with type `%08x`;", _responsePackage, _responseTypeName, _responseRawType)
|
2021-12-17 19:58:36 +00:00
|
|
|
|
2021-12-17 20:56:07 +00:00
|
|
|
_handlerHeaderReflect := _responseReflect.FieldByName ("handlerHeader")
|
|
|
|
_handlerHeaderAddress := unsafe.Pointer (_handlerHeaderReflect.UnsafeAddr ())
|
2021-12-17 19:58:36 +00:00
|
|
|
|
2021-12-17 20:56:07 +00:00
|
|
|
_cwHeaderReflect := _responseReflect.FieldByName ("cw") .FieldByName ("header")
|
|
|
|
_cwHeaderAddress := unsafe.Pointer (_cwHeaderReflect.UnsafeAddr ())
|
2021-12-17 19:58:36 +00:00
|
|
|
|
2021-12-18 00:51:45 +00:00
|
|
|
_responseAddress := unsafe.Pointer (_responseReflect.UnsafeAddr ())
|
2021-12-17 20:56:07 +00:00
|
|
|
_handlerHeaderOffset := int32 (int64 (uintptr (_handlerHeaderAddress)) - int64 (uintptr (_responseAddress)))
|
|
|
|
_cwHeaderOffset := int32 (int64 (uintptr (_cwHeaderAddress)) - int64 (uintptr (_responseAddress)))
|
2021-12-17 19:58:36 +00:00
|
|
|
|
2021-12-17 20:56:07 +00:00
|
|
|
atomic.StoreInt32 (&_httpResponseWriterHeadersMagic_netHttp1_handlerHeaderOffset, _handlerHeaderOffset)
|
|
|
|
atomic.StoreInt32 (&_httpResponseWriterHeadersMagic_netHttp1_cwHeaderOffset, _cwHeaderOffset)
|
|
|
|
|
|
|
|
atomic.StoreUintptr (&_httpResponseWriterHeadersMagic_netHttp1_type, _responseRawType)
|
2021-12-18 01:17:59 +00:00
|
|
|
|
|
|
|
return true
|
2021-12-17 19:58:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case (_responsePackage == "net/http") && (_responseTypeName == "http2responseWriter") : {
|
|
|
|
|
2021-12-17 21:27:55 +00:00
|
|
|
log.Printf ("[dd] [cfb457eb] [magic...] detected NetHttp2 (`%s.%s`) with type `%08x`;", _responsePackage, _responseTypeName, _responseRawType)
|
2021-12-17 20:56:07 +00:00
|
|
|
|
2021-12-18 00:51:45 +00:00
|
|
|
_responseReflect = _responseReflect.FieldByName ("rws") .Elem ()
|
|
|
|
|
|
|
|
_handlerHeaderReflect := _responseReflect.FieldByName ("handlerHeader")
|
|
|
|
_handlerHeaderAddress := unsafe.Pointer (_handlerHeaderReflect.UnsafeAddr ())
|
|
|
|
|
|
|
|
_snapHeaderReflect := _responseReflect.FieldByName ("snapHeader")
|
|
|
|
_snapHeaderAddress := unsafe.Pointer (_snapHeaderReflect.UnsafeAddr ())
|
|
|
|
|
|
|
|
_responseAddress := unsafe.Pointer (_responseReflect.UnsafeAddr ())
|
|
|
|
|
|
|
|
_handlerHeaderOffset := int32 (int64 (uintptr (_handlerHeaderAddress)) - int64 (uintptr (_responseAddress)))
|
|
|
|
_snapHeaderOffset := int32 (int64 (uintptr (_snapHeaderAddress)) - int64 (uintptr (_responseAddress)))
|
|
|
|
|
|
|
|
atomic.StoreInt32 (&_httpResponseWriterHeadersMagic_netHttp2_handlerHeaderOffset, _handlerHeaderOffset)
|
|
|
|
atomic.StoreInt32 (&_httpResponseWriterHeadersMagic_netHttp2_snapHeaderOffset, _snapHeaderOffset)
|
|
|
|
|
2021-12-17 20:56:07 +00:00
|
|
|
atomic.StoreUintptr (&_httpResponseWriterHeadersMagic_netHttp2_type, _responseRawType)
|
2021-12-18 01:17:59 +00:00
|
|
|
|
|
|
|
return true
|
2021-12-17 19:58:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case (_responsePackage == "github.com/lucas-clemente/quic-go/http3") && (_responseTypeName == "responseWriter") : {
|
|
|
|
|
2021-12-17 21:27:55 +00:00
|
|
|
log.Printf ("[dd] [90b8f7c6] [magic...] detected QuicHttp3 (`%s.%s`) with type `%08x`;", _responsePackage, _responseTypeName, _responseRawType)
|
2021-12-17 20:56:07 +00:00
|
|
|
|
|
|
|
atomic.StoreUintptr (&_httpResponseWriterHeadersMagic_quicHttp3_type, _responseRawType)
|
2021-12-18 01:17:59 +00:00
|
|
|
|
|
|
|
return true
|
2021-12-17 19:58:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
default : {
|
|
|
|
|
2021-12-18 01:17:59 +00:00
|
|
|
if !_httpResponseWriterHeadersMagic_quiet {
|
|
|
|
log.Printf ("[ee] [64583df9] unsupported HTTP ResponseWriter `%s.%s`!\n", _responsePackage, _responseTypeName)
|
|
|
|
}
|
2021-12-17 19:58:36 +00:00
|
|
|
|
2021-12-17 20:56:07 +00:00
|
|
|
if _httpResponseWriterHeadersMagic_panic {
|
2021-12-17 19:58:36 +00:00
|
|
|
panic (fmt.Sprintf ("[09274c17] unsupported HTTP ResponseWriter `%s.%s`!", _responsePackage, _responseTypeName))
|
|
|
|
}
|
2021-12-18 01:17:59 +00:00
|
|
|
|
|
|
|
return false
|
2021-12-17 19:58:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-12-18 01:17:59 +00:00
|
|
|
const _httpResponseWriterHeadersMagic_enabled = true
|
|
|
|
const _httpResponseWriterHeadersMagic_panic = true
|
|
|
|
const _httpResponseWriterHeadersMagic_quiet = false
|
2021-12-17 19:58:36 +00:00
|
|
|
|
2021-12-17 20:56:07 +00:00
|
|
|
var _httpResponseWriterHeadersMagic_netHttp1_handlerHeaderOffset int32
|
|
|
|
var _httpResponseWriterHeadersMagic_netHttp1_cwHeaderOffset int32
|
2021-12-17 19:58:36 +00:00
|
|
|
|
2021-12-18 00:51:45 +00:00
|
|
|
var _httpResponseWriterHeadersMagic_netHttp2_handlerHeaderOffset int32
|
|
|
|
var _httpResponseWriterHeadersMagic_netHttp2_snapHeaderOffset int32
|
|
|
|
|