From e9b4d16d716ff03aaab66308a4ffe175ab10d859 Mon Sep 17 00:00:00 2001 From: s3lph <5564491+s3lph@users.noreply.github.com> Date: Fri, 10 Oct 2025 22:35:15 +0200 Subject: [PATCH 1/2] feat: add validator response fields for ipv6, ipv4 and http status code --- README.md | 3 +++ openapi.go | 14 +++++++++++++- v2/validator.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1700004..1411a91 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,10 @@ Response: "message": "", "isHttps": true, "httpsForward": false, + "httpStatus": 200, "reachable": true, + "reachableIPv6": true, + "reachableIPv4": true, "cors": true, "contentType": true, "certValid": true, diff --git a/openapi.go b/openapi.go index 962cd6f..29e130a 100644 --- a/openapi.go +++ b/openapi.go @@ -4,7 +4,7 @@ var openapi = `{ "openapi": "3.0.2", "info": { "description": "This is the SpaceApi Validator api", - "version": "1.2.0", + "version": "1.3.0", "title": "SpaceApi Validator" }, "servers": [ @@ -235,9 +235,18 @@ var openapi = `{ "httpsForward": { "type": "boolean" }, + "httpStatus": { + "type": "integer" + }, "reachable": { "type": "boolean" }, + "reachableIPv6": { + "type": "boolean" + }, + "reachableIPv4": { + "type": "boolean" + }, "cors": { "type": "boolean" }, @@ -267,7 +276,10 @@ var openapi = `{ "valid", "isHttps", "httpsForward", + "httpStatus", "reachable", + "reachableIPv6", + "reachableIPv4", "cors", "contentType", "certValid" diff --git a/v2/validator.go b/v2/validator.go index 672c4a2..946a7e6 100644 --- a/v2/validator.go +++ b/v2/validator.go @@ -1,6 +1,7 @@ package v2 import ( + "context" "crypto/tls" "encoding/json" "fmt" @@ -10,6 +11,7 @@ import ( "golang.org/x/time/rate" "io" "io/ioutil" + "net" "net/http" "net/url" "strings" @@ -31,7 +33,10 @@ type urlValidationResponse struct { Message string `json:"message,omitempty"` IsHTTPS bool `json:"isHttps"` HTTPSForward bool `json:"httpsForward"` + HTTPStatus int `json:"httpStatus"` Reachable bool `json:"reachable"` + ReachableIPv4 bool `json:"reachableIPv4"` + ReachableIPv6 bool `json:"reachableIPv6"` Cors bool `json:"cors"` ContentType bool `json:"contentType"` CertValid bool `json:"certValid"` @@ -183,10 +188,33 @@ func checkHeader(response *urlValidationResponse, header http.Header) { } func fetchURL(validationResponse *urlValidationResponse, url *url.URL, skipVerify bool) (http.Header, string, error) { + dialer := net.Dialer{} + trv6 := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: skipVerify}, + DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { + return dialer.DialContext(ctx, "tcp6", addr) + }, + } + trv4 := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: skipVerify}, + DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { + return dialer.DialContext(ctx, "tcp4", addr) + }, + } tr := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: skipVerify}, } + clientv6 := http.Client{ + Timeout: time.Second * 10, + Transport: trv6, + } + defer clientv6.CloseIdleConnections() + clientv4 := http.Client{ + Timeout: time.Second * 10, + Transport: trv4, + } + defer clientv4.CloseIdleConnections() client := http.Client{ Timeout: time.Second * 10, CheckRedirect: func(req *http.Request, via []*http.Request) error { @@ -206,6 +234,25 @@ func fetchURL(validationResponse *urlValidationResponse, url *url.URL, skipVerif } req.Header.Add("Origin", "https://validator.spaceapi.io") + + responsev6, err := clientv6.Do(req) + if err == nil { + validationResponse.ReachableIPv6 = true + err = responsev6.Body.Close() + if err != nil { + panic(err) + } + } + + responsev4, err := clientv4.Do(req) + if err == nil { + validationResponse.ReachableIPv4 = true + err = responsev4.Body.Close() + if err != nil { + panic(err) + } + } + response, err := client.Do(req) if err != nil { if skipVerify == false { @@ -223,6 +270,7 @@ func fetchURL(validationResponse *urlValidationResponse, url *url.URL, skipVerif } }() + validationResponse.HTTPStatus = response.StatusCode if response.StatusCode >= 400 { validationResponse.Reachable = false _, _ = io.Copy(ioutil.Discard, response.Body) From 337dd5a3f3fabe90e7a7f8921b743d1a25bf2f48 Mon Sep 17 00:00:00 2001 From: s3lph <5564491+s3lph@users.noreply.github.com> Date: Mon, 13 Oct 2025 00:59:04 +0200 Subject: [PATCH 2/2] feat: move http timeout literals into one variable --- v2/validator.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/v2/validator.go b/v2/validator.go index 946a7e6..f84ad03 100644 --- a/v2/validator.go +++ b/v2/validator.go @@ -189,6 +189,7 @@ func checkHeader(response *urlValidationResponse, header http.Header) { func fetchURL(validationResponse *urlValidationResponse, url *url.URL, skipVerify bool) (http.Header, string, error) { dialer := net.Dialer{} + httpTimeout := 10 * time.Second trv6 := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: skipVerify}, DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { @@ -206,17 +207,17 @@ func fetchURL(validationResponse *urlValidationResponse, url *url.URL, skipVerif } clientv6 := http.Client{ - Timeout: time.Second * 10, + Timeout: httpTimeout, Transport: trv6, } defer clientv6.CloseIdleConnections() clientv4 := http.Client{ - Timeout: time.Second * 10, + Timeout: httpTimeout, Transport: trv4, } defer clientv4.CloseIdleConnections() client := http.Client{ - Timeout: time.Second * 10, + Timeout: httpTimeout, CheckRedirect: func(req *http.Request, via []*http.Request) error { if req.URL.Scheme == "https" { validationResponse.HTTPSForward = true