Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ Response:
"message": "",
"isHttps": true,
"httpsForward": false,
"httpStatus": 200,
"reachable": true,
"reachableIPv6": true,
"reachableIPv4": true,
"cors": true,
"contentType": true,
"certValid": true,
Expand Down
14 changes: 13 additions & 1 deletion openapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
Expand Down Expand Up @@ -235,9 +235,18 @@ var openapi = `{
"httpsForward": {
"type": "boolean"
},
"httpStatus": {
"type": "integer"
},
"reachable": {
"type": "boolean"
},
"reachableIPv6": {
"type": "boolean"
},
"reachableIPv4": {
"type": "boolean"
},
"cors": {
"type": "boolean"
},
Expand Down Expand Up @@ -267,7 +276,10 @@ var openapi = `{
"valid",
"isHttps",
"httpsForward",
"httpStatus",
"reachable",
"reachableIPv6",
"reachableIPv4",
"cors",
"contentType",
"certValid"
Expand Down
51 changes: 50 additions & 1 deletion v2/validator.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package v2

import (
"context"
"crypto/tls"
"encoding/json"
"fmt"
Expand All @@ -10,6 +11,7 @@ import (
"golang.org/x/time/rate"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
"strings"
Expand All @@ -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"`
Expand Down Expand Up @@ -183,12 +188,36 @@ 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) {
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: httpTimeout,
Transport: trv6,
}
defer clientv6.CloseIdleConnections()
clientv4 := http.Client{
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
Expand All @@ -206,6 +235,25 @@ func fetchURL(validationResponse *urlValidationResponse, url *url.URL, skipVerif
}

req.Header.Add("Origin", "https://validator.spaceapi.io")

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it intentional that the checks below happen after setting the Origin header, but ther egular Reachable-Check above happens before?

Also, couldn't the validationResponse.Reachable value just be validationResponse.ReachableIPv6 || validationResponse.ReachableIPv4?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it intentional that the checks below happen after setting the Origin header, but ther egular Reachable-Check above happens before?

The thing that happens in L230-234 is the preparation of the request, not the actual sending. The single request will then be used 3 times below. As far as I understand it, setting .Reachable = false in L232 is actually a no-op, as the variable is initialized as false anyway. The actual "regular" check happens in L256 and onward.

Also, couldn't the validationResponse.Reachable value just be validationResponse.ReachableIPv6 || validationResponse.ReachableIPv4?

Unfortunately not. validationResponse.Reachable is actually a bit of a misnomer, as it also checks for e.g. the HTTP status code (L274). With the IPv6 and IPv4 request, reachable just means "we got a HTTP response". I'm unsure whether this is the best approach, but it's one that doesn't break the semantics of existing API fields. You can look into SpaceApi/validator-web#14 to see how I'm using the new API fields in combination with existing ones without breaking the existing ones.

If we decided to change the semantics of validationResponse.Reachable instead, I see it as a breaking change warranting a new major API version.

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 {
Expand All @@ -223,6 +271,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)
Expand Down