Merge branch 'master' into bitbucketserver

Moving git username and password to the url
Removing un-needed setting of Allows
Moving log.Fatal to log.Error
Removing panics
Moving to https for gravatar

# Conflicts:
#	remote/remote.go
This commit is contained in:
Joachim Hill-Grannec
2016-04-19 09:47:02 -07:00
213 changed files with 22669 additions and 848 deletions

View File

@@ -0,0 +1,22 @@
package middleware
import (
"time"
"github.com/drone/drone/cache"
"github.com/gin-gonic/gin"
"github.com/ianschenck/envflag"
)
var ttl = envflag.Duration("CACHE_TTL", time.Minute*15, "")
// Cache is a middleware function that initializes the Cache and attaches to
// the context of every http.Request.
func Cache() gin.HandlerFunc {
cc := cache.NewTTL(*ttl)
return func(c *gin.Context) {
cache.ToContext(c, cc)
c.Next()
}
}

View File

@@ -1,14 +0,0 @@
package cache
import (
"github.com/drone/drone/cache"
"github.com/gin-gonic/gin"
)
func Default() gin.HandlerFunc {
cc := cache.Default()
return func(c *gin.Context) {
cache.ToContext(c, cc)
c.Next()
}
}

View File

@@ -1,37 +0,0 @@
package context
import (
"github.com/drone/drone/engine"
"github.com/drone/drone/remote"
"github.com/drone/drone/store"
"github.com/gin-gonic/gin"
)
func SetStore(s store.Store) gin.HandlerFunc {
return func(c *gin.Context) {
store.ToContext(c, s)
c.Next()
}
}
func SetRemote(remote remote.Remote) gin.HandlerFunc {
return func(c *gin.Context) {
c.Set("remote", remote)
c.Next()
}
}
func Remote(c *gin.Context) remote.Remote {
return c.MustGet("remote").(remote.Remote)
}
func SetEngine(engine engine.Engine) gin.HandlerFunc {
return func(c *gin.Context) {
c.Set("engine", engine)
c.Next()
}
}
func Engine(c *gin.Context) engine.Engine {
return c.MustGet("engine").(engine.Engine)
}

View File

@@ -0,0 +1,28 @@
package middleware
import (
"sync"
"github.com/drone/drone/engine"
"github.com/drone/drone/store"
"github.com/gin-gonic/gin"
)
// Engine is a middleware function that initializes the Engine and attaches to
// the context of every http.Request.
func Engine() gin.HandlerFunc {
var once sync.Once
var engine_ engine.Engine
return func(c *gin.Context) {
once.Do(func() {
store_ := store.FromContext(c)
engine_ = engine.Load(store_)
})
engine.ToContext(c, engine_)
c.Next()
}
}

View File

@@ -1,95 +0,0 @@
package location
import (
"net/http"
"strings"
"github.com/gin-gonic/gin"
)
// Resolve is a middleware function that resolves the hostname
// and scheme for the http.Request and adds to the context.
func Resolve(c *gin.Context) {
c.Set("host", resolveHost(c.Request))
c.Set("scheme", resolveScheme(c.Request))
c.Next()
}
// parseHeader parses non unique headers value
// from a http.Request and return a slice of the values
// queried from the header
func parseHeader(r *http.Request, header string, token string) (val []string) {
for _, v := range r.Header[header] {
options := strings.Split(v, ";")
for _, o := range options {
keyvalue := strings.Split(o, "=")
var key, value string
if len(keyvalue) > 1 {
key, value = strings.TrimSpace(keyvalue[0]), strings.TrimSpace(keyvalue[1])
}
key = strings.ToLower(key)
if key == token {
val = append(val, value)
}
}
}
return
}
// resolveScheme is a helper function that evaluates the http.Request
// and returns the scheme, HTTP or HTTPS. It is able to detect,
// using the X-Forwarded-Proto, if the original request was HTTPS
// and routed through a reverse proxy with SSL termination.
func resolveScheme(r *http.Request) string {
switch {
case r.URL.Scheme == "https":
return "https"
case r.TLS != nil:
return "https"
case strings.HasPrefix(r.Proto, "HTTPS"):
return "https"
case r.Header.Get("X-Forwarded-Proto") == "https":
return "https"
case len(r.Header.Get("Forwarded")) != 0 && len(parseHeader(r, "Forwarded", "proto")) != 0 && parseHeader(r, "Forwarded", "proto")[0] == "https":
return "https"
default:
return "http"
}
}
// resolveHost is a helper function that evaluates the http.Request
// and returns the hostname. It is able to detect, using the
// X-Forarded-For header, the original hostname when routed
// through a reverse proxy.
func resolveHost(r *http.Request) string {
switch {
case len(r.Host) != 0:
return r.Host
case len(r.URL.Host) != 0:
return r.URL.Host
case len(r.Header.Get("X-Forwarded-For")) != 0:
return r.Header.Get("X-Forwarded-For")
case len(r.Header.Get("Forwarded")) != 0 && len(parseHeader(r, "Forwarded", "for")) != 0:
return parseHeader(r, "Forwarded", "for")[0]
case len(r.Header.Get("X-Host")) != 0:
return r.Header.Get("X-Host")
case len(r.Header.Get("Forwarded")) != 0 && len(parseHeader(r, "Forwarded", "host")) != 0:
return parseHeader(r, "Forwarded", "host")[0]
case len(r.Header.Get("XFF")) != 0:
return r.Header.Get("XFF")
case len(r.Header.Get("X-Real-IP")) != 0:
return r.Header.Get("X-Real-IP")
default:
return "localhost:8000"
}
}
// Hostname returns the hostname associated with
// the current context.
func Hostname(c *gin.Context) (host string) {
v, ok := c.Get("host")
if ok {
host = v.(string)
}
return
}

View File

@@ -1,48 +0,0 @@
package location
import (
"github.com/franela/goblin"
"net/http"
"reflect"
"testing"
)
var mockHeader []string
var mockRequest *http.Request
var wronglyFormedHeader []string
var wronglyFormedRequest *http.Request
func init() {
mockHeader = []string{"For= 110.0.2.2", "for = \"[::1]\"; Host=example.com; foR=10.2.3.4; pRoto =https ; By = 127.0.0.1"}
mockRequest = &http.Request{Header: map[string][]string{"Forwarded": mockHeader}}
wronglyFormedHeader = []string{"Fro= 110.0.2.2", "for = \"[:1]\"% Host=example:.com| foR=10.278.3.4% poto =https | Bi % 127.0.0.1", ""}
wronglyFormedRequest = &http.Request{Header: map[string][]string{"Forwarded": wronglyFormedHeader}}
}
func TestParseForwardedHeadersProto(t *testing.T) {
g := goblin.Goblin(t)
g.Describe("Parse proto Forwarded Headers", func() {
g.It("Should parse a normal proto Forwarded header", func() {
parsedHeader := parseHeader(mockRequest, "Forwarded", "proto")
g.Assert("https" == parsedHeader[0]).IsTrue()
})
g.It("Should parse a normal for Forwarded header", func() {
parsedHeader := parseHeader(mockRequest, "Forwarded", "for")
g.Assert(reflect.DeepEqual([]string{"110.0.2.2", "\"[::1]\"", "10.2.3.4"}, parsedHeader)).IsTrue()
})
g.It("Should parse a normal host Forwarded header", func() {
parsedHeader := parseHeader(mockRequest, "Forwarded", "host")
g.Assert("example.com" == parsedHeader[0]).IsTrue()
})
g.It("Should parse a normal by Forwarded header", func() {
parsedHeader := parseHeader(mockRequest, "Forwarded", "by")
g.Assert("127.0.0.1" == parsedHeader[0]).IsTrue()
})
g.It("Should not crash if a wrongly formed Forwarder header is sent", func() {
parsedHeader := parseHeader(wronglyFormedRequest, "Forwarded", "by")
g.Assert(len(parsedHeader) == 0).IsTrue()
})
})
}

View File

@@ -0,0 +1,48 @@
package middleware
import (
"github.com/drone/drone/remote"
"github.com/drone/drone/remote/bitbucket"
"github.com/drone/drone/remote/github"
"github.com/drone/drone/remote/gitlab"
"github.com/drone/drone/remote/gogs"
"github.com/Sirupsen/logrus"
"github.com/gin-gonic/gin"
"github.com/ianschenck/envflag"
"github.com/drone/drone/remote/bitbucketserver"
)
var (
driver = envflag.String("REMOTE_DRIVER", "", "")
config = envflag.String("REMOTE_CONFIG", "", "")
)
// Remote is a middleware function that initializes the Remote and attaches to
// the context of every http.Request.
func Remote() gin.HandlerFunc {
logrus.Infof("using remote driver %s", *driver)
logrus.Infof("using remote config %s", *config)
var remote_ remote.Remote
switch *driver {
case "github":
remote_ = github.Load(*config)
case "bitbucket":
remote_ = bitbucket.Load(*config)
case "gogs":
remote_ = gogs.Load(*config)
case "gitlab":
remote_ = gitlab.Load(*config)
case "bitbucketserver":
remote_ = bitbucketserver.Load(*config)
default:
logrus.Fatalln("remote configuraiton not found")
}
return func(c *gin.Context) {
remote.ToContext(c, remote_)
c.Next()
}
}

View File

@@ -0,0 +1,29 @@
package middleware
import (
"github.com/drone/drone/store"
"github.com/drone/drone/store/datastore"
"github.com/Sirupsen/logrus"
"github.com/gin-gonic/gin"
"github.com/ianschenck/envflag"
)
var (
database = envflag.String("DATABASE_DRIVER", "sqlite3", "")
datasource = envflag.String("DATABASE_CONFIG", "drone.sqlite", "")
)
// Store is a middleware function that initializes the Datastore and attaches to
// the context of every http.Request.
func Store() gin.HandlerFunc {
db := datastore.New(*database, *datasource)
logrus.Infof("using database driver %s", *database)
logrus.Infof("using database config %s", *datasource)
return func(c *gin.Context) {
store.ToContext(c, db)
c.Next()
}
}

View File

@@ -0,0 +1,14 @@
package middleware
import (
"github.com/drone/drone/version"
"github.com/gin-gonic/gin"
)
// Version is a middleware function that appends the Drone
// version information to the HTTP response. This is intended
// for debugging and troubleshooting.
func Version(c *gin.Context) {
c.Header("X-DRONE-VERSION", version.Version)
c.Next()
}

View File

@@ -8,7 +8,6 @@ import (
"github.com/drone/drone/api"
"github.com/drone/drone/router/middleware/header"
"github.com/drone/drone/router/middleware/location"
"github.com/drone/drone/router/middleware/session"
"github.com/drone/drone/router/middleware/token"
"github.com/drone/drone/static"
@@ -17,11 +16,12 @@ import (
)
func Load(middleware ...gin.HandlerFunc) http.Handler {
e := gin.Default()
e := gin.New()
e.Use(gin.Recovery())
e.SetHTMLTemplate(template.Load())
e.StaticFS("/static", static.FileSystem())
e.Use(location.Resolve)
e.Use(header.NoCache)
e.Use(header.Options)
e.Use(header.Secure)
@@ -140,6 +140,13 @@ func Load(middleware ...gin.HandlerFunc) http.Handler {
stream.GET("/:owner/:name/:build/:number", web.GetStream)
}
bots := e.Group("/bots")
{
bots.Use(session.MustUser())
bots.POST("/slack", web.Slack)
bots.POST("/slack/:command", web.Slack)
}
auth := e.Group("/authorize")
{
auth.GET("", web.GetLogin)
@@ -170,7 +177,7 @@ func normalize(h http.Handler) http.Handler {
parts := strings.Split(r.URL.Path, "/")[1:]
switch parts[0] {
case "settings", "repos", "api", "login", "logout", "", "authorize", "hook", "static", "gitlab":
case "settings", "bots", "repos", "api", "login", "logout", "", "authorize", "hook", "static", "gitlab":
// no-op
default: