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)