mirror of
https://github.com/Myzel394/config-lsp.git
synced 2025-06-19 07:25:27 +02:00
feat(hosts): Add resolver analyzation
This commit is contained in:
parent
4fe2f46b1b
commit
960f365bc9
@ -3,6 +3,7 @@ package docvalues
|
||||
import (
|
||||
"config-lsp/utils"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -173,3 +174,9 @@ func SingleEnumValue(value string) EnumValue {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func DomainValue() Value {
|
||||
return RegexValue{
|
||||
Regex: *regexp.MustCompile(`^.+?\..+$`),
|
||||
}
|
||||
}
|
||||
|
10
handlers/hosts/fields/documentation-fields.go
Normal file
10
handlers/hosts/fields/documentation-fields.go
Normal file
@ -0,0 +1,10 @@
|
||||
package fields
|
||||
|
||||
import docvalues "config-lsp/doc-values"
|
||||
|
||||
var IPAddressField = docvalues.IPAddressValue{
|
||||
AllowIPv4: true,
|
||||
AllowIPv6: true,
|
||||
}
|
||||
|
||||
var HostnameField = docvalues.DomainValue()
|
93
handlers/hosts/handlers/analyzer.go
Normal file
93
handlers/hosts/handlers/analyzer.go
Normal file
@ -0,0 +1,93 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"config-lsp/common"
|
||||
"config-lsp/handlers/hosts/tree"
|
||||
"config-lsp/utils"
|
||||
"net"
|
||||
)
|
||||
|
||||
type ResolverEntry struct {
|
||||
IPv4Address net.IP
|
||||
IPv6Address net.IP
|
||||
Line uint32
|
||||
}
|
||||
|
||||
type Resolver struct {
|
||||
Entries map[string]ResolverEntry
|
||||
}
|
||||
|
||||
func createEntry(
|
||||
line uint32,
|
||||
ip net.IP,
|
||||
) ResolverEntry {
|
||||
entry := ResolverEntry{
|
||||
Line: line,
|
||||
}
|
||||
|
||||
if ipv4 := ip.To4(); ipv4 != nil {
|
||||
entry.IPv4Address = ipv4
|
||||
} else if ipv6 := ip.To16(); ipv6 != nil {
|
||||
entry.IPv6Address = ipv6
|
||||
}
|
||||
|
||||
return entry
|
||||
}
|
||||
|
||||
type hostnameEntry struct {
|
||||
Location common.LocationRange
|
||||
HostName string
|
||||
}
|
||||
|
||||
func CreateResolverFromParser(p tree.HostsParser) (Resolver, []common.LSPError) {
|
||||
errors := make([]common.LSPError, 0)
|
||||
resolver := Resolver{
|
||||
Entries: make(map[string]ResolverEntry),
|
||||
}
|
||||
|
||||
for lineNumber, entry := range p.Tree.Entries {
|
||||
if entry.IPAddress != nil && entry.Hostname != nil {
|
||||
hostNames := append(
|
||||
[]hostnameEntry{
|
||||
{
|
||||
Location: entry.Hostname.Location,
|
||||
HostName: entry.Hostname.Value,
|
||||
},
|
||||
},
|
||||
utils.Map(
|
||||
entry.Aliases,
|
||||
func(alias *tree.HostsHostname) hostnameEntry {
|
||||
return hostnameEntry{
|
||||
Location: alias.Location,
|
||||
HostName: alias.Value,
|
||||
}
|
||||
},
|
||||
)...,
|
||||
)
|
||||
|
||||
for _, hostName := range hostNames {
|
||||
entry := createEntry(
|
||||
lineNumber,
|
||||
entry.IPAddress.Value.IP,
|
||||
)
|
||||
|
||||
if resolv, found := resolver.Entries[hostName.HostName]; found {
|
||||
errors = append(
|
||||
errors,
|
||||
common.LSPError{
|
||||
Range: hostName.Location,
|
||||
Err: DuplicateHostEntry{
|
||||
AlreadyFoundAt: resolv.Line,
|
||||
Hostname: hostName.HostName,
|
||||
},
|
||||
},
|
||||
)
|
||||
} else {
|
||||
resolver.Entries[hostName.HostName] = entry
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resolver, errors
|
||||
}
|
117
handlers/hosts/handlers/analyzer_test.go
Normal file
117
handlers/hosts/handlers/analyzer_test.go
Normal file
@ -0,0 +1,117 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"config-lsp/handlers/hosts/tree"
|
||||
"config-lsp/utils"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestResolverEntriesWorksWithNonOverlapping(
|
||||
t *testing.T,
|
||||
) {
|
||||
input := utils.Dedent(`
|
||||
1.2.3.4 hello.com
|
||||
5.5.5.5 world.com
|
||||
`)
|
||||
|
||||
parser := tree.CreateNewHostsParser()
|
||||
errors := parser.Parse(input)
|
||||
|
||||
if len(errors) != 0 {
|
||||
t.Fatalf("PARER FAILED! Expected no errors, but got %v", errors)
|
||||
}
|
||||
|
||||
resolver, errors := CreateResolverFromParser(parser)
|
||||
|
||||
if len(errors) != 0 {
|
||||
t.Errorf("Expected no errors, but got %v", errors)
|
||||
}
|
||||
|
||||
if len(resolver.Entries) != 2 {
|
||||
t.Errorf("Expected 2 entries, but got %v", len(resolver.Entries))
|
||||
}
|
||||
|
||||
if !(resolver.Entries["hello.com"].IPv4Address.String() == "1.2.3.4") {
|
||||
t.Errorf("Expected hello.com to be 1.2.3.4, but got %v", resolver.Entries["hello.com"].IPv4Address)
|
||||
}
|
||||
|
||||
if !(resolver.Entries["world.com"].IPv4Address.String() == "5.5.5.5") {
|
||||
t.Errorf("Expected world.com to be 5.5.5.5, but got %v", resolver.Entries["world.com"].IPv4Address)
|
||||
}
|
||||
|
||||
if !(resolver.Entries["hello.com"].IPv6Address == nil) {
|
||||
t.Errorf("Expected hello.com to have no IPv6 address, but got %v", resolver.Entries["hello.com"].IPv6Address)
|
||||
}
|
||||
|
||||
if !(resolver.Entries["world.com"].IPv6Address == nil) {
|
||||
t.Errorf("Expected world.com to have no IPv6 address, but got %v", resolver.Entries["world.com"].IPv6Address)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolverEntriesWithSimpleOverlapping(
|
||||
t *testing.T,
|
||||
) {
|
||||
input := utils.Dedent(`
|
||||
1.2.3.4 hello.com
|
||||
5.5.5.5 hello.com
|
||||
`)
|
||||
|
||||
parser := tree.CreateNewHostsParser()
|
||||
errors := parser.Parse(input)
|
||||
|
||||
if len(errors) != 0 {
|
||||
t.Fatalf("PARER FAILED! Expected no errors, but got %v", errors)
|
||||
}
|
||||
|
||||
resolver, errors := CreateResolverFromParser(parser)
|
||||
|
||||
if !(len(errors) == 1) {
|
||||
t.Errorf("Expected 1 error, but got %v", len(errors))
|
||||
}
|
||||
|
||||
if len(resolver.Entries) != 1 {
|
||||
t.Errorf("Expected 1 entry, but got %v", len(resolver.Entries))
|
||||
}
|
||||
|
||||
if !(resolver.Entries["hello.com"].IPv4Address.String() == "1.2.3.4") {
|
||||
t.Errorf("Expected hello.com to be 1.2.3.4, but got %v", resolver.Entries["hello.com"].IPv4Address)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolverEntriesWithComplexOverlapping(
|
||||
t *testing.T,
|
||||
) {
|
||||
input := utils.Dedent(`
|
||||
1.2.3.4 hello.com test.com
|
||||
5.5.5.5 check.com test.com
|
||||
`)
|
||||
|
||||
parser := tree.CreateNewHostsParser()
|
||||
errors := parser.Parse(input)
|
||||
|
||||
if len(errors) != 0 {
|
||||
t.Fatalf("PARER FAILED! Expected no errors, but got %v", errors)
|
||||
}
|
||||
|
||||
resolver, errors := CreateResolverFromParser(parser)
|
||||
|
||||
if !(len(errors) == 1) {
|
||||
t.Errorf("Expected 1 error, but got %v", len(errors))
|
||||
}
|
||||
|
||||
if len(resolver.Entries) != 3 {
|
||||
t.Errorf("Expected 3 entries, but got %v", len(resolver.Entries))
|
||||
}
|
||||
|
||||
if !(resolver.Entries["hello.com"].IPv4Address.String() == "1.2.3.4") {
|
||||
t.Errorf("Expected hello.com to be 1.2.3.4, but got %v", resolver.Entries["hello.com"].IPv4Address)
|
||||
}
|
||||
|
||||
if !(resolver.Entries["check.com"].IPv4Address.String() == "5.5.5.5") {
|
||||
t.Errorf("Expected check.com to be 5.5.5.5, but got %v", resolver.Entries["check.com"].IPv4Address)
|
||||
}
|
||||
|
||||
if !(resolver.Entries["test.com"].IPv4Address.String() == "1.2.3.4") {
|
||||
t.Errorf("Expected test.com to have no IPv4 address, but got %v", resolver.Entries["test.com"].IPv4Address)
|
||||
}
|
||||
}
|
12
handlers/hosts/handlers/errors.go
Normal file
12
handlers/hosts/handlers/errors.go
Normal file
@ -0,0 +1,12 @@
|
||||
package handlers
|
||||
|
||||
import "fmt"
|
||||
|
||||
type DuplicateHostEntry struct {
|
||||
AlreadyFoundAt uint32
|
||||
Hostname string
|
||||
}
|
||||
|
||||
func (d DuplicateHostEntry) Error() string {
|
||||
return fmt.Sprintf("'%s' already defined on line %d", d.Hostname, d.AlreadyFoundAt)
|
||||
}
|
@ -2,6 +2,7 @@ package tree
|
||||
|
||||
import (
|
||||
"config-lsp/utils"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -27,7 +28,7 @@ func TestValidSimpleExampleWorks(
|
||||
t.Errorf("Expected IP address to be present, but got nil")
|
||||
}
|
||||
|
||||
if !(parser.Tree.Entries[1].IPAddress.Value == "1.2.3.4") {
|
||||
if !(parser.Tree.Entries[1].IPAddress.Value.String() == net.ParseIP("1.2.3.4").String()) {
|
||||
t.Errorf("Expected IP address to be 1.2.3.4, but got %v", parser.Tree.Entries[1].IPAddress.Value)
|
||||
}
|
||||
|
||||
@ -94,7 +95,7 @@ func TestValidComplexExampleWorks(
|
||||
t.Errorf("Expected IP address to be present, but got nil")
|
||||
}
|
||||
|
||||
if !(parser.Tree.Entries[3].IPAddress.Value == "1.2.3.4") {
|
||||
if !(parser.Tree.Entries[3].IPAddress.Value.String() == net.ParseIP("1.2.3.4").String()) {
|
||||
t.Errorf("Expected IP address to be 1.2.3.4, but got %v", parser.Tree.Entries[2].IPAddress.Value)
|
||||
}
|
||||
|
||||
@ -129,7 +130,7 @@ func TestInvalidExampleWorks(
|
||||
t.Errorf("Expected no comment lines, but got %v", len(parser.CommentLines))
|
||||
}
|
||||
|
||||
if !(parser.Tree.Entries[1].IPAddress.Value == "1.2.3.4") {
|
||||
if !(parser.Tree.Entries[1].IPAddress.Value.String() == net.ParseIP("1.2.3.4").String()) {
|
||||
t.Errorf("Expected IP address to be nil, but got %v", parser.Tree.Entries[1].IPAddress)
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ package tree
|
||||
import (
|
||||
"config-lsp/common"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/antlr4-go/antlr/v4"
|
||||
)
|
||||
@ -48,7 +49,7 @@ func (p HostsEntry) String() string {
|
||||
str := fmt.Sprintf("HostsEntry(%v)", p.Location)
|
||||
|
||||
if p.IPAddress != nil {
|
||||
str += " " + p.IPAddress.Value
|
||||
str += " " + p.IPAddress.Value.String()
|
||||
}
|
||||
|
||||
if p.Hostname != nil {
|
||||
@ -64,7 +65,7 @@ func (p HostsEntry) String() string {
|
||||
|
||||
type HostsIPAddress struct {
|
||||
Location common.LocationRange
|
||||
Value string
|
||||
Value net.IPAddr
|
||||
}
|
||||
|
||||
type HostsHostname struct {
|
||||
|
@ -2,7 +2,9 @@ package tree
|
||||
|
||||
import (
|
||||
"config-lsp/common"
|
||||
docvalues "config-lsp/doc-values"
|
||||
"config-lsp/handlers/hosts/parser"
|
||||
"net"
|
||||
|
||||
"github.com/antlr4-go/antlr/v4"
|
||||
)
|
||||
@ -14,6 +16,7 @@ type hostsListenerContext struct {
|
||||
type hostsParserListener struct {
|
||||
*parser.BaseHostsListener
|
||||
Parser *HostsParser
|
||||
Errors []common.LSPError
|
||||
hostsContext hostsListenerContext
|
||||
}
|
||||
|
||||
@ -35,11 +38,30 @@ func (s *hostsParserListener) EnterIpAddress(ctx *parser.IpAddressContext) {
|
||||
location := characterRangeFromCtx(ctx.BaseParserRuleContext)
|
||||
location.ChangeBothLines(s.hostsContext.line)
|
||||
|
||||
ip := net.ParseIP(ctx.GetText())
|
||||
|
||||
if ip == nil {
|
||||
s.Errors = append(s.Errors, common.LSPError{
|
||||
Range: location,
|
||||
Err: docvalues.InvalidIPAddress{},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ipAddr, err := net.ResolveIPAddr("ip", ip.String())
|
||||
|
||||
if err != nil {
|
||||
s.Errors = append(s.Errors, common.LSPError{
|
||||
Range: location,
|
||||
Err: docvalues.InvalidIPAddress{},
|
||||
})
|
||||
}
|
||||
|
||||
entry := s.Parser.Tree.Entries[location.Start.Line]
|
||||
|
||||
entry.IPAddress = &HostsIPAddress{
|
||||
Location: location,
|
||||
Value: ctx.GetText(),
|
||||
Value: *ipAddr,
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,6 +113,7 @@ func createHostsFileListener(
|
||||
hostsContext: hostsListenerContext{
|
||||
line: line,
|
||||
},
|
||||
Errors: make([]common.LSPError, 0),
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user