1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-12-22 18:17:52 -05:00

http authenticator

This commit is contained in:
Darien Raymond 2016-10-31 22:26:46 +01:00
parent 5e1c6fe816
commit ac3b91a877
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169
7 changed files with 433 additions and 0 deletions

View File

@ -0,0 +1,53 @@
package http
import (
"v2ray.com/core/common/dice"
)
func pickString(arr []string) string {
n := len(arr)
if n == 0 {
return ""
}
return arr[dice.Roll(n)]
}
func (this *RequestConfig) PickUri() string {
return pickString(this.Uri)
}
func (this *RequestConfig) PickHeaders() []string {
n := len(this.Header)
if n == 0 {
return nil
}
headers := make([]string, n)
for idx, headerConfig := range this.Header {
headerName := headerConfig.Name
headerValue := pickString(headerConfig.Value)
headers[idx] = headerName + ": " + headerValue
}
return headers
}
func (this *RequestConfig) GetVersion() string {
return "HTTP/" + this.Version
}
func (this *ResponseConfig) PickHeaders() []string {
n := len(this.Header)
if n == 0 {
return nil
}
headers := make([]string, n)
for idx, headerConfig := range this.Header {
headerName := headerConfig.Name
headerValue := pickString(headerConfig.Value)
headers[idx] = headerName + ": " + headerValue
}
return headers
}
func (this *ResponseConfig) GetVersion() string {
return "HTTP/" + this.Version
}

View File

@ -0,0 +1,128 @@
// Code generated by protoc-gen-go.
// source: v2ray.com/core/transport/internet/authenticators/http/config.proto
// DO NOT EDIT!
/*
Package http is a generated protocol buffer package.
It is generated from these files:
v2ray.com/core/transport/internet/authenticators/http/config.proto
It has these top-level messages:
Header
HeaderEnding
RequestConfig
ResponseConfig
*/
package http
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Header struct {
// "Accept", "Cookie", etc
Name string `protobuf:"bytes,1,opt,name=name" 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" json:"value,omitempty"`
}
func (m *Header) Reset() { *m = Header{} }
func (m *Header) String() string { return proto.CompactTextString(m) }
func (*Header) ProtoMessage() {}
func (*Header) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
type HeaderEnding struct {
Value string `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"`
}
func (m *HeaderEnding) Reset() { *m = HeaderEnding{} }
func (m *HeaderEnding) String() string { return proto.CompactTextString(m) }
func (*HeaderEnding) ProtoMessage() {}
func (*HeaderEnding) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
type RequestConfig struct {
// Full HTTP version like "1.1".
Version string `protobuf:"bytes,1,opt,name=version" json:"version,omitempty"`
// GET, POST, CONNECT etc
Method string `protobuf:"bytes,2,opt,name=method" json:"method,omitempty"`
// URI like "/login.php"
Uri []string `protobuf:"bytes,3,rep,name=uri" json:"uri,omitempty"`
Header []*Header `protobuf:"bytes,4,rep,name=header" json:"header,omitempty"`
}
func (m *RequestConfig) Reset() { *m = RequestConfig{} }
func (m *RequestConfig) String() string { return proto.CompactTextString(m) }
func (*RequestConfig) ProtoMessage() {}
func (*RequestConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (m *RequestConfig) GetHeader() []*Header {
if m != nil {
return m.Header
}
return nil
}
type ResponseConfig struct {
Version string `protobuf:"bytes,1,opt,name=version" json:"version,omitempty"`
Status string `protobuf:"bytes,2,opt,name=status" json:"status,omitempty"`
Reason string `protobuf:"bytes,3,opt,name=reason" json:"reason,omitempty"`
Header []*Header `protobuf:"bytes,4,rep,name=header" json:"header,omitempty"`
}
func (m *ResponseConfig) Reset() { *m = ResponseConfig{} }
func (m *ResponseConfig) String() string { return proto.CompactTextString(m) }
func (*ResponseConfig) ProtoMessage() {}
func (*ResponseConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
func (m *ResponseConfig) GetHeader() []*Header {
if m != nil {
return m.Header
}
return nil
}
func init() {
proto.RegisterType((*Header)(nil), "v2ray.core.transport.internet.authenticators.http.Header")
proto.RegisterType((*HeaderEnding)(nil), "v2ray.core.transport.internet.authenticators.http.HeaderEnding")
proto.RegisterType((*RequestConfig)(nil), "v2ray.core.transport.internet.authenticators.http.RequestConfig")
proto.RegisterType((*ResponseConfig)(nil), "v2ray.core.transport.internet.authenticators.http.ResponseConfig")
}
func init() {
proto.RegisterFile("v2ray.com/core/transport/internet/authenticators/http/config.proto", fileDescriptor0)
}
var fileDescriptor0 = []byte{
// 303 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x92, 0x31, 0x4b, 0xfc, 0x40,
0x10, 0xc5, 0xc9, 0xe5, 0xfe, 0xf9, 0x73, 0x73, 0x2a, 0xb2, 0x88, 0x6c, 0x79, 0x1c, 0x16, 0x57,
0x6d, 0xf0, 0xc4, 0xc2, 0xf6, 0x44, 0x10, 0x2b, 0x4d, 0x69, 0xb7, 0xe6, 0xc6, 0x4b, 0xc0, 0xec,
0xc4, 0xd9, 0x49, 0xc0, 0x2f, 0x64, 0xe7, 0x77, 0x94, 0x64, 0x13, 0xc5, 0xce, 0x2b, 0xec, 0xf6,
0xcd, 0xce, 0xef, 0xcd, 0x1b, 0x18, 0xd8, 0xb4, 0x6b, 0xb6, 0x6f, 0x26, 0xa7, 0x2a, 0xcd, 0x89,
0x31, 0x15, 0xb6, 0xce, 0xd7, 0xc4, 0x92, 0x96, 0x4e, 0x90, 0x1d, 0x4a, 0x6a, 0x1b, 0x29, 0xd0,
0x49, 0x99, 0x5b, 0x21, 0xf6, 0x69, 0x21, 0x52, 0xa7, 0x39, 0xb9, 0xe7, 0x72, 0x67, 0x6a, 0x26,
0x21, 0x75, 0x3e, 0x7a, 0x30, 0x9a, 0x2f, 0xde, 0x8c, 0xbc, 0xf9, 0xc9, 0x9b, 0x8e, 0x5f, 0xae,
0x21, 0xb9, 0x45, 0xbb, 0x45, 0x56, 0x0a, 0xa6, 0xce, 0x56, 0xa8, 0xa3, 0x45, 0xb4, 0x9a, 0x65,
0xfd, 0x5b, 0x9d, 0xc0, 0xbf, 0xd6, 0xbe, 0x34, 0xa8, 0x27, 0x8b, 0x78, 0x35, 0xcb, 0x82, 0x58,
0x9e, 0xc1, 0x41, 0x60, 0x6e, 0xdc, 0xb6, 0x74, 0xbb, 0xef, 0xae, 0x80, 0x0e, 0x5d, 0xef, 0x11,
0x1c, 0x66, 0xf8, 0xda, 0xa0, 0x97, 0xeb, 0x3e, 0xa4, 0xd2, 0xf0, 0xbf, 0x45, 0xf6, 0x25, 0xb9,
0xa1, 0x73, 0x94, 0xea, 0x14, 0x92, 0x0a, 0xa5, 0xa0, 0xad, 0x9e, 0xf4, 0x1f, 0x83, 0x52, 0xc7,
0x10, 0x37, 0x5c, 0xea, 0xb8, 0x9f, 0xde, 0x3d, 0xd5, 0x03, 0x24, 0x45, 0x3f, 0x5b, 0x4f, 0x17,
0xf1, 0x6a, 0xbe, 0xbe, 0x32, 0x7b, 0xef, 0x6c, 0x42, 0xf8, 0x6c, 0x30, 0x5a, 0x7e, 0x44, 0x70,
0x94, 0xa1, 0xaf, 0xc9, 0x79, 0xfc, 0x4d, 0x52, 0x2f, 0x56, 0x1a, 0x3f, 0x26, 0x0d, 0xaa, 0xab,
0x33, 0x5a, 0x4f, 0x4e, 0xc7, 0xa1, 0x1e, 0xd4, 0x1f, 0xe4, 0xdd, 0xdc, 0xc1, 0x65, 0x4e, 0xd5,
0xfe, 0x3e, 0x9b, 0x79, 0xd8, 0xee, 0xbe, 0xbb, 0x95, 0xc7, 0x69, 0x57, 0x7a, 0x4a, 0xfa, 0xc3,
0xb9, 0xf8, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x78, 0x8c, 0xa7, 0x40, 0x7e, 0x02, 0x00, 0x00,
}

View File

@ -0,0 +1,41 @@
syntax = "proto3";
package v2ray.core.transport.internet.authenticators.http;
option go_package = "http";
option java_package = "com.v2ray.core.transport.internet.authenticators.http";
option java_outer_classname = "ConfigProto";
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;
}
message HeaderEnding {
string value = 1;
}
message RequestConfig {
// Full HTTP version like "1.1".
string version = 1;
// GET, POST, CONNECT etc
string method = 2;
// URI like "/login.php"
repeated string uri = 3;
repeated Header header = 4;
}
message ResponseConfig {
string version = 1;
string status = 2;
string reason = 3;
repeated Header header = 4;
}

View File

@ -0,0 +1,120 @@
package http
import (
"bytes"
"io"
"v2ray.com/core/common/alloc"
"v2ray.com/core/transport/internet"
)
const (
CRLF = "\r\n"
ENDING = CRLF + CRLF
)
type RequestAuthenticator struct {
config *RequestConfig
}
func (this *RequestAuthenticator) Seal(writer io.Writer) io.Writer {
header := alloc.NewLocalBuffer(2048)
header.AppendString(this.config.Method).AppendString(" ").AppendString(this.config.PickUri()).AppendString(" ").AppendString(this.config.GetVersion()).AppendString(CRLF)
headers := this.config.PickHeaders()
for _, h := range headers {
header.AppendString(h).AppendString(CRLF)
}
header.AppendString(CRLF)
writer.Write(header.Value)
header.Release()
return writer
}
func (this *RequestAuthenticator) Open(reader io.Reader) (io.Reader, error) {
buffer := alloc.NewLocalBuffer(2048)
for {
_, err := buffer.FillFrom(reader)
if err != nil {
return nil, err
}
if n := bytes.Index(buffer.Value, []byte(ENDING)); n != -1 {
buffer.SliceFrom(n + len(ENDING))
return &BufferAndReader{
buffer: buffer,
reader: reader,
}, nil
}
if buffer.Len() >= len(ENDING) {
copy(buffer.Value, buffer.Value[buffer.Len()-len(ENDING):])
buffer.Slice(0, len(ENDING))
}
}
}
type BufferAndReader struct {
buffer *alloc.Buffer
reader io.Reader
}
func (this *BufferAndReader) Read(b []byte) (int, error) {
if this.buffer.Len() == 0 {
return this.reader.Read(b)
}
n, err := this.buffer.Read(b)
if n == this.buffer.Len() {
this.buffer.Release()
this.buffer = nil
}
return n, err
}
type RequestAuthenticatorFactory struct{}
func (RequestAuthenticatorFactory) Create(config interface{}) internet.ConnectionAuthenticator {
return &RequestAuthenticator{
config: config.(*RequestConfig),
}
}
type ResponseAuthenticator struct {
config *ResponseConfig
}
func (this *ResponseAuthenticator) Seal(writer io.Writer) io.Writer {
header := alloc.NewLocalBuffer(2048)
header.AppendString(this.config.GetVersion()).AppendString(" ").AppendString(this.config.Status).AppendString(" ").AppendString(this.config.Reason).AppendString(CRLF)
headers := this.config.PickHeaders()
for _, h := range headers {
header.AppendString(h).AppendString(CRLF)
}
header.AppendString(CRLF)
writer.Write(header.Value)
header.Release()
return writer
}
func (this *ResponseAuthenticator) Open(reader io.Reader) (io.Reader, error) {
buffer := alloc.NewLocalBuffer(2048)
for {
_, err := buffer.FillFrom(reader)
if err != nil {
return nil, err
}
if n := bytes.Index(buffer.Value, []byte(ENDING)); n != -1 {
buffer.SliceFrom(n + len(ENDING))
return &BufferAndReader{
buffer: buffer,
reader: reader,
}, nil
}
if buffer.Len() >= len(ENDING) {
copy(buffer.Value, buffer.Value[buffer.Len()-len(ENDING):])
buffer.Slice(0, len(ENDING))
}
}
}

View File

@ -0,0 +1,38 @@
package http_test
import (
"testing"
"v2ray.com/core/common/alloc"
"v2ray.com/core/testing/assert"
. "v2ray.com/core/transport/internet/authenticators/http"
)
func TestRequestOpenSeal(t *testing.T) {
assert := assert.On(t)
content := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g'}
cache := alloc.NewLargeBuffer()
http := (RequestAuthenticatorFactory{}).Create(&RequestConfig{
Method: "GET",
Uri: []string{"/"},
Version: "1.1",
Header: []*Header{
{
Name: "Content-Length",
Value: []string{"123"},
},
},
})
http.Seal(cache).Write(content)
actualContent := make([]byte, 256)
reader, err := http.Open(cache)
assert.Error(err).IsNil()
n, err := reader.Read(actualContent)
assert.Error(err).IsNil()
assert.Bytes(content).Equals(actualContent[:n])
}

View File

@ -1,6 +1,7 @@
package noop package noop
import ( import (
"io"
"v2ray.com/core/common/alloc" "v2ray.com/core/common/alloc"
"v2ray.com/core/common/loader" "v2ray.com/core/common/loader"
"v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet"
@ -22,6 +23,23 @@ func (this NoOpAuthenticatorFactory) Create(config interface{}) internet.Authent
return NoOpAuthenticator{} return NoOpAuthenticator{}
} }
type NoOpConnectionAuthenticator struct{}
func (NoOpConnectionAuthenticator) Open(reader io.Reader) (bool, io.Reader) {
return true, reader
}
func (NoOpConnectionAuthenticator) Seal(writer io.Writer) io.Writer {
return writer
}
type NoOpConnectionAuthenticatorFactory struct{}
func (NoOpConnectionAuthenticatorFactory) Create(config interface{}) internet.ConnectionAuthenticator {
return NoOpConnectionAuthenticator{}
}
func init() { func init() {
internet.RegisterAuthenticator(loader.GetType(new(Config)), NoOpAuthenticatorFactory{}) internet.RegisterAuthenticator(loader.GetType(new(Config)), NoOpAuthenticatorFactory{})
internet.RegisterConnectionAuthenticator(loader.GetType(new(Config)), NoOpConnectionAuthenticatorFactory{})
} }

View File

@ -0,0 +1,35 @@
package internet
import (
"io"
"v2ray.com/core/common"
)
type ConnectionAuthenticator interface {
Seal(io.Writer) io.Writer
Open(io.Reader) (io.Reader, error)
}
type ConnectionAuthenticatorFactory interface {
Create(interface{}) ConnectionAuthenticator
}
var (
connectionAuthenticatorCache = make(map[string]ConnectionAuthenticatorFactory)
)
func RegisterConnectionAuthenticator(name string, factory ConnectionAuthenticatorFactory) error {
if _, found := connectionAuthenticatorCache[name]; found {
return common.ErrDuplicatedName
}
connectionAuthenticatorCache[name] = factory
return nil
}
func CreateConnectionAuthenticator(name string, config interface{}) (ConnectionAuthenticator, error) {
factory, found := connectionAuthenticatorCache[name]
if !found {
return nil, common.ErrObjectNotFound
}
return factory.Create(config), nil
}