mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-01-12 03:21:33 +00:00
Merge pull request #646 from smira/update-gin
Upgrade gin-gonic to latest master, fix compatibility issues
This commit is contained in:
35
Gopkg.lock
generated
35
Gopkg.lock
generated
@@ -1,4 +1,4 @@
|
||||
memo = "becdf010a814559719c990c1bd645c737cee332ad52004c440605c13de100d45"
|
||||
memo = "57879f27cc9f82276b92ed638fbc04122c3793ed4a16bea668c9fbfda280c280"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/AlekSi/pointer"
|
||||
@@ -30,10 +30,17 @@ memo = "becdf010a814559719c990c1bd645c737cee332ad52004c440605c13de100d45"
|
||||
revision = "cdf719fac0dd208251aa828e687c2d5802053b51"
|
||||
version = "v1.0.10"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/gin-contrib/sse"
|
||||
packages = ["."]
|
||||
revision = "22d885f9ecc78bf4ee5d72b937e4bbcdc58e8cae"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gin-gonic/gin"
|
||||
packages = [".","binding","render"]
|
||||
revision = "b1758d3bfa09e61ddbc1c9a627e936eec6a170de"
|
||||
revision = "d459835d2b077e44f7c9b453505ee29881d5d12d"
|
||||
version = "v1.2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-ini/ini"
|
||||
@@ -41,6 +48,12 @@ memo = "becdf010a814559719c990c1bd645c737cee332ad52004c440605c13de100d45"
|
||||
revision = "1730955e3146956d6a087861380f9b4667ed5071"
|
||||
version = "v1.26.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/golang/protobuf"
|
||||
packages = ["proto"]
|
||||
revision = "130e6b02ab059e7b717a096f397c5b60111cae74"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/golang/snappy"
|
||||
@@ -66,10 +79,10 @@ memo = "becdf010a814559719c990c1bd645c737cee332ad52004c440605c13de100d45"
|
||||
version = "0.2.2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/julienschmidt/httprouter"
|
||||
name = "github.com/mattn/go-isatty"
|
||||
packages = ["."]
|
||||
revision = "8c199fb6259ffc1af525cc3ad52ee60ba8359669"
|
||||
version = "v1.1"
|
||||
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-runewidth"
|
||||
@@ -184,8 +197,20 @@ memo = "becdf010a814559719c990c1bd645c737cee332ad52004c440605c13de100d45"
|
||||
packages = ["."]
|
||||
revision = "20d25e2804050c1cd24a7eea1e7a6447dd0e74ec"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/go-playground/validator.v8"
|
||||
packages = ["."]
|
||||
revision = "5f1438d3fca68893a817e4a66806cea46a9e4ebf"
|
||||
version = "v8.18.2"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/h2non/filetype.v1"
|
||||
packages = ["types"]
|
||||
revision = "3093b8ebec6efb56ac813238b8beab4ed4eaac6a"
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "v2"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
revision = "eb3733d160e74a9c7e442f435eb3bea458e1d19f"
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
|
||||
[[dependencies]]
|
||||
name = "github.com/gin-gonic/gin"
|
||||
revision = "b1758d3bfa09e61ddbc1c9a627e936eec6a170de"
|
||||
|
||||
[[dependencies]]
|
||||
branch = "master"
|
||||
name = "github.com/mkrautz/goar"
|
||||
|
||||
@@ -112,7 +112,7 @@ func showPackages(c *gin.Context, reflist *deb.PackageRefList) {
|
||||
|
||||
list, err := deb.NewPackageListFromRefList(reflist, context.CollectionFactory().PackageCollection(), nil)
|
||||
if err != nil {
|
||||
c.Fail(404, err)
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ func showPackages(c *gin.Context, reflist *deb.PackageRefList) {
|
||||
if queryS != "" {
|
||||
q, err := query.Parse(c.Request.URL.Query().Get("q"))
|
||||
if err != nil {
|
||||
c.Fail(400, err)
|
||||
c.AbortWithError(400, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ func showPackages(c *gin.Context, reflist *deb.PackageRefList) {
|
||||
sort.Strings(architecturesList)
|
||||
|
||||
if len(architecturesList) == 0 {
|
||||
c.Fail(400, fmt.Errorf("unable to determine list of architectures, please specify explicitly"))
|
||||
c.AbortWithError(400, fmt.Errorf("unable to determine list of architectures, please specify explicitly"))
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -147,7 +147,7 @@ func showPackages(c *gin.Context, reflist *deb.PackageRefList) {
|
||||
list, err = list.Filter([]deb.PackageQuery{q}, withDeps,
|
||||
nil, context.DependencyOptions(), architecturesList)
|
||||
if err != nil {
|
||||
c.Fail(500, fmt.Errorf("unable to search: %s", err))
|
||||
c.AbortWithError(500, fmt.Errorf("unable to search: %s", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
24
api/files.go
24
api/files.go
@@ -24,7 +24,7 @@ func verifyPath(path string) bool {
|
||||
|
||||
func verifyDir(c *gin.Context) bool {
|
||||
if !verifyPath(c.Params.ByName("dir")) {
|
||||
c.Fail(400, fmt.Errorf("wrong dir"))
|
||||
c.AbortWithError(400, fmt.Errorf("wrong dir"))
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ func apiFilesListDirs(c *gin.Context) {
|
||||
})
|
||||
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
c.Fail(400, err)
|
||||
c.AbortWithError(400, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -70,13 +70,13 @@ func apiFilesUpload(c *gin.Context) {
|
||||
err := os.MkdirAll(path, 0777)
|
||||
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = c.Request.ParseMultipartForm(10 * 1024 * 1024)
|
||||
if err != nil {
|
||||
c.Fail(400, err)
|
||||
c.AbortWithError(400, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ func apiFilesUpload(c *gin.Context) {
|
||||
for _, file := range files {
|
||||
src, err := file.Open()
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
defer src.Close()
|
||||
@@ -94,14 +94,14 @@ func apiFilesUpload(c *gin.Context) {
|
||||
destPath := filepath.Join(path, filepath.Base(file.Filename))
|
||||
dst, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
defer dst.Close()
|
||||
|
||||
_, err = io.Copy(dst, src)
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -138,9 +138,9 @@ func apiFilesListFiles(c *gin.Context) {
|
||||
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
c.Fail(404, err)
|
||||
c.AbortWithError(404, err)
|
||||
} else {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -156,7 +156,7 @@ func apiFilesDeleteDir(c *gin.Context) {
|
||||
|
||||
err := os.RemoveAll(filepath.Join(context.UploadPath(), c.Params.ByName("dir")))
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -170,14 +170,14 @@ func apiFilesDeleteFile(c *gin.Context) {
|
||||
}
|
||||
|
||||
if !verifyPath(c.Params.ByName("name")) {
|
||||
c.Fail(400, fmt.Errorf("wrong file"))
|
||||
c.AbortWithError(400, fmt.Errorf("wrong file"))
|
||||
return
|
||||
}
|
||||
|
||||
err := os.Remove(filepath.Join(context.UploadPath(), c.Params.ByName("dir"), c.Params.ByName("name")))
|
||||
if err != nil {
|
||||
if err1, ok := err.(*os.PathError); !ok || !os.IsNotExist(err1.Err) {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,25 +53,25 @@ func apiGraph(c *gin.Context) {
|
||||
|
||||
stdin, err := command.StdinPipe()
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = io.Copy(stdin, buf)
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = stdin.Close()
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
output, err = command.Output()
|
||||
if err != nil {
|
||||
c.Fail(500, fmt.Errorf("unable to execute dot: %s (is graphviz package installed?)", err))
|
||||
c.AbortWithError(500, fmt.Errorf("unable to execute dot: %s (is graphviz package installed?)", err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
func apiPackagesShow(c *gin.Context) {
|
||||
p, err := context.CollectionFactory().PackageCollection().ByKey([]byte(c.Params.ByName("key")))
|
||||
if err != nil {
|
||||
c.Fail(404, err)
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ func apiPublishList(c *gin.Context) {
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -106,18 +106,18 @@ func apiPublishRepoOrSnapshot(c *gin.Context) {
|
||||
Signing SigningOptions
|
||||
}
|
||||
|
||||
if !c.Bind(&b) {
|
||||
if c.Bind(&b) != nil {
|
||||
return
|
||||
}
|
||||
|
||||
signer, err := getSigner(&b.Signing)
|
||||
if err != nil {
|
||||
c.Fail(500, fmt.Errorf("unable to initialize GPG signer: %s", err))
|
||||
c.AbortWithError(500, fmt.Errorf("unable to initialize GPG signer: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
if len(b.Sources) == 0 {
|
||||
c.Fail(400, fmt.Errorf("unable to publish: soures are empty"))
|
||||
c.AbortWithError(400, fmt.Errorf("unable to publish: soures are empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -136,13 +136,13 @@ func apiPublishRepoOrSnapshot(c *gin.Context) {
|
||||
|
||||
snapshot, err = snapshotCollection.ByName(source.Name)
|
||||
if err != nil {
|
||||
c.Fail(404, fmt.Errorf("unable to publish: %s", err))
|
||||
c.AbortWithError(404, fmt.Errorf("unable to publish: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
err = snapshotCollection.LoadComplete(snapshot)
|
||||
if err != nil {
|
||||
c.Fail(500, fmt.Errorf("unable to publish: %s", err))
|
||||
c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -160,19 +160,19 @@ func apiPublishRepoOrSnapshot(c *gin.Context) {
|
||||
|
||||
localRepo, err = localCollection.ByName(source.Name)
|
||||
if err != nil {
|
||||
c.Fail(404, fmt.Errorf("unable to publish: %s", err))
|
||||
c.AbortWithError(404, fmt.Errorf("unable to publish: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
err = localCollection.LoadComplete(localRepo)
|
||||
if err != nil {
|
||||
c.Fail(500, fmt.Errorf("unable to publish: %s", err))
|
||||
c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err))
|
||||
}
|
||||
|
||||
sources = append(sources, localRepo)
|
||||
}
|
||||
} else {
|
||||
c.Fail(400, fmt.Errorf("unknown SourceKind"))
|
||||
c.AbortWithError(400, fmt.Errorf("unknown SourceKind"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ func apiPublishRepoOrSnapshot(c *gin.Context) {
|
||||
|
||||
published, err := deb.NewPublishedRepo(storage, prefix, b.Distribution, b.Architectures, components, sources, context.CollectionFactory())
|
||||
if err != nil {
|
||||
c.Fail(500, fmt.Errorf("unable to publish: %s", err))
|
||||
c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err))
|
||||
return
|
||||
}
|
||||
if b.Origin != "" {
|
||||
@@ -204,19 +204,19 @@ func apiPublishRepoOrSnapshot(c *gin.Context) {
|
||||
duplicate := collection.CheckDuplicate(published)
|
||||
if duplicate != nil {
|
||||
context.CollectionFactory().PublishedRepoCollection().LoadComplete(duplicate, context.CollectionFactory())
|
||||
c.Fail(400, fmt.Errorf("prefix/distribution already used by another published repo: %s", duplicate))
|
||||
c.AbortWithError(400, fmt.Errorf("prefix/distribution already used by another published repo: %s", duplicate))
|
||||
return
|
||||
}
|
||||
|
||||
err = published.Publish(context.PackagePool(), context, context.CollectionFactory(), signer, nil, b.ForceOverwrite)
|
||||
if err != nil {
|
||||
c.Fail(500, fmt.Errorf("unable to publish: %s", err))
|
||||
c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
err = collection.Add(published)
|
||||
if err != nil {
|
||||
c.Fail(500, fmt.Errorf("unable to save to DB: %s", err))
|
||||
c.AbortWithError(500, fmt.Errorf("unable to save to DB: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -240,13 +240,13 @@ func apiPublishUpdateSwitch(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
if !c.Bind(&b) {
|
||||
if c.Bind(&b) != nil {
|
||||
return
|
||||
}
|
||||
|
||||
signer, err := getSigner(&b.Signing)
|
||||
if err != nil {
|
||||
c.Fail(500, fmt.Errorf("unable to initialize GPG signer: %s", err))
|
||||
c.AbortWithError(500, fmt.Errorf("unable to initialize GPG signer: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -265,12 +265,12 @@ func apiPublishUpdateSwitch(c *gin.Context) {
|
||||
|
||||
published, err := collection.ByStoragePrefixDistribution(storage, prefix, distribution)
|
||||
if err != nil {
|
||||
c.Fail(404, fmt.Errorf("unable to update: %s", err))
|
||||
c.AbortWithError(404, fmt.Errorf("unable to update: %s", err))
|
||||
return
|
||||
}
|
||||
err = collection.LoadComplete(published, context.CollectionFactory())
|
||||
if err != nil {
|
||||
c.Fail(500, fmt.Errorf("unable to update: %s", err))
|
||||
c.AbortWithError(500, fmt.Errorf("unable to update: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -278,7 +278,7 @@ func apiPublishUpdateSwitch(c *gin.Context) {
|
||||
|
||||
if published.SourceKind == deb.SourceLocalRepo {
|
||||
if len(b.Snapshots) > 0 {
|
||||
c.Fail(400, fmt.Errorf("snapshots shouldn't be given when updating local repo"))
|
||||
c.AbortWithError(400, fmt.Errorf("snapshots shouldn't be given when updating local repo"))
|
||||
return
|
||||
}
|
||||
updatedComponents = published.Components()
|
||||
@@ -289,19 +289,19 @@ func apiPublishUpdateSwitch(c *gin.Context) {
|
||||
publishedComponents := published.Components()
|
||||
for _, snapshotInfo := range b.Snapshots {
|
||||
if !utils.StrSliceHasItem(publishedComponents, snapshotInfo.Component) {
|
||||
c.Fail(404, fmt.Errorf("component %s is not in published repository", snapshotInfo.Component))
|
||||
c.AbortWithError(404, fmt.Errorf("component %s is not in published repository", snapshotInfo.Component))
|
||||
return
|
||||
}
|
||||
|
||||
snapshot, err2 := snapshotCollection.ByName(snapshotInfo.Name)
|
||||
if err != nil {
|
||||
c.Fail(404, err2)
|
||||
c.AbortWithError(404, err2)
|
||||
return
|
||||
}
|
||||
|
||||
err2 = snapshotCollection.LoadComplete(snapshot)
|
||||
if err2 != nil {
|
||||
c.Fail(500, err2)
|
||||
c.AbortWithError(500, err2)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -309,7 +309,7 @@ func apiPublishUpdateSwitch(c *gin.Context) {
|
||||
updatedComponents = append(updatedComponents, snapshotInfo.Component)
|
||||
}
|
||||
} else {
|
||||
c.Fail(500, fmt.Errorf("unknown published repository type"))
|
||||
c.AbortWithError(500, fmt.Errorf("unknown published repository type"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -319,13 +319,13 @@ func apiPublishUpdateSwitch(c *gin.Context) {
|
||||
|
||||
err = published.Publish(context.PackagePool(), context, context.CollectionFactory(), signer, nil, b.ForceOverwrite)
|
||||
if err != nil {
|
||||
c.Fail(500, fmt.Errorf("unable to update: %s", err))
|
||||
c.AbortWithError(500, fmt.Errorf("unable to update: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
err = collection.Update(published)
|
||||
if err != nil {
|
||||
c.Fail(500, fmt.Errorf("unable to save to DB: %s", err))
|
||||
c.AbortWithError(500, fmt.Errorf("unable to save to DB: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -333,7 +333,7 @@ func apiPublishUpdateSwitch(c *gin.Context) {
|
||||
err = collection.CleanupPrefixComponentFiles(published.Prefix, updatedComponents,
|
||||
context.GetPublishedStorage(storage), context.CollectionFactory(), nil)
|
||||
if err != nil {
|
||||
c.Fail(500, fmt.Errorf("unable to update: %s", err))
|
||||
c.AbortWithError(500, fmt.Errorf("unable to update: %s", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -362,7 +362,7 @@ func apiPublishDrop(c *gin.Context) {
|
||||
err := collection.Remove(context, storage, prefix, distribution,
|
||||
context.CollectionFactory(), context.Progress(), force, skipCleanup)
|
||||
if err != nil {
|
||||
c.Fail(500, fmt.Errorf("unable to drop: %s", err))
|
||||
c.AbortWithError(500, fmt.Errorf("unable to drop: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
52
api/repos.go
52
api/repos.go
@@ -37,7 +37,7 @@ func apiReposCreate(c *gin.Context) {
|
||||
DefaultComponent string
|
||||
}
|
||||
|
||||
if !c.Bind(&b) {
|
||||
if c.Bind(&b) != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func apiReposCreate(c *gin.Context) {
|
||||
|
||||
err := context.CollectionFactory().LocalRepoCollection().Add(repo)
|
||||
if err != nil {
|
||||
c.Fail(400, err)
|
||||
c.AbortWithError(400, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ func apiReposEdit(c *gin.Context) {
|
||||
DefaultComponent *string
|
||||
}
|
||||
|
||||
if !c.Bind(&b) {
|
||||
if c.Bind(&b) != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ func apiReposEdit(c *gin.Context) {
|
||||
|
||||
repo, err := collection.ByName(c.Params.ByName("name"))
|
||||
if err != nil {
|
||||
c.Fail(404, err)
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ func apiReposEdit(c *gin.Context) {
|
||||
|
||||
err = collection.Update(repo)
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ func apiReposShow(c *gin.Context) {
|
||||
|
||||
repo, err := collection.ByName(c.Params.ByName("name"))
|
||||
if err != nil {
|
||||
c.Fail(404, err)
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -132,27 +132,27 @@ func apiReposDrop(c *gin.Context) {
|
||||
|
||||
repo, err := collection.ByName(c.Params.ByName("name"))
|
||||
if err != nil {
|
||||
c.Fail(404, err)
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
||||
published := publishedCollection.ByLocalRepo(repo)
|
||||
if len(published) > 0 {
|
||||
c.Fail(409, fmt.Errorf("unable to drop, local repo is published"))
|
||||
c.AbortWithError(409, fmt.Errorf("unable to drop, local repo is published"))
|
||||
return
|
||||
}
|
||||
|
||||
if !force {
|
||||
snapshots := snapshotCollection.ByLocalRepoSource(repo)
|
||||
if len(snapshots) > 0 {
|
||||
c.Fail(409, fmt.Errorf("unable to drop, local repo has snapshots, use ?force=1 to override"))
|
||||
c.AbortWithError(409, fmt.Errorf("unable to drop, local repo has snapshots, use ?force=1 to override"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = collection.Drop(repo)
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -167,13 +167,13 @@ func apiReposPackagesShow(c *gin.Context) {
|
||||
|
||||
repo, err := collection.ByName(c.Params.ByName("name"))
|
||||
if err != nil {
|
||||
c.Fail(404, err)
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = collection.LoadComplete(repo)
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ func apiReposPackagesAddDelete(c *gin.Context, cb func(list *deb.PackageList, p
|
||||
PackageRefs []string
|
||||
}
|
||||
|
||||
if !c.Bind(&b) {
|
||||
if c.Bind(&b) != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -196,19 +196,19 @@ func apiReposPackagesAddDelete(c *gin.Context, cb func(list *deb.PackageList, p
|
||||
|
||||
repo, err := collection.ByName(c.Params.ByName("name"))
|
||||
if err != nil {
|
||||
c.Fail(404, err)
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = collection.LoadComplete(repo)
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
list, err := deb.NewPackageListFromRefList(repo.RefList(), context.CollectionFactory().PackageCollection(), nil)
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -219,15 +219,15 @@ func apiReposPackagesAddDelete(c *gin.Context, cb func(list *deb.PackageList, p
|
||||
p, err = context.CollectionFactory().PackageCollection().ByKey([]byte(ref))
|
||||
if err != nil {
|
||||
if err == database.ErrNotFound {
|
||||
c.Fail(404, fmt.Errorf("package %s: %s", ref, err))
|
||||
c.AbortWithError(404, fmt.Errorf("package %s: %s", ref, err))
|
||||
} else {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
err = cb(list, p)
|
||||
if err != nil {
|
||||
c.Fail(400, err)
|
||||
c.AbortWithError(400, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -236,7 +236,7 @@ func apiReposPackagesAddDelete(c *gin.Context, cb func(list *deb.PackageList, p
|
||||
|
||||
err = context.CollectionFactory().LocalRepoCollection().Update(repo)
|
||||
if err != nil {
|
||||
c.Fail(500, fmt.Errorf("unable to save: %s", err))
|
||||
c.AbortWithError(500, fmt.Errorf("unable to save: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -276,7 +276,7 @@ func apiReposPackageFromDir(c *gin.Context) {
|
||||
|
||||
fileParam := c.Params.ByName("file")
|
||||
if fileParam != "" && !verifyPath(fileParam) {
|
||||
c.Fail(400, fmt.Errorf("wrong file"))
|
||||
c.AbortWithError(400, fmt.Errorf("wrong file"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -286,13 +286,13 @@ func apiReposPackageFromDir(c *gin.Context) {
|
||||
|
||||
repo, err := collection.ByName(c.Params.ByName("name"))
|
||||
if err != nil {
|
||||
c.Fail(404, err)
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = collection.LoadComplete(repo)
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -320,7 +320,7 @@ func apiReposPackageFromDir(c *gin.Context) {
|
||||
|
||||
list, err = deb.NewPackageListFromRefList(repo.RefList(), context.CollectionFactory().PackageCollection(), nil)
|
||||
if err != nil {
|
||||
c.Fail(500, fmt.Errorf("unable to load packages: %s", err))
|
||||
c.AbortWithError(500, fmt.Errorf("unable to load packages: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -329,7 +329,7 @@ func apiReposPackageFromDir(c *gin.Context) {
|
||||
failedFiles = append(failedFiles, failedFiles2...)
|
||||
|
||||
if err != nil {
|
||||
c.Fail(500, fmt.Errorf("unable to import package files: %s", err))
|
||||
c.AbortWithError(500, fmt.Errorf("unable to import package files: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -337,7 +337,7 @@ func apiReposPackageFromDir(c *gin.Context) {
|
||||
|
||||
err = context.CollectionFactory().LocalRepoCollection().Update(repo)
|
||||
if err != nil {
|
||||
c.Fail(500, fmt.Errorf("unable to save: %s", err))
|
||||
c.AbortWithError(500, fmt.Errorf("unable to save: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ func Router(c *ctx.AptlyContext) http.Handler {
|
||||
|
||||
err = <-errCh
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ func Router(c *ctx.AptlyContext) http.Handler {
|
||||
requests <- dbRequest{releasedb, errCh}
|
||||
err = <-errCh
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ func apiSnapshotsCreateFromMirror(c *gin.Context) {
|
||||
Description string
|
||||
}
|
||||
|
||||
if !c.Bind(&b) {
|
||||
if c.Bind(&b) != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -56,25 +56,25 @@ func apiSnapshotsCreateFromMirror(c *gin.Context) {
|
||||
|
||||
repo, err = collection.ByName(c.Params.ByName("name"))
|
||||
if err != nil {
|
||||
c.Fail(404, err)
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = repo.CheckLock()
|
||||
if err != nil {
|
||||
c.Fail(409, err)
|
||||
c.AbortWithError(409, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = collection.LoadComplete(repo)
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
snapshot, err = deb.NewSnapshotFromRepository(b.Name, repo)
|
||||
if err != nil {
|
||||
c.Fail(400, err)
|
||||
c.AbortWithError(400, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ func apiSnapshotsCreateFromMirror(c *gin.Context) {
|
||||
|
||||
err = snapshotCollection.Add(snapshot)
|
||||
if err != nil {
|
||||
c.Fail(400, err)
|
||||
c.AbortWithError(400, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ func apiSnapshotsCreate(c *gin.Context) {
|
||||
PackageRefs []string
|
||||
}
|
||||
|
||||
if !c.Bind(&b) {
|
||||
if c.Bind(&b) != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -124,13 +124,13 @@ func apiSnapshotsCreate(c *gin.Context) {
|
||||
for i := range b.SourceSnapshots {
|
||||
sources[i], err = snapshotCollection.ByName(b.SourceSnapshots[i])
|
||||
if err != nil {
|
||||
c.Fail(404, err)
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = snapshotCollection.LoadComplete(sources[i])
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -144,15 +144,15 @@ func apiSnapshotsCreate(c *gin.Context) {
|
||||
p, err = context.CollectionFactory().PackageCollection().ByKey([]byte(ref))
|
||||
if err != nil {
|
||||
if err == database.ErrNotFound {
|
||||
c.Fail(404, fmt.Errorf("package %s: %s", ref, err))
|
||||
c.AbortWithError(404, fmt.Errorf("package %s: %s", ref, err))
|
||||
} else {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
err = list.Add(p)
|
||||
if err != nil {
|
||||
c.Fail(400, err)
|
||||
c.AbortWithError(400, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -161,7 +161,7 @@ func apiSnapshotsCreate(c *gin.Context) {
|
||||
|
||||
err = snapshotCollection.Add(snapshot)
|
||||
if err != nil {
|
||||
c.Fail(400, err)
|
||||
c.AbortWithError(400, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ func apiSnapshotsCreateFromRepository(c *gin.Context) {
|
||||
Description string
|
||||
}
|
||||
|
||||
if !c.Bind(&b) {
|
||||
if c.Bind(&b) != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -195,19 +195,19 @@ func apiSnapshotsCreateFromRepository(c *gin.Context) {
|
||||
|
||||
repo, err = collection.ByName(c.Params.ByName("name"))
|
||||
if err != nil {
|
||||
c.Fail(404, err)
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = collection.LoadComplete(repo)
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
snapshot, err = deb.NewSnapshotFromLocalRepo(b.Name, repo)
|
||||
if err != nil {
|
||||
c.Fail(400, err)
|
||||
c.AbortWithError(400, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ func apiSnapshotsCreateFromRepository(c *gin.Context) {
|
||||
|
||||
err = snapshotCollection.Add(snapshot)
|
||||
if err != nil {
|
||||
c.Fail(400, err)
|
||||
c.AbortWithError(400, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -236,7 +236,7 @@ func apiSnapshotsUpdate(c *gin.Context) {
|
||||
Description string
|
||||
}
|
||||
|
||||
if !c.Bind(&b) {
|
||||
if c.Bind(&b) != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -246,13 +246,13 @@ func apiSnapshotsUpdate(c *gin.Context) {
|
||||
|
||||
snapshot, err = collection.ByName(c.Params.ByName("name"))
|
||||
if err != nil {
|
||||
c.Fail(404, err)
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = collection.ByName(b.Name)
|
||||
if err == nil {
|
||||
c.Fail(409, fmt.Errorf("unable to rename: snapshot %s already exists", b.Name))
|
||||
c.AbortWithError(409, fmt.Errorf("unable to rename: snapshot %s already exists", b.Name))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ func apiSnapshotsUpdate(c *gin.Context) {
|
||||
|
||||
err = context.CollectionFactory().SnapshotCollection().Update(snapshot)
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -281,13 +281,13 @@ func apiSnapshotsShow(c *gin.Context) {
|
||||
|
||||
snapshot, err := collection.ByName(c.Params.ByName("name"))
|
||||
if err != nil {
|
||||
c.Fail(404, err)
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = collection.LoadComplete(snapshot)
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -309,28 +309,28 @@ func apiSnapshotsDrop(c *gin.Context) {
|
||||
|
||||
snapshot, err := snapshotCollection.ByName(name)
|
||||
if err != nil {
|
||||
c.Fail(404, err)
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
||||
published := publishedCollection.BySnapshot(snapshot)
|
||||
|
||||
if len(published) > 0 {
|
||||
c.Fail(409, fmt.Errorf("unable to drop: snapshot is published"))
|
||||
c.AbortWithError(409, fmt.Errorf("unable to drop: snapshot is published"))
|
||||
return
|
||||
}
|
||||
|
||||
if !force {
|
||||
snapshots := snapshotCollection.BySnapshotSource(snapshot)
|
||||
if len(snapshots) > 0 {
|
||||
c.Fail(409, fmt.Errorf("won't delete snapshot that was used as source for other snapshots, use ?force=1 to override"))
|
||||
c.AbortWithError(409, fmt.Errorf("won't delete snapshot that was used as source for other snapshots, use ?force=1 to override"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = snapshotCollection.Drop(snapshot)
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -347,32 +347,32 @@ func apiSnapshotsDiff(c *gin.Context) {
|
||||
|
||||
snapshotA, err := collection.ByName(c.Params.ByName("name"))
|
||||
if err != nil {
|
||||
c.Fail(404, err)
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
||||
snapshotB, err := collection.ByName(c.Params.ByName("withSnapshot"))
|
||||
if err != nil {
|
||||
c.Fail(404, err)
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = collection.LoadComplete(snapshotA)
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = collection.LoadComplete(snapshotB)
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Calculate diff
|
||||
diff, err := snapshotA.RefList().Diff(snapshotB.RefList(), context.CollectionFactory().PackageCollection())
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -397,13 +397,13 @@ func apiSnapshotsSearchPackages(c *gin.Context) {
|
||||
|
||||
snapshot, err := collection.ByName(c.Params.ByName("name"))
|
||||
if err != nil {
|
||||
c.Fail(404, err)
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = collection.LoadComplete(snapshot)
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
c.AbortWithError(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ class FilesAPITestSecurity(APITest):
|
||||
|
||||
def check(self):
|
||||
self.check_equal(self.delete("/api/files/.").status_code, 400)
|
||||
self.check_equal(self.delete("/api/files").status_code, 405)
|
||||
self.check_equal(self.delete("/api/files").status_code, 404)
|
||||
self.check_equal(self.delete("/api/files/").status_code, 404)
|
||||
self.check_equal(self.delete("/api/files/../.").status_code, 400)
|
||||
self.check_equal(self.delete("/api/files/./..").status_code, 400)
|
||||
|
||||
@@ -205,7 +205,7 @@ class ReposAPITestShowQuery(APITest):
|
||||
|
||||
resp = self.get("/api/repos/" + repo_name + "/packages", params={"q": "pyspi)"})
|
||||
self.check_equal(resp.status_code, 400)
|
||||
self.check_equal(resp.json()[0]["error"], u'parsing failed: unexpected token ): expecting end of query')
|
||||
self.check_equal(resp.json()["error"], u'parsing failed: unexpected token ): expecting end of query')
|
||||
|
||||
|
||||
class ReposAPITestAddMultiple(APITest):
|
||||
|
||||
15
vendor/github.com/gin-contrib/sse/.travis.yml
generated
vendored
Normal file
15
vendor/github.com/gin-contrib/sse/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
language: go
|
||||
sudo: false
|
||||
go:
|
||||
- 1.6.4
|
||||
- 1.7.4
|
||||
- tip
|
||||
|
||||
git:
|
||||
depth: 3
|
||||
|
||||
script:
|
||||
- go test -v -covermode=count -coverprofile=coverage.out
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
21
vendor/github.com/gin-contrib/sse/LICENSE
generated
vendored
Normal file
21
vendor/github.com/gin-contrib/sse/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Manuel Martínez-Almeida
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
58
vendor/github.com/gin-contrib/sse/README.md
generated
vendored
Normal file
58
vendor/github.com/gin-contrib/sse/README.md
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
# Server-Sent Events
|
||||
|
||||
[](https://godoc.org/github.com/gin-contrib/sse)
|
||||
[](https://travis-ci.org/gin-contrib/sse)
|
||||
[](https://codecov.io/gh/gin-contrib/sse)
|
||||
[](https://goreportcard.com/report/github.com/gin-contrib/sse)
|
||||
|
||||
Server-sent events (SSE) is a technology where a browser receives automatic updates from a server via HTTP connection. The Server-Sent Events EventSource API is [standardized as part of HTML5[1] by the W3C](http://www.w3.org/TR/2009/WD-eventsource-20091029/).
|
||||
|
||||
- [Read this great SSE introduction by the HTML5Rocks guys](http://www.html5rocks.com/en/tutorials/eventsource/basics/)
|
||||
- [Browser support](http://caniuse.com/#feat=eventsource)
|
||||
|
||||
## Sample code
|
||||
|
||||
```go
|
||||
import "github.com/gin-contrib/sse"
|
||||
|
||||
func httpHandler(w http.ResponseWriter, req *http.Request) {
|
||||
// data can be a primitive like a string, an integer or a float
|
||||
sse.Encode(w, sse.Event{
|
||||
Event: "message",
|
||||
Data: "some data\nmore data",
|
||||
})
|
||||
|
||||
// also a complex type, like a map, a struct or a slice
|
||||
sse.Encode(w, sse.Event{
|
||||
Id: "124",
|
||||
Event: "message",
|
||||
Data: map[string]interface{}{
|
||||
"user": "manu",
|
||||
"date": time.Now().Unix(),
|
||||
"content": "hi!",
|
||||
},
|
||||
})
|
||||
}
|
||||
```
|
||||
```
|
||||
event: message
|
||||
data: some data\\nmore data
|
||||
|
||||
id: 124
|
||||
event: message
|
||||
data: {"content":"hi!","date":1431540810,"user":"manu"}
|
||||
|
||||
```
|
||||
|
||||
## Content-Type
|
||||
|
||||
```go
|
||||
fmt.Println(sse.ContentType)
|
||||
```
|
||||
```
|
||||
text/event-stream
|
||||
```
|
||||
|
||||
## Decoding support
|
||||
|
||||
There is a client-side implementation of SSE coming soon.
|
||||
116
vendor/github.com/gin-contrib/sse/sse-decoder.go
generated
vendored
Normal file
116
vendor/github.com/gin-contrib/sse/sse-decoder.go
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sse
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
type decoder struct {
|
||||
events []Event
|
||||
}
|
||||
|
||||
func Decode(r io.Reader) ([]Event, error) {
|
||||
var dec decoder
|
||||
return dec.decode(r)
|
||||
}
|
||||
|
||||
func (d *decoder) dispatchEvent(event Event, data string) {
|
||||
dataLength := len(data)
|
||||
if dataLength > 0 {
|
||||
//If the data buffer's last character is a U+000A LINE FEED (LF) character, then remove the last character from the data buffer.
|
||||
data = data[:dataLength-1]
|
||||
dataLength--
|
||||
}
|
||||
if dataLength == 0 && event.Event == "" {
|
||||
return
|
||||
}
|
||||
if event.Event == "" {
|
||||
event.Event = "message"
|
||||
}
|
||||
event.Data = data
|
||||
d.events = append(d.events, event)
|
||||
}
|
||||
|
||||
func (d *decoder) decode(r io.Reader) ([]Event, error) {
|
||||
buf, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var currentEvent Event
|
||||
var dataBuffer *bytes.Buffer = new(bytes.Buffer)
|
||||
// TODO (and unit tests)
|
||||
// Lines must be separated by either a U+000D CARRIAGE RETURN U+000A LINE FEED (CRLF) character pair,
|
||||
// a single U+000A LINE FEED (LF) character,
|
||||
// or a single U+000D CARRIAGE RETURN (CR) character.
|
||||
lines := bytes.Split(buf, []byte{'\n'})
|
||||
for _, line := range lines {
|
||||
if len(line) == 0 {
|
||||
// If the line is empty (a blank line). Dispatch the event.
|
||||
d.dispatchEvent(currentEvent, dataBuffer.String())
|
||||
|
||||
// reset current event and data buffer
|
||||
currentEvent = Event{}
|
||||
dataBuffer.Reset()
|
||||
continue
|
||||
}
|
||||
if line[0] == byte(':') {
|
||||
// If the line starts with a U+003A COLON character (:), ignore the line.
|
||||
continue
|
||||
}
|
||||
|
||||
var field, value []byte
|
||||
colonIndex := bytes.IndexRune(line, ':')
|
||||
if colonIndex != -1 {
|
||||
// If the line contains a U+003A COLON character character (:)
|
||||
// Collect the characters on the line before the first U+003A COLON character (:),
|
||||
// and let field be that string.
|
||||
field = line[:colonIndex]
|
||||
// Collect the characters on the line after the first U+003A COLON character (:),
|
||||
// and let value be that string.
|
||||
value = line[colonIndex+1:]
|
||||
// If value starts with a single U+0020 SPACE character, remove it from value.
|
||||
if len(value) > 0 && value[0] == ' ' {
|
||||
value = value[1:]
|
||||
}
|
||||
} else {
|
||||
// Otherwise, the string is not empty but does not contain a U+003A COLON character character (:)
|
||||
// Use the whole line as the field name, and the empty string as the field value.
|
||||
field = line
|
||||
value = []byte{}
|
||||
}
|
||||
// The steps to process the field given a field name and a field value depend on the field name,
|
||||
// as given in the following list. Field names must be compared literally,
|
||||
// with no case folding performed.
|
||||
switch string(field) {
|
||||
case "event":
|
||||
// Set the event name buffer to field value.
|
||||
currentEvent.Event = string(value)
|
||||
case "id":
|
||||
// Set the event stream's last event ID to the field value.
|
||||
currentEvent.Id = string(value)
|
||||
case "retry":
|
||||
// If the field value consists of only characters in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9),
|
||||
// then interpret the field value as an integer in base ten, and set the event stream's reconnection time to that integer.
|
||||
// Otherwise, ignore the field.
|
||||
currentEvent.Id = string(value)
|
||||
case "data":
|
||||
// Append the field value to the data buffer,
|
||||
dataBuffer.Write(value)
|
||||
// then append a single U+000A LINE FEED (LF) character to the data buffer.
|
||||
dataBuffer.WriteString("\n")
|
||||
default:
|
||||
//Otherwise. The field is ignored.
|
||||
continue
|
||||
}
|
||||
}
|
||||
// Once the end of the file is reached, the user agent must dispatch the event one final time.
|
||||
d.dispatchEvent(currentEvent, dataBuffer.String())
|
||||
|
||||
return d.events, nil
|
||||
}
|
||||
116
vendor/github.com/gin-contrib/sse/sse-decoder_test.go
generated
vendored
Normal file
116
vendor/github.com/gin-contrib/sse/sse-decoder_test.go
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sse
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDecodeSingle1(t *testing.T) {
|
||||
events, err := Decode(bytes.NewBufferString(
|
||||
`data: this is a text
|
||||
event: message
|
||||
fake:
|
||||
id: 123456789010
|
||||
: we can append data
|
||||
: and multiple comments should not break it
|
||||
data: a very nice one`))
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, events, 1)
|
||||
assert.Equal(t, events[0].Event, "message")
|
||||
assert.Equal(t, events[0].Id, "123456789010")
|
||||
}
|
||||
|
||||
func TestDecodeSingle2(t *testing.T) {
|
||||
events, err := Decode(bytes.NewBufferString(
|
||||
`: starting with a comment
|
||||
fake:
|
||||
|
||||
data:this is a \ntext
|
||||
event:a message\n\n
|
||||
fake
|
||||
:and multiple comments\n should not break it\n\n
|
||||
id:1234567890\n10
|
||||
:we can append data
|
||||
data:a very nice one\n!
|
||||
|
||||
|
||||
`))
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, events, 1)
|
||||
assert.Equal(t, events[0].Event, "a message\\n\\n")
|
||||
assert.Equal(t, events[0].Id, "1234567890\\n10")
|
||||
}
|
||||
|
||||
func TestDecodeSingle3(t *testing.T) {
|
||||
events, err := Decode(bytes.NewBufferString(
|
||||
`
|
||||
id:123456ABCabc789010
|
||||
event: message123
|
||||
: we can append data
|
||||
data:this is a text
|
||||
data: a very nice one
|
||||
data:
|
||||
data
|
||||
: ending with a comment`))
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, events, 1)
|
||||
assert.Equal(t, events[0].Event, "message123")
|
||||
assert.Equal(t, events[0].Id, "123456ABCabc789010")
|
||||
}
|
||||
|
||||
func TestDecodeMulti1(t *testing.T) {
|
||||
events, err := Decode(bytes.NewBufferString(
|
||||
`
|
||||
id:
|
||||
event: weird event
|
||||
data:this is a text
|
||||
:data: this should NOT APER
|
||||
data: second line
|
||||
|
||||
: a comment
|
||||
event: message
|
||||
id:123
|
||||
data:this is a text
|
||||
:data: this should NOT APER
|
||||
data: second line
|
||||
|
||||
|
||||
: a comment
|
||||
event: message
|
||||
id:123
|
||||
data:this is a text
|
||||
data: second line
|
||||
|
||||
:hola
|
||||
|
||||
data
|
||||
|
||||
event:
|
||||
|
||||
id`))
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, events, 3)
|
||||
assert.Equal(t, events[0].Event, "weird event")
|
||||
assert.Equal(t, events[0].Id, "")
|
||||
}
|
||||
|
||||
func TestDecodeW3C(t *testing.T) {
|
||||
events, err := Decode(bytes.NewBufferString(
|
||||
`data
|
||||
|
||||
data
|
||||
data
|
||||
|
||||
data:
|
||||
`))
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, events, 1)
|
||||
}
|
||||
110
vendor/github.com/gin-contrib/sse/sse-encoder.go
generated
vendored
Normal file
110
vendor/github.com/gin-contrib/sse/sse-encoder.go
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sse
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Server-Sent Events
|
||||
// W3C Working Draft 29 October 2009
|
||||
// http://www.w3.org/TR/2009/WD-eventsource-20091029/
|
||||
|
||||
const ContentType = "text/event-stream"
|
||||
|
||||
var contentType = []string{ContentType}
|
||||
var noCache = []string{"no-cache"}
|
||||
|
||||
var fieldReplacer = strings.NewReplacer(
|
||||
"\n", "\\n",
|
||||
"\r", "\\r")
|
||||
|
||||
var dataReplacer = strings.NewReplacer(
|
||||
"\n", "\ndata:",
|
||||
"\r", "\\r")
|
||||
|
||||
type Event struct {
|
||||
Event string
|
||||
Id string
|
||||
Retry uint
|
||||
Data interface{}
|
||||
}
|
||||
|
||||
func Encode(writer io.Writer, event Event) error {
|
||||
w := checkWriter(writer)
|
||||
writeId(w, event.Id)
|
||||
writeEvent(w, event.Event)
|
||||
writeRetry(w, event.Retry)
|
||||
return writeData(w, event.Data)
|
||||
}
|
||||
|
||||
func writeId(w stringWriter, id string) {
|
||||
if len(id) > 0 {
|
||||
w.WriteString("id:")
|
||||
fieldReplacer.WriteString(w, id)
|
||||
w.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
func writeEvent(w stringWriter, event string) {
|
||||
if len(event) > 0 {
|
||||
w.WriteString("event:")
|
||||
fieldReplacer.WriteString(w, event)
|
||||
w.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
func writeRetry(w stringWriter, retry uint) {
|
||||
if retry > 0 {
|
||||
w.WriteString("retry:")
|
||||
w.WriteString(strconv.FormatUint(uint64(retry), 10))
|
||||
w.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
func writeData(w stringWriter, data interface{}) error {
|
||||
w.WriteString("data:")
|
||||
switch kindOfData(data) {
|
||||
case reflect.Struct, reflect.Slice, reflect.Map:
|
||||
err := json.NewEncoder(w).Encode(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.WriteString("\n")
|
||||
default:
|
||||
dataReplacer.WriteString(w, fmt.Sprint(data))
|
||||
w.WriteString("\n\n")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r Event) Render(w http.ResponseWriter) error {
|
||||
r.WriteContentType(w)
|
||||
return Encode(w, r)
|
||||
}
|
||||
|
||||
func (r Event) WriteContentType(w http.ResponseWriter) {
|
||||
header := w.Header()
|
||||
header["Content-Type"] = contentType
|
||||
|
||||
if _, exist := header["Cache-Control"]; !exist {
|
||||
header["Cache-Control"] = noCache
|
||||
}
|
||||
}
|
||||
|
||||
func kindOfData(data interface{}) reflect.Kind {
|
||||
value := reflect.ValueOf(data)
|
||||
valueType := value.Kind()
|
||||
if valueType == reflect.Ptr {
|
||||
valueType = value.Elem().Kind()
|
||||
}
|
||||
return valueType
|
||||
}
|
||||
255
vendor/github.com/gin-contrib/sse/sse_test.go
generated
vendored
Normal file
255
vendor/github.com/gin-contrib/sse/sse_test.go
generated
vendored
Normal file
@@ -0,0 +1,255 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sse
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEncodeOnlyData(t *testing.T) {
|
||||
w := new(bytes.Buffer)
|
||||
event := Event{
|
||||
Data: "junk\n\njk\nid:fake",
|
||||
}
|
||||
err := Encode(w, event)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, w.String(),
|
||||
`data:junk
|
||||
data:
|
||||
data:jk
|
||||
data:id:fake
|
||||
|
||||
`)
|
||||
|
||||
decoded, _ := Decode(w)
|
||||
assert.Equal(t, decoded, []Event{event})
|
||||
}
|
||||
|
||||
func TestEncodeWithEvent(t *testing.T) {
|
||||
w := new(bytes.Buffer)
|
||||
event := Event{
|
||||
Event: "t\n:<>\r\test",
|
||||
Data: "junk\n\njk\nid:fake",
|
||||
}
|
||||
err := Encode(w, event)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, w.String(),
|
||||
`event:t\n:<>\r est
|
||||
data:junk
|
||||
data:
|
||||
data:jk
|
||||
data:id:fake
|
||||
|
||||
`)
|
||||
|
||||
decoded, _ := Decode(w)
|
||||
assert.Equal(t, decoded, []Event{event})
|
||||
}
|
||||
|
||||
func TestEncodeWithId(t *testing.T) {
|
||||
w := new(bytes.Buffer)
|
||||
err := Encode(w, Event{
|
||||
Id: "t\n:<>\r\test",
|
||||
Data: "junk\n\njk\nid:fa\rke",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, w.String(),
|
||||
`id:t\n:<>\r est
|
||||
data:junk
|
||||
data:
|
||||
data:jk
|
||||
data:id:fa\rke
|
||||
|
||||
`)
|
||||
}
|
||||
|
||||
func TestEncodeWithRetry(t *testing.T) {
|
||||
w := new(bytes.Buffer)
|
||||
err := Encode(w, Event{
|
||||
Retry: 11,
|
||||
Data: "junk\n\njk\nid:fake\n",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, w.String(),
|
||||
`retry:11
|
||||
data:junk
|
||||
data:
|
||||
data:jk
|
||||
data:id:fake
|
||||
data:
|
||||
|
||||
`)
|
||||
}
|
||||
|
||||
func TestEncodeWithEverything(t *testing.T) {
|
||||
w := new(bytes.Buffer)
|
||||
err := Encode(w, Event{
|
||||
Event: "abc",
|
||||
Id: "12345",
|
||||
Retry: 10,
|
||||
Data: "some data",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, w.String(), "id:12345\nevent:abc\nretry:10\ndata:some data\n\n")
|
||||
}
|
||||
|
||||
func TestEncodeMap(t *testing.T) {
|
||||
w := new(bytes.Buffer)
|
||||
err := Encode(w, Event{
|
||||
Event: "a map",
|
||||
Data: map[string]interface{}{
|
||||
"foo": "b\n\rar",
|
||||
"bar": "id: 2",
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, w.String(), "event:a map\ndata:{\"bar\":\"id: 2\",\"foo\":\"b\\n\\rar\"}\n\n")
|
||||
}
|
||||
|
||||
func TestEncodeSlice(t *testing.T) {
|
||||
w := new(bytes.Buffer)
|
||||
err := Encode(w, Event{
|
||||
Event: "a slice",
|
||||
Data: []interface{}{1, "text", map[string]interface{}{"foo": "bar"}},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, w.String(), "event:a slice\ndata:[1,\"text\",{\"foo\":\"bar\"}]\n\n")
|
||||
}
|
||||
|
||||
func TestEncodeStruct(t *testing.T) {
|
||||
myStruct := struct {
|
||||
A int
|
||||
B string `json:"value"`
|
||||
}{1, "number"}
|
||||
|
||||
w := new(bytes.Buffer)
|
||||
err := Encode(w, Event{
|
||||
Event: "a struct",
|
||||
Data: myStruct,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, w.String(), "event:a struct\ndata:{\"A\":1,\"value\":\"number\"}\n\n")
|
||||
|
||||
w.Reset()
|
||||
err = Encode(w, Event{
|
||||
Event: "a struct",
|
||||
Data: &myStruct,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, w.String(), "event:a struct\ndata:{\"A\":1,\"value\":\"number\"}\n\n")
|
||||
}
|
||||
|
||||
func TestEncodeInteger(t *testing.T) {
|
||||
w := new(bytes.Buffer)
|
||||
err := Encode(w, Event{
|
||||
Event: "an integer",
|
||||
Data: 1,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, w.String(), "event:an integer\ndata:1\n\n")
|
||||
}
|
||||
|
||||
func TestEncodeFloat(t *testing.T) {
|
||||
w := new(bytes.Buffer)
|
||||
err := Encode(w, Event{
|
||||
Event: "Float",
|
||||
Data: 1.5,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, w.String(), "event:Float\ndata:1.5\n\n")
|
||||
}
|
||||
|
||||
func TestEncodeStream(t *testing.T) {
|
||||
w := new(bytes.Buffer)
|
||||
|
||||
Encode(w, Event{
|
||||
Event: "float",
|
||||
Data: 1.5,
|
||||
})
|
||||
|
||||
Encode(w, Event{
|
||||
Id: "123",
|
||||
Data: map[string]interface{}{"foo": "bar", "bar": "foo"},
|
||||
})
|
||||
|
||||
Encode(w, Event{
|
||||
Id: "124",
|
||||
Event: "chat",
|
||||
Data: "hi! dude",
|
||||
})
|
||||
assert.Equal(t, w.String(), "event:float\ndata:1.5\n\nid:123\ndata:{\"bar\":\"foo\",\"foo\":\"bar\"}\n\nid:124\nevent:chat\ndata:hi! dude\n\n")
|
||||
}
|
||||
|
||||
func TestRenderSSE(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
err := (Event{
|
||||
Event: "msg",
|
||||
Data: "hi! how are you?",
|
||||
}).Render(w)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, w.Body.String(), "event:msg\ndata:hi! how are you?\n\n")
|
||||
assert.Equal(t, w.Header().Get("Content-Type"), "text/event-stream")
|
||||
assert.Equal(t, w.Header().Get("Cache-Control"), "no-cache")
|
||||
}
|
||||
|
||||
func BenchmarkResponseWriter(b *testing.B) {
|
||||
w := httptest.NewRecorder()
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
(Event{
|
||||
Event: "new_message",
|
||||
Data: "hi! how are you? I am fine. this is a long stupid message!!!",
|
||||
}).Render(w)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFullSSE(b *testing.B) {
|
||||
buf := new(bytes.Buffer)
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Encode(buf, Event{
|
||||
Event: "new_message",
|
||||
Id: "13435",
|
||||
Retry: 10,
|
||||
Data: "hi! how are you? I am fine. this is a long stupid message!!!",
|
||||
})
|
||||
buf.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNoRetrySSE(b *testing.B) {
|
||||
buf := new(bytes.Buffer)
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Encode(buf, Event{
|
||||
Event: "new_message",
|
||||
Id: "13435",
|
||||
Data: "hi! how are you? I am fine. this is a long stupid message!!!",
|
||||
})
|
||||
buf.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSimpleSSE(b *testing.B) {
|
||||
buf := new(bytes.Buffer)
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Encode(buf, Event{
|
||||
Event: "new_message",
|
||||
Data: "hi! how are you? I am fine. this is a long stupid message!!!",
|
||||
})
|
||||
buf.Reset()
|
||||
}
|
||||
}
|
||||
24
vendor/github.com/gin-contrib/sse/writer.go
generated
vendored
Normal file
24
vendor/github.com/gin-contrib/sse/writer.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
package sse
|
||||
|
||||
import "io"
|
||||
|
||||
type stringWriter interface {
|
||||
io.Writer
|
||||
WriteString(string) (int, error)
|
||||
}
|
||||
|
||||
type stringWrapper struct {
|
||||
io.Writer
|
||||
}
|
||||
|
||||
func (w stringWrapper) WriteString(str string) (int, error) {
|
||||
return w.Writer.Write([]byte(str))
|
||||
}
|
||||
|
||||
func checkWriter(writer io.Writer) stringWriter {
|
||||
if w, ok := writer.(stringWriter); ok {
|
||||
return w
|
||||
} else {
|
||||
return stringWrapper{writer}
|
||||
}
|
||||
}
|
||||
6
vendor/github.com/gin-gonic/gin/.gitignore
generated
vendored
6
vendor/github.com/gin-gonic/gin/.gitignore
generated
vendored
@@ -1,2 +1,4 @@
|
||||
Godeps/*
|
||||
!Godeps/Godeps.json
|
||||
vendor/*
|
||||
!vendor/vendor.json
|
||||
coverage.out
|
||||
count.out
|
||||
|
||||
31
vendor/github.com/gin-gonic/gin/.travis.yml
generated
vendored
31
vendor/github.com/gin-gonic/gin/.travis.yml
generated
vendored
@@ -1,6 +1,31 @@
|
||||
language: go
|
||||
sudo: false
|
||||
go:
|
||||
- 1.3
|
||||
- 1.4
|
||||
- tip
|
||||
- 1.6.x
|
||||
- 1.7.x
|
||||
- 1.8.x
|
||||
- master
|
||||
|
||||
git:
|
||||
depth: 3
|
||||
|
||||
install:
|
||||
- make install
|
||||
|
||||
script:
|
||||
- make vet
|
||||
- make fmt-check
|
||||
- make embedmd
|
||||
- make misspell-check
|
||||
- make test
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/7f95bf605c4d356372f4
|
||||
on_success: change # options: [always|never|change] default: always
|
||||
on_failure: always # options: [always|never|change] default: always
|
||||
on_start: false # default: false
|
||||
|
||||
65
vendor/github.com/gin-gonic/gin/AUTHORS.md
generated
vendored
65
vendor/github.com/gin-gonic/gin/AUTHORS.md
generated
vendored
@@ -1,14 +1,15 @@
|
||||
List of all the awesome people working to make Gin the best Web Framework in Go.
|
||||
|
||||
## gin 0.x series authors
|
||||
|
||||
|
||||
##gin 0.x series authors
|
||||
|
||||
**Original Developer:** Manu Martinez-Almeida (@manucorporat)
|
||||
**Long-term Maintainer:** Javier Provecho (@javierprovecho)
|
||||
**Maintainer:** Manu Martinez-Almeida (@manucorporat), Javier Provecho (@javierprovecho)
|
||||
|
||||
People and companies, who have contributed, in alphabetical order.
|
||||
|
||||
**@858806258 (杰哥)**
|
||||
- Fix typo in example
|
||||
|
||||
|
||||
**@achedeuzot (Klemen Sever)**
|
||||
- Fix newline debug printing
|
||||
|
||||
@@ -21,6 +22,10 @@ People and companies, who have contributed, in alphabetical order.
|
||||
- Typos in README
|
||||
|
||||
|
||||
**@alexanderdidenko (Aleksandr Didenko)**
|
||||
- Add support multipart/form-data
|
||||
|
||||
|
||||
**@alexandernyquist (Alexander Nyquist)**
|
||||
- Using template.Must to fix multiple return issue
|
||||
- ★ Added support for OPTIONS verb
|
||||
@@ -55,15 +60,39 @@ People and companies, who have contributed, in alphabetical order.
|
||||
- Add example about serving static files
|
||||
|
||||
|
||||
**@donileo (Adonis)**
|
||||
- Add NoMethod handler
|
||||
|
||||
|
||||
**@dutchcoders (DutchCoders)**
|
||||
- ★ Fix security bug that allows client to spoof ip
|
||||
- Fix typo. r.HTMLTemplates -> SetHTMLTemplate
|
||||
|
||||
|
||||
**@el3ctro- (Joshua Loper)**
|
||||
- Fix typo in example
|
||||
|
||||
|
||||
**@ethankan (Ethan Kan)**
|
||||
- Unsigned integers in binding
|
||||
|
||||
|
||||
**(Evgeny Persienko)**
|
||||
- Validate sub structures
|
||||
|
||||
|
||||
**@frankbille (Frank Bille)**
|
||||
- Add support for HTTP Realm Auth
|
||||
|
||||
|
||||
**@fmd (Fareed Dudhia)**
|
||||
- Fix typo. SetHTTPTemplate -> SetHTMLTemplate
|
||||
|
||||
|
||||
**@ironiridis (Christopher Harrington)**
|
||||
- Remove old reference
|
||||
|
||||
|
||||
**@jammie-stackhouse (Jamie Stackhouse)**
|
||||
- Add more shortcuts for router methods
|
||||
|
||||
@@ -104,6 +133,10 @@ People and companies, who have contributed, in alphabetical order.
|
||||
- ★ work around path.Join removing trailing slashes from routes
|
||||
|
||||
|
||||
**@mattn (Yasuhiro Matsumoto)**
|
||||
- Improve color logger
|
||||
|
||||
|
||||
**@mdigger (Dmitry Sedykh)**
|
||||
- Fixes Form binding when content-type is x-www-form-urlencoded
|
||||
- No repeat call c.Writer.Status() in gin.Logger
|
||||
@@ -138,10 +171,22 @@ People and companies, who have contributed, in alphabetical order.
|
||||
- Fix Port usage in README.
|
||||
|
||||
|
||||
**@rayrod2030 (Ray Rodriguez)**
|
||||
- Fix typo in example
|
||||
|
||||
|
||||
**@rns**
|
||||
- Fix typo in example
|
||||
|
||||
|
||||
**@RobAWilkinson (Robert Wilkinson)**
|
||||
- Add example of forms and params
|
||||
|
||||
|
||||
**@rogierlommers (Rogier Lommers)**
|
||||
- Add updated static serve example
|
||||
|
||||
|
||||
**@se77en (Damon Zhao)**
|
||||
- Improve color logging
|
||||
|
||||
@@ -166,9 +211,17 @@ People and companies, who have contributed, in alphabetical order.
|
||||
- Update httprouter godeps
|
||||
|
||||
|
||||
**@tebeka (Miki Tebeka)**
|
||||
- Use net/http constants instead of numeric values
|
||||
|
||||
|
||||
**@techjanitor**
|
||||
- Update context.go reserved IPs
|
||||
|
||||
|
||||
**@yosssi (Keiji Yoshida)**
|
||||
- Fix link in README
|
||||
|
||||
|
||||
**@yuyabee**
|
||||
- Fixed README
|
||||
- Fixed README
|
||||
|
||||
298
vendor/github.com/gin-gonic/gin/BENCHMARKS.md
generated
vendored
Normal file
298
vendor/github.com/gin-gonic/gin/BENCHMARKS.md
generated
vendored
Normal file
@@ -0,0 +1,298 @@
|
||||
**Machine:** intel i7 ivy bridge quad-core. 8GB RAM.
|
||||
**Date:** June 4th, 2015
|
||||
[https://github.com/gin-gonic/go-http-routing-benchmark](https://github.com/gin-gonic/go-http-routing-benchmark)
|
||||
|
||||
```
|
||||
BenchmarkAce_Param 5000000 372 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkBear_Param 1000000 1165 ns/op 424 B/op 5 allocs/op
|
||||
BenchmarkBeego_Param 1000000 2440 ns/op 720 B/op 10 allocs/op
|
||||
BenchmarkBone_Param 1000000 1067 ns/op 384 B/op 3 allocs/op
|
||||
BenchmarkDenco_Param 5000000 240 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkEcho_Param 10000000 130 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGin_Param 10000000 133 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_Param 1000000 1826 ns/op 656 B/op 9 allocs/op
|
||||
BenchmarkGoji_Param 2000000 957 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGoJsonRest_Param 1000000 2021 ns/op 657 B/op 14 allocs/op
|
||||
BenchmarkGoRestful_Param 200000 8825 ns/op 2496 B/op 31 allocs/op
|
||||
BenchmarkGorillaMux_Param 500000 3340 ns/op 784 B/op 9 allocs/op
|
||||
BenchmarkHttpRouter_Param 10000000 152 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_Param 2000000 717 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkKocha_Param 3000000 423 ns/op 56 B/op 3 allocs/op
|
||||
BenchmarkMacaron_Param 1000000 3410 ns/op 1104 B/op 11 allocs/op
|
||||
BenchmarkMartini_Param 200000 7101 ns/op 1152 B/op 12 allocs/op
|
||||
BenchmarkPat_Param 1000000 2040 ns/op 656 B/op 14 allocs/op
|
||||
BenchmarkPossum_Param 1000000 2048 ns/op 624 B/op 7 allocs/op
|
||||
BenchmarkR2router_Param 1000000 1144 ns/op 432 B/op 6 allocs/op
|
||||
BenchmarkRevel_Param 200000 6725 ns/op 1672 B/op 28 allocs/op
|
||||
BenchmarkRivet_Param 1000000 1121 ns/op 464 B/op 5 allocs/op
|
||||
BenchmarkTango_Param 1000000 1479 ns/op 256 B/op 10 allocs/op
|
||||
BenchmarkTigerTonic_Param 1000000 3393 ns/op 992 B/op 19 allocs/op
|
||||
BenchmarkTraffic_Param 300000 5525 ns/op 1984 B/op 23 allocs/op
|
||||
BenchmarkVulcan_Param 2000000 924 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkZeus_Param 1000000 1084 ns/op 368 B/op 3 allocs/op
|
||||
BenchmarkAce_Param5 3000000 614 ns/op 160 B/op 1 allocs/op
|
||||
BenchmarkBear_Param5 1000000 1617 ns/op 469 B/op 5 allocs/op
|
||||
BenchmarkBeego_Param5 1000000 3373 ns/op 992 B/op 13 allocs/op
|
||||
BenchmarkBone_Param5 1000000 1478 ns/op 432 B/op 3 allocs/op
|
||||
BenchmarkDenco_Param5 3000000 570 ns/op 160 B/op 1 allocs/op
|
||||
BenchmarkEcho_Param5 5000000 256 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGin_Param5 10000000 222 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_Param5 1000000 2789 ns/op 928 B/op 12 allocs/op
|
||||
BenchmarkGoji_Param5 1000000 1287 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGoJsonRest_Param5 1000000 3670 ns/op 1105 B/op 17 allocs/op
|
||||
BenchmarkGoRestful_Param5 200000 10756 ns/op 2672 B/op 31 allocs/op
|
||||
BenchmarkGorillaMux_Param5 300000 5543 ns/op 912 B/op 9 allocs/op
|
||||
BenchmarkHttpRouter_Param5 5000000 403 ns/op 160 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_Param5 1000000 1089 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkKocha_Param5 1000000 1682 ns/op 440 B/op 10 allocs/op
|
||||
BenchmarkMacaron_Param5 300000 4596 ns/op 1376 B/op 14 allocs/op
|
||||
BenchmarkMartini_Param5 100000 15703 ns/op 1280 B/op 12 allocs/op
|
||||
BenchmarkPat_Param5 300000 5320 ns/op 1008 B/op 42 allocs/op
|
||||
BenchmarkPossum_Param5 1000000 2155 ns/op 624 B/op 7 allocs/op
|
||||
BenchmarkR2router_Param5 1000000 1559 ns/op 432 B/op 6 allocs/op
|
||||
BenchmarkRevel_Param5 200000 8184 ns/op 2024 B/op 35 allocs/op
|
||||
BenchmarkRivet_Param5 1000000 1914 ns/op 528 B/op 9 allocs/op
|
||||
BenchmarkTango_Param5 1000000 3280 ns/op 944 B/op 18 allocs/op
|
||||
BenchmarkTigerTonic_Param5 200000 11638 ns/op 2519 B/op 53 allocs/op
|
||||
BenchmarkTraffic_Param5 200000 8941 ns/op 2280 B/op 31 allocs/op
|
||||
BenchmarkVulcan_Param5 1000000 1279 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkZeus_Param5 1000000 1574 ns/op 416 B/op 3 allocs/op
|
||||
BenchmarkAce_Param20 1000000 1528 ns/op 640 B/op 1 allocs/op
|
||||
BenchmarkBear_Param20 300000 4906 ns/op 1633 B/op 5 allocs/op
|
||||
BenchmarkBeego_Param20 200000 10529 ns/op 3868 B/op 17 allocs/op
|
||||
BenchmarkBone_Param20 300000 7362 ns/op 2539 B/op 5 allocs/op
|
||||
BenchmarkDenco_Param20 1000000 1884 ns/op 640 B/op 1 allocs/op
|
||||
BenchmarkEcho_Param20 2000000 689 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGin_Param20 3000000 545 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_Param20 200000 9437 ns/op 3804 B/op 16 allocs/op
|
||||
BenchmarkGoji_Param20 500000 3987 ns/op 1246 B/op 2 allocs/op
|
||||
BenchmarkGoJsonRest_Param20 100000 12799 ns/op 4492 B/op 21 allocs/op
|
||||
BenchmarkGoRestful_Param20 100000 19451 ns/op 5244 B/op 33 allocs/op
|
||||
BenchmarkGorillaMux_Param20 100000 12456 ns/op 3275 B/op 11 allocs/op
|
||||
BenchmarkHttpRouter_Param20 1000000 1333 ns/op 640 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_Param20 300000 6490 ns/op 2187 B/op 4 allocs/op
|
||||
BenchmarkKocha_Param20 300000 5335 ns/op 1808 B/op 27 allocs/op
|
||||
BenchmarkMacaron_Param20 200000 11325 ns/op 4252 B/op 18 allocs/op
|
||||
BenchmarkMartini_Param20 20000 64419 ns/op 3644 B/op 14 allocs/op
|
||||
BenchmarkPat_Param20 50000 24672 ns/op 4888 B/op 151 allocs/op
|
||||
BenchmarkPossum_Param20 1000000 2085 ns/op 624 B/op 7 allocs/op
|
||||
BenchmarkR2router_Param20 300000 6809 ns/op 2283 B/op 8 allocs/op
|
||||
BenchmarkRevel_Param20 100000 16600 ns/op 5551 B/op 54 allocs/op
|
||||
BenchmarkRivet_Param20 200000 8428 ns/op 2620 B/op 26 allocs/op
|
||||
BenchmarkTango_Param20 100000 16302 ns/op 8224 B/op 48 allocs/op
|
||||
BenchmarkTigerTonic_Param20 30000 46828 ns/op 10538 B/op 178 allocs/op
|
||||
BenchmarkTraffic_Param20 50000 28871 ns/op 7998 B/op 66 allocs/op
|
||||
BenchmarkVulcan_Param20 1000000 2267 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkZeus_Param20 300000 6828 ns/op 2507 B/op 5 allocs/op
|
||||
BenchmarkAce_ParamWrite 3000000 502 ns/op 40 B/op 2 allocs/op
|
||||
BenchmarkBear_ParamWrite 1000000 1303 ns/op 424 B/op 5 allocs/op
|
||||
BenchmarkBeego_ParamWrite 1000000 2489 ns/op 728 B/op 11 allocs/op
|
||||
BenchmarkBone_ParamWrite 1000000 1181 ns/op 384 B/op 3 allocs/op
|
||||
BenchmarkDenco_ParamWrite 5000000 315 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkEcho_ParamWrite 10000000 237 ns/op 8 B/op 1 allocs/op
|
||||
BenchmarkGin_ParamWrite 5000000 336 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_ParamWrite 1000000 2079 ns/op 664 B/op 10 allocs/op
|
||||
BenchmarkGoji_ParamWrite 1000000 1092 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGoJsonRest_ParamWrite 1000000 3329 ns/op 1136 B/op 19 allocs/op
|
||||
BenchmarkGoRestful_ParamWrite 200000 9273 ns/op 2504 B/op 32 allocs/op
|
||||
BenchmarkGorillaMux_ParamWrite 500000 3919 ns/op 792 B/op 10 allocs/op
|
||||
BenchmarkHttpRouter_ParamWrite 10000000 223 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_ParamWrite 2000000 788 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkKocha_ParamWrite 3000000 549 ns/op 56 B/op 3 allocs/op
|
||||
BenchmarkMacaron_ParamWrite 500000 4558 ns/op 1216 B/op 16 allocs/op
|
||||
BenchmarkMartini_ParamWrite 200000 8850 ns/op 1256 B/op 16 allocs/op
|
||||
BenchmarkPat_ParamWrite 500000 3679 ns/op 1088 B/op 19 allocs/op
|
||||
BenchmarkPossum_ParamWrite 1000000 2114 ns/op 624 B/op 7 allocs/op
|
||||
BenchmarkR2router_ParamWrite 1000000 1320 ns/op 432 B/op 6 allocs/op
|
||||
BenchmarkRevel_ParamWrite 200000 8048 ns/op 2128 B/op 33 allocs/op
|
||||
BenchmarkRivet_ParamWrite 1000000 1393 ns/op 472 B/op 6 allocs/op
|
||||
BenchmarkTango_ParamWrite 2000000 819 ns/op 136 B/op 5 allocs/op
|
||||
BenchmarkTigerTonic_ParamWrite 300000 5860 ns/op 1440 B/op 25 allocs/op
|
||||
BenchmarkTraffic_ParamWrite 200000 7429 ns/op 2400 B/op 27 allocs/op
|
||||
BenchmarkVulcan_ParamWrite 2000000 972 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkZeus_ParamWrite 1000000 1226 ns/op 368 B/op 3 allocs/op
|
||||
BenchmarkAce_GithubStatic 5000000 294 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkBear_GithubStatic 3000000 575 ns/op 88 B/op 3 allocs/op
|
||||
BenchmarkBeego_GithubStatic 1000000 1561 ns/op 368 B/op 7 allocs/op
|
||||
BenchmarkBone_GithubStatic 200000 12301 ns/op 2880 B/op 60 allocs/op
|
||||
BenchmarkDenco_GithubStatic 20000000 74.6 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkEcho_GithubStatic 10000000 176 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGin_GithubStatic 10000000 159 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_GithubStatic 1000000 1116 ns/op 304 B/op 6 allocs/op
|
||||
BenchmarkGoji_GithubStatic 5000000 413 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGoRestful_GithubStatic 30000 55200 ns/op 3520 B/op 36 allocs/op
|
||||
BenchmarkGoJsonRest_GithubStatic 1000000 1504 ns/op 337 B/op 12 allocs/op
|
||||
BenchmarkGorillaMux_GithubStatic 100000 23620 ns/op 464 B/op 8 allocs/op
|
||||
BenchmarkHttpRouter_GithubStatic 20000000 78.3 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkHttpTreeMux_GithubStatic 20000000 84.9 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkKocha_GithubStatic 20000000 111 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_GithubStatic 1000000 2686 ns/op 752 B/op 8 allocs/op
|
||||
BenchmarkMartini_GithubStatic 100000 22244 ns/op 832 B/op 11 allocs/op
|
||||
BenchmarkPat_GithubStatic 100000 13278 ns/op 3648 B/op 76 allocs/op
|
||||
BenchmarkPossum_GithubStatic 1000000 1429 ns/op 480 B/op 4 allocs/op
|
||||
BenchmarkR2router_GithubStatic 2000000 726 ns/op 144 B/op 5 allocs/op
|
||||
BenchmarkRevel_GithubStatic 300000 6271 ns/op 1288 B/op 25 allocs/op
|
||||
BenchmarkRivet_GithubStatic 3000000 474 ns/op 112 B/op 2 allocs/op
|
||||
BenchmarkTango_GithubStatic 1000000 1842 ns/op 256 B/op 10 allocs/op
|
||||
BenchmarkTigerTonic_GithubStatic 5000000 361 ns/op 48 B/op 1 allocs/op
|
||||
BenchmarkTraffic_GithubStatic 30000 47197 ns/op 18920 B/op 149 allocs/op
|
||||
BenchmarkVulcan_GithubStatic 1000000 1415 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkZeus_GithubStatic 1000000 2522 ns/op 512 B/op 11 allocs/op
|
||||
BenchmarkAce_GithubParam 3000000 578 ns/op 96 B/op 1 allocs/op
|
||||
BenchmarkBear_GithubParam 1000000 1592 ns/op 464 B/op 5 allocs/op
|
||||
BenchmarkBeego_GithubParam 1000000 2891 ns/op 784 B/op 11 allocs/op
|
||||
BenchmarkBone_GithubParam 300000 6440 ns/op 1456 B/op 16 allocs/op
|
||||
BenchmarkDenco_GithubParam 3000000 514 ns/op 128 B/op 1 allocs/op
|
||||
BenchmarkEcho_GithubParam 5000000 292 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGin_GithubParam 10000000 242 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_GithubParam 1000000 2343 ns/op 720 B/op 10 allocs/op
|
||||
BenchmarkGoji_GithubParam 1000000 1566 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGoJsonRest_GithubParam 1000000 2828 ns/op 721 B/op 15 allocs/op
|
||||
BenchmarkGoRestful_GithubParam 10000 177711 ns/op 2816 B/op 35 allocs/op
|
||||
BenchmarkGorillaMux_GithubParam 100000 13591 ns/op 816 B/op 9 allocs/op
|
||||
BenchmarkHttpRouter_GithubParam 5000000 352 ns/op 96 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_GithubParam 2000000 973 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkKocha_GithubParam 2000000 889 ns/op 128 B/op 5 allocs/op
|
||||
BenchmarkMacaron_GithubParam 500000 4047 ns/op 1168 B/op 12 allocs/op
|
||||
BenchmarkMartini_GithubParam 50000 28982 ns/op 1184 B/op 12 allocs/op
|
||||
BenchmarkPat_GithubParam 200000 8747 ns/op 2480 B/op 56 allocs/op
|
||||
BenchmarkPossum_GithubParam 1000000 2158 ns/op 624 B/op 7 allocs/op
|
||||
BenchmarkR2router_GithubParam 1000000 1352 ns/op 432 B/op 6 allocs/op
|
||||
BenchmarkRevel_GithubParam 200000 7673 ns/op 1784 B/op 30 allocs/op
|
||||
BenchmarkRivet_GithubParam 1000000 1573 ns/op 480 B/op 6 allocs/op
|
||||
BenchmarkTango_GithubParam 1000000 2418 ns/op 480 B/op 13 allocs/op
|
||||
BenchmarkTigerTonic_GithubParam 300000 6048 ns/op 1440 B/op 28 allocs/op
|
||||
BenchmarkTraffic_GithubParam 100000 20143 ns/op 6024 B/op 55 allocs/op
|
||||
BenchmarkVulcan_GithubParam 1000000 2224 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkZeus_GithubParam 500000 4156 ns/op 1312 B/op 12 allocs/op
|
||||
BenchmarkAce_GithubAll 10000 109482 ns/op 13792 B/op 167 allocs/op
|
||||
BenchmarkBear_GithubAll 10000 287490 ns/op 79952 B/op 943 allocs/op
|
||||
BenchmarkBeego_GithubAll 3000 562184 ns/op 146272 B/op 2092 allocs/op
|
||||
BenchmarkBone_GithubAll 500 2578716 ns/op 648016 B/op 8119 allocs/op
|
||||
BenchmarkDenco_GithubAll 20000 94955 ns/op 20224 B/op 167 allocs/op
|
||||
BenchmarkEcho_GithubAll 30000 58705 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGin_GithubAll 30000 50991 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_GithubAll 5000 449648 ns/op 133280 B/op 1889 allocs/op
|
||||
BenchmarkGoji_GithubAll 2000 689748 ns/op 56113 B/op 334 allocs/op
|
||||
BenchmarkGoJsonRest_GithubAll 5000 537769 ns/op 135995 B/op 2940 allocs/op
|
||||
BenchmarkGoRestful_GithubAll 100 18410628 ns/op 797236 B/op 7725 allocs/op
|
||||
BenchmarkGorillaMux_GithubAll 200 8036360 ns/op 153137 B/op 1791 allocs/op
|
||||
BenchmarkHttpRouter_GithubAll 20000 63506 ns/op 13792 B/op 167 allocs/op
|
||||
BenchmarkHttpTreeMux_GithubAll 10000 165927 ns/op 56112 B/op 334 allocs/op
|
||||
BenchmarkKocha_GithubAll 10000 171362 ns/op 23304 B/op 843 allocs/op
|
||||
BenchmarkMacaron_GithubAll 2000 817008 ns/op 224960 B/op 2315 allocs/op
|
||||
BenchmarkMartini_GithubAll 100 12609209 ns/op 237952 B/op 2686 allocs/op
|
||||
BenchmarkPat_GithubAll 300 4830398 ns/op 1504101 B/op 32222 allocs/op
|
||||
BenchmarkPossum_GithubAll 10000 301716 ns/op 97440 B/op 812 allocs/op
|
||||
BenchmarkR2router_GithubAll 10000 270691 ns/op 77328 B/op 1182 allocs/op
|
||||
BenchmarkRevel_GithubAll 1000 1491919 ns/op 345553 B/op 5918 allocs/op
|
||||
BenchmarkRivet_GithubAll 10000 283860 ns/op 84272 B/op 1079 allocs/op
|
||||
BenchmarkTango_GithubAll 5000 473821 ns/op 87078 B/op 2470 allocs/op
|
||||
BenchmarkTigerTonic_GithubAll 2000 1120131 ns/op 241088 B/op 6052 allocs/op
|
||||
BenchmarkTraffic_GithubAll 200 8708979 ns/op 2664762 B/op 22390 allocs/op
|
||||
BenchmarkVulcan_GithubAll 5000 353392 ns/op 19894 B/op 609 allocs/op
|
||||
BenchmarkZeus_GithubAll 2000 944234 ns/op 300688 B/op 2648 allocs/op
|
||||
BenchmarkAce_GPlusStatic 5000000 251 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkBear_GPlusStatic 3000000 415 ns/op 72 B/op 3 allocs/op
|
||||
BenchmarkBeego_GPlusStatic 1000000 1416 ns/op 352 B/op 7 allocs/op
|
||||
BenchmarkBone_GPlusStatic 10000000 192 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkDenco_GPlusStatic 30000000 47.6 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkEcho_GPlusStatic 10000000 131 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGin_GPlusStatic 10000000 131 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_GPlusStatic 1000000 1035 ns/op 288 B/op 6 allocs/op
|
||||
BenchmarkGoji_GPlusStatic 5000000 304 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGoJsonRest_GPlusStatic 1000000 1286 ns/op 337 B/op 12 allocs/op
|
||||
BenchmarkGoRestful_GPlusStatic 200000 9649 ns/op 2160 B/op 30 allocs/op
|
||||
BenchmarkGorillaMux_GPlusStatic 1000000 2346 ns/op 464 B/op 8 allocs/op
|
||||
BenchmarkHttpRouter_GPlusStatic 30000000 42.7 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkHttpTreeMux_GPlusStatic 30000000 49.5 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkKocha_GPlusStatic 20000000 74.8 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_GPlusStatic 1000000 2520 ns/op 736 B/op 8 allocs/op
|
||||
BenchmarkMartini_GPlusStatic 300000 5310 ns/op 832 B/op 11 allocs/op
|
||||
BenchmarkPat_GPlusStatic 5000000 398 ns/op 96 B/op 2 allocs/op
|
||||
BenchmarkPossum_GPlusStatic 1000000 1434 ns/op 480 B/op 4 allocs/op
|
||||
BenchmarkR2router_GPlusStatic 2000000 646 ns/op 144 B/op 5 allocs/op
|
||||
BenchmarkRevel_GPlusStatic 300000 6172 ns/op 1272 B/op 25 allocs/op
|
||||
BenchmarkRivet_GPlusStatic 3000000 444 ns/op 112 B/op 2 allocs/op
|
||||
BenchmarkTango_GPlusStatic 1000000 1400 ns/op 208 B/op 10 allocs/op
|
||||
BenchmarkTigerTonic_GPlusStatic 10000000 213 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkTraffic_GPlusStatic 1000000 3091 ns/op 1208 B/op 16 allocs/op
|
||||
BenchmarkVulcan_GPlusStatic 2000000 863 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkZeus_GPlusStatic 10000000 237 ns/op 16 B/op 1 allocs/op
|
||||
BenchmarkAce_GPlusParam 3000000 435 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkBear_GPlusParam 1000000 1205 ns/op 448 B/op 5 allocs/op
|
||||
BenchmarkBeego_GPlusParam 1000000 2494 ns/op 720 B/op 10 allocs/op
|
||||
BenchmarkBone_GPlusParam 1000000 1126 ns/op 384 B/op 3 allocs/op
|
||||
BenchmarkDenco_GPlusParam 5000000 325 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkEcho_GPlusParam 10000000 168 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGin_GPlusParam 10000000 170 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_GPlusParam 1000000 1895 ns/op 656 B/op 9 allocs/op
|
||||
BenchmarkGoji_GPlusParam 1000000 1071 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGoJsonRest_GPlusParam 1000000 2282 ns/op 657 B/op 14 allocs/op
|
||||
BenchmarkGoRestful_GPlusParam 100000 19400 ns/op 2560 B/op 33 allocs/op
|
||||
BenchmarkGorillaMux_GPlusParam 500000 5001 ns/op 784 B/op 9 allocs/op
|
||||
BenchmarkHttpRouter_GPlusParam 10000000 240 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_GPlusParam 2000000 797 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkKocha_GPlusParam 3000000 505 ns/op 56 B/op 3 allocs/op
|
||||
BenchmarkMacaron_GPlusParam 1000000 3668 ns/op 1104 B/op 11 allocs/op
|
||||
BenchmarkMartini_GPlusParam 200000 10672 ns/op 1152 B/op 12 allocs/op
|
||||
BenchmarkPat_GPlusParam 1000000 2376 ns/op 704 B/op 14 allocs/op
|
||||
BenchmarkPossum_GPlusParam 1000000 2090 ns/op 624 B/op 7 allocs/op
|
||||
BenchmarkR2router_GPlusParam 1000000 1233 ns/op 432 B/op 6 allocs/op
|
||||
BenchmarkRevel_GPlusParam 200000 6778 ns/op 1704 B/op 28 allocs/op
|
||||
BenchmarkRivet_GPlusParam 1000000 1279 ns/op 464 B/op 5 allocs/op
|
||||
BenchmarkTango_GPlusParam 1000000 1981 ns/op 272 B/op 10 allocs/op
|
||||
BenchmarkTigerTonic_GPlusParam 500000 3893 ns/op 1064 B/op 19 allocs/op
|
||||
BenchmarkTraffic_GPlusParam 200000 6585 ns/op 2000 B/op 23 allocs/op
|
||||
BenchmarkVulcan_GPlusParam 1000000 1233 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkZeus_GPlusParam 1000000 1350 ns/op 368 B/op 3 allocs/op
|
||||
BenchmarkAce_GPlus2Params 3000000 512 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkBear_GPlus2Params 1000000 1564 ns/op 464 B/op 5 allocs/op
|
||||
BenchmarkBeego_GPlus2Params 1000000 3043 ns/op 784 B/op 11 allocs/op
|
||||
BenchmarkBone_GPlus2Params 1000000 3152 ns/op 736 B/op 7 allocs/op
|
||||
BenchmarkDenco_GPlus2Params 3000000 431 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkEcho_GPlus2Params 5000000 247 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGin_GPlus2Params 10000000 219 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_GPlus2Params 1000000 2363 ns/op 720 B/op 10 allocs/op
|
||||
BenchmarkGoji_GPlus2Params 1000000 1540 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGoJsonRest_GPlus2Params 1000000 2872 ns/op 721 B/op 15 allocs/op
|
||||
BenchmarkGoRestful_GPlus2Params 100000 23030 ns/op 2720 B/op 35 allocs/op
|
||||
BenchmarkGorillaMux_GPlus2Params 200000 10516 ns/op 816 B/op 9 allocs/op
|
||||
BenchmarkHttpRouter_GPlus2Params 5000000 273 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_GPlus2Params 2000000 939 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkKocha_GPlus2Params 2000000 844 ns/op 128 B/op 5 allocs/op
|
||||
BenchmarkMacaron_GPlus2Params 500000 3914 ns/op 1168 B/op 12 allocs/op
|
||||
BenchmarkMartini_GPlus2Params 50000 35759 ns/op 1280 B/op 16 allocs/op
|
||||
BenchmarkPat_GPlus2Params 200000 7089 ns/op 2304 B/op 41 allocs/op
|
||||
BenchmarkPossum_GPlus2Params 1000000 2093 ns/op 624 B/op 7 allocs/op
|
||||
BenchmarkR2router_GPlus2Params 1000000 1320 ns/op 432 B/op 6 allocs/op
|
||||
BenchmarkRevel_GPlus2Params 200000 7351 ns/op 1800 B/op 30 allocs/op
|
||||
BenchmarkRivet_GPlus2Params 1000000 1485 ns/op 480 B/op 6 allocs/op
|
||||
BenchmarkTango_GPlus2Params 1000000 2111 ns/op 448 B/op 12 allocs/op
|
||||
BenchmarkTigerTonic_GPlus2Params 300000 6271 ns/op 1528 B/op 28 allocs/op
|
||||
BenchmarkTraffic_GPlus2Params 100000 14886 ns/op 3312 B/op 34 allocs/op
|
||||
BenchmarkVulcan_GPlus2Params 1000000 1883 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkZeus_GPlus2Params 1000000 2686 ns/op 784 B/op 6 allocs/op
|
||||
BenchmarkAce_GPlusAll 300000 5912 ns/op 640 B/op 11 allocs/op
|
||||
BenchmarkBear_GPlusAll 100000 16448 ns/op 5072 B/op 61 allocs/op
|
||||
BenchmarkBeego_GPlusAll 50000 32916 ns/op 8976 B/op 129 allocs/op
|
||||
BenchmarkBone_GPlusAll 50000 25836 ns/op 6992 B/op 76 allocs/op
|
||||
BenchmarkDenco_GPlusAll 500000 4462 ns/op 672 B/op 11 allocs/op
|
||||
BenchmarkEcho_GPlusAll 500000 2806 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGin_GPlusAll 500000 2579 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_GPlusAll 50000 25223 ns/op 8144 B/op 116 allocs/op
|
||||
BenchmarkGoji_GPlusAll 100000 14237 ns/op 3696 B/op 22 allocs/op
|
||||
BenchmarkGoJsonRest_GPlusAll 50000 29227 ns/op 8221 B/op 183 allocs/op
|
||||
BenchmarkGoRestful_GPlusAll 10000 203144 ns/op 36064 B/op 441 allocs/op
|
||||
BenchmarkGorillaMux_GPlusAll 20000 80906 ns/op 9712 B/op 115 allocs/op
|
||||
BenchmarkHttpRouter_GPlusAll 500000 3040 ns/op 640 B/op 11 allocs/op
|
||||
BenchmarkHttpTreeMux_GPlusAll 200000 9627 ns/op 3696 B/op 22 allocs/op
|
||||
BenchmarkKocha_GPlusAll 200000 8108 ns/op 976 B/op 43 allocs/op
|
||||
BenchmarkMacaron_GPlusAll 30000 48083 ns/op 13968 B/op 142 allocs/op
|
||||
BenchmarkMartini_GPlusAll 10000 196978 ns/op 15072 B/op 178 allocs/op
|
||||
BenchmarkPat_GPlusAll 30000 58865 ns/op 16880 B/op 343 allocs/op
|
||||
BenchmarkPossum_GPlusAll 100000 19685 ns/op 6240 B/op 52 allocs/op
|
||||
BenchmarkR2router_GPlusAll 100000 16251 ns/op 5040 B/op 76 allocs/op
|
||||
BenchmarkRevel_GPlusAll 20000 93489 ns/op 21656 B/op 368 allocs/op
|
||||
BenchmarkRivet_GPlusAll 100000 16907 ns/op 5408 B/op 64 allocs/op
|
||||
```
|
||||
139
vendor/github.com/gin-gonic/gin/CHANGELOG.md
generated
vendored
139
vendor/github.com/gin-gonic/gin/CHANGELOG.md
generated
vendored
@@ -1,16 +1,143 @@
|
||||
#Changelog
|
||||
# CHANGELOG
|
||||
|
||||
###Gin 0.6 (Mar 7, 2015)
|
||||
### Gin 1.2
|
||||
|
||||
- [NEW] Switch from godeps to govendor
|
||||
- [NEW] Add support for Let's Encrypt via gin-gonic/autotls
|
||||
- [NEW] Improve README examples and add extra at examples folder
|
||||
- [NEW] Improved support with App Engine
|
||||
- [NEW] Add custom template delimiters, see #860
|
||||
- [NEW] Add Template Func Maps, see #962
|
||||
- [NEW] Add \*context.Handler(), see #928
|
||||
- [NEW] Add \*context.GetRawData()
|
||||
- [NEW] Add \*context.GetHeader() (request)
|
||||
- [NEW] Add \*context.AbortWithStatusJSON() (JSON content type)
|
||||
- [NEW] Add \*context.Keys type cast helpers
|
||||
- [NEW] Add \*context.ShouldBindWith()
|
||||
- [NEW] Add \*context.MustBindWith()
|
||||
- [NEW] Add \*engine.SetFuncMap()
|
||||
- [DEPRECATE] On next release: \*context.BindWith(), see #855
|
||||
- [FIX] Refactor render
|
||||
- [FIX] Reworked tests
|
||||
- [FIX] logger now supports cygwin
|
||||
- [FIX] Use X-Forwarded-For before X-Real-Ip
|
||||
- [FIX] time.Time binding (#904)
|
||||
|
||||
### Gin 1.1.4
|
||||
|
||||
- [NEW] Support google appengine for IsTerminal func
|
||||
|
||||
### Gin 1.1.3
|
||||
|
||||
- [FIX] Reverted Logger: skip ANSI color commands
|
||||
|
||||
### Gin 1.1
|
||||
|
||||
- [NEW] Implement QueryArray and PostArray methods
|
||||
- [NEW] Refactor GetQuery and GetPostForm
|
||||
- [NEW] Add contribution guide
|
||||
- [FIX] Corrected typos in README
|
||||
- [FIX] Removed additional Iota
|
||||
- [FIX] Changed imports to gopkg instead of github in README (#733)
|
||||
- [FIX] Logger: skip ANSI color commands if output is not a tty
|
||||
|
||||
### Gin 1.0rc2 (...)
|
||||
|
||||
- [PERFORMANCE] Fast path for writing Content-Type.
|
||||
- [PERFORMANCE] Much faster 404 routing
|
||||
- [PERFORMANCE] Allocation optimizations
|
||||
- [PERFORMANCE] Faster root tree lookup
|
||||
- [PERFORMANCE] Zero overhead, String() and JSON() rendering.
|
||||
- [PERFORMANCE] Faster ClientIP parsing
|
||||
- [PERFORMANCE] Much faster SSE implementation
|
||||
- [NEW] Benchmarks suite
|
||||
- [NEW] Bind validation can be disabled and replaced with custom validators.
|
||||
- [NEW] More flexible HTML render
|
||||
- [NEW] Multipart and PostForm bindings
|
||||
- [NEW] Adds method to return all the registered routes
|
||||
- [NEW] Context.HandlerName() returns the main handler's name
|
||||
- [NEW] Adds Error.IsType() helper
|
||||
- [FIX] Binding multipart form
|
||||
- [FIX] Integration tests
|
||||
- [FIX] Crash when binding non struct object in Context.
|
||||
- [FIX] RunTLS() implementation
|
||||
- [FIX] Logger() unit tests
|
||||
- [FIX] Adds SetHTMLTemplate() warning
|
||||
- [FIX] Context.IsAborted()
|
||||
- [FIX] More unit tests
|
||||
- [FIX] JSON, XML, HTML renders accept custom content-types
|
||||
- [FIX] gin.AbortIndex is unexported
|
||||
- [FIX] Better approach to avoid directory listing in StaticFS()
|
||||
- [FIX] Context.ClientIP() always returns the IP with trimmed spaces.
|
||||
- [FIX] Better warning when running in debug mode.
|
||||
- [FIX] Google App Engine integration. debugPrint does not use os.Stdout
|
||||
- [FIX] Fixes integer overflow in error type
|
||||
- [FIX] Error implements the json.Marshaller interface
|
||||
- [FIX] MIT license in every file
|
||||
|
||||
|
||||
###Gin 0.5 (Feb 7, 2015)
|
||||
### Gin 1.0rc1 (May 22, 2015)
|
||||
|
||||
- [PERFORMANCE] Zero allocation router
|
||||
- [PERFORMANCE] Faster JSON, XML and text rendering
|
||||
- [PERFORMANCE] Custom hand optimized HttpRouter for Gin
|
||||
- [PERFORMANCE] Misc code optimizations. Inlining, tail call optimizations
|
||||
- [NEW] Built-in support for golang.org/x/net/context
|
||||
- [NEW] Any(path, handler). Create a route that matches any path
|
||||
- [NEW] Refactored rendering pipeline (faster and static typeded)
|
||||
- [NEW] Refactored errors API
|
||||
- [NEW] IndentedJSON() prints pretty JSON
|
||||
- [NEW] Added gin.DefaultWriter
|
||||
- [NEW] UNIX socket support
|
||||
- [NEW] RouterGroup.BasePath is exposed
|
||||
- [NEW] JSON validation using go-validate-yourself (very powerful options)
|
||||
- [NEW] Completed suite of unit tests
|
||||
- [NEW] HTTP streaming with c.Stream()
|
||||
- [NEW] StaticFile() creates a router for serving just one file.
|
||||
- [NEW] StaticFS() has an option to disable directory listing.
|
||||
- [NEW] StaticFS() for serving static files through virtual filesystems
|
||||
- [NEW] Server-Sent Events native support
|
||||
- [NEW] WrapF() and WrapH() helpers for wrapping http.HandlerFunc and http.Handler
|
||||
- [NEW] Added LoggerWithWriter() middleware
|
||||
- [NEW] Added RecoveryWithWriter() middleware
|
||||
- [NEW] Added DefaultPostFormValue()
|
||||
- [NEW] Added DefaultFormValue()
|
||||
- [NEW] Added DefaultParamValue()
|
||||
- [FIX] BasicAuth() when using custom realm
|
||||
- [FIX] Bug when serving static files in nested routing group
|
||||
- [FIX] Redirect using built-in http.Redirect()
|
||||
- [FIX] Logger when printing the requested path
|
||||
- [FIX] Documentation typos
|
||||
- [FIX] Context.Engine renamed to Context.engine
|
||||
- [FIX] Better debugging messages
|
||||
- [FIX] ErrorLogger
|
||||
- [FIX] Debug HTTP render
|
||||
- [FIX] Refactored binding and render modules
|
||||
- [FIX] Refactored Context initialization
|
||||
- [FIX] Refactored BasicAuth()
|
||||
- [FIX] NoMethod/NoRoute handlers
|
||||
- [FIX] Hijacking http
|
||||
- [FIX] Better support for Google App Engine (using log instead of fmt)
|
||||
|
||||
|
||||
### Gin 0.6 (Mar 9, 2015)
|
||||
|
||||
- [NEW] Support multipart/form-data
|
||||
- [NEW] NoMethod handler
|
||||
- [NEW] Validate sub structures
|
||||
- [NEW] Support for HTTP Realm Auth
|
||||
- [FIX] Unsigned integers in binding
|
||||
- [FIX] Improve color logger
|
||||
|
||||
|
||||
### Gin 0.5 (Feb 7, 2015)
|
||||
|
||||
- [NEW] Content Negotiation
|
||||
- [FIX] Solved security bug that allow a client to spoof ip
|
||||
- [FIX] Fix unexported/ignored fields in binding
|
||||
|
||||
|
||||
###Gin 0.4 (Aug 21, 2014)
|
||||
### Gin 0.4 (Aug 21, 2014)
|
||||
|
||||
- [NEW] Development mode
|
||||
- [NEW] Unit tests
|
||||
@@ -19,7 +146,7 @@
|
||||
- [FIX] Improved documentation for model binding
|
||||
|
||||
|
||||
###Gin 0.3 (Jul 18, 2014)
|
||||
### Gin 0.3 (Jul 18, 2014)
|
||||
|
||||
- [PERFORMANCE] Normal log and error log are printed in the same call.
|
||||
- [PERFORMANCE] Improve performance of NoRouter()
|
||||
@@ -37,7 +164,7 @@
|
||||
- [FIX] Check application/x-www-form-urlencoded when parsing form
|
||||
|
||||
|
||||
###Gin 0.2b (Jul 08, 2014)
|
||||
### Gin 0.2b (Jul 08, 2014)
|
||||
- [PERFORMANCE] Using sync.Pool to allocatio/gc overhead
|
||||
- [NEW] Travis CI integration
|
||||
- [NEW] Completely new logger
|
||||
|
||||
10
vendor/github.com/gin-gonic/gin/Godeps/Godeps.json
generated
vendored
10
vendor/github.com/gin-gonic/gin/Godeps/Godeps.json
generated
vendored
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"ImportPath": "github.com/gin-gonic/gin",
|
||||
"GoVersion": "go1.3",
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "github.com/julienschmidt/httprouter",
|
||||
"Rev": "00ce1c6a267162792c367acc43b1681a884e1872"
|
||||
}
|
||||
]
|
||||
}
|
||||
61
vendor/github.com/gin-gonic/gin/Makefile
generated
vendored
Normal file
61
vendor/github.com/gin-gonic/gin/Makefile
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
GOFMT ?= gofmt "-s"
|
||||
PACKAGES ?= $(shell go list ./... | grep -v /vendor/)
|
||||
GOFILES := $(shell find . -name "*.go" -type f -not -path "./vendor/*")
|
||||
|
||||
all: build
|
||||
|
||||
install: deps
|
||||
govendor sync
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
go test -v -covermode=count -coverprofile=coverage.out
|
||||
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
$(GOFMT) -w $(GOFILES)
|
||||
|
||||
.PHONY: fmt-check
|
||||
fmt-check:
|
||||
# get all go files and run go fmt on them
|
||||
@diff=$$($(GOFMT) -d $(GOFILES)); \
|
||||
if [ -n "$$diff" ]; then \
|
||||
echo "Please run 'make fmt' and commit the result:"; \
|
||||
echo "$${diff}"; \
|
||||
exit 1; \
|
||||
fi;
|
||||
|
||||
vet:
|
||||
go vet $(PACKAGES)
|
||||
|
||||
deps:
|
||||
@hash govendor > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
go get -u github.com/kardianos/govendor; \
|
||||
fi
|
||||
@hash embedmd > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
go get -u github.com/campoy/embedmd; \
|
||||
fi
|
||||
|
||||
embedmd:
|
||||
embedmd -d *.md
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
@hash golint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
go get -u github.com/golang/lint/golint; \
|
||||
fi
|
||||
for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done;
|
||||
|
||||
.PHONY: misspell-check
|
||||
misspell-check:
|
||||
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
go get -u github.com/client9/misspell/cmd/misspell; \
|
||||
fi
|
||||
misspell -error $(GOFILES)
|
||||
|
||||
.PHONY: misspell
|
||||
misspell:
|
||||
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
go get -u github.com/client9/misspell/cmd/misspell; \
|
||||
fi
|
||||
misspell -w $(GOFILES)
|
||||
889
vendor/github.com/gin-gonic/gin/README.md
generated
vendored
889
vendor/github.com/gin-gonic/gin/README.md
generated
vendored
File diff suppressed because it is too large
Load Diff
94
vendor/github.com/gin-gonic/gin/auth.go
generated
vendored
94
vendor/github.com/gin-gonic/gin/auth.go
generated
vendored
@@ -7,13 +7,10 @@ package gin
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"sort"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
AuthUserKey = "user"
|
||||
)
|
||||
const AuthUserKey = "user"
|
||||
|
||||
type (
|
||||
Accounts map[string]string
|
||||
@@ -24,71 +21,72 @@ type (
|
||||
authPairs []authPair
|
||||
)
|
||||
|
||||
func (a authPairs) Len() int { return len(a) }
|
||||
func (a authPairs) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a authPairs) Less(i, j int) bool { return a[i].Value < a[j].Value }
|
||||
|
||||
// Implements a basic Basic HTTP Authorization. It takes as argument a map[string]string where
|
||||
// the key is the user name and the value is the password.
|
||||
func BasicAuth(accounts Accounts) HandlerFunc {
|
||||
pairs, err := processAccounts(accounts)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
func (a authPairs) searchCredential(authValue string) (string, bool) {
|
||||
if len(authValue) == 0 {
|
||||
return "", false
|
||||
}
|
||||
for _, pair := range a {
|
||||
if pair.Value == authValue {
|
||||
return pair.User, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// BasicAuthForRealm returns a Basic HTTP Authorization middleware. It takes as arguments a map[string]string where
|
||||
// the key is the user name and the value is the password, as well as the name of the Realm.
|
||||
// If the realm is empty, "Authorization Required" will be used by default.
|
||||
// (see http://tools.ietf.org/html/rfc2617#section-1.2)
|
||||
func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc {
|
||||
if realm == "" {
|
||||
realm = "Authorization Required"
|
||||
}
|
||||
realm = "Basic realm=" + strconv.Quote(realm)
|
||||
pairs := processAccounts(accounts)
|
||||
return func(c *Context) {
|
||||
// Search user in the slice of allowed credentials
|
||||
user, ok := searchCredential(pairs, c.Request.Header.Get("Authorization"))
|
||||
if !ok {
|
||||
// Credentials doesn't match, we return 401 Unauthorized and abort request.
|
||||
c.Writer.Header().Set("WWW-Authenticate", "Basic realm=\"Authorization Required\"")
|
||||
c.Fail(401, errors.New("Unauthorized"))
|
||||
user, found := pairs.searchCredential(c.Request.Header.Get("Authorization"))
|
||||
if !found {
|
||||
// Credentials doesn't match, we return 401 and abort handlers chain.
|
||||
c.Header("WWW-Authenticate", realm)
|
||||
c.AbortWithStatus(401)
|
||||
} else {
|
||||
// user is allowed, set UserId to key "user" in this context, the userId can be read later using
|
||||
// c.Get(gin.AuthUserKey)
|
||||
// The user credentials was found, set user's id to key AuthUserKey in this context, the userId can be read later using
|
||||
// c.MustGet(gin.AuthUserKey)
|
||||
c.Set(AuthUserKey, user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func processAccounts(accounts Accounts) (authPairs, error) {
|
||||
if len(accounts) == 0 {
|
||||
return nil, errors.New("Empty list of authorized credentials")
|
||||
}
|
||||
// BasicAuth returns a Basic HTTP Authorization middleware. It takes as argument a map[string]string where
|
||||
// the key is the user name and the value is the password.
|
||||
func BasicAuth(accounts Accounts) HandlerFunc {
|
||||
return BasicAuthForRealm(accounts, "")
|
||||
}
|
||||
|
||||
func processAccounts(accounts Accounts) authPairs {
|
||||
assert1(len(accounts) > 0, "Empty list of authorized credentials")
|
||||
pairs := make(authPairs, 0, len(accounts))
|
||||
for user, password := range accounts {
|
||||
if len(user) == 0 {
|
||||
return nil, errors.New("User can not be empty")
|
||||
}
|
||||
base := user + ":" + password
|
||||
value := "Basic " + base64.StdEncoding.EncodeToString([]byte(base))
|
||||
assert1(len(user) > 0, "User can not be empty")
|
||||
value := authorizationHeader(user, password)
|
||||
pairs = append(pairs, authPair{
|
||||
Value: value,
|
||||
User: user,
|
||||
})
|
||||
}
|
||||
// We have to sort the credentials in order to use bsearch later.
|
||||
sort.Sort(pairs)
|
||||
return pairs, nil
|
||||
return pairs
|
||||
}
|
||||
|
||||
func searchCredential(pairs authPairs, auth string) (string, bool) {
|
||||
if len(auth) == 0 {
|
||||
return "", false
|
||||
}
|
||||
// Search user in the slice of allowed credentials
|
||||
r := sort.Search(len(pairs), func(i int) bool { return pairs[i].Value >= auth })
|
||||
if r < len(pairs) && secureCompare(pairs[r].Value, auth) {
|
||||
return pairs[r].User, true
|
||||
} else {
|
||||
return "", false
|
||||
}
|
||||
func authorizationHeader(user, password string) string {
|
||||
base := user + ":" + password
|
||||
return "Basic " + base64.StdEncoding.EncodeToString([]byte(base))
|
||||
}
|
||||
|
||||
func secureCompare(given, actual string) bool {
|
||||
if subtle.ConstantTimeEq(int32(len(given)), int32(len(actual))) == 1 {
|
||||
return subtle.ConstantTimeCompare([]byte(given), []byte(actual)) == 1
|
||||
} else {
|
||||
/* Securely compare actual to itself to keep constant time, but always return false */
|
||||
return subtle.ConstantTimeCompare([]byte(actual), []byte(actual)) == 1 && false
|
||||
}
|
||||
/* Securely compare actual to itself to keep constant time, but always return false */
|
||||
return subtle.ConstantTimeCompare([]byte(actual), []byte(actual)) == 1 && false
|
||||
}
|
||||
|
||||
155
vendor/github.com/gin-gonic/gin/auth_test.go
generated
vendored
155
vendor/github.com/gin-gonic/gin/auth_test.go
generated
vendored
@@ -9,53 +9,138 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBasicAuthSucceed(t *testing.T) {
|
||||
req, _ := http.NewRequest("GET", "/login", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
r := New()
|
||||
accounts := Accounts{"admin": "password"}
|
||||
r.Use(BasicAuth(accounts))
|
||||
|
||||
r.GET("/login", func(c *Context) {
|
||||
c.String(200, "autorized")
|
||||
func TestBasicAuth(t *testing.T) {
|
||||
pairs := processAccounts(Accounts{
|
||||
"admin": "password",
|
||||
"foo": "bar",
|
||||
"bar": "foo",
|
||||
})
|
||||
|
||||
req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("admin:password")))
|
||||
r.ServeHTTP(w, req)
|
||||
assert.Len(t, pairs, 3)
|
||||
assert.Contains(t, pairs, authPair{
|
||||
User: "bar",
|
||||
Value: "Basic YmFyOmZvbw==",
|
||||
})
|
||||
assert.Contains(t, pairs, authPair{
|
||||
User: "foo",
|
||||
Value: "Basic Zm9vOmJhcg==",
|
||||
})
|
||||
assert.Contains(t, pairs, authPair{
|
||||
User: "admin",
|
||||
Value: "Basic YWRtaW46cGFzc3dvcmQ=",
|
||||
})
|
||||
}
|
||||
|
||||
if w.Code != 200 {
|
||||
t.Errorf("Response code should be Ok, was: %s", w.Code)
|
||||
}
|
||||
bodyAsString := w.Body.String()
|
||||
func TestBasicAuthFails(t *testing.T) {
|
||||
assert.Panics(t, func() { processAccounts(nil) })
|
||||
assert.Panics(t, func() {
|
||||
processAccounts(Accounts{
|
||||
"": "password",
|
||||
"foo": "bar",
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if bodyAsString != "autorized" {
|
||||
t.Errorf("Response body should be `autorized`, was %s", bodyAsString)
|
||||
}
|
||||
func TestBasicAuthSearchCredential(t *testing.T) {
|
||||
pairs := processAccounts(Accounts{
|
||||
"admin": "password",
|
||||
"foo": "bar",
|
||||
"bar": "foo",
|
||||
})
|
||||
|
||||
user, found := pairs.searchCredential(authorizationHeader("admin", "password"))
|
||||
assert.Equal(t, user, "admin")
|
||||
assert.True(t, found)
|
||||
|
||||
user, found = pairs.searchCredential(authorizationHeader("foo", "bar"))
|
||||
assert.Equal(t, user, "foo")
|
||||
assert.True(t, found)
|
||||
|
||||
user, found = pairs.searchCredential(authorizationHeader("bar", "foo"))
|
||||
assert.Equal(t, user, "bar")
|
||||
assert.True(t, found)
|
||||
|
||||
user, found = pairs.searchCredential(authorizationHeader("admins", "password"))
|
||||
assert.Empty(t, user)
|
||||
assert.False(t, found)
|
||||
|
||||
user, found = pairs.searchCredential(authorizationHeader("foo", "bar "))
|
||||
assert.Empty(t, user)
|
||||
assert.False(t, found)
|
||||
|
||||
user, found = pairs.searchCredential("")
|
||||
assert.Empty(t, user)
|
||||
assert.False(t, found)
|
||||
}
|
||||
|
||||
func TestBasicAuthAuthorizationHeader(t *testing.T) {
|
||||
assert.Equal(t, authorizationHeader("admin", "password"), "Basic YWRtaW46cGFzc3dvcmQ=")
|
||||
}
|
||||
|
||||
func TestBasicAuthSecureCompare(t *testing.T) {
|
||||
assert.True(t, secureCompare("1234567890", "1234567890"))
|
||||
assert.False(t, secureCompare("123456789", "1234567890"))
|
||||
assert.False(t, secureCompare("12345678900", "1234567890"))
|
||||
assert.False(t, secureCompare("1234567891", "1234567890"))
|
||||
}
|
||||
|
||||
func TestBasicAuthSucceed(t *testing.T) {
|
||||
accounts := Accounts{"admin": "password"}
|
||||
router := New()
|
||||
router.Use(BasicAuth(accounts))
|
||||
router.GET("/login", func(c *Context) {
|
||||
c.String(200, c.MustGet(AuthUserKey).(string))
|
||||
})
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest("GET", "/login", nil)
|
||||
req.Header.Set("Authorization", authorizationHeader("admin", "password"))
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
assert.Equal(t, w.Code, 200)
|
||||
assert.Equal(t, w.Body.String(), "admin")
|
||||
}
|
||||
|
||||
func TestBasicAuth401(t *testing.T) {
|
||||
req, _ := http.NewRequest("GET", "/login", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
r := New()
|
||||
called := false
|
||||
accounts := Accounts{"foo": "bar"}
|
||||
r.Use(BasicAuth(accounts))
|
||||
|
||||
r.GET("/login", func(c *Context) {
|
||||
c.String(200, "autorized")
|
||||
router := New()
|
||||
router.Use(BasicAuth(accounts))
|
||||
router.GET("/login", func(c *Context) {
|
||||
called = true
|
||||
c.String(200, c.MustGet(AuthUserKey).(string))
|
||||
})
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest("GET", "/login", nil)
|
||||
req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("admin:password")))
|
||||
r.ServeHTTP(w, req)
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != 401 {
|
||||
t.Errorf("Response code should be Not autorized, was: %s", w.Code)
|
||||
}
|
||||
|
||||
if w.HeaderMap.Get("WWW-Authenticate") != "Basic realm=\"Authorization Required\"" {
|
||||
t.Errorf("WWW-Authenticate header is incorrect: %s", w.HeaderMap.Get("Content-Type"))
|
||||
}
|
||||
assert.False(t, called)
|
||||
assert.Equal(t, w.Code, 401)
|
||||
assert.Equal(t, w.HeaderMap.Get("WWW-Authenticate"), "Basic realm=\"Authorization Required\"")
|
||||
}
|
||||
|
||||
func TestBasicAuth401WithCustomRealm(t *testing.T) {
|
||||
called := false
|
||||
accounts := Accounts{"foo": "bar"}
|
||||
router := New()
|
||||
router.Use(BasicAuthForRealm(accounts, "My Custom \"Realm\""))
|
||||
router.GET("/login", func(c *Context) {
|
||||
called = true
|
||||
c.String(200, c.MustGet(AuthUserKey).(string))
|
||||
})
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest("GET", "/login", nil)
|
||||
req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("admin:password")))
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
assert.False(t, called)
|
||||
assert.Equal(t, w.Code, 401)
|
||||
assert.Equal(t, w.HeaderMap.Get("WWW-Authenticate"), "Basic realm=\"My Custom \\\"Realm\\\"\"")
|
||||
}
|
||||
|
||||
162
vendor/github.com/gin-gonic/gin/benchmarks_test.go
generated
vendored
Normal file
162
vendor/github.com/gin-gonic/gin/benchmarks_test.go
generated
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
// Copyright 2017 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gin
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkOneRoute(B *testing.B) {
|
||||
router := New()
|
||||
router.GET("/ping", func(c *Context) {})
|
||||
runRequest(B, router, "GET", "/ping")
|
||||
}
|
||||
|
||||
func BenchmarkRecoveryMiddleware(B *testing.B) {
|
||||
router := New()
|
||||
router.Use(Recovery())
|
||||
router.GET("/", func(c *Context) {})
|
||||
runRequest(B, router, "GET", "/")
|
||||
}
|
||||
|
||||
func BenchmarkLoggerMiddleware(B *testing.B) {
|
||||
router := New()
|
||||
router.Use(LoggerWithWriter(newMockWriter()))
|
||||
router.GET("/", func(c *Context) {})
|
||||
runRequest(B, router, "GET", "/")
|
||||
}
|
||||
|
||||
func BenchmarkManyHandlers(B *testing.B) {
|
||||
router := New()
|
||||
router.Use(Recovery(), LoggerWithWriter(newMockWriter()))
|
||||
router.Use(func(c *Context) {})
|
||||
router.Use(func(c *Context) {})
|
||||
router.GET("/ping", func(c *Context) {})
|
||||
runRequest(B, router, "GET", "/ping")
|
||||
}
|
||||
|
||||
func Benchmark5Params(B *testing.B) {
|
||||
DefaultWriter = os.Stdout
|
||||
router := New()
|
||||
router.Use(func(c *Context) {})
|
||||
router.GET("/param/:param1/:params2/:param3/:param4/:param5", func(c *Context) {})
|
||||
runRequest(B, router, "GET", "/param/path/to/parameter/john/12345")
|
||||
}
|
||||
|
||||
func BenchmarkOneRouteJSON(B *testing.B) {
|
||||
router := New()
|
||||
data := struct {
|
||||
Status string `json:"status"`
|
||||
}{"ok"}
|
||||
router.GET("/json", func(c *Context) {
|
||||
c.JSON(200, data)
|
||||
})
|
||||
runRequest(B, router, "GET", "/json")
|
||||
}
|
||||
|
||||
var htmlContentType = []string{"text/html; charset=utf-8"}
|
||||
|
||||
func BenchmarkOneRouteHTML(B *testing.B) {
|
||||
router := New()
|
||||
t := template.Must(template.New("index").Parse(`
|
||||
<html><body><h1>{{.}}</h1></body></html>`))
|
||||
router.SetHTMLTemplate(t)
|
||||
|
||||
router.GET("/html", func(c *Context) {
|
||||
c.HTML(200, "index", "hola")
|
||||
})
|
||||
runRequest(B, router, "GET", "/html")
|
||||
}
|
||||
|
||||
func BenchmarkOneRouteSet(B *testing.B) {
|
||||
router := New()
|
||||
router.GET("/ping", func(c *Context) {
|
||||
c.Set("key", "value")
|
||||
})
|
||||
runRequest(B, router, "GET", "/ping")
|
||||
}
|
||||
|
||||
func BenchmarkOneRouteString(B *testing.B) {
|
||||
router := New()
|
||||
router.GET("/text", func(c *Context) {
|
||||
c.String(200, "this is a plain text")
|
||||
})
|
||||
runRequest(B, router, "GET", "/text")
|
||||
}
|
||||
|
||||
func BenchmarkManyRoutesFist(B *testing.B) {
|
||||
router := New()
|
||||
router.Any("/ping", func(c *Context) {})
|
||||
runRequest(B, router, "GET", "/ping")
|
||||
}
|
||||
|
||||
func BenchmarkManyRoutesLast(B *testing.B) {
|
||||
router := New()
|
||||
router.Any("/ping", func(c *Context) {})
|
||||
runRequest(B, router, "OPTIONS", "/ping")
|
||||
}
|
||||
|
||||
func Benchmark404(B *testing.B) {
|
||||
router := New()
|
||||
router.Any("/something", func(c *Context) {})
|
||||
router.NoRoute(func(c *Context) {})
|
||||
runRequest(B, router, "GET", "/ping")
|
||||
}
|
||||
|
||||
func Benchmark404Many(B *testing.B) {
|
||||
router := New()
|
||||
router.GET("/", func(c *Context) {})
|
||||
router.GET("/path/to/something", func(c *Context) {})
|
||||
router.GET("/post/:id", func(c *Context) {})
|
||||
router.GET("/view/:id", func(c *Context) {})
|
||||
router.GET("/favicon.ico", func(c *Context) {})
|
||||
router.GET("/robots.txt", func(c *Context) {})
|
||||
router.GET("/delete/:id", func(c *Context) {})
|
||||
router.GET("/user/:id/:mode", func(c *Context) {})
|
||||
|
||||
router.NoRoute(func(c *Context) {})
|
||||
runRequest(B, router, "GET", "/viewfake")
|
||||
}
|
||||
|
||||
type mockWriter struct {
|
||||
headers http.Header
|
||||
}
|
||||
|
||||
func newMockWriter() *mockWriter {
|
||||
return &mockWriter{
|
||||
http.Header{},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mockWriter) Header() (h http.Header) {
|
||||
return m.headers
|
||||
}
|
||||
|
||||
func (m *mockWriter) Write(p []byte) (n int, err error) {
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (m *mockWriter) WriteString(s string) (n int, err error) {
|
||||
return len(s), nil
|
||||
}
|
||||
|
||||
func (m *mockWriter) WriteHeader(int) {}
|
||||
|
||||
func runRequest(B *testing.B, r *Engine, method, path string) {
|
||||
// create fake request
|
||||
req, err := http.NewRequest(method, path, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
w := newMockWriter()
|
||||
B.ReportAllocs()
|
||||
B.ResetTimer()
|
||||
for i := 0; i < B.N; i++ {
|
||||
r.ServeHTTP(w, req)
|
||||
}
|
||||
}
|
||||
248
vendor/github.com/gin-gonic/gin/binding/binding.go
generated
vendored
248
vendor/github.com/gin-gonic/gin/binding/binding.go
generated
vendored
@@ -4,213 +4,69 @@
|
||||
|
||||
package binding
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
import "net/http"
|
||||
|
||||
const (
|
||||
MIMEJSON = "application/json"
|
||||
MIMEHTML = "text/html"
|
||||
MIMEXML = "application/xml"
|
||||
MIMEXML2 = "text/xml"
|
||||
MIMEPlain = "text/plain"
|
||||
MIMEPOSTForm = "application/x-www-form-urlencoded"
|
||||
MIMEMultipartPOSTForm = "multipart/form-data"
|
||||
MIMEPROTOBUF = "application/x-protobuf"
|
||||
MIMEMSGPACK = "application/x-msgpack"
|
||||
MIMEMSGPACK2 = "application/msgpack"
|
||||
)
|
||||
|
||||
type (
|
||||
Binding interface {
|
||||
Bind(*http.Request, interface{}) error
|
||||
}
|
||||
type Binding interface {
|
||||
Name() string
|
||||
Bind(*http.Request, interface{}) error
|
||||
}
|
||||
|
||||
// JSON binding
|
||||
jsonBinding struct{}
|
||||
type StructValidator interface {
|
||||
// ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right.
|
||||
// If the received type is not a struct, any validation should be skipped and nil must be returned.
|
||||
// If the received type is a struct or pointer to a struct, the validation should be performed.
|
||||
// If the struct is not valid or the validation itself fails, a descriptive error should be returned.
|
||||
// Otherwise nil must be returned.
|
||||
ValidateStruct(interface{}) error
|
||||
}
|
||||
|
||||
// XML binding
|
||||
xmlBinding struct{}
|
||||
|
||||
// // form binding
|
||||
formBinding struct{}
|
||||
)
|
||||
var Validator StructValidator = &defaultValidator{}
|
||||
|
||||
var (
|
||||
JSON = jsonBinding{}
|
||||
XML = xmlBinding{}
|
||||
Form = formBinding{} // todo
|
||||
JSON = jsonBinding{}
|
||||
XML = xmlBinding{}
|
||||
Form = formBinding{}
|
||||
FormPost = formPostBinding{}
|
||||
FormMultipart = formMultipartBinding{}
|
||||
ProtoBuf = protobufBinding{}
|
||||
MsgPack = msgpackBinding{}
|
||||
)
|
||||
|
||||
func (_ jsonBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
decoder := json.NewDecoder(req.Body)
|
||||
if err := decoder.Decode(obj); err == nil {
|
||||
return Validate(obj)
|
||||
} else {
|
||||
return err
|
||||
func Default(method, contentType string) Binding {
|
||||
if method == "GET" {
|
||||
return Form
|
||||
}
|
||||
|
||||
switch contentType {
|
||||
case MIMEJSON:
|
||||
return JSON
|
||||
case MIMEXML, MIMEXML2:
|
||||
return XML
|
||||
case MIMEPROTOBUF:
|
||||
return ProtoBuf
|
||||
case MIMEMSGPACK, MIMEMSGPACK2:
|
||||
return MsgPack
|
||||
default: //case MIMEPOSTForm, MIMEMultipartPOSTForm:
|
||||
return Form
|
||||
}
|
||||
}
|
||||
|
||||
func (_ xmlBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
decoder := xml.NewDecoder(req.Body)
|
||||
if err := decoder.Decode(obj); err == nil {
|
||||
return Validate(obj)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func (_ formBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := mapForm(obj, req.Form); err != nil {
|
||||
return err
|
||||
}
|
||||
return Validate(obj)
|
||||
}
|
||||
|
||||
func mapForm(ptr interface{}, form map[string][]string) error {
|
||||
typ := reflect.TypeOf(ptr).Elem()
|
||||
formStruct := reflect.ValueOf(ptr).Elem()
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
typeField := typ.Field(i)
|
||||
if inputFieldName := typeField.Tag.Get("form"); inputFieldName != "" {
|
||||
structField := formStruct.Field(i)
|
||||
if !structField.CanSet() {
|
||||
continue
|
||||
}
|
||||
|
||||
inputValue, exists := form[inputFieldName]
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
numElems := len(inputValue)
|
||||
if structField.Kind() == reflect.Slice && numElems > 0 {
|
||||
sliceOf := structField.Type().Elem().Kind()
|
||||
slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
|
||||
for i := 0; i < numElems; i++ {
|
||||
if err := setWithProperType(sliceOf, inputValue[i], slice.Index(i)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
formStruct.Field(i).Set(slice)
|
||||
} else {
|
||||
if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error {
|
||||
switch valueKind {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
if val == "" {
|
||||
val = "0"
|
||||
}
|
||||
intVal, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
structField.SetInt(int64(intVal))
|
||||
}
|
||||
case reflect.Bool:
|
||||
if val == "" {
|
||||
val = "false"
|
||||
}
|
||||
boolVal, err := strconv.ParseBool(val)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
structField.SetBool(boolVal)
|
||||
}
|
||||
case reflect.Float32:
|
||||
if val == "" {
|
||||
val = "0.0"
|
||||
}
|
||||
floatVal, err := strconv.ParseFloat(val, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
structField.SetFloat(floatVal)
|
||||
}
|
||||
case reflect.Float64:
|
||||
if val == "" {
|
||||
val = "0.0"
|
||||
}
|
||||
floatVal, err := strconv.ParseFloat(val, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
structField.SetFloat(floatVal)
|
||||
}
|
||||
case reflect.String:
|
||||
structField.SetString(val)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Don't pass in pointers to bind to. Can lead to bugs. See:
|
||||
// https://github.com/codegangsta/martini-contrib/issues/40
|
||||
// https://github.com/codegangsta/martini-contrib/pull/34#issuecomment-29683659
|
||||
func ensureNotPointer(obj interface{}) {
|
||||
if reflect.TypeOf(obj).Kind() == reflect.Ptr {
|
||||
panic("Pointers are not accepted as binding models")
|
||||
}
|
||||
}
|
||||
|
||||
func Validate(obj interface{}, parents ...string) error {
|
||||
typ := reflect.TypeOf(obj)
|
||||
val := reflect.ValueOf(obj)
|
||||
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typ = typ.Elem()
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
switch typ.Kind() {
|
||||
case reflect.Struct:
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
field := typ.Field(i)
|
||||
|
||||
// Allow ignored and unexported fields in the struct
|
||||
if len(field.PkgPath) > 0 || field.Tag.Get("form") == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldValue := val.Field(i).Interface()
|
||||
zero := reflect.Zero(field.Type).Interface()
|
||||
|
||||
if strings.Index(field.Tag.Get("binding"), "required") > -1 {
|
||||
fieldType := field.Type.Kind()
|
||||
if fieldType == reflect.Struct {
|
||||
if reflect.DeepEqual(zero, fieldValue) {
|
||||
return errors.New("Required " + field.Name)
|
||||
}
|
||||
err := Validate(fieldValue, field.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if reflect.DeepEqual(zero, fieldValue) {
|
||||
if len(parents) > 0 {
|
||||
return errors.New("Required " + field.Name + " on " + parents[0])
|
||||
} else {
|
||||
return errors.New("Required " + field.Name)
|
||||
}
|
||||
} else if fieldType == reflect.Slice && field.Type.Elem().Kind() == reflect.Struct {
|
||||
err := Validate(fieldValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Slice:
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
fieldValue := val.Index(i).Interface()
|
||||
err := Validate(fieldValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
func validate(obj interface{}) error {
|
||||
if Validator == nil {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
return Validator.ValidateStruct(obj)
|
||||
}
|
||||
|
||||
259
vendor/github.com/gin-gonic/gin/binding/binding_test.go
generated
vendored
Normal file
259
vendor/github.com/gin-gonic/gin/binding/binding_test.go
generated
vendored
Normal file
@@ -0,0 +1,259 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin/binding/example"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/ugorji/go/codec"
|
||||
)
|
||||
|
||||
type FooStruct struct {
|
||||
Foo string `msgpack:"foo" json:"foo" form:"foo" xml:"foo" binding:"required"`
|
||||
}
|
||||
|
||||
type FooBarStruct struct {
|
||||
FooStruct
|
||||
Bar string `msgpack:"bar" json:"bar" form:"bar" xml:"bar" binding:"required"`
|
||||
}
|
||||
|
||||
func TestBindingDefault(t *testing.T) {
|
||||
assert.Equal(t, Default("GET", ""), Form)
|
||||
assert.Equal(t, Default("GET", MIMEJSON), Form)
|
||||
|
||||
assert.Equal(t, Default("POST", MIMEJSON), JSON)
|
||||
assert.Equal(t, Default("PUT", MIMEJSON), JSON)
|
||||
|
||||
assert.Equal(t, Default("POST", MIMEXML), XML)
|
||||
assert.Equal(t, Default("PUT", MIMEXML2), XML)
|
||||
|
||||
assert.Equal(t, Default("POST", MIMEPOSTForm), Form)
|
||||
assert.Equal(t, Default("PUT", MIMEPOSTForm), Form)
|
||||
|
||||
assert.Equal(t, Default("POST", MIMEMultipartPOSTForm), Form)
|
||||
assert.Equal(t, Default("PUT", MIMEMultipartPOSTForm), Form)
|
||||
|
||||
assert.Equal(t, Default("POST", MIMEPROTOBUF), ProtoBuf)
|
||||
assert.Equal(t, Default("PUT", MIMEPROTOBUF), ProtoBuf)
|
||||
|
||||
assert.Equal(t, Default("POST", MIMEMSGPACK), MsgPack)
|
||||
assert.Equal(t, Default("PUT", MIMEMSGPACK2), MsgPack)
|
||||
}
|
||||
|
||||
func TestBindingJSON(t *testing.T) {
|
||||
testBodyBinding(t,
|
||||
JSON, "json",
|
||||
"/", "/",
|
||||
`{"foo": "bar"}`, `{"bar": "foo"}`)
|
||||
}
|
||||
|
||||
func TestBindingForm(t *testing.T) {
|
||||
testFormBinding(t, "POST",
|
||||
"/", "/",
|
||||
"foo=bar&bar=foo", "bar2=foo")
|
||||
}
|
||||
|
||||
func TestBindingForm2(t *testing.T) {
|
||||
testFormBinding(t, "GET",
|
||||
"/?foo=bar&bar=foo", "/?bar2=foo",
|
||||
"", "")
|
||||
}
|
||||
|
||||
func TestBindingXML(t *testing.T) {
|
||||
testBodyBinding(t,
|
||||
XML, "xml",
|
||||
"/", "/",
|
||||
"<map><foo>bar</foo></map>", "<map><bar>foo</bar></map>")
|
||||
}
|
||||
|
||||
func createFormPostRequest() *http.Request {
|
||||
req, _ := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", bytes.NewBufferString("foo=bar&bar=foo"))
|
||||
req.Header.Set("Content-Type", MIMEPOSTForm)
|
||||
return req
|
||||
}
|
||||
|
||||
func createFormMultipartRequest() *http.Request {
|
||||
boundary := "--testboundary"
|
||||
body := new(bytes.Buffer)
|
||||
mw := multipart.NewWriter(body)
|
||||
defer mw.Close()
|
||||
|
||||
mw.SetBoundary(boundary)
|
||||
mw.WriteField("foo", "bar")
|
||||
mw.WriteField("bar", "foo")
|
||||
req, _ := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", body)
|
||||
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
|
||||
return req
|
||||
}
|
||||
|
||||
func TestBindingFormPost(t *testing.T) {
|
||||
req := createFormPostRequest()
|
||||
var obj FooBarStruct
|
||||
FormPost.Bind(req, &obj)
|
||||
|
||||
assert.Equal(t, obj.Foo, "bar")
|
||||
assert.Equal(t, obj.Bar, "foo")
|
||||
}
|
||||
|
||||
func TestBindingFormMultipart(t *testing.T) {
|
||||
req := createFormMultipartRequest()
|
||||
var obj FooBarStruct
|
||||
FormMultipart.Bind(req, &obj)
|
||||
|
||||
assert.Equal(t, obj.Foo, "bar")
|
||||
assert.Equal(t, obj.Bar, "foo")
|
||||
}
|
||||
|
||||
func TestBindingProtoBuf(t *testing.T) {
|
||||
test := &example.Test{
|
||||
Label: proto.String("yes"),
|
||||
}
|
||||
data, _ := proto.Marshal(test)
|
||||
|
||||
testProtoBodyBinding(t,
|
||||
ProtoBuf, "protobuf",
|
||||
"/", "/",
|
||||
string(data), string(data[1:]))
|
||||
}
|
||||
|
||||
func TestBindingMsgPack(t *testing.T) {
|
||||
test := FooStruct{
|
||||
Foo: "bar",
|
||||
}
|
||||
|
||||
h := new(codec.MsgpackHandle)
|
||||
assert.NotNil(t, h)
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
assert.NotNil(t, buf)
|
||||
err := codec.NewEncoder(buf, h).Encode(test)
|
||||
assert.NoError(t, err)
|
||||
|
||||
data := buf.Bytes()
|
||||
|
||||
testMsgPackBodyBinding(t,
|
||||
MsgPack, "msgpack",
|
||||
"/", "/",
|
||||
string(data), string(data[1:]))
|
||||
}
|
||||
|
||||
func TestValidationFails(t *testing.T) {
|
||||
var obj FooStruct
|
||||
req := requestWithBody("POST", "/", `{"bar": "foo"}`)
|
||||
err := JSON.Bind(req, &obj)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestValidationDisabled(t *testing.T) {
|
||||
backup := Validator
|
||||
Validator = nil
|
||||
defer func() { Validator = backup }()
|
||||
|
||||
var obj FooStruct
|
||||
req := requestWithBody("POST", "/", `{"bar": "foo"}`)
|
||||
err := JSON.Bind(req, &obj)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestExistsSucceeds(t *testing.T) {
|
||||
type HogeStruct struct {
|
||||
Hoge *int `json:"hoge" binding:"exists"`
|
||||
}
|
||||
|
||||
var obj HogeStruct
|
||||
req := requestWithBody("POST", "/", `{"hoge": 0}`)
|
||||
err := JSON.Bind(req, &obj)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestExistsFails(t *testing.T) {
|
||||
type HogeStruct struct {
|
||||
Hoge *int `json:"foo" binding:"exists"`
|
||||
}
|
||||
|
||||
var obj HogeStruct
|
||||
req := requestWithBody("POST", "/", `{"boen": 0}`)
|
||||
err := JSON.Bind(req, &obj)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func testFormBinding(t *testing.T, method, path, badPath, body, badBody string) {
|
||||
b := Form
|
||||
assert.Equal(t, b.Name(), "form")
|
||||
|
||||
obj := FooBarStruct{}
|
||||
req := requestWithBody(method, path, body)
|
||||
if method == "POST" {
|
||||
req.Header.Add("Content-Type", MIMEPOSTForm)
|
||||
}
|
||||
err := b.Bind(req, &obj)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, obj.Foo, "bar")
|
||||
assert.Equal(t, obj.Bar, "foo")
|
||||
|
||||
obj = FooBarStruct{}
|
||||
req = requestWithBody(method, badPath, badBody)
|
||||
err = JSON.Bind(req, &obj)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func testBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
|
||||
assert.Equal(t, b.Name(), name)
|
||||
|
||||
obj := FooStruct{}
|
||||
req := requestWithBody("POST", path, body)
|
||||
err := b.Bind(req, &obj)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, obj.Foo, "bar")
|
||||
|
||||
obj = FooStruct{}
|
||||
req = requestWithBody("POST", badPath, badBody)
|
||||
err = JSON.Bind(req, &obj)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func testProtoBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
|
||||
assert.Equal(t, b.Name(), name)
|
||||
|
||||
obj := example.Test{}
|
||||
req := requestWithBody("POST", path, body)
|
||||
req.Header.Add("Content-Type", MIMEPROTOBUF)
|
||||
err := b.Bind(req, &obj)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, *obj.Label, "yes")
|
||||
|
||||
obj = example.Test{}
|
||||
req = requestWithBody("POST", badPath, badBody)
|
||||
req.Header.Add("Content-Type", MIMEPROTOBUF)
|
||||
err = ProtoBuf.Bind(req, &obj)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func testMsgPackBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
|
||||
assert.Equal(t, b.Name(), name)
|
||||
|
||||
obj := FooStruct{}
|
||||
req := requestWithBody("POST", path, body)
|
||||
req.Header.Add("Content-Type", MIMEMSGPACK)
|
||||
err := b.Bind(req, &obj)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, obj.Foo, "bar")
|
||||
|
||||
obj = FooStruct{}
|
||||
req = requestWithBody("POST", badPath, badBody)
|
||||
req.Header.Add("Content-Type", MIMEMSGPACK)
|
||||
err = MsgPack.Bind(req, &obj)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func requestWithBody(method, path, body string) (req *http.Request) {
|
||||
req, _ = http.NewRequest(method, path, bytes.NewBufferString(body))
|
||||
return
|
||||
}
|
||||
45
vendor/github.com/gin-gonic/gin/binding/default_validator.go
generated
vendored
Normal file
45
vendor/github.com/gin-gonic/gin/binding/default_validator.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright 2017 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"gopkg.in/go-playground/validator.v8"
|
||||
)
|
||||
|
||||
type defaultValidator struct {
|
||||
once sync.Once
|
||||
validate *validator.Validate
|
||||
}
|
||||
|
||||
var _ StructValidator = &defaultValidator{}
|
||||
|
||||
func (v *defaultValidator) ValidateStruct(obj interface{}) error {
|
||||
if kindOfData(obj) == reflect.Struct {
|
||||
v.lazyinit()
|
||||
if err := v.validate.Struct(obj); err != nil {
|
||||
return error(err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *defaultValidator) lazyinit() {
|
||||
v.once.Do(func() {
|
||||
config := &validator.Config{TagName: "binding"}
|
||||
v.validate = validator.New(config)
|
||||
})
|
||||
}
|
||||
|
||||
func kindOfData(data interface{}) reflect.Kind {
|
||||
value := reflect.ValueOf(data)
|
||||
valueType := value.Kind()
|
||||
if valueType == reflect.Ptr {
|
||||
valueType = value.Elem().Kind()
|
||||
}
|
||||
return valueType
|
||||
}
|
||||
113
vendor/github.com/gin-gonic/gin/binding/example/test.pb.go
generated
vendored
Normal file
113
vendor/github.com/gin-gonic/gin/binding/example/test.pb.go
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
// Code generated by protoc-gen-go.
|
||||
// source: test.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
/*
|
||||
Package example is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
test.proto
|
||||
|
||||
It has these top-level messages:
|
||||
Test
|
||||
*/
|
||||
package example
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import math "math"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = math.Inf
|
||||
|
||||
type FOO int32
|
||||
|
||||
const (
|
||||
FOO_X FOO = 17
|
||||
)
|
||||
|
||||
var FOO_name = map[int32]string{
|
||||
17: "X",
|
||||
}
|
||||
var FOO_value = map[string]int32{
|
||||
"X": 17,
|
||||
}
|
||||
|
||||
func (x FOO) Enum() *FOO {
|
||||
p := new(FOO)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
func (x FOO) String() string {
|
||||
return proto.EnumName(FOO_name, int32(x))
|
||||
}
|
||||
func (x *FOO) UnmarshalJSON(data []byte) error {
|
||||
value, err := proto.UnmarshalJSONEnum(FOO_value, data, "FOO")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*x = FOO(value)
|
||||
return nil
|
||||
}
|
||||
|
||||
type Test struct {
|
||||
Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"`
|
||||
Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"`
|
||||
Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"`
|
||||
Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Test) Reset() { *m = Test{} }
|
||||
func (m *Test) String() string { return proto.CompactTextString(m) }
|
||||
func (*Test) ProtoMessage() {}
|
||||
|
||||
const Default_Test_Type int32 = 77
|
||||
|
||||
func (m *Test) GetLabel() string {
|
||||
if m != nil && m.Label != nil {
|
||||
return *m.Label
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Test) GetType() int32 {
|
||||
if m != nil && m.Type != nil {
|
||||
return *m.Type
|
||||
}
|
||||
return Default_Test_Type
|
||||
}
|
||||
|
||||
func (m *Test) GetReps() []int64 {
|
||||
if m != nil {
|
||||
return m.Reps
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Test) GetOptionalgroup() *Test_OptionalGroup {
|
||||
if m != nil {
|
||||
return m.Optionalgroup
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Test_OptionalGroup struct {
|
||||
RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} }
|
||||
func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) }
|
||||
func (*Test_OptionalGroup) ProtoMessage() {}
|
||||
|
||||
func (m *Test_OptionalGroup) GetRequiredField() string {
|
||||
if m != nil && m.RequiredField != nil {
|
||||
return *m.RequiredField
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterEnum("example.FOO", FOO_name, FOO_value)
|
||||
}
|
||||
12
vendor/github.com/gin-gonic/gin/binding/example/test.proto
generated
vendored
Normal file
12
vendor/github.com/gin-gonic/gin/binding/example/test.proto
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
package example;
|
||||
|
||||
enum FOO {X=17;};
|
||||
|
||||
message Test {
|
||||
required string label = 1;
|
||||
optional int32 type = 2[default=77];
|
||||
repeated int64 reps = 3;
|
||||
optional group OptionalGroup = 4{
|
||||
required string RequiredField = 5;
|
||||
}
|
||||
}
|
||||
54
vendor/github.com/gin-gonic/gin/binding/form.go
generated
vendored
Normal file
54
vendor/github.com/gin-gonic/gin/binding/form.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
import "net/http"
|
||||
|
||||
type formBinding struct{}
|
||||
type formPostBinding struct{}
|
||||
type formMultipartBinding struct{}
|
||||
|
||||
func (formBinding) Name() string {
|
||||
return "form"
|
||||
}
|
||||
|
||||
func (formBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
req.ParseMultipartForm(32 << 10) // 32 MB
|
||||
if err := mapForm(obj, req.Form); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
|
||||
func (formPostBinding) Name() string {
|
||||
return "form-urlencoded"
|
||||
}
|
||||
|
||||
func (formPostBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := mapForm(obj, req.PostForm); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
|
||||
func (formMultipartBinding) Name() string {
|
||||
return "multipart/form-data"
|
||||
}
|
||||
|
||||
func (formMultipartBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
if err := req.ParseMultipartForm(32 << 10); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := mapForm(obj, req.MultipartForm.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
182
vendor/github.com/gin-gonic/gin/binding/form_mapping.go
generated
vendored
Normal file
182
vendor/github.com/gin-gonic/gin/binding/form_mapping.go
generated
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func mapForm(ptr interface{}, form map[string][]string) error {
|
||||
typ := reflect.TypeOf(ptr).Elem()
|
||||
val := reflect.ValueOf(ptr).Elem()
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
typeField := typ.Field(i)
|
||||
structField := val.Field(i)
|
||||
if !structField.CanSet() {
|
||||
continue
|
||||
}
|
||||
|
||||
structFieldKind := structField.Kind()
|
||||
inputFieldName := typeField.Tag.Get("form")
|
||||
if inputFieldName == "" {
|
||||
inputFieldName = typeField.Name
|
||||
|
||||
// if "form" tag is nil, we inspect if the field is a struct.
|
||||
// this would not make sense for JSON parsing but it does for a form
|
||||
// since data is flatten
|
||||
if structFieldKind == reflect.Struct {
|
||||
err := mapForm(structField.Addr().Interface(), form)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
inputValue, exists := form[inputFieldName]
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
|
||||
numElems := len(inputValue)
|
||||
if structFieldKind == reflect.Slice && numElems > 0 {
|
||||
sliceOf := structField.Type().Elem().Kind()
|
||||
slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
|
||||
for i := 0; i < numElems; i++ {
|
||||
if err := setWithProperType(sliceOf, inputValue[i], slice.Index(i)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
val.Field(i).Set(slice)
|
||||
} else {
|
||||
if _, isTime := structField.Interface().(time.Time); isTime {
|
||||
if err := setTimeField(inputValue[0], typeField, structField); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error {
|
||||
switch valueKind {
|
||||
case reflect.Int:
|
||||
return setIntField(val, 0, structField)
|
||||
case reflect.Int8:
|
||||
return setIntField(val, 8, structField)
|
||||
case reflect.Int16:
|
||||
return setIntField(val, 16, structField)
|
||||
case reflect.Int32:
|
||||
return setIntField(val, 32, structField)
|
||||
case reflect.Int64:
|
||||
return setIntField(val, 64, structField)
|
||||
case reflect.Uint:
|
||||
return setUintField(val, 0, structField)
|
||||
case reflect.Uint8:
|
||||
return setUintField(val, 8, structField)
|
||||
case reflect.Uint16:
|
||||
return setUintField(val, 16, structField)
|
||||
case reflect.Uint32:
|
||||
return setUintField(val, 32, structField)
|
||||
case reflect.Uint64:
|
||||
return setUintField(val, 64, structField)
|
||||
case reflect.Bool:
|
||||
return setBoolField(val, structField)
|
||||
case reflect.Float32:
|
||||
return setFloatField(val, 32, structField)
|
||||
case reflect.Float64:
|
||||
return setFloatField(val, 64, structField)
|
||||
case reflect.String:
|
||||
structField.SetString(val)
|
||||
default:
|
||||
return errors.New("Unknown type")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setIntField(val string, bitSize int, field reflect.Value) error {
|
||||
if val == "" {
|
||||
val = "0"
|
||||
}
|
||||
intVal, err := strconv.ParseInt(val, 10, bitSize)
|
||||
if err == nil {
|
||||
field.SetInt(intVal)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func setUintField(val string, bitSize int, field reflect.Value) error {
|
||||
if val == "" {
|
||||
val = "0"
|
||||
}
|
||||
uintVal, err := strconv.ParseUint(val, 10, bitSize)
|
||||
if err == nil {
|
||||
field.SetUint(uintVal)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func setBoolField(val string, field reflect.Value) error {
|
||||
if val == "" {
|
||||
val = "false"
|
||||
}
|
||||
boolVal, err := strconv.ParseBool(val)
|
||||
if err == nil {
|
||||
field.SetBool(boolVal)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setFloatField(val string, bitSize int, field reflect.Value) error {
|
||||
if val == "" {
|
||||
val = "0.0"
|
||||
}
|
||||
floatVal, err := strconv.ParseFloat(val, bitSize)
|
||||
if err == nil {
|
||||
field.SetFloat(floatVal)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func setTimeField(val string, structField reflect.StructField, value reflect.Value) error {
|
||||
timeFormat := structField.Tag.Get("time_format")
|
||||
if timeFormat == "" {
|
||||
return errors.New("Blank time format")
|
||||
}
|
||||
|
||||
if val == "" {
|
||||
value.Set(reflect.ValueOf(time.Time{}))
|
||||
return nil
|
||||
}
|
||||
|
||||
l := time.Local
|
||||
if isUTC, _ := strconv.ParseBool(structField.Tag.Get("time_utc")); isUTC {
|
||||
l = time.UTC
|
||||
}
|
||||
|
||||
t, err := time.ParseInLocation(timeFormat, val, l)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
value.Set(reflect.ValueOf(t))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Don't pass in pointers to bind to. Can lead to bugs. See:
|
||||
// https://github.com/codegangsta/martini-contrib/issues/40
|
||||
// https://github.com/codegangsta/martini-contrib/pull/34#issuecomment-29683659
|
||||
func ensureNotPointer(obj interface{}) {
|
||||
if reflect.TypeOf(obj).Kind() == reflect.Ptr {
|
||||
panic("Pointers are not accepted as binding models")
|
||||
}
|
||||
}
|
||||
24
vendor/github.com/gin-gonic/gin/binding/json.go
generated
vendored
Normal file
24
vendor/github.com/gin-gonic/gin/binding/json.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type jsonBinding struct{}
|
||||
|
||||
func (jsonBinding) Name() string {
|
||||
return "json"
|
||||
}
|
||||
|
||||
func (jsonBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
decoder := json.NewDecoder(req.Body)
|
||||
if err := decoder.Decode(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
28
vendor/github.com/gin-gonic/gin/binding/msgpack.go
generated
vendored
Normal file
28
vendor/github.com/gin-gonic/gin/binding/msgpack.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright 2017 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/ugorji/go/codec"
|
||||
)
|
||||
|
||||
type msgpackBinding struct{}
|
||||
|
||||
func (msgpackBinding) Name() string {
|
||||
return "msgpack"
|
||||
}
|
||||
|
||||
func (msgpackBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
|
||||
if err := codec.NewDecoder(req.Body, new(codec.MsgpackHandle)).Decode(&obj); err != nil {
|
||||
//var decoder *codec.Decoder = codec.NewDecoder(req.Body, &codec.MsgpackHandle)
|
||||
//if err := decoder.Decode(&obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
|
||||
}
|
||||
35
vendor/github.com/gin-gonic/gin/binding/protobuf.go
generated
vendored
Normal file
35
vendor/github.com/gin-gonic/gin/binding/protobuf.go
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
)
|
||||
|
||||
type protobufBinding struct{}
|
||||
|
||||
func (protobufBinding) Name() string {
|
||||
return "protobuf"
|
||||
}
|
||||
|
||||
func (protobufBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
|
||||
buf, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = proto.Unmarshal(buf, obj.(proto.Message)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//Here it's same to return validate(obj), but util now we cann't add `binding:""` to the struct
|
||||
//which automatically generate by gen-proto
|
||||
return nil
|
||||
//return validate(obj)
|
||||
}
|
||||
192
vendor/github.com/gin-gonic/gin/binding/validate_test.go
generated
vendored
Normal file
192
vendor/github.com/gin-gonic/gin/binding/validate_test.go
generated
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type testInterface interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
type substructNoValidation struct {
|
||||
IString string
|
||||
IInt int
|
||||
}
|
||||
|
||||
type mapNoValidationSub map[string]substructNoValidation
|
||||
|
||||
type structNoValidationValues struct {
|
||||
substructNoValidation
|
||||
|
||||
Boolean bool
|
||||
|
||||
Uinteger uint
|
||||
Integer int
|
||||
Integer8 int8
|
||||
Integer16 int16
|
||||
Integer32 int32
|
||||
Integer64 int64
|
||||
Uinteger8 uint8
|
||||
Uinteger16 uint16
|
||||
Uinteger32 uint32
|
||||
Uinteger64 uint64
|
||||
|
||||
Float32 float32
|
||||
Float64 float64
|
||||
|
||||
String string
|
||||
|
||||
Date time.Time
|
||||
|
||||
Struct substructNoValidation
|
||||
InlinedStruct struct {
|
||||
String []string
|
||||
Integer int
|
||||
}
|
||||
|
||||
IntSlice []int
|
||||
IntPointerSlice []*int
|
||||
StructPointerSlice []*substructNoValidation
|
||||
StructSlice []substructNoValidation
|
||||
InterfaceSlice []testInterface
|
||||
|
||||
UniversalInterface interface{}
|
||||
CustomInterface testInterface
|
||||
|
||||
FloatMap map[string]float32
|
||||
StructMap mapNoValidationSub
|
||||
}
|
||||
|
||||
func createNoValidationValues() structNoValidationValues {
|
||||
integer := 1
|
||||
s := structNoValidationValues{
|
||||
Boolean: true,
|
||||
Uinteger: 1 << 29,
|
||||
Integer: -10000,
|
||||
Integer8: 120,
|
||||
Integer16: -20000,
|
||||
Integer32: 1 << 29,
|
||||
Integer64: 1 << 61,
|
||||
Uinteger8: 250,
|
||||
Uinteger16: 50000,
|
||||
Uinteger32: 1 << 31,
|
||||
Uinteger64: 1 << 62,
|
||||
Float32: 123.456,
|
||||
Float64: 123.456789,
|
||||
String: "text",
|
||||
Date: time.Time{},
|
||||
CustomInterface: &bytes.Buffer{},
|
||||
Struct: substructNoValidation{},
|
||||
IntSlice: []int{-3, -2, 1, 0, 1, 2, 3},
|
||||
IntPointerSlice: []*int{&integer},
|
||||
StructSlice: []substructNoValidation{},
|
||||
UniversalInterface: 1.2,
|
||||
FloatMap: map[string]float32{
|
||||
"foo": 1.23,
|
||||
"bar": 232.323,
|
||||
},
|
||||
StructMap: mapNoValidationSub{
|
||||
"foo": substructNoValidation{},
|
||||
"bar": substructNoValidation{},
|
||||
},
|
||||
// StructPointerSlice []noValidationSub
|
||||
// InterfaceSlice []testInterface
|
||||
}
|
||||
s.InlinedStruct.Integer = 1000
|
||||
s.InlinedStruct.String = []string{"first", "second"}
|
||||
s.IString = "substring"
|
||||
s.IInt = 987654
|
||||
return s
|
||||
}
|
||||
|
||||
func TestValidateNoValidationValues(t *testing.T) {
|
||||
origin := createNoValidationValues()
|
||||
test := createNoValidationValues()
|
||||
empty := structNoValidationValues{}
|
||||
|
||||
assert.Nil(t, validate(test))
|
||||
assert.Nil(t, validate(&test))
|
||||
assert.Nil(t, validate(empty))
|
||||
assert.Nil(t, validate(&empty))
|
||||
|
||||
assert.Equal(t, origin, test)
|
||||
}
|
||||
|
||||
type structNoValidationPointer struct {
|
||||
substructNoValidation
|
||||
|
||||
Boolean bool
|
||||
|
||||
Uinteger *uint
|
||||
Integer *int
|
||||
Integer8 *int8
|
||||
Integer16 *int16
|
||||
Integer32 *int32
|
||||
Integer64 *int64
|
||||
Uinteger8 *uint8
|
||||
Uinteger16 *uint16
|
||||
Uinteger32 *uint32
|
||||
Uinteger64 *uint64
|
||||
|
||||
Float32 *float32
|
||||
Float64 *float64
|
||||
|
||||
String *string
|
||||
|
||||
Date *time.Time
|
||||
|
||||
Struct *substructNoValidation
|
||||
|
||||
IntSlice *[]int
|
||||
IntPointerSlice *[]*int
|
||||
StructPointerSlice *[]*substructNoValidation
|
||||
StructSlice *[]substructNoValidation
|
||||
InterfaceSlice *[]testInterface
|
||||
|
||||
FloatMap *map[string]float32
|
||||
StructMap *mapNoValidationSub
|
||||
}
|
||||
|
||||
func TestValidateNoValidationPointers(t *testing.T) {
|
||||
//origin := createNoValidation_values()
|
||||
//test := createNoValidation_values()
|
||||
empty := structNoValidationPointer{}
|
||||
|
||||
//assert.Nil(t, validate(test))
|
||||
//assert.Nil(t, validate(&test))
|
||||
assert.Nil(t, validate(empty))
|
||||
assert.Nil(t, validate(&empty))
|
||||
|
||||
//assert.Equal(t, origin, test)
|
||||
}
|
||||
|
||||
type Object map[string]interface{}
|
||||
|
||||
func TestValidatePrimitives(t *testing.T) {
|
||||
obj := Object{"foo": "bar", "bar": 1}
|
||||
assert.NoError(t, validate(obj))
|
||||
assert.NoError(t, validate(&obj))
|
||||
assert.Equal(t, obj, Object{"foo": "bar", "bar": 1})
|
||||
|
||||
obj2 := []Object{{"foo": "bar", "bar": 1}, {"foo": "bar", "bar": 1}}
|
||||
assert.NoError(t, validate(obj2))
|
||||
assert.NoError(t, validate(&obj2))
|
||||
|
||||
nu := 10
|
||||
assert.NoError(t, validate(nu))
|
||||
assert.NoError(t, validate(&nu))
|
||||
assert.Equal(t, nu, 10)
|
||||
|
||||
str := "value"
|
||||
assert.NoError(t, validate(str))
|
||||
assert.NoError(t, validate(&str))
|
||||
assert.Equal(t, str, "value")
|
||||
}
|
||||
24
vendor/github.com/gin-gonic/gin/binding/xml.go
generated
vendored
Normal file
24
vendor/github.com/gin-gonic/gin/binding/xml.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type xmlBinding struct{}
|
||||
|
||||
func (xmlBinding) Name() string {
|
||||
return "xml"
|
||||
}
|
||||
|
||||
func (xmlBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
decoder := xml.NewDecoder(req.Body)
|
||||
if err := decoder.Decode(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
5
vendor/github.com/gin-gonic/gin/codecov.yml
generated
vendored
Normal file
5
vendor/github.com/gin-gonic/gin/codecov.yml
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
coverage:
|
||||
notify:
|
||||
gitter:
|
||||
default:
|
||||
url: https://webhooks.gitter.im/e/d90dcdeeab2f1e357165
|
||||
888
vendor/github.com/gin-gonic/gin/context.go
generated
vendored
888
vendor/github.com/gin-gonic/gin/context.go
generated
vendored
File diff suppressed because it is too large
Load Diff
11
vendor/github.com/gin-gonic/gin/context_appengine.go
generated
vendored
Normal file
11
vendor/github.com/gin-gonic/gin/context_appengine.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// +build appengine
|
||||
|
||||
// Copyright 2017 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gin
|
||||
|
||||
func init() {
|
||||
defaultAppEngine = true
|
||||
}
|
||||
1466
vendor/github.com/gin-gonic/gin/context_test.go
generated
vendored
1466
vendor/github.com/gin-gonic/gin/context_test.go
generated
vendored
File diff suppressed because it is too large
Load Diff
71
vendor/github.com/gin-gonic/gin/debug.go
generated
vendored
Normal file
71
vendor/github.com/gin-gonic/gin/debug.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"html/template"
|
||||
"log"
|
||||
)
|
||||
|
||||
func init() {
|
||||
log.SetFlags(0)
|
||||
}
|
||||
|
||||
// IsDebugging returns true if the framework is running in debug mode.
|
||||
// Use SetMode(gin.Release) to switch to disable the debug mode.
|
||||
func IsDebugging() bool {
|
||||
return ginMode == debugCode
|
||||
}
|
||||
|
||||
func debugPrintRoute(httpMethod, absolutePath string, handlers HandlersChain) {
|
||||
if IsDebugging() {
|
||||
nuHandlers := len(handlers)
|
||||
handlerName := nameOfFunction(handlers.Last())
|
||||
debugPrint("%-6s %-25s --> %s (%d handlers)\n", httpMethod, absolutePath, handlerName, nuHandlers)
|
||||
}
|
||||
}
|
||||
|
||||
func debugPrintLoadTemplate(tmpl *template.Template) {
|
||||
if IsDebugging() {
|
||||
var buf bytes.Buffer
|
||||
for _, tmpl := range tmpl.Templates() {
|
||||
buf.WriteString("\t- ")
|
||||
buf.WriteString(tmpl.Name())
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
debugPrint("Loaded HTML Templates (%d): \n%s\n", len(tmpl.Templates()), buf.String())
|
||||
}
|
||||
}
|
||||
|
||||
func debugPrint(format string, values ...interface{}) {
|
||||
if IsDebugging() {
|
||||
log.Printf("[GIN-debug] "+format, values...)
|
||||
}
|
||||
}
|
||||
|
||||
func debugPrintWARNINGNew() {
|
||||
debugPrint(`[WARNING] Running in "debug" mode. Switch to "release" mode in production.
|
||||
- using env: export GIN_MODE=release
|
||||
- using code: gin.SetMode(gin.ReleaseMode)
|
||||
|
||||
`)
|
||||
}
|
||||
|
||||
func debugPrintWARNINGSetHTMLTemplate() {
|
||||
debugPrint(`[WARNING] Since SetHTMLTemplate() is NOT thread-safe. It should only be called
|
||||
at initialization. ie. before any route is registered or the router is listening in a socket:
|
||||
|
||||
router := gin.Default()
|
||||
router.SetHTMLTemplate(template) // << good place
|
||||
|
||||
`)
|
||||
}
|
||||
|
||||
func debugPrintError(err error) {
|
||||
if err != nil {
|
||||
debugPrint("[ERROR] %v\n", err)
|
||||
}
|
||||
}
|
||||
97
vendor/github.com/gin-gonic/gin/debug_test.go
generated
vendored
Normal file
97
vendor/github.com/gin-gonic/gin/debug_test.go
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"html/template"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// TODO
|
||||
// func debugRoute(httpMethod, absolutePath string, handlers HandlersChain) {
|
||||
// func debugPrint(format string, values ...interface{}) {
|
||||
|
||||
func TestIsDebugging(t *testing.T) {
|
||||
SetMode(DebugMode)
|
||||
assert.True(t, IsDebugging())
|
||||
SetMode(ReleaseMode)
|
||||
assert.False(t, IsDebugging())
|
||||
SetMode(TestMode)
|
||||
assert.False(t, IsDebugging())
|
||||
}
|
||||
|
||||
func TestDebugPrint(t *testing.T) {
|
||||
var w bytes.Buffer
|
||||
setup(&w)
|
||||
defer teardown()
|
||||
|
||||
SetMode(ReleaseMode)
|
||||
debugPrint("DEBUG this!")
|
||||
SetMode(TestMode)
|
||||
debugPrint("DEBUG this!")
|
||||
assert.Empty(t, w.String())
|
||||
|
||||
SetMode(DebugMode)
|
||||
debugPrint("these are %d %s\n", 2, "error messages")
|
||||
assert.Equal(t, w.String(), "[GIN-debug] these are 2 error messages\n")
|
||||
}
|
||||
|
||||
func TestDebugPrintError(t *testing.T) {
|
||||
var w bytes.Buffer
|
||||
setup(&w)
|
||||
defer teardown()
|
||||
|
||||
SetMode(DebugMode)
|
||||
debugPrintError(nil)
|
||||
assert.Empty(t, w.String())
|
||||
|
||||
debugPrintError(errors.New("this is an error"))
|
||||
assert.Equal(t, w.String(), "[GIN-debug] [ERROR] this is an error\n")
|
||||
}
|
||||
|
||||
func TestDebugPrintRoutes(t *testing.T) {
|
||||
var w bytes.Buffer
|
||||
setup(&w)
|
||||
defer teardown()
|
||||
|
||||
debugPrintRoute("GET", "/path/to/route/:param", HandlersChain{func(c *Context) {}, handlerNameTest})
|
||||
assert.Regexp(t, `^\[GIN-debug\] GET /path/to/route/:param --> (.*/vendor/)?github.com/gin-gonic/gin.handlerNameTest \(2 handlers\)\n$`, w.String())
|
||||
}
|
||||
|
||||
func TestDebugPrintLoadTemplate(t *testing.T) {
|
||||
var w bytes.Buffer
|
||||
setup(&w)
|
||||
defer teardown()
|
||||
|
||||
templ := template.Must(template.New("").Delims("{[{", "}]}").ParseGlob("./fixtures/basic/hello.tmpl"))
|
||||
debugPrintLoadTemplate(templ)
|
||||
assert.Equal(t, w.String(), "[GIN-debug] Loaded HTML Templates (2): \n\t- \n\t- hello.tmpl\n\n")
|
||||
}
|
||||
|
||||
func TestDebugPrintWARNINGSetHTMLTemplate(t *testing.T) {
|
||||
var w bytes.Buffer
|
||||
setup(&w)
|
||||
defer teardown()
|
||||
|
||||
debugPrintWARNINGSetHTMLTemplate()
|
||||
assert.Equal(t, w.String(), "[GIN-debug] [WARNING] Since SetHTMLTemplate() is NOT thread-safe. It should only be called\nat initialization. ie. before any route is registered or the router is listening in a socket:\n\n\trouter := gin.Default()\n\trouter.SetHTMLTemplate(template) // << good place\n\n")
|
||||
}
|
||||
|
||||
func setup(w io.Writer) {
|
||||
SetMode(DebugMode)
|
||||
log.SetOutput(w)
|
||||
}
|
||||
|
||||
func teardown() {
|
||||
SetMode(TestMode)
|
||||
log.SetOutput(os.Stdout)
|
||||
}
|
||||
46
vendor/github.com/gin-gonic/gin/deprecated.go
generated
vendored
46
vendor/github.com/gin-gonic/gin/deprecated.go
generated
vendored
@@ -6,42 +6,20 @@ package gin
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
"net/http"
|
||||
"log"
|
||||
)
|
||||
|
||||
// DEPRECATED, use Bind() instead.
|
||||
// Like ParseBody() but this method also writes a 400 error if the json is not valid.
|
||||
func (c *Context) EnsureBody(item interface{}) bool {
|
||||
return c.Bind(item)
|
||||
func (c *Context) GetCookie(name string) (string, error) {
|
||||
log.Println("GetCookie() method is deprecated. Use Cookie() instead.")
|
||||
return c.Cookie(name)
|
||||
}
|
||||
|
||||
// DEPRECATED use bindings directly
|
||||
// Parses the body content as a JSON input. It decodes the json payload into the struct specified as a pointer.
|
||||
func (c *Context) ParseBody(item interface{}) error {
|
||||
return binding.JSON.Bind(c.Request, item)
|
||||
}
|
||||
|
||||
// DEPRECATED use gin.Static() instead
|
||||
// ServeFiles serves files from the given file system root.
|
||||
// The path must end with "/*filepath", files are then served from the local
|
||||
// path /defined/root/dir/*filepath.
|
||||
// For example if root is "/etc" and *filepath is "passwd", the local file
|
||||
// "/etc/passwd" would be served.
|
||||
// Internally a http.FileServer is used, therefore http.NotFound is used instead
|
||||
// of the Router's NotFound handler.
|
||||
// To use the operating system's file system implementation,
|
||||
// use http.Dir:
|
||||
// router.ServeFiles("/src/*filepath", http.Dir("/var/www"))
|
||||
func (engine *Engine) ServeFiles(path string, root http.FileSystem) {
|
||||
engine.router.ServeFiles(path, root)
|
||||
}
|
||||
|
||||
// DEPRECATED use gin.LoadHTMLGlob() or gin.LoadHTMLFiles() instead
|
||||
func (engine *Engine) LoadHTMLTemplates(pattern string) {
|
||||
engine.LoadHTMLGlob(pattern)
|
||||
}
|
||||
|
||||
// DEPRECATED. Use NoRoute() instead
|
||||
func (engine *Engine) NotFound404(handlers ...HandlerFunc) {
|
||||
engine.NoRoute(handlers...)
|
||||
// BindWith binds the passed struct pointer using the specified binding engine.
|
||||
// See the binding package.
|
||||
func (c *Context) BindWith(obj interface{}, b binding.Binding) error {
|
||||
log.Println(`BindWith(\"interface{}, binding.Binding\") error is going to
|
||||
be deprecated, please check issue #662 and either use MustBindWith() if you
|
||||
want HTTP 400 to be automatically returned if any error occur, of use
|
||||
ShouldBindWith() if you need to manage the error.`)
|
||||
return c.MustBindWith(obj, b)
|
||||
}
|
||||
|
||||
159
vendor/github.com/gin-gonic/gin/errors.go
generated
vendored
Normal file
159
vendor/github.com/gin-gonic/gin/errors.go
generated
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type ErrorType uint64
|
||||
|
||||
const (
|
||||
ErrorTypeBind ErrorType = 1 << 63 // used when c.Bind() fails
|
||||
ErrorTypeRender ErrorType = 1 << 62 // used when c.Render() fails
|
||||
ErrorTypePrivate ErrorType = 1 << 0
|
||||
ErrorTypePublic ErrorType = 1 << 1
|
||||
|
||||
ErrorTypeAny ErrorType = 1<<64 - 1
|
||||
ErrorTypeNu = 2
|
||||
)
|
||||
|
||||
type (
|
||||
Error struct {
|
||||
Err error
|
||||
Type ErrorType
|
||||
Meta interface{}
|
||||
}
|
||||
|
||||
errorMsgs []*Error
|
||||
)
|
||||
|
||||
var _ error = &Error{}
|
||||
|
||||
func (msg *Error) SetType(flags ErrorType) *Error {
|
||||
msg.Type = flags
|
||||
return msg
|
||||
}
|
||||
|
||||
func (msg *Error) SetMeta(data interface{}) *Error {
|
||||
msg.Meta = data
|
||||
return msg
|
||||
}
|
||||
|
||||
func (msg *Error) JSON() interface{} {
|
||||
json := H{}
|
||||
if msg.Meta != nil {
|
||||
value := reflect.ValueOf(msg.Meta)
|
||||
switch value.Kind() {
|
||||
case reflect.Struct:
|
||||
return msg.Meta
|
||||
case reflect.Map:
|
||||
for _, key := range value.MapKeys() {
|
||||
json[key.String()] = value.MapIndex(key).Interface()
|
||||
}
|
||||
default:
|
||||
json["meta"] = msg.Meta
|
||||
}
|
||||
}
|
||||
if _, ok := json["error"]; !ok {
|
||||
json["error"] = msg.Error()
|
||||
}
|
||||
return json
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaller interface
|
||||
func (msg *Error) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(msg.JSON())
|
||||
}
|
||||
|
||||
// Implements the error interface
|
||||
func (msg Error) Error() string {
|
||||
return msg.Err.Error()
|
||||
}
|
||||
|
||||
func (msg *Error) IsType(flags ErrorType) bool {
|
||||
return (msg.Type & flags) > 0
|
||||
}
|
||||
|
||||
// Returns a readonly copy filtered the byte.
|
||||
// ie ByType(gin.ErrorTypePublic) returns a slice of errors with type=ErrorTypePublic
|
||||
func (a errorMsgs) ByType(typ ErrorType) errorMsgs {
|
||||
if len(a) == 0 {
|
||||
return nil
|
||||
}
|
||||
if typ == ErrorTypeAny {
|
||||
return a
|
||||
}
|
||||
var result errorMsgs
|
||||
for _, msg := range a {
|
||||
if msg.IsType(typ) {
|
||||
result = append(result, msg)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Returns the last error in the slice. It returns nil if the array is empty.
|
||||
// Shortcut for errors[len(errors)-1]
|
||||
func (a errorMsgs) Last() *Error {
|
||||
length := len(a)
|
||||
if length > 0 {
|
||||
return a[length-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns an array will all the error messages.
|
||||
// Example:
|
||||
// c.Error(errors.New("first"))
|
||||
// c.Error(errors.New("second"))
|
||||
// c.Error(errors.New("third"))
|
||||
// c.Errors.Errors() // == []string{"first", "second", "third"}
|
||||
func (a errorMsgs) Errors() []string {
|
||||
if len(a) == 0 {
|
||||
return nil
|
||||
}
|
||||
errorStrings := make([]string, len(a))
|
||||
for i, err := range a {
|
||||
errorStrings[i] = err.Error()
|
||||
}
|
||||
return errorStrings
|
||||
}
|
||||
|
||||
func (a errorMsgs) JSON() interface{} {
|
||||
switch len(a) {
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
return a.Last().JSON()
|
||||
default:
|
||||
json := make([]interface{}, len(a))
|
||||
for i, err := range a {
|
||||
json[i] = err.JSON()
|
||||
}
|
||||
return json
|
||||
}
|
||||
}
|
||||
|
||||
func (a errorMsgs) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(a.JSON())
|
||||
}
|
||||
|
||||
func (a errorMsgs) String() string {
|
||||
if len(a) == 0 {
|
||||
return ""
|
||||
}
|
||||
var buffer bytes.Buffer
|
||||
for i, msg := range a {
|
||||
fmt.Fprintf(&buffer, "Error #%02d: %s\n", (i + 1), msg.Err)
|
||||
if msg.Meta != nil {
|
||||
fmt.Fprintf(&buffer, " Meta: %v\n", msg.Meta)
|
||||
}
|
||||
}
|
||||
return buffer.String()
|
||||
}
|
||||
106
vendor/github.com/gin-gonic/gin/errors_test.go
generated
vendored
Normal file
106
vendor/github.com/gin-gonic/gin/errors_test.go
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestError(t *testing.T) {
|
||||
baseError := errors.New("test error")
|
||||
err := &Error{
|
||||
Err: baseError,
|
||||
Type: ErrorTypePrivate,
|
||||
}
|
||||
assert.Equal(t, err.Error(), baseError.Error())
|
||||
assert.Equal(t, err.JSON(), H{"error": baseError.Error()})
|
||||
|
||||
assert.Equal(t, err.SetType(ErrorTypePublic), err)
|
||||
assert.Equal(t, err.Type, ErrorTypePublic)
|
||||
|
||||
assert.Equal(t, err.SetMeta("some data"), err)
|
||||
assert.Equal(t, err.Meta, "some data")
|
||||
assert.Equal(t, err.JSON(), H{
|
||||
"error": baseError.Error(),
|
||||
"meta": "some data",
|
||||
})
|
||||
|
||||
jsonBytes, _ := json.Marshal(err)
|
||||
assert.Equal(t, string(jsonBytes), "{\"error\":\"test error\",\"meta\":\"some data\"}")
|
||||
|
||||
err.SetMeta(H{
|
||||
"status": "200",
|
||||
"data": "some data",
|
||||
})
|
||||
assert.Equal(t, err.JSON(), H{
|
||||
"error": baseError.Error(),
|
||||
"status": "200",
|
||||
"data": "some data",
|
||||
})
|
||||
|
||||
err.SetMeta(H{
|
||||
"error": "custom error",
|
||||
"status": "200",
|
||||
"data": "some data",
|
||||
})
|
||||
assert.Equal(t, err.JSON(), H{
|
||||
"error": "custom error",
|
||||
"status": "200",
|
||||
"data": "some data",
|
||||
})
|
||||
|
||||
type customError struct {
|
||||
status string
|
||||
data string
|
||||
}
|
||||
err.SetMeta(customError{status: "200", data: "other data"})
|
||||
assert.Equal(t, err.JSON(), customError{status: "200", data: "other data"})
|
||||
}
|
||||
|
||||
func TestErrorSlice(t *testing.T) {
|
||||
errs := errorMsgs{
|
||||
{Err: errors.New("first"), Type: ErrorTypePrivate},
|
||||
{Err: errors.New("second"), Type: ErrorTypePrivate, Meta: "some data"},
|
||||
{Err: errors.New("third"), Type: ErrorTypePublic, Meta: H{"status": "400"}},
|
||||
}
|
||||
|
||||
assert.Equal(t, errs, errs.ByType(ErrorTypeAny))
|
||||
assert.Equal(t, errs.Last().Error(), "third")
|
||||
assert.Equal(t, errs.Errors(), []string{"first", "second", "third"})
|
||||
assert.Equal(t, errs.ByType(ErrorTypePublic).Errors(), []string{"third"})
|
||||
assert.Equal(t, errs.ByType(ErrorTypePrivate).Errors(), []string{"first", "second"})
|
||||
assert.Equal(t, errs.ByType(ErrorTypePublic|ErrorTypePrivate).Errors(), []string{"first", "second", "third"})
|
||||
assert.Empty(t, errs.ByType(ErrorTypeBind))
|
||||
assert.Empty(t, errs.ByType(ErrorTypeBind).String())
|
||||
|
||||
assert.Equal(t, errs.String(), `Error #01: first
|
||||
Error #02: second
|
||||
Meta: some data
|
||||
Error #03: third
|
||||
Meta: map[status:400]
|
||||
`)
|
||||
assert.Equal(t, errs.JSON(), []interface{}{
|
||||
H{"error": "first"},
|
||||
H{"error": "second", "meta": "some data"},
|
||||
H{"error": "third", "status": "400"},
|
||||
})
|
||||
jsonBytes, _ := json.Marshal(errs)
|
||||
assert.Equal(t, string(jsonBytes), "[{\"error\":\"first\"},{\"error\":\"second\",\"meta\":\"some data\"},{\"error\":\"third\",\"status\":\"400\"}]")
|
||||
errs = errorMsgs{
|
||||
{Err: errors.New("first"), Type: ErrorTypePrivate},
|
||||
}
|
||||
assert.Equal(t, errs.JSON(), H{"error": "first"})
|
||||
jsonBytes, _ = json.Marshal(errs)
|
||||
assert.Equal(t, string(jsonBytes), "{\"error\":\"first\"}")
|
||||
|
||||
errs = errorMsgs{}
|
||||
assert.Nil(t, errs.Last())
|
||||
assert.Nil(t, errs.JSON())
|
||||
assert.Empty(t, errs.String())
|
||||
}
|
||||
7
vendor/github.com/gin-gonic/gin/examples/app-engine/hello.go
generated
vendored
7
vendor/github.com/gin-gonic/gin/examples/app-engine/hello.go
generated
vendored
@@ -2,6 +2,7 @@ package hello
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -11,13 +12,13 @@ func init() {
|
||||
r := gin.New()
|
||||
|
||||
// Define your handlers
|
||||
r.GET("/", func(c *gin.Context){
|
||||
r.GET("/", func(c *gin.Context) {
|
||||
c.String(200, "Hello World!")
|
||||
})
|
||||
r.GET("/ping", func(c *gin.Context){
|
||||
r.GET("/ping", func(c *gin.Context) {
|
||||
c.String(200, "pong")
|
||||
})
|
||||
|
||||
// Handle all requests using net/http
|
||||
http.Handle("/", r)
|
||||
}
|
||||
}
|
||||
|
||||
19
vendor/github.com/gin-gonic/gin/examples/auto-tls/example1.go
generated
vendored
Normal file
19
vendor/github.com/gin-gonic/gin/examples/auto-tls/example1.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/gin-gonic/autotls"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
r := gin.Default()
|
||||
|
||||
// Ping handler
|
||||
r.GET("/ping", func(c *gin.Context) {
|
||||
c.String(200, "pong")
|
||||
})
|
||||
|
||||
log.Fatal(autotls.Run(r, "example1.com", "example2.com"))
|
||||
}
|
||||
26
vendor/github.com/gin-gonic/gin/examples/auto-tls/example2.go
generated
vendored
Normal file
26
vendor/github.com/gin-gonic/gin/examples/auto-tls/example2.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/gin-gonic/autotls"
|
||||
"github.com/gin-gonic/gin"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
)
|
||||
|
||||
func main() {
|
||||
r := gin.Default()
|
||||
|
||||
// Ping handler
|
||||
r.GET("/ping", func(c *gin.Context) {
|
||||
c.String(200, "pong")
|
||||
})
|
||||
|
||||
m := autocert.Manager{
|
||||
Prompt: autocert.AcceptTOS,
|
||||
HostPolicy: autocert.HostWhitelist("example1.com", "example2.com"),
|
||||
Cache: autocert.DirCache("/var/www/.cache"),
|
||||
}
|
||||
|
||||
log.Fatal(autotls.RunWithManager(r, m))
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
var DB = make(map[string]string)
|
||||
|
||||
func main() {
|
||||
// Disable Console Color
|
||||
// gin.DisableConsoleColor()
|
||||
r := gin.Default()
|
||||
|
||||
// Ping test
|
||||
@@ -45,7 +47,7 @@ func main() {
|
||||
Value string `json:"value" binding:"required"`
|
||||
}
|
||||
|
||||
if c.Bind(&json) {
|
||||
if c.Bind(&json) == nil {
|
||||
DB[user] = json.Value
|
||||
c.JSON(200, gin.H{"status": "ok"})
|
||||
}
|
||||
45
vendor/github.com/gin-gonic/gin/examples/graceful-shutdown/close/server.go
generated
vendored
Normal file
45
vendor/github.com/gin-gonic/gin/examples/graceful-shutdown/close/server.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
// +build go1.8
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
router := gin.Default()
|
||||
router.GET("/", func(c *gin.Context) {
|
||||
c.String(http.StatusOK, "Welcome Gin Server")
|
||||
})
|
||||
|
||||
server := &http.Server{
|
||||
Addr: ":8080",
|
||||
Handler: router,
|
||||
}
|
||||
|
||||
quit := make(chan os.Signal)
|
||||
signal.Notify(quit, os.Interrupt)
|
||||
|
||||
go func() {
|
||||
<-quit
|
||||
log.Println("receive interrupt signal")
|
||||
if err := server.Close(); err != nil {
|
||||
log.Fatal("Server Close:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := server.ListenAndServe(); err != nil {
|
||||
if err == http.ErrServerClosed {
|
||||
log.Println("Server closed under request")
|
||||
} else {
|
||||
log.Fatal("Server closed unexpect")
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("Server exist")
|
||||
}
|
||||
48
vendor/github.com/gin-gonic/gin/examples/graceful-shutdown/graceful-shutdown/server.go
generated
vendored
Normal file
48
vendor/github.com/gin-gonic/gin/examples/graceful-shutdown/graceful-shutdown/server.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
// +build go1.8
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
router := gin.Default()
|
||||
router.GET("/", func(c *gin.Context) {
|
||||
time.Sleep(5 * time.Second)
|
||||
c.String(http.StatusOK, "Welcome Gin Server")
|
||||
})
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: ":8080",
|
||||
Handler: router,
|
||||
}
|
||||
|
||||
go func() {
|
||||
// service connections
|
||||
if err := srv.ListenAndServe(); err != nil {
|
||||
log.Printf("listen: %s\n", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for interrupt signal to gracefully shutdown the server with
|
||||
// a timeout of 5 seconds.
|
||||
quit := make(chan os.Signal)
|
||||
signal.Notify(quit, os.Interrupt)
|
||||
<-quit
|
||||
log.Println("Shutdown Server ...")
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
if err := srv.Shutdown(ctx); err != nil {
|
||||
log.Fatal("Server Shutdown:", err)
|
||||
}
|
||||
log.Println("Server exist")
|
||||
}
|
||||
58
vendor/github.com/gin-gonic/gin/examples/pluggable_renderer/example_pongo2.go
generated
vendored
58
vendor/github.com/gin-gonic/gin/examples/pluggable_renderer/example_pongo2.go
generated
vendored
@@ -1,58 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/flosch/pongo2"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type pongoRender struct {
|
||||
cache map[string]*pongo2.Template
|
||||
}
|
||||
|
||||
func newPongoRender() *pongoRender {
|
||||
return &pongoRender{map[string]*pongo2.Template{}}
|
||||
}
|
||||
|
||||
func writeHeader(w http.ResponseWriter, code int, contentType string) {
|
||||
if code >= 0 {
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
w.WriteHeader(code)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *pongoRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
|
||||
file := data[0].(string)
|
||||
ctx := data[1].(pongo2.Context)
|
||||
var t *pongo2.Template
|
||||
|
||||
if tmpl, ok := p.cache[file]; ok {
|
||||
t = tmpl
|
||||
} else {
|
||||
tmpl, err := pongo2.FromFile(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.cache[file] = tmpl
|
||||
t = tmpl
|
||||
}
|
||||
writeHeader(w, code, "text/html")
|
||||
return t.ExecuteWriter(ctx, w)
|
||||
}
|
||||
|
||||
func main() {
|
||||
r := gin.Default()
|
||||
r.HTMLRender = newPongoRender()
|
||||
|
||||
r.GET("/index", func(c *gin.Context) {
|
||||
name := c.Request.FormValue("name")
|
||||
ctx := pongo2.Context{
|
||||
"title": "Gin meets pongo2 !",
|
||||
"name": name,
|
||||
}
|
||||
c.HTML(200, "index.html", ctx)
|
||||
})
|
||||
|
||||
// Listen and server on 0.0.0.0:8080
|
||||
r.Run(":8080")
|
||||
}
|
||||
12
vendor/github.com/gin-gonic/gin/examples/pluggable_renderer/index.html
generated
vendored
12
vendor/github.com/gin-gonic/gin/examples/pluggable_renderer/index.html
generated
vendored
@@ -1,12 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ja">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>{{ title }}</title>
|
||||
<meta name="keywords" content="">
|
||||
<meta name="description" content="">
|
||||
</head>
|
||||
<body>
|
||||
Hello {{ name }} !
|
||||
</body>
|
||||
</html>
|
||||
10
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/Makefile
generated
vendored
Normal file
10
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/Makefile
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
all: deps build
|
||||
|
||||
.PHONY: deps
|
||||
deps:
|
||||
go get -d -v github.com/dustin/go-broadcast/...
|
||||
go get -d -v github.com/manucorporat/stats/...
|
||||
|
||||
.PHONY: build
|
||||
build: deps
|
||||
go build -o realtime-advanced main.go rooms.go routes.go stats.go
|
||||
39
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/main.go
generated
vendored
Normal file
39
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/main.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ConfigRuntime()
|
||||
StartWorkers()
|
||||
StartGin()
|
||||
}
|
||||
|
||||
func ConfigRuntime() {
|
||||
nuCPU := runtime.NumCPU()
|
||||
runtime.GOMAXPROCS(nuCPU)
|
||||
fmt.Printf("Running with %d CPUs\n", nuCPU)
|
||||
}
|
||||
|
||||
func StartWorkers() {
|
||||
go statsWorker()
|
||||
}
|
||||
|
||||
func StartGin() {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
|
||||
router := gin.New()
|
||||
router.Use(rateLimit, gin.Recovery())
|
||||
router.LoadHTMLGlob("resources/*.templ.html")
|
||||
router.Static("/static", "resources/static")
|
||||
router.GET("/", index)
|
||||
router.GET("/room/:roomid", roomGET)
|
||||
router.POST("/room-post/:roomid", roomPOST)
|
||||
router.GET("/stream/:roomid", streamRoom)
|
||||
|
||||
router.Run(":80")
|
||||
}
|
||||
208
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/resources/room_login.templ.html
generated
vendored
Normal file
208
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/resources/room_login.templ.html
generated
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Server-Sent Events. Room "{{.roomid}}"</title>
|
||||
<!-- jQuery -->
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
|
||||
<script src="http://malsup.github.com/jquery.form.js"></script>
|
||||
<!-- EPOCH -->
|
||||
<script src="http://d3js.org/d3.v3.min.js"></script>
|
||||
<script src="/static/epoch.min.js"></script>
|
||||
<link rel="stylesheet" href="/static/epoch.min.css">
|
||||
<script src="/static/realtime.js"></script>
|
||||
<!-- Latest compiled and minified CSS -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
|
||||
<!-- Optional theme -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap-theme.min.css">
|
||||
<!-- Latest compiled and minified JavaScript -->
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
|
||||
<!-- Primjs -->
|
||||
<link href="/static/prismjs.min.css" rel="stylesheet" />
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
StartRealtime({{.roomid}}, {{.timestamp}});
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
body { padding-top: 50px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-fixed-top navbar-inverse">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="#">Server-Sent Events</a>
|
||||
</div>
|
||||
<div id="navbar" class="collapse navbar-collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="active"><a href="#">Demo</a></li>
|
||||
<li><a href="http://www.w3.org/TR/2009/WD-eventsource-20091029/">W3 Standard</a></li>
|
||||
<li><a href="http://caniuse.com/#feat=eventsource">Browser Support</a></li>
|
||||
<li><a href="http://gin-gonic.github.io/gin/">Gin Framework</a></li>
|
||||
<li><a href="https://github.com/gin-gonic/gin/tree/develop/examples/realtime-advanced">Github</a></li>
|
||||
</ul>
|
||||
</div><!-- /.nav-collapse -->
|
||||
</div><!-- /.container -->
|
||||
</nav><!-- /.navbar -->
|
||||
<!-- Main jumbotron for a primary marketing message or call to action -->
|
||||
<div class="jumbotron">
|
||||
<div class="container">
|
||||
<h1>Server-Sent Events in Go</h1>
|
||||
<p>Server-sent events (SSE) is a technology where a browser receives automatic updates from a server via HTTP connection. It is not websockets. <a href="http://www.html5rocks.com/en/tutorials/eventsource/basics/">Learn more.</a></p>
|
||||
<p>The chat and the charts data is provided in realtime using the SSE implemention of <a href="https://github.com/gin-gonic/gin/blob/15b0c49da556d58a3d934b86e3aa552ff224026d/examples/realtime-chat/main.go#L23-L32">Gin Framework</a>.</p>
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div id="chat-scroll" style="overflow-y:scroll; overflow-x:scroll; height:290px">
|
||||
<table id="table-style" class="table" data-show-header="false">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-field="nick" class="col-md-2">Nick</th>
|
||||
<th data-field="message" class="col-md-8">Message</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="chat"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{if .nick}}
|
||||
<form autocomplete="off" class="form-inline" id="chat-form" action="/room-post/{{.roomid}}?nick={{.nick}}" method="post">
|
||||
<div class="form-group">
|
||||
<label class="sr-only" for="chat-message">Message</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon">{{.nick}}</div>
|
||||
<input type="text" name="message" id="chat-message" class="form-control" placeholder="a message" value="" />
|
||||
</div>
|
||||
</div>
|
||||
<input type="submit" class="btn btn-primary" value="Send" />
|
||||
</form>
|
||||
{{else}}
|
||||
<form action="" method="get" class="form-inline">
|
||||
<legend>Join the SSE real-time chat</legend>
|
||||
<div class="form-group">
|
||||
<input value='' name="nick" id="nick" placeholder="Your Name" type="text" class="form-control" />
|
||||
</div>
|
||||
<div class="form-group text-center">
|
||||
<input type="submit" class="btn btn-success btn-login-submit" value="Join" />
|
||||
</div>
|
||||
</form>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div id="messagesChart" class="epoch category10"></div>
|
||||
<p>
|
||||
<span style="font-size:20px; color:#1f77b4">◼︎</span> Users<br>
|
||||
<span style="font-size:20px; color:#ff7f0e">◼︎</span> Inbound messages / sec<br>
|
||||
<span style="font-size:20px; color:#2ca02c">◼︎</span> Outbound messages / sec<br>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<h2>Realtime server Go stats</h2>
|
||||
<div class="col-md-6">
|
||||
<h3>Memory usage</h3>
|
||||
<p>
|
||||
<div id="heapChart" class="epoch category20c"></div>
|
||||
</p>
|
||||
<p>
|
||||
<span style="font-size:20px; color:#1f77b4">◼︎</span> Heap bytes<br>
|
||||
<span style="font-size:20px; color:#aec7e8">◼︎</span> Stack bytes<br>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h3>Allocations per second</h3>
|
||||
<p>
|
||||
<div id="mallocsChart" class="epoch category20b"></div>
|
||||
</p>
|
||||
<p>
|
||||
<span style="font-size:20px; color:#393b79">◼︎</span> Mallocs / sec<br>
|
||||
<span style="font-size:20px; color:#5254a3">◼︎</span> Frees / sec<br>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<h2>MIT Open Sourced</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/gin-gonic/gin/tree/develop/examples/realtime-advanced">This demo website (JS and Go)</a></li>
|
||||
<li><a href="https://github.com/manucorporat/sse">The SSE implementation in Go</a></li>
|
||||
<li><a href="https://github.com/gin-gonic/gin">The Web Framework (Gin)</a></li>
|
||||
</ul>
|
||||
<div class="col-md-6">
|
||||
<script src="/static/prismjs.min.js"></script>
|
||||
<h3>Server-side (Go)</h3>
|
||||
<pre><code class="language-go">func streamRoom(c *gin.Context) {
|
||||
roomid := c.ParamValue("roomid")
|
||||
listener := openListener(roomid)
|
||||
statsTicker := time.NewTicker(1 * time.Second)
|
||||
defer closeListener(roomid, listener)
|
||||
defer statsTicker.Stop()
|
||||
|
||||
c.Stream(func(w io.Writer) bool {
|
||||
select {
|
||||
case msg := <-listener:
|
||||
c.SSEvent("message", msg)
|
||||
case <-statsTicker.C:
|
||||
c.SSEvent("stats", Stats())
|
||||
}
|
||||
return true
|
||||
})
|
||||
}</code></pre>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h3>Client-side (JS)</h3>
|
||||
<pre><code class="language-javascript">function StartSSE(roomid) {
|
||||
var source = new EventSource('/stream/'+roomid);
|
||||
source.addEventListener('message', newChatMessage, false);
|
||||
source.addEventListener('stats', stats, false);
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>SSE package</h3>
|
||||
<pre><code class="language-go">import "github.com/manucorporat/sse"
|
||||
|
||||
func httpHandler(w http.ResponseWriter, req *http.Request) {
|
||||
// data can be a primitive like a string, an integer or a float
|
||||
sse.Encode(w, sse.Event{
|
||||
Event: "message",
|
||||
Data: "some data\nmore data",
|
||||
})
|
||||
|
||||
// also a complex type, like a map, a struct or a slice
|
||||
sse.Encode(w, sse.Event{
|
||||
Id: "124",
|
||||
Event: "message",
|
||||
Data: map[string]interface{}{
|
||||
"user": "manu",
|
||||
"date": time.Now().Unix(),
|
||||
"content": "hi!",
|
||||
},
|
||||
})
|
||||
}</code></pre>
|
||||
<pre>event: message
|
||||
data: some data\\nmore data
|
||||
|
||||
id: 124
|
||||
event: message
|
||||
data: {"content":"hi!","date":1431540810,"user":"manu"}</pre>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<footer>
|
||||
<p>Created with <span class="glyphicon glyphicon-heart"></span> by <a href="https://github.com/manucorporat">Manu Martinez-Almeida</a></p>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
1
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/resources/static/epoch.min.css
generated
vendored
Normal file
1
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/resources/static/epoch.min.css
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
114
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/resources/static/epoch.min.js
generated
vendored
Normal file
114
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/resources/static/epoch.min.js
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
(function(){var e;null==window.Epoch&&(window.Epoch={});null==(e=window.Epoch).Chart&&(e.Chart={});null==(e=window.Epoch).Time&&(e.Time={});null==(e=window.Epoch).Util&&(e.Util={});null==(e=window.Epoch).Formats&&(e.Formats={});Epoch.warn=function(g){return(console.warn||console.log)("Epoch Warning: "+g)};Epoch.exception=function(g){throw"Epoch Error: "+g;}}).call(this);
|
||||
(function(){Epoch.TestContext=function(){function e(){var c,a,d;this._log=[];a=0;for(d=g.length;a<d;a++)c=g[a],this._makeFauxMethod(c)}var g;g="arc arcTo beginPath bezierCurveTo clearRect clip closePath drawImage fill fillRect fillText moveTo quadraticCurveTo rect restore rotate save scale scrollPathIntoView setLineDash setTransform stroke strokeRect strokeText transform translate".split(" ");e.prototype._makeFauxMethod=function(c){return this[c]=function(){var a;return this._log.push(""+c+"("+function(){var d,
|
||||
b,h;h=[];d=0;for(b=arguments.length;d<b;d++)a=arguments[d],h.push(a.toString());return h}.apply(this,arguments).join(",")+")")}};e.prototype.getImageData=function(){var c;this._log.push("getImageData("+function(){var a,d,b;b=[];a=0;for(d=arguments.length;a<d;a++)c=arguments[a],b.push(c.toString());return b}.apply(this,arguments).join(",")+")");return{width:0,height:0,resolution:1,data:[]}};return e}()}).call(this);
|
||||
(function(){var e,g;e=function(c){return function(a){return Object.prototype.toString.call(a)==="[object "+c+"]"}};Epoch.isArray=null!=(g=Array.isArray)?g:e("Array");Epoch.isObject=e("Object");Epoch.isString=e("String");Epoch.isFunction=e("Function");Epoch.isNumber=e("Number");Epoch.isElement=function(c){return"undefined"!==typeof HTMLElement&&null!==HTMLElement?c instanceof HTMLElement:null!=c&&Epoch.isObject(c)&&1===c.nodeType&&Epoch.isString(c.nodeName)};Epoch.Util.copy=function(c){var a,d,b;if(null==
|
||||
c)return null;a={};for(d in c)b=c[d],a[d]=b;return a};Epoch.Util.defaults=function(c,a){var d,b,h,k,f;f=Epoch.Util.copy(c);for(h in a)k=c[h],b=a[h],d=Epoch.isObject(k)&&Epoch.isObject(b),null!=k&&null!=b?d&&!Epoch.isArray(k)?f[h]=Epoch.Util.defaults(k,b):f[h]=k:f[h]=null!=k?k:b;return f};Epoch.Util.formatSI=function(c,a,d){var b,h,k,f;null==a&&(a=1);null==d&&(d=!1);if(1E3>c){if((c|0)!==c||d)c=c.toFixed(a);return c}f="KMGTPEZY".split("");for(h in f)if(k=f[h],b=Math.pow(10,3*((h|0)+1)),c>=b&&c<Math.pow(10,
|
||||
3*((h|0)+2))){c/=b;if(0!==c%1||d)c=c.toFixed(a);return""+c+" "+k}};Epoch.Util.formatBytes=function(c,a,d){var b,h,k,f;null==a&&(a=1);null==d&&(d=!1);if(1024>c){if(0!==c%1||d)c=c.toFixed(a);return""+c+" B"}f="KB MB GB TB PB EB ZB YB".split(" ");for(h in f)if(k=f[h],b=Math.pow(1024,(h|0)+1),c>=b&&c<Math.pow(1024,(h|0)+2)){c/=b;if(0!==c%1||d)c=c.toFixed(a);return""+c+" "+k}};Epoch.Util.dasherize=function(c){return Epoch.Util.trim(c).replace("\n","").replace(/\s+/g,"-").toLowerCase()};Epoch.Util.domain=
|
||||
function(c,a){var d,b,h,k,f,q,u,m;null==a&&(a="x");h={};d=[];k=0;for(q=c.length;k<q;k++)for(b=c[k],m=b.values,f=0,u=m.length;f<u;f++)b=m[f],null==h[b[a]]&&(d.push(b[a]),h[b[a]]=!0);return d};Epoch.Util.trim=function(c){return Epoch.isString(c)?c.replace(/^\s+/g,"").replace(/\s+$/g,""):null};Epoch.Util.getComputedStyle=function(c,a){if(Epoch.isFunction(window.getComputedStyle))return window.getComputedStyle(c,a);if(null!=c.currentStyle)return c.currentStyle};Epoch.Util.toRGBA=function(c,a){var d,b,
|
||||
h;if(d=c.match(/^rgba\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*[0-9\.]+\)/))h=d[1],b=d[2],d=d[3],b="rgba("+h+","+b+","+d+","+a+")";else if(d=d3.rgb(c))b="rgba("+d.r+","+d.g+","+d.b+","+a+")";return b};Epoch.Util.getContext=function(c,a){null==a&&(a="2d");return null!=c.getContext?c.getContext(a):new Epoch.TestContext}}).call(this);
|
||||
(function(){d3.selection.prototype.width=function(e){return null!=e&&Epoch.isString(e)?this.style("width",e):null!=e&&Epoch.isNumber(e)?this.style("width",""+e+"px"):+Epoch.Util.getComputedStyle(this.node(),null).width.replace("px","")};d3.selection.prototype.height=function(e){return null!=e&&Epoch.isString(e)?this.style("height",e):null!=e&&Epoch.isNumber(e)?this.style("height",""+e+"px"):+Epoch.Util.getComputedStyle(this.node(),null).height.replace("px","")}}).call(this);
|
||||
(function(){var e;Epoch.Formats.regular=function(g){return g};Epoch.Formats.si=function(g){return Epoch.Util.formatSI(g)};Epoch.Formats.percent=function(g){return(100*g).toFixed(1)+"%"};Epoch.Formats.seconds=function(g){return e(new Date(1E3*g))};e=d3.time.format("%I:%M:%S %p");Epoch.Formats.bytes=function(g){return Epoch.Util.formatBytes(g)}}).call(this);
|
||||
(function(){var e={}.hasOwnProperty,g=function(c,a){function d(){this.constructor=c}for(var b in a)e.call(a,b)&&(c[b]=a[b]);d.prototype=a.prototype;c.prototype=new d;c.__super__=a.prototype;return c};Epoch.Events=function(){function c(){this._events={}}c.prototype.on=function(a,d){var b;if(null!=d)return null==(b=this._events)[a]&&(b[a]=[]),this._events[a].push(d)};c.prototype.onAll=function(a){var d,b,h;if(Epoch.isObject(a)){h=[];for(b in a)d=a[b],h.push(this.on(b,d));return h}};c.prototype.off=
|
||||
function(a,d){var b,h;if(Epoch.isArray(this._events[a])){if(null==d)return delete this._events[a];for(h=[];0<=(b=this._events[a].indexOf(d));)h.push(this._events[a].splice(b,1));return h}};c.prototype.offAll=function(a){var d,b,h,k;if(Epoch.isArray(a)){k=[];d=0;for(h=a.length;d<h;d++)b=a[d],k.push(this.off(b));return k}if(Epoch.isObject(a)){h=[];for(b in a)d=a[b],h.push(this.off(b,d));return h}};c.prototype.trigger=function(a){var d,b,h,k,f,q,c,m;if(null!=this._events[a]){d=function(){var a,f,q;q=
|
||||
[];k=a=1;for(f=arguments.length;1<=f?a<f:a>f;k=1<=f?++a:--a)q.push(arguments[k]);return q}.apply(this,arguments);c=this._events[a];m=[];f=0;for(q=c.length;f<q;f++)b=c[f],h=null,Epoch.isString(b)?h=this[b]:Epoch.isFunction(b)&&(h=b),null==h&&Epoch.exception("Callback for event '"+a+"' is not a function or reference to a method."),m.push(h.apply(this,d));return m}};return c}();Epoch.Chart.Base=function(c){function a(h){this.options=null!=h?h:{};a.__super__.constructor.call(this);this.setData(this.options.data||
|
||||
[]);null!=this.options.el&&(this.el=d3.select(this.options.el));this.width=this.options.width;this.height=this.options.height;null!=this.el?(null==this.width&&(this.width=this.el.width()),null==this.height&&(this.height=this.el.height())):(null==this.width&&(this.width=d.width),null==this.height&&(this.height=d.height));this.onAll(b)}var d,b;g(a,c);d={width:320,height:240};b={"option:width":"dimensionsChanged","option:height":"dimensionsChanged"};a.prototype._getAllOptions=function(){return Epoch.Util.defaults({},
|
||||
this.options)};a.prototype._getOption=function(a){var k,f;a=a.split(".");for(k=this.options;a.length&&null!=k;)f=a.shift(),k=k[f];return k};a.prototype._setOption=function(a,k){var f,q,b;f=a.split(".");for(q=this.options;f.length;){b=f.shift();if(0===f.length){q[b]=k;this.trigger("option:"+a);break}null==q[b]&&(q[b]={});q=q[b]}};a.prototype._setManyOptions=function(a,k){var f,q,b;null==k&&(k="");b=[];for(f in a)q=a[f],Epoch.isObject(q)?b.push(this._setManyOptions(q,""+(k+f)+".")):b.push(this._setOption(k+
|
||||
f,q));return b};a.prototype.option=function(){if(0===arguments.length)return this._getAllOptions();if(1===arguments.length&&Epoch.isString(arguments[0]))return this._getOption(arguments[0]);if(2===arguments.length&&Epoch.isString(arguments[0]))return this._setOption(arguments[0],arguments[1]);if(1===arguments.length&&Epoch.isObject(arguments[0]))return this._setManyOptions(arguments[0])};a.prototype.setData=function(a){var k,f,b,d,c;k=1;d=0;for(c=a.length;d<c;d++)b=a[d],f=["layer"],f.push("category"+
|
||||
k),b.category=k,null!=b.label&&f.push(Epoch.Util.dasherize(b.label)),b.className=f.join(" "),k++;return this.data=a};a.prototype.update=function(a,k){null==k&&(k=!0);this.setData(a);if(k)return this.draw()};a.prototype.draw=function(){return this.trigger("draw")};a.prototype.extent=function(a){return[d3.min(this.data,function(k){return d3.min(k.values,a)}),d3.max(this.data,function(k){return d3.max(k.values,a)})]};a.prototype.dimensionsChanged=function(){this.width=this.option("width")||this.width;
|
||||
this.height=this.option("height")||this.height;this.el.width(this.width);return this.el.height(this.height)};return a}(Epoch.Events);Epoch.Chart.SVG=function(c){function a(d){this.options=null!=d?d:{};a.__super__.constructor.call(this,this.options);this.svg=null!=this.el?this.el.append("svg"):d3.select(document.createElement("svg"));this.svg.attr({xmlns:"http://www.w3.org/2000/svg",width:this.width,height:this.height})}g(a,c);a.prototype.dimensionsChanged=function(){a.__super__.dimensionsChanged.call(this);
|
||||
return this.svg.attr("width",this.width).attr("height",this.height)};return a}(Epoch.Chart.Base);Epoch.Chart.Canvas=function(c){function a(d){this.options=null!=d?d:{};a.__super__.constructor.call(this,this.options);this.pixelRatio=null!=this.options.pixelRatio?this.options.pixelRatio:null!=window.devicePixelRatio?window.devicePixelRatio:1;this.canvas=d3.select(document.createElement("CANVAS"));this.canvas.style({width:""+this.width+"px",height:""+this.height+"px"});this.canvas.attr({width:this.getWidth(),
|
||||
height:this.getHeight()});null!=this.el&&this.el.node().appendChild(this.canvas.node());this.ctx=Epoch.Util.getContext(this.canvas.node())}g(a,c);a.prototype.getWidth=function(){return this.width*this.pixelRatio};a.prototype.getHeight=function(){return this.height*this.pixelRatio};a.prototype.clear=function(){return this.ctx.clearRect(0,0,this.getWidth(),this.getHeight())};a.prototype.getStyles=function(a){return Epoch.QueryCSS.getStyles(a,this.el)};a.prototype.dimensionsChanged=function(){a.__super__.dimensionsChanged.call(this);
|
||||
this.canvas.style({width:""+this.width+"px",height:""+this.height+"px"});return this.canvas.attr({width:this.getWidth(),height:this.getHeight()})};return a}(Epoch.Chart.Base)}).call(this);
|
||||
(function(){var e;e=function(){function g(){}var c,a,d,b,h;a=0;b=function(){return"epoch-container-"+a++};c=/^([^#. ]+)?(#[^. ]+)?(\.[^# ]+)?$/;d=!1;h=function(a){var f,b;f=a.match(c);if(null==f)return Epoch.error("Query CSS cannot match given selector: "+a);b=f[1];a=f[2];f=f[3];b=(null!=b?b:"div").toUpperCase();b=document.createElement(b);null!=a&&(b.id=a.substr(1));null!=f&&(b.className=f.substr(1).replace(/\./g," "));return b};g.log=function(a){return d=a};g.cache={};g.styleList=["fill","stroke",
|
||||
"stroke-width"];g.container=null;g.purge=function(){return g.cache={}};g.getContainer=function(){var a;if(null!=g.container)return g.container;a=document.createElement("DIV");a.id="_canvas_css_reference";document.body.appendChild(a);return g.container=d3.select(a)};g.hash=function(a,f){var d;d=f.attr("data-epoch-container-id");null==d&&(d=b(),f.attr("data-epoch-container-id",d));return""+d+"__"+a};g.getStyles=function(a,f){var b,c,m,l,n,e,r;c=g.hash(a,f);b=g.cache[c];if(null!=b)return b;m=[];for(b=
|
||||
f.node().parentNode;null!=b&&"body"!==b.nodeName.toLowerCase();)m.unshift(b),b=b.parentNode;m.push(f.node());b=[];e=0;for(r=m.length;e<r;e++)l=m[e],n=l.nodeName.toLowerCase(),null!=l.id&&0<l.id.length&&(n+="#"+l.id),null!=l.className&&0<l.className.length&&(n+="."+Epoch.Util.trim(l.className).replace(/\s+/g,".")),b.push(n);b.push("svg");e=Epoch.Util.trim(a).split(/\s+/);l=0;for(n=e.length;l<n;l++)m=e[l],b.push(m);d&&console.log(b);for(l=n=h(b.shift());b.length;)m=h(b.shift()),l.appendChild(m),l=m;
|
||||
d&&console.log(n);g.getContainer().node().appendChild(n);m=d3.select("#_canvas_css_reference "+a);l={};r=g.styleList;n=0;for(e=r.length;n<e;n++)b=r[n],l[b]=m.style(b);g.cache[c]=l;g.getContainer().html("");return l};return g}();Epoch.QueryCSS=e}).call(this);
|
||||
(function(){var e={}.hasOwnProperty,g=function(c,a){function d(){this.constructor=c}for(var b in a)e.call(a,b)&&(c[b]=a[b]);d.prototype=a.prototype;c.prototype=new d;c.__super__=a.prototype;return c};Epoch.Chart.Plot=function(c){function a(k){var f,c,u;this.options=null!=k?k:{};Epoch.Util.copy(this.options.margins);a.__super__.constructor.call(this,this.options=Epoch.Util.defaults(this.options,b));this.margins={};u=["top","right","bottom","left"];f=0;for(c=u.length;f<c;f++)k=u[f],this.margins[k]=
|
||||
null!=this.options.margins&&null!=this.options.margins[k]?this.options.margins[k]:this.hasAxis(k)?d[k]:6;this.g=this.svg.append("g").attr("transform","translate("+this.margins.left+", "+this.margins.top+")");this.onAll(h)}var d,b,h;g(a,c);b={domain:null,range:null,axes:["left","bottom"],ticks:{top:14,bottom:14,left:5,right:5},tickFormats:{top:Epoch.Formats.regular,bottom:Epoch.Formats.regular,left:Epoch.Formats.si,right:Epoch.Formats.si}};d={top:25,right:50,bottom:25,left:50};h={"option:margins.top":"marginsChanged",
|
||||
"option:margins.right":"marginsChanged","option:margins.bottom":"marginsChanged","option:margins.left":"marginsChanged","option:axes":"axesChanged","option:ticks.top":"ticksChanged","option:ticks.right":"ticksChanged","option:ticks.bottom":"ticksChanged","option:ticks.left":"ticksChanged","option:tickFormats.top":"tickFormatsChanged","option:tickFormats.right":"tickFormatsChanged","option:tickFormats.bottom":"tickFormatsChanged","option:tickFormats.left":"tickFormatsChanged","option:domain":"domainChanged",
|
||||
"option:range":"rangeChanged"};a.prototype.setTickFormat=function(a,f){return this.options.tickFormats[a]=f};a.prototype.hasAxis=function(a){return-1<this.options.axes.indexOf(a)};a.prototype.innerWidth=function(){return this.width-(this.margins.left+this.margins.right)};a.prototype.innerHeight=function(){return this.height-(this.margins.top+this.margins.bottom)};a.prototype.x=function(){var a,f;a=null!=(f=this.options.domain)?f:this.extent(function(a){return a.x});return d3.scale.linear().domain(a).range([0,
|
||||
this.innerWidth()])};a.prototype.y=function(){var a,f;a=null!=(f=this.options.range)?f:this.extent(function(a){return a.y});return d3.scale.linear().domain(a).range([this.innerHeight(),0])};a.prototype.bottomAxis=function(){return d3.svg.axis().scale(this.x()).orient("bottom").ticks(this.options.ticks.bottom).tickFormat(this.options.tickFormats.bottom)};a.prototype.topAxis=function(){return d3.svg.axis().scale(this.x()).orient("top").ticks(this.options.ticks.top).tickFormat(this.options.tickFormats.top)};
|
||||
a.prototype.leftAxis=function(){return d3.svg.axis().scale(this.y()).orient("left").ticks(this.options.ticks.left).tickFormat(this.options.tickFormats.left)};a.prototype.rightAxis=function(){return d3.svg.axis().scale(this.y()).orient("right").ticks(this.options.ticks.right).tickFormat(this.options.tickFormats.right)};a.prototype.draw=function(){this._axesDrawn?this._redrawAxes():this._drawAxes();return a.__super__.draw.call(this)};a.prototype._redrawAxes=function(){this.hasAxis("bottom")&&this.g.selectAll(".x.axis.bottom").transition().duration(500).ease("linear").call(this.bottomAxis());
|
||||
this.hasAxis("top")&&this.g.selectAll(".x.axis.top").transition().duration(500).ease("linear").call(this.topAxis());this.hasAxis("left")&&this.g.selectAll(".y.axis.left").transition().duration(500).ease("linear").call(this.leftAxis());if(this.hasAxis("right"))return this.g.selectAll(".y.axis.right").transition().duration(500).ease("linear").call(this.rightAxis())};a.prototype._drawAxes=function(){this.hasAxis("bottom")&&this.g.append("g").attr("class","x axis bottom").attr("transform","translate(0, "+
|
||||
this.innerHeight()+")").call(this.bottomAxis());this.hasAxis("top")&&this.g.append("g").attr("class","x axis top").call(this.topAxis());this.hasAxis("left")&&this.g.append("g").attr("class","y axis left").call(this.leftAxis());this.hasAxis("right")&&this.g.append("g").attr("class","y axis right").attr("transform","translate("+this.innerWidth()+", 0)").call(this.rightAxis());return this._axesDrawn=!0};a.prototype.dimensionsChanged=function(){a.__super__.dimensionsChanged.call(this);this.g.selectAll(".axis").remove();
|
||||
this._axesDrawn=!1;return this.draw()};a.prototype.marginsChanged=function(){var a,f,b;if(null!=this.options.margins){b=this.options.margins;for(a in b)f=b[a],this.margins[a]=null==f?6:f;this.g.transition().duration(750).attr("transform","translate("+this.margins.left+", "+this.margins.top+")");return this.draw()}};a.prototype.axesChanged=function(){var a,f,b,c;c=["top","right","bottom","left"];f=0;for(b=c.length;f<b;f++)if(a=c[f],null==this.options.margins||null==this.options.margins[a])this.hasAxis(a)?
|
||||
this.margins[a]=d[a]:this.margins[a]=6;this.g.transition().duration(750).attr("transform","translate("+this.margins.left+", "+this.margins.top+")");this.g.selectAll(".axis").remove();this._axesDrawn=!1;return this.draw()};a.prototype.ticksChanged=function(){return this.draw()};a.prototype.tickFormatsChanged=function(){return this.draw()};a.prototype.domainChanged=function(){return this.draw()};a.prototype.rangeChanged=function(){return this.draw()};return a}(Epoch.Chart.SVG)}).call(this);
|
||||
(function(){var e={}.hasOwnProperty,g=function(c,a){function d(){this.constructor=c}for(var b in a)e.call(a,b)&&(c[b]=a[b]);d.prototype=a.prototype;c.prototype=new d;c.__super__=a.prototype;return c};Epoch.Chart.Area=function(c){function a(){return a.__super__.constructor.apply(this,arguments)}g(a,c);a.prototype.y=function(){var a,b,c,k,f,q,u,m;a=[];q=this.data;k=0;for(f=q.length;k<f;k++)for(b in c=q[k],u=c.values,u)c=u[b],null!=a[b]&&(a[b]+=c.y),null==a[b]&&(a[b]=c.y);return d3.scale.linear().domain(null!=
|
||||
(m=this.options.range)?m:[0,d3.max(a)]).range([this.height-this.margins.top-this.margins.bottom,0])};a.prototype.draw=function(){var d,b,c,k;b=[this.x(),this.y()];c=b[0];k=b[1];d=d3.svg.area().x(function(a){return c(a.x)}).y0(function(a){return k(a.y0)}).y1(function(a){return k(a.y0+a.y)});d3.layout.stack().values(function(a){return a.values})(this.data);this.g.selectAll(".layer").remove();b=this.g.selectAll(".layer").data(this.data,function(a){return a.category});b.select(".area").attr("d",function(a){return d(a.values)});
|
||||
b.enter().append("g").attr("class",function(a){return a.className});b.append("path").attr("class","area").attr("d",function(a){return d(a.values)});return a.__super__.draw.call(this)};return a}(Epoch.Chart.Plot)}).call(this);
|
||||
(function(){var e={}.hasOwnProperty,g=function(c,a){function d(){this.constructor=c}for(var b in a)e.call(a,b)&&(c[b]=a[b]);d.prototype=a.prototype;c.prototype=new d;c.__super__=a.prototype;return c};Epoch.Chart.Bar=function(c){function a(k){this.options=null!=k?k:{};this.options="horizontal"===this.options.orientation?Epoch.Util.defaults(this.options,b):Epoch.Util.defaults(this.options,d);a.__super__.constructor.call(this,this.options);this.onAll(h)}var d,b,h;g(a,c);d={style:"grouped",orientation:"vertical",
|
||||
padding:{bar:0.08,group:0.1},outerPadding:{bar:0.08,group:0.1}};b=Epoch.Util.defaults({tickFormats:{top:Epoch.Formats.si,bottom:Epoch.Formats.si,left:Epoch.Formats.regular,right:Epoch.Formats.regular}},d);h={"option:orientation":"orientationChanged","option:padding":"paddingChanged","option:outerPadding":"paddingChanged","option:padding:bar":"paddingChanged","option:padding:group":"paddingChanged","option:outerPadding:bar":"paddingChanged","option:outerPadding:group":"paddingChanged"};a.prototype.x=
|
||||
function(){var a;if("vertical"===this.options.orientation)return d3.scale.ordinal().domain(Epoch.Util.domain(this.data)).rangeRoundBands([0,this.innerWidth()],this.options.padding.group,this.options.outerPadding.group);a=this.extent(function(a){return a.y});a[0]=Math.min(0,a[0]);return d3.scale.linear().domain(a).range([0,this.width-this.margins.left-this.margins.right])};a.prototype.x1=function(a){var f;return d3.scale.ordinal().domain(function(){var a,k,b,d;b=this.data;d=[];a=0;for(k=b.length;a<
|
||||
k;a++)f=b[a],d.push(f.category);return d}.call(this)).rangeRoundBands([0,a.rangeBand()],this.options.padding.bar,this.options.outerPadding.bar)};a.prototype.y=function(){var a;return"vertical"===this.options.orientation?(a=this.extent(function(a){return a.y}),a[0]=Math.min(0,a[0]),d3.scale.linear().domain(a).range([this.height-this.margins.top-this.margins.bottom,0])):d3.scale.ordinal().domain(Epoch.Util.domain(this.data)).rangeRoundBands([0,this.innerHeight()],this.options.padding.group,this.options.outerPadding.group)};
|
||||
a.prototype.y1=function(a){var f;return d3.scale.ordinal().domain(function(){var a,k,b,d;b=this.data;d=[];a=0;for(k=b.length;a<k;a++)f=b[a],d.push(f.category);return d}.call(this)).rangeRoundBands([0,a.rangeBand()],this.options.padding.bar,this.options.outerPadding.bar)};a.prototype._remapData=function(){var a,f,b,d,c,h,n,e,g,s,t,v;c={};t=this.data;h=0;for(e=t.length;h<e;h++)for(d=t[h],a="bar "+d.className.replace(/\s*layer\s*/,""),v=d.values,n=0,g=v.length;n<g;n++)f=v[n],null==c[s=f.x]&&(c[s]=[]),
|
||||
c[f.x].push({label:d.category,y:f.y,className:a});f=[];for(b in c)a=c[b],f.push({group:b,values:a});return f};a.prototype.draw=function(){"horizontal"===this.options.orientation?this._drawHorizontal():this._drawVertical();return a.__super__.draw.call(this)};a.prototype._drawVertical=function(){var a,b,d,c,h,l;a=[this.x(),this.y()];c=a[0];l=a[1];h=this.x1(c);b=this.height-this.margins.top-this.margins.bottom;a=this._remapData();a=this.g.selectAll(".layer").data(a,function(a){return a.group});a.transition().duration(750).attr("transform",
|
||||
function(a){return"translate("+c(a.group)+", 0)"});a.enter().append("g").attr("class","layer").attr("transform",function(a){return"translate("+c(a.group)+", 0)"});d=a.selectAll("rect").data(function(a){return a.values});d.transition().duration(600).attr("x",function(a){return h(a.label)}).attr("y",function(a){return l(a.y)}).attr("width",h.rangeBand()).attr("height",function(a){return b-l(a.y)});d.enter().append("rect").attr("class",function(a){return a.className}).attr("x",function(a){return h(a.label)}).attr("y",
|
||||
function(a){return l(a.y)}).attr("width",h.rangeBand()).attr("height",function(a){return b-l(a.y)});d.exit().transition().duration(150).style("opacity","0").remove();return a.exit().transition().duration(750).style("opacity","0").remove()};a.prototype._drawHorizontal=function(){var a,b,d,c,h;a=[this.x(),this.y()];d=a[0];c=a[1];h=this.y1(c);a=this._remapData();a=this.g.selectAll(".layer").data(a,function(a){return a.group});a.transition().duration(750).attr("transform",function(a){return"translate(0, "+
|
||||
c(a.group)+")"});a.enter().append("g").attr("class","layer").attr("transform",function(a){return"translate(0, "+c(a.group)+")"});b=a.selectAll("rect").data(function(a){return a.values});b.transition().duration(600).attr("x",function(a){return 0}).attr("y",function(a){return h(a.label)}).attr("height",h.rangeBand()).attr("width",function(a){return d(a.y)});b.enter().append("rect").attr("class",function(a){return a.className}).attr("x",function(a){return 0}).attr("y",function(a){return h(a.label)}).attr("height",
|
||||
h.rangeBand()).attr("width",function(a){return d(a.y)});b.exit().transition().duration(150).style("opacity","0").remove();return a.exit().transition().duration(750).style("opacity","0").remove()};a.prototype.orientationChanged=function(){var a,b,d,c;c=this.options.tickFormats.top;a=this.options.tickFormats.bottom;b=this.options.tickFormats.left;d=this.options.tickFormats.right;this.options.tickFormats.left=c;this.options.tickFormats.right=a;this.options.tickFormats.top=b;this.options.tickFormats.bottom=
|
||||
d;return this.draw()};a.prototype.paddingChanged=function(){return this.draw()};return a}(Epoch.Chart.Plot)}).call(this);
|
||||
(function(){var e={}.hasOwnProperty,g=function(c,a){function d(){this.constructor=c}for(var b in a)e.call(a,b)&&(c[b]=a[b]);d.prototype=a.prototype;c.prototype=new d;c.__super__=a.prototype;return c};Epoch.Chart.Line=function(c){function a(){return a.__super__.constructor.apply(this,arguments)}g(a,c);a.prototype.line=function(){var a,b,c;c=[this.x(),this.y()];a=c[0];b=c[1];return d3.svg.line().x(function(b){return function(b){return a(b.x)}}(this)).y(function(a){return function(a){return b(a.y)}}(this))};a.prototype.draw=
|
||||
function(){var c,b;b=[this.x(),this.y(),this.line()][2];c=this.g.selectAll(".layer").data(this.data,function(a){return a.category});c.select(".line").transition().duration(500).attr("d",function(a){return b(a.values)});c.enter().append("g").attr("class",function(a){return a.className}).append("path").attr("class","line").attr("d",function(a){return b(a.values)});c.exit().transition().duration(750).style("opacity","0").remove();return a.__super__.draw.call(this)};return a}(Epoch.Chart.Plot)}).call(this);
|
||||
(function(){var e={}.hasOwnProperty,g=function(c,a){function d(){this.constructor=c}for(var b in a)e.call(a,b)&&(c[b]=a[b]);d.prototype=a.prototype;c.prototype=new d;c.__super__=a.prototype;return c};Epoch.Chart.Pie=function(c){function a(b){this.options=null!=b?b:{};a.__super__.constructor.call(this,this.options=Epoch.Util.defaults(this.options,d));this.pie=d3.layout.pie().sort(null).value(function(a){return a.value});this.arc=d3.svg.arc().outerRadius(function(a){return function(){return Math.max(a.width,
|
||||
a.height)/2-a.options.margin}}(this)).innerRadius(function(a){return function(){return a.options.inner}}(this));this.g=this.svg.append("g").attr("transform","translate("+this.width/2+", "+this.height/2+")");this.on("option:margin","marginChanged");this.on("option:inner","innerChanged")}var d;g(a,c);d={margin:10,inner:0};a.prototype.draw=function(){var b;this.g.selectAll(".arc").remove();b=this.g.selectAll(".arc").data(this.pie(this.data),function(a){return a.data.category});b.enter().append("g").attr("class",
|
||||
function(a){return"arc pie "+a.data.className});b.select("path").attr("d",this.arc);b.select("text").attr("transform",function(a){return function(b){return"translate("+a.arc.centroid(b)+")"}}(this)).text(function(a){return a.data.label||a.data.category});b.append("path").attr("d",this.arc).each(function(a){return this._current=a});b.append("text").attr("transform",function(a){return function(b){return"translate("+a.arc.centroid(b)+")"}}(this)).attr("dy",".35em").style("text-anchor","middle").text(function(a){return a.data.label||
|
||||
a.data.category});return a.__super__.draw.call(this)};a.prototype.marginChanged=function(){return this.draw()};a.prototype.innerChanged=function(){return this.draw()};return a}(Epoch.Chart.SVG)}).call(this);
|
||||
(function(){var e={}.hasOwnProperty,g=function(c,a){function d(){this.constructor=c}for(var b in a)e.call(a,b)&&(c[b]=a[b]);d.prototype=a.prototype;c.prototype=new d;c.__super__=a.prototype;return c};Epoch.Chart.Scatter=function(c){function a(b){this.options=null!=b?b:{};a.__super__.constructor.call(this,this.options=Epoch.Util.defaults(this.options,d));this.on("option:radius","radiusChanged")}var d;g(a,c);d={radius:3.5,axes:["top","bottom","left","right"]};a.prototype.draw=function(){var b,c,k,f,
|
||||
d;b=[this.x(),this.y()];f=b[0];d=b[1];k=this.options.radius;c=this.g.selectAll(".layer").data(this.data,function(a){return a.category});c.enter().append("g").attr("class",function(a){return a.className});b=c.selectAll(".dot").data(function(a){return a.values});b.transition().duration(500).attr("r",function(a){var b;return null!=(b=a.r)?b:k}).attr("cx",function(a){return f(a.x)}).attr("cy",function(a){return d(a.y)});b.enter().append("circle").attr("class","dot").attr("r",function(a){var b;return null!=
|
||||
(b=a.r)?b:k}).attr("cx",function(a){return f(a.x)}).attr("cy",function(a){return d(a.y)});b.exit().transition().duration(750).style("opacity",0).remove();c.exit().transition().duration(750).style("opacity",0).remove();return a.__super__.draw.call(this)};a.prototype.radiusChanged=function(){return this.draw()};return a}(Epoch.Chart.Plot)}).call(this);
|
||||
(function(){var e={}.hasOwnProperty,g=function(c,a){function d(){this.constructor=c}for(var b in a)e.call(a,b)&&(c[b]=a[b]);d.prototype=a.prototype;c.prototype=new d;c.__super__=a.prototype;return c};Epoch.Time.Plot=function(c){function a(k){var f,c,u;this.options=k;Epoch.Util.copy(this.options.margins);a.__super__.constructor.call(this,this.options=Epoch.Util.defaults(this.options,b));this._queue=[];this.margins={};u=["top","right","bottom","left"];f=0;for(c=u.length;f<c;f++)k=u[f],this.margins[k]=
|
||||
null!=this.options.margins&&null!=this.options.margins[k]?this.options.margins[k]:this.hasAxis(k)?d[k]:6;this.svg=this.el.insert("svg",":first-child").attr("width",this.width).attr("height",this.height).style("z-index","1000");"absolute"!==this.el.style("position")&&"relative"!==this.el.style("position")&&this.el.style("position","relative");this.canvas.style({position:"absolute","z-index":"999"});this._sizeCanvas();this.animation={interval:null,active:!1,delta:function(a){return function(){return-(a.w()/
|
||||
a.options.fps)}}(this),tickDelta:function(a){return function(){return-(a.w()/a.pixelRatio/a.options.fps)}}(this),frame:0,duration:this.options.fps};this._buildAxes();this.animationCallback=function(a){return function(){return a._animate()}}(this);this.onAll(h)}var d,b,h;g(a,c);b={fps:24,historySize:120,windowSize:40,queueSize:10,axes:["bottom"],ticks:{time:15,left:5,right:5},tickFormats:{top:Epoch.Formats.seconds,bottom:Epoch.Formats.seconds,left:Epoch.Formats.si,right:Epoch.Formats.si}};d={top:25,
|
||||
right:50,bottom:25,left:50};h={"option:margins":"marginsChanged","option:margins.top":"marginsChanged","option:margins.right":"marginsChanged","option:margins.bottom":"marginsChanged","option:margins.left":"marginsChanged","option:axes":"axesChanged","option:ticks":"ticksChanged","option:ticks.top":"ticksChanged","option:ticks.right":"ticksChanged","option:ticks.bottom":"ticksChanged","option:ticks.left":"ticksChanged","option:tickFormats":"tickFormatsChanged","option:tickFormats.top":"tickFormatsChanged",
|
||||
"option:tickFormats.right":"tickFormatsChanged","option:tickFormats.bottom":"tickFormatsChanged","option:tickFormats.left":"tickFormatsChanged"};a.prototype._sizeCanvas=function(){this.canvas.attr({width:this.innerWidth(),height:this.innerHeight()});return this.canvas.style({width:""+this.innerWidth()/this.pixelRatio+"px",height:""+this.innerHeight()/this.pixelRatio+"px",top:""+this.margins.top+"px",left:""+this.margins.left+"px"})};a.prototype._buildAxes=function(){this.svg.selectAll(".axis").remove();
|
||||
this._prepareTimeAxes();return this._prepareRangeAxes()};a.prototype.setData=function(a){var b,c,d,h,e;this.data=[];e=[];for(d in a)h=a[d],c=Epoch.Util.copy(h),b=Math.max(0,h.values.length-this.options.historySize),c.values=h.values.slice(b),b=["layer"],b.push("category"+((d|0)+1)),null!=h.label&&b.push(Epoch.Util.dasherize(h.label)),c.className=b.join(" "),e.push(this.data.push(c));return e};a.prototype._offsetX=function(){return 0};a.prototype._prepareTimeAxes=function(){var a;this.hasAxis("bottom")&&
|
||||
(a=this.bottomAxis=this.svg.append("g").attr("class","x axis bottom canvas").attr("transform","translate("+(this.margins.left-1)+", "+(this.innerHeight()/this.pixelRatio+this.margins.top)+")"),a.append("path").attr("class","domain").attr("d","M0,0H"+(this.innerWidth()/this.pixelRatio+1)));this.hasAxis("top")&&(a=this.topAxis=this.svg.append("g").attr("class","x axis top canvas").attr("transform","translate("+(this.margins.left-1)+", "+this.margins.top+")"),a.append("path").attr("class","domain").attr("d",
|
||||
"M0,0H"+(this.innerWidth()/this.pixelRatio+1)));return this._resetInitialTimeTicks()};a.prototype._resetInitialTimeTicks=function(){var a,b,c,d,h;d=this.options.ticks.time;this._ticks=[];this._tickTimer=d;null!=this.bottomAxis&&this.bottomAxis.selectAll(".tick").remove();null!=this.topAxis&&this.topAxis.selectAll(".tick").remove();h=this.data;a=0;for(b=h.length;a<b;a++)if(c=h[a],null!=c.values&&0<c.values.length){b=[this.options.windowSize-1,c.values.length-1];a=b[0];for(b=b[1];0<=a&&0<=b;)this._pushTick(a,
|
||||
c.values[b].time,!1,!0),a-=d,b-=d;break}return[]};a.prototype._prepareRangeAxes=function(){this.hasAxis("left")&&this.svg.append("g").attr("class","y axis left").attr("transform","translate("+(this.margins.left-1)+", "+this.margins.top+")").call(this.leftAxis());if(this.hasAxis("right"))return this.svg.append("g").attr("class","y axis right").attr("transform","translate("+(this.width-this.margins.right)+", "+this.margins.top+")").call(this.rightAxis())};a.prototype.leftAxis=function(){var a,b;b=this.options.ticks.left;
|
||||
a=d3.svg.axis().scale(this.ySvg()).orient("left").tickFormat(this.options.tickFormats.left);return 2===b?a.tickValues(this.extent(function(a){return a.y})):a.ticks(b)};a.prototype.rightAxis=function(){var a,b;this.extent(function(a){return a.y});b=this.options.ticks.right;a=d3.svg.axis().scale(this.ySvg()).orient("right").tickFormat(this.options.tickFormats.left);return 2===b?a.tickValues(this.extent(function(a){return a.y})):a.ticks(b)};a.prototype.hasAxis=function(a){return-1<this.options.axes.indexOf(a)};
|
||||
a.prototype.innerWidth=function(){return(this.width-(this.margins.left+this.margins.right))*this.pixelRatio};a.prototype.innerHeight=function(){return(this.height-(this.margins.top+this.margins.bottom))*this.pixelRatio};a.prototype._prepareEntry=function(a){return a};a.prototype._prepareLayers=function(a){return a};a.prototype._startTransition=function(){if(!0!==this.animation.active&&0!==this._queue.length)return this.trigger("transition:start"),this._shift(),this.animation.active=!0,this.animation.interval=
|
||||
setInterval(this.animationCallback,1E3/this.options.fps)};a.prototype._stopTransition=function(){var a,b,c,d;if(this.inTransition()){d=this.data;b=0;for(c=d.length;b<c;b++)a=d[b],a.values.length>this.options.windowSize+1&&a.values.shift();b=[this._ticks[0],this._ticks[this._ticks.length-1]];a=b[0];b=b[1];null!=b&&b.enter&&(b.enter=!1,b.opacity=1);null!=a&&a.exit&&this._shiftTick();this.animation.frame=0;this.trigger("transition:end");if(0<this._queue.length)return this._shift();this.animation.active=
|
||||
!1;return clearInterval(this.animation.interval)}};a.prototype.inTransition=function(){return this.animation.active};a.prototype.push=function(a){a=this._prepareLayers(a);this._queue.length>this.options.queueSize&&this._queue.splice(this.options.queueSize,this._queue.length-this.options.queueSize);if(this._queue.length===this.options.queueSize)return!1;this._queue.push(a.map(function(a){return function(b){return a._prepareEntry(b)}}(this)));this.trigger("push");if(!this.inTransition())return this._startTransition()};
|
||||
a.prototype._shift=function(){var a,b,c,d;this.trigger("before:shift");a=this._queue.shift();d=this.data;for(b in d)c=d[b],c.values.push(a[b]);this._updateTicks(a[0].time);this._transitionRangeAxes();return this.trigger("after:shift")};a.prototype._transitionRangeAxes=function(){this.hasAxis("left")&&this.svg.selectAll(".y.axis.left").transition().duration(500).ease("linear").call(this.leftAxis());if(this.hasAxis("right"))return this.svg.selectAll(".y.axis.right").transition().duration(500).ease("linear").call(this.rightAxis())};
|
||||
a.prototype._animate=function(){if(this.inTransition())return++this.animation.frame===this.animation.duration&&this._stopTransition(),this.draw(this.animation.frame*this.animation.delta()),this._updateTimeAxes()};a.prototype.y=function(){return d3.scale.linear().domain(this.extent(function(a){return a.y})).range([this.innerHeight(),0])};a.prototype.ySvg=function(){return d3.scale.linear().domain(this.extent(function(a){return a.y})).range([this.innerHeight()/this.pixelRatio,0])};a.prototype.w=function(){return this.innerWidth()/
|
||||
this.options.windowSize};a.prototype._updateTicks=function(a){if(this.hasAxis("top")||this.hasAxis("bottom"))if(++this._tickTimer%this.options.ticks.time||this._pushTick(this.options.windowSize,a,!0),!(0<=this._ticks[0].x-this.w()/this.pixelRatio))return this._ticks[0].exit=!0};a.prototype._pushTick=function(a,b,c,d){null==c&&(c=!1);null==d&&(d=!1);if(this.hasAxis("top")||this.hasAxis("bottom"))return b={time:b,x:a*(this.w()/this.pixelRatio)+this._offsetX(),opacity:c?0:1,enter:c?!0:!1,exit:!1},this.hasAxis("bottom")&&
|
||||
(a=this.bottomAxis.append("g").attr("class","tick major").attr("transform","translate("+(b.x+1)+",0)").style("opacity",b.opacity),a.append("line").attr("y2",6),a.append("text").attr("text-anchor","middle").attr("dy",19).text(this.options.tickFormats.bottom(b.time)),b.bottomEl=a),this.hasAxis("top")&&(a=this.topAxis.append("g").attr("class","tick major").attr("transform","translate("+(b.x+1)+",0)").style("opacity",b.opacity),a.append("line").attr("y2",-6),a.append("text").attr("text-anchor","middle").attr("dy",
|
||||
-10).text(this.options.tickFormats.top(b.time)),b.topEl=a),d?this._ticks.unshift(b):this._ticks.push(b),b};a.prototype._shiftTick=function(){var a;if(0<this._ticks.length&&(a=this._ticks.shift(),null!=a.topEl&&a.topEl.remove(),null!=a.bottomEl))return a.bottomEl.remove()};a.prototype._updateTimeAxes=function(){var a,b,c,d,h,e,g;if(this.hasAxis("top")||this.hasAxis("bottom")){a=[this.animation.tickDelta(),1/this.options.fps];b=a[0];a=a[1];e=this._ticks;g=[];d=0;for(h=e.length;d<h;d++)c=e[d],c.x+=b,
|
||||
this.hasAxis("bottom")&&c.bottomEl.attr("transform","translate("+(c.x+1)+",0)"),this.hasAxis("top")&&c.topEl.attr("transform","translate("+(c.x+1)+",0)"),c.enter?c.opacity+=a:c.exit&&(c.opacity-=a),c.enter||c.exit?(this.hasAxis("bottom")&&c.bottomEl.style("opacity",c.opacity),this.hasAxis("top")?g.push(c.topEl.style("opacity",c.opacity)):g.push(void 0)):g.push(void 0);return g}};a.prototype.draw=function(b){return a.__super__.draw.call(this)};a.prototype.dimensionsChanged=function(){a.__super__.dimensionsChanged.call(this);
|
||||
this.svg.attr("width",this.width).attr("height",this.height);this._sizeCanvas();this._buildAxes();return this.draw(this.animation.frame*this.animation.delta())};a.prototype.axesChanged=function(){var a,b,c,h;h=["top","right","bottom","left"];b=0;for(c=h.length;b<c;b++)if(a=h[b],null==this.options.margins||null==this.options.margins[a])this.hasAxis(a)?this.margins[a]=d[a]:this.margins[a]=6;this._sizeCanvas();this._buildAxes();return this.draw(this.animation.frame*this.animation.delta())};a.prototype.ticksChanged=
|
||||
function(){this._resetInitialTimeTicks();this._transitionRangeAxes();return this.draw(this.animation.frame*this.animation.delta())};a.prototype.tickFormatsChanged=function(){this._resetInitialTimeTicks();this._transitionRangeAxes();return this.draw(this.animation.frame*this.animation.delta())};a.prototype.marginsChanged=function(){var a,b,c;if(null!=this.options.margins){c=this.options.margins;for(a in c)b=c[a],this.margins[a]=null==b?6:b;this._sizeCanvas();return this.draw(this.animation.frame*this.animation.delta())}};
|
||||
return a}(Epoch.Chart.Canvas);Epoch.Time.Stack=function(c){function a(){return a.__super__.constructor.apply(this,arguments)}g(a,c);a.prototype._prepareLayers=function(a){var b,c,k,f;k=c=0;for(f=a.length;k<f;k++)b=a[k],b.y0=c,c+=b.y;return a};a.prototype.setData=function(c){var b,h,k,f,e;a.__super__.setData.call(this,c);e=[];b=c=0;for(f=this.data[0].values.length;0<=f?c<f:c>f;b=0<=f?++c:--c)k=0,e.push(function(){var a,c,d,f;d=this.data;f=[];a=0;for(c=d.length;a<c;a++)h=d[a],h.values[b].y0=k,f.push(k+=
|
||||
h.values[b].y);return f}.call(this));return e};a.prototype.extent=function(){var a,b,c,k,f,e,g,m;a=f=c=0;for(g=this.data[0].values.length;0<=g?f<g:f>g;a=0<=g?++f:--f){b=e=k=0;for(m=this.data.length;0<=m?e<m:e>m;b=0<=m?++e:--e)k+=this.data[b].values[a].y;k>c&&(c=k)}return[0,c]};return a}(Epoch.Time.Plot)}).call(this);
|
||||
(function(){var e={}.hasOwnProperty,g=function(c,a){function d(){this.constructor=c}for(var b in a)e.call(a,b)&&(c[b]=a[b]);d.prototype=a.prototype;c.prototype=new d;c.__super__=a.prototype;return c};Epoch.Time.Area=function(c){function a(){return a.__super__.constructor.apply(this,arguments)}g(a,c);a.prototype.setStyles=function(a){a=null!=a.className?this.getStyles("g."+a.className.replace(/\s/g,".")+" path.area"):this.getStyles("g path.area");this.ctx.fillStyle=a.fill;null!=a.stroke&&(this.ctx.strokeStyle=
|
||||
a.stroke);if(null!=a["stroke-width"])return this.ctx.lineWidth=a["stroke-width"].replace("px","")};a.prototype._drawAreas=function(a){var b,c,k,f,e,g,m,l,n,p;null==a&&(a=0);g=[this.y(),this.w()];m=g[0];g=g[1];p=[];for(c=l=n=this.data.length-1;0>=n?0>=l:0<=l;c=0>=n?++l:--l){f=this.data[c];this.setStyles(f);this.ctx.beginPath();e=[this.options.windowSize,f.values.length,this.inTransition()];c=e[0];k=e[1];for(e=e[2];-2<=--c&&0<=--k;)b=f.values[k],b=[(c+1)*g+a,m(b.y+b.y0)],e&&(b[0]+=g),c===this.options.windowSize-
|
||||
1?this.ctx.moveTo.apply(this.ctx,b):this.ctx.lineTo.apply(this.ctx,b);c=e?(c+3)*g+a:(c+2)*g+a;this.ctx.lineTo(c,this.innerHeight());this.ctx.lineTo(this.width*this.pixelRatio+g+a,this.innerHeight());this.ctx.closePath();p.push(this.ctx.fill())}return p};a.prototype._drawStrokes=function(a){var b,c,k,f,e,g,m,l,n,p;null==a&&(a=0);c=[this.y(),this.w()];m=c[0];g=c[1];p=[];for(c=l=n=this.data.length-1;0>=n?0>=l:0<=l;c=0>=n?++l:--l){f=this.data[c];this.setStyles(f);this.ctx.beginPath();e=[this.options.windowSize,
|
||||
f.values.length,this.inTransition()];c=e[0];k=e[1];for(e=e[2];-2<=--c&&0<=--k;)b=f.values[k],b=[(c+1)*g+a,m(b.y+b.y0)],e&&(b[0]+=g),c===this.options.windowSize-1?this.ctx.moveTo.apply(this.ctx,b):this.ctx.lineTo.apply(this.ctx,b);p.push(this.ctx.stroke())}return p};a.prototype.draw=function(c){null==c&&(c=0);this.clear();this._drawAreas(c);this._drawStrokes(c);return a.__super__.draw.call(this)};return a}(Epoch.Time.Stack)}).call(this);
|
||||
(function(){var e={}.hasOwnProperty,g=function(c,a){function d(){this.constructor=c}for(var b in a)e.call(a,b)&&(c[b]=a[b]);d.prototype=a.prototype;c.prototype=new d;c.__super__=a.prototype;return c};Epoch.Time.Bar=function(c){function a(){return a.__super__.constructor.apply(this,arguments)}g(a,c);a.prototype._offsetX=function(){return 0.5*this.w()/this.pixelRatio};a.prototype.setStyles=function(a){a=this.getStyles("rect.bar."+a.replace(/\s/g,"."));this.ctx.fillStyle=a.fill;this.ctx.strokeStyle=
|
||||
null==a.stroke||"none"===a.stroke?"transparent":a.stroke;if(null!=a["stroke-width"])return this.ctx.lineWidth=a["stroke-width"].replace("px","")};a.prototype.draw=function(c){var b,h,k,f,e,g,m,l,n,p,r,s,t;null==c&&(c=0);this.clear();f=[this.y(),this.w()];p=f[0];n=f[1];t=this.data;r=0;for(s=t.length;r<s;r++)if(m=t[r],0<m.values.length)for(this.setStyles(m.className),e=[this.options.windowSize,m.values.length,this.inTransition()],f=e[0],g=e[1],e=(l=e[2])?-1:0;--f>=e&&0<=--g;)b=m.values[g],k=[f*n+c,
|
||||
b.y,b.y0],b=k[0],h=k[1],k=k[2],l&&(b+=n),b=[b+1,p(h+k),n-2,this.innerHeight()-p(h)+0.5*this.pixelRatio],this.ctx.fillRect.apply(this.ctx,b),this.ctx.strokeRect.apply(this.ctx,b);return a.__super__.draw.call(this)};return a}(Epoch.Time.Stack)}).call(this);
|
||||
(function(){var e={}.hasOwnProperty,g=function(c,a){function d(){this.constructor=c}for(var b in a)e.call(a,b)&&(c[b]=a[b]);d.prototype=a.prototype;c.prototype=new d;c.__super__=a.prototype;return c};Epoch.Time.Gauge=function(c){function a(c){this.options=null!=c?c:{};a.__super__.constructor.call(this,this.options=Epoch.Util.defaults(this.options,d));this.value=this.options.value||0;"absolute"!==this.el.style("position")&&"relative"!==this.el.style("position")&&this.el.style("position","relative");
|
||||
this.svg=this.el.insert("svg",":first-child").attr("width",this.width).attr("height",this.height).attr("class","gauge-labels");this.svg.style({position:"absolute","z-index":"1"});this.svg.append("g").attr("transform","translate("+this.textX()+", "+this.textY()+")").append("text").attr("class","value").text(this.options.format(this.value));this.animation={interval:null,active:!1,delta:0,target:0};this._animate=function(a){return function(){Math.abs(a.animation.target-a.value)<Math.abs(a.animation.delta)?
|
||||
(a.value=a.animation.target,clearInterval(a.animation.interval),a.animation.active=!1):a.value+=a.animation.delta;a.svg.select("text.value").text(a.options.format(a.value));return a.draw()}}(this);this.onAll(b)}var d,b;g(a,c);d={domain:[0,1],ticks:10,tickSize:5,tickOffset:5,fps:34,format:Epoch.Formats.percent};b={"option:domain":"domainChanged","option:ticks":"ticksChanged","option:tickSize":"tickSizeChanged","option:tickOffset":"tickOffsetChanged","option:format":"formatChanged"};a.prototype.update=
|
||||
function(a){this.animation.target=a;this.animation.delta=(a-this.value)/this.options.fps;if(!this.animation.active)return this.animation.interval=setInterval(this._animate,1E3/this.options.fps),this.animation.active=!0};a.prototype.push=function(a){return this.update(a)};a.prototype.radius=function(){return this.getHeight()/1.58};a.prototype.centerX=function(){return this.getWidth()/2};a.prototype.centerY=function(){return 0.68*this.getHeight()};a.prototype.textX=function(){return this.width/2};a.prototype.textY=
|
||||
function(){return 0.48*this.height};a.prototype.getAngle=function(a){var b,c;c=this.options.domain;b=c[0];return(a-b)/(c[1]-b)*(Math.PI+2*Math.PI/8)-Math.PI/2-Math.PI/8};a.prototype.setStyles=function(a){a=this.getStyles(a);this.ctx.fillStyle=a.fill;this.ctx.strokeStyle=a.stroke;if(null!=a["stroke-width"])return this.ctx.lineWidth=a["stroke-width"].replace("px","")};a.prototype.draw=function(){var b,c,d,e,g,m,l,n,p,r,s,t;g=[this.centerX(),this.centerY(),this.radius()];d=g[0];e=g[1];g=g[2];l=[this.options.tickOffset,
|
||||
this.options.tickSize];n=l[0];p=l[1];this.clear();l=d3.scale.linear().domain([0,this.options.ticks]).range([-1.125*Math.PI,Math.PI/8]);this.setStyles(".epoch .gauge .tick");this.ctx.beginPath();b=s=0;for(t=this.options.ticks;0<=t?s<=t:s>=t;b=0<=t?++s:--s)b=l(b),b=[Math.cos(b),Math.sin(b)],c=b[0],m=b[1],b=c*(g-n)+d,r=m*(g-n)+e,c=c*(g-n-p)+d,m=m*(g-n-p)+e,this.ctx.moveTo(b,r),this.ctx.lineTo(c,m);this.ctx.stroke();this.setStyles(".epoch .gauge .arc.outer");this.ctx.beginPath();this.ctx.arc(d,e,g,-1.125*
|
||||
Math.PI,0.125*Math.PI,!1);this.ctx.stroke();this.setStyles(".epoch .gauge .arc.inner");this.ctx.beginPath();this.ctx.arc(d,e,g-10,-1.125*Math.PI,0.125*Math.PI,!1);this.ctx.stroke();this.drawNeedle();return a.__super__.draw.call(this)};a.prototype.drawNeedle=function(){var a,b,c;c=[this.centerX(),this.centerY(),this.radius()];a=c[0];b=c[1];c=c[2];this.setStyles(".epoch .gauge .needle");this.ctx.beginPath();this.ctx.save();this.ctx.translate(a,b);this.ctx.rotate(this.getAngle(this.value));this.ctx.moveTo(4*
|
||||
this.pixelRatio,0);this.ctx.lineTo(-4*this.pixelRatio,0);this.ctx.lineTo(-1*this.pixelRatio,19-c);this.ctx.lineTo(1,19-c);this.ctx.fill();this.setStyles(".epoch .gauge .needle-base");this.ctx.beginPath();this.ctx.arc(0,0,this.getWidth()/25,0,2*Math.PI);this.ctx.fill();return this.ctx.restore()};a.prototype.domainChanged=function(){return this.draw()};a.prototype.ticksChanged=function(){return this.draw()};a.prototype.tickSizeChanged=function(){return this.draw()};a.prototype.tickOffsetChanged=function(){return this.draw()};
|
||||
a.prototype.formatChanged=function(){return this.svg.select("text.value").text(this.options.format(this.value))};return a}(Epoch.Chart.Canvas)}).call(this);
|
||||
(function(){var e={}.hasOwnProperty,g=function(c,a){function d(){this.constructor=c}for(var b in a)e.call(a,b)&&(c[b]=a[b]);d.prototype=a.prototype;c.prototype=new d;c.__super__=a.prototype;return c};Epoch.Time.Heatmap=function(c){function a(c){this.options=c;a.__super__.constructor.call(this,this.options=Epoch.Util.defaults(this.options,b));this._setOpacityFunction();this._setupPaintCanvas();this.onAll(e)}var d,b,e;g(a,c);b={buckets:10,bucketRange:[0,100],opacity:"linear",bucketPadding:2,paintZeroValues:!1,
|
||||
cutOutliers:!1};d={root:function(a,b){return Math.pow(a/b,0.5)},linear:function(a,b){return a/b},quadratic:function(a,b){return Math.pow(a/b,2)},cubic:function(a,b){return Math.pow(a/b,3)},quartic:function(a,b){return Math.pow(a/b,4)},quintic:function(a,b){return Math.pow(a/b,5)}};e={"option:buckets":"bucketsChanged","option:bucketRange":"bucketRangeChanged","option:opacity":"opacityChanged","option:bucketPadding":"bucketPaddingChanged","option:paintZeroValues":"paintZeroValuesChanged","option:cutOutliers":"cutOutliersChanged"};
|
||||
a.prototype._setOpacityFunction=function(){if(Epoch.isString(this.options.opacity)){if(this._opacityFn=d[this.options.opacity],null==this._opacityFn)return Epoch.exception("Unknown coloring function provided '"+this.options.opacity+"'")}else return Epoch.isFunction(this.options.opacity)?this._opacityFn=this.options.opacity:Epoch.exception("Unknown type for provided coloring function.")};a.prototype.setData=function(b){var c,d,e,g;a.__super__.setData.call(this,b);e=this.data;g=[];c=0;for(d=e.length;c<
|
||||
d;c++)b=e[c],g.push(b.values=b.values.map(function(a){return function(b){return a._prepareEntry(b)}}(this)));return g};a.prototype._getBuckets=function(a){var b,c,d,e,g;e=a.time;g=[];b=0;for(d=this.options.buckets;0<=d?b<d:b>d;0<=d?++b:--b)g.push(0);e={time:e,max:0,buckets:g};b=(this.options.bucketRange[1]-this.options.bucketRange[0])/this.options.buckets;g=a.histogram;for(c in g)a=g[c],d=parseInt((c-this.options.bucketRange[0])/b),this.options.cutOutliers&&(0>d||d>=this.options.buckets)||(0>d?d=
|
||||
0:d>=this.options.buckets&&(d=this.options.buckets-1),e.buckets[d]+=parseInt(a));c=a=0;for(b=e.buckets.length;0<=b?a<b:a>b;c=0<=b?++a:--a)e.max=Math.max(e.max,e.buckets[c]);return e};a.prototype.y=function(){return d3.scale.linear().domain(this.options.bucketRange).range([this.innerHeight(),0])};a.prototype.ySvg=function(){return d3.scale.linear().domain(this.options.bucketRange).range([this.innerHeight()/this.pixelRatio,0])};a.prototype.h=function(){return this.innerHeight()/this.options.buckets};
|
||||
a.prototype._offsetX=function(){return 0.5*this.w()/this.pixelRatio};a.prototype._setupPaintCanvas=function(){this.paintWidth=(this.options.windowSize+1)*this.w();this.paintHeight=this.height*this.pixelRatio;this.paint=document.createElement("CANVAS");this.paint.width=this.paintWidth;this.paint.height=this.paintHeight;this.p=Epoch.Util.getContext(this.paint);this.redraw();this.on("after:shift","_paintEntry");this.on("transition:end","_shiftPaintCanvas");return this.on("transition:end",function(a){return function(){return a.draw(a.animation.frame*
|
||||
a.animation.delta())}}(this))};a.prototype.redraw=function(){var a,b;b=this.data[0].values.length;a=this.options.windowSize;for(this.inTransition()&&a++;0<=--b&&0<=--a;)this._paintEntry(b,a);return this.draw(this.animation.frame*this.animation.delta())};a.prototype._computeColor=function(a,b,c){return Epoch.Util.toRGBA(c,this._opacityFn(a,b))};a.prototype._paintEntry=function(a,b){var c,d,e,g,h,p,r,s,t,v,y,w,A,z;null==a&&(a=null);null==b&&(b=null);g=[this.w(),this.h()];y=g[0];p=g[1];null==a&&(a=this.data[0].values.length-
|
||||
1);null==b&&(b=this.options.windowSize);g=[];var x;x=[];h=0;for(v=this.options.buckets;0<=v?h<v:h>v;0<=v?++h:--h)x.push(0);v=0;t=this.data;d=0;for(r=t.length;d<r;d++){s=t[d];h=this._getBuckets(s.values[a]);w=h.buckets;for(c in w)e=w[c],x[c]+=e;v+=h.max;e=this.getStyles("."+s.className.split(" ").join(".")+" rect.bucket");h.color=e.fill;g.push(h)}s=b*y;this.p.clearRect(s,0,y,this.paintHeight);r=this.options.buckets;z=[];for(c in x){e=x[c];d=this._avgLab(g,c);w=t=0;for(A=g.length;w<A;w++)h=g[w],t+=
|
||||
h.buckets[c]/e*v;if(0<e||this.options.paintZeroValues)this.p.fillStyle=this._computeColor(e,t,d),this.p.fillRect(s,(r-1)*p,y-this.options.bucketPadding,p-this.options.bucketPadding);z.push(r--)}return z};a.prototype._shiftPaintCanvas=function(){var a;a=this.p.getImageData(this.w(),0,this.paintWidth-this.w(),this.paintHeight);return this.p.putImageData(a,0,0)};a.prototype._avgLab=function(a,b){var c,d,e,g,h,p,r,s;r=[0,0,0,0];h=r[0];c=r[1];d=r[2];r=r[3];p=0;for(s=a.length;p<s;p++)e=a[p],null!=e.buckets[b]&&
|
||||
(r+=e.buckets[b]);for(g in a)e=a[g],p=null!=e.buckets[b]?e.buckets[b]|0:0,p/=r,e=d3.lab(e.color),h+=p*e.l,c+=p*e.a,d+=p*e.b;return d3.lab(h,c,d).toString()};a.prototype.draw=function(b){null==b&&(b=0);this.clear();this.ctx.drawImage(this.paint,b,0);return a.__super__.draw.call(this)};a.prototype.bucketsChanged=function(){return this.redraw()};a.prototype.bucketRangeChanged=function(){this._transitionRangeAxes();return this.redraw()};a.prototype.opacityChanged=function(){this._setOpacityFunction();
|
||||
return this.redraw()};a.prototype.bucketPaddingChanged=function(){return this.redraw()};a.prototype.paintZeroValuesChanged=function(){return this.redraw()};a.prototype.cutOutliersChanged=function(){return this.redraw()};return a}(Epoch.Time.Plot)}).call(this);
|
||||
(function(){var e={}.hasOwnProperty,g=function(c,a){function d(){this.constructor=c}for(var b in a)e.call(a,b)&&(c[b]=a[b]);d.prototype=a.prototype;c.prototype=new d;c.__super__=a.prototype;return c};Epoch.Time.Line=function(c){function a(){return a.__super__.constructor.apply(this,arguments)}g(a,c);a.prototype.setStyles=function(a){a=this.getStyles("g."+a.replace(/\s/g,".")+" path.line");this.ctx.fillStyle=a.fill;this.ctx.strokeStyle=a.stroke;return this.ctx.lineWidth=this.pixelRatio*a["stroke-width"].replace("px",
|
||||
"")};a.prototype.y=function(){return d3.scale.linear().domain(this.extent(function(a){return a.y})).range([this.innerHeight()-this.pixelRatio/2,this.pixelRatio])};a.prototype.draw=function(c){var b,e,g,f,q,u,m,l,n,p;null==c&&(c=0);this.clear();e=[this.y(),this.w()];m=e[0];u=e[1];p=this.data;l=0;for(n=p.length;l<n;l++)if(f=p[l],0<f.values.length){this.setStyles(f.className);this.ctx.beginPath();q=[this.options.windowSize,f.values.length,this.inTransition()];e=q[0];g=q[1];for(q=q[2];-2<=--e&&0<=--g;)b=
|
||||
f.values[g],b=[(e+1)*u+c,m(b.y)],q&&(b[0]+=u),e===this.options.windowSize-1?this.ctx.moveTo.apply(this.ctx,b):this.ctx.lineTo.apply(this.ctx,b);this.ctx.stroke()}return a.__super__.draw.call(this)};return a}(Epoch.Time.Plot)}).call(this);(function(){Epoch._typeMap={area:Epoch.Chart.Area,bar:Epoch.Chart.Bar,line:Epoch.Chart.Line,pie:Epoch.Chart.Pie,scatter:Epoch.Chart.Scatter,"time.area":Epoch.Time.Area,"time.bar":Epoch.Time.Bar,"time.line":Epoch.Time.Line,"time.gauge":Epoch.Time.Gauge,"time.heatmap":Epoch.Time.Heatmap}}).call(this);
|
||||
(function(){null!=window.MooTools&&function(){return Element.implement("epoch",function(e){var g,c;c=$$(this);null==(g=c.retrieve("epoch-chart")[0])&&(e.el=this,g=Epoch._typeMap[e.type],null==g&&Epoch.exception("Unknown chart type '"+e.type+"'"),c.store("epoch-chart",g=new g(e)),g.draw());return g})}()}).call(this);
|
||||
(function(){var e;e=function(e){return e.fn.epoch=function(c){var a;c.el=this.get(0);null==(a=this.data("epoch-chart"))&&(a=Epoch._typeMap[c.type],null==a&&Epoch.exception("Unknown chart type '"+c.type+"'"),this.data("epoch-chart",a=new a(c)),a.draw());return a}};null!=window.jQuery&&e(jQuery)}).call(this);
|
||||
(function(){var e;e=function(e){var c,a,d;a={};c=0;d=function(){return"epoch-chart-"+ ++c};return e.extend(e.fn,{epoch:function(b){var c,e;if(null!=(c=this.data("epoch-chart")))return a[c];b.el=this.get(0);e=Epoch._typeMap[b.type];null==e&&Epoch.exception("Unknown chart type '"+b.type+"'");this.data("epoch-chart",c=d());b=new e(b);a[c]=b;b.draw();return b}})};null!=window.Zepto&&e(Zepto)}).call(this);
|
||||
137
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/resources/static/prismjs.min.css
generated
vendored
Normal file
137
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/resources/static/prismjs.min.css
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
/* http://prismjs.com/download.html?themes=prism&languages=clike+javascript+go */
|
||||
/**
|
||||
* prism.js default theme for JavaScript, CSS and HTML
|
||||
* Based on dabblet (http://dabblet.com)
|
||||
* @author Lea Verou
|
||||
*/
|
||||
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
color: black;
|
||||
text-shadow: 0 1px white;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', monospace;
|
||||
direction: ltr;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
line-height: 1.5;
|
||||
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
|
||||
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
|
||||
code[class*="language-"]::selection, code[class*="language-"] ::selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
@media print {
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
pre[class*="language-"] {
|
||||
padding: 1em;
|
||||
margin: .5em 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:not(pre) > code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
background: #f5f2f0;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre) > code[class*="language-"] {
|
||||
padding: .1em;
|
||||
border-radius: .3em;
|
||||
}
|
||||
|
||||
.token.comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: slategray;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.namespace {
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.tag,
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.constant,
|
||||
.token.symbol,
|
||||
.token.deleted {
|
||||
color: #905;
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
.token.attr-name,
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.builtin,
|
||||
.token.inserted {
|
||||
color: #690;
|
||||
}
|
||||
|
||||
.token.operator,
|
||||
.token.entity,
|
||||
.token.url,
|
||||
.language-css .token.string,
|
||||
.style .token.string {
|
||||
color: #a67f59;
|
||||
background: hsla(0, 0%, 100%, .5);
|
||||
}
|
||||
|
||||
.token.atrule,
|
||||
.token.attr-value,
|
||||
.token.keyword {
|
||||
color: #07a;
|
||||
}
|
||||
|
||||
.token.function {
|
||||
color: #DD4A68;
|
||||
}
|
||||
|
||||
.token.regex,
|
||||
.token.important,
|
||||
.token.variable {
|
||||
color: #e90;
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
5
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/resources/static/prismjs.min.js
generated
vendored
Normal file
5
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/resources/static/prismjs.min.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/* http://prismjs.com/download.html?themes=prism&languages=clike+javascript+go */
|
||||
self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{};var Prism=function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=self.Prism={util:{encode:function(e){return e instanceof n?new n(e.type,t.util.encode(e.content),e.alias):"Array"===t.util.type(e)?e.map(t.util.encode):e.replace(/&/g,"&").replace(/</g,"<").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},clone:function(e){var n=t.util.type(e);switch(n){case"Object":var a={};for(var r in e)e.hasOwnProperty(r)&&(a[r]=t.util.clone(e[r]));return a;case"Array":return e.map(function(e){return t.util.clone(e)})}return e}},languages:{extend:function(e,n){var a=t.util.clone(t.languages[e]);for(var r in n)a[r]=n[r];return a},insertBefore:function(e,n,a,r){r=r||t.languages;var i=r[e];if(2==arguments.length){a=arguments[1];for(var l in a)a.hasOwnProperty(l)&&(i[l]=a[l]);return i}var s={};for(var o in i)if(i.hasOwnProperty(o)){if(o==n)for(var l in a)a.hasOwnProperty(l)&&(s[l]=a[l]);s[o]=i[o]}return t.languages.DFS(t.languages,function(t,n){n===r[e]&&t!=e&&(this[t]=s)}),r[e]=s},DFS:function(e,n,a){for(var r in e)e.hasOwnProperty(r)&&(n.call(e,r,e[r],a||r),"Object"===t.util.type(e[r])?t.languages.DFS(e[r],n):"Array"===t.util.type(e[r])&&t.languages.DFS(e[r],n,r))}},highlightAll:function(e,n){for(var a,r=document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'),i=0;a=r[i++];)t.highlightElement(a,e===!0,n)},highlightElement:function(a,r,i){for(var l,s,o=a;o&&!e.test(o.className);)o=o.parentNode;if(o&&(l=(o.className.match(e)||[,""])[1],s=t.languages[l]),s){a.className=a.className.replace(e,"").replace(/\s+/g," ")+" language-"+l,o=a.parentNode,/pre/i.test(o.nodeName)&&(o.className=o.className.replace(e,"").replace(/\s+/g," ")+" language-"+l);var u=a.textContent;if(u){u=u.replace(/^(?:\r?\n|\r)/,"");var g={element:a,language:l,grammar:s,code:u};if(t.hooks.run("before-highlight",g),r&&self.Worker){var c=new Worker(t.filename);c.onmessage=function(e){g.highlightedCode=n.stringify(JSON.parse(e.data),l),t.hooks.run("before-insert",g),g.element.innerHTML=g.highlightedCode,i&&i.call(g.element),t.hooks.run("after-highlight",g)},c.postMessage(JSON.stringify({language:g.language,code:g.code}))}else g.highlightedCode=t.highlight(g.code,g.grammar,g.language),t.hooks.run("before-insert",g),g.element.innerHTML=g.highlightedCode,i&&i.call(a),t.hooks.run("after-highlight",g)}}},highlight:function(e,a,r){var i=t.tokenize(e,a);return n.stringify(t.util.encode(i),r)},tokenize:function(e,n){var a=t.Token,r=[e],i=n.rest;if(i){for(var l in i)n[l]=i[l];delete n.rest}e:for(var l in n)if(n.hasOwnProperty(l)&&n[l]){var s=n[l];s="Array"===t.util.type(s)?s:[s];for(var o=0;o<s.length;++o){var u=s[o],g=u.inside,c=!!u.lookbehind,f=0,h=u.alias;u=u.pattern||u;for(var p=0;p<r.length;p++){var d=r[p];if(r.length>e.length)break e;if(!(d instanceof a)){u.lastIndex=0;var m=u.exec(d);if(m){c&&(f=m[1].length);var y=m.index-1+f,m=m[0].slice(f),v=m.length,k=y+v,b=d.slice(0,y+1),w=d.slice(k+1),N=[p,1];b&&N.push(b);var O=new a(l,g?t.tokenize(m,g):m,h);N.push(O),w&&N.push(w),Array.prototype.splice.apply(r,N)}}}}}return r},hooks:{all:{},add:function(e,n){var a=t.hooks.all;a[e]=a[e]||[],a[e].push(n)},run:function(e,n){var a=t.hooks.all[e];if(a&&a.length)for(var r,i=0;r=a[i++];)r(n)}}},n=t.Token=function(e,t,n){this.type=e,this.content=t,this.alias=n};if(n.stringify=function(e,a,r){if("string"==typeof e)return e;if("Array"===t.util.type(e))return e.map(function(t){return n.stringify(t,a,e)}).join("");var i={type:e.type,content:n.stringify(e.content,a,r),tag:"span",classes:["token",e.type],attributes:{},language:a,parent:r};if("comment"==i.type&&(i.attributes.spellcheck="true"),e.alias){var l="Array"===t.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(i.classes,l)}t.hooks.run("wrap",i);var s="";for(var o in i.attributes)s+=o+'="'+(i.attributes[o]||"")+'"';return"<"+i.tag+' class="'+i.classes.join(" ")+'" '+s+">"+i.content+"</"+i.tag+">"},!self.document)return self.addEventListener?(self.addEventListener("message",function(e){var n=JSON.parse(e.data),a=n.language,r=n.code;self.postMessage(JSON.stringify(t.util.encode(t.tokenize(r,t.languages[a])))),self.close()},!1),self.Prism):self.Prism;var a=document.getElementsByTagName("script");return a=a[a.length-1],a&&(t.filename=a.src,document.addEventListener&&!a.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)),self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism);;
|
||||
Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:/("|')(\\\n|\\?.)*?\1/,"class-name":{pattern:/((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(true|false)\b/,"function":{pattern:/[a-z0-9_]+\(/i,inside:{punctuation:/\(/}},number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/,operator:/[-+]{1,2}|!|<=?|>=?|={1,3}|&{1,2}|\|?\||\?|\*|\/|~|\^|%/,ignore:/&(lt|gt|amp);/i,punctuation:/[{}[\];(),.:]/};;
|
||||
Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|function|get|if|implements|import|in|instanceof|interface|let|new|null|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|-?Infinity)\b/,"function":/(?!\d)[a-z0-9_$]+(?=\()/i}),Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/<script[\w\W]*?>[\w\W]*?<\/script>/i,inside:{tag:{pattern:/<script[\w\W]*?>|<\/script>/i,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.javascript},alias:"language-javascript"}});;
|
||||
Prism.languages.go=Prism.languages.extend("clike",{keyword:/\b(break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,builtin:/\b(bool|byte|complex(64|128)|error|float(32|64)|rune|string|u?int(8|16|32|64|)|uintptr|append|cap|close|complex|copy|delete|imag|len|make|new|panic|print(ln)?|real|recover)\b/,"boolean":/\b(_|iota|nil|true|false)\b/,operator:/([(){}\[\]]|[*\/%^!]=?|\+[=+]?|-[>=-]?|\|[=|]?|>[=>]?|<(<|[=-])?|==?|&(&|=|^=?)?|\.(\.\.)?|[,;]|:=?)/,number:/\b(-?(0x[a-f\d]+|(\d+\.?\d*|\.\d+)(e[-+]?\d+)?)i?)\b/i,string:/("|'|`)(\\?.|\r|\n)*?\1/}),delete Prism.languages.go["class-name"];;
|
||||
144
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/resources/static/realtime.js
generated
vendored
Normal file
144
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/resources/static/realtime.js
generated
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
|
||||
|
||||
function StartRealtime(roomid, timestamp) {
|
||||
StartEpoch(timestamp);
|
||||
StartSSE(roomid);
|
||||
StartForm();
|
||||
}
|
||||
|
||||
function StartForm() {
|
||||
$('#chat-message').focus();
|
||||
$('#chat-form').ajaxForm(function() {
|
||||
$('#chat-message').val('');
|
||||
$('#chat-message').focus();
|
||||
});
|
||||
}
|
||||
|
||||
function StartEpoch(timestamp) {
|
||||
var windowSize = 60;
|
||||
var height = 200;
|
||||
var defaultData = histogram(windowSize, timestamp);
|
||||
|
||||
window.heapChart = $('#heapChart').epoch({
|
||||
type: 'time.area',
|
||||
axes: ['bottom', 'left'],
|
||||
height: height,
|
||||
historySize: 10,
|
||||
data: [
|
||||
{values: defaultData},
|
||||
{values: defaultData}
|
||||
]
|
||||
});
|
||||
|
||||
window.mallocsChart = $('#mallocsChart').epoch({
|
||||
type: 'time.area',
|
||||
axes: ['bottom', 'left'],
|
||||
height: height,
|
||||
historySize: 10,
|
||||
data: [
|
||||
{values: defaultData},
|
||||
{values: defaultData}
|
||||
]
|
||||
});
|
||||
|
||||
window.messagesChart = $('#messagesChart').epoch({
|
||||
type: 'time.line',
|
||||
axes: ['bottom', 'left'],
|
||||
height: 240,
|
||||
historySize: 10,
|
||||
data: [
|
||||
{values: defaultData},
|
||||
{values: defaultData},
|
||||
{values: defaultData}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
function StartSSE(roomid) {
|
||||
if (!window.EventSource) {
|
||||
alert("EventSource is not enabled in this browser");
|
||||
return;
|
||||
}
|
||||
var source = new EventSource('/stream/'+roomid);
|
||||
source.addEventListener('message', newChatMessage, false);
|
||||
source.addEventListener('stats', stats, false);
|
||||
}
|
||||
|
||||
function stats(e) {
|
||||
var data = parseJSONStats(e.data);
|
||||
heapChart.push(data.heap);
|
||||
mallocsChart.push(data.mallocs);
|
||||
messagesChart.push(data.messages);
|
||||
}
|
||||
|
||||
function parseJSONStats(e) {
|
||||
var data = jQuery.parseJSON(e);
|
||||
var timestamp = data.timestamp;
|
||||
|
||||
var heap = [
|
||||
{time: timestamp, y: data.HeapInuse},
|
||||
{time: timestamp, y: data.StackInuse}
|
||||
];
|
||||
|
||||
var mallocs = [
|
||||
{time: timestamp, y: data.Mallocs},
|
||||
{time: timestamp, y: data.Frees}
|
||||
];
|
||||
var messages = [
|
||||
{time: timestamp, y: data.Connected},
|
||||
{time: timestamp, y: data.Inbound},
|
||||
{time: timestamp, y: data.Outbound}
|
||||
];
|
||||
|
||||
return {
|
||||
heap: heap,
|
||||
mallocs: mallocs,
|
||||
messages: messages
|
||||
}
|
||||
}
|
||||
|
||||
function newChatMessage(e) {
|
||||
var data = jQuery.parseJSON(e.data);
|
||||
var nick = data.nick;
|
||||
var message = data.message;
|
||||
var style = rowStyle(nick);
|
||||
var html = "<tr class=\""+style+"\"><td>"+nick+"</td><td>"+message+"</td></tr>";
|
||||
$('#chat').append(html);
|
||||
|
||||
$("#chat-scroll").scrollTop($("#chat-scroll")[0].scrollHeight);
|
||||
}
|
||||
|
||||
function histogram(windowSize, timestamp) {
|
||||
var entries = new Array(windowSize);
|
||||
for(var i = 0; i < windowSize; i++) {
|
||||
entries[i] = {time: (timestamp-windowSize+i-1), y:0};
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
var entityMap = {
|
||||
"&": "&",
|
||||
"<": "<",
|
||||
">": ">",
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
"/": '/'
|
||||
};
|
||||
|
||||
function rowStyle(nick) {
|
||||
var classes = ['active', 'success', 'info', 'warning', 'danger'];
|
||||
var index = hashCode(nick)%5;
|
||||
return classes[index];
|
||||
}
|
||||
|
||||
function hashCode(s){
|
||||
return Math.abs(s.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0));
|
||||
}
|
||||
|
||||
function escapeHtml(string) {
|
||||
return String(string).replace(/[&<>"'\/]/g, function (s) {
|
||||
return entityMap[s];
|
||||
});
|
||||
}
|
||||
|
||||
window.StartRealtime = StartRealtime
|
||||
25
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/rooms.go
generated
vendored
Normal file
25
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/rooms.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import "github.com/dustin/go-broadcast"
|
||||
|
||||
var roomChannels = make(map[string]broadcast.Broadcaster)
|
||||
|
||||
func openListener(roomid string) chan interface{} {
|
||||
listener := make(chan interface{})
|
||||
room(roomid).Register(listener)
|
||||
return listener
|
||||
}
|
||||
|
||||
func closeListener(roomid string, listener chan interface{}) {
|
||||
room(roomid).Unregister(listener)
|
||||
close(listener)
|
||||
}
|
||||
|
||||
func room(roomid string) broadcast.Broadcaster {
|
||||
b, ok := roomChannels[roomid]
|
||||
if !ok {
|
||||
b = broadcast.NewBroadcaster(10)
|
||||
roomChannels[roomid] = b
|
||||
}
|
||||
return b
|
||||
}
|
||||
95
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/routes.go
generated
vendored
Normal file
95
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/routes.go
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func rateLimit(c *gin.Context) {
|
||||
ip := c.ClientIP()
|
||||
value := int(ips.Add(ip, 1))
|
||||
if value%50 == 0 {
|
||||
fmt.Printf("ip: %s, count: %d\n", ip, value)
|
||||
}
|
||||
if value >= 200 {
|
||||
if value%200 == 0 {
|
||||
fmt.Println("ip blocked")
|
||||
}
|
||||
c.Abort()
|
||||
c.String(503, "you were automatically banned :)")
|
||||
}
|
||||
}
|
||||
|
||||
func index(c *gin.Context) {
|
||||
c.Redirect(301, "/room/hn")
|
||||
}
|
||||
|
||||
func roomGET(c *gin.Context) {
|
||||
roomid := c.Param("roomid")
|
||||
nick := c.Query("nick")
|
||||
if len(nick) < 2 {
|
||||
nick = ""
|
||||
}
|
||||
if len(nick) > 13 {
|
||||
nick = nick[0:12] + "..."
|
||||
}
|
||||
c.HTML(200, "room_login.templ.html", gin.H{
|
||||
"roomid": roomid,
|
||||
"nick": nick,
|
||||
"timestamp": time.Now().Unix(),
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func roomPOST(c *gin.Context) {
|
||||
roomid := c.Param("roomid")
|
||||
nick := c.Query("nick")
|
||||
message := c.PostForm("message")
|
||||
message = strings.TrimSpace(message)
|
||||
|
||||
validMessage := len(message) > 1 && len(message) < 200
|
||||
validNick := len(nick) > 1 && len(nick) < 14
|
||||
if !validMessage || !validNick {
|
||||
c.JSON(400, gin.H{
|
||||
"status": "failed",
|
||||
"error": "the message or nickname is too long",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
post := gin.H{
|
||||
"nick": html.EscapeString(nick),
|
||||
"message": html.EscapeString(message),
|
||||
}
|
||||
messages.Add("inbound", 1)
|
||||
room(roomid).Submit(post)
|
||||
c.JSON(200, post)
|
||||
}
|
||||
|
||||
func streamRoom(c *gin.Context) {
|
||||
roomid := c.Param("roomid")
|
||||
listener := openListener(roomid)
|
||||
ticker := time.NewTicker(1 * time.Second)
|
||||
users.Add("connected", 1)
|
||||
defer func() {
|
||||
closeListener(roomid, listener)
|
||||
ticker.Stop()
|
||||
users.Add("disconnected", 1)
|
||||
}()
|
||||
|
||||
c.Stream(func(w io.Writer) bool {
|
||||
select {
|
||||
case msg := <-listener:
|
||||
messages.Add("outbound", 1)
|
||||
c.SSEvent("message", msg)
|
||||
case <-ticker.C:
|
||||
c.SSEvent("stats", Stats())
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
58
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/stats.go
generated
vendored
Normal file
58
vendor/github.com/gin-gonic/gin/examples/realtime-advanced/stats.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/manucorporat/stats"
|
||||
)
|
||||
|
||||
var (
|
||||
ips = stats.New()
|
||||
messages = stats.New()
|
||||
users = stats.New()
|
||||
mutexStats sync.RWMutex
|
||||
savedStats map[string]uint64
|
||||
)
|
||||
|
||||
func statsWorker() {
|
||||
c := time.Tick(1 * time.Second)
|
||||
var lastMallocs uint64
|
||||
var lastFrees uint64
|
||||
for range c {
|
||||
var stats runtime.MemStats
|
||||
runtime.ReadMemStats(&stats)
|
||||
|
||||
mutexStats.Lock()
|
||||
savedStats = map[string]uint64{
|
||||
"timestamp": uint64(time.Now().Unix()),
|
||||
"HeapInuse": stats.HeapInuse,
|
||||
"StackInuse": stats.StackInuse,
|
||||
"Mallocs": (stats.Mallocs - lastMallocs),
|
||||
"Frees": (stats.Frees - lastFrees),
|
||||
"Inbound": uint64(messages.Get("inbound")),
|
||||
"Outbound": uint64(messages.Get("outbound")),
|
||||
"Connected": connectedUsers(),
|
||||
}
|
||||
lastMallocs = stats.Mallocs
|
||||
lastFrees = stats.Frees
|
||||
messages.Reset()
|
||||
mutexStats.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
func connectedUsers() uint64 {
|
||||
connected := users.Get("connected") - users.Get("disconnected")
|
||||
if connected < 0 {
|
||||
return 0
|
||||
}
|
||||
return uint64(connected)
|
||||
}
|
||||
|
||||
func Stats() map[string]uint64 {
|
||||
mutexStats.RLock()
|
||||
defer mutexStats.RUnlock()
|
||||
|
||||
return savedStats
|
||||
}
|
||||
9
vendor/github.com/gin-gonic/gin/examples/realtime-chat/Makefile
generated
vendored
Normal file
9
vendor/github.com/gin-gonic/gin/examples/realtime-chat/Makefile
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
all: deps build
|
||||
|
||||
.PHONY: deps
|
||||
deps:
|
||||
go get -d -v github.com/dustin/go-broadcast/...
|
||||
|
||||
.PHONY: build
|
||||
build: deps
|
||||
go build -o realtime-chat main.go rooms.go template.go
|
||||
58
vendor/github.com/gin-gonic/gin/examples/realtime-chat/main.go
generated
vendored
Normal file
58
vendor/github.com/gin-gonic/gin/examples/realtime-chat/main.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
router := gin.Default()
|
||||
router.SetHTMLTemplate(html)
|
||||
|
||||
router.GET("/room/:roomid", roomGET)
|
||||
router.POST("/room/:roomid", roomPOST)
|
||||
router.DELETE("/room/:roomid", roomDELETE)
|
||||
router.GET("/stream/:roomid", stream)
|
||||
|
||||
router.Run(":8080")
|
||||
}
|
||||
|
||||
func stream(c *gin.Context) {
|
||||
roomid := c.Param("roomid")
|
||||
listener := openListener(roomid)
|
||||
defer closeListener(roomid, listener)
|
||||
|
||||
c.Stream(func(w io.Writer) bool {
|
||||
c.SSEvent("message", <-listener)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func roomGET(c *gin.Context) {
|
||||
roomid := c.Param("roomid")
|
||||
userid := fmt.Sprint(rand.Int31())
|
||||
c.HTML(200, "chat_room", gin.H{
|
||||
"roomid": roomid,
|
||||
"userid": userid,
|
||||
})
|
||||
}
|
||||
|
||||
func roomPOST(c *gin.Context) {
|
||||
roomid := c.Param("roomid")
|
||||
userid := c.PostForm("user")
|
||||
message := c.PostForm("message")
|
||||
room(roomid).Submit(userid + ": " + message)
|
||||
|
||||
c.JSON(200, gin.H{
|
||||
"status": "success",
|
||||
"message": message,
|
||||
})
|
||||
}
|
||||
|
||||
func roomDELETE(c *gin.Context) {
|
||||
roomid := c.Param("roomid")
|
||||
deleteBroadcast(roomid)
|
||||
}
|
||||
33
vendor/github.com/gin-gonic/gin/examples/realtime-chat/rooms.go
generated
vendored
Normal file
33
vendor/github.com/gin-gonic/gin/examples/realtime-chat/rooms.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import "github.com/dustin/go-broadcast"
|
||||
|
||||
var roomChannels = make(map[string]broadcast.Broadcaster)
|
||||
|
||||
func openListener(roomid string) chan interface{} {
|
||||
listener := make(chan interface{})
|
||||
room(roomid).Register(listener)
|
||||
return listener
|
||||
}
|
||||
|
||||
func closeListener(roomid string, listener chan interface{}) {
|
||||
room(roomid).Unregister(listener)
|
||||
close(listener)
|
||||
}
|
||||
|
||||
func deleteBroadcast(roomid string) {
|
||||
b, ok := roomChannels[roomid]
|
||||
if ok {
|
||||
b.Close()
|
||||
delete(roomChannels, roomid)
|
||||
}
|
||||
}
|
||||
|
||||
func room(roomid string) broadcast.Broadcaster {
|
||||
b, ok := roomChannels[roomid]
|
||||
if !ok {
|
||||
b = broadcast.NewBroadcaster(10)
|
||||
roomChannels[roomid] = b
|
||||
}
|
||||
return b
|
||||
}
|
||||
44
vendor/github.com/gin-gonic/gin/examples/realtime-chat/template.go
generated
vendored
Normal file
44
vendor/github.com/gin-gonic/gin/examples/realtime-chat/template.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
package main
|
||||
|
||||
import "html/template"
|
||||
|
||||
var html = template.Must(template.New("chat_room").Parse(`
|
||||
<html>
|
||||
<head>
|
||||
<title>{{.roomid}}</title>
|
||||
<link rel="stylesheet" type="text/css" href="http://meyerweb.com/eric/tools/css/reset/reset.css"/>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.js"></script>
|
||||
<script src="http://malsup.github.com/jquery.form.js"></script>
|
||||
<script>
|
||||
$('#message_form').focus();
|
||||
$(document).ready(function() {
|
||||
// bind 'myForm' and provide a simple callback function
|
||||
$('#myForm').ajaxForm(function() {
|
||||
$('#message_form').val('');
|
||||
$('#message_form').focus();
|
||||
});
|
||||
|
||||
if (!!window.EventSource) {
|
||||
var source = new EventSource('/stream/{{.roomid}}');
|
||||
source.addEventListener('message', function(e) {
|
||||
$('#messages').append(e.data + "</br>");
|
||||
$('html, body').animate({scrollTop:$(document).height()}, 'slow');
|
||||
|
||||
}, false);
|
||||
} else {
|
||||
alert("NOT SUPPORTED");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Welcome to {{.roomid}} room</h1>
|
||||
<div id="messages"></div>
|
||||
<form id="myForm" action="/room/{{.roomid}}" method="post">
|
||||
User: <input id="user_form" name="user" value="{{.userid}}"></input>
|
||||
Message: <input id="message_form" name="message"></input>
|
||||
<input type="submit" value="Submit" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
`))
|
||||
39
vendor/github.com/gin-gonic/gin/examples/upload-file/multiple/main.go
generated
vendored
Normal file
39
vendor/github.com/gin-gonic/gin/examples/upload-file/multiple/main.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
router := gin.Default()
|
||||
router.Static("/", "./public")
|
||||
router.POST("/upload", func(c *gin.Context) {
|
||||
name := c.PostForm("name")
|
||||
email := c.PostForm("email")
|
||||
|
||||
// Multipart form
|
||||
form, _ := c.MultipartForm()
|
||||
files := form.File["files"]
|
||||
|
||||
for _, file := range files {
|
||||
// Source
|
||||
src, _ := file.Open()
|
||||
defer src.Close()
|
||||
|
||||
// Destination
|
||||
dst, _ := os.Create(file.Filename)
|
||||
defer dst.Close()
|
||||
|
||||
// Copy
|
||||
io.Copy(dst, src)
|
||||
}
|
||||
|
||||
c.String(http.StatusOK, fmt.Sprintf("Uploaded successfully %d files with fields name=%s and email=%s.", len(files), name, email))
|
||||
})
|
||||
router.Run(":8080")
|
||||
}
|
||||
17
vendor/github.com/gin-gonic/gin/examples/upload-file/multiple/public/index.html
generated
vendored
Normal file
17
vendor/github.com/gin-gonic/gin/examples/upload-file/multiple/public/index.html
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Multiple file upload</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Upload multiple files with fields</h1>
|
||||
|
||||
<form action="/upload" method="post" enctype="multipart/form-data">
|
||||
Name: <input type="text" name="name"><br>
|
||||
Email: <input type="email" name="email"><br>
|
||||
Files: <input type="file" name="files" multiple><br><br>
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
34
vendor/github.com/gin-gonic/gin/examples/upload-file/single/main.go
generated
vendored
Normal file
34
vendor/github.com/gin-gonic/gin/examples/upload-file/single/main.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
router := gin.Default()
|
||||
router.Static("/", "./public")
|
||||
router.POST("/upload", func(c *gin.Context) {
|
||||
name := c.PostForm("name")
|
||||
email := c.PostForm("email")
|
||||
|
||||
// Source
|
||||
file, _ := c.FormFile("file")
|
||||
src, _ := file.Open()
|
||||
defer src.Close()
|
||||
|
||||
// Destination
|
||||
dst, _ := os.Create(file.Filename)
|
||||
defer dst.Close()
|
||||
|
||||
// Copy
|
||||
io.Copy(dst, src)
|
||||
|
||||
c.String(http.StatusOK, fmt.Sprintf("File %s uploaded successfully with fields name=%s and email=%s.", file.Filename, name, email))
|
||||
})
|
||||
router.Run(":8080")
|
||||
}
|
||||
16
vendor/github.com/gin-gonic/gin/examples/upload-file/single/public/index.html
generated
vendored
Normal file
16
vendor/github.com/gin-gonic/gin/examples/upload-file/single/public/index.html
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Single file upload</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Upload single file with fields</h1>
|
||||
|
||||
<form action="/upload" method="post" enctype="multipart/form-data">
|
||||
Name: <input type="text" name="name"><br>
|
||||
Email: <input type="email" name="email"><br>
|
||||
Files: <input type="file" name="file"><br><br>
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
</body>
|
||||
1
vendor/github.com/gin-gonic/gin/fixtures/basic/hello.tmpl
generated
vendored
Normal file
1
vendor/github.com/gin-gonic/gin/fixtures/basic/hello.tmpl
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<h1>Hello {[{.name}]}</h1>
|
||||
1
vendor/github.com/gin-gonic/gin/fixtures/basic/raw.tmpl
generated
vendored
Normal file
1
vendor/github.com/gin-gonic/gin/fixtures/basic/raw.tmpl
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
Date: {[{.now | formatAsDate}]}
|
||||
46
vendor/github.com/gin-gonic/gin/fs.go
generated
vendored
Normal file
46
vendor/github.com/gin-gonic/gin/fs.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright 2017 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gin
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
type (
|
||||
onlyfilesFS struct {
|
||||
fs http.FileSystem
|
||||
}
|
||||
neuteredReaddirFile struct {
|
||||
http.File
|
||||
}
|
||||
)
|
||||
|
||||
// Dir returns a http.Filesystem that can be used by http.FileServer(). It is used internally
|
||||
// in router.Static().
|
||||
// if listDirectory == true, then it works the same as http.Dir() otherwise it returns
|
||||
// a filesystem that prevents http.FileServer() to list the directory files.
|
||||
func Dir(root string, listDirectory bool) http.FileSystem {
|
||||
fs := http.Dir(root)
|
||||
if listDirectory {
|
||||
return fs
|
||||
}
|
||||
return &onlyfilesFS{fs}
|
||||
}
|
||||
|
||||
// Conforms to http.Filesystem
|
||||
func (fs onlyfilesFS) Open(name string) (http.File, error) {
|
||||
f, err := fs.fs.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return neuteredReaddirFile{f}, nil
|
||||
}
|
||||
|
||||
// Overrides the http.File default implementation
|
||||
func (f neuteredReaddirFile) Readdir(count int) ([]os.FileInfo, error) {
|
||||
// this disables directory listing
|
||||
return nil, nil
|
||||
}
|
||||
423
vendor/github.com/gin-gonic/gin/gin.go
generated
vendored
423
vendor/github.com/gin-gonic/gin/gin.go
generated
vendored
@@ -5,139 +5,414 @@
|
||||
package gin
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin/render"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"html/template"
|
||||
"math"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/gin-gonic/gin/render"
|
||||
)
|
||||
|
||||
const (
|
||||
AbortIndex = math.MaxInt8 / 2
|
||||
MIMEJSON = "application/json"
|
||||
MIMEHTML = "text/html"
|
||||
MIMEXML = "application/xml"
|
||||
MIMEXML2 = "text/xml"
|
||||
MIMEPlain = "text/plain"
|
||||
MIMEPOSTForm = "application/x-www-form-urlencoded"
|
||||
)
|
||||
// Version is Framework's version
|
||||
const Version = "v1.2"
|
||||
|
||||
var default404Body = []byte("404 page not found")
|
||||
var default405Body = []byte("405 method not allowed")
|
||||
var defaultAppEngine bool
|
||||
|
||||
type HandlerFunc func(*Context)
|
||||
type HandlersChain []HandlerFunc
|
||||
|
||||
// Last returns the last handler in the chain. ie. the last handler is the main own.
|
||||
func (c HandlersChain) Last() HandlerFunc {
|
||||
length := len(c)
|
||||
if length > 0 {
|
||||
return c[length-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type (
|
||||
HandlerFunc func(*Context)
|
||||
RoutesInfo []RouteInfo
|
||||
RouteInfo struct {
|
||||
Method string
|
||||
Path string
|
||||
Handler string
|
||||
}
|
||||
|
||||
// Represents the web framework, it wraps the blazing fast httprouter multiplexer and a list of global middlewares.
|
||||
// Engine is the framework's instance, it contains the muxer, middleware and configuration settings.
|
||||
// Create an instance of Engine, by using New() or Default()
|
||||
Engine struct {
|
||||
*RouterGroup
|
||||
HTMLRender render.Render
|
||||
Default404Body []byte
|
||||
pool sync.Pool
|
||||
allNoRoute []HandlerFunc
|
||||
noRoute []HandlerFunc
|
||||
router *httprouter.Router
|
||||
RouterGroup
|
||||
delims render.Delims
|
||||
HTMLRender render.HTMLRender
|
||||
FuncMap template.FuncMap
|
||||
allNoRoute HandlersChain
|
||||
allNoMethod HandlersChain
|
||||
noRoute HandlersChain
|
||||
noMethod HandlersChain
|
||||
pool sync.Pool
|
||||
trees methodTrees
|
||||
|
||||
// Enables automatic redirection if the current route can't be matched but a
|
||||
// handler for the path with (without) the trailing slash exists.
|
||||
// For example if /foo/ is requested but a route only exists for /foo, the
|
||||
// client is redirected to /foo with http status code 301 for GET requests
|
||||
// and 307 for all other request methods.
|
||||
RedirectTrailingSlash bool
|
||||
|
||||
// If enabled, the router tries to fix the current request path, if no
|
||||
// handle is registered for it.
|
||||
// First superfluous path elements like ../ or // are removed.
|
||||
// Afterwards the router does a case-insensitive lookup of the cleaned path.
|
||||
// If a handle can be found for this route, the router makes a redirection
|
||||
// to the corrected path with status code 301 for GET requests and 307 for
|
||||
// all other request methods.
|
||||
// For example /FOO and /..//Foo could be redirected to /foo.
|
||||
// RedirectTrailingSlash is independent of this option.
|
||||
RedirectFixedPath bool
|
||||
|
||||
// If enabled, the router checks if another method is allowed for the
|
||||
// current route, if the current request can not be routed.
|
||||
// If this is the case, the request is answered with 'Method Not Allowed'
|
||||
// and HTTP status code 405.
|
||||
// If no other Method is allowed, the request is delegated to the NotFound
|
||||
// handler.
|
||||
HandleMethodNotAllowed bool
|
||||
ForwardedByClientIP bool
|
||||
|
||||
// #726 #755 If enabled, it will thrust some headers starting with
|
||||
// 'X-AppEngine...' for better integration with that PaaS.
|
||||
AppEngine bool
|
||||
|
||||
// If enabled, the url.RawPath will be used to find parameters.
|
||||
UseRawPath bool
|
||||
// If true, the path value will be unescaped.
|
||||
// If UseRawPath is false (by default), the UnescapePathValues effectively is true,
|
||||
// as url.Path gonna be used, which is already unescaped.
|
||||
UnescapePathValues bool
|
||||
}
|
||||
)
|
||||
|
||||
// Returns a new blank Engine instance without any middleware attached.
|
||||
// The most basic configuration
|
||||
var _ IRouter = &Engine{}
|
||||
|
||||
// New returns a new blank Engine instance without any middleware attached.
|
||||
// By default the configuration is:
|
||||
// - RedirectTrailingSlash: true
|
||||
// - RedirectFixedPath: false
|
||||
// - HandleMethodNotAllowed: false
|
||||
// - ForwardedByClientIP: true
|
||||
// - UseRawPath: false
|
||||
// - UnescapePathValues: true
|
||||
func New() *Engine {
|
||||
engine := &Engine{}
|
||||
engine.RouterGroup = &RouterGroup{
|
||||
Handlers: nil,
|
||||
absolutePath: "/",
|
||||
engine: engine,
|
||||
debugPrintWARNINGNew()
|
||||
engine := &Engine{
|
||||
RouterGroup: RouterGroup{
|
||||
Handlers: nil,
|
||||
basePath: "/",
|
||||
root: true,
|
||||
},
|
||||
FuncMap: template.FuncMap{},
|
||||
RedirectTrailingSlash: true,
|
||||
RedirectFixedPath: false,
|
||||
HandleMethodNotAllowed: false,
|
||||
ForwardedByClientIP: true,
|
||||
AppEngine: defaultAppEngine,
|
||||
UseRawPath: false,
|
||||
UnescapePathValues: true,
|
||||
trees: make(methodTrees, 0, 9),
|
||||
delims: render.Delims{"{{", "}}"},
|
||||
}
|
||||
engine.router = httprouter.New()
|
||||
engine.Default404Body = []byte("404 page not found")
|
||||
engine.router.NotFound = engine.handle404
|
||||
engine.RouterGroup.engine = engine
|
||||
engine.pool.New = func() interface{} {
|
||||
c := &Context{Engine: engine}
|
||||
c.Writer = &c.writermem
|
||||
return c
|
||||
return engine.allocateContext()
|
||||
}
|
||||
return engine
|
||||
}
|
||||
|
||||
// Returns a Engine instance with the Logger and Recovery already attached.
|
||||
// Default returns an Engine instance with the Logger and Recovery middleware already attached.
|
||||
func Default() *Engine {
|
||||
engine := New()
|
||||
engine.Use(Recovery(), Logger())
|
||||
engine.Use(Logger(), Recovery())
|
||||
return engine
|
||||
}
|
||||
|
||||
func (engine *Engine) allocateContext() *Context {
|
||||
return &Context{engine: engine}
|
||||
}
|
||||
|
||||
func (engine *Engine) Delims(left, right string) *Engine {
|
||||
engine.delims = render.Delims{left, right}
|
||||
return engine
|
||||
}
|
||||
|
||||
func (engine *Engine) LoadHTMLGlob(pattern string) {
|
||||
if IsDebugging() {
|
||||
render.HTMLDebug.AddGlob(pattern)
|
||||
engine.HTMLRender = render.HTMLDebug
|
||||
debugPrintLoadTemplate(template.Must(template.New("").Delims(engine.delims.Left, engine.delims.Right).Funcs(engine.FuncMap).ParseGlob(pattern)))
|
||||
engine.HTMLRender = render.HTMLDebug{Glob: pattern, FuncMap: engine.FuncMap, Delims: engine.delims}
|
||||
} else {
|
||||
templ := template.Must(template.ParseGlob(pattern))
|
||||
templ := template.Must(template.New("").Delims(engine.delims.Left, engine.delims.Right).Funcs(engine.FuncMap).ParseGlob(pattern))
|
||||
engine.SetHTMLTemplate(templ)
|
||||
}
|
||||
}
|
||||
|
||||
func (engine *Engine) LoadHTMLFiles(files ...string) {
|
||||
if IsDebugging() {
|
||||
render.HTMLDebug.AddFiles(files...)
|
||||
engine.HTMLRender = render.HTMLDebug
|
||||
engine.HTMLRender = render.HTMLDebug{Files: files, FuncMap: engine.FuncMap, Delims: engine.delims}
|
||||
} else {
|
||||
templ := template.Must(template.ParseFiles(files...))
|
||||
templ := template.Must(template.New("").Delims(engine.delims.Left, engine.delims.Right).Funcs(engine.FuncMap).ParseFiles(files...))
|
||||
engine.SetHTMLTemplate(templ)
|
||||
}
|
||||
}
|
||||
|
||||
func (engine *Engine) SetHTMLTemplate(templ *template.Template) {
|
||||
engine.HTMLRender = render.HTMLRender{
|
||||
Template: templ,
|
||||
if len(engine.trees) > 0 {
|
||||
debugPrintWARNINGSetHTMLTemplate()
|
||||
}
|
||||
|
||||
engine.HTMLRender = render.HTMLProduction{Template: templ.Funcs(engine.FuncMap)}
|
||||
}
|
||||
|
||||
// Adds handlers for NoRoute. It return a 404 code by default.
|
||||
func (engine *Engine) SetFuncMap(funcMap template.FuncMap) {
|
||||
engine.FuncMap = funcMap
|
||||
}
|
||||
|
||||
// NoRoute adds handlers for NoRoute. It return a 404 code by default.
|
||||
func (engine *Engine) NoRoute(handlers ...HandlerFunc) {
|
||||
engine.noRoute = handlers
|
||||
engine.rebuild404Handlers()
|
||||
}
|
||||
|
||||
func (engine *Engine) Use(middlewares ...HandlerFunc) {
|
||||
engine.RouterGroup.Use(middlewares...)
|
||||
// NoMethod sets the handlers called when... TODO
|
||||
func (engine *Engine) NoMethod(handlers ...HandlerFunc) {
|
||||
engine.noMethod = handlers
|
||||
engine.rebuild405Handlers()
|
||||
}
|
||||
|
||||
// Use attachs a global middleware to the router. ie. the middleware attached though Use() will be
|
||||
// included in the handlers chain for every single request. Even 404, 405, static files...
|
||||
// For example, this is the right place for a logger or error management middleware.
|
||||
func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
|
||||
engine.RouterGroup.Use(middleware...)
|
||||
engine.rebuild404Handlers()
|
||||
engine.rebuild405Handlers()
|
||||
return engine
|
||||
}
|
||||
|
||||
func (engine *Engine) rebuild404Handlers() {
|
||||
engine.allNoRoute = engine.combineHandlers(engine.noRoute)
|
||||
}
|
||||
|
||||
func (engine *Engine) handle404(w http.ResponseWriter, req *http.Request) {
|
||||
c := engine.createContext(w, req, nil, engine.allNoRoute)
|
||||
// set 404 by default, useful for logging
|
||||
c.Writer.WriteHeader(404)
|
||||
c.Next()
|
||||
if !c.Writer.Written() {
|
||||
if c.Writer.Status() == 404 {
|
||||
c.Data(-1, MIMEPlain, engine.Default404Body)
|
||||
} else {
|
||||
c.Writer.WriteHeaderNow()
|
||||
func (engine *Engine) rebuild405Handlers() {
|
||||
engine.allNoMethod = engine.combineHandlers(engine.noMethod)
|
||||
}
|
||||
|
||||
func (engine *Engine) addRoute(method, path string, handlers HandlersChain) {
|
||||
assert1(path[0] == '/', "path must begin with '/'")
|
||||
assert1(len(method) > 0, "HTTP method can not be empty")
|
||||
assert1(len(handlers) > 0, "there must be at least one handler")
|
||||
|
||||
debugPrintRoute(method, path, handlers)
|
||||
root := engine.trees.get(method)
|
||||
if root == nil {
|
||||
root = new(node)
|
||||
engine.trees = append(engine.trees, methodTree{method: method, root: root})
|
||||
}
|
||||
root.addRoute(path, handlers)
|
||||
}
|
||||
|
||||
// Routes returns a slice of registered routes, including some useful information, such as:
|
||||
// the http method, path and the handler name.
|
||||
func (engine *Engine) Routes() (routes RoutesInfo) {
|
||||
for _, tree := range engine.trees {
|
||||
routes = iterate("", tree.method, routes, tree.root)
|
||||
}
|
||||
return routes
|
||||
}
|
||||
|
||||
func iterate(path, method string, routes RoutesInfo, root *node) RoutesInfo {
|
||||
path += root.path
|
||||
if len(root.handlers) > 0 {
|
||||
routes = append(routes, RouteInfo{
|
||||
Method: method,
|
||||
Path: path,
|
||||
Handler: nameOfFunction(root.handlers.Last()),
|
||||
})
|
||||
}
|
||||
for _, child := range root.children {
|
||||
routes = iterate(path, method, routes, child)
|
||||
}
|
||||
return routes
|
||||
}
|
||||
|
||||
// Run attaches the router to a http.Server and starts listening and serving HTTP requests.
|
||||
// It is a shortcut for http.ListenAndServe(addr, router)
|
||||
// Note: this method will block the calling goroutine indefinitely unless an error happens.
|
||||
func (engine *Engine) Run(addr ...string) (err error) {
|
||||
defer func() { debugPrintError(err) }()
|
||||
|
||||
address := resolveAddress(addr)
|
||||
debugPrint("Listening and serving HTTP on %s\n", address)
|
||||
err = http.ListenAndServe(address, engine)
|
||||
return
|
||||
}
|
||||
|
||||
// RunTLS attaches the router to a http.Server and starts listening and serving HTTPS (secure) requests.
|
||||
// It is a shortcut for http.ListenAndServeTLS(addr, certFile, keyFile, router)
|
||||
// Note: this method will block the calling goroutine indefinitely unless an error happens.
|
||||
func (engine *Engine) RunTLS(addr string, certFile string, keyFile string) (err error) {
|
||||
debugPrint("Listening and serving HTTPS on %s\n", addr)
|
||||
defer func() { debugPrintError(err) }()
|
||||
|
||||
err = http.ListenAndServeTLS(addr, certFile, keyFile, engine)
|
||||
return
|
||||
}
|
||||
|
||||
// RunUnix attaches the router to a http.Server and starts listening and serving HTTP requests
|
||||
// through the specified unix socket (ie. a file).
|
||||
// Note: this method will block the calling goroutine indefinitely unless an error happens.
|
||||
func (engine *Engine) RunUnix(file string) (err error) {
|
||||
debugPrint("Listening and serving HTTP on unix:/%s", file)
|
||||
defer func() { debugPrintError(err) }()
|
||||
|
||||
os.Remove(file)
|
||||
listener, err := net.Listen("unix", file)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer listener.Close()
|
||||
err = http.Serve(listener, engine)
|
||||
return
|
||||
}
|
||||
|
||||
// Conforms to the http.Handler interface.
|
||||
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
c := engine.pool.Get().(*Context)
|
||||
c.writermem.reset(w)
|
||||
c.Request = req
|
||||
c.reset()
|
||||
|
||||
engine.handleHTTPRequest(c)
|
||||
|
||||
engine.pool.Put(c)
|
||||
}
|
||||
|
||||
// Re-enter a context that has been rewritten.
|
||||
// This can be done by setting c.Request.Path to your new target.
|
||||
// Disclaimer: You can loop yourself to death with this, use wisely.
|
||||
func (engine *Engine) HandleContext(c *Context) {
|
||||
c.reset()
|
||||
engine.handleHTTPRequest(c)
|
||||
engine.pool.Put(c)
|
||||
}
|
||||
|
||||
func (engine *Engine) handleHTTPRequest(context *Context) {
|
||||
httpMethod := context.Request.Method
|
||||
var path string
|
||||
var unescape bool
|
||||
if engine.UseRawPath && len(context.Request.URL.RawPath) > 0 {
|
||||
path = context.Request.URL.RawPath
|
||||
unescape = engine.UnescapePathValues
|
||||
} else {
|
||||
path = context.Request.URL.Path
|
||||
unescape = false
|
||||
}
|
||||
|
||||
// Find root of the tree for the given HTTP method
|
||||
t := engine.trees
|
||||
for i, tl := 0, len(t); i < tl; i++ {
|
||||
if t[i].method == httpMethod {
|
||||
root := t[i].root
|
||||
// Find route in tree
|
||||
handlers, params, tsr := root.getValue(path, context.Params, unescape)
|
||||
if handlers != nil {
|
||||
context.handlers = handlers
|
||||
context.Params = params
|
||||
context.Next()
|
||||
context.writermem.WriteHeaderNow()
|
||||
return
|
||||
}
|
||||
if httpMethod != "CONNECT" && path != "/" {
|
||||
if tsr && engine.RedirectTrailingSlash {
|
||||
redirectTrailingSlash(context)
|
||||
return
|
||||
}
|
||||
if engine.RedirectFixedPath && redirectFixedPath(context, root, engine.RedirectFixedPath) {
|
||||
return
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
engine.reuseContext(c)
|
||||
}
|
||||
|
||||
// ServeHTTP makes the router implement the http.Handler interface.
|
||||
func (engine *Engine) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||
engine.router.ServeHTTP(writer, request)
|
||||
}
|
||||
|
||||
func (engine *Engine) Run(addr string) error {
|
||||
debugPrint("Listening and serving HTTP on %s\n", addr)
|
||||
if err := http.ListenAndServe(addr, engine); err != nil {
|
||||
return err
|
||||
// TODO: unit test
|
||||
if engine.HandleMethodNotAllowed {
|
||||
for _, tree := range engine.trees {
|
||||
if tree.method != httpMethod {
|
||||
if handlers, _, _ := tree.root.getValue(path, nil, unescape); handlers != nil {
|
||||
context.handlers = engine.allNoMethod
|
||||
serveError(context, 405, default405Body)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
context.handlers = engine.allNoRoute
|
||||
serveError(context, 404, default404Body)
|
||||
}
|
||||
|
||||
func (engine *Engine) RunTLS(addr string, cert string, key string) error {
|
||||
debugPrint("Listening and serving HTTPS on %s\n", addr)
|
||||
if err := http.ListenAndServeTLS(addr, cert, key, engine); err != nil {
|
||||
return err
|
||||
var mimePlain = []string{MIMEPlain}
|
||||
|
||||
func serveError(c *Context, code int, defaultMessage []byte) {
|
||||
c.writermem.status = code
|
||||
c.Next()
|
||||
if !c.writermem.Written() {
|
||||
if c.writermem.Status() == code {
|
||||
c.writermem.Header()["Content-Type"] = mimePlain
|
||||
c.Writer.Write(defaultMessage)
|
||||
} else {
|
||||
c.writermem.WriteHeaderNow()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func redirectTrailingSlash(c *Context) {
|
||||
req := c.Request
|
||||
path := req.URL.Path
|
||||
code := 301 // Permanent redirect, request with GET method
|
||||
if req.Method != "GET" {
|
||||
code = 307
|
||||
}
|
||||
|
||||
if len(path) > 1 && path[len(path)-1] == '/' {
|
||||
req.URL.Path = path[:len(path)-1]
|
||||
} else {
|
||||
req.URL.Path = path + "/"
|
||||
}
|
||||
debugPrint("redirecting request %d: %s --> %s", code, path, req.URL.String())
|
||||
http.Redirect(c.Writer, req, req.URL.String(), code)
|
||||
c.writermem.WriteHeaderNow()
|
||||
}
|
||||
|
||||
func redirectFixedPath(c *Context, root *node, trailingSlash bool) bool {
|
||||
req := c.Request
|
||||
path := req.URL.Path
|
||||
|
||||
fixedPath, found := root.findCaseInsensitivePath(
|
||||
cleanPath(path),
|
||||
trailingSlash,
|
||||
)
|
||||
if found {
|
||||
code := 301 // Permanent redirect, request with GET method
|
||||
if req.Method != "GET" {
|
||||
code = 307
|
||||
}
|
||||
req.URL.Path = string(fixedPath)
|
||||
debugPrint("redirecting request %d: %s --> %s", code, path, req.URL.String())
|
||||
http.Redirect(c.Writer, req, req.URL.String(), code)
|
||||
c.writermem.WriteHeaderNow()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
17
vendor/github.com/gin-gonic/gin/ginS/README.md
generated
vendored
Normal file
17
vendor/github.com/gin-gonic/gin/ginS/README.md
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# Gin Default Server
|
||||
|
||||
This is API experiment for Gin.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/ginS"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ginS.GET("/", func(c *gin.Context) { c.String(200, "Hello World") })
|
||||
ginS.Run()
|
||||
}
|
||||
```
|
||||
140
vendor/github.com/gin-gonic/gin/ginS/gins.go
generated
vendored
Normal file
140
vendor/github.com/gin-gonic/gin/ginS/gins.go
generated
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ginS
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
. "github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var once sync.Once
|
||||
var internalEngine *Engine
|
||||
|
||||
func engine() *Engine {
|
||||
once.Do(func() {
|
||||
internalEngine = Default()
|
||||
})
|
||||
return internalEngine
|
||||
}
|
||||
|
||||
func LoadHTMLGlob(pattern string) {
|
||||
engine().LoadHTMLGlob(pattern)
|
||||
}
|
||||
|
||||
func LoadHTMLFiles(files ...string) {
|
||||
engine().LoadHTMLFiles(files...)
|
||||
}
|
||||
|
||||
func SetHTMLTemplate(templ *template.Template) {
|
||||
engine().SetHTMLTemplate(templ)
|
||||
}
|
||||
|
||||
// NoRoute adds handlers for NoRoute. It return a 404 code by default.
|
||||
func NoRoute(handlers ...HandlerFunc) {
|
||||
engine().NoRoute(handlers...)
|
||||
}
|
||||
|
||||
// NoMethod sets the handlers called when... TODO
|
||||
func NoMethod(handlers ...HandlerFunc) {
|
||||
engine().NoMethod(handlers...)
|
||||
}
|
||||
|
||||
// Group creates a new router group. You should add all the routes that have common middlwares or the same path prefix.
|
||||
// For example, all the routes that use a common middlware for authorization could be grouped.
|
||||
func Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {
|
||||
return engine().Group(relativePath, handlers...)
|
||||
}
|
||||
|
||||
func Handle(httpMethod, relativePath string, handlers ...HandlerFunc) IRoutes {
|
||||
return engine().Handle(httpMethod, relativePath, handlers...)
|
||||
}
|
||||
|
||||
// POST is a shortcut for router.Handle("POST", path, handle)
|
||||
func POST(relativePath string, handlers ...HandlerFunc) IRoutes {
|
||||
return engine().POST(relativePath, handlers...)
|
||||
}
|
||||
|
||||
// GET is a shortcut for router.Handle("GET", path, handle)
|
||||
func GET(relativePath string, handlers ...HandlerFunc) IRoutes {
|
||||
return engine().GET(relativePath, handlers...)
|
||||
}
|
||||
|
||||
// DELETE is a shortcut for router.Handle("DELETE", path, handle)
|
||||
func DELETE(relativePath string, handlers ...HandlerFunc) IRoutes {
|
||||
return engine().DELETE(relativePath, handlers...)
|
||||
}
|
||||
|
||||
// PATCH is a shortcut for router.Handle("PATCH", path, handle)
|
||||
func PATCH(relativePath string, handlers ...HandlerFunc) IRoutes {
|
||||
return engine().PATCH(relativePath, handlers...)
|
||||
}
|
||||
|
||||
// PUT is a shortcut for router.Handle("PUT", path, handle)
|
||||
func PUT(relativePath string, handlers ...HandlerFunc) IRoutes {
|
||||
return engine().PUT(relativePath, handlers...)
|
||||
}
|
||||
|
||||
// OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle)
|
||||
func OPTIONS(relativePath string, handlers ...HandlerFunc) IRoutes {
|
||||
return engine().OPTIONS(relativePath, handlers...)
|
||||
}
|
||||
|
||||
// HEAD is a shortcut for router.Handle("HEAD", path, handle)
|
||||
func HEAD(relativePath string, handlers ...HandlerFunc) IRoutes {
|
||||
return engine().HEAD(relativePath, handlers...)
|
||||
}
|
||||
|
||||
func Any(relativePath string, handlers ...HandlerFunc) IRoutes {
|
||||
return engine().Any(relativePath, handlers...)
|
||||
}
|
||||
|
||||
func StaticFile(relativePath, filepath string) IRoutes {
|
||||
return engine().StaticFile(relativePath, filepath)
|
||||
}
|
||||
|
||||
// Static serves files from the given file system root.
|
||||
// Internally a http.FileServer is used, therefore http.NotFound is used instead
|
||||
// of the Router's NotFound handler.
|
||||
// To use the operating system's file system implementation,
|
||||
// use :
|
||||
// router.Static("/static", "/var/www")
|
||||
func Static(relativePath, root string) IRoutes {
|
||||
return engine().Static(relativePath, root)
|
||||
}
|
||||
|
||||
func StaticFS(relativePath string, fs http.FileSystem) IRoutes {
|
||||
return engine().StaticFS(relativePath, fs)
|
||||
}
|
||||
|
||||
// Use attachs a global middleware to the router. ie. the middlewares attached though Use() will be
|
||||
// included in the handlers chain for every single request. Even 404, 405, static files...
|
||||
// For example, this is the right place for a logger or error management middleware.
|
||||
func Use(middlewares ...HandlerFunc) IRoutes {
|
||||
return engine().Use(middlewares...)
|
||||
}
|
||||
|
||||
// Run : The router is attached to a http.Server and starts listening and serving HTTP requests.
|
||||
// It is a shortcut for http.ListenAndServe(addr, router)
|
||||
// Note: this method will block the calling goroutine undefinitelly unless an error happens.
|
||||
func Run(addr ...string) (err error) {
|
||||
return engine().Run(addr...)
|
||||
}
|
||||
|
||||
// RunTLS : The router is attached to a http.Server and starts listening and serving HTTPS requests.
|
||||
// It is a shortcut for http.ListenAndServeTLS(addr, certFile, keyFile, router)
|
||||
// Note: this method will block the calling goroutine undefinitelly unless an error happens.
|
||||
func RunTLS(addr string, certFile string, keyFile string) (err error) {
|
||||
return engine().RunTLS(addr, certFile, keyFile)
|
||||
}
|
||||
|
||||
// RunUnix : The router is attached to a http.Server and starts listening and serving HTTP requests
|
||||
// through the specified unix socket (ie. a file)
|
||||
// Note: this method will block the calling goroutine undefinitelly unless an error happens.
|
||||
func RunUnix(file string) (err error) {
|
||||
return engine().RunUnix(file)
|
||||
}
|
||||
135
vendor/github.com/gin-gonic/gin/gin_integration_test.go
generated
vendored
Normal file
135
vendor/github.com/gin-gonic/gin/gin_integration_test.go
generated
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
// Copyright 2017 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gin
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func testRequest(t *testing.T, url string) {
|
||||
resp, err := http.Get(url)
|
||||
assert.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, ioerr := ioutil.ReadAll(resp.Body)
|
||||
assert.NoError(t, ioerr)
|
||||
assert.Equal(t, "it worked", string(body), "resp body should match")
|
||||
assert.Equal(t, "200 OK", resp.Status, "should get a 200")
|
||||
}
|
||||
|
||||
func TestRunEmpty(t *testing.T) {
|
||||
os.Setenv("PORT", "")
|
||||
router := New()
|
||||
go func() {
|
||||
router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
|
||||
assert.NoError(t, router.Run())
|
||||
}()
|
||||
// have to wait for the goroutine to start and run the server
|
||||
// otherwise the main thread will complete
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
|
||||
assert.Error(t, router.Run(":8080"))
|
||||
testRequest(t, "http://localhost:8080/example")
|
||||
}
|
||||
|
||||
func TestRunEmptyWithEnv(t *testing.T) {
|
||||
os.Setenv("PORT", "3123")
|
||||
router := New()
|
||||
go func() {
|
||||
router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
|
||||
assert.NoError(t, router.Run())
|
||||
}()
|
||||
// have to wait for the goroutine to start and run the server
|
||||
// otherwise the main thread will complete
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
|
||||
assert.Error(t, router.Run(":3123"))
|
||||
testRequest(t, "http://localhost:3123/example")
|
||||
}
|
||||
|
||||
func TestRunTooMuchParams(t *testing.T) {
|
||||
router := New()
|
||||
assert.Panics(t, func() {
|
||||
router.Run("2", "2")
|
||||
})
|
||||
}
|
||||
|
||||
func TestRunWithPort(t *testing.T) {
|
||||
router := New()
|
||||
go func() {
|
||||
router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
|
||||
assert.NoError(t, router.Run(":5150"))
|
||||
}()
|
||||
// have to wait for the goroutine to start and run the server
|
||||
// otherwise the main thread will complete
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
|
||||
assert.Error(t, router.Run(":5150"))
|
||||
testRequest(t, "http://localhost:5150/example")
|
||||
}
|
||||
|
||||
func TestUnixSocket(t *testing.T) {
|
||||
router := New()
|
||||
|
||||
go func() {
|
||||
router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
|
||||
assert.NoError(t, router.RunUnix("/tmp/unix_unit_test"))
|
||||
}()
|
||||
// have to wait for the goroutine to start and run the server
|
||||
// otherwise the main thread will complete
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
|
||||
c, err := net.Dial("unix", "/tmp/unix_unit_test")
|
||||
assert.NoError(t, err)
|
||||
|
||||
fmt.Fprintf(c, "GET /example HTTP/1.0\r\n\r\n")
|
||||
scanner := bufio.NewScanner(c)
|
||||
var response string
|
||||
for scanner.Scan() {
|
||||
response += scanner.Text()
|
||||
}
|
||||
assert.Contains(t, response, "HTTP/1.0 200", "should get a 200")
|
||||
assert.Contains(t, response, "it worked", "resp body should match")
|
||||
}
|
||||
|
||||
func TestBadUnixSocket(t *testing.T) {
|
||||
router := New()
|
||||
assert.Error(t, router.RunUnix("#/tmp/unix_unit_test"))
|
||||
}
|
||||
|
||||
func TestWithHttptestWithAutoSelectedPort(t *testing.T) {
|
||||
router := New()
|
||||
router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
|
||||
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
testRequest(t, ts.URL+"/example")
|
||||
}
|
||||
|
||||
// func TestWithHttptestWithSpecifiedPort(t *testing.T) {
|
||||
// router := New()
|
||||
// router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
|
||||
|
||||
// l, _ := net.Listen("tcp", ":8033")
|
||||
// ts := httptest.Server{
|
||||
// Listener: l,
|
||||
// Config: &http.Server{Handler: router},
|
||||
// }
|
||||
// ts.Start()
|
||||
// defer ts.Close()
|
||||
|
||||
// testRequest(t, "http://localhost:8033/example")
|
||||
// }
|
||||
505
vendor/github.com/gin-gonic/gin/gin_test.go
generated
vendored
505
vendor/github.com/gin-gonic/gin/gin_test.go
generated
vendored
@@ -5,202 +5,361 @@
|
||||
package gin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func formatAsDate(t time.Time) string {
|
||||
year, month, day := t.Date()
|
||||
return fmt.Sprintf("%d/%02d/%02d", year, month, day)
|
||||
}
|
||||
|
||||
func setupHTMLFiles(t *testing.T) func() {
|
||||
go func() {
|
||||
SetMode(TestMode)
|
||||
router := New()
|
||||
router.Delims("{[{", "}]}")
|
||||
router.SetFuncMap(template.FuncMap{
|
||||
"formatAsDate": formatAsDate,
|
||||
})
|
||||
router.LoadHTMLFiles("./fixtures/basic/hello.tmpl", "./fixtures/basic/raw.tmpl")
|
||||
router.GET("/test", func(c *Context) {
|
||||
c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"})
|
||||
})
|
||||
router.GET("/raw", func(c *Context) {
|
||||
c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{
|
||||
"now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC),
|
||||
})
|
||||
})
|
||||
router.Run(":8888")
|
||||
}()
|
||||
t.Log("waiting 1 second for server startup")
|
||||
time.Sleep(1 * time.Second)
|
||||
return func() {}
|
||||
}
|
||||
|
||||
func setupHTMLGlob(t *testing.T) func() {
|
||||
go func() {
|
||||
SetMode(DebugMode)
|
||||
router := New()
|
||||
router.Delims("{[{", "}]}")
|
||||
router.SetFuncMap(template.FuncMap{
|
||||
"formatAsDate": formatAsDate,
|
||||
})
|
||||
router.LoadHTMLGlob("./fixtures/basic/*")
|
||||
router.GET("/test", func(c *Context) {
|
||||
c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"})
|
||||
})
|
||||
router.GET("/raw", func(c *Context) {
|
||||
c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{
|
||||
"now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC),
|
||||
})
|
||||
})
|
||||
router.Run(":8888")
|
||||
}()
|
||||
t.Log("waiting 1 second for server startup")
|
||||
time.Sleep(1 * time.Second)
|
||||
return func() {}
|
||||
}
|
||||
|
||||
//TODO
|
||||
func TestLoadHTMLGlob(t *testing.T) {
|
||||
td := setupHTMLGlob(t)
|
||||
res, err := http.Get("http://127.0.0.1:8888/test")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
resp, _ := ioutil.ReadAll(res.Body)
|
||||
assert.Equal(t, "<h1>Hello world</h1>", string(resp[:]))
|
||||
|
||||
td()
|
||||
}
|
||||
|
||||
func TestLoadHTMLGlobFromFuncMap(t *testing.T) {
|
||||
time.Now()
|
||||
td := setupHTMLGlob(t)
|
||||
res, err := http.Get("http://127.0.0.1:8888/raw")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
resp, _ := ioutil.ReadAll(res.Body)
|
||||
assert.Equal(t, "Date: 2017/07/01\n", string(resp[:]))
|
||||
|
||||
td()
|
||||
}
|
||||
|
||||
// func (engine *Engine) LoadHTMLFiles(files ...string) {
|
||||
// func (engine *Engine) RunTLS(addr string, cert string, key string) error {
|
||||
|
||||
func init() {
|
||||
SetMode(TestMode)
|
||||
}
|
||||
|
||||
func PerformRequest(r http.Handler, method, path string) *httptest.ResponseRecorder {
|
||||
req, _ := http.NewRequest(method, path, nil)
|
||||
w := httptest.NewRecorder()
|
||||
r.ServeHTTP(w, req)
|
||||
return w
|
||||
func TestCreateEngine(t *testing.T) {
|
||||
router := New()
|
||||
assert.Equal(t, "/", router.basePath)
|
||||
assert.Equal(t, router.engine, router)
|
||||
assert.Empty(t, router.Handlers)
|
||||
}
|
||||
|
||||
// TestSingleRouteOK tests that POST route is correctly invoked.
|
||||
func testRouteOK(method string, t *testing.T) {
|
||||
// SETUP
|
||||
passed := false
|
||||
r := New()
|
||||
r.Handle(method, "/test", []HandlerFunc{func(c *Context) {
|
||||
passed = true
|
||||
}})
|
||||
// func TestLoadHTMLDebugMode(t *testing.T) {
|
||||
// router := New()
|
||||
// SetMode(DebugMode)
|
||||
// router.LoadHTMLGlob("*.testtmpl")
|
||||
// r := router.HTMLRender.(render.HTMLDebug)
|
||||
// assert.Empty(t, r.Files)
|
||||
// assert.Equal(t, r.Glob, "*.testtmpl")
|
||||
//
|
||||
// router.LoadHTMLFiles("index.html.testtmpl", "login.html.testtmpl")
|
||||
// r = router.HTMLRender.(render.HTMLDebug)
|
||||
// assert.Empty(t, r.Glob)
|
||||
// assert.Equal(t, r.Files, []string{"index.html", "login.html"})
|
||||
// SetMode(TestMode)
|
||||
// }
|
||||
|
||||
// RUN
|
||||
w := PerformRequest(r, method, "/test")
|
||||
|
||||
// TEST
|
||||
if passed == false {
|
||||
t.Errorf(method + " route handler was not invoked.")
|
||||
}
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Status code should be %v, was %d", http.StatusOK, w.Code)
|
||||
}
|
||||
}
|
||||
func TestRouterGroupRouteOK(t *testing.T) {
|
||||
testRouteOK("POST", t)
|
||||
testRouteOK("DELETE", t)
|
||||
testRouteOK("PATCH", t)
|
||||
testRouteOK("PUT", t)
|
||||
testRouteOK("OPTIONS", t)
|
||||
testRouteOK("HEAD", t)
|
||||
}
|
||||
|
||||
// TestSingleRouteOK tests that POST route is correctly invoked.
|
||||
func testRouteNotOK(method string, t *testing.T) {
|
||||
// SETUP
|
||||
passed := false
|
||||
r := New()
|
||||
r.Handle(method, "/test_2", []HandlerFunc{func(c *Context) {
|
||||
passed = true
|
||||
}})
|
||||
|
||||
// RUN
|
||||
w := PerformRequest(r, method, "/test")
|
||||
|
||||
// TEST
|
||||
if passed == true {
|
||||
t.Errorf(method + " route handler was invoked, when it should not")
|
||||
}
|
||||
if w.Code != http.StatusNotFound {
|
||||
// If this fails, it's because httprouter needs to be updated to at least f78f58a0db
|
||||
t.Errorf("Status code should be %v, was %d. Location: %s", http.StatusNotFound, w.Code, w.HeaderMap.Get("Location"))
|
||||
}
|
||||
}
|
||||
|
||||
// TestSingleRouteOK tests that POST route is correctly invoked.
|
||||
func TestRouteNotOK(t *testing.T) {
|
||||
testRouteNotOK("POST", t)
|
||||
testRouteNotOK("DELETE", t)
|
||||
testRouteNotOK("PATCH", t)
|
||||
testRouteNotOK("PUT", t)
|
||||
testRouteNotOK("OPTIONS", t)
|
||||
testRouteNotOK("HEAD", t)
|
||||
}
|
||||
|
||||
// TestSingleRouteOK tests that POST route is correctly invoked.
|
||||
func testRouteNotOK2(method string, t *testing.T) {
|
||||
// SETUP
|
||||
passed := false
|
||||
r := New()
|
||||
var methodRoute string
|
||||
if method == "POST" {
|
||||
methodRoute = "GET"
|
||||
} else {
|
||||
methodRoute = "POST"
|
||||
}
|
||||
r.Handle(methodRoute, "/test", []HandlerFunc{func(c *Context) {
|
||||
passed = true
|
||||
}})
|
||||
|
||||
// RUN
|
||||
w := PerformRequest(r, method, "/test")
|
||||
|
||||
// TEST
|
||||
if passed == true {
|
||||
t.Errorf(method + " route handler was invoked, when it should not")
|
||||
}
|
||||
if w.Code != http.StatusMethodNotAllowed {
|
||||
t.Errorf("Status code should be %v, was %d. Location: %s", http.StatusMethodNotAllowed, w.Code, w.HeaderMap.Get("Location"))
|
||||
}
|
||||
}
|
||||
|
||||
// TestSingleRouteOK tests that POST route is correctly invoked.
|
||||
func TestRouteNotOK2(t *testing.T) {
|
||||
testRouteNotOK2("POST", t)
|
||||
testRouteNotOK2("DELETE", t)
|
||||
testRouteNotOK2("PATCH", t)
|
||||
testRouteNotOK2("PUT", t)
|
||||
testRouteNotOK2("OPTIONS", t)
|
||||
testRouteNotOK2("HEAD", t)
|
||||
}
|
||||
|
||||
// TestHandleStaticFile - ensure the static file handles properly
|
||||
func TestHandleStaticFile(t *testing.T) {
|
||||
// SETUP file
|
||||
testRoot, _ := os.Getwd()
|
||||
f, err := ioutil.TempFile(testRoot, "")
|
||||
func TestLoadHTMLFiles(t *testing.T) {
|
||||
td := setupHTMLFiles(t)
|
||||
res, err := http.Get("http://127.0.0.1:8888/test")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
fmt.Println(err)
|
||||
}
|
||||
defer os.Remove(f.Name())
|
||||
filePath := path.Join("/", path.Base(f.Name()))
|
||||
f.WriteString("Gin Web Framework")
|
||||
f.Close()
|
||||
|
||||
// SETUP gin
|
||||
r := New()
|
||||
r.Static("./", testRoot)
|
||||
resp, _ := ioutil.ReadAll(res.Body)
|
||||
assert.Equal(t, "<h1>Hello world</h1>", string(resp[:]))
|
||||
td()
|
||||
}
|
||||
|
||||
// RUN
|
||||
w := PerformRequest(r, "GET", filePath)
|
||||
|
||||
// TEST
|
||||
if w.Code != 200 {
|
||||
t.Errorf("Response code should be 200, was: %d", w.Code)
|
||||
func TestLoadHTMLFilesFuncMap(t *testing.T) {
|
||||
time.Now()
|
||||
td := setupHTMLFiles(t)
|
||||
res, err := http.Get("http://127.0.0.1:8888/raw")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
if w.Body.String() != "Gin Web Framework" {
|
||||
t.Errorf("Response should be test, was: %s", w.Body.String())
|
||||
}
|
||||
if w.HeaderMap.Get("Content-Type") != "text/plain; charset=utf-8" {
|
||||
t.Errorf("Content-Type should be text/plain, was %s", w.HeaderMap.Get("Content-Type"))
|
||||
|
||||
resp, _ := ioutil.ReadAll(res.Body)
|
||||
assert.Equal(t, "Date: 2017/07/01\n", string(resp[:]))
|
||||
|
||||
td()
|
||||
}
|
||||
|
||||
func TestLoadHTMLReleaseMode(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestAddRoute(t *testing.T) {
|
||||
router := New()
|
||||
router.addRoute("GET", "/", HandlersChain{func(_ *Context) {}})
|
||||
|
||||
assert.Len(t, router.trees, 1)
|
||||
assert.NotNil(t, router.trees.get("GET"))
|
||||
assert.Nil(t, router.trees.get("POST"))
|
||||
|
||||
router.addRoute("POST", "/", HandlersChain{func(_ *Context) {}})
|
||||
|
||||
assert.Len(t, router.trees, 2)
|
||||
assert.NotNil(t, router.trees.get("GET"))
|
||||
assert.NotNil(t, router.trees.get("POST"))
|
||||
|
||||
router.addRoute("POST", "/post", HandlersChain{func(_ *Context) {}})
|
||||
assert.Len(t, router.trees, 2)
|
||||
}
|
||||
|
||||
func TestAddRouteFails(t *testing.T) {
|
||||
router := New()
|
||||
assert.Panics(t, func() { router.addRoute("", "/", HandlersChain{func(_ *Context) {}}) })
|
||||
assert.Panics(t, func() { router.addRoute("GET", "a", HandlersChain{func(_ *Context) {}}) })
|
||||
assert.Panics(t, func() { router.addRoute("GET", "/", HandlersChain{}) })
|
||||
|
||||
router.addRoute("POST", "/post", HandlersChain{func(_ *Context) {}})
|
||||
assert.Panics(t, func() {
|
||||
router.addRoute("POST", "/post", HandlersChain{func(_ *Context) {}})
|
||||
})
|
||||
}
|
||||
|
||||
func TestCreateDefaultRouter(t *testing.T) {
|
||||
router := Default()
|
||||
assert.Len(t, router.Handlers, 2)
|
||||
}
|
||||
|
||||
func TestNoRouteWithoutGlobalHandlers(t *testing.T) {
|
||||
var middleware0 HandlerFunc = func(c *Context) {}
|
||||
var middleware1 HandlerFunc = func(c *Context) {}
|
||||
|
||||
router := New()
|
||||
|
||||
router.NoRoute(middleware0)
|
||||
assert.Nil(t, router.Handlers)
|
||||
assert.Len(t, router.noRoute, 1)
|
||||
assert.Len(t, router.allNoRoute, 1)
|
||||
compareFunc(t, router.noRoute[0], middleware0)
|
||||
compareFunc(t, router.allNoRoute[0], middleware0)
|
||||
|
||||
router.NoRoute(middleware1, middleware0)
|
||||
assert.Len(t, router.noRoute, 2)
|
||||
assert.Len(t, router.allNoRoute, 2)
|
||||
compareFunc(t, router.noRoute[0], middleware1)
|
||||
compareFunc(t, router.allNoRoute[0], middleware1)
|
||||
compareFunc(t, router.noRoute[1], middleware0)
|
||||
compareFunc(t, router.allNoRoute[1], middleware0)
|
||||
}
|
||||
|
||||
func TestNoRouteWithGlobalHandlers(t *testing.T) {
|
||||
var middleware0 HandlerFunc = func(c *Context) {}
|
||||
var middleware1 HandlerFunc = func(c *Context) {}
|
||||
var middleware2 HandlerFunc = func(c *Context) {}
|
||||
|
||||
router := New()
|
||||
router.Use(middleware2)
|
||||
|
||||
router.NoRoute(middleware0)
|
||||
assert.Len(t, router.allNoRoute, 2)
|
||||
assert.Len(t, router.Handlers, 1)
|
||||
assert.Len(t, router.noRoute, 1)
|
||||
|
||||
compareFunc(t, router.Handlers[0], middleware2)
|
||||
compareFunc(t, router.noRoute[0], middleware0)
|
||||
compareFunc(t, router.allNoRoute[0], middleware2)
|
||||
compareFunc(t, router.allNoRoute[1], middleware0)
|
||||
|
||||
router.Use(middleware1)
|
||||
assert.Len(t, router.allNoRoute, 3)
|
||||
assert.Len(t, router.Handlers, 2)
|
||||
assert.Len(t, router.noRoute, 1)
|
||||
|
||||
compareFunc(t, router.Handlers[0], middleware2)
|
||||
compareFunc(t, router.Handlers[1], middleware1)
|
||||
compareFunc(t, router.noRoute[0], middleware0)
|
||||
compareFunc(t, router.allNoRoute[0], middleware2)
|
||||
compareFunc(t, router.allNoRoute[1], middleware1)
|
||||
compareFunc(t, router.allNoRoute[2], middleware0)
|
||||
}
|
||||
|
||||
func TestNoMethodWithoutGlobalHandlers(t *testing.T) {
|
||||
var middleware0 HandlerFunc = func(c *Context) {}
|
||||
var middleware1 HandlerFunc = func(c *Context) {}
|
||||
|
||||
router := New()
|
||||
|
||||
router.NoMethod(middleware0)
|
||||
assert.Empty(t, router.Handlers)
|
||||
assert.Len(t, router.noMethod, 1)
|
||||
assert.Len(t, router.allNoMethod, 1)
|
||||
compareFunc(t, router.noMethod[0], middleware0)
|
||||
compareFunc(t, router.allNoMethod[0], middleware0)
|
||||
|
||||
router.NoMethod(middleware1, middleware0)
|
||||
assert.Len(t, router.noMethod, 2)
|
||||
assert.Len(t, router.allNoMethod, 2)
|
||||
compareFunc(t, router.noMethod[0], middleware1)
|
||||
compareFunc(t, router.allNoMethod[0], middleware1)
|
||||
compareFunc(t, router.noMethod[1], middleware0)
|
||||
compareFunc(t, router.allNoMethod[1], middleware0)
|
||||
}
|
||||
|
||||
func TestRebuild404Handlers(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestNoMethodWithGlobalHandlers(t *testing.T) {
|
||||
var middleware0 HandlerFunc = func(c *Context) {}
|
||||
var middleware1 HandlerFunc = func(c *Context) {}
|
||||
var middleware2 HandlerFunc = func(c *Context) {}
|
||||
|
||||
router := New()
|
||||
router.Use(middleware2)
|
||||
|
||||
router.NoMethod(middleware0)
|
||||
assert.Len(t, router.allNoMethod, 2)
|
||||
assert.Len(t, router.Handlers, 1)
|
||||
assert.Len(t, router.noMethod, 1)
|
||||
|
||||
compareFunc(t, router.Handlers[0], middleware2)
|
||||
compareFunc(t, router.noMethod[0], middleware0)
|
||||
compareFunc(t, router.allNoMethod[0], middleware2)
|
||||
compareFunc(t, router.allNoMethod[1], middleware0)
|
||||
|
||||
router.Use(middleware1)
|
||||
assert.Len(t, router.allNoMethod, 3)
|
||||
assert.Len(t, router.Handlers, 2)
|
||||
assert.Len(t, router.noMethod, 1)
|
||||
|
||||
compareFunc(t, router.Handlers[0], middleware2)
|
||||
compareFunc(t, router.Handlers[1], middleware1)
|
||||
compareFunc(t, router.noMethod[0], middleware0)
|
||||
compareFunc(t, router.allNoMethod[0], middleware2)
|
||||
compareFunc(t, router.allNoMethod[1], middleware1)
|
||||
compareFunc(t, router.allNoMethod[2], middleware0)
|
||||
}
|
||||
|
||||
func compareFunc(t *testing.T, a, b interface{}) {
|
||||
sf1 := reflect.ValueOf(a)
|
||||
sf2 := reflect.ValueOf(b)
|
||||
if sf1.Pointer() != sf2.Pointer() {
|
||||
t.Error("different functions")
|
||||
}
|
||||
}
|
||||
|
||||
// TestHandleStaticDir - ensure the root/sub dir handles properly
|
||||
func TestHandleStaticDir(t *testing.T) {
|
||||
// SETUP
|
||||
r := New()
|
||||
r.Static("/", "./")
|
||||
func TestListOfRoutes(t *testing.T) {
|
||||
router := New()
|
||||
router.GET("/favicon.ico", handlerTest1)
|
||||
router.GET("/", handlerTest1)
|
||||
group := router.Group("/users")
|
||||
{
|
||||
group.GET("/", handlerTest2)
|
||||
group.GET("/:id", handlerTest1)
|
||||
group.POST("/:id", handlerTest2)
|
||||
}
|
||||
router.Static("/static", ".")
|
||||
|
||||
// RUN
|
||||
w := PerformRequest(r, "GET", "/")
|
||||
list := router.Routes()
|
||||
|
||||
// TEST
|
||||
bodyAsString := w.Body.String()
|
||||
if w.Code != 200 {
|
||||
t.Errorf("Response code should be 200, was: %d", w.Code)
|
||||
}
|
||||
if len(bodyAsString) == 0 {
|
||||
t.Errorf("Got empty body instead of file tree")
|
||||
}
|
||||
if !strings.Contains(bodyAsString, "gin.go") {
|
||||
t.Errorf("Can't find:`gin.go` in file tree: %s", bodyAsString)
|
||||
}
|
||||
if w.HeaderMap.Get("Content-Type") != "text/html; charset=utf-8" {
|
||||
t.Errorf("Content-Type should be text/plain, was %s", w.HeaderMap.Get("Content-Type"))
|
||||
}
|
||||
assert.Len(t, list, 7)
|
||||
assertRoutePresent(t, list, RouteInfo{
|
||||
Method: "GET",
|
||||
Path: "/favicon.ico",
|
||||
Handler: "^(.*/vendor/)?github.com/gin-gonic/gin.handlerTest1$",
|
||||
})
|
||||
assertRoutePresent(t, list, RouteInfo{
|
||||
Method: "GET",
|
||||
Path: "/",
|
||||
Handler: "^(.*/vendor/)?github.com/gin-gonic/gin.handlerTest1$",
|
||||
})
|
||||
assertRoutePresent(t, list, RouteInfo{
|
||||
Method: "GET",
|
||||
Path: "/users/",
|
||||
Handler: "^(.*/vendor/)?github.com/gin-gonic/gin.handlerTest2$",
|
||||
})
|
||||
assertRoutePresent(t, list, RouteInfo{
|
||||
Method: "GET",
|
||||
Path: "/users/:id",
|
||||
Handler: "^(.*/vendor/)?github.com/gin-gonic/gin.handlerTest1$",
|
||||
})
|
||||
assertRoutePresent(t, list, RouteInfo{
|
||||
Method: "POST",
|
||||
Path: "/users/:id",
|
||||
Handler: "^(.*/vendor/)?github.com/gin-gonic/gin.handlerTest2$",
|
||||
})
|
||||
}
|
||||
|
||||
// TestHandleHeadToDir - ensure the root/sub dir handles properly
|
||||
func TestHandleHeadToDir(t *testing.T) {
|
||||
// SETUP
|
||||
r := New()
|
||||
r.Static("/", "./")
|
||||
|
||||
// RUN
|
||||
w := PerformRequest(r, "HEAD", "/")
|
||||
|
||||
// TEST
|
||||
bodyAsString := w.Body.String()
|
||||
if w.Code != 200 {
|
||||
t.Errorf("Response code should be Ok, was: %s", w.Code)
|
||||
}
|
||||
if len(bodyAsString) == 0 {
|
||||
t.Errorf("Got empty body instead of file tree")
|
||||
}
|
||||
if !strings.Contains(bodyAsString, "gin.go") {
|
||||
t.Errorf("Can't find:`gin.go` in file tree: %s", bodyAsString)
|
||||
}
|
||||
if w.HeaderMap.Get("Content-Type") != "text/html; charset=utf-8" {
|
||||
t.Errorf("Content-Type should be text/plain, was %s", w.HeaderMap.Get("Content-Type"))
|
||||
func assertRoutePresent(t *testing.T, gotRoutes RoutesInfo, wantRoute RouteInfo) {
|
||||
for _, gotRoute := range gotRoutes {
|
||||
if gotRoute.Path == wantRoute.Path && gotRoute.Method == wantRoute.Method {
|
||||
assert.Regexp(t, wantRoute.Handler, gotRoute.Handler)
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Errorf("route not found: %v", wantRoute)
|
||||
}
|
||||
|
||||
func handlerTest1(c *Context) {}
|
||||
func handlerTest2(c *Context) {}
|
||||
|
||||
390
vendor/github.com/gin-gonic/gin/githubapi_test.go
generated
vendored
Normal file
390
vendor/github.com/gin-gonic/gin/githubapi_test.go
generated
vendored
Normal file
@@ -0,0 +1,390 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type route struct {
|
||||
method string
|
||||
path string
|
||||
}
|
||||
|
||||
// http://developer.github.com/v3/
|
||||
var githubAPI = []route{
|
||||
// OAuth Authorizations
|
||||
{"GET", "/authorizations"},
|
||||
{"GET", "/authorizations/:id"},
|
||||
{"POST", "/authorizations"},
|
||||
//{"PUT", "/authorizations/clients/:client_id"},
|
||||
//{"PATCH", "/authorizations/:id"},
|
||||
{"DELETE", "/authorizations/:id"},
|
||||
{"GET", "/applications/:client_id/tokens/:access_token"},
|
||||
{"DELETE", "/applications/:client_id/tokens"},
|
||||
{"DELETE", "/applications/:client_id/tokens/:access_token"},
|
||||
|
||||
// Activity
|
||||
{"GET", "/events"},
|
||||
{"GET", "/repos/:owner/:repo/events"},
|
||||
{"GET", "/networks/:owner/:repo/events"},
|
||||
{"GET", "/orgs/:org/events"},
|
||||
{"GET", "/users/:user/received_events"},
|
||||
{"GET", "/users/:user/received_events/public"},
|
||||
{"GET", "/users/:user/events"},
|
||||
{"GET", "/users/:user/events/public"},
|
||||
{"GET", "/users/:user/events/orgs/:org"},
|
||||
{"GET", "/feeds"},
|
||||
{"GET", "/notifications"},
|
||||
{"GET", "/repos/:owner/:repo/notifications"},
|
||||
{"PUT", "/notifications"},
|
||||
{"PUT", "/repos/:owner/:repo/notifications"},
|
||||
{"GET", "/notifications/threads/:id"},
|
||||
//{"PATCH", "/notifications/threads/:id"},
|
||||
{"GET", "/notifications/threads/:id/subscription"},
|
||||
{"PUT", "/notifications/threads/:id/subscription"},
|
||||
{"DELETE", "/notifications/threads/:id/subscription"},
|
||||
{"GET", "/repos/:owner/:repo/stargazers"},
|
||||
{"GET", "/users/:user/starred"},
|
||||
{"GET", "/user/starred"},
|
||||
{"GET", "/user/starred/:owner/:repo"},
|
||||
{"PUT", "/user/starred/:owner/:repo"},
|
||||
{"DELETE", "/user/starred/:owner/:repo"},
|
||||
{"GET", "/repos/:owner/:repo/subscribers"},
|
||||
{"GET", "/users/:user/subscriptions"},
|
||||
{"GET", "/user/subscriptions"},
|
||||
{"GET", "/repos/:owner/:repo/subscription"},
|
||||
{"PUT", "/repos/:owner/:repo/subscription"},
|
||||
{"DELETE", "/repos/:owner/:repo/subscription"},
|
||||
{"GET", "/user/subscriptions/:owner/:repo"},
|
||||
{"PUT", "/user/subscriptions/:owner/:repo"},
|
||||
{"DELETE", "/user/subscriptions/:owner/:repo"},
|
||||
|
||||
// Gists
|
||||
{"GET", "/users/:user/gists"},
|
||||
{"GET", "/gists"},
|
||||
//{"GET", "/gists/public"},
|
||||
//{"GET", "/gists/starred"},
|
||||
{"GET", "/gists/:id"},
|
||||
{"POST", "/gists"},
|
||||
//{"PATCH", "/gists/:id"},
|
||||
{"PUT", "/gists/:id/star"},
|
||||
{"DELETE", "/gists/:id/star"},
|
||||
{"GET", "/gists/:id/star"},
|
||||
{"POST", "/gists/:id/forks"},
|
||||
{"DELETE", "/gists/:id"},
|
||||
|
||||
// Git Data
|
||||
{"GET", "/repos/:owner/:repo/git/blobs/:sha"},
|
||||
{"POST", "/repos/:owner/:repo/git/blobs"},
|
||||
{"GET", "/repos/:owner/:repo/git/commits/:sha"},
|
||||
{"POST", "/repos/:owner/:repo/git/commits"},
|
||||
//{"GET", "/repos/:owner/:repo/git/refs/*ref"},
|
||||
{"GET", "/repos/:owner/:repo/git/refs"},
|
||||
{"POST", "/repos/:owner/:repo/git/refs"},
|
||||
//{"PATCH", "/repos/:owner/:repo/git/refs/*ref"},
|
||||
//{"DELETE", "/repos/:owner/:repo/git/refs/*ref"},
|
||||
{"GET", "/repos/:owner/:repo/git/tags/:sha"},
|
||||
{"POST", "/repos/:owner/:repo/git/tags"},
|
||||
{"GET", "/repos/:owner/:repo/git/trees/:sha"},
|
||||
{"POST", "/repos/:owner/:repo/git/trees"},
|
||||
|
||||
// Issues
|
||||
{"GET", "/issues"},
|
||||
{"GET", "/user/issues"},
|
||||
{"GET", "/orgs/:org/issues"},
|
||||
{"GET", "/repos/:owner/:repo/issues"},
|
||||
{"GET", "/repos/:owner/:repo/issues/:number"},
|
||||
{"POST", "/repos/:owner/:repo/issues"},
|
||||
//{"PATCH", "/repos/:owner/:repo/issues/:number"},
|
||||
{"GET", "/repos/:owner/:repo/assignees"},
|
||||
{"GET", "/repos/:owner/:repo/assignees/:assignee"},
|
||||
{"GET", "/repos/:owner/:repo/issues/:number/comments"},
|
||||
//{"GET", "/repos/:owner/:repo/issues/comments"},
|
||||
//{"GET", "/repos/:owner/:repo/issues/comments/:id"},
|
||||
{"POST", "/repos/:owner/:repo/issues/:number/comments"},
|
||||
//{"PATCH", "/repos/:owner/:repo/issues/comments/:id"},
|
||||
//{"DELETE", "/repos/:owner/:repo/issues/comments/:id"},
|
||||
{"GET", "/repos/:owner/:repo/issues/:number/events"},
|
||||
//{"GET", "/repos/:owner/:repo/issues/events"},
|
||||
//{"GET", "/repos/:owner/:repo/issues/events/:id"},
|
||||
{"GET", "/repos/:owner/:repo/labels"},
|
||||
{"GET", "/repos/:owner/:repo/labels/:name"},
|
||||
{"POST", "/repos/:owner/:repo/labels"},
|
||||
//{"PATCH", "/repos/:owner/:repo/labels/:name"},
|
||||
{"DELETE", "/repos/:owner/:repo/labels/:name"},
|
||||
{"GET", "/repos/:owner/:repo/issues/:number/labels"},
|
||||
{"POST", "/repos/:owner/:repo/issues/:number/labels"},
|
||||
{"DELETE", "/repos/:owner/:repo/issues/:number/labels/:name"},
|
||||
{"PUT", "/repos/:owner/:repo/issues/:number/labels"},
|
||||
{"DELETE", "/repos/:owner/:repo/issues/:number/labels"},
|
||||
{"GET", "/repos/:owner/:repo/milestones/:number/labels"},
|
||||
{"GET", "/repos/:owner/:repo/milestones"},
|
||||
{"GET", "/repos/:owner/:repo/milestones/:number"},
|
||||
{"POST", "/repos/:owner/:repo/milestones"},
|
||||
//{"PATCH", "/repos/:owner/:repo/milestones/:number"},
|
||||
{"DELETE", "/repos/:owner/:repo/milestones/:number"},
|
||||
|
||||
// Miscellaneous
|
||||
{"GET", "/emojis"},
|
||||
{"GET", "/gitignore/templates"},
|
||||
{"GET", "/gitignore/templates/:name"},
|
||||
{"POST", "/markdown"},
|
||||
{"POST", "/markdown/raw"},
|
||||
{"GET", "/meta"},
|
||||
{"GET", "/rate_limit"},
|
||||
|
||||
// Organizations
|
||||
{"GET", "/users/:user/orgs"},
|
||||
{"GET", "/user/orgs"},
|
||||
{"GET", "/orgs/:org"},
|
||||
//{"PATCH", "/orgs/:org"},
|
||||
{"GET", "/orgs/:org/members"},
|
||||
{"GET", "/orgs/:org/members/:user"},
|
||||
{"DELETE", "/orgs/:org/members/:user"},
|
||||
{"GET", "/orgs/:org/public_members"},
|
||||
{"GET", "/orgs/:org/public_members/:user"},
|
||||
{"PUT", "/orgs/:org/public_members/:user"},
|
||||
{"DELETE", "/orgs/:org/public_members/:user"},
|
||||
{"GET", "/orgs/:org/teams"},
|
||||
{"GET", "/teams/:id"},
|
||||
{"POST", "/orgs/:org/teams"},
|
||||
//{"PATCH", "/teams/:id"},
|
||||
{"DELETE", "/teams/:id"},
|
||||
{"GET", "/teams/:id/members"},
|
||||
{"GET", "/teams/:id/members/:user"},
|
||||
{"PUT", "/teams/:id/members/:user"},
|
||||
{"DELETE", "/teams/:id/members/:user"},
|
||||
{"GET", "/teams/:id/repos"},
|
||||
{"GET", "/teams/:id/repos/:owner/:repo"},
|
||||
{"PUT", "/teams/:id/repos/:owner/:repo"},
|
||||
{"DELETE", "/teams/:id/repos/:owner/:repo"},
|
||||
{"GET", "/user/teams"},
|
||||
|
||||
// Pull Requests
|
||||
{"GET", "/repos/:owner/:repo/pulls"},
|
||||
{"GET", "/repos/:owner/:repo/pulls/:number"},
|
||||
{"POST", "/repos/:owner/:repo/pulls"},
|
||||
//{"PATCH", "/repos/:owner/:repo/pulls/:number"},
|
||||
{"GET", "/repos/:owner/:repo/pulls/:number/commits"},
|
||||
{"GET", "/repos/:owner/:repo/pulls/:number/files"},
|
||||
{"GET", "/repos/:owner/:repo/pulls/:number/merge"},
|
||||
{"PUT", "/repos/:owner/:repo/pulls/:number/merge"},
|
||||
{"GET", "/repos/:owner/:repo/pulls/:number/comments"},
|
||||
//{"GET", "/repos/:owner/:repo/pulls/comments"},
|
||||
//{"GET", "/repos/:owner/:repo/pulls/comments/:number"},
|
||||
{"PUT", "/repos/:owner/:repo/pulls/:number/comments"},
|
||||
//{"PATCH", "/repos/:owner/:repo/pulls/comments/:number"},
|
||||
//{"DELETE", "/repos/:owner/:repo/pulls/comments/:number"},
|
||||
|
||||
// Repositories
|
||||
{"GET", "/user/repos"},
|
||||
{"GET", "/users/:user/repos"},
|
||||
{"GET", "/orgs/:org/repos"},
|
||||
{"GET", "/repositories"},
|
||||
{"POST", "/user/repos"},
|
||||
{"POST", "/orgs/:org/repos"},
|
||||
{"GET", "/repos/:owner/:repo"},
|
||||
//{"PATCH", "/repos/:owner/:repo"},
|
||||
{"GET", "/repos/:owner/:repo/contributors"},
|
||||
{"GET", "/repos/:owner/:repo/languages"},
|
||||
{"GET", "/repos/:owner/:repo/teams"},
|
||||
{"GET", "/repos/:owner/:repo/tags"},
|
||||
{"GET", "/repos/:owner/:repo/branches"},
|
||||
{"GET", "/repos/:owner/:repo/branches/:branch"},
|
||||
{"DELETE", "/repos/:owner/:repo"},
|
||||
{"GET", "/repos/:owner/:repo/collaborators"},
|
||||
{"GET", "/repos/:owner/:repo/collaborators/:user"},
|
||||
{"PUT", "/repos/:owner/:repo/collaborators/:user"},
|
||||
{"DELETE", "/repos/:owner/:repo/collaborators/:user"},
|
||||
{"GET", "/repos/:owner/:repo/comments"},
|
||||
{"GET", "/repos/:owner/:repo/commits/:sha/comments"},
|
||||
{"POST", "/repos/:owner/:repo/commits/:sha/comments"},
|
||||
{"GET", "/repos/:owner/:repo/comments/:id"},
|
||||
//{"PATCH", "/repos/:owner/:repo/comments/:id"},
|
||||
{"DELETE", "/repos/:owner/:repo/comments/:id"},
|
||||
{"GET", "/repos/:owner/:repo/commits"},
|
||||
{"GET", "/repos/:owner/:repo/commits/:sha"},
|
||||
{"GET", "/repos/:owner/:repo/readme"},
|
||||
//{"GET", "/repos/:owner/:repo/contents/*path"},
|
||||
//{"PUT", "/repos/:owner/:repo/contents/*path"},
|
||||
//{"DELETE", "/repos/:owner/:repo/contents/*path"},
|
||||
//{"GET", "/repos/:owner/:repo/:archive_format/:ref"},
|
||||
{"GET", "/repos/:owner/:repo/keys"},
|
||||
{"GET", "/repos/:owner/:repo/keys/:id"},
|
||||
{"POST", "/repos/:owner/:repo/keys"},
|
||||
//{"PATCH", "/repos/:owner/:repo/keys/:id"},
|
||||
{"DELETE", "/repos/:owner/:repo/keys/:id"},
|
||||
{"GET", "/repos/:owner/:repo/downloads"},
|
||||
{"GET", "/repos/:owner/:repo/downloads/:id"},
|
||||
{"DELETE", "/repos/:owner/:repo/downloads/:id"},
|
||||
{"GET", "/repos/:owner/:repo/forks"},
|
||||
{"POST", "/repos/:owner/:repo/forks"},
|
||||
{"GET", "/repos/:owner/:repo/hooks"},
|
||||
{"GET", "/repos/:owner/:repo/hooks/:id"},
|
||||
{"POST", "/repos/:owner/:repo/hooks"},
|
||||
//{"PATCH", "/repos/:owner/:repo/hooks/:id"},
|
||||
{"POST", "/repos/:owner/:repo/hooks/:id/tests"},
|
||||
{"DELETE", "/repos/:owner/:repo/hooks/:id"},
|
||||
{"POST", "/repos/:owner/:repo/merges"},
|
||||
{"GET", "/repos/:owner/:repo/releases"},
|
||||
{"GET", "/repos/:owner/:repo/releases/:id"},
|
||||
{"POST", "/repos/:owner/:repo/releases"},
|
||||
//{"PATCH", "/repos/:owner/:repo/releases/:id"},
|
||||
{"DELETE", "/repos/:owner/:repo/releases/:id"},
|
||||
{"GET", "/repos/:owner/:repo/releases/:id/assets"},
|
||||
{"GET", "/repos/:owner/:repo/stats/contributors"},
|
||||
{"GET", "/repos/:owner/:repo/stats/commit_activity"},
|
||||
{"GET", "/repos/:owner/:repo/stats/code_frequency"},
|
||||
{"GET", "/repos/:owner/:repo/stats/participation"},
|
||||
{"GET", "/repos/:owner/:repo/stats/punch_card"},
|
||||
{"GET", "/repos/:owner/:repo/statuses/:ref"},
|
||||
{"POST", "/repos/:owner/:repo/statuses/:ref"},
|
||||
|
||||
// Search
|
||||
{"GET", "/search/repositories"},
|
||||
{"GET", "/search/code"},
|
||||
{"GET", "/search/issues"},
|
||||
{"GET", "/search/users"},
|
||||
{"GET", "/legacy/issues/search/:owner/:repository/:state/:keyword"},
|
||||
{"GET", "/legacy/repos/search/:keyword"},
|
||||
{"GET", "/legacy/user/search/:keyword"},
|
||||
{"GET", "/legacy/user/email/:email"},
|
||||
|
||||
// Users
|
||||
{"GET", "/users/:user"},
|
||||
{"GET", "/user"},
|
||||
//{"PATCH", "/user"},
|
||||
{"GET", "/users"},
|
||||
{"GET", "/user/emails"},
|
||||
{"POST", "/user/emails"},
|
||||
{"DELETE", "/user/emails"},
|
||||
{"GET", "/users/:user/followers"},
|
||||
{"GET", "/user/followers"},
|
||||
{"GET", "/users/:user/following"},
|
||||
{"GET", "/user/following"},
|
||||
{"GET", "/user/following/:user"},
|
||||
{"GET", "/users/:user/following/:target_user"},
|
||||
{"PUT", "/user/following/:user"},
|
||||
{"DELETE", "/user/following/:user"},
|
||||
{"GET", "/users/:user/keys"},
|
||||
{"GET", "/user/keys"},
|
||||
{"GET", "/user/keys/:id"},
|
||||
{"POST", "/user/keys"},
|
||||
//{"PATCH", "/user/keys/:id"},
|
||||
{"DELETE", "/user/keys/:id"},
|
||||
}
|
||||
|
||||
func githubConfigRouter(router *Engine) {
|
||||
for _, route := range githubAPI {
|
||||
router.Handle(route.method, route.path, func(c *Context) {
|
||||
output := make(map[string]string, len(c.Params)+1)
|
||||
output["status"] = "good"
|
||||
for _, param := range c.Params {
|
||||
output[param.Key] = param.Value
|
||||
}
|
||||
c.JSON(200, output)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGithubAPI(t *testing.T) {
|
||||
DefaultWriter = os.Stdout
|
||||
router := Default()
|
||||
githubConfigRouter(router)
|
||||
|
||||
for _, route := range githubAPI {
|
||||
path, values := exampleFromPath(route.path)
|
||||
w := performRequest(router, route.method, path)
|
||||
|
||||
// TEST
|
||||
assert.Contains(t, w.Body.String(), "\"status\":\"good\"")
|
||||
for _, value := range values {
|
||||
str := fmt.Sprintf("\"%s\":\"%s\"", value.Key, value.Value)
|
||||
assert.Contains(t, w.Body.String(), str)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func exampleFromPath(path string) (string, Params) {
|
||||
output := new(bytes.Buffer)
|
||||
params := make(Params, 0, 6)
|
||||
start := -1
|
||||
for i, c := range path {
|
||||
if c == ':' {
|
||||
start = i + 1
|
||||
}
|
||||
if start >= 0 {
|
||||
if c == '/' {
|
||||
value := fmt.Sprint(rand.Intn(100000))
|
||||
params = append(params, Param{
|
||||
Key: path[start:i],
|
||||
Value: value,
|
||||
})
|
||||
output.WriteString(value)
|
||||
output.WriteRune(c)
|
||||
start = -1
|
||||
}
|
||||
} else {
|
||||
output.WriteRune(c)
|
||||
}
|
||||
}
|
||||
if start >= 0 {
|
||||
value := fmt.Sprint(rand.Intn(100000))
|
||||
params = append(params, Param{
|
||||
Key: path[start:],
|
||||
Value: value,
|
||||
})
|
||||
output.WriteString(value)
|
||||
}
|
||||
|
||||
return output.String(), params
|
||||
}
|
||||
|
||||
func BenchmarkGithub(b *testing.B) {
|
||||
router := New()
|
||||
githubConfigRouter(router)
|
||||
runRequest(b, router, "GET", "/legacy/issues/search/:owner/:repository/:state/:keyword")
|
||||
}
|
||||
|
||||
func BenchmarkParallelGithub(b *testing.B) {
|
||||
DefaultWriter = os.Stdout
|
||||
router := New()
|
||||
githubConfigRouter(router)
|
||||
|
||||
req, _ := http.NewRequest("POST", "/repos/manucorporat/sse/git/blobs", nil)
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
// Each goroutine has its own bytes.Buffer.
|
||||
for pb.Next() {
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkParallelGithubDefault(b *testing.B) {
|
||||
DefaultWriter = os.Stdout
|
||||
router := Default()
|
||||
githubConfigRouter(router)
|
||||
|
||||
req, _ := http.NewRequest("POST", "/repos/manucorporat/sse/git/blobs", nil)
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
// Each goroutine has its own bytes.Buffer.
|
||||
for pb.Next() {
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
}
|
||||
})
|
||||
}
|
||||
131
vendor/github.com/gin-gonic/gin/logger.go
generated
vendored
131
vendor/github.com/gin-gonic/gin/logger.go
generated
vendored
@@ -5,78 +5,115 @@
|
||||
package gin
|
||||
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
var (
|
||||
green = string([]byte{27, 91, 57, 55, 59, 52, 50, 109})
|
||||
white = string([]byte{27, 91, 57, 48, 59, 52, 55, 109})
|
||||
yellow = string([]byte{27, 91, 57, 55, 59, 52, 51, 109})
|
||||
red = string([]byte{27, 91, 57, 55, 59, 52, 49, 109})
|
||||
blue = string([]byte{27, 91, 57, 55, 59, 52, 52, 109})
|
||||
magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109})
|
||||
cyan = string([]byte{27, 91, 57, 55, 59, 52, 54, 109})
|
||||
reset = string([]byte{27, 91, 48, 109})
|
||||
green = string([]byte{27, 91, 57, 55, 59, 52, 50, 109})
|
||||
white = string([]byte{27, 91, 57, 48, 59, 52, 55, 109})
|
||||
yellow = string([]byte{27, 91, 57, 55, 59, 52, 51, 109})
|
||||
red = string([]byte{27, 91, 57, 55, 59, 52, 49, 109})
|
||||
blue = string([]byte{27, 91, 57, 55, 59, 52, 52, 109})
|
||||
magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109})
|
||||
cyan = string([]byte{27, 91, 57, 55, 59, 52, 54, 109})
|
||||
reset = string([]byte{27, 91, 48, 109})
|
||||
disableColor = false
|
||||
)
|
||||
|
||||
func ErrorLogger() HandlerFunc {
|
||||
return ErrorLoggerT(ErrorTypeAll)
|
||||
func DisableConsoleColor() {
|
||||
disableColor = true
|
||||
}
|
||||
|
||||
func ErrorLoggerT(typ uint32) HandlerFunc {
|
||||
func ErrorLogger() HandlerFunc {
|
||||
return ErrorLoggerT(ErrorTypeAny)
|
||||
}
|
||||
|
||||
func ErrorLoggerT(typ ErrorType) HandlerFunc {
|
||||
return func(c *Context) {
|
||||
c.Next()
|
||||
|
||||
errs := c.Errors.ByType(typ)
|
||||
if len(errs) > 0 {
|
||||
// -1 status code = do not change current one
|
||||
c.JSON(-1, c.Errors)
|
||||
errors := c.Errors.ByType(typ)
|
||||
if len(errors) > 0 {
|
||||
c.JSON(-1, errors)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Logger instances a Logger middleware that will write the logs to gin.DefaultWriter
|
||||
// By default gin.DefaultWriter = os.Stdout
|
||||
func Logger() HandlerFunc {
|
||||
stdlogger := log.New(os.Stdout, "", 0)
|
||||
//errlogger := log.New(os.Stderr, "", 0)
|
||||
return LoggerWithWriter(DefaultWriter)
|
||||
}
|
||||
|
||||
// LoggerWithWriter instance a Logger middleware with the specified writter buffer.
|
||||
// Example: os.Stdout, a file opened in write mode, a socket...
|
||||
func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
|
||||
isTerm := true
|
||||
|
||||
if w, ok := out.(*os.File); !ok ||
|
||||
(os.Getenv("TERM") == "dumb" || (!isatty.IsTerminal(w.Fd()) && !isatty.IsCygwinTerminal(w.Fd()))) ||
|
||||
disableColor {
|
||||
isTerm = false
|
||||
}
|
||||
|
||||
var skip map[string]struct{}
|
||||
|
||||
if length := len(notlogged); length > 0 {
|
||||
skip = make(map[string]struct{}, length)
|
||||
|
||||
for _, path := range notlogged {
|
||||
skip[path] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
return func(c *Context) {
|
||||
// Start timer
|
||||
start := time.Now()
|
||||
path := c.Request.URL.Path
|
||||
|
||||
// Process request
|
||||
c.Next()
|
||||
|
||||
// Stop timer
|
||||
end := time.Now()
|
||||
latency := end.Sub(start)
|
||||
// Log only when path is not being skipped
|
||||
if _, ok := skip[path]; !ok {
|
||||
// Stop timer
|
||||
end := time.Now()
|
||||
latency := end.Sub(start)
|
||||
|
||||
clientIP := c.ClientIP()
|
||||
method := c.Request.Method
|
||||
statusCode := c.Writer.Status()
|
||||
statusColor := colorForStatus(statusCode)
|
||||
methodColor := colorForMethod(method)
|
||||
clientIP := c.ClientIP()
|
||||
method := c.Request.Method
|
||||
statusCode := c.Writer.Status()
|
||||
var statusColor, methodColor string
|
||||
if isTerm {
|
||||
statusColor = colorForStatus(statusCode)
|
||||
methodColor = colorForMethod(method)
|
||||
}
|
||||
comment := c.Errors.ByType(ErrorTypePrivate).String()
|
||||
|
||||
stdlogger.Printf("[GIN] %v |%s %3d %s| %12v | %s |%s %s %-7s %s\n%s",
|
||||
end.Format("2006/01/02 - 15:04:05"),
|
||||
statusColor, statusCode, reset,
|
||||
latency,
|
||||
clientIP,
|
||||
methodColor, reset, method,
|
||||
c.Request.URL.Path,
|
||||
c.Errors.String(),
|
||||
)
|
||||
fmt.Fprintf(out, "[GIN] %v |%s %3d %s| %13v | %15s |%s %s %-7s %s\n%s",
|
||||
end.Format("2006/01/02 - 15:04:05"),
|
||||
statusColor, statusCode, reset,
|
||||
latency,
|
||||
clientIP,
|
||||
methodColor, method, reset,
|
||||
path,
|
||||
comment,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func colorForStatus(code int) string {
|
||||
switch {
|
||||
case code >= 200 && code <= 299:
|
||||
case code >= 200 && code < 300:
|
||||
return green
|
||||
case code >= 300 && code <= 399:
|
||||
case code >= 300 && code < 400:
|
||||
return white
|
||||
case code >= 400 && code <= 499:
|
||||
case code >= 400 && code < 500:
|
||||
return yellow
|
||||
default:
|
||||
return red
|
||||
@@ -84,20 +121,20 @@ func colorForStatus(code int) string {
|
||||
}
|
||||
|
||||
func colorForMethod(method string) string {
|
||||
switch {
|
||||
case method == "GET":
|
||||
switch method {
|
||||
case "GET":
|
||||
return blue
|
||||
case method == "POST":
|
||||
case "POST":
|
||||
return cyan
|
||||
case method == "PUT":
|
||||
case "PUT":
|
||||
return yellow
|
||||
case method == "DELETE":
|
||||
case "DELETE":
|
||||
return red
|
||||
case method == "PATCH":
|
||||
case "PATCH":
|
||||
return green
|
||||
case method == "HEAD":
|
||||
case "HEAD":
|
||||
return magenta
|
||||
case method == "OPTIONS":
|
||||
case "OPTIONS":
|
||||
return white
|
||||
default:
|
||||
return reset
|
||||
|
||||
148
vendor/github.com/gin-gonic/gin/logger_test.go
generated
vendored
Normal file
148
vendor/github.com/gin-gonic/gin/logger_test.go
generated
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func init() {
|
||||
SetMode(TestMode)
|
||||
}
|
||||
|
||||
func TestLogger(t *testing.T) {
|
||||
buffer := new(bytes.Buffer)
|
||||
router := New()
|
||||
router.Use(LoggerWithWriter(buffer))
|
||||
router.GET("/example", func(c *Context) {})
|
||||
router.POST("/example", func(c *Context) {})
|
||||
router.PUT("/example", func(c *Context) {})
|
||||
router.DELETE("/example", func(c *Context) {})
|
||||
router.PATCH("/example", func(c *Context) {})
|
||||
router.HEAD("/example", func(c *Context) {})
|
||||
router.OPTIONS("/example", func(c *Context) {})
|
||||
|
||||
performRequest(router, "GET", "/example")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "GET")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
|
||||
// I wrote these first (extending the above) but then realized they are more
|
||||
// like integration tests because they test the whole logging process rather
|
||||
// than individual functions. Im not sure where these should go.
|
||||
buffer.Reset()
|
||||
performRequest(router, "POST", "/example")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "POST")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
|
||||
buffer.Reset()
|
||||
performRequest(router, "PUT", "/example")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "PUT")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
|
||||
buffer.Reset()
|
||||
performRequest(router, "DELETE", "/example")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "DELETE")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
|
||||
buffer.Reset()
|
||||
performRequest(router, "PATCH", "/example")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "PATCH")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
|
||||
buffer.Reset()
|
||||
performRequest(router, "HEAD", "/example")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "HEAD")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
|
||||
buffer.Reset()
|
||||
performRequest(router, "OPTIONS", "/example")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "OPTIONS")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
|
||||
buffer.Reset()
|
||||
performRequest(router, "GET", "/notfound")
|
||||
assert.Contains(t, buffer.String(), "404")
|
||||
assert.Contains(t, buffer.String(), "GET")
|
||||
assert.Contains(t, buffer.String(), "/notfound")
|
||||
|
||||
}
|
||||
|
||||
func TestColorForMethod(t *testing.T) {
|
||||
assert.Equal(t, colorForMethod("GET"), string([]byte{27, 91, 57, 55, 59, 52, 52, 109}), "get should be blue")
|
||||
assert.Equal(t, colorForMethod("POST"), string([]byte{27, 91, 57, 55, 59, 52, 54, 109}), "post should be cyan")
|
||||
assert.Equal(t, colorForMethod("PUT"), string([]byte{27, 91, 57, 55, 59, 52, 51, 109}), "put should be yellow")
|
||||
assert.Equal(t, colorForMethod("DELETE"), string([]byte{27, 91, 57, 55, 59, 52, 49, 109}), "delete should be red")
|
||||
assert.Equal(t, colorForMethod("PATCH"), string([]byte{27, 91, 57, 55, 59, 52, 50, 109}), "patch should be green")
|
||||
assert.Equal(t, colorForMethod("HEAD"), string([]byte{27, 91, 57, 55, 59, 52, 53, 109}), "head should be magenta")
|
||||
assert.Equal(t, colorForMethod("OPTIONS"), string([]byte{27, 91, 57, 48, 59, 52, 55, 109}), "options should be white")
|
||||
assert.Equal(t, colorForMethod("TRACE"), string([]byte{27, 91, 48, 109}), "trace is not defined and should be the reset color")
|
||||
}
|
||||
|
||||
func TestColorForStatus(t *testing.T) {
|
||||
assert.Equal(t, colorForStatus(200), string([]byte{27, 91, 57, 55, 59, 52, 50, 109}), "2xx should be green")
|
||||
assert.Equal(t, colorForStatus(301), string([]byte{27, 91, 57, 48, 59, 52, 55, 109}), "3xx should be white")
|
||||
assert.Equal(t, colorForStatus(404), string([]byte{27, 91, 57, 55, 59, 52, 51, 109}), "4xx should be yellow")
|
||||
assert.Equal(t, colorForStatus(2), string([]byte{27, 91, 57, 55, 59, 52, 49, 109}), "other things should be red")
|
||||
}
|
||||
|
||||
func TestErrorLogger(t *testing.T) {
|
||||
router := New()
|
||||
router.Use(ErrorLogger())
|
||||
router.GET("/error", func(c *Context) {
|
||||
c.Error(errors.New("this is an error"))
|
||||
})
|
||||
router.GET("/abort", func(c *Context) {
|
||||
c.AbortWithError(401, errors.New("no authorized"))
|
||||
})
|
||||
router.GET("/print", func(c *Context) {
|
||||
c.Error(errors.New("this is an error"))
|
||||
c.String(500, "hola!")
|
||||
})
|
||||
|
||||
w := performRequest(router, "GET", "/error")
|
||||
assert.Equal(t, 200, w.Code)
|
||||
assert.Equal(t, "{\"error\":\"this is an error\"}", w.Body.String())
|
||||
|
||||
w = performRequest(router, "GET", "/abort")
|
||||
assert.Equal(t, 401, w.Code)
|
||||
assert.Equal(t, "{\"error\":\"no authorized\"}", w.Body.String())
|
||||
|
||||
w = performRequest(router, "GET", "/print")
|
||||
assert.Equal(t, 500, w.Code)
|
||||
assert.Equal(t, "hola!{\"error\":\"this is an error\"}", w.Body.String())
|
||||
}
|
||||
|
||||
func TestSkippingPaths(t *testing.T) {
|
||||
buffer := new(bytes.Buffer)
|
||||
router := New()
|
||||
router.Use(LoggerWithWriter(buffer, "/skipped"))
|
||||
router.GET("/logged", func(c *Context) {})
|
||||
router.GET("/skipped", func(c *Context) {})
|
||||
|
||||
performRequest(router, "GET", "/logged")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
|
||||
buffer.Reset()
|
||||
performRequest(router, "GET", "/skipped")
|
||||
assert.Contains(t, buffer.String(), "")
|
||||
}
|
||||
|
||||
func TestDisableConsoleColor(t *testing.T) {
|
||||
New()
|
||||
assert.False(t, disableColor)
|
||||
DisableConsoleColor()
|
||||
assert.True(t, disableColor)
|
||||
}
|
||||
BIN
vendor/github.com/gin-gonic/gin/logo.jpg
generated
vendored
Normal file
BIN
vendor/github.com/gin-gonic/gin/logo.jpg
generated
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
249
vendor/github.com/gin-gonic/gin/middleware_test.go
generated
vendored
Normal file
249
vendor/github.com/gin-gonic/gin/middleware_test.go
generated
vendored
Normal file
@@ -0,0 +1,249 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-contrib/sse"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMiddlewareGeneralCase(t *testing.T) {
|
||||
signature := ""
|
||||
router := New()
|
||||
router.Use(func(c *Context) {
|
||||
signature += "A"
|
||||
c.Next()
|
||||
signature += "B"
|
||||
})
|
||||
router.Use(func(c *Context) {
|
||||
signature += "C"
|
||||
})
|
||||
router.GET("/", func(c *Context) {
|
||||
signature += "D"
|
||||
})
|
||||
router.NoRoute(func(c *Context) {
|
||||
signature += " X "
|
||||
})
|
||||
router.NoMethod(func(c *Context) {
|
||||
signature += " XX "
|
||||
})
|
||||
// RUN
|
||||
w := performRequest(router, "GET", "/")
|
||||
|
||||
// TEST
|
||||
assert.Equal(t, w.Code, 200)
|
||||
assert.Equal(t, signature, "ACDB")
|
||||
}
|
||||
|
||||
func TestMiddlewareNoRoute(t *testing.T) {
|
||||
signature := ""
|
||||
router := New()
|
||||
router.Use(func(c *Context) {
|
||||
signature += "A"
|
||||
c.Next()
|
||||
signature += "B"
|
||||
})
|
||||
router.Use(func(c *Context) {
|
||||
signature += "C"
|
||||
c.Next()
|
||||
c.Next()
|
||||
c.Next()
|
||||
c.Next()
|
||||
signature += "D"
|
||||
})
|
||||
router.NoRoute(func(c *Context) {
|
||||
signature += "E"
|
||||
c.Next()
|
||||
signature += "F"
|
||||
}, func(c *Context) {
|
||||
signature += "G"
|
||||
c.Next()
|
||||
signature += "H"
|
||||
})
|
||||
router.NoMethod(func(c *Context) {
|
||||
signature += " X "
|
||||
})
|
||||
// RUN
|
||||
w := performRequest(router, "GET", "/")
|
||||
|
||||
// TEST
|
||||
assert.Equal(t, w.Code, 404)
|
||||
assert.Equal(t, signature, "ACEGHFDB")
|
||||
}
|
||||
|
||||
func TestMiddlewareNoMethodEnabled(t *testing.T) {
|
||||
signature := ""
|
||||
router := New()
|
||||
router.HandleMethodNotAllowed = true
|
||||
router.Use(func(c *Context) {
|
||||
signature += "A"
|
||||
c.Next()
|
||||
signature += "B"
|
||||
})
|
||||
router.Use(func(c *Context) {
|
||||
signature += "C"
|
||||
c.Next()
|
||||
signature += "D"
|
||||
})
|
||||
router.NoMethod(func(c *Context) {
|
||||
signature += "E"
|
||||
c.Next()
|
||||
signature += "F"
|
||||
}, func(c *Context) {
|
||||
signature += "G"
|
||||
c.Next()
|
||||
signature += "H"
|
||||
})
|
||||
router.NoRoute(func(c *Context) {
|
||||
signature += " X "
|
||||
})
|
||||
router.POST("/", func(c *Context) {
|
||||
signature += " XX "
|
||||
})
|
||||
// RUN
|
||||
w := performRequest(router, "GET", "/")
|
||||
|
||||
// TEST
|
||||
assert.Equal(t, w.Code, 405)
|
||||
assert.Equal(t, signature, "ACEGHFDB")
|
||||
}
|
||||
|
||||
func TestMiddlewareNoMethodDisabled(t *testing.T) {
|
||||
signature := ""
|
||||
router := New()
|
||||
router.HandleMethodNotAllowed = false
|
||||
router.Use(func(c *Context) {
|
||||
signature += "A"
|
||||
c.Next()
|
||||
signature += "B"
|
||||
})
|
||||
router.Use(func(c *Context) {
|
||||
signature += "C"
|
||||
c.Next()
|
||||
signature += "D"
|
||||
})
|
||||
router.NoMethod(func(c *Context) {
|
||||
signature += "E"
|
||||
c.Next()
|
||||
signature += "F"
|
||||
}, func(c *Context) {
|
||||
signature += "G"
|
||||
c.Next()
|
||||
signature += "H"
|
||||
})
|
||||
router.NoRoute(func(c *Context) {
|
||||
signature += " X "
|
||||
})
|
||||
router.POST("/", func(c *Context) {
|
||||
signature += " XX "
|
||||
})
|
||||
// RUN
|
||||
w := performRequest(router, "GET", "/")
|
||||
|
||||
// TEST
|
||||
assert.Equal(t, w.Code, 404)
|
||||
assert.Equal(t, signature, "AC X DB")
|
||||
}
|
||||
|
||||
func TestMiddlewareAbort(t *testing.T) {
|
||||
signature := ""
|
||||
router := New()
|
||||
router.Use(func(c *Context) {
|
||||
signature += "A"
|
||||
})
|
||||
router.Use(func(c *Context) {
|
||||
signature += "C"
|
||||
c.AbortWithStatus(401)
|
||||
c.Next()
|
||||
signature += "D"
|
||||
})
|
||||
router.GET("/", func(c *Context) {
|
||||
signature += " X "
|
||||
c.Next()
|
||||
signature += " XX "
|
||||
})
|
||||
|
||||
// RUN
|
||||
w := performRequest(router, "GET", "/")
|
||||
|
||||
// TEST
|
||||
assert.Equal(t, w.Code, 401)
|
||||
assert.Equal(t, signature, "ACD")
|
||||
}
|
||||
|
||||
func TestMiddlewareAbortHandlersChainAndNext(t *testing.T) {
|
||||
signature := ""
|
||||
router := New()
|
||||
router.Use(func(c *Context) {
|
||||
signature += "A"
|
||||
c.Next()
|
||||
c.AbortWithStatus(410)
|
||||
signature += "B"
|
||||
|
||||
})
|
||||
router.GET("/", func(c *Context) {
|
||||
signature += "C"
|
||||
c.Next()
|
||||
})
|
||||
// RUN
|
||||
w := performRequest(router, "GET", "/")
|
||||
|
||||
// TEST
|
||||
assert.Equal(t, w.Code, 410)
|
||||
assert.Equal(t, signature, "ACB")
|
||||
}
|
||||
|
||||
// TestFailHandlersChain - ensure that Fail interrupt used middleware in fifo order as
|
||||
// as well as Abort
|
||||
func TestMiddlewareFailHandlersChain(t *testing.T) {
|
||||
// SETUP
|
||||
signature := ""
|
||||
router := New()
|
||||
router.Use(func(context *Context) {
|
||||
signature += "A"
|
||||
context.AbortWithError(500, errors.New("foo"))
|
||||
})
|
||||
router.Use(func(context *Context) {
|
||||
signature += "B"
|
||||
context.Next()
|
||||
signature += "C"
|
||||
})
|
||||
// RUN
|
||||
w := performRequest(router, "GET", "/")
|
||||
|
||||
// TEST
|
||||
assert.Equal(t, w.Code, 500)
|
||||
assert.Equal(t, signature, "A")
|
||||
}
|
||||
|
||||
func TestMiddlewareWrite(t *testing.T) {
|
||||
router := New()
|
||||
router.Use(func(c *Context) {
|
||||
c.String(400, "hola\n")
|
||||
})
|
||||
router.Use(func(c *Context) {
|
||||
c.XML(400, H{"foo": "bar"})
|
||||
})
|
||||
router.Use(func(c *Context) {
|
||||
c.JSON(400, H{"foo": "bar"})
|
||||
})
|
||||
router.GET("/", func(c *Context) {
|
||||
c.JSON(400, H{"foo": "bar"})
|
||||
}, func(c *Context) {
|
||||
c.Render(400, sse.Event{
|
||||
Event: "test",
|
||||
Data: "message",
|
||||
})
|
||||
})
|
||||
|
||||
w := performRequest(router, "GET", "/")
|
||||
|
||||
assert.Equal(t, 400, w.Code)
|
||||
assert.Equal(t, strings.Replace("hola\n<map><foo>bar</foo></map>{\"foo\":\"bar\"}{\"foo\":\"bar\"}event:test\ndata:message\n\n", " ", "", -1), strings.Replace(w.Body.String(), " ", "", -1))
|
||||
}
|
||||
56
vendor/github.com/gin-gonic/gin/mode.go
generated
vendored
56
vendor/github.com/gin-gonic/gin/mode.go
generated
vendored
@@ -5,11 +5,13 @@
|
||||
package gin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
)
|
||||
|
||||
const GIN_MODE = "GIN_MODE"
|
||||
const ENV_GIN_MODE = "GIN_MODE"
|
||||
|
||||
const (
|
||||
DebugMode string = "debug"
|
||||
@@ -17,47 +19,51 @@ const (
|
||||
TestMode string = "test"
|
||||
)
|
||||
const (
|
||||
debugCode = iota
|
||||
releaseCode = iota
|
||||
testCode = iota
|
||||
debugCode = iota
|
||||
releaseCode
|
||||
testCode
|
||||
)
|
||||
|
||||
var gin_mode int = debugCode
|
||||
var mode_name string = DebugMode
|
||||
// DefaultWriter is the default io.Writer used the Gin for debug output and
|
||||
// middleware output like Logger() or Recovery().
|
||||
// Note that both Logger and Recovery provides custom ways to configure their
|
||||
// output io.Writer.
|
||||
// To support coloring in Windows use:
|
||||
// import "github.com/mattn/go-colorable"
|
||||
// gin.DefaultWriter = colorable.NewColorableStdout()
|
||||
var DefaultWriter io.Writer = os.Stdout
|
||||
var DefaultErrorWriter io.Writer = os.Stderr
|
||||
|
||||
var ginMode = debugCode
|
||||
var modeName = DebugMode
|
||||
|
||||
func init() {
|
||||
value := os.Getenv(GIN_MODE)
|
||||
if len(value) == 0 {
|
||||
mode := os.Getenv(ENV_GIN_MODE)
|
||||
if len(mode) == 0 {
|
||||
SetMode(DebugMode)
|
||||
} else {
|
||||
SetMode(value)
|
||||
SetMode(mode)
|
||||
}
|
||||
}
|
||||
|
||||
func SetMode(value string) {
|
||||
switch value {
|
||||
case DebugMode:
|
||||
gin_mode = debugCode
|
||||
ginMode = debugCode
|
||||
case ReleaseMode:
|
||||
gin_mode = releaseCode
|
||||
ginMode = releaseCode
|
||||
case TestMode:
|
||||
gin_mode = testCode
|
||||
ginMode = testCode
|
||||
default:
|
||||
panic("gin mode unknown: " + value)
|
||||
}
|
||||
mode_name = value
|
||||
modeName = value
|
||||
}
|
||||
|
||||
func DisableBindValidation() {
|
||||
binding.Validator = nil
|
||||
}
|
||||
|
||||
func Mode() string {
|
||||
return mode_name
|
||||
}
|
||||
|
||||
func IsDebugging() bool {
|
||||
return gin_mode == debugCode
|
||||
}
|
||||
|
||||
func debugPrint(format string, values ...interface{}) {
|
||||
if IsDebugging() {
|
||||
fmt.Printf("[GIN-debug] "+format, values...)
|
||||
}
|
||||
return modeName
|
||||
}
|
||||
|
||||
31
vendor/github.com/gin-gonic/gin/mode_test.go
generated
vendored
Normal file
31
vendor/github.com/gin-gonic/gin/mode_test.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gin
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func init() {
|
||||
SetMode(TestMode)
|
||||
}
|
||||
|
||||
func TestSetMode(t *testing.T) {
|
||||
SetMode(DebugMode)
|
||||
assert.Equal(t, ginMode, debugCode)
|
||||
assert.Equal(t, Mode(), DebugMode)
|
||||
|
||||
SetMode(ReleaseMode)
|
||||
assert.Equal(t, ginMode, releaseCode)
|
||||
assert.Equal(t, Mode(), ReleaseMode)
|
||||
|
||||
SetMode(TestMode)
|
||||
assert.Equal(t, ginMode, testCode)
|
||||
assert.Equal(t, Mode(), TestMode)
|
||||
|
||||
assert.Panics(t, func() { SetMode("unknown") })
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
// Copyright 2013 Julien Schmidt. All rights reserved.
|
||||
// Based on the path package, Copyright 2009 The Go Authors.
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
// at https://github.com/julienschmidt/httprouter/blob/master/LICENSE.
|
||||
|
||||
package httprouter
|
||||
package gin
|
||||
|
||||
// CleanPath is the URL version of path.Clean, it returns a canonical URL path
|
||||
// for p, eliminating . and .. elements.
|
||||
@@ -18,7 +18,7 @@ package httprouter
|
||||
// that is, replace "/.." by "/" at the beginning of a path.
|
||||
//
|
||||
// If the result of this process is an empty string, "/" is returned
|
||||
func CleanPath(p string) string {
|
||||
func cleanPath(p string) string {
|
||||
// Turn empty string into "/"
|
||||
if p == "" {
|
||||
return "/"
|
||||
@@ -1,13 +1,15 @@
|
||||
// Copyright 2013 Julien Schmidt. All rights reserved.
|
||||
// Based on the path package, Copyright 2009 The Go Authors.
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
// at https://github.com/julienschmidt/httprouter/blob/master/LICENSE
|
||||
|
||||
package httprouter
|
||||
package gin
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var cleanTests = []struct {
|
||||
@@ -65,12 +67,8 @@ var cleanTests = []struct {
|
||||
|
||||
func TestPathClean(t *testing.T) {
|
||||
for _, test := range cleanTests {
|
||||
if s := CleanPath(test.path); s != test.result {
|
||||
t.Errorf("CleanPath(%q) = %q, want %q", test.path, s, test.result)
|
||||
}
|
||||
if s := CleanPath(test.result); s != test.result {
|
||||
t.Errorf("CleanPath(%q) = %q, want %q", test.result, s, test.result)
|
||||
}
|
||||
assert.Equal(t, cleanPath(test.path), test.result)
|
||||
assert.Equal(t, cleanPath(test.result), test.result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,9 +82,7 @@ func TestPathCleanMallocs(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, test := range cleanTests {
|
||||
allocs := testing.AllocsPerRun(100, func() { CleanPath(test.result) })
|
||||
if allocs > 0 {
|
||||
t.Errorf("CleanPath(%q): %v allocs, want zero", test.result, allocs)
|
||||
}
|
||||
allocs := testing.AllocsPerRun(100, func() { cleanPath(test.result) })
|
||||
assert.EqualValues(t, allocs, 0)
|
||||
}
|
||||
}
|
||||
44
vendor/github.com/gin-gonic/gin/recovery.go
generated
vendored
44
vendor/github.com/gin-gonic/gin/recovery.go
generated
vendored
@@ -7,9 +7,10 @@ package gin
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
@@ -20,6 +21,31 @@ var (
|
||||
slash = []byte("/")
|
||||
)
|
||||
|
||||
// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one.
|
||||
func Recovery() HandlerFunc {
|
||||
return RecoveryWithWriter(DefaultErrorWriter)
|
||||
}
|
||||
|
||||
func RecoveryWithWriter(out io.Writer) HandlerFunc {
|
||||
var logger *log.Logger
|
||||
if out != nil {
|
||||
logger = log.New(out, "\n\n\x1b[31m", log.LstdFlags)
|
||||
}
|
||||
return func(c *Context) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
if logger != nil {
|
||||
stack := stack(3)
|
||||
httprequest, _ := httputil.DumpRequest(c.Request, false)
|
||||
logger.Printf("[Recovery] panic recovered:\n%s\n%s\n%s%s", string(httprequest), err, stack, reset)
|
||||
}
|
||||
c.AbortWithStatus(500)
|
||||
}
|
||||
}()
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// stack returns a nicely formated stack frame, skipping skip frames
|
||||
func stack(skip int) []byte {
|
||||
buf := new(bytes.Buffer) // the returned data
|
||||
@@ -80,19 +106,3 @@ func function(pc uintptr) []byte {
|
||||
name = bytes.Replace(name, centerDot, dot, -1)
|
||||
return name
|
||||
}
|
||||
|
||||
// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one.
|
||||
// While Martini is in development mode, Recovery will also output the panic as HTML.
|
||||
func Recovery() HandlerFunc {
|
||||
return func(c *Context) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
stack := stack(3)
|
||||
log.Printf("PANIC: %s\n%s", err, stack)
|
||||
c.Writer.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}()
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
47
vendor/github.com/gin-gonic/gin/recovery_test.go
generated
vendored
47
vendor/github.com/gin-gonic/gin/recovery_test.go
generated
vendored
@@ -6,51 +6,38 @@ package gin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// TestPanicInHandler assert that panic has been recovered.
|
||||
func TestPanicInHandler(t *testing.T) {
|
||||
// SETUP
|
||||
log.SetOutput(bytes.NewBuffer(nil)) // Disable panic logs for testing
|
||||
r := New()
|
||||
r.Use(Recovery())
|
||||
r.GET("/recovery", func(_ *Context) {
|
||||
buffer := new(bytes.Buffer)
|
||||
router := New()
|
||||
router.Use(RecoveryWithWriter(buffer))
|
||||
router.GET("/recovery", func(_ *Context) {
|
||||
panic("Oupps, Houston, we have a problem")
|
||||
})
|
||||
|
||||
// RUN
|
||||
w := PerformRequest(r, "GET", "/recovery")
|
||||
|
||||
// restore logging
|
||||
log.SetOutput(os.Stderr)
|
||||
|
||||
if w.Code != 500 {
|
||||
t.Errorf("Response code should be Internal Server Error, was: %s", w.Code)
|
||||
}
|
||||
w := performRequest(router, "GET", "/recovery")
|
||||
// TEST
|
||||
assert.Equal(t, w.Code, 500)
|
||||
assert.Contains(t, buffer.String(), "GET /recovery")
|
||||
assert.Contains(t, buffer.String(), "Oupps, Houston, we have a problem")
|
||||
assert.Contains(t, buffer.String(), "TestPanicInHandler")
|
||||
}
|
||||
|
||||
// TestPanicWithAbort assert that panic has been recovered even if context.Abort was used.
|
||||
func TestPanicWithAbort(t *testing.T) {
|
||||
// SETUP
|
||||
log.SetOutput(bytes.NewBuffer(nil))
|
||||
r := New()
|
||||
r.Use(Recovery())
|
||||
r.GET("/recovery", func(c *Context) {
|
||||
router := New()
|
||||
router.Use(RecoveryWithWriter(nil))
|
||||
router.GET("/recovery", func(c *Context) {
|
||||
c.AbortWithStatus(400)
|
||||
panic("Oupps, Houston, we have a problem")
|
||||
})
|
||||
|
||||
// RUN
|
||||
w := PerformRequest(r, "GET", "/recovery")
|
||||
|
||||
// restore logging
|
||||
log.SetOutput(os.Stderr)
|
||||
|
||||
w := performRequest(router, "GET", "/recovery")
|
||||
// TEST
|
||||
if w.Code != 500 {
|
||||
t.Errorf("Response code should be Bad request, was: %s", w.Code)
|
||||
}
|
||||
assert.Equal(t, w.Code, 400)
|
||||
}
|
||||
|
||||
23
vendor/github.com/gin-gonic/gin/render/data.go
generated
vendored
Normal file
23
vendor/github.com/gin-gonic/gin/render/data.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package render
|
||||
|
||||
import "net/http"
|
||||
|
||||
type Data struct {
|
||||
ContentType string
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// Render (Data) writes data with custom ContentType
|
||||
func (r Data) Render(w http.ResponseWriter) (err error) {
|
||||
r.WriteContentType(w)
|
||||
_, err = w.Write(r.Data)
|
||||
return
|
||||
}
|
||||
|
||||
func (r Data) WriteContentType(w http.ResponseWriter) {
|
||||
writeContentType(w, []string{r.ContentType})
|
||||
}
|
||||
82
vendor/github.com/gin-gonic/gin/render/html.go
generated
vendored
Normal file
82
vendor/github.com/gin-gonic/gin/render/html.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package render
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type (
|
||||
Delims struct {
|
||||
Left string
|
||||
Right string
|
||||
}
|
||||
|
||||
HTMLRender interface {
|
||||
Instance(string, interface{}) Render
|
||||
}
|
||||
|
||||
HTMLProduction struct {
|
||||
Template *template.Template
|
||||
Delims Delims
|
||||
}
|
||||
|
||||
HTMLDebug struct {
|
||||
Files []string
|
||||
Glob string
|
||||
Delims Delims
|
||||
FuncMap template.FuncMap
|
||||
}
|
||||
|
||||
HTML struct {
|
||||
Template *template.Template
|
||||
Name string
|
||||
Data interface{}
|
||||
}
|
||||
)
|
||||
|
||||
var htmlContentType = []string{"text/html; charset=utf-8"}
|
||||
|
||||
func (r HTMLProduction) Instance(name string, data interface{}) Render {
|
||||
return HTML{
|
||||
Template: r.Template,
|
||||
Name: name,
|
||||
Data: data,
|
||||
}
|
||||
}
|
||||
|
||||
func (r HTMLDebug) Instance(name string, data interface{}) Render {
|
||||
return HTML{
|
||||
Template: r.loadTemplate(),
|
||||
Name: name,
|
||||
Data: data,
|
||||
}
|
||||
}
|
||||
func (r HTMLDebug) loadTemplate() *template.Template {
|
||||
if r.FuncMap == nil {
|
||||
r.FuncMap = template.FuncMap{}
|
||||
}
|
||||
if len(r.Files) > 0 {
|
||||
return template.Must(template.New("").Delims(r.Delims.Left, r.Delims.Right).Funcs(r.FuncMap).ParseFiles(r.Files...))
|
||||
}
|
||||
if len(r.Glob) > 0 {
|
||||
return template.Must(template.New("").Delims(r.Delims.Left, r.Delims.Right).Funcs(r.FuncMap).ParseGlob(r.Glob))
|
||||
}
|
||||
panic("the HTML debug render was created without files or glob pattern")
|
||||
}
|
||||
|
||||
func (r HTML) Render(w http.ResponseWriter) error {
|
||||
r.WriteContentType(w)
|
||||
|
||||
if len(r.Name) == 0 {
|
||||
return r.Template.Execute(w, r.Data)
|
||||
}
|
||||
return r.Template.ExecuteTemplate(w, r.Name, r.Data)
|
||||
}
|
||||
|
||||
func (r HTML) WriteContentType(w http.ResponseWriter) {
|
||||
writeContentType(w, htmlContentType)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user