mirror of https://github.com/v2ray/v2ray-core
Darien Raymond
6 years ago
5 changed files with 265 additions and 0 deletions
@ -0,0 +1,67 @@
|
||||
package speedtest |
||||
|
||||
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 Config struct { |
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"` |
||||
XXX_unrecognized []byte `json:"-"` |
||||
XXX_sizecache int32 `json:"-"` |
||||
} |
||||
|
||||
func (m *Config) Reset() { *m = Config{} } |
||||
func (m *Config) String() string { return proto.CompactTextString(m) } |
||||
func (*Config) ProtoMessage() {} |
||||
func (*Config) Descriptor() ([]byte, []int) { |
||||
return fileDescriptor_config_a46c59b79195c0b1, []int{0} |
||||
} |
||||
func (m *Config) XXX_Unmarshal(b []byte) error { |
||||
return xxx_messageInfo_Config.Unmarshal(m, b) |
||||
} |
||||
func (m *Config) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |
||||
return xxx_messageInfo_Config.Marshal(b, m, deterministic) |
||||
} |
||||
func (dst *Config) XXX_Merge(src proto.Message) { |
||||
xxx_messageInfo_Config.Merge(dst, src) |
||||
} |
||||
func (m *Config) XXX_Size() int { |
||||
return xxx_messageInfo_Config.Size(m) |
||||
} |
||||
func (m *Config) XXX_DiscardUnknown() { |
||||
xxx_messageInfo_Config.DiscardUnknown(m) |
||||
} |
||||
|
||||
var xxx_messageInfo_Config proto.InternalMessageInfo |
||||
|
||||
func init() { |
||||
proto.RegisterType((*Config)(nil), "v2ray.core.proxy.speedtest.Config") |
||||
} |
||||
|
||||
func init() { |
||||
proto.RegisterFile("v2ray.com/core/proxy/speedtest/config.proto", fileDescriptor_config_a46c59b79195c0b1) |
||||
} |
||||
|
||||
var fileDescriptor_config_a46c59b79195c0b1 = []byte{ |
||||
// 131 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x2e, 0x33, 0x2a, 0x4a, |
||||
0xac, 0xd4, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0x2f, 0x4a, 0xd5, 0x2f, 0x28, 0xca, 0xaf, 0xa8, |
||||
0xd4, 0x2f, 0x2e, 0x48, 0x4d, 0x4d, 0x29, 0x49, 0x2d, 0x2e, 0xd1, 0x4f, 0xce, 0xcf, 0x4b, 0xcb, |
||||
0x4c, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x82, 0x29, 0x2e, 0x4a, 0xd5, 0x03, 0x2b, |
||||
0xd4, 0x83, 0x2b, 0x54, 0xe2, 0xe0, 0x62, 0x73, 0x06, 0xab, 0x75, 0xf2, 0xe2, 0x92, 0x4b, 0xce, |
||||
0xcf, 0xd5, 0xc3, 0xad, 0x36, 0x80, 0x31, 0x8a, 0x13, 0xce, 0x59, 0xc5, 0x24, 0x15, 0x66, 0x14, |
||||
0x94, 0x58, 0xa9, 0xe7, 0x0c, 0x52, 0x19, 0x00, 0x56, 0x19, 0x0c, 0x92, 0x0c, 0x49, 0x2d, 0x2e, |
||||
0x49, 0x62, 0x03, 0x5b, 0x6c, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x07, 0x81, 0xb2, 0x36, 0xa7, |
||||
0x00, 0x00, 0x00, |
||||
} |
@ -0,0 +1,9 @@
|
||||
syntax = "proto3"; |
||||
|
||||
package v2ray.core.proxy.speedtest; |
||||
option csharp_namespace = "V2Ray.Core.Proxy.SpeedTest"; |
||||
option go_package = "speedtest"; |
||||
option java_package = "com.v2ray.core.proxy.speedtest"; |
||||
option java_multiple_files = true; |
||||
|
||||
message Config {} |
@ -0,0 +1,7 @@
|
||||
package speedtest |
||||
|
||||
import "v2ray.com/core/common/errors" |
||||
|
||||
func newError(values ...interface{}) *errors.Error { |
||||
return errors.New(values...).Path("Proxy", "SpeedTest") |
||||
} |
@ -0,0 +1,181 @@
|
||||
package speedtest |
||||
|
||||
//go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg speedtest -path Proxy,SpeedTest
|
||||
|
||||
import ( |
||||
"bufio" |
||||
"context" |
||||
"io" |
||||
"net/http" |
||||
"strconv" |
||||
"strings" |
||||
|
||||
"v2ray.com/core" |
||||
"v2ray.com/core/common" |
||||
"v2ray.com/core/common/buf" |
||||
"v2ray.com/core/common/serial" |
||||
"v2ray.com/core/common/session" |
||||
"v2ray.com/core/proxy" |
||||
) |
||||
|
||||
var rndBytes = []byte("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&\\'()*+,-") |
||||
|
||||
type rndBytesReader struct{} |
||||
|
||||
func (rndBytesReader) Read(b []byte) (int, error) { |
||||
totalBytes := 0 |
||||
for totalBytes < len(b) { |
||||
nBytes := copy(b[totalBytes:], rndBytes[:]) |
||||
totalBytes += nBytes |
||||
} |
||||
return totalBytes, nil |
||||
} |
||||
|
||||
func (rndBytesReader) Close() error { |
||||
return nil |
||||
} |
||||
|
||||
type SpeedTestHandler struct{} |
||||
|
||||
func New(ctx context.Context, config *Config) (*SpeedTestHandler, error) { |
||||
return &SpeedTestHandler{}, nil |
||||
} |
||||
|
||||
type noOpCloser struct { |
||||
io.Reader |
||||
} |
||||
|
||||
func (c *noOpCloser) Close() error { |
||||
return nil |
||||
} |
||||
|
||||
func defaultResponse() *http.Response { |
||||
response := &http.Response{ |
||||
Status: "Not Found", |
||||
StatusCode: 404, |
||||
Proto: "HTTP/1.1", |
||||
ProtoMajor: 1, |
||||
ProtoMinor: 1, |
||||
Header: http.Header(make(map[string][]string)), |
||||
Body: nil, |
||||
ContentLength: 0, |
||||
Close: true, |
||||
} |
||||
response.Header.Set("Content-Type", "text/plain; charset=UTF-8") |
||||
return response |
||||
} |
||||
|
||||
func (h *SpeedTestHandler) Process(ctx context.Context, link *core.Link, dialer proxy.Dialer) error { |
||||
reader := link.Reader |
||||
writer := link.Writer |
||||
|
||||
defer func() { |
||||
common.Close(writer) |
||||
}() |
||||
|
||||
bufReader := bufio.NewReader(&buf.BufferedReader{ |
||||
Reader: reader, |
||||
Direct: true, |
||||
}) |
||||
|
||||
bufWriter := buf.NewBufferedWriter(writer) |
||||
common.Must(bufWriter.SetBuffered(false)) |
||||
|
||||
request, err := http.ReadRequest(bufReader) |
||||
if err != nil { |
||||
return newError("failed to read speedtest request").Base(err) |
||||
} |
||||
|
||||
path := strings.ToLower(request.URL.Path) |
||||
if len(path) > 0 && path[0] == '/' { |
||||
path = path[1:] |
||||
} |
||||
|
||||
switch path { |
||||
case "hello": |
||||
respBody := "hello 2.5 2017-08-15.1314.4ae12d5" |
||||
response := &http.Response{ |
||||
Status: "OK", |
||||
StatusCode: 200, |
||||
Proto: "HTTP/1.1", |
||||
ProtoMajor: 1, |
||||
ProtoMinor: 1, |
||||
Header: http.Header(make(map[string][]string)), |
||||
Body: &noOpCloser{strings.NewReader(respBody)}, |
||||
ContentLength: int64(len(respBody)), |
||||
Close: true, |
||||
} |
||||
response.Header.Set("Content-Type", "text/plain; charset=UTF-8") |
||||
return response.Write(bufWriter) |
||||
case "upload": |
||||
switch strings.ToUpper(request.Method) { |
||||
case "POST": |
||||
var sc buf.SizeCounter |
||||
buf.Copy(buf.NewReader(request.Body), buf.Discard, buf.CountSize(&sc)) // nolint: errcheck
|
||||
|
||||
response := &http.Response{ |
||||
Status: "OK", |
||||
StatusCode: 200, |
||||
Proto: "HTTP/1.1", |
||||
ProtoMajor: 1, |
||||
ProtoMinor: 1, |
||||
Header: http.Header(make(map[string][]string)), |
||||
Body: &noOpCloser{strings.NewReader(serial.Concat("size=", sc.Size))}, |
||||
Close: true, |
||||
} |
||||
response.Header.Set("Content-Type", "text/plain; charset=UTF-8") |
||||
return response.Write(bufWriter) |
||||
case "OPTIONS": |
||||
response := &http.Response{ |
||||
Status: "OK", |
||||
StatusCode: 200, |
||||
Proto: "HTTP/1.1", |
||||
ProtoMajor: 1, |
||||
ProtoMinor: 1, |
||||
Header: http.Header(make(map[string][]string)), |
||||
Body: nil, |
||||
ContentLength: 0, |
||||
Close: true, |
||||
} |
||||
|
||||
response.Header.Set("Content-Type", "text/plain; charset=UTF-8") |
||||
response.Header.Set("Connection", "Close") |
||||
response.Header.Set("Access-Control-Allow-Methods", "OPTIONS, POST") |
||||
response.Header.Set("Access-Control-Allow-Headers", "content-type") |
||||
response.Header.Set("Access-Control-Allow-Origin", "http://www.speedtest.net") |
||||
return response.Write(bufWriter) |
||||
default: |
||||
newError("unknown method for upload: ", request.Method).WriteToLog(session.ExportIDToError(ctx)) |
||||
return defaultResponse().Write(bufWriter) |
||||
} |
||||
case "download": |
||||
query := request.URL.Query() |
||||
sizeStr := query.Get("size") |
||||
size, err := strconv.Atoi(sizeStr) |
||||
if err != nil { |
||||
return defaultResponse().Write(bufWriter) |
||||
} |
||||
response := &http.Response{ |
||||
Status: "OK", |
||||
StatusCode: 200, |
||||
Proto: "HTTP/1.1", |
||||
ProtoMajor: 1, |
||||
ProtoMinor: 1, |
||||
Header: http.Header(make(map[string][]string)), |
||||
Body: rndBytesReader{}, |
||||
ContentLength: int64(size), |
||||
Close: true, |
||||
} |
||||
response.Header.Set("Content-Type", "text/plain; charset=UTF-8") |
||||
return response.Write(bufWriter) |
||||
default: |
||||
newError("unknown path: ", path).WriteToLog(session.ExportIDToError(ctx)) |
||||
return defaultResponse().Write(bufWriter) |
||||
} |
||||
} |
||||
|
||||
func init() { |
||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { |
||||
return New(ctx, config.(*Config)) |
||||
})) |
||||
} |
Loading…
Reference in new issue