Skip to content

Commit

Permalink
use Options pattern for creating Client instance
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrej.benkovsky committed Oct 27, 2024
1 parent 5df5b91 commit bcfa858
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 31 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ go get github.com/tantalor93/doh-go

## Examples
```
// create client with default http.Client
c := doh.NewClient(nil)
// create client with default settings
c := doh.NewClient()
// prepare payload
msg := dns.Msg{}
Expand Down
21 changes: 12 additions & 9 deletions doh/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,21 @@ import (

// Client encapsulates and provides logic for querying DNS servers over DoH.
type Client struct {
c *http.Client
client *http.Client
}

// NewClient creates new Client instance with standard net/http client. If nil, default http.Client is used.
func NewClient(c *http.Client) *Client {
if c == nil {
c = &http.Client{}
// NewClient creates new Client instance with standard net/http client.
func NewClient(opts ...Option) *Client {
client := &Client{
client: &http.Client{},
}
return &Client{c}
for _, opt := range opts {
opt.apply(client)
}
return client
}

// SendViaPost sends DNS message to the given DNS server over DoH using POST, see https://datatracker.ietf.org/doc/html/rfc8484#section-4.1
// SendViaPost sends DNS message to the given DNS server over DoH using POST method, see https://datatracker.ietf.org/doc/html/rfc8484#section-4.1
func (dc *Client) SendViaPost(ctx context.Context, server string, msg *dns.Msg) (*dns.Msg, error) {
pack, err := msg.Pack()
if err != nil {
Expand All @@ -41,7 +44,7 @@ func (dc *Client) SendViaPost(ctx context.Context, server string, msg *dns.Msg)
return dc.send(request)
}

// SendViaGet sends DNS message to the given DNS server over DoH using GET, see https://datatracker.ietf.org/doc/html/rfc8484#section-4.1
// SendViaGet sends DNS message to the given DNS server over DoH using GET method, see https://datatracker.ietf.org/doc/html/rfc8484#section-4.1
func (dc *Client) SendViaGet(ctx context.Context, server string, msg *dns.Msg) (*dns.Msg, error) {
pack, err := msg.Pack()
if err != nil {
Expand All @@ -60,7 +63,7 @@ func (dc *Client) SendViaGet(ctx context.Context, server string, msg *dns.Msg) (
}

func (dc *Client) send(r *http.Request) (*dns.Msg, error) {
resp, err := dc.c.Do(r)
resp, err := dc.client.Do(r)
if err != nil {
return nil, err
}
Expand Down
32 changes: 12 additions & 20 deletions doh/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,37 +58,33 @@ func Test_SendViaPost(t *testing.T) {
}))
defer ts.Close()

type args struct {
server string
msg *dns.Msg
}
tests := []struct {
name string
args args
msg *dns.Msg
wantRcode int
wantErr error
}{
{
name: "NOERROR DNS resolution",
args: args{server: ts.URL, msg: question(existingDomain)},
msg: question(existingDomain),
wantRcode: dns.RcodeSuccess,
},
{
name: "NXDOMAIN DNS resolution",
args: args{server: ts.URL, msg: question(notExistingDomain)},
msg: question(notExistingDomain),
wantRcode: dns.RcodeNameError,
},
{
name: "bad upstream HTTP response",
args: args{server: ts.URL, msg: question(badStatusDomain)},
msg: question(badStatusDomain),
wantErr: &doh.UnexpectedServerHTTPStatusError{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
client := doh.NewClient(nil)
client := doh.NewClient()

got, err := client.SendViaPost(context.Background(), tt.args.server, tt.args.msg)
got, err := client.SendViaPost(context.Background(), ts.URL, tt.msg)

if tt.wantErr != nil {
require.ErrorAs(t, err, tt.wantErr, "SendViaPost() error")
Expand Down Expand Up @@ -142,37 +138,33 @@ func Test_SendViaGet(t *testing.T) {
}))
defer ts.Close()

type args struct {
server string
msg *dns.Msg
}
tests := []struct {
name string
args args
msg *dns.Msg
wantRcode int
wantErr error
}{
{
name: "NOERROR DNS resolution",
args: args{server: ts.URL, msg: question(existingDomain)},
msg: question(existingDomain),
wantRcode: dns.RcodeSuccess,
},
{
name: "NXDOMAIN DNS resolution",
args: args{server: ts.URL, msg: question(notExistingDomain)},
msg: question(existingDomain),
wantRcode: dns.RcodeNameError,
},
{
name: "bad upstream HTTP response",
args: args{server: ts.URL, msg: question(badStatusDomain)},
msg: question(badStatusDomain),
wantErr: &doh.UnexpectedServerHTTPStatusError{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
client := doh.NewClient(nil)
client := doh.NewClient()

got, err := client.SendViaGet(context.Background(), tt.args.server, tt.args.msg)
got, err := client.SendViaGet(context.Background(), ts.URL, tt.msg)

if tt.wantErr != nil {
require.ErrorAs(t, err, tt.wantErr, "SendViaPost() error")
Expand Down
23 changes: 23 additions & 0 deletions doh/opts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package doh

import "net/http"

// Option represents configuration options for doh.Client.
type Option interface {
apply(c *Client)
}

type httpClientOption struct {
client *http.Client
}

func (o *httpClientOption) apply(c *Client) {
c.client = o.client
}

// WithHTTPClient is a configuration option that overrides default http.Client instance used by the doh.Client.
func WithHTTPClient(c *http.Client) Option {
return &httpClientOption{
client: c,
}
}

0 comments on commit bcfa858

Please sign in to comment.