Ver Fonte

speedtest

Darien Raymond há 7 anos atrás
pai
commit
a21d769e37

+ 1 - 0
main/distro/all/all.go

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

+ 67 - 0
proxy/speedtest/config.pb.go

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

+ 9 - 0
proxy/speedtest/config.proto

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

+ 7 - 0
proxy/speedtest/errors.generated.go

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

+ 181 - 0
proxy/speedtest/speedtest.go

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