1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-06-10 09:50:43 +00:00

speedtest

This commit is contained in:
Darien Raymond 2018-07-25 19:22:36 +02:00
parent 20a08111ff
commit a21d769e37
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169
5 changed files with 265 additions and 0 deletions

View File

@ -29,6 +29,7 @@ import (
_ "v2ray.com/core/proxy/mtproto"
_ "v2ray.com/core/proxy/shadowsocks"
_ "v2ray.com/core/proxy/socks"
_ "v2ray.com/core/proxy/speedtest"
_ "v2ray.com/core/proxy/vmess/inbound"
_ "v2ray.com/core/proxy/vmess/outbound"

View File

@ -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,
}

View File

@ -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 {}

View File

@ -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")
}

View File

@ -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))
}))
}