I am writing a web application. Incoming requests will pass through middlewares first. At the moment, I've added two middlwares session and security.
After walked through middlwares, it will execute the handler for the request.
Session and security middlwares will execute in their own goroutine.
When I am testing I've got a lot of data race, specially in middlware section
WARNING: DATA RACE
Write by goroutine 18:
runtime.mapassign1()
c:/go/src/runtime/hashmap.go:383 +0x0
net/textproto.MIMEHeader.Set()
c:/go/src/net/textproto/header.go:22 +0xf4
net/http.Header.Set()
c:/go/src/net/http/header.go:31 +0x64
project/middlewares/session.(*ctrl).setHttpHeader()
D:/gocode/src/project/middlewares/session/ctrl.go:76 +0x9d
project/middlewares/session.(*ctrl).evaluateJwt()
D:/gocode/src/project/middlewares/session/ctrl.go:56 +0x31a
project/middlewares/session.(*ctrl).serveHttp()
D:/gocode/src/project/middlewares/session/ctrl.go:94 +0x8a
project/middlewares/session.func┬À006()
D:/gocode/src/project/middlewares/session/serve_http.go:23 +0x
Previous write by goroutine 17:
runtime.mapassign1()
c:/go/src/runtime/hashmap.go:383 +0x0
net/textproto.MIMEHeader.Add()
c:/go/src/net/textproto/header.go:15 +0x212
net/http.Header.Add()
c:/go/src/net/http/header.go:24 +0x64
github.com/unrolled/secure.(*Secure).Process()
D:/gocode/src/github.com/unrolled/secure/secure.go:177 +0xe5b
project/middlewares/security.func┬À001()
D:/gocode/src/project/middlewares/security/serve_http.go:33 +0
Goroutine 18 (running) created at:
project/middlewares/session.ServeHttp()
D:/gocode/src/project/middlewares/session/serve_http.go:29 +0x
project/middlewares.New()
D:/gocode/src/project/middlewares/ctrl.go:12 +0x99
github.com/codegangsta/negroni.HandlerFunc.ServeHTTP()
D:/gocode/src/github.com/codegangsta/negroni/negroni.go:24 +0x5f
github.com/codegangsta/negroni.middleware.ServeHTTP()
D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
github.com/codegangsta/negroni.(*Static).ServeHTTP()
D:/gocode/src/github.com/codegangsta/negroni/static.go:30 +0xb71
github.com/codegangsta/negroni.middleware.ServeHTTP()
D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
github.com/codegangsta/negroni.(*Logger).ServeHTTP()
D:/gocode/src/github.com/codegangsta/negroni/logger.go:25 +0x249
github.com/codegangsta/negroni.middleware.ServeHTTP()
D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
github.com/codegangsta/negroni.(*Recovery).ServeHTTP()
D:/gocode/src/github.com/codegangsta/negroni/recovery.go:45 +0xd9
github.com/codegangsta/negroni.middleware.ServeHTTP()
D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
github.com/codegangsta/negroni.(*Negroni).ServeHTTP()
D:/gocode/src/github.com/codegangsta/negroni/negroni.go:73 +0x1c7
net/http/httptest.(*waitGroupHandler).ServeHTTP()
c:/go/src/net/http/httptest/server.go:200 +0xfe
net/http.serverHandler.ServeHTTP()
c:/go/src/net/http/server.go:1703 +0x1fd
net/http.(*conn).serve()
c:/go/src/net/http/server.go:1204 +0x108e
Goroutine 17 (finished) created at:
project/middlewares/security.ServeHttp()
D:/gocode/src/project/middlewares/security/serve_http.go:37 +0
project/middlewares.New()
D:/gocode/src/project/middlewares/ctrl.go:12 +0x64
github.com/codegangsta/negroni.HandlerFunc.ServeHTTP()
D:/gocode/src/github.com/codegangsta/negroni/negroni.go:24 +0x5f
github.com/codegangsta/negroni.middleware.ServeHTTP()
D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
github.com/codegangsta/negroni.(*Static).ServeHTTP()
D:/gocode/src/github.com/codegangsta/negroni/static.go:30 +0xb71
github.com/codegangsta/negroni.middleware.ServeHTTP()
D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
github.com/codegangsta/negroni.(*Logger).ServeHTTP()
D:/gocode/src/github.com/codegangsta/negroni/logger.go:25 +0x249
github.com/codegangsta/negroni.middleware.ServeHTTP()
D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
github.com/codegangsta/negroni.(*Recovery).ServeHTTP()
D:/gocode/src/github.com/codegangsta/negroni/recovery.go:45 +0xd9
github.com/codegangsta/negroni.middleware.ServeHTTP()
D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
github.com/codegangsta/negroni.(*Negroni).ServeHTTP()
D:/gocode/src/github.com/codegangsta/negroni/negroni.go:73 +0x1c7
net/http/httptest.(*waitGroupHandler).ServeHTTP()
c:/go/src/net/http/httptest/server.go:200 +0xfe
net/http.serverHandler.ServeHTTP()
c:/go/src/net/http/server.go:1703 +0x1fd
net/http.(*conn).serve()
c:/go/src/net/http/server.go:1204 +0x108e
==================
2015/02/03 15:05:31 ctrl.go:17: End of process middlewares
2015/02/03 15:05:31 funcs.go:10: Create new user
2015/02/03 15:05:31 validate.go:14: Validate email thompson@example.com
2015/02/03 15:05:31 validate.go:100: Validate password Test!1234
2015/02/03 15:05:31 validate.go:52: Validate name: ValidName
2015/02/03 15:05:31 create.go:120: Done
[negroni] Completed 0 in 197ms
PASS
ok project/testing/account_test 0.664s
PS D:\gocode\src\project\testing\account_test> go test -race
2015/02/03 15:08:10 vs.go:50: Connect to neo4j db.
[negroni] Started POST /user
==================
WARNING: DATA RACE
Write by goroutine 18:
net/http.(*response).Header()
c:/go/src/net/http/server.go:615 +0x11a
github.com/codegangsta/negroni.(*responseWriter).Header()
<autogenerated>:42 +0x78
project/middlewares/session.(*ctrl).setHttpHeader()
D:/gocode/src/project/middlewares/session/ctrl.go:76 +0x68
project/middlewares/session.(*ctrl).evaluateJwt()
D:/gocode/src/project/middlewares/session/ctrl.go:56 +0x31a
project/middlewares/session.(*ctrl).serveHttp()
D:/gocode/src/project/middlewares/session/ctrl.go:94 +0x8a
project/middlewares/session.func┬À006()
D:/gocode/src/project/middlewares/session/serve_http.go:23 +0x
Previous write by goroutine 17:
net/http.(*response).Header()
c:/go/src/net/http/server.go:615 +0x11a
github.com/codegangsta/negroni.(*responseWriter).Header()
<autogenerated>:42 +0x78
github.com/unrolled/secure.(*Secure).Process()
D:/gocode/src/github.com/unrolled/secure/secure.go:177 +0xe24
project/middlewares/security.func┬À001()
D:/gocode/src/project/middlewares/security/serve_http.go:33 +0
I use negroni to process middlwares works.
The way, how I process middlwares
func New(res http.ResponseWriter, req *http.Request, next http.HandlerFunc) {
if err := process(security.ServeHttp(res, req), session.ServeHttp(res, req)); err != nil {
res.WriteHeader(http.StatusInternalServerError)
return
}
log.Println("End of process middlewares")
next(res, req)
}
// Process all middlewares
func process(chErrs ...<-chan error) error {
for _, chErr := range chErrs {
// Will abort the loop, when error occurs
if err := <-chErr; err != nil {
return err
}
}
return nil
}
As you can see, every middlware have they own channel. The for statement will loop until the error channel is closed or error send.
The server configuration
func Config() *negroni.Negroni {
n := negroni.Classic()
n.Use(negroni.HandlerFunc(middlewares.New))
n.UseHandler(routes.Set())
return n
}
My question is, are the middlewares the reason, why I've got the data race?