Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
caddy
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
caddy
Commits
f9bc7462
Commit
f9bc7462
authored
Oct 09, 2015
by
Zac Bergquist
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Address various lint and gocyclo warnings. Fixes #253
parent
17c91152
Changes
29
Hide whitespace changes
Inline
Side-by-side
Showing
29 changed files
with
293 additions
and
258 deletions
+293
-258
app/app.go
app/app.go
+2
-2
config/config.go
config/config.go
+3
-0
config/directives.go
config/directives.go
+2
-2
config/parse/dispenser.go
config/parse/dispenser.go
+4
-3
config/parse/parsing.go
config/parse/parsing.go
+2
-2
config/parse/parsing_test.go
config/parse/parsing_test.go
+3
-3
config/setup/markdown.go
config/setup/markdown.go
+69
-56
config/setup/proxy.go
config/setup/proxy.go
+5
-5
config/setup/startupshutdown.go
config/setup/startupshutdown.go
+1
-2
main.go
main.go
+2
-2
middleware/basicauth/basicauth.go
middleware/basicauth/basicauth.go
+3
-0
middleware/browse/browse_test.go
middleware/browse/browse_test.go
+6
-7
middleware/errors/errors.go
middleware/errors/errors.go
+1
-2
middleware/fastcgi/fastcgi.go
middleware/fastcgi/fastcgi.go
+22
-18
middleware/fastcgi/fcgiclient.go
middleware/fastcgi/fcgiclient.go
+40
-38
middleware/fastcgi/fcgiclient_test.go
middleware/fastcgi/fcgiclient_test.go
+28
-28
middleware/gzip/filter.go
middleware/gzip/filter.go
+1
-1
middleware/gzip/gzip_test.go
middleware/gzip/gzip_test.go
+1
-1
middleware/markdown/markdown_test.go
middleware/markdown/markdown_test.go
+4
-4
middleware/markdown/process.go
middleware/markdown/process.go
+2
-2
middleware/markdown/watcher.go
middleware/markdown/watcher.go
+2
-0
middleware/proxy/policy_test.go
middleware/proxy/policy_test.go
+3
-3
middleware/proxy/upstream.go
middleware/proxy/upstream.go
+66
-60
middleware/replacer_test.go
middleware/replacer_test.go
+4
-4
middleware/rewrite/rewrite.go
middleware/rewrite/rewrite.go
+1
-1
middleware/rewrite/rewrite_test.go
middleware/rewrite/rewrite_test.go
+9
-9
middleware/roller.go
middleware/roller.go
+2
-0
middleware/templates/templates_test.go
middleware/templates/templates_test.go
+3
-3
server/server.go
server/server.go
+2
-0
No files found.
app/app.go
View file @
f9bc7462
...
...
@@ -33,8 +33,8 @@ var (
// Wg is used to wait for all servers to shut down
Wg
sync
.
WaitGroup
// H
ttp
2 indicates whether HTTP2 is enabled or not
H
ttp
2
bool
// TODO: temporary flag until http2 is standard
// H
TTP
2 indicates whether HTTP2 is enabled or not
H
TTP
2
bool
// TODO: temporary flag until http2 is standard
// Quiet mode hides non-error initialization output
Quiet
bool
...
...
config/config.go
View file @
f9bc7462
...
...
@@ -234,6 +234,8 @@ func validDirective(d string) bool {
return
false
}
// NewDefault creates a default configuration using the default
// root, host, and port.
func
NewDefault
()
server
.
Config
{
return
server
.
Config
{
Root
:
Root
,
...
...
@@ -256,4 +258,5 @@ var (
Port
=
DefaultPort
)
// Group maps network addresses to their configurations.
type
Group
map
[
*
net
.
TCPAddr
][]
server
.
Config
config/directives.go
View file @
f9bc7462
...
...
@@ -74,7 +74,7 @@ type directive struct {
setup
SetupFunc
}
//
A setup function takes a setup controller. Its return values may
//
both be nil. If
middleware is not nil, it will be chained into
//
SetupFunc takes a controller and may optionally return a middleware.
//
If the resulting
middleware is not nil, it will be chained into
// the HTTP handlers in the order specified in this package.
type
SetupFunc
func
(
c
*
setup
.
Controller
)
(
middleware
.
Middleware
,
error
)
config/parse/dispenser.go
View file @
f9bc7462
...
...
@@ -119,6 +119,7 @@ func (d *Dispenser) NextBlock() bool {
return
true
}
// IncrNest adds a level of nesting to the dispenser.
func
(
d
*
Dispenser
)
IncrNest
()
{
d
.
nesting
++
return
...
...
@@ -208,9 +209,9 @@ func (d *Dispenser) SyntaxErr(expected string) error {
return
errors
.
New
(
msg
)
}
// E
ofErr returns an EOF error, meaning that end of input
//
was found when another token was expected
.
func
(
d
*
Dispenser
)
E
of
Err
()
error
{
// E
OFErr returns an error indicating that the dispenser reached
//
the end of the input when searching for the next token
.
func
(
d
*
Dispenser
)
E
OF
Err
()
error
{
return
d
.
Errf
(
"Unexpected EOF"
)
}
...
...
config/parse/parsing.go
View file @
f9bc7462
...
...
@@ -108,7 +108,7 @@ func (p *parser) addresses() error {
// Advance token and possibly break out of loop or return error
hasNext
:=
p
.
Next
()
if
expectingAnother
&&
!
hasNext
{
return
p
.
E
of
Err
()
return
p
.
E
OF
Err
()
}
if
!
hasNext
{
p
.
eof
=
true
...
...
@@ -242,7 +242,7 @@ func (p *parser) directive() error {
}
if
nesting
>
0
{
return
p
.
E
of
Err
()
return
p
.
E
OF
Err
()
}
return
nil
}
...
...
config/parse/parsing_test.go
View file @
f9bc7462
...
...
@@ -338,9 +338,9 @@ func TestParseAll(t *testing.T) {
func
setupParseTests
()
{
// Set up some bogus directives for testing
ValidDirectives
=
map
[
string
]
struct
{}{
"dir1"
:
struct
{}
{},
"dir2"
:
struct
{}
{},
"dir3"
:
struct
{}
{},
"dir1"
:
{},
"dir2"
:
{},
"dir3"
:
{},
}
}
...
...
config/setup/markdown.go
View file @
f9bc7462
...
...
@@ -68,62 +68,8 @@ func markdownParse(c *Controller) ([]*markdown.Config, error) {
// Load any other configuration parameters
for
c
.
NextBlock
()
{
switch
c
.
Val
()
{
case
"ext"
:
exts
:=
c
.
RemainingArgs
()
if
len
(
exts
)
==
0
{
return
mdconfigs
,
c
.
ArgErr
()
}
md
.
Extensions
=
append
(
md
.
Extensions
,
exts
...
)
case
"css"
:
if
!
c
.
NextArg
()
{
return
mdconfigs
,
c
.
ArgErr
()
}
md
.
Styles
=
append
(
md
.
Styles
,
c
.
Val
())
case
"js"
:
if
!
c
.
NextArg
()
{
return
mdconfigs
,
c
.
ArgErr
()
}
md
.
Scripts
=
append
(
md
.
Scripts
,
c
.
Val
())
case
"template"
:
tArgs
:=
c
.
RemainingArgs
()
switch
len
(
tArgs
)
{
case
0
:
return
mdconfigs
,
c
.
ArgErr
()
case
1
:
if
_
,
ok
:=
md
.
Templates
[
markdown
.
DefaultTemplate
];
ok
{
return
mdconfigs
,
c
.
Err
(
"only one default template is allowed, use alias."
)
}
fpath
:=
filepath
.
Clean
(
c
.
Root
+
string
(
filepath
.
Separator
)
+
tArgs
[
0
])
md
.
Templates
[
markdown
.
DefaultTemplate
]
=
fpath
case
2
:
fpath
:=
filepath
.
Clean
(
c
.
Root
+
string
(
filepath
.
Separator
)
+
tArgs
[
1
])
md
.
Templates
[
tArgs
[
0
]]
=
fpath
default
:
return
mdconfigs
,
c
.
ArgErr
()
}
case
"sitegen"
:
if
c
.
NextArg
()
{
md
.
StaticDir
=
path
.
Join
(
c
.
Root
,
c
.
Val
())
}
else
{
md
.
StaticDir
=
path
.
Join
(
c
.
Root
,
markdown
.
DefaultStaticDir
)
}
if
c
.
NextArg
()
{
// only 1 argument allowed
return
mdconfigs
,
c
.
ArgErr
()
}
case
"dev"
:
if
c
.
NextArg
()
{
md
.
Development
=
strings
.
ToLower
(
c
.
Val
())
==
"true"
}
else
{
md
.
Development
=
true
}
if
c
.
NextArg
()
{
// only 1 argument allowed
return
mdconfigs
,
c
.
ArgErr
()
}
default
:
return
mdconfigs
,
c
.
Err
(
"Expected valid markdown configuration property"
)
if
err
:=
loadParams
(
c
,
md
);
err
!=
nil
{
return
mdconfigs
,
err
}
}
...
...
@@ -137,3 +83,70 @@ func markdownParse(c *Controller) ([]*markdown.Config, error) {
return
mdconfigs
,
nil
}
func
loadParams
(
c
*
Controller
,
mdc
*
markdown
.
Config
)
error
{
switch
c
.
Val
()
{
case
"ext"
:
exts
:=
c
.
RemainingArgs
()
if
len
(
exts
)
==
0
{
return
c
.
ArgErr
()
}
mdc
.
Extensions
=
append
(
mdc
.
Extensions
,
exts
...
)
return
nil
case
"css"
:
if
!
c
.
NextArg
()
{
return
c
.
ArgErr
()
}
mdc
.
Styles
=
append
(
mdc
.
Styles
,
c
.
Val
())
return
nil
case
"js"
:
if
!
c
.
NextArg
()
{
return
c
.
ArgErr
()
}
mdc
.
Scripts
=
append
(
mdc
.
Scripts
,
c
.
Val
())
return
nil
case
"template"
:
tArgs
:=
c
.
RemainingArgs
()
switch
len
(
tArgs
)
{
case
0
:
return
c
.
ArgErr
()
case
1
:
if
_
,
ok
:=
mdc
.
Templates
[
markdown
.
DefaultTemplate
];
ok
{
return
c
.
Err
(
"only one default template is allowed, use alias."
)
}
fpath
:=
filepath
.
Clean
(
c
.
Root
+
string
(
filepath
.
Separator
)
+
tArgs
[
0
])
mdc
.
Templates
[
markdown
.
DefaultTemplate
]
=
fpath
return
nil
case
2
:
fpath
:=
filepath
.
Clean
(
c
.
Root
+
string
(
filepath
.
Separator
)
+
tArgs
[
1
])
mdc
.
Templates
[
tArgs
[
0
]]
=
fpath
return
nil
default
:
return
c
.
ArgErr
()
}
case
"sitegen"
:
if
c
.
NextArg
()
{
mdc
.
StaticDir
=
path
.
Join
(
c
.
Root
,
c
.
Val
())
}
else
{
mdc
.
StaticDir
=
path
.
Join
(
c
.
Root
,
markdown
.
DefaultStaticDir
)
}
if
c
.
NextArg
()
{
// only 1 argument allowed
return
c
.
ArgErr
()
}
return
nil
case
"dev"
:
if
c
.
NextArg
()
{
mdc
.
Development
=
strings
.
ToLower
(
c
.
Val
())
==
"true"
}
else
{
mdc
.
Development
=
true
}
if
c
.
NextArg
()
{
// only 1 argument allowed
return
c
.
ArgErr
()
}
return
nil
default
:
return
c
.
Err
(
"Expected valid markdown configuration property"
)
}
}
config/setup/proxy.go
View file @
f9bc7462
...
...
@@ -7,11 +7,11 @@ import (
// Proxy configures a new Proxy middleware instance.
func
Proxy
(
c
*
Controller
)
(
middleware
.
Middleware
,
error
)
{
if
upstreams
,
err
:=
proxy
.
NewStaticUpstreams
(
c
.
Dispenser
);
err
==
nil
{
return
func
(
next
middleware
.
Handler
)
middleware
.
Handler
{
return
proxy
.
Proxy
{
Next
:
next
,
Upstreams
:
upstreams
}
},
nil
}
else
{
upstreams
,
err
:=
proxy
.
NewStaticUpstreams
(
c
.
Dispenser
)
if
err
!=
nil
{
return
nil
,
err
}
return
func
(
next
middleware
.
Handler
)
middleware
.
Handler
{
return
proxy
.
Proxy
{
Next
:
next
,
Upstreams
:
upstreams
}
},
nil
}
config/setup/startupshutdown.go
View file @
f9bc7462
...
...
@@ -46,9 +46,8 @@ func registerCallback(c *Controller, list *[]func() error) error {
if
nonblock
{
return
cmd
.
Start
()
}
else
{
return
cmd
.
Run
()
}
return
cmd
.
Run
()
}
*
list
=
append
(
*
list
,
fn
)
...
...
main.go
View file @
f9bc7462
...
...
@@ -26,7 +26,7 @@ var (
func
init
()
{
flag
.
StringVar
(
&
conf
,
"conf"
,
""
,
"Configuration file to use (default="
+
config
.
DefaultConfigFile
+
")"
)
flag
.
BoolVar
(
&
app
.
H
ttp
2
,
"http2"
,
true
,
"Enable HTTP/2 support"
)
// TODO: temporary flag until http2 merged into std lib
flag
.
BoolVar
(
&
app
.
H
TTP
2
,
"http2"
,
true
,
"Enable HTTP/2 support"
)
// TODO: temporary flag until http2 merged into std lib
flag
.
BoolVar
(
&
app
.
Quiet
,
"quiet"
,
false
,
"Quiet mode (no initialization output)"
)
flag
.
StringVar
(
&
cpu
,
"cpu"
,
"100%"
,
"CPU cap"
)
flag
.
StringVar
(
&
config
.
Root
,
"root"
,
config
.
DefaultRoot
,
"Root path to default site"
)
...
...
@@ -61,7 +61,7 @@ func main() {
if
err
!=
nil
{
log
.
Fatal
(
err
)
}
s
.
HTTP2
=
app
.
H
ttp
2
// TODO: This setting is temporary
s
.
HTTP2
=
app
.
H
TTP
2
// TODO: This setting is temporary
app
.
Wg
.
Add
(
1
)
go
func
(
s
*
server
.
Server
)
{
defer
app
.
Wg
.
Done
()
...
...
middleware/basicauth/basicauth.go
View file @
f9bc7462
...
...
@@ -78,6 +78,7 @@ type Rule struct {
Resources
[]
string
}
// PasswordMatcher determines whether a password mathes a rule.
type
PasswordMatcher
func
(
pw
string
)
bool
var
(
...
...
@@ -137,6 +138,8 @@ func parseHtpasswd(pm map[string]PasswordMatcher, r io.Reader) error {
return
scanner
.
Err
()
}
// PlainMatcher returns a PasswordMatcher that does a constant-time
// byte-wise comparison.
func
PlainMatcher
(
passw
string
)
PasswordMatcher
{
return
func
(
pw
string
)
bool
{
return
subtle
.
ConstantTimeCompare
([]
byte
(
pw
),
[]
byte
(
passw
))
==
1
...
...
middleware/browse/browse_test.go
View file @
f9bc7462
...
...
@@ -117,7 +117,7 @@ func TestBrowseTemplate(t *testing.T) {
}),
Root
:
"./testdata"
,
Configs
:
[]
Config
{
Config
{
{
PathScope
:
"/photos"
,
Template
:
tmpl
,
},
...
...
@@ -172,7 +172,7 @@ func TestBrowseJson(t *testing.T) {
}),
Root
:
"./testdata"
,
Configs
:
[]
Config
{
Config
{
{
PathScope
:
"/photos/"
,
},
},
...
...
@@ -283,7 +283,7 @@ func TestBrowseJson(t *testing.T) {
t
.
Fatalf
(
"Expected Content type to be application/json; charset=utf-8, but got %s "
,
rec
.
HeaderMap
.
Get
(
"Content-Type"
))
}
actualJ
sonResponseString
:=
rec
.
Body
.
String
()
actualJ
SONResponse
:=
rec
.
Body
.
String
()
copyOflisting
:=
listing
if
test
.
SortBy
==
""
{
copyOflisting
.
Sort
=
"name"
...
...
@@ -308,12 +308,11 @@ func TestBrowseJson(t *testing.T) {
if
err
!=
nil
{
t
.
Fatalf
(
"Unable to Marshal the listing "
)
}
expectedJ
sonString
:=
string
(
marsh
)
expectedJ
SON
:=
string
(
marsh
)
if
actualJ
sonResponseString
!=
expectedJsonString
{
if
actualJ
SONResponse
!=
expectedJSON
{
t
.
Errorf
(
"JSON response doesn't match the expected for test number %d with sort=%s, order=%s
\n
Expected response %s
\n
Actual response = %s
\n
"
,
i
+
1
,
test
.
SortBy
,
test
.
OrderBy
,
expectedJ
sonString
,
actualJsonResponseString
)
i
+
1
,
test
.
SortBy
,
test
.
OrderBy
,
expectedJ
SON
,
actualJSONResponse
)
}
}
}
middleware/errors/errors.go
View file @
f9bc7462
...
...
@@ -37,9 +37,8 @@ func (h ErrorHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, er
w
.
WriteHeader
(
status
)
fmt
.
Fprintln
(
w
,
errMsg
)
return
0
,
err
// returning < 400 signals that a response has been written
}
else
{
h
.
Log
.
Println
(
errMsg
)
}
h
.
Log
.
Println
(
errMsg
)
}
if
status
>=
400
{
...
...
middleware/fastcgi/fastcgi.go
View file @
f9bc7462
...
...
@@ -58,17 +58,7 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error)
}
// Connect to FastCGI gateway
var
fcgi
*
FCGIClient
// check if unix socket or tcp
if
strings
.
HasPrefix
(
rule
.
Address
,
"/"
)
||
strings
.
HasPrefix
(
rule
.
Address
,
"unix:"
)
{
if
strings
.
HasPrefix
(
rule
.
Address
,
"unix:"
)
{
rule
.
Address
=
rule
.
Address
[
len
(
"unix:"
)
:
]
}
fcgi
,
err
=
Dial
(
"unix"
,
rule
.
Address
)
}
else
{
fcgi
,
err
=
Dial
(
"tcp"
,
rule
.
Address
)
}
fcgi
,
err
:=
getClient
(
&
rule
)
if
err
!=
nil
{
return
http
.
StatusBadGateway
,
err
}
...
...
@@ -102,13 +92,7 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error)
return
http
.
StatusBadGateway
,
err
}
// Write the response header
for
key
,
vals
:=
range
resp
.
Header
{
for
_
,
val
:=
range
vals
{
w
.
Header
()
.
Add
(
key
,
val
)
}
}
w
.
WriteHeader
(
resp
.
StatusCode
)
writeHeader
(
w
,
resp
)
// Write the response body
// TODO: If this has an error, the response will already be
...
...
@@ -126,6 +110,26 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error)
return
h
.
Next
.
ServeHTTP
(
w
,
r
)
}
func
getClient
(
r
*
Rule
)
(
*
FCGIClient
,
error
)
{
// check if unix socket or TCP
if
trim
:=
strings
.
HasPrefix
(
r
.
Address
,
"unix"
);
strings
.
HasPrefix
(
r
.
Address
,
"/"
)
||
trim
{
if
trim
{
r
.
Address
=
r
.
Address
[
len
(
"unix:"
)
:
]
}
return
Dial
(
"unix"
,
r
.
Address
)
}
return
Dial
(
"tcp"
,
r
.
Address
)
}
func
writeHeader
(
w
http
.
ResponseWriter
,
r
*
http
.
Response
)
{
for
key
,
vals
:=
range
r
.
Header
{
for
_
,
val
:=
range
vals
{
w
.
Header
()
.
Add
(
key
,
val
)
}
}
w
.
WriteHeader
(
r
.
StatusCode
)
}
func
(
h
Handler
)
exists
(
path
string
)
bool
{
if
_
,
err
:=
os
.
Stat
(
h
.
Root
+
path
);
err
==
nil
{
return
true
...
...
middleware/fastcgi/fcgiclient.go
View file @
f9bc7462
...
...
@@ -30,45 +30,45 @@ import (
"sync"
)
const
FCGI
_LISTENSOCK_FILENO
uint8
=
0
const
FCGI
_HEADER_LEN
uint8
=
8
const
V
ERSION_
1
uint8
=
1
const
FCGI
_NULL_REQUEST_
ID
uint8
=
0
const
FCGI
_KEEP_CONN
uint8
=
1
const
FCGI
ListenSockFileno
uint8
=
0
const
FCGI
HeaderLen
uint8
=
8
const
V
ersion
1
uint8
=
1
const
FCGI
NullRequest
ID
uint8
=
0
const
FCGI
KeepConn
uint8
=
1
const
doubleCRLF
=
"
\r\n\r\n
"
const
(
FCGI_BEGIN_REQUEST
uint8
=
iota
+
1
FCGI_ABORT_REQUEST
FCGI_END_REQUEST
FCGI_PARAMS
FCGI_STDIN
FCGI_STDOUT
FCGI_STDERR
FCGI_DATA
FCGI_GET_VALUES
FCGI_GET_VALUES_RESULT
FCGI_UNKNOWN_TYPE
FCGI_MAXTYPE
=
FCGI_UNKNOWN_TYPE
BeginRequest
uint8
=
iota
+
1
AbortRequest
EndRequest
Params
Stdin
Stdout
Stderr
Data
GetValues
GetValuesResult
UnknownType
MaxType
=
UnknownType
)
const
(
FCGI_RESPONDER
uint8
=
iota
+
1
FCGI_AUTHORIZER
F
CGI_FILTER
Responder
uint8
=
iota
+
1
Authorizer
F
ilter
)
const
(
FCGI_REQUEST_COMPLETE
uint8
=
iota
FCGI_CANT_MPX_CONN
FCGI_OVERLOADED
FCGI_UNKNOWN_ROLE
RequestComplete
uint8
=
iota
CantMultiplexConns
Overloaded
UnknownRole
)
const
(
FCGI_MAX_CONNS
string
=
"MAX_CONNS"
FCGI_MAX_REQS
string
=
"MAX_REQS"
FCGI_MPXS_CONNS
string
=
"MPXS_CONNS"
MaxConns
string
=
"MAX_CONNS"
MaxRequests
string
=
"MAX_REQS"
MultiplexConns
string
=
"MPXS_CONNS"
)
const
(
...
...
@@ -79,7 +79,7 @@ const (
type
header
struct
{
Version
uint8
Type
uint8
I
d
uint16
I
D
uint16
ContentLength
uint16
PaddingLength
uint8
Reserved
uint8
...
...
@@ -92,7 +92,7 @@ var pad [maxPad]byte
func
(
h
*
header
)
init
(
recType
uint8
,
reqID
uint16
,
contentLength
int
)
{
h
.
Version
=
1
h
.
Type
=
recType
h
.
I
d
=
reqID
h
.
I
D
=
reqID
h
.
ContentLength
=
uint16
(
contentLength
)
h
.
PaddingLength
=
uint8
(
-
contentLength
&
7
)
}
...
...
@@ -110,7 +110,7 @@ func (rec *record) read(r io.Reader) (buf []byte, err error) {
err
=
errors
.
New
(
"fcgi: invalid header version"
)
return
}
if
rec
.
h
.
Type
==
FCGI_END_REQUEST
{
if
rec
.
h
.
Type
==
EndRequest
{
err
=
io
.
EOF
return
}
...
...
@@ -126,13 +126,15 @@ func (rec *record) read(r io.Reader) (buf []byte, err error) {
return
}
// FCGIClient implements a FastCGI client, which is a standard for
// interfacing external applications with Web servers.
type
FCGIClient
struct
{
mutex
sync
.
Mutex
rwc
io
.
ReadWriteCloser
h
header
buf
bytes
.
Buffer
keepAlive
bool
reqI
d
uint16
reqI
D
uint16
}
// Dial connects to the fcgi responder at the specified network address.
...
...
@@ -148,7 +150,7 @@ func Dial(network, address string) (fcgi *FCGIClient, err error) {
fcgi
=
&
FCGIClient
{
rwc
:
conn
,
keepAlive
:
false
,
reqI
d
:
1
,
reqI
D
:
1
,
}
return
...
...
@@ -163,7 +165,7 @@ func (c *FCGIClient) writeRecord(recType uint8, content []byte) (err error) {
c
.
mutex
.
Lock
()
defer
c
.
mutex
.
Unlock
()
c
.
buf
.
Reset
()
c
.
h
.
init
(
recType
,
c
.
reqI
d
,
len
(
content
))
c
.
h
.
init
(
recType
,
c
.
reqI
D
,
len
(
content
))
if
err
:=
binary
.
Write
(
&
c
.
buf
,
binary
.
BigEndian
,
c
.
h
);
err
!=
nil
{
return
err
}
...
...
@@ -179,14 +181,14 @@ func (c *FCGIClient) writeRecord(recType uint8, content []byte) (err error) {
func
(
c
*
FCGIClient
)
writeBeginRequest
(
role
uint16
,
flags
uint8
)
error
{
b
:=
[
8
]
byte
{
byte
(
role
>>
8
),
byte
(
role
),
flags
}
return
c
.
writeRecord
(
FCGI_BEGIN_REQUEST
,
b
[
:
])
return
c
.
writeRecord
(
BeginRequest
,
b
[
:
])
}
func
(
c
*
FCGIClient
)
writeEndRequest
(
appStatus
int
,
protocolStatus
uint8
)
error
{
b
:=
make
([]
byte
,
8
)
binary
.
BigEndian
.
PutUint32
(
b
,
uint32
(
appStatus
))
b
[
4
]
=
protocolStatus
return
c
.
writeRecord
(
FCGI_END_REQUEST
,
b
)
return
c
.
writeRecord
(
EndRequest
,
b
)
}
func
(
c
*
FCGIClient
)
writePairs
(
recType
uint8
,
pairs
map
[
string
]
string
)
error
{
...
...
@@ -334,17 +336,17 @@ func (w *streamReader) Read(p []byte) (n int, err error) {
// Do made the request and returns a io.Reader that translates the data read
// from fcgi responder out of fcgi packet before returning it.
func
(
c
*
FCGIClient
)
Do
(
p
map
[
string
]
string
,
req
io
.
Reader
)
(
r
io
.
Reader
,
err
error
)
{
err
=
c
.
writeBeginRequest
(
uint16
(
FCGI_RESPONDER
),
0
)
err
=
c
.
writeBeginRequest
(
uint16
(
Responder
),
0
)
if
err
!=
nil
{
return
}
err
=
c
.
writePairs
(
FCGI_PARAMS
,
p
)
err
=
c
.
writePairs
(
Params
,
p
)
if
err
!=
nil
{
return
}
body
:=
newWriter
(
c
,
FCGI_STDIN
)
body
:=
newWriter
(
c
,
Stdin
)
if
req
!=
nil
{
io
.
Copy
(
body
,
req
)
}
...
...
middleware/fastcgi/fcgiclient_test.go
View file @
f9bc7462
...
...
@@ -34,13 +34,13 @@ import (
// test failed if the remote fcgi(script) failed md5 verification
// and output "FAILED" in response
const
(
script
_f
ile
=
"/tank/www/fcgic_test.php"
//ip
_p
ort = "remote-php-serv:59000"
ip
_p
ort
=
"127.0.0.1:59000"
script
F
ile
=
"/tank/www/fcgic_test.php"
//ip
P
ort = "remote-php-serv:59000"
ip
P
ort
=
"127.0.0.1:59000"
)
var
(
t_
*
testing
.
T
=
nil
t_
*
testing
.
T
)
type
FastCGIServer
struct
{}
...
...
@@ -51,7 +51,7 @@ func (s FastCGIServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
stat
:=
"PASSED"
fmt
.
Fprintln
(
resp
,
"-"
)
file
_n
um
:=
0
file
N
um
:=
0
{
length
:=
0
for
k0
,
v0
:=
range
req
.
Form
{
...
...
@@ -69,7 +69,7 @@ func (s FastCGIServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
}
}
if
req
.
MultipartForm
!=
nil
{
file
_n
um
=
len
(
req
.
MultipartForm
.
File
)
file
N
um
=
len
(
req
.
MultipartForm
.
File
)
for
kn
,
fns
:=
range
req
.
MultipartForm
.
File
{
//fmt.Fprintln(resp, "server:filekey ", kn )
length
+=
len
(
kn
)
...
...
@@ -101,11 +101,11 @@ func (s FastCGIServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
fmt
.
Fprintln
(
resp
,
"server:got data length"
,
length
)
}
fmt
.
Fprintln
(
resp
,
"-"
+
stat
+
"-POST("
,
len
(
req
.
Form
),
")-FILE("
,
file
_n
um
,
")--"
)
fmt
.
Fprintln
(
resp
,
"-"
+
stat
+
"-POST("
,
len
(
req
.
Form
),
")-FILE("
,
file
N
um
,
")--"
)
}
func
sendFcgi
(
reqType
int
,
fcgi
_p
arams
map
[
string
]
string
,
data
[]
byte
,
posts
map
[
string
]
string
,
files
map
[
string
]
string
)
(
content
[]
byte
)
{
fcgi
,
err
:=
Dial
(
"tcp"
,
ip
_p
ort
)
func
sendFcgi
(
reqType
int
,
fcgi
P
arams
map
[
string
]
string
,
data
[]
byte
,
posts
map
[
string
]
string
,
files
map
[
string
]
string
)
(
content
[]
byte
)
{
fcgi
,
err
:=
Dial
(
"tcp"
,
ip
P
ort
)
if
err
!=
nil
{
log
.
Println
(
"err:"
,
err
)
return
...
...
@@ -119,16 +119,16 @@ func sendFcgi(reqType int, fcgi_params map[string]string, data []byte, posts map
if
len
(
data
)
>
0
{
length
=
len
(
data
)
rd
:=
bytes
.
NewReader
(
data
)
resp
,
err
=
fcgi
.
Post
(
fcgi
_p
arams
,
""
,
rd
,
rd
.
Len
())
resp
,
err
=
fcgi
.
Post
(
fcgi
P
arams
,
""
,
rd
,
rd
.
Len
())
}
else
if
len
(
posts
)
>
0
{
values
:=
url
.
Values
{}
for
k
,
v
:=
range
posts
{
values
.
Set
(
k
,
v
)
length
+=
len
(
k
)
+
2
+
len
(
v
)
}
resp
,
err
=
fcgi
.
PostForm
(
fcgi
_p
arams
,
values
)
resp
,
err
=
fcgi
.
PostForm
(
fcgi
P
arams
,
values
)
}
else
{
resp
,
err
=
fcgi
.
Get
(
fcgi
_p
arams
)
resp
,
err
=
fcgi
.
Get
(
fcgi
P
arams
)
}
default
:
...
...
@@ -142,7 +142,7 @@ func sendFcgi(reqType int, fcgi_params map[string]string, data []byte, posts map
fi
,
_
:=
os
.
Lstat
(
v
)
length
+=
len
(
k
)
+
int
(
fi
.
Size
())
}
resp
,
err
=
fcgi
.
PostFile
(
fcgi
_p
arams
,
values
,
files
)
resp
,
err
=
fcgi
.
PostFile
(
fcgi
P
arams
,
values
,
files
)
}
if
err
!=
nil
{
...
...
@@ -191,7 +191,7 @@ func generateRandFile(size int) (p string, m string) {
return
}
func
Disabled
_
Test
(
t
*
testing
.
T
)
{
func
DisabledTest
(
t
*
testing
.
T
)
{
// TODO: test chunked reader
t_
=
t
...
...
@@ -199,7 +199,7 @@ func Disabled_Test(t *testing.T) {
// server
go
func
()
{
listener
,
err
:=
net
.
Listen
(
"tcp"
,
ip
_p
ort
)
listener
,
err
:=
net
.
Listen
(
"tcp"
,
ip
P
ort
)
if
err
!=
nil
{
// handle error
log
.
Println
(
"listener creatation failed: "
,
err
)
...
...
@@ -212,19 +212,19 @@ func Disabled_Test(t *testing.T) {
time
.
Sleep
(
1
*
time
.
Second
)
// init
fcgi
_p
arams
:=
make
(
map
[
string
]
string
)
fcgi
_p
arams
[
"REQUEST_METHOD"
]
=
"GET"
fcgi
_p
arams
[
"SERVER_PROTOCOL"
]
=
"HTTP/1.1"
fcgi
P
arams
:=
make
(
map
[
string
]
string
)
fcgi
P
arams
[
"REQUEST_METHOD"
]
=
"GET"
fcgi
P
arams
[
"SERVER_PROTOCOL"
]
=
"HTTP/1.1"
//fcgi_params["GATEWAY_INTERFACE"] = "CGI/1.1"
fcgi
_params
[
"SCRIPT_FILENAME"
]
=
script_f
ile
fcgi
Params
[
"SCRIPT_FILENAME"
]
=
scriptF
ile
// simple GET
log
.
Println
(
"test:"
,
"get"
)
sendFcgi
(
0
,
fcgi
_p
arams
,
nil
,
nil
,
nil
)
sendFcgi
(
0
,
fcgi
P
arams
,
nil
,
nil
,
nil
)
// simple post data
log
.
Println
(
"test:"
,
"post"
)
sendFcgi
(
0
,
fcgi
_p
arams
,
[]
byte
(
"c4ca4238a0b923820dcc509a6f75849b=1&7b8b965ad4bca0e41ab51de7b31363a1=n"
),
nil
,
nil
)
sendFcgi
(
0
,
fcgi
P
arams
,
[]
byte
(
"c4ca4238a0b923820dcc509a6f75849b=1&7b8b965ad4bca0e41ab51de7b31363a1=n"
),
nil
,
nil
)
log
.
Println
(
"test:"
,
"post data (more than 60KB)"
)
data
:=
""
...
...
@@ -240,13 +240,13 @@ func Disabled_Test(t *testing.T) {
data
+=
k0
+
"="
+
url
.
QueryEscape
(
v0
)
+
"&"
}
sendFcgi
(
0
,
fcgi
_p
arams
,
[]
byte
(
data
),
nil
,
nil
)
sendFcgi
(
0
,
fcgi
P
arams
,
[]
byte
(
data
),
nil
,
nil
)
log
.
Println
(
"test:"
,
"post form (use url.Values)"
)
p0
:=
make
(
map
[
string
]
string
,
1
)
p0
[
"c4ca4238a0b923820dcc509a6f75849b"
]
=
"1"
p0
[
"7b8b965ad4bca0e41ab51de7b31363a1"
]
=
"n"
sendFcgi
(
1
,
fcgi
_p
arams
,
nil
,
p0
,
nil
)
sendFcgi
(
1
,
fcgi
P
arams
,
nil
,
p0
,
nil
)
log
.
Println
(
"test:"
,
"post forms (256 keys, more than 1MB)"
)
p1
:=
make
(
map
[
string
]
string
,
1
)
...
...
@@ -257,25 +257,25 @@ func Disabled_Test(t *testing.T) {
k0
:=
fmt
.
Sprintf
(
"%x"
,
h
.
Sum
(
nil
))
p1
[
k0
]
=
v0
}
sendFcgi
(
1
,
fcgi
_p
arams
,
nil
,
p1
,
nil
)
sendFcgi
(
1
,
fcgi
P
arams
,
nil
,
p1
,
nil
)
log
.
Println
(
"test:"
,
"post file (1 file, 500KB)) "
)
f0
:=
make
(
map
[
string
]
string
,
1
)
path0
,
m0
:=
generateRandFile
(
500000
)
f0
[
m0
]
=
path0
sendFcgi
(
1
,
fcgi
_p
arams
,
nil
,
p1
,
f0
)
sendFcgi
(
1
,
fcgi
P
arams
,
nil
,
p1
,
f0
)
log
.
Println
(
"test:"
,
"post multiple files (2 files, 5M each) and forms (256 keys, more than 1MB data"
)
path1
,
m1
:=
generateRandFile
(
5000000
)
f0
[
m1
]
=
path1
sendFcgi
(
1
,
fcgi
_p
arams
,
nil
,
p1
,
f0
)
sendFcgi
(
1
,
fcgi
P
arams
,
nil
,
p1
,
f0
)
log
.
Println
(
"test:"
,
"post only files (2 files, 5M each)"
)
sendFcgi
(
1
,
fcgi
_p
arams
,
nil
,
nil
,
f0
)
sendFcgi
(
1
,
fcgi
P
arams
,
nil
,
nil
,
f0
)
log
.
Println
(
"test:"
,
"post only 1 file"
)
delete
(
f0
,
"m0"
)
sendFcgi
(
1
,
fcgi
_p
arams
,
nil
,
nil
,
f0
)
sendFcgi
(
1
,
fcgi
P
arams
,
nil
,
nil
,
f0
)
os
.
Remove
(
path0
)
os
.
Remove
(
path1
)
...
...
middleware/gzip/filter.go
View file @
f9bc7462
...
...
@@ -81,7 +81,7 @@ func (s Set) Contains(value string) bool {
// elements in the set and passes each to f. It returns true
// on the first call to f that returns true and false otherwise.
func
(
s
Set
)
ContainsFunc
(
f
func
(
string
)
bool
)
bool
{
for
k
,
_
:=
range
s
{
for
k
:=
range
s
{
if
f
(
k
)
{
return
true
}
...
...
middleware/gzip/gzip_test.go
View file @
f9bc7462
...
...
@@ -21,7 +21,7 @@ func TestGzipHandler(t *testing.T) {
extFilter
.
Exts
.
Add
(
e
)
}
gz
:=
Gzip
{
Configs
:
[]
Config
{
Config
{
Filters
:
[]
Filter
{
pathFilter
,
extFilter
}},
{
Filters
:
[]
Filter
{
pathFilter
,
extFilter
}},
}}
w
:=
httptest
.
NewRecorder
()
...
...
middleware/markdown/markdown_test.go
View file @
f9bc7462
...
...
@@ -22,7 +22,7 @@ func TestMarkdown(t *testing.T) {
Root
:
"./testdata"
,
FileSys
:
http
.
Dir
(
"./testdata"
),
Configs
:
[]
*
Config
{
&
Config
{
{
Renderer
:
blackfriday
.
HtmlRenderer
(
0
,
""
,
""
),
PathScope
:
"/blog"
,
Extensions
:
[]
string
{
".md"
},
...
...
@@ -32,7 +32,7 @@ func TestMarkdown(t *testing.T) {
StaticDir
:
DefaultStaticDir
,
StaticFiles
:
make
(
map
[
string
]
string
),
},
&
Config
{
{
Renderer
:
blackfriday
.
HtmlRenderer
(
0
,
""
,
""
),
PathScope
:
"/log"
,
Extensions
:
[]
string
{
".md"
},
...
...
@@ -42,7 +42,7 @@ func TestMarkdown(t *testing.T) {
StaticDir
:
DefaultStaticDir
,
StaticFiles
:
make
(
map
[
string
]
string
),
},
&
Config
{
{
Renderer
:
blackfriday
.
HtmlRenderer
(
0
,
""
,
""
),
PathScope
:
"/og"
,
Extensions
:
[]
string
{
".md"
},
...
...
@@ -52,7 +52,7 @@ func TestMarkdown(t *testing.T) {
StaticDir
:
"testdata/og_static"
,
StaticFiles
:
map
[
string
]
string
{
"/og/first.md"
:
"testdata/og_static/og/first.md/index.html"
},
Links
:
[]
PageLink
{
PageLink
{
{
Title
:
"first"
,
Summary
:
""
,
Date
:
time
.
Now
(),
...
...
middleware/markdown/process.go
View file @
f9bc7462
...
...
@@ -18,7 +18,7 @@ const (
DefaultStaticDir
=
"generated_site"
)
type
Markdown
Data
struct
{
type
Data
struct
{
middleware
.
Context
Doc
map
[
string
]
string
Links
[]
PageLink
...
...
@@ -95,7 +95,7 @@ func (md Markdown) processTemplate(c *Config, requestPath string, tmpl []byte, m
if
err
!=
nil
{
return
nil
,
err
}
mdData
:=
Markdown
Data
{
mdData
:=
Data
{
Context
:
ctx
,
Doc
:
metadata
.
Variables
,
Links
:
c
.
Links
,
...
...
middleware/markdown/watcher.go
View file @
f9bc7462
...
...
@@ -5,6 +5,8 @@ import (
"time"
)
// DefaultInterval is the default interval at which the markdown watcher
// checks for changes.
const
DefaultInterval
=
time
.
Second
*
60
// Watch monitors the configured markdown directory for changes. It calls GenerateLinks
...
...
middleware/proxy/policy_test.go
View file @
f9bc7462
...
...
@@ -12,13 +12,13 @@ func (r *customPolicy) Select(pool HostPool) *UpstreamHost {
func
testPool
()
HostPool
{
pool
:=
[]
*
UpstreamHost
{
&
UpstreamHost
{
{
Name
:
"http://google.com"
,
// this should resolve (healthcheck test)
},
&
UpstreamHost
{
{
Name
:
"http://shouldnot.resolve"
,
// this shouldn't
},
&
UpstreamHost
{
{
Name
:
"http://C"
,
},
}
...
...
middleware/proxy/upstream.go
View file @
f9bc7462
...
...
@@ -13,8 +13,8 @@ import (
)
var
(
supportedPolicies
map
[
string
]
func
()
Policy
=
make
(
map
[
string
]
func
()
Policy
)
proxyHeaders
http
.
Header
=
make
(
http
.
Header
)
supportedPolicies
=
make
(
map
[
string
]
func
()
Policy
)
proxyHeaders
=
make
(
http
.
Header
)
)
type
staticUpstream
struct
{
...
...
@@ -53,64 +53,8 @@ func NewStaticUpstreams(c parse.Dispenser) ([]Upstream, error) {
}
for
c
.
NextBlock
()
{
switch
c
.
Val
()
{
case
"policy"
:
if
!
c
.
NextArg
()
{
return
upstreams
,
c
.
ArgErr
()
}
if
policyCreateFunc
,
ok
:=
supportedPolicies
[
c
.
Val
()];
ok
{
upstream
.
Policy
=
policyCreateFunc
()
}
else
{
return
upstreams
,
c
.
ArgErr
()
}
case
"fail_timeout"
:
if
!
c
.
NextArg
()
{
return
upstreams
,
c
.
ArgErr
()
}
if
dur
,
err
:=
time
.
ParseDuration
(
c
.
Val
());
err
==
nil
{
upstream
.
FailTimeout
=
dur
}
else
{
return
upstreams
,
err
}
case
"max_fails"
:
if
!
c
.
NextArg
()
{
return
upstreams
,
c
.
ArgErr
()
}
if
n
,
err
:=
strconv
.
Atoi
(
c
.
Val
());
err
==
nil
{
upstream
.
MaxFails
=
int32
(
n
)
}
else
{
return
upstreams
,
err
}
case
"health_check"
:
if
!
c
.
NextArg
()
{
return
upstreams
,
c
.
ArgErr
()
}
upstream
.
HealthCheck
.
Path
=
c
.
Val
()
upstream
.
HealthCheck
.
Interval
=
30
*
time
.
Second
if
c
.
NextArg
()
{
if
dur
,
err
:=
time
.
ParseDuration
(
c
.
Val
());
err
==
nil
{
upstream
.
HealthCheck
.
Interval
=
dur
}
else
{
return
upstreams
,
err
}
}
case
"proxy_header"
:
var
header
,
value
string
if
!
c
.
Args
(
&
header
,
&
value
)
{
return
upstreams
,
c
.
ArgErr
()
}
proxyHeaders
.
Add
(
header
,
value
)
case
"websocket"
:
proxyHeaders
.
Add
(
"Connection"
,
"{>Connection}"
)
proxyHeaders
.
Add
(
"Upgrade"
,
"{>Upgrade}"
)
case
"without"
:
if
!
c
.
NextArg
()
{
return
upstreams
,
c
.
ArgErr
()
}
upstream
.
WithoutPathPrefix
=
c
.
Val
()
default
:
return
upstreams
,
c
.
Errf
(
"unknown property '%s'"
,
c
.
Val
())
if
err
:=
parseBlock
(
&
c
,
upstream
);
err
!=
nil
{
return
upstreams
,
err
}
}
...
...
@@ -165,6 +109,68 @@ func (u *staticUpstream) From() string {
return
u
.
from
}
func
parseBlock
(
c
*
parse
.
Dispenser
,
u
*
staticUpstream
)
error
{
switch
c
.
Val
()
{
case
"policy"
:
if
!
c
.
NextArg
()
{
return
c
.
ArgErr
()
}
policyCreateFunc
,
ok
:=
supportedPolicies
[
c
.
Val
()]
if
!
ok
{
return
c
.
ArgErr
()
}
u
.
Policy
=
policyCreateFunc
()
case
"fail_timeout"
:
if
!
c
.
NextArg
()
{
return
c
.
ArgErr
()
}
dur
,
err
:=
time
.
ParseDuration
(
c
.
Val
())
if
err
!=
nil
{
return
err
}
u
.
FailTimeout
=
dur
case
"max_fails"
:
if
!
c
.
NextArg
()
{
return
c
.
ArgErr
()
}
n
,
err
:=
strconv
.
Atoi
(
c
.
Val
())
if
err
!=
nil
{
return
err
}
u
.
MaxFails
=
int32
(
n
)
case
"health_check"
:
if
!
c
.
NextArg
()
{
return
c
.
ArgErr
()
}
u
.
HealthCheck
.
Path
=
c
.
Val
()
u
.
HealthCheck
.
Interval
=
30
*
time
.
Second
if
c
.
NextArg
()
{
dur
,
err
:=
time
.
ParseDuration
(
c
.
Val
())
if
err
!=
nil
{
return
err
}
u
.
HealthCheck
.
Interval
=
dur
}
case
"proxy_header"
:
var
header
,
value
string
if
!
c
.
Args
(
&
header
,
&
value
)
{
return
c
.
ArgErr
()
}
proxyHeaders
.
Add
(
header
,
value
)
case
"websocket"
:
proxyHeaders
.
Add
(
"Connection"
,
"{>Connection}"
)
proxyHeaders
.
Add
(
"Upgrade"
,
"{>Upgrade}"
)
case
"without"
:
if
!
c
.
NextArg
()
{
return
c
.
ArgErr
()
}
u
.
WithoutPathPrefix
=
c
.
Val
()
default
:
return
c
.
Errf
(
"unknown property '%s'"
,
c
.
Val
())
}
return
nil
}
func
(
u
*
staticUpstream
)
healthCheck
()
{
for
_
,
host
:=
range
u
.
Hosts
{
hostURL
:=
host
.
Name
+
u
.
HealthCheck
.
Path
...
...
middleware/replacer_test.go
View file @
f9bc7462
...
...
@@ -10,9 +10,9 @@ import (
func
TestNewReplacer
(
t
*
testing
.
T
)
{
w
:=
httptest
.
NewRecorder
()
recordRequest
:=
NewResponseRecorder
(
w
)
userJ
son
:=
`{"username": "dennis"}`
userJ
SON
:=
`{"username": "dennis"}`
reader
:=
strings
.
NewReader
(
userJ
son
)
//Convert string to reader
reader
:=
strings
.
NewReader
(
userJ
SON
)
//Convert string to reader
request
,
err
:=
http
.
NewRequest
(
"POST"
,
"http://caddyserver.com"
,
reader
)
//Create request with JSON body
if
err
!=
nil
{
...
...
@@ -41,9 +41,9 @@ func TestNewReplacer(t *testing.T) {
func
TestReplace
(
t
*
testing
.
T
)
{
w
:=
httptest
.
NewRecorder
()
recordRequest
:=
NewResponseRecorder
(
w
)
userJ
son
:=
`{"username": "dennis"}`
userJ
SON
:=
`{"username": "dennis"}`
reader
:=
strings
.
NewReader
(
userJ
son
)
//Convert string to reader
reader
:=
strings
.
NewReader
(
userJ
SON
)
//Convert string to reader
request
,
err
:=
http
.
NewRequest
(
"POST"
,
"http://caddyserver.com"
,
reader
)
//Create request with JSON body
if
err
!=
nil
{
...
...
middleware/rewrite/rewrite.go
View file @
f9bc7462
...
...
@@ -115,7 +115,7 @@ func (r *RegexpRule) Rewrite(req *http.Request) bool {
// include trailing slash in regexp if present
start
:=
len
(
r
.
Base
)
if
strings
.
HasSuffix
(
r
.
Base
,
"/"
)
{
start
-=
1
start
--
}
// validate regexp
...
...
middleware/rewrite/rewrite_test.go
View file @
f9bc7462
...
...
@@ -21,15 +21,15 @@ func TestRewrite(t *testing.T) {
}
regexpRules
:=
[][]
string
{
[]
string
{
"/reg/"
,
".*"
,
"/to"
,
""
},
[]
string
{
"/r/"
,
"[a-z]+"
,
"/toaz"
,
"!.html|"
},
[]
string
{
"/url/"
,
"a([a-z0-9]*)s([A-Z]{2})"
,
"/to/{path}"
,
""
},
[]
string
{
"/ab/"
,
"ab"
,
"/ab?{query}"
,
".txt|"
},
[]
string
{
"/ab/"
,
"ab"
,
"/ab?type=html&{query}"
,
".html|"
},
[]
string
{
"/abc/"
,
"ab"
,
"/abc/{file}"
,
".html|"
},
[]
string
{
"/abcd/"
,
"ab"
,
"/a/{dir}/{file}"
,
".html|"
},
[]
string
{
"/abcde/"
,
"ab"
,
"/a#{fragment}"
,
".html|"
},
[]
string
{
"/ab/"
,
`.*\.jpg`
,
"/ajpg"
,
""
},
{
"/reg/"
,
".*"
,
"/to"
,
""
},
{
"/r/"
,
"[a-z]+"
,
"/toaz"
,
"!.html|"
},
{
"/url/"
,
"a([a-z0-9]*)s([A-Z]{2})"
,
"/to/{path}"
,
""
},
{
"/ab/"
,
"ab"
,
"/ab?{query}"
,
".txt|"
},
{
"/ab/"
,
"ab"
,
"/ab?type=html&{query}"
,
".html|"
},
{
"/abc/"
,
"ab"
,
"/abc/{file}"
,
".html|"
},
{
"/abcd/"
,
"ab"
,
"/a/{dir}/{file}"
,
".html|"
},
{
"/abcde/"
,
"ab"
,
"/a#{fragment}"
,
".html|"
},
{
"/ab/"
,
`.*\.jpg`
,
"/ajpg"
,
""
},
}
for
_
,
regexpRule
:=
range
regexpRules
{
...
...
middleware/roller.go
View file @
f9bc7462
...
...
@@ -6,6 +6,7 @@ import (
"gopkg.in/natefinch/lumberjack.v2"
)
// LogRoller implements a middleware that provides a rolling logger.
type
LogRoller
struct
{
Filename
string
MaxSize
int
...
...
@@ -14,6 +15,7 @@ type LogRoller struct {
LocalTime
bool
}
// GetLogWriter returns an io.Writer that writes to a rolling logger.
func
(
l
LogRoller
)
GetLogWriter
()
io
.
Writer
{
return
&
lumberjack
.
Logger
{
Filename
:
l
.
Filename
,
...
...
middleware/templates/templates_test.go
View file @
f9bc7462
...
...
@@ -14,12 +14,12 @@ func Test(t *testing.T) {
return
0
,
nil
}),
Rules
:
[]
Rule
{
Rule
{
{
Extensions
:
[]
string
{
".html"
},
IndexFiles
:
[]
string
{
"index.html"
},
Path
:
"/photos"
,
},
Rule
{
{
Extensions
:
[]
string
{
".html"
,
".htm"
},
IndexFiles
:
[]
string
{
"index.html"
,
"index.htm"
},
Path
:
"/images"
,
...
...
@@ -34,7 +34,7 @@ func Test(t *testing.T) {
return
0
,
nil
}),
Rules
:
[]
Rule
{
Rule
{
{
Extensions
:
[]
string
{
".html"
},
IndexFiles
:
[]
string
{
"index.html"
},
Path
:
"/"
,
...
...
server/server.go
View file @
f9bc7462
...
...
@@ -264,6 +264,8 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
}
// DefaultErrorFunc responds to an HTTP request with a simple description
// of the specified HTTP status code.
func
DefaultErrorFunc
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
,
status
int
)
{
w
.
WriteHeader
(
status
)
fmt
.
Fprintf
(
w
,
"%d %s"
,
status
,
http
.
StatusText
(
status
))
...
...
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