diff --git a/internal/whois/adapter_vn.go b/internal/whois/adapter_vn.go new file mode 100644 index 0000000..ce65ab8 --- /dev/null +++ b/internal/whois/adapter_vn.go @@ -0,0 +1,67 @@ +package whois + +import ( + "net/url" + "strings" + + "github.com/domainr/whois" +) + +// Adapter for whois.net.vn +type vnAdapter struct{} + +func (a *vnAdapter) Prepare(req *whois.Request) error { + req.URL = generateVnWhoisRequestUrl(req.Query) + // Override request body to avoid any conflict. + req.Body = nil + + return nil +} + +func (a *vnAdapter) Text(res *whois.Response) ([]byte, error) { + return parseVnWhoisResponseBody(res.Body), nil +} + +func init() { + whois.BindAdapter( + &vnAdapter{}, + "whois.net.vn", + ) +} + +// Generate URL for .vn whois request. +// Query sent to whois.net.vn should go to `/whois.php` route with `act` & `domain` parameters. +func generateVnWhoisRequestUrl(query string) string { + whoisEndpoint := "https://whois.net.vn/whois.php?" + + whoisQueryParams := url.Values{} + whoisQueryParams.Set("act", "getwhois") + whoisQueryParams.Set("domain", query) + + return whoisEndpoint + whoisQueryParams.Encode() +} + +// Remove HTML Tags, tab characters, exceeding spaces, correct some keys and generate a registar field +// to avoid parsing errors in later step. +func parseVnWhoisResponseBody(bodyContent []byte) []byte { + htmlTags := []string{"
", "
", "
"} + + resBodyString := string(bodyContent) + + // Remove HTML tag (
,
). + for _, htmlTag := range htmlTags { + resBodyString = strings.ReplaceAll(resBodyString, htmlTag, "") + } + + // Remove tab characters. + resBodyString = strings.ReplaceAll(resBodyString, "\t", "") + + // Remove exceeding spaces & correct some keys in response. + resBodyString = strings.ReplaceAll(resBodyString, "Expired Date : ", "Expire Date:") + resBodyString = strings.ReplaceAll(resBodyString, "Issue Date : ", "Issue Date:") + + // Generate Registrar field. + resBodyString = "Registrar WHOIS Server: Not available" + resBodyString + + return []byte(resBodyString) +} diff --git a/internal/whois/whois.go b/internal/whois/whois.go index de890ac..e0cdd73 100644 --- a/internal/whois/whois.go +++ b/internal/whois/whois.go @@ -124,7 +124,12 @@ func (c whoisClient) request(ctx context.Context, domain, host string) (string, if err != nil { return "", fmt.Errorf("failed to fetch whois request: %w", err) } - body := string(resp.Body) + respText, err := resp.Text() + if err != nil { + return "", fmt.Errorf("failed to parse response body into text: %w", err) + } + + body := string(respText) if host == "" { // do not recurse diff --git a/internal/whois/whois_test.go b/internal/whois/whois_test.go index 8ff6f62..1188050 100644 --- a/internal/whois/whois_test.go +++ b/internal/whois/whois_test.go @@ -40,13 +40,14 @@ func TestWhoisParsing(t *testing.T) { {domain: "GOOGLE.RS", host: "", err: ""}, {domain: "google.co.th", host: "", err: ""}, {domain: "google.fi", host: "", err: ""}, + {domain: "google.vn", host: "whois.net.vn", err: ""}, } { tt := tt t.Run(tt.domain, func(t *testing.T) { t.Parallel() is := is.New(t) - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) t.Cleanup(cancel) expiry, err := NewClient().ExpireTime(ctx, tt.domain, tt.host)