Compare commits

..
7 changed files with 115 additions and 6 deletions
+2 -2
View File
@@ -9,8 +9,8 @@ ARG TARGETARCH
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -o xray -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags "-s -w -buildid=" ./main
# Download geodat into a staging directory
ADD https://raw.githubusercontent.com/XTLS/Xray-rules-dat/release/geoip/geoip-full.dat /tmp/geodat/geoip.dat
ADD https://raw.githubusercontent.com/XTLS/Xray-rules-dat/release/geosite/geosite-expand.dat /tmp/geodat/geosite.dat
ADD https://github.com/XTLS/Xray-rules-dat/releases/latest/download/geoip-full.dat /tmp/geodat/geoip.dat
ADD https://github.com/XTLS/Xray-rules-dat/releases/latest/download/geosite-expand.dat /tmp/geodat/geosite.dat
RUN mkdir -p /tmp/empty
+2 -2
View File
@@ -9,8 +9,8 @@ ARG TARGETARCH
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -o xray -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags "-s -w -buildid=" ./main
# Download geodat into a staging directory
ADD https://raw.githubusercontent.com/XTLS/Xray-rules-dat/release/geoip/geoip-full.dat /tmp/geodat/geoip.dat
ADD https://raw.githubusercontent.com/XTLS/Xray-rules-dat/release/geosite/geosite-expand.dat /tmp/geodat/geosite.dat
ADD https://github.com/XTLS/Xray-rules-dat/releases/latest/download/geoip-full.dat /tmp/geodat/geoip.dat
ADD https://github.com/XTLS/Xray-rules-dat/releases/latest/download/geosite-expand.dat /tmp/geodat/geosite.dat
RUN mkdir -p /tmp/empty
+11 -1
View File
@@ -2,6 +2,7 @@ package conf
import (
"net/url"
"strings"
"github.com/robfig/cron/v3"
"github.com/xtls/xray-core/app/geodata"
@@ -19,11 +20,20 @@ func (c *GeodataAssetConfig) Build() (*geodata.Asset, error) {
return nil, errors.New("invalid geodata asset url: ", c.URL).Base(err)
}
return &geodata.Asset{
Url: c.URL,
Url: migrateGeodataURL(c.URL),
File: c.File,
}, nil
}
func migrateGeodataURL(assetURL string) string
if strings.HasSuffix(strings.ToLower(assetURL), ".dat") && (strings.HasPrefix(strings.ToLower(assetURL), "https://github.com/xtls/xray-rules-dat/")
|| strings.HasPrefix(strings.ToLower(assetURL), "https://raw.githubusercontent.com/xtls/xray-rules-dat/")) {
errors.PrintDeprecatedFeatureWarning(assetURL, assetURL+".gz")
return assetURL + ".gz"
}
return assetURL
}
func validateHTTPS(s string) error {
u, err := url.ParseRequestURI(s)
if err != nil {
+1 -1
View File
@@ -72,7 +72,7 @@ func (s *localStorage) Get(ctx context.Context, name string) ([]byte, error) {
if err != nil {
return nil, err
}
data, err := os.ReadFile(full)
data, err := readFile(ctx, full)
if err != nil {
if os.IsNotExist(err) {
return nil, errNotFound
+12
View File
@@ -0,0 +1,12 @@
//go:build !windows
package xdrive
import (
"context"
"os"
)
func readFile(_ context.Context, name string) ([]byte, error) {
return os.ReadFile(name)
}
@@ -0,0 +1,30 @@
package xdrive
import (
"context"
"errors"
"os"
"time"
"golang.org/x/sys/windows"
)
// readFile retries os.ReadFile for up to 2 seconds on sharing violations:
// os.Rename (MoveFileEx) in Put holds the file with DELETE access, which
// os.ReadFile does not share, until a moment after its new name appears in List
func readFile(ctx context.Context, name string) ([]byte, error) {
deadline := time.Now().Add(2 * time.Second)
delay := time.Millisecond
for {
data, err := os.ReadFile(name)
if !errors.Is(err, windows.ERROR_SHARING_VIOLATION) || time.Now().Add(delay).After(deadline) {
return data, err
}
select {
case <-ctx.Done():
return nil, err
case <-time.After(delay):
}
delay = min(2*delay, 100*time.Millisecond)
}
}
@@ -0,0 +1,57 @@
package xdrive
import (
"context"
"errors"
"sync"
"testing"
"time"
"golang.org/x/sys/windows"
)
func TestLocalSharingViolation(t *testing.T) {
storage, err := newLocalStorage(t.TempDir())
if err != nil {
t.Fatalf("newLocalStorage: %v", err)
}
const name = "streams/session/c2s/000000000.seg"
if err := storage.Put(context.Background(), name, []byte("segment")); err != nil {
t.Fatalf("Put: %v", err)
}
full, err := storage.resolve(name)
if err != nil {
t.Fatalf("resolve: %v", err)
}
path, err := windows.UTF16PtrFromString(full)
if err != nil {
t.Fatalf("UTF16PtrFromString: %v", err)
}
// os.Rename holds the file like this until a moment after its new name
// appears
handle, err := windows.CreateFile(path, windows.DELETE,
windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE,
nil, windows.OPEN_EXISTING, 0, 0)
if err != nil {
t.Fatalf("CreateFile: %v", err)
}
var once sync.Once
release := func() { once.Do(func() { windows.CloseHandle(handle) }) }
defer release()
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
defer cancel()
if _, err := storage.Get(ctx, name); !errors.Is(err, windows.ERROR_SHARING_VIOLATION) {
t.Fatalf("Get returned %v while the file is held, want a sharing violation", err)
}
time.AfterFunc(100*time.Millisecond, release)
data, err := storage.Get(context.Background(), name)
if err != nil {
t.Fatalf("Get: %v", err)
}
if string(data) != "segment" {
t.Fatalf("Get returned %q, want %q", data, "segment")
}
}