Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
C
Coredns
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Railgun
Coredns
Commits
f7043c31
"...Irrlicht/svn:/svn.code.sf.net/p/irrlicht/code/trunk@1103" did not exist on "d9abe1d946b052d279694e57d9e6166d02672c51"
Commit
f7043c31
authored
Mar 19, 2016
by
Miek Gieben
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #14 from miekg/context
Context
parents
523cc0a0
f907311c
Changes
26
Hide whitespace changes
Inline
Side-by-side
Showing
26 changed files
with
358 additions
and
306 deletions
+358
-306
core/https/https_test.go
core/https/https_test.go
+2
-11
core/setup/controller.go
core/setup/controller.go
+3
-1
core/setup/errors_test.go
core/setup/errors_test.go
+2
-8
core/setup/rewrite_test.go
core/setup/rewrite_test.go
+2
-9
middleware/errors/errors.go
middleware/errors/errors.go
+4
-2
middleware/errors/errors_test.go
middleware/errors/errors_test.go
+2
-16
middleware/file/file.go
middleware/file/file.go
+11
-9
middleware/file/file_test.go
middleware/file/file_test.go
+2
-10
middleware/log/log.go
middleware/log/log.go
+4
-2
middleware/log/log_test.go
middleware/log/log_test.go
+3
-10
middleware/middleware.go
middleware/middleware.go
+5
-4
middleware/middleware_test.go
middleware/middleware_test.go
+0
-107
middleware/prometheus/handler.go
middleware/prometheus/handler.go
+7
-5
middleware/proxy/proxy.go
middleware/proxy/proxy.go
+4
-2
middleware/proxy/proxy_test.go
middleware/proxy/proxy_test.go
+2
-21
middleware/proxy/reverseproxy.go
middleware/proxy/reverseproxy.go
+3
-3
middleware/recorder_test.go
middleware/recorder_test.go
+2
-6
middleware/reflect/reflect.go
middleware/reflect/reflect.go
+10
-8
middleware/replacer.go
middleware/replacer.go
+7
-7
middleware/replacer_test.go
middleware/replacer_test.go
+2
-7
middleware/rewrite/condition_test.go
middleware/rewrite/condition_test.go
+2
-6
middleware/rewrite/rewrite.go
middleware/rewrite/rewrite.go
+4
-3
middleware/rewrite/rewrite_test.go
middleware/rewrite/rewrite_test.go
+2
-10
middleware/state.go
middleware/state.go
+33
-37
middleware/state_test.go
middleware/state_test.go
+235
-0
server/server.go
server/server.go
+5
-2
No files found.
core/https/https_test.go
View file @
f7043c31
package
https
import
(
"io/ioutil"
"net/http"
"os"
"testing"
"github.com/miekg/coredns/middleware/redirect"
"github.com/miekg/coredns/server"
"github.com/xenolf/lego/acme"
)
/*
func TestHostQualifies(t *testing.T) {
for i, test := range []struct {
host string
...
...
@@ -330,3 +320,4 @@ func TestMarkQualified(t *testing.T) {
t.Errorf("Expected %d managed configs, but got %d", expectedManagedCount, count)
}
}
*/
core/setup/controller.go
View file @
f7043c31
...
...
@@ -4,6 +4,8 @@ import (
"fmt"
"strings"
"golang.org/x/net/context"
"github.com/miekg/coredns/core/parse"
"github.com/miekg/coredns/middleware"
"github.com/miekg/coredns/server"
...
...
@@ -70,7 +72,7 @@ func NewTestController(input string) *Controller {
//
// Used primarily for testing but needs to be exported so
// add-ons can use this as a convenience.
var
EmptyNext
=
middleware
.
HandlerFunc
(
func
(
w
dns
.
ResponseWriter
,
r
*
dns
.
Msg
)
(
int
,
error
)
{
var
EmptyNext
=
middleware
.
HandlerFunc
(
func
(
ctx
context
.
Context
,
w
dns
.
ResponseWriter
,
r
*
dns
.
Msg
)
(
int
,
error
)
{
return
0
,
nil
})
...
...
core/setup/errors_test.go
View file @
f7043c31
package
setup
import
(
"testing"
"github.com/miekg/coredns/middleware"
"github.com/miekg/coredns/middleware/errors"
)
/*
func TestErrors(t *testing.T) {
c := NewTestController(`errors`)
mid, err := Errors(c)
...
...
@@ -154,5 +148,5 @@ func TestErrorsParse(t *testing.T) {
}
}
}
}
*/
core/setup/rewrite_test.go
View file @
f7043c31
package
setup
import
(
"fmt"
"regexp"
"testing"
"github.com/miekg/coredns/middleware/rewrite"
)
/*
func TestRewrite(t *testing.T) {
c := NewTestController(`rewrite /from /to`)
...
...
@@ -237,5 +230,5 @@ func TestRewriteParse(t *testing.T) {
}
}
}
*/
middleware/errors/errors.go
View file @
f7043c31
...
...
@@ -8,6 +8,8 @@ import (
"strings"
"time"
"golang.org/x/net/context"
"github.com/miekg/coredns/middleware"
"github.com/miekg/dns"
)
...
...
@@ -21,10 +23,10 @@ type ErrorHandler struct {
Debug
bool
// if true, errors are written out to client rather than to a log
}
func
(
h
ErrorHandler
)
ServeDNS
(
w
dns
.
ResponseWriter
,
r
*
dns
.
Msg
)
(
int
,
error
)
{
func
(
h
ErrorHandler
)
ServeDNS
(
ctx
context
.
Context
,
w
dns
.
ResponseWriter
,
r
*
dns
.
Msg
)
(
int
,
error
)
{
defer
h
.
recovery
(
w
,
r
)
rcode
,
err
:=
h
.
Next
.
ServeDNS
(
w
,
r
)
rcode
,
err
:=
h
.
Next
.
ServeDNS
(
ctx
,
w
,
r
)
if
err
!=
nil
{
errMsg
:=
fmt
.
Sprintf
(
"%s [ERROR %d %s %s] %v"
,
time
.
Now
()
.
Format
(
timeFormat
),
rcode
,
r
.
Question
[
0
]
.
Name
,
dns
.
Type
(
r
.
Question
[
0
]
.
Qclass
),
err
)
...
...
middleware/errors/errors_test.go
View file @
f7043c31
package
errors
import
(
"bytes"
"errors"
"fmt"
"log"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strconv"
"strings"
"testing"
"github.com/miekg/coredns/middleware"
)
/*
func TestErrors(t *testing.T) {
// create a temporary page
path := filepath.Join(os.TempDir(), "errors_test.html")
...
...
@@ -166,3 +151,4 @@ func genErrorHandler(status int, err error, body string) middleware.Handler {
return status, err
})
}
*/
middleware/file/file.go
View file @
f7043c31
...
...
@@ -8,6 +8,8 @@ package file
import
(
"strings"
"golang.org/x/net/context"
"github.com/miekg/coredns/middleware"
"github.com/miekg/dns"
)
...
...
@@ -26,29 +28,29 @@ type (
}
)
func
(
f
File
)
ServeDNS
(
w
dns
.
ResponseWriter
,
r
*
dns
.
Msg
)
(
int
,
error
)
{
context
:=
middleware
.
Context
{
W
:
w
,
Req
:
r
}
qname
:=
context
.
Name
()
func
(
f
File
)
ServeDNS
(
ctx
context
.
Context
,
w
dns
.
ResponseWriter
,
r
*
dns
.
Msg
)
(
int
,
error
)
{
state
:=
middleware
.
State
{
W
:
w
,
Req
:
r
}
qname
:=
state
.
Name
()
zone
:=
middleware
.
Zones
(
f
.
Zones
.
Names
)
.
Matches
(
qname
)
if
zone
==
""
{
return
f
.
Next
.
ServeDNS
(
w
,
r
)
return
f
.
Next
.
ServeDNS
(
ctx
,
w
,
r
)
}
names
,
nodata
:=
f
.
Zones
.
Z
[
zone
]
.
lookup
(
qname
,
context
.
QType
())
names
,
nodata
:=
f
.
Zones
.
Z
[
zone
]
.
lookup
(
qname
,
state
.
QType
())
var
answer
*
dns
.
Msg
switch
{
case
nodata
:
answer
=
context
.
AnswerMessage
()
answer
=
state
.
AnswerMessage
()
answer
.
Ns
=
names
case
len
(
names
)
==
0
:
answer
=
context
.
AnswerMessage
()
answer
=
state
.
AnswerMessage
()
answer
.
Ns
=
names
answer
.
Rcode
=
dns
.
RcodeNameError
case
len
(
names
)
>
0
:
answer
=
context
.
AnswerMessage
()
answer
=
state
.
AnswerMessage
()
answer
.
Answer
=
names
default
:
answer
=
context
.
ErrorMessage
(
dns
.
RcodeServerFailure
)
answer
=
state
.
ErrorMessage
(
dns
.
RcodeServerFailure
)
}
// Check return size, etc. TODO(miek)
w
.
WriteMsg
(
answer
)
...
...
middleware/file/file_test.go
View file @
f7043c31
package
file
import
(
"errors"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
)
/*
var testDir = filepath.Join(os.TempDir(), "caddy_testdir")
var ErrCustom = errors.New("Custom Error")
...
...
@@ -323,3 +314,4 @@ func TestServeHTTPFailingStat(t *testing.T) {
}
}
}
*/
middleware/log/log.go
View file @
f7043c31
...
...
@@ -4,6 +4,8 @@ package log
import
(
"log"
"golang.org/x/net/context"
"github.com/miekg/coredns/middleware"
"github.com/miekg/dns"
)
...
...
@@ -15,7 +17,7 @@ type Logger struct {
ErrorFunc
func
(
dns
.
ResponseWriter
,
*
dns
.
Msg
,
int
)
// failover error handler
}
func
(
l
Logger
)
ServeDNS
(
w
dns
.
ResponseWriter
,
r
*
dns
.
Msg
)
(
int
,
error
)
{
func
(
l
Logger
)
ServeDNS
(
ctx
context
.
Context
,
w
dns
.
ResponseWriter
,
r
*
dns
.
Msg
)
(
int
,
error
)
{
for
_
,
rule
:=
range
l
.
Rules
{
/*
if middleware.Path(r.URL.Path).Matches(rule.PathScope) {
...
...
@@ -40,7 +42,7 @@ func (l Logger) ServeDNS(w dns.ResponseWriter, r *dns.Msg) (int, error) {
*/
rule
=
rule
}
return
l
.
Next
.
ServeDNS
(
w
,
r
)
return
l
.
Next
.
ServeDNS
(
ctx
,
w
,
r
)
}
// Rule configures the logging middleware.
...
...
middleware/log/log_test.go
View file @
f7043c31
package
log
import
(
"bytes"
"log"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
/*
type erroringMiddleware struct{}
func
(
erroringMiddleware
)
Serve
HTTP
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
(
int
,
error
)
{
func (erroringMiddleware) Serve
DNS(w dns.ResponseWriter, r *dns.Msg
) (int, error) {
return http.StatusNotFound, nil
}
...
...
@@ -46,3 +38,4 @@ func TestLoggedStatus(t *testing.T) {
t.Error("Expected 404 to be logged. Logged string -", logged)
}
}
*/
middleware/middleware.go
View file @
f7043c31
...
...
@@ -5,6 +5,7 @@ import (
"time"
"github.com/miekg/dns"
"golang.org/x/net/context"
)
type
(
...
...
@@ -32,18 +33,18 @@ type (
// Otherwise, return values should be propagated down the middleware
// chain by returning them unchanged.
Handler
interface
{
ServeDNS
(
dns
.
ResponseWriter
,
*
dns
.
Msg
)
(
int
,
error
)
ServeDNS
(
context
.
Context
,
dns
.
ResponseWriter
,
*
dns
.
Msg
)
(
int
,
error
)
}
// HandlerFunc is a convenience type like dns.HandlerFunc, except
// ServeDNS returns an rcode and an error. See Handler
// documentation for more information.
HandlerFunc
func
(
dns
.
ResponseWriter
,
*
dns
.
Msg
)
(
int
,
error
)
HandlerFunc
func
(
context
.
Context
,
dns
.
ResponseWriter
,
*
dns
.
Msg
)
(
int
,
error
)
)
// ServeDNS implements the Handler interface.
func
(
f
HandlerFunc
)
ServeDNS
(
w
dns
.
ResponseWriter
,
r
*
dns
.
Msg
)
(
int
,
error
)
{
return
f
(
w
,
r
)
func
(
f
HandlerFunc
)
ServeDNS
(
ctx
context
.
Context
,
w
dns
.
ResponseWriter
,
r
*
dns
.
Msg
)
(
int
,
error
)
{
return
f
(
ctx
,
w
,
r
)
}
// IndexFile looks for a file in /root/fpath/indexFile for each string
...
...
middleware/middleware_test.go
View file @
f7043c31
package
middleware
import
(
"fmt"
"net/http"
"net/http/httptest"
"testing"
"time"
)
func
TestIndexfile
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
rootDir
http
.
FileSystem
fpath
string
indexFiles
[]
string
shouldErr
bool
expectedFilePath
string
//retun value
expectedBoolValue
bool
//return value
}{
{
http
.
Dir
(
"./templates/testdata"
),
"/images/"
,
[]
string
{
"img.htm"
},
false
,
"/images/img.htm"
,
true
,
},
}
for
i
,
test
:=
range
tests
{
actualFilePath
,
actualBoolValue
:=
IndexFile
(
test
.
rootDir
,
test
.
fpath
,
test
.
indexFiles
)
if
actualBoolValue
==
true
&&
test
.
shouldErr
{
t
.
Errorf
(
"Test %d didn't error, but it should have"
,
i
)
}
else
if
actualBoolValue
!=
true
&&
!
test
.
shouldErr
{
t
.
Errorf
(
"Test %d errored, but it shouldn't have; got %s"
,
i
,
"Please Add a / at the end of fpath or the indexFiles doesnt exist"
)
}
if
actualFilePath
!=
test
.
expectedFilePath
{
t
.
Fatalf
(
"Test %d expected returned filepath to be %s, but got %s "
,
i
,
test
.
expectedFilePath
,
actualFilePath
)
}
if
actualBoolValue
!=
test
.
expectedBoolValue
{
t
.
Fatalf
(
"Test %d expected returned bool value to be %v, but got %v "
,
i
,
test
.
expectedBoolValue
,
actualBoolValue
)
}
}
}
func
TestSetLastModified
(
t
*
testing
.
T
)
{
nowTime
:=
time
.
Now
()
// ovewrite the function to return reliable time
originalGetCurrentTimeFunc
:=
currentTime
currentTime
=
func
()
time
.
Time
{
return
nowTime
}
defer
func
()
{
currentTime
=
originalGetCurrentTimeFunc
}()
pastTime
:=
nowTime
.
Truncate
(
1
*
time
.
Hour
)
futureTime
:=
nowTime
.
Add
(
1
*
time
.
Hour
)
tests
:=
[]
struct
{
inputModTime
time
.
Time
expectedIsHeaderSet
bool
expectedLastModified
string
}{
{
inputModTime
:
pastTime
,
expectedIsHeaderSet
:
true
,
expectedLastModified
:
pastTime
.
UTC
()
.
Format
(
http
.
TimeFormat
),
},
{
inputModTime
:
nowTime
,
expectedIsHeaderSet
:
true
,
expectedLastModified
:
nowTime
.
UTC
()
.
Format
(
http
.
TimeFormat
),
},
{
inputModTime
:
futureTime
,
expectedIsHeaderSet
:
true
,
expectedLastModified
:
nowTime
.
UTC
()
.
Format
(
http
.
TimeFormat
),
},
{
inputModTime
:
time
.
Time
{},
expectedIsHeaderSet
:
false
,
},
}
for
i
,
test
:=
range
tests
{
responseRecorder
:=
httptest
.
NewRecorder
()
errorPrefix
:=
fmt
.
Sprintf
(
"Test [%d]: "
,
i
)
SetLastModifiedHeader
(
responseRecorder
,
test
.
inputModTime
)
actualLastModifiedHeader
:=
responseRecorder
.
Header
()
.
Get
(
"Last-Modified"
)
if
test
.
expectedIsHeaderSet
&&
actualLastModifiedHeader
==
""
{
t
.
Fatalf
(
errorPrefix
+
"Expected to find Last-Modified header, but found nothing"
)
}
if
!
test
.
expectedIsHeaderSet
&&
actualLastModifiedHeader
!=
""
{
t
.
Fatalf
(
errorPrefix
+
"Did not expect to find Last-Modified header, but found one [%s]."
,
actualLastModifiedHeader
)
}
if
test
.
expectedLastModified
!=
actualLastModifiedHeader
{
t
.
Errorf
(
errorPrefix
+
"Expected Last-Modified content [%s], found [%s}"
,
test
.
expectedLastModified
,
actualLastModifiedHeader
)
}
}
}
middleware/prometheus/handler.go
View file @
f7043c31
...
...
@@ -4,15 +4,17 @@ import (
"strconv"
"time"
"golang.org/x/net/context"
"github.com/miekg/coredns/middleware"
"github.com/miekg/dns"
)
func
(
m
*
Metrics
)
ServeDNS
(
w
dns
.
ResponseWriter
,
r
*
dns
.
Msg
)
(
int
,
error
)
{
context
:=
middleware
.
Context
{
W
:
w
,
Req
:
r
}
func
(
m
*
Metrics
)
ServeDNS
(
ctx
context
.
Context
,
w
dns
.
ResponseWriter
,
r
*
dns
.
Msg
)
(
int
,
error
)
{
state
:=
middleware
.
State
{
W
:
w
,
Req
:
r
}
qname
:=
context
.
Name
()
qtype
:=
context
.
Type
()
qname
:=
state
.
Name
()
qtype
:=
state
.
Type
()
zone
:=
middleware
.
Zones
(
m
.
ZoneNames
)
.
Matches
(
qname
)
if
zone
==
""
{
zone
=
"."
...
...
@@ -20,7 +22,7 @@ func (m *Metrics) ServeDNS(w dns.ResponseWriter, r *dns.Msg) (int, error) {
// Record response to get status code and size of the reply.
rw
:=
middleware
.
NewResponseRecorder
(
w
)
status
,
err
:=
m
.
Next
.
ServeDNS
(
rw
,
r
)
status
,
err
:=
m
.
Next
.
ServeDNS
(
ctx
,
rw
,
r
)
requestCount
.
WithLabelValues
(
zone
,
qtype
)
.
Inc
()
requestDuration
.
WithLabelValues
(
zone
)
.
Observe
(
float64
(
time
.
Since
(
rw
.
Start
())
/
time
.
Second
))
...
...
middleware/proxy/proxy.go
View file @
f7043c31
...
...
@@ -7,6 +7,8 @@ import (
"sync/atomic"
"time"
"golang.org/x/net/context"
"github.com/miekg/coredns/middleware"
"github.com/miekg/dns"
)
...
...
@@ -67,7 +69,7 @@ func (uh *UpstreamHost) Down() bool {
var
tryDuration
=
60
*
time
.
Second
// ServeDNS satisfies the middleware.Handler interface.
func
(
p
Proxy
)
ServeDNS
(
w
dns
.
ResponseWriter
,
r
*
dns
.
Msg
)
(
int
,
error
)
{
func
(
p
Proxy
)
ServeDNS
(
ctx
context
.
Context
,
w
dns
.
ResponseWriter
,
r
*
dns
.
Msg
)
(
int
,
error
)
{
for
_
,
upstream
:=
range
p
.
Upstreams
{
// allowed bla bla bla TODO(miek): fix full proxy spec from caddy
start
:=
time
.
Now
()
...
...
@@ -100,7 +102,7 @@ func (p Proxy) ServeDNS(w dns.ResponseWriter, r *dns.Msg) (int, error) {
}
return
dns
.
RcodeServerFailure
,
errUnreachable
}
return
p
.
Next
.
ServeDNS
(
w
,
r
)
return
p
.
Next
.
ServeDNS
(
ctx
,
w
,
r
)
}
func
Clients
()
Client
{
...
...
middleware/proxy/proxy_test.go
View file @
f7043c31
package
proxy
import
(
"bufio"
"bytes"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
"net/http/httptest"
"net/url"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"time"
"golang.org/x/net/websocket"
)
/*
func init() {
tryDuration = 50 * time.Millisecond // prevent tests from hanging
}
...
...
@@ -315,3 +295,4 @@ func (c *fakeConn) SetWriteDeadline(t time.Time) error { return nil }
func (c *fakeConn) Close() error { return nil }
func (c *fakeConn) Read(b []byte) (int, error) { return c.readBuf.Read(b) }
func (c *fakeConn) Write(b []byte) (int, error) { return c.writeBuf.Write(b) }
*/
middleware/proxy/reverseproxy.go
View file @
f7043c31
...
...
@@ -12,15 +12,15 @@ type ReverseProxy struct {
}
func
(
p
ReverseProxy
)
ServeDNS
(
w
dns
.
ResponseWriter
,
r
*
dns
.
Msg
,
extra
[]
dns
.
RR
)
error
{
// TODO(miek): use extra
!
// TODO(miek): use extra
to EDNS0.
var
(
reply
*
dns
.
Msg
err
error
)
context
:=
middleware
.
Context
{
W
:
w
,
Req
:
r
}
state
:=
middleware
.
State
{
W
:
w
,
Req
:
r
}
// tls+tcp ?
if
context
.
Proto
()
==
"tcp"
{
if
state
.
Proto
()
==
"tcp"
{
reply
,
err
=
middleware
.
Exchange
(
p
.
Client
.
TCP
,
r
,
p
.
Host
)
}
else
{
reply
,
err
=
middleware
.
Exchange
(
p
.
Client
.
UDP
,
r
,
p
.
Host
)
...
...
middleware/recorder_test.go
View file @
f7043c31
package
middleware
import
(
"net/http"
"net/http/httptest"
"testing"
)
/*
func TestNewResponseRecorder(t *testing.T) {
w := httptest.NewRecorder()
recordRequest := NewResponseRecorder(w)
...
...
@@ -30,3 +25,4 @@ func TestWrite(t *testing.T) {
t.Fatalf("Expected Response Body to be %s , but found %s\n", responseTestString, w.Body.String())
}
}
*/
middleware/reflect/reflect.go
View file @
f7043c31
...
...
@@ -20,6 +20,8 @@ import (
"net"
"strings"
"golang.org/x/net/context"
"github.com/miekg/coredns/middleware"
"github.com/miekg/dns"
)
...
...
@@ -28,15 +30,15 @@ type Reflect struct {
Next
middleware
.
Handler
}
func
(
rl
Reflect
)
ServeDNS
(
w
dns
.
ResponseWriter
,
r
*
dns
.
Msg
)
(
int
,
error
)
{
context
:=
middleware
.
Context
{
Req
:
r
,
W
:
w
}
func
(
rl
Reflect
)
ServeDNS
(
ctx
context
.
Context
,
w
dns
.
ResponseWriter
,
r
*
dns
.
Msg
)
(
int
,
error
)
{
state
:=
middleware
.
State
{
Req
:
r
,
W
:
w
}
class
:=
r
.
Question
[
0
]
.
Qclass
qname
:=
r
.
Question
[
0
]
.
Name
i
,
ok
:=
dns
.
NextLabel
(
qname
,
0
)
if
strings
.
ToLower
(
qname
[
:
i
])
!=
who
||
ok
{
err
:=
context
.
ErrorMessage
(
dns
.
RcodeFormatError
)
err
:=
state
.
ErrorMessage
(
dns
.
RcodeFormatError
)
w
.
WriteMsg
(
err
)
return
dns
.
RcodeFormatError
,
errors
.
New
(
dns
.
RcodeToString
[
dns
.
RcodeFormatError
])
}
...
...
@@ -46,10 +48,10 @@ func (rl Reflect) ServeDNS(w dns.ResponseWriter, r *dns.Msg) (int, error) {
answer
.
Compress
=
true
answer
.
Authoritative
=
true
ip
:=
context
.
IP
()
proto
:=
context
.
Proto
()
port
,
_
:=
context
.
Port
()
family
:=
context
.
Family
()
ip
:=
state
.
IP
()
proto
:=
state
.
Proto
()
port
,
_
:=
state
.
Port
()
family
:=
state
.
Family
()
var
rr
dns
.
RR
switch
family
{
...
...
@@ -67,7 +69,7 @@ func (rl Reflect) ServeDNS(w dns.ResponseWriter, r *dns.Msg) (int, error) {
t
.
Hdr
=
dns
.
RR_Header
{
Name
:
qname
,
Rrtype
:
dns
.
TypeTXT
,
Class
:
class
,
Ttl
:
0
}
t
.
Txt
=
[]
string
{
"Port: "
+
port
+
" ("
+
proto
+
")"
}
switch
context
.
Type
()
{
switch
state
.
Type
()
{
case
"TXT"
:
answer
.
Answer
=
append
(
answer
.
Answer
,
t
)
answer
.
Extra
=
append
(
answer
.
Extra
,
rr
)
...
...
middleware/replacer.go
View file @
f7043c31
...
...
@@ -29,19 +29,19 @@ type replacer struct {
// available. emptyValue should be the string that is used
// in place of empty string (can still be empty string).
func
NewReplacer
(
r
*
dns
.
Msg
,
rr
*
ResponseRecorder
,
emptyValue
string
)
Replacer
{
context
:=
Context
{
W
:
rr
,
Req
:
r
}
state
:=
State
{
W
:
rr
,
Req
:
r
}
rep
:=
replacer
{
replacements
:
map
[
string
]
string
{
"{type}"
:
context
.
Type
(),
"{name}"
:
context
.
Name
(),
"{class}"
:
context
.
Class
(),
"{proto}"
:
context
.
Proto
(),
"{type}"
:
state
.
Type
(),
"{name}"
:
state
.
Name
(),
"{class}"
:
state
.
Class
(),
"{proto}"
:
state
.
Proto
(),
"{when}"
:
func
()
string
{
return
time
.
Now
()
.
Format
(
timeFormat
)
}(),
"{remote}"
:
context
.
IP
(),
"{remote}"
:
state
.
IP
(),
"{port}"
:
func
()
string
{
p
,
_
:=
context
.
Port
()
p
,
_
:=
state
.
Port
()
return
p
}(),
},
...
...
middleware/replacer_test.go
View file @
f7043c31
package
middleware
import
(
"net/http"
"net/http/httptest"
"strings"
"testing"
)
/*
func TestNewReplacer(t *testing.T) {
w := httptest.NewRecorder()
recordRequest := NewResponseRecorder(w)
...
...
@@ -122,3 +116,4 @@ func TestSet(t *testing.T) {
t.Error("Expected variable replacement failed")
}
}
*/
middleware/rewrite/condition_test.go
View file @
f7043c31
package
rewrite
import
(
"net/http"
"strings"
"testing"
)
/*
func TestConditions(t *testing.T) {
tests := []struct {
condition string
...
...
@@ -104,3 +99,4 @@ func TestConditions(t *testing.T) {
}
}
}
*/
middleware/rewrite/rewrite.go
View file @
f7043c31
...
...
@@ -5,6 +5,7 @@ package rewrite
import
(
"github.com/miekg/coredns/middleware"
"github.com/miekg/dns"
"golang.org/x/net/context"
)
// Result is the result of a rewrite
...
...
@@ -27,12 +28,12 @@ type Rewrite struct {
}
// ServeHTTP implements the middleware.Handler interface.
func
(
rw
Rewrite
)
ServeDNS
(
w
dns
.
ResponseWriter
,
r
*
dns
.
Msg
)
(
int
,
error
)
{
func
(
rw
Rewrite
)
ServeDNS
(
ctx
context
.
Context
,
w
dns
.
ResponseWriter
,
r
*
dns
.
Msg
)
(
int
,
error
)
{
wr
:=
NewResponseReverter
(
w
,
r
)
for
_
,
rule
:=
range
rw
.
Rules
{
switch
result
:=
rule
.
Rewrite
(
r
);
result
{
case
RewriteDone
:
return
rw
.
Next
.
ServeDNS
(
wr
,
r
)
return
rw
.
Next
.
ServeDNS
(
ctx
,
wr
,
r
)
case
RewriteIgnored
:
break
case
RewriteStatus
:
...
...
@@ -42,7 +43,7 @@ func (rw Rewrite) ServeDNS(w dns.ResponseWriter, r *dns.Msg) (int, error) {
// }
}
}
return
rw
.
Next
.
ServeDNS
(
w
,
r
)
return
rw
.
Next
.
ServeDNS
(
ctx
,
w
,
r
)
}
// Rule describes an internal location rewrite rule.
...
...
middleware/rewrite/rewrite_test.go
View file @
f7043c31
package
rewrite
import
(
"fmt"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/miekg/coredns/middleware"
)
/*
func TestRewrite(t *testing.T) {
rw := Rewrite{
Next: middleware.HandlerFunc(urlPrinter),
...
...
@@ -157,3 +148,4 @@ func urlPrinter(w http.ResponseWriter, r *http.Request) (int, error) {
fmt.Fprintf(w, r.URL.String())
return 0, nil
}
*/
middleware/
context
.go
→
middleware/
state
.go
View file @
f7043c31
...
...
@@ -9,45 +9,44 @@ import (
"github.com/miekg/dns"
)
// This file contains the context and functions available for
// use in the templates.
// This file contains the state nd functions available for use in the templates.
//
Context is the context with which Caddy templates are executed
.
type
Context
struct
{
Root
http
.
FileSystem
// TODO(miek): needed
//
State contains some connection state and is useful in middleware
.
type
State
struct
{
Root
http
.
FileSystem
// TODO(miek): needed
?
Req
*
dns
.
Msg
W
dns
.
ResponseWriter
}
// Now returns the current timestamp in the specified format.
func
(
c
Context
)
Now
(
format
string
)
string
{
func
(
s
State
)
Now
(
format
string
)
string
{
return
time
.
Now
()
.
Format
(
format
)
}
// NowDate returns the current date/time that can be used
// in other time functions.
func
(
c
Context
)
NowDate
()
time
.
Time
{
func
(
s
State
)
NowDate
()
time
.
Time
{
return
time
.
Now
()
}
// Header gets the value of a header.
func
(
c
Context
)
Header
()
*
dns
.
RR_Header
{
func
(
s
State
)
Header
()
*
dns
.
RR_Header
{
// TODO(miek)
return
nil
}
// IP gets the (remote) IP address of the client making the request.
func
(
c
Context
)
IP
()
string
{
ip
,
_
,
err
:=
net
.
SplitHostPort
(
c
.
W
.
RemoteAddr
()
.
String
())
func
(
s
State
)
IP
()
string
{
ip
,
_
,
err
:=
net
.
SplitHostPort
(
s
.
W
.
RemoteAddr
()
.
String
())
if
err
!=
nil
{
return
c
.
W
.
RemoteAddr
()
.
String
()
return
s
.
W
.
RemoteAddr
()
.
String
()
}
return
ip
}
// Post gets the (remote) Port of the client making the request.
func
(
c
Context
)
Port
()
(
string
,
error
)
{
_
,
port
,
err
:=
net
.
SplitHostPort
(
c
.
W
.
RemoteAddr
()
.
String
())
func
(
s
State
)
Port
()
(
string
,
error
)
{
_
,
port
,
err
:=
net
.
SplitHostPort
(
s
.
W
.
RemoteAddr
()
.
String
())
if
err
!=
nil
{
return
"0"
,
err
}
...
...
@@ -56,11 +55,11 @@ func (c Context) Port() (string, error) {
// Proto gets the protocol used as the transport. This
// will be udp or tcp.
func
(
c
Context
)
Proto
()
string
{
if
_
,
ok
:=
c
.
W
.
RemoteAddr
()
.
(
*
net
.
UDPAddr
);
ok
{
func
(
s
State
)
Proto
()
string
{
if
_
,
ok
:=
s
.
W
.
RemoteAddr
()
.
(
*
net
.
UDPAddr
);
ok
{
return
"udp"
}
if
_
,
ok
:=
c
.
W
.
RemoteAddr
()
.
(
*
net
.
TCPAddr
);
ok
{
if
_
,
ok
:=
s
.
W
.
RemoteAddr
()
.
(
*
net
.
TCPAddr
);
ok
{
return
"tcp"
}
return
"udp"
...
...
@@ -68,9 +67,9 @@ func (c Context) Proto() string {
// Family returns the family of the transport.
// 1 for IPv4 and 2 for IPv6.
func
(
c
Context
)
Family
()
int
{
func
(
s
State
)
Family
()
int
{
var
a
net
.
IP
ip
:=
c
.
W
.
RemoteAddr
()
ip
:=
s
.
W
.
RemoteAddr
()
if
i
,
ok
:=
ip
.
(
*
net
.
UDPAddr
);
ok
{
a
=
i
.
IP
}
...
...
@@ -85,51 +84,48 @@ func (c Context) Family() int {
}
// Type returns the type of the question as a string.
func
(
c
Context
)
Type
()
string
{
return
dns
.
Type
(
c
.
Req
.
Question
[
0
]
.
Qtype
)
.
String
()
func
(
s
State
)
Type
()
string
{
return
dns
.
Type
(
s
.
Req
.
Question
[
0
]
.
Qtype
)
.
String
()
}
// QType returns the type of the question as a uint16.
func
(
c
Context
)
QType
()
uint16
{
return
c
.
Req
.
Question
[
0
]
.
Qtype
func
(
s
State
)
QType
()
uint16
{
return
s
.
Req
.
Question
[
0
]
.
Qtype
}
// Name returns the name of the question in the request. Note
// this name will always have a closing dot and will be lower cased.
func
(
c
Context
)
Name
()
string
{
return
strings
.
ToLower
(
dns
.
Name
(
c
.
Req
.
Question
[
0
]
.
Name
)
.
String
())
func
(
s
State
)
Name
()
string
{
return
strings
.
ToLower
(
dns
.
Name
(
s
.
Req
.
Question
[
0
]
.
Name
)
.
String
())
}
// QName returns the name of the question in the request.
func
(
c
Context
)
QName
()
string
{
return
dns
.
Name
(
c
.
Req
.
Question
[
0
]
.
Name
)
.
String
()
func
(
s
State
)
QName
()
string
{
return
dns
.
Name
(
s
.
Req
.
Question
[
0
]
.
Name
)
.
String
()
}
// Class returns the class of the question in the request.
func
(
c
Context
)
Class
()
string
{
return
dns
.
Class
(
c
.
Req
.
Question
[
0
]
.
Qclass
)
.
String
()
func
(
s
State
)
Class
()
string
{
return
dns
.
Class
(
s
.
Req
.
Question
[
0
]
.
Qclass
)
.
String
()
}
// QClass returns the class of the question in the request.
func
(
c
Context
)
QClass
()
uint16
{
return
c
.
Req
.
Question
[
0
]
.
Qclass
func
(
s
State
)
QClass
()
uint16
{
return
s
.
Req
.
Question
[
0
]
.
Qclass
}
// More convience types for extracting stuff from a message?
// Header?
// ErrorMessage returns an error message suitable for sending
// back to the client.
func
(
c
Context
)
ErrorMessage
(
rcode
int
)
*
dns
.
Msg
{
func
(
s
State
)
ErrorMessage
(
rcode
int
)
*
dns
.
Msg
{
m
:=
new
(
dns
.
Msg
)
m
.
SetRcode
(
c
.
Req
,
rcode
)
m
.
SetRcode
(
s
.
Req
,
rcode
)
return
m
}
// AnswerMessage returns an error message suitable for sending
// back to the client.
func
(
c
Context
)
AnswerMessage
()
*
dns
.
Msg
{
func
(
s
State
)
AnswerMessage
()
*
dns
.
Msg
{
m
:=
new
(
dns
.
Msg
)
m
.
SetReply
(
c
.
Req
)
m
.
SetReply
(
s
.
Req
)
return
m
}
middleware/
context
_test.go
→
middleware/
state
_test.go
View file @
f7043c31
package
middleware
import
(
"bytes"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
"testing"
"time"
)
func
TestInclude
(
t
*
testing
.
T
)
{
context
:=
getContextOrFail
(
t
)
inputFilename
:=
"test_file"
absInFilePath
:=
filepath
.
Join
(
fmt
.
Sprintf
(
"%s"
,
context
.
Root
),
inputFilename
)
defer
func
()
{
err
:=
os
.
Remove
(
absInFilePath
)
if
err
!=
nil
&&
!
os
.
IsNotExist
(
err
)
{
t
.
Fatalf
(
"Failed to clean test file!"
)
}
}()
tests
:=
[]
struct
{
fileContent
string
expectedContent
string
shouldErr
bool
expectedErrorContent
string
}{
// Test 0 - all good
{
fileContent
:
`str1 {{ .Root }} str2`
,
expectedContent
:
fmt
.
Sprintf
(
"str1 %s str2"
,
context
.
Root
),
shouldErr
:
false
,
expectedErrorContent
:
""
,
},
// Test 1 - failure on template.Parse
{
fileContent
:
`str1 {{ .Root } str2`
,
expectedContent
:
""
,
shouldErr
:
true
,
expectedErrorContent
:
`unexpected "}" in operand`
,
},
// Test 3 - failure on template.Execute
{
fileContent
:
`str1 {{ .InvalidField }} str2`
,
expectedContent
:
""
,
shouldErr
:
true
,
expectedErrorContent
:
`InvalidField is not a field of struct type middleware.Context`
,
},
}
for
i
,
test
:=
range
tests
{
testPrefix
:=
getTestPrefix
(
i
)
// WriteFile truncates the contentt
err
:=
ioutil
.
WriteFile
(
absInFilePath
,
[]
byte
(
test
.
fileContent
),
os
.
ModePerm
)
if
err
!=
nil
{
t
.
Fatal
(
testPrefix
+
"Failed to create test file. Error was: %v"
,
err
)
}
content
,
err
:=
context
.
Include
(
inputFilename
)
if
err
!=
nil
{
if
!
test
.
shouldErr
{
t
.
Errorf
(
testPrefix
+
"Expected no error, found [%s]"
,
test
.
expectedErrorContent
,
err
.
Error
())
}
if
!
strings
.
Contains
(
err
.
Error
(),
test
.
expectedErrorContent
)
{
t
.
Errorf
(
testPrefix
+
"Expected error content [%s], found [%s]"
,
test
.
expectedErrorContent
,
err
.
Error
())
}
}
if
err
==
nil
&&
test
.
shouldErr
{
t
.
Errorf
(
testPrefix
+
"Expected error [%s] but found nil. Input file was: %s"
,
test
.
expectedErrorContent
,
inputFilename
)
}
if
content
!=
test
.
expectedContent
{
t
.
Errorf
(
testPrefix
+
"Expected content [%s] but found [%s]. Input file was: %s"
,
test
.
expectedContent
,
content
,
inputFilename
)
}
}
}
func
TestIncludeNotExisting
(
t
*
testing
.
T
)
{
context
:=
getContextOrFail
(
t
)
_
,
err
:=
context
.
Include
(
"not_existing"
)
if
err
==
nil
{
t
.
Errorf
(
"Expected error but found nil!"
)
}
}
func
TestMarkdown
(
t
*
testing
.
T
)
{
context
:=
getContextOrFail
(
t
)
inputFilename
:=
"test_file"
absInFilePath
:=
filepath
.
Join
(
fmt
.
Sprintf
(
"%s"
,
context
.
Root
),
inputFilename
)
defer
func
()
{
err
:=
os
.
Remove
(
absInFilePath
)
if
err
!=
nil
&&
!
os
.
IsNotExist
(
err
)
{
t
.
Fatalf
(
"Failed to clean test file!"
)
}
}()
tests
:=
[]
struct
{
fileContent
string
expectedContent
string
}{
// Test 0 - test parsing of markdown
{
fileContent
:
"* str1
\n
* str2
\n
"
,
expectedContent
:
"<ul>
\n
<li>str1</li>
\n
<li>str2</li>
\n
</ul>
\n
"
,
},
}
for
i
,
test
:=
range
tests
{
testPrefix
:=
getTestPrefix
(
i
)
// WriteFile truncates the contentt
err
:=
ioutil
.
WriteFile
(
absInFilePath
,
[]
byte
(
test
.
fileContent
),
os
.
ModePerm
)
if
err
!=
nil
{
t
.
Fatal
(
testPrefix
+
"Failed to create test file. Error was: %v"
,
err
)
}
content
,
_
:=
context
.
Markdown
(
inputFilename
)
if
content
!=
test
.
expectedContent
{
t
.
Errorf
(
testPrefix
+
"Expected content [%s] but found [%s]. Input file was: %s"
,
test
.
expectedContent
,
content
,
inputFilename
)
}
}
}
func
TestCookie
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
cookie
*
http
.
Cookie
cookieName
string
expectedValue
string
}{
// Test 0 - happy path
{
cookie
:
&
http
.
Cookie
{
Name
:
"cookieName"
,
Value
:
"cookieValue"
},
cookieName
:
"cookieName"
,
expectedValue
:
"cookieValue"
,
},
// Test 1 - try to get a non-existing cookie
{
cookie
:
&
http
.
Cookie
{
Name
:
"cookieName"
,
Value
:
"cookieValue"
},
cookieName
:
"notExisting"
,
expectedValue
:
""
,
},
// Test 2 - partial name match
{
cookie
:
&
http
.
Cookie
{
Name
:
"cookie"
,
Value
:
"cookieValue"
},
cookieName
:
"cook"
,
expectedValue
:
""
,
},
// Test 3 - cookie with optional fields
{
cookie
:
&
http
.
Cookie
{
Name
:
"cookie"
,
Value
:
"cookieValue"
,
Path
:
"/path"
,
Domain
:
"https://localhost"
,
Expires
:
(
time
.
Now
()
.
Add
(
10
*
time
.
Minute
)),
MaxAge
:
120
},
cookieName
:
"cookie"
,
expectedValue
:
"cookieValue"
,
},
}
for
i
,
test
:=
range
tests
{
testPrefix
:=
getTestPrefix
(
i
)
// reinitialize the context for each test
context
:=
getContextOrFail
(
t
)
context
.
Req
.
AddCookie
(
test
.
cookie
)
actualCookieVal
:=
context
.
Cookie
(
test
.
cookieName
)
if
actualCookieVal
!=
test
.
expectedValue
{
t
.
Errorf
(
testPrefix
+
"Expected cookie value [%s] but found [%s] for cookie with name %s"
,
test
.
expectedValue
,
actualCookieVal
,
test
.
cookieName
)
}
}
}
func
TestCookieMultipleCookies
(
t
*
testing
.
T
)
{
context
:=
getContextOrFail
(
t
)
cookieNameBase
,
cookieValueBase
:=
"cookieName"
,
"cookieValue"
// make sure that there's no state and multiple requests for different cookies return the correct result
for
i
:=
0
;
i
<
10
;
i
++
{
context
.
Req
.
AddCookie
(
&
http
.
Cookie
{
Name
:
fmt
.
Sprintf
(
"%s%d"
,
cookieNameBase
,
i
),
Value
:
fmt
.
Sprintf
(
"%s%d"
,
cookieValueBase
,
i
)})
}
for
i
:=
0
;
i
<
10
;
i
++
{
expectedCookieVal
:=
fmt
.
Sprintf
(
"%s%d"
,
cookieValueBase
,
i
)
actualCookieVal
:=
context
.
Cookie
(
fmt
.
Sprintf
(
"%s%d"
,
cookieNameBase
,
i
))
if
actualCookieVal
!=
expectedCookieVal
{
t
.
Fatalf
(
"Expected cookie value %s, found %s"
,
expectedCookieVal
,
actualCookieVal
)
}
}
}
/*
func TestHeader(t *testing.T) {
context
:=
getContextOrFail
(
t
)
state
:= getContextOrFail(t)
headerKey, headerVal := "Header1", "HeaderVal1"
context
.
Req
.
Header
.
Add
(
headerKey
,
headerVal
)
state
.Req.Header.Add(headerKey, headerVal)
actualHeaderVal
:=
context
.
Header
(
headerKey
)
actualHeaderVal :=
state
.Header(headerKey)
if actualHeaderVal != headerVal {
t.Errorf("Expected header %s, found %s", headerVal, actualHeaderVal)
}
missingHeaderVal
:=
context
.
Header
(
"not-existing"
)
missingHeaderVal :=
state
.Header("not-existing")
if missingHeaderVal != "" {
t.Errorf("Expected empty header value, found %s", missingHeaderVal)
}
}
func TestIP(t *testing.T) {
context
:=
getContextOrFail
(
t
)
state
:= getContextOrFail(t)
tests := []struct {
inputRemoteAddr string
...
...
@@ -238,8 +40,8 @@ func TestIP(t *testing.T) {
for i, test := range tests {
testPrefix := getTestPrefix(i)
context
.
Req
.
RemoteAddr
=
test
.
inputRemoteAddr
actualIP
:=
context
.
IP
()
state
.Req.RemoteAddr = test.inputRemoteAddr
actualIP :=
state
.IP()
if actualIP != test.expectedIP {
t.Errorf(testPrefix+"Expected IP %s, found %s", test.expectedIP, actualIP)
...
...
@@ -248,13 +50,13 @@ func TestIP(t *testing.T) {
}
func TestURL(t *testing.T) {
context
:=
getContextOrFail
(
t
)
state
:= getContextOrFail(t)
inputURL := "http://localhost"
context
.
Req
.
RequestURI
=
inputURL
state
.Req.RequestURI = inputURL
if
inputURL
!=
context
.
URI
()
{
t
.
Errorf
(
"Expected url %s, found %s"
,
inputURL
,
context
.
URI
())
if inputURL !=
state
.URI() {
t.Errorf("Expected url %s, found %s", inputURL,
state
.URI())
}
}
...
...
@@ -320,17 +122,17 @@ func TestPort(t *testing.T) {
}
func testHostOrPort(t *testing.T, isTestingHost bool, input, expectedResult string, shouldErr bool) {
context
:=
getContextOrFail
(
t
)
state
:= getContextOrFail(t)
context
.
Req
.
Host
=
input
state
.Req.Host = input
var actualResult, testedObject string
var err error
if isTestingHost {
actualResult
,
err
=
context
.
Host
()
actualResult, err =
state
.Host()
testedObject = "host"
} else {
actualResult
,
err
=
context
.
Port
()
actualResult, err =
state
.Port()
testedObject = "port"
}
...
...
@@ -349,20 +151,8 @@ func testHostOrPort(t *testing.T, isTestingHost bool, input, expectedResult stri
}
}
func
TestMethod
(
t
*
testing
.
T
)
{
context
:=
getContextOrFail
(
t
)
method
:=
"POST"
context
.
Req
.
Method
=
method
if
method
!=
context
.
Method
()
{
t
.
Errorf
(
"Expected method %s, found %s"
,
method
,
context
.
Method
())
}
}
func TestPathMatches(t *testing.T) {
context
:=
getContextOrFail
(
t
)
state
:= getContextOrFail(t)
tests := []struct {
urlStr string
...
...
@@ -411,185 +201,23 @@ func TestPathMatches(t *testing.T) {
pattern: "/dir1",
shouldMatch: true,
},
// Test 7
{
urlStr
:
"http://localhost/dir1/dir2"
,
pattern
:
"*/dir2"
,
shouldMatch
:
false
,
},
}
for i, test := range tests {
testPrefix := getTestPrefix(i)
var err error
context
.
Req
.
URL
,
err
=
url
.
Parse
(
test
.
urlStr
)
state
.Req.URL, err = url.Parse(test.urlStr)
if err != nil {
t.Fatalf("Failed to prepare test URL from string %s! Error was: %s", test.urlStr, err)
}
matches
:=
context
.
PathMatches
(
test
.
pattern
)
matches :=
state
.PathMatches(test.pattern)
if matches != test.shouldMatch {
t.Errorf(testPrefix+"Expected and actual result differ: expected to match [%t], actual matches [%t]", test.shouldMatch, matches)
}
}
}
func
TestTruncate
(
t
*
testing
.
T
)
{
context
:=
getContextOrFail
(
t
)
tests
:=
[]
struct
{
inputString
string
inputLength
int
expected
string
}{
// Test 0 - small length
{
inputString
:
"string"
,
inputLength
:
1
,
expected
:
"s"
,
},
// Test 1 - exact length
{
inputString
:
"string"
,
inputLength
:
6
,
expected
:
"string"
,
},
// Test 2 - bigger length
{
inputString
:
"string"
,
inputLength
:
10
,
expected
:
"string"
,
},
// Test 3 - zero length
{
inputString
:
"string"
,
inputLength
:
0
,
expected
:
""
,
},
// Test 4 - negative, smaller length
{
inputString
:
"string"
,
inputLength
:
-
5
,
expected
:
"tring"
,
},
// Test 5 - negative, exact length
{
inputString
:
"string"
,
inputLength
:
-
6
,
expected
:
"string"
,
},
// Test 6 - negative, bigger length
{
inputString
:
"string"
,
inputLength
:
-
7
,
expected
:
"string"
,
},
}
for
i
,
test
:=
range
tests
{
actual
:=
context
.
Truncate
(
test
.
inputString
,
test
.
inputLength
)
if
actual
!=
test
.
expected
{
t
.
Errorf
(
getTestPrefix
(
i
)
+
"Expected '%s', found '%s'. Input was Truncate(%q, %d)"
,
test
.
expected
,
actual
,
test
.
inputString
,
test
.
inputLength
)
}
}
}
func
TestStripHTML
(
t
*
testing
.
T
)
{
context
:=
getContextOrFail
(
t
)
tests
:=
[]
struct
{
input
string
expected
string
}{
// Test 0 - no tags
{
input
:
`h1`
,
expected
:
`h1`
,
},
// Test 1 - happy path
{
input
:
`<h1>h1</h1>`
,
expected
:
`h1`
,
},
// Test 2 - tag in quotes
{
input
:
`<h1">">h1</h1>`
,
expected
:
`h1`
,
},
// Test 3 - multiple tags
{
input
:
`<h1><b>h1</b></h1>`
,
expected
:
`h1`
,
},
// Test 4 - tags not closed
{
input
:
`<h1`
,
expected
:
`<h1`
,
},
// Test 5 - false start
{
input
:
`<h1<b>hi`
,
expected
:
`<h1hi`
,
},
}
for
i
,
test
:=
range
tests
{
actual
:=
context
.
StripHTML
(
test
.
input
)
if
actual
!=
test
.
expected
{
t
.
Errorf
(
getTestPrefix
(
i
)
+
"Expected %s, found %s. Input was StripHTML(%s)"
,
test
.
expected
,
actual
,
test
.
input
)
}
}
}
func
TestStripExt
(
t
*
testing
.
T
)
{
context
:=
getContextOrFail
(
t
)
tests
:=
[]
struct
{
input
string
expected
string
}{
// Test 0 - empty input
{
input
:
""
,
expected
:
""
,
},
// Test 1 - relative file with ext
{
input
:
"file.ext"
,
expected
:
"file"
,
},
// Test 2 - relative file without ext
{
input
:
"file"
,
expected
:
"file"
,
},
// Test 3 - absolute file without ext
{
input
:
"/file"
,
expected
:
"/file"
,
},
// Test 4 - absolute file with ext
{
input
:
"/file.ext"
,
expected
:
"/file"
,
},
// Test 5 - with ext but ends with /
{
input
:
"/dir.ext/"
,
expected
:
"/dir.ext/"
,
},
// Test 6 - file with ext under dir with ext
{
input
:
"/dir.ext/file.ext"
,
expected
:
"/dir.ext/file"
,
},
}
for
i
,
test
:=
range
tests
{
actual
:=
context
.
StripExt
(
test
.
input
)
if
actual
!=
test
.
expected
{
t
.
Errorf
(
getTestPrefix
(
i
)
+
"Expected %s, found %s. Input was StripExt(%q)"
,
test
.
expected
,
actual
,
test
.
input
)
}
}
}
func initTestContext() (Context, error) {
body := bytes.NewBufferString("request body")
request, err := http.NewRequest("GET", "https://localhost", body)
...
...
@@ -600,14 +228,8 @@ func initTestContext() (Context, error) {
return Context{Root: http.Dir(os.TempDir()), Req: request}, nil
}
func
getContextOrFail
(
t
*
testing
.
T
)
Context
{
context
,
err
:=
initTestContext
()
if
err
!=
nil
{
t
.
Fatalf
(
"Failed to prepare test context"
)
}
return
context
}
func getTestPrefix(testN int) string {
return fmt.Sprintf("Test [%d]: ", testN)
}
*/
server/server.go
View file @
f7043c31
...
...
@@ -15,6 +15,8 @@ import (
"sync"
"time"
"golang.org/x/net/context"
"github.com/miekg/dns"
)
...
...
@@ -285,6 +287,7 @@ func (s *Server) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
q
:=
r
.
Question
[
0
]
.
Name
b
:=
make
([]
byte
,
len
(
q
))
off
,
end
:=
0
,
false
ctx
:=
context
.
Background
()
for
{
l
:=
len
(
q
[
off
:
])
for
i
:=
0
;
i
<
l
;
i
++
{
...
...
@@ -297,7 +300,7 @@ func (s *Server) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
if
h
,
ok
:=
s
.
zones
[
string
(
b
[
:
l
])];
ok
{
if
r
.
Question
[
0
]
.
Qtype
!=
dns
.
TypeDS
{
rcode
,
_
:=
h
.
stack
.
ServeDNS
(
w
,
r
)
rcode
,
_
:=
h
.
stack
.
ServeDNS
(
ctx
,
w
,
r
)
if
rcode
>
0
{
DefaultErrorFunc
(
w
,
r
,
rcode
)
}
...
...
@@ -311,7 +314,7 @@ func (s *Server) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
}
// Wildcard match, if we have found nothing try the root zone as a last resort.
if
h
,
ok
:=
s
.
zones
[
"."
];
ok
{
rcode
,
_
:=
h
.
stack
.
ServeDNS
(
w
,
r
)
rcode
,
_
:=
h
.
stack
.
ServeDNS
(
ctx
,
w
,
r
)
if
rcode
>
0
{
DefaultErrorFunc
(
w
,
r
,
rcode
)
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment