This commit is contained in:
RPRX 2020-11-25 19:01:53 +08:00
parent 47d23e9972
commit c7f7c08ead
711 changed files with 82154 additions and 2 deletions

View file

@ -0,0 +1,100 @@
package http
import (
"strings"
"github.com/xtls/xray-core/v1/common/dice"
)
func pickString(arr []string) string {
n := len(arr)
switch n {
case 0:
return ""
case 1:
return arr[0]
default:
return arr[dice.Roll(n)]
}
}
func (v *RequestConfig) PickURI() string {
return pickString(v.Uri)
}
func (v *RequestConfig) PickHeaders() []string {
n := len(v.Header)
if n == 0 {
return nil
}
headers := make([]string, n)
for idx, headerConfig := range v.Header {
headerName := headerConfig.Name
headerValue := pickString(headerConfig.Value)
headers[idx] = headerName + ": " + headerValue
}
return headers
}
func (v *RequestConfig) GetVersionValue() string {
if v == nil || v.Version == nil {
return "1.1"
}
return v.Version.Value
}
func (v *RequestConfig) GetMethodValue() string {
if v == nil || v.Method == nil {
return "GET"
}
return v.Method.Value
}
func (v *RequestConfig) GetFullVersion() string {
return "HTTP/" + v.GetVersionValue()
}
func (v *ResponseConfig) HasHeader(header string) bool {
cHeader := strings.ToLower(header)
for _, tHeader := range v.Header {
if strings.EqualFold(tHeader.Name, cHeader) {
return true
}
}
return false
}
func (v *ResponseConfig) PickHeaders() []string {
n := len(v.Header)
if n == 0 {
return nil
}
headers := make([]string, n)
for idx, headerConfig := range v.Header {
headerName := headerConfig.Name
headerValue := pickString(headerConfig.Value)
headers[idx] = headerName + ": " + headerValue
}
return headers
}
func (v *ResponseConfig) GetVersionValue() string {
if v == nil || v.Version == nil {
return "1.1"
}
return v.Version.Value
}
func (v *ResponseConfig) GetFullVersion() string {
return "HTTP/" + v.GetVersionValue()
}
func (v *ResponseConfig) GetStatusValue() *Status {
if v == nil || v.Status == nil {
return &Status{
Code: "200",
Reason: "OK",
}
}
return v.Status
}

View file

@ -0,0 +1,654 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.14.0
// source: transport/internet/headers/http/config.proto
package http
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Header struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// "Accept", "Cookie", etc
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
// Each entry must be valid in one piece. Random entry will be chosen if
// multiple entries present.
Value []string `protobuf:"bytes,2,rep,name=value,proto3" json:"value,omitempty"`
}
func (x *Header) Reset() {
*x = Header{}
if protoimpl.UnsafeEnabled {
mi := &file_transport_internet_headers_http_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Header) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Header) ProtoMessage() {}
func (x *Header) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_headers_http_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Header.ProtoReflect.Descriptor instead.
func (*Header) Descriptor() ([]byte, []int) {
return file_transport_internet_headers_http_config_proto_rawDescGZIP(), []int{0}
}
func (x *Header) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *Header) GetValue() []string {
if x != nil {
return x.Value
}
return nil
}
// HTTP version. Default value "1.1".
type Version struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
}
func (x *Version) Reset() {
*x = Version{}
if protoimpl.UnsafeEnabled {
mi := &file_transport_internet_headers_http_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Version) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Version) ProtoMessage() {}
func (x *Version) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_headers_http_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Version.ProtoReflect.Descriptor instead.
func (*Version) Descriptor() ([]byte, []int) {
return file_transport_internet_headers_http_config_proto_rawDescGZIP(), []int{1}
}
func (x *Version) GetValue() string {
if x != nil {
return x.Value
}
return ""
}
// HTTP method. Default value "GET".
type Method struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
}
func (x *Method) Reset() {
*x = Method{}
if protoimpl.UnsafeEnabled {
mi := &file_transport_internet_headers_http_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Method) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Method) ProtoMessage() {}
func (x *Method) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_headers_http_config_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Method.ProtoReflect.Descriptor instead.
func (*Method) Descriptor() ([]byte, []int) {
return file_transport_internet_headers_http_config_proto_rawDescGZIP(), []int{2}
}
func (x *Method) GetValue() string {
if x != nil {
return x.Value
}
return ""
}
type RequestConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Full HTTP version like "1.1".
Version *Version `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"`
// GET, POST, CONNECT etc
Method *Method `protobuf:"bytes,2,opt,name=method,proto3" json:"method,omitempty"`
// URI like "/login.php"
Uri []string `protobuf:"bytes,3,rep,name=uri,proto3" json:"uri,omitempty"`
Header []*Header `protobuf:"bytes,4,rep,name=header,proto3" json:"header,omitempty"`
}
func (x *RequestConfig) Reset() {
*x = RequestConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_transport_internet_headers_http_config_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RequestConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RequestConfig) ProtoMessage() {}
func (x *RequestConfig) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_headers_http_config_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RequestConfig.ProtoReflect.Descriptor instead.
func (*RequestConfig) Descriptor() ([]byte, []int) {
return file_transport_internet_headers_http_config_proto_rawDescGZIP(), []int{3}
}
func (x *RequestConfig) GetVersion() *Version {
if x != nil {
return x.Version
}
return nil
}
func (x *RequestConfig) GetMethod() *Method {
if x != nil {
return x.Method
}
return nil
}
func (x *RequestConfig) GetUri() []string {
if x != nil {
return x.Uri
}
return nil
}
func (x *RequestConfig) GetHeader() []*Header {
if x != nil {
return x.Header
}
return nil
}
type Status struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Status code. Default "200".
Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"`
// Statue reason. Default "OK".
Reason string `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"`
}
func (x *Status) Reset() {
*x = Status{}
if protoimpl.UnsafeEnabled {
mi := &file_transport_internet_headers_http_config_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Status) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Status) ProtoMessage() {}
func (x *Status) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_headers_http_config_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Status.ProtoReflect.Descriptor instead.
func (*Status) Descriptor() ([]byte, []int) {
return file_transport_internet_headers_http_config_proto_rawDescGZIP(), []int{4}
}
func (x *Status) GetCode() string {
if x != nil {
return x.Code
}
return ""
}
func (x *Status) GetReason() string {
if x != nil {
return x.Reason
}
return ""
}
type ResponseConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Version *Version `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"`
Status *Status `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"`
Header []*Header `protobuf:"bytes,3,rep,name=header,proto3" json:"header,omitempty"`
}
func (x *ResponseConfig) Reset() {
*x = ResponseConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_transport_internet_headers_http_config_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ResponseConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ResponseConfig) ProtoMessage() {}
func (x *ResponseConfig) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_headers_http_config_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ResponseConfig.ProtoReflect.Descriptor instead.
func (*ResponseConfig) Descriptor() ([]byte, []int) {
return file_transport_internet_headers_http_config_proto_rawDescGZIP(), []int{5}
}
func (x *ResponseConfig) GetVersion() *Version {
if x != nil {
return x.Version
}
return nil
}
func (x *ResponseConfig) GetStatus() *Status {
if x != nil {
return x.Status
}
return nil
}
func (x *ResponseConfig) GetHeader() []*Header {
if x != nil {
return x.Header
}
return nil
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Settings for authenticating requests. If not set, client side will not send
// authenication header, and server side will bypass authentication.
Request *RequestConfig `protobuf:"bytes,1,opt,name=request,proto3" json:"request,omitempty"`
// Settings for authenticating responses. If not set, client side will bypass
// authentication, and server side will not send authentication header.
Response *ResponseConfig `protobuf:"bytes,2,opt,name=response,proto3" json:"response,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_transport_internet_headers_http_config_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_headers_http_config_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_transport_internet_headers_http_config_proto_rawDescGZIP(), []int{6}
}
func (x *Config) GetRequest() *RequestConfig {
if x != nil {
return x.Request
}
return nil
}
func (x *Config) GetResponse() *ResponseConfig {
if x != nil {
return x.Response
}
return nil
}
var File_transport_internet_headers_http_config_proto protoreflect.FileDescriptor
var file_transport_internet_headers_http_config_proto_rawDesc = []byte{
0x0a, 0x2c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x68, 0x74, 0x74,
0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x24,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69,
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e,
0x68, 0x74, 0x74, 0x70, 0x22, 0x32, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x12,
0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28,
0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x1f, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x1e, 0x0a, 0x06, 0x4d, 0x65, 0x74,
0x68, 0x6f, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xf6, 0x01, 0x0a, 0x0d, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x47, 0x0a, 0x07, 0x76,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x68,
0x74, 0x74, 0x70, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x76, 0x65, 0x72,
0x73, 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e,
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68,
0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x2e, 0x4d, 0x65, 0x74, 0x68,
0x6f, 0x64, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72,
0x69, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x44, 0x0a, 0x06,
0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x68,
0x74, 0x74, 0x70, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64,
0x65, 0x72, 0x22, 0x34, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04,
0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65,
0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0xe5, 0x01, 0x0a, 0x0e, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x47, 0x0a, 0x07, 0x76,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x68,
0x74, 0x74, 0x70, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x76, 0x65, 0x72,
0x73, 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e,
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68,
0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x2e, 0x53, 0x74, 0x61, 0x74,
0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x44, 0x0a, 0x06, 0x68, 0x65,
0x61, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x68, 0x74, 0x74,
0x70, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
0x22, 0xa9, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4d, 0x0a, 0x07, 0x72,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x68,
0x74, 0x74, 0x70, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x50, 0x0a, 0x08, 0x72, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x68,
0x74, 0x74, 0x70, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x91, 0x01, 0x0a,
0x28, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,
0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61,
0x64, 0x65, 0x72, 0x73, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x50, 0x01, 0x5a, 0x3c, 0x67, 0x69, 0x74,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61,
0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,
0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x65, 0x61,
0x64, 0x65, 0x72, 0x73, 0x2f, 0x68, 0x74, 0x74, 0x70, 0xaa, 0x02, 0x24, 0x58, 0x72, 0x61, 0x79,
0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72,
0x6e, 0x65, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x48, 0x74, 0x74, 0x70,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_transport_internet_headers_http_config_proto_rawDescOnce sync.Once
file_transport_internet_headers_http_config_proto_rawDescData = file_transport_internet_headers_http_config_proto_rawDesc
)
func file_transport_internet_headers_http_config_proto_rawDescGZIP() []byte {
file_transport_internet_headers_http_config_proto_rawDescOnce.Do(func() {
file_transport_internet_headers_http_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_headers_http_config_proto_rawDescData)
})
return file_transport_internet_headers_http_config_proto_rawDescData
}
var file_transport_internet_headers_http_config_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_transport_internet_headers_http_config_proto_goTypes = []interface{}{
(*Header)(nil), // 0: xray.transport.internet.headers.http.Header
(*Version)(nil), // 1: xray.transport.internet.headers.http.Version
(*Method)(nil), // 2: xray.transport.internet.headers.http.Method
(*RequestConfig)(nil), // 3: xray.transport.internet.headers.http.RequestConfig
(*Status)(nil), // 4: xray.transport.internet.headers.http.Status
(*ResponseConfig)(nil), // 5: xray.transport.internet.headers.http.ResponseConfig
(*Config)(nil), // 6: xray.transport.internet.headers.http.Config
}
var file_transport_internet_headers_http_config_proto_depIdxs = []int32{
1, // 0: xray.transport.internet.headers.http.RequestConfig.version:type_name -> xray.transport.internet.headers.http.Version
2, // 1: xray.transport.internet.headers.http.RequestConfig.method:type_name -> xray.transport.internet.headers.http.Method
0, // 2: xray.transport.internet.headers.http.RequestConfig.header:type_name -> xray.transport.internet.headers.http.Header
1, // 3: xray.transport.internet.headers.http.ResponseConfig.version:type_name -> xray.transport.internet.headers.http.Version
4, // 4: xray.transport.internet.headers.http.ResponseConfig.status:type_name -> xray.transport.internet.headers.http.Status
0, // 5: xray.transport.internet.headers.http.ResponseConfig.header:type_name -> xray.transport.internet.headers.http.Header
3, // 6: xray.transport.internet.headers.http.Config.request:type_name -> xray.transport.internet.headers.http.RequestConfig
5, // 7: xray.transport.internet.headers.http.Config.response:type_name -> xray.transport.internet.headers.http.ResponseConfig
8, // [8:8] is the sub-list for method output_type
8, // [8:8] is the sub-list for method input_type
8, // [8:8] is the sub-list for extension type_name
8, // [8:8] is the sub-list for extension extendee
0, // [0:8] is the sub-list for field type_name
}
func init() { file_transport_internet_headers_http_config_proto_init() }
func file_transport_internet_headers_http_config_proto_init() {
if File_transport_internet_headers_http_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_transport_internet_headers_http_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Header); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_transport_internet_headers_http_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Version); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_transport_internet_headers_http_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Method); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_transport_internet_headers_http_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RequestConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_transport_internet_headers_http_config_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Status); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_transport_internet_headers_http_config_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ResponseConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_transport_internet_headers_http_config_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_transport_internet_headers_http_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 7,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_transport_internet_headers_http_config_proto_goTypes,
DependencyIndexes: file_transport_internet_headers_http_config_proto_depIdxs,
MessageInfos: file_transport_internet_headers_http_config_proto_msgTypes,
}.Build()
File_transport_internet_headers_http_config_proto = out.File
file_transport_internet_headers_http_config_proto_rawDesc = nil
file_transport_internet_headers_http_config_proto_goTypes = nil
file_transport_internet_headers_http_config_proto_depIdxs = nil
}

View file

@ -0,0 +1,65 @@
syntax = "proto3";
package xray.transport.internet.headers.http;
option csharp_namespace = "Xray.Transport.Internet.Headers.Http";
option go_package = "github.com/xtls/xray-core/v1/transport/internet/headers/http";
option java_package = "com.xray.transport.internet.headers.http";
option java_multiple_files = true;
message Header {
// "Accept", "Cookie", etc
string name = 1;
// Each entry must be valid in one piece. Random entry will be chosen if
// multiple entries present.
repeated string value = 2;
}
// HTTP version. Default value "1.1".
message Version {
string value = 1;
}
// HTTP method. Default value "GET".
message Method {
string value = 1;
}
message RequestConfig {
// Full HTTP version like "1.1".
Version version = 1;
// GET, POST, CONNECT etc
Method method = 2;
// URI like "/login.php"
repeated string uri = 3;
repeated Header header = 4;
}
message Status {
// Status code. Default "200".
string code = 1;
// Statue reason. Default "OK".
string reason = 2;
}
message ResponseConfig {
Version version = 1;
Status status = 2;
repeated Header header = 3;
}
message Config {
// Settings for authenticating requests. If not set, client side will not send
// authenication header, and server side will bypass authentication.
RequestConfig request = 1;
// Settings for authenticating responses. If not set, client side will bypass
// authentication, and server side will not send authentication header.
ResponseConfig response = 2;
}

View file

@ -0,0 +1,9 @@
package http
import "github.com/xtls/xray-core/v1/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View file

@ -0,0 +1,321 @@
package http
//go:generate go run github.com/xtls/xray-core/v1/common/errors/errorgen
import (
"bufio"
"bytes"
"context"
"io"
"net"
"net/http"
"strings"
"time"
"github.com/xtls/xray-core/v1/common"
"github.com/xtls/xray-core/v1/common/buf"
)
const (
// CRLF is the line ending in HTTP header
CRLF = "\r\n"
// ENDING is the double line ending between HTTP header and body.
ENDING = CRLF + CRLF
// max length of HTTP header. Safety precaution for DDoS attack.
maxHeaderLength = 8192
)
var (
ErrHeaderToLong = newError("Header too long.")
ErrHeaderMisMatch = newError("Header Mismatch.")
)
type Reader interface {
Read(io.Reader) (*buf.Buffer, error)
}
type Writer interface {
Write(io.Writer) error
}
type NoOpReader struct{}
func (NoOpReader) Read(io.Reader) (*buf.Buffer, error) {
return nil, nil
}
type NoOpWriter struct{}
func (NoOpWriter) Write(io.Writer) error {
return nil
}
type HeaderReader struct {
req *http.Request
expectedHeader *RequestConfig
}
func (h *HeaderReader) ExpectThisRequest(expectedHeader *RequestConfig) *HeaderReader {
h.expectedHeader = expectedHeader
return h
}
func (h *HeaderReader) Read(reader io.Reader) (*buf.Buffer, error) {
buffer := buf.New()
totalBytes := int32(0)
endingDetected := false
var headerBuf bytes.Buffer
for totalBytes < maxHeaderLength {
_, err := buffer.ReadFrom(reader)
if err != nil {
buffer.Release()
return nil, err
}
if n := bytes.Index(buffer.Bytes(), []byte(ENDING)); n != -1 {
headerBuf.Write(buffer.BytesRange(0, int32(n+len(ENDING))))
buffer.Advance(int32(n + len(ENDING)))
endingDetected = true
break
}
lenEnding := int32(len(ENDING))
if buffer.Len() >= lenEnding {
totalBytes += buffer.Len() - lenEnding
headerBuf.Write(buffer.BytesRange(0, buffer.Len()-lenEnding))
leftover := buffer.BytesFrom(-lenEnding)
buffer.Clear()
copy(buffer.Extend(lenEnding), leftover)
if _, err := readRequest(bufio.NewReader(bytes.NewReader(headerBuf.Bytes())), false); err != io.ErrUnexpectedEOF {
return nil, err
}
}
}
if !endingDetected {
buffer.Release()
return nil, ErrHeaderToLong
}
if h.expectedHeader == nil {
if buffer.IsEmpty() {
buffer.Release()
return nil, nil
}
return buffer, nil
}
// Parse the request
if req, err := readRequest(bufio.NewReader(bytes.NewReader(headerBuf.Bytes())), false); err != nil {
return nil, err
} else {
h.req = req
}
// Check req
path := h.req.URL.Path
hasThisURI := false
for _, u := range h.expectedHeader.Uri {
if u == path {
hasThisURI = true
}
}
if !hasThisURI {
return nil, ErrHeaderMisMatch
}
if buffer.IsEmpty() {
buffer.Release()
return nil, nil
}
return buffer, nil
}
type HeaderWriter struct {
header *buf.Buffer
}
func NewHeaderWriter(header *buf.Buffer) *HeaderWriter {
return &HeaderWriter{
header: header,
}
}
func (w *HeaderWriter) Write(writer io.Writer) error {
if w.header == nil {
return nil
}
err := buf.WriteAllBytes(writer, w.header.Bytes())
w.header.Release()
w.header = nil
return err
}
type Conn struct {
net.Conn
readBuffer *buf.Buffer
oneTimeReader Reader
oneTimeWriter Writer
errorWriter Writer
errorMismatchWriter Writer
errorTooLongWriter Writer
errReason error
}
func NewConn(conn net.Conn, reader Reader, writer Writer, errorWriter Writer, errorMismatchWriter Writer, errorTooLongWriter Writer) *Conn {
return &Conn{
Conn: conn,
oneTimeReader: reader,
oneTimeWriter: writer,
errorWriter: errorWriter,
errorMismatchWriter: errorMismatchWriter,
errorTooLongWriter: errorTooLongWriter,
}
}
func (c *Conn) Read(b []byte) (int, error) {
if c.oneTimeReader != nil {
buffer, err := c.oneTimeReader.Read(c.Conn)
if err != nil {
c.errReason = err
return 0, err
}
c.readBuffer = buffer
c.oneTimeReader = nil
}
if !c.readBuffer.IsEmpty() {
nBytes, _ := c.readBuffer.Read(b)
if c.readBuffer.IsEmpty() {
c.readBuffer.Release()
c.readBuffer = nil
}
return nBytes, nil
}
return c.Conn.Read(b)
}
// Write implements io.Writer.
func (c *Conn) Write(b []byte) (int, error) {
if c.oneTimeWriter != nil {
err := c.oneTimeWriter.Write(c.Conn)
c.oneTimeWriter = nil
if err != nil {
return 0, err
}
}
return c.Conn.Write(b)
}
// Close implements net.Conn.Close().
func (c *Conn) Close() error {
if c.oneTimeWriter != nil && c.errorWriter != nil {
// Connection is being closed but header wasn't sent. This means the client request
// is probably not valid. Sending back a server error header in this case.
// Write response based on error reason
switch c.errReason {
case ErrHeaderMisMatch:
c.errorMismatchWriter.Write(c.Conn)
case ErrHeaderToLong:
c.errorTooLongWriter.Write(c.Conn)
default:
c.errorWriter.Write(c.Conn)
}
}
return c.Conn.Close()
}
func formResponseHeader(config *ResponseConfig) *HeaderWriter {
header := buf.New()
common.Must2(header.WriteString(strings.Join([]string{config.GetFullVersion(), config.GetStatusValue().Code, config.GetStatusValue().Reason}, " ")))
common.Must2(header.WriteString(CRLF))
headers := config.PickHeaders()
for _, h := range headers {
common.Must2(header.WriteString(h))
common.Must2(header.WriteString(CRLF))
}
if !config.HasHeader("Date") {
common.Must2(header.WriteString("Date: "))
common.Must2(header.WriteString(time.Now().Format(http.TimeFormat)))
common.Must2(header.WriteString(CRLF))
}
common.Must2(header.WriteString(CRLF))
return &HeaderWriter{
header: header,
}
}
type Authenticator struct {
config *Config
}
func (a Authenticator) GetClientWriter() *HeaderWriter {
header := buf.New()
config := a.config.Request
common.Must2(header.WriteString(strings.Join([]string{config.GetMethodValue(), config.PickURI(), config.GetFullVersion()}, " ")))
common.Must2(header.WriteString(CRLF))
headers := config.PickHeaders()
for _, h := range headers {
common.Must2(header.WriteString(h))
common.Must2(header.WriteString(CRLF))
}
common.Must2(header.WriteString(CRLF))
return &HeaderWriter{
header: header,
}
}
func (a Authenticator) GetServerWriter() *HeaderWriter {
return formResponseHeader(a.config.Response)
}
func (a Authenticator) Client(conn net.Conn) net.Conn {
if a.config.Request == nil && a.config.Response == nil {
return conn
}
var reader Reader = NoOpReader{}
if a.config.Request != nil {
reader = new(HeaderReader)
}
var writer Writer = NoOpWriter{}
if a.config.Response != nil {
writer = a.GetClientWriter()
}
return NewConn(conn, reader, writer, NoOpWriter{}, NoOpWriter{}, NoOpWriter{})
}
func (a Authenticator) Server(conn net.Conn) net.Conn {
if a.config.Request == nil && a.config.Response == nil {
return conn
}
return NewConn(conn, new(HeaderReader).ExpectThisRequest(a.config.Request), a.GetServerWriter(),
formResponseHeader(resp400),
formResponseHeader(resp404),
formResponseHeader(resp400))
}
func NewAuthenticator(ctx context.Context, config *Config) (Authenticator, error) {
return Authenticator{
config: config,
}, nil
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewAuthenticator(ctx, config.(*Config))
}))
}

View file

@ -0,0 +1,305 @@
package http_test
import (
"bufio"
"bytes"
"context"
"crypto/rand"
"strings"
"testing"
"time"
"github.com/xtls/xray-core/v1/common"
"github.com/xtls/xray-core/v1/common/buf"
"github.com/xtls/xray-core/v1/common/net"
. "github.com/xtls/xray-core/v1/transport/internet/headers/http"
)
func TestReaderWriter(t *testing.T) {
cache := buf.New()
b := buf.New()
common.Must2(b.WriteString("abcd" + ENDING))
writer := NewHeaderWriter(b)
err := writer.Write(cache)
common.Must(err)
if v := cache.Len(); v != 8 {
t.Error("cache len: ", v)
}
_, err = cache.Write([]byte{'e', 'f', 'g'})
common.Must(err)
reader := &HeaderReader{}
_, err = reader.Read(cache)
if err != nil && !strings.HasPrefix(err.Error(), "malformed HTTP request") {
t.Error("unknown error ", err)
}
}
func TestRequestHeader(t *testing.T) {
auth, err := NewAuthenticator(context.Background(), &Config{
Request: &RequestConfig{
Uri: []string{"/"},
Header: []*Header{
{
Name: "Test",
Value: []string{"Value"},
},
},
},
})
common.Must(err)
cache := buf.New()
err = auth.GetClientWriter().Write(cache)
common.Must(err)
if cache.String() != "GET / HTTP/1.1\r\nTest: Value\r\n\r\n" {
t.Error("cache: ", cache.String())
}
}
func TestLongRequestHeader(t *testing.T) {
payload := make([]byte, buf.Size+2)
common.Must2(rand.Read(payload[:buf.Size-2]))
copy(payload[buf.Size-2:], ENDING)
payload = append(payload, []byte("abcd")...)
reader := HeaderReader{}
_, err := reader.Read(bytes.NewReader(payload))
if err != nil && !(strings.HasPrefix(err.Error(), "invalid") || strings.HasPrefix(err.Error(), "malformed")) {
t.Error("unknown error ", err)
}
}
func TestConnection(t *testing.T) {
auth, err := NewAuthenticator(context.Background(), &Config{
Request: &RequestConfig{
Method: &Method{Value: "Post"},
Uri: []string{"/testpath"},
Header: []*Header{
{
Name: "Host",
Value: []string{"www.example.com", "www.google.com"},
},
{
Name: "User-Agent",
Value: []string{"Test-Agent"},
},
},
},
Response: &ResponseConfig{
Version: &Version{
Value: "1.1",
},
Status: &Status{
Code: "404",
Reason: "Not Found",
},
},
})
common.Must(err)
listener, err := net.Listen("tcp", "127.0.0.1:0")
common.Must(err)
go func() {
conn, err := listener.Accept()
common.Must(err)
authConn := auth.Server(conn)
b := make([]byte, 256)
for {
n, err := authConn.Read(b)
if err != nil {
break
}
_, err = authConn.Write(b[:n])
common.Must(err)
}
}()
conn, err := net.DialTCP("tcp", nil, listener.Addr().(*net.TCPAddr))
common.Must(err)
authConn := auth.Client(conn)
defer authConn.Close()
authConn.Write([]byte("Test payload"))
authConn.Write([]byte("Test payload 2"))
expectedResponse := "Test payloadTest payload 2"
actualResponse := make([]byte, 256)
deadline := time.Now().Add(time.Second * 5)
totalBytes := 0
for {
n, err := authConn.Read(actualResponse[totalBytes:])
common.Must(err)
totalBytes += n
if totalBytes >= len(expectedResponse) || time.Now().After(deadline) {
break
}
}
if string(actualResponse[:totalBytes]) != expectedResponse {
t.Error("response: ", string(actualResponse[:totalBytes]))
}
}
func TestConnectionInvPath(t *testing.T) {
auth, err := NewAuthenticator(context.Background(), &Config{
Request: &RequestConfig{
Method: &Method{Value: "Post"},
Uri: []string{"/testpath"},
Header: []*Header{
{
Name: "Host",
Value: []string{"www.example.com", "www.google.com"},
},
{
Name: "User-Agent",
Value: []string{"Test-Agent"},
},
},
},
Response: &ResponseConfig{
Version: &Version{
Value: "1.1",
},
Status: &Status{
Code: "404",
Reason: "Not Found",
},
},
})
common.Must(err)
authR, err := NewAuthenticator(context.Background(), &Config{
Request: &RequestConfig{
Method: &Method{Value: "Post"},
Uri: []string{"/testpathErr"},
Header: []*Header{
{
Name: "Host",
Value: []string{"www.example.com", "www.google.com"},
},
{
Name: "User-Agent",
Value: []string{"Test-Agent"},
},
},
},
Response: &ResponseConfig{
Version: &Version{
Value: "1.1",
},
Status: &Status{
Code: "404",
Reason: "Not Found",
},
},
})
common.Must(err)
listener, err := net.Listen("tcp", "127.0.0.1:0")
common.Must(err)
go func() {
conn, err := listener.Accept()
common.Must(err)
authConn := auth.Server(conn)
b := make([]byte, 256)
for {
n, err := authConn.Read(b)
if err != nil {
authConn.Close()
break
}
_, err = authConn.Write(b[:n])
common.Must(err)
}
}()
conn, err := net.DialTCP("tcp", nil, listener.Addr().(*net.TCPAddr))
common.Must(err)
authConn := authR.Client(conn)
defer authConn.Close()
authConn.Write([]byte("Test payload"))
authConn.Write([]byte("Test payload 2"))
expectedResponse := "Test payloadTest payload 2"
actualResponse := make([]byte, 256)
deadline := time.Now().Add(time.Second * 5)
totalBytes := 0
for {
n, err := authConn.Read(actualResponse[totalBytes:])
if err == nil {
t.Error("Error Expected", err)
} else {
return
}
totalBytes += n
if totalBytes >= len(expectedResponse) || time.Now().After(deadline) {
break
}
}
}
func TestConnectionInvReq(t *testing.T) {
auth, err := NewAuthenticator(context.Background(), &Config{
Request: &RequestConfig{
Method: &Method{Value: "Post"},
Uri: []string{"/testpath"},
Header: []*Header{
{
Name: "Host",
Value: []string{"www.example.com", "www.google.com"},
},
{
Name: "User-Agent",
Value: []string{"Test-Agent"},
},
},
},
Response: &ResponseConfig{
Version: &Version{
Value: "1.1",
},
Status: &Status{
Code: "404",
Reason: "Not Found",
},
},
})
common.Must(err)
listener, err := net.Listen("tcp", "127.0.0.1:0")
common.Must(err)
go func() {
conn, err := listener.Accept()
common.Must(err)
authConn := auth.Server(conn)
b := make([]byte, 256)
for {
n, err := authConn.Read(b)
if err != nil {
authConn.Close()
break
}
_, err = authConn.Write(b[:n])
common.Must(err)
}
}()
conn, err := net.DialTCP("tcp", nil, listener.Addr().(*net.TCPAddr))
common.Must(err)
conn.Write([]byte("ABCDEFGHIJKMLN\r\n\r\n"))
l, _, err := bufio.NewReader(conn).ReadLine()
common.Must(err)
if !strings.HasPrefix(string(l), "HTTP/1.1 400 Bad Request") {
t.Error("Resp to non http conn", string(l))
}
}

View file

@ -0,0 +1,11 @@
package http
import (
"bufio"
"net/http"
_ "unsafe" // required to use //go:linkname
)
//go:linkname readRequest net/http.readRequest
func readRequest(b *bufio.Reader, deleteHostHeader bool) (req *http.Request, err error)

View file

@ -0,0 +1,49 @@
package http
var resp400 = &ResponseConfig{
Version: &Version{
Value: "1.1",
},
Status: &Status{
Code: "400",
Reason: "Bad Request",
},
Header: []*Header{
{
Name: "Connection",
Value: []string{"close"},
},
{
Name: "Cache-Control",
Value: []string{"private"},
},
{
Name: "Content-Length",
Value: []string{"0"},
},
},
}
var resp404 = &ResponseConfig{
Version: &Version{
Value: "1.1",
},
Status: &Status{
Code: "404",
Reason: "Not Found",
},
Header: []*Header{
{
Name: "Connection",
Value: []string{"close"},
},
{
Name: "Cache-Control",
Value: []string{"private"},
},
{
Name: "Content-Length",
Value: []string{"0"},
},
},
}