mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	Updating go-restful
This commit is contained in:
		
							
								
								
									
										4
									
								
								Godeps/Godeps.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								Godeps/Godeps.json
									
									
									
										generated
									
									
									
								
							@@ -378,8 +378,8 @@
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/emicklei/go-restful",
 | 
			
		||||
			"Comment": "v1.1.3-98-g1f9a0ee",
 | 
			
		||||
			"Rev": "1f9a0ee00ff93717a275e15b30cf7df356255877"
 | 
			
		||||
			"Comment": "v1.2",
 | 
			
		||||
			"Rev": "777bb3f19bcafe2575ffb2a3e46af92509ae9594"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/evanphx/json-patch",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/CHANGES.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/CHANGES.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,5 +1,15 @@
 | 
			
		||||
Change history of go-restful
 | 
			
		||||
=
 | 
			
		||||
2015-09-27
 | 
			
		||||
- rename new WriteStatusAnd... to WriteHeaderAnd... for consistency
 | 
			
		||||
 | 
			
		||||
2015-09-25
 | 
			
		||||
- fixed problem with changing Header after WriteHeader (issue 235)
 | 
			
		||||
 | 
			
		||||
2015-09-14
 | 
			
		||||
- changed behavior of WriteHeader (immediate write) and WriteEntity (no status write)
 | 
			
		||||
- added support for custom EntityReaderWriters.
 | 
			
		||||
 | 
			
		||||
2015-08-06
 | 
			
		||||
- add support for reading entities from compressed request content
 | 
			
		||||
- use sync.Pool for compressors of http response and request body
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -54,6 +54,8 @@ func (u UserResource) findUser(request *restful.Request, response *restful.Respo
 | 
			
		||||
- Panic recovery to produce HTTP 500, customizable using RecoverHandler(...)
 | 
			
		||||
- Route errors produce HTTP 404/405/406/415 errors, customizable using ServiceErrorHandler(...)
 | 
			
		||||
- Configurable (trace) logging
 | 
			
		||||
- Customizable encoding using EntityReaderWriter registration
 | 
			
		||||
- Customizable gzip/deflate readers and writers using CompressorProvider registration
 | 
			
		||||
	
 | 
			
		||||
### Resources
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										29
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/compress.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/compress.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -20,6 +20,7 @@ var EnableContentEncoding = false
 | 
			
		||||
type CompressingResponseWriter struct {
 | 
			
		||||
	writer     http.ResponseWriter
 | 
			
		||||
	compressor io.WriteCloser
 | 
			
		||||
	encoding   string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Header is part of http.ResponseWriter interface
 | 
			
		||||
@@ -35,6 +36,9 @@ func (c *CompressingResponseWriter) WriteHeader(status int) {
 | 
			
		||||
// Write is part of http.ResponseWriter interface
 | 
			
		||||
// It is passed through the compressor
 | 
			
		||||
func (c *CompressingResponseWriter) Write(bytes []byte) (int, error) {
 | 
			
		||||
	if c.isCompressorClosed() {
 | 
			
		||||
		return -1, errors.New("Compressing error: tried to write data using closed compressor")
 | 
			
		||||
	}
 | 
			
		||||
	return c.compressor.Write(bytes)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -44,8 +48,25 @@ func (c *CompressingResponseWriter) CloseNotify() <-chan bool {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close the underlying compressor
 | 
			
		||||
func (c *CompressingResponseWriter) Close() {
 | 
			
		||||
func (c *CompressingResponseWriter) Close() error {
 | 
			
		||||
	if c.isCompressorClosed() {
 | 
			
		||||
		return errors.New("Compressing error: tried to close already closed compressor")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.compressor.Close()
 | 
			
		||||
	if ENCODING_GZIP == c.encoding {
 | 
			
		||||
		currentCompressorProvider.ReleaseGzipWriter(c.compressor.(*gzip.Writer))
 | 
			
		||||
	}
 | 
			
		||||
	if ENCODING_DEFLATE == c.encoding {
 | 
			
		||||
		currentCompressorProvider.ReleaseZlibWriter(c.compressor.(*zlib.Writer))
 | 
			
		||||
	}
 | 
			
		||||
	// gc hint needed?
 | 
			
		||||
	c.compressor = nil
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *CompressingResponseWriter) isCompressorClosed() bool {
 | 
			
		||||
	return nil == c.compressor
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WantsCompressedResponse reads the Accept-Encoding header to see if and which encoding is requested.
 | 
			
		||||
@@ -73,13 +94,15 @@ func NewCompressingResponseWriter(httpWriter http.ResponseWriter, encoding strin
 | 
			
		||||
	c.writer = httpWriter
 | 
			
		||||
	var err error
 | 
			
		||||
	if ENCODING_GZIP == encoding {
 | 
			
		||||
		w := GzipWriterPool.Get().(*gzip.Writer)
 | 
			
		||||
		w := currentCompressorProvider.AcquireGzipWriter()
 | 
			
		||||
		w.Reset(httpWriter)
 | 
			
		||||
		c.compressor = w
 | 
			
		||||
		c.encoding = ENCODING_GZIP
 | 
			
		||||
	} else if ENCODING_DEFLATE == encoding {
 | 
			
		||||
		w := ZlibWriterPool.Get().(*zlib.Writer)
 | 
			
		||||
		w := currentCompressorProvider.AcquireZlibWriter()
 | 
			
		||||
		w.Reset(httpWriter)
 | 
			
		||||
		c.compressor = w
 | 
			
		||||
		c.encoding = ENCODING_DEFLATE
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil, errors.New("Unknown encoding:" + encoding)
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										103
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/compressor_cache.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/compressor_cache.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,103 @@
 | 
			
		||||
package restful
 | 
			
		||||
 | 
			
		||||
// Copyright 2015 Ernest Micklei. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a license
 | 
			
		||||
// that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"compress/gzip"
 | 
			
		||||
	"compress/zlib"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// BoundedCachedCompressors is a CompressorProvider that uses a cache with a fixed amount
 | 
			
		||||
// of writers and readers (resources).
 | 
			
		||||
// If a new resource is acquired and all are in use, it will return a new unmanaged resource.
 | 
			
		||||
type BoundedCachedCompressors struct {
 | 
			
		||||
	gzipWriters     chan *gzip.Writer
 | 
			
		||||
	gzipReaders     chan *gzip.Reader
 | 
			
		||||
	zlibWriters     chan *zlib.Writer
 | 
			
		||||
	writersCapacity int
 | 
			
		||||
	readersCapacity int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewBoundedCachedCompressors returns a new, with filled cache,  BoundedCachedCompressors.
 | 
			
		||||
func NewBoundedCachedCompressors(writersCapacity, readersCapacity int) *BoundedCachedCompressors {
 | 
			
		||||
	b := &BoundedCachedCompressors{
 | 
			
		||||
		gzipWriters:     make(chan *gzip.Writer, writersCapacity),
 | 
			
		||||
		gzipReaders:     make(chan *gzip.Reader, readersCapacity),
 | 
			
		||||
		zlibWriters:     make(chan *zlib.Writer, writersCapacity),
 | 
			
		||||
		writersCapacity: writersCapacity,
 | 
			
		||||
		readersCapacity: readersCapacity,
 | 
			
		||||
	}
 | 
			
		||||
	for ix := 0; ix < writersCapacity; ix++ {
 | 
			
		||||
		b.gzipWriters <- newGzipWriter()
 | 
			
		||||
		b.zlibWriters <- newZlibWriter()
 | 
			
		||||
	}
 | 
			
		||||
	for ix := 0; ix < readersCapacity; ix++ {
 | 
			
		||||
		b.gzipReaders <- newGzipReader()
 | 
			
		||||
	}
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AcquireGzipWriter returns an resettable *gzip.Writer. Needs to be released.
 | 
			
		||||
func (b *BoundedCachedCompressors) AcquireGzipWriter() *gzip.Writer {
 | 
			
		||||
	var writer *gzip.Writer
 | 
			
		||||
	select {
 | 
			
		||||
	case writer, _ = <-b.gzipWriters:
 | 
			
		||||
	default:
 | 
			
		||||
		// return a new unmanaged one
 | 
			
		||||
		writer = newGzipWriter()
 | 
			
		||||
	}
 | 
			
		||||
	return writer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReleaseGzipWriter accepts a writer (does not have to be one that was cached)
 | 
			
		||||
// only when the cache has room for it. It will ignore it otherwise.
 | 
			
		||||
func (b *BoundedCachedCompressors) ReleaseGzipWriter(w *gzip.Writer) {
 | 
			
		||||
	// forget the unmanaged ones
 | 
			
		||||
	if len(b.gzipWriters) < b.writersCapacity {
 | 
			
		||||
		b.gzipWriters <- w
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AcquireGzipReader returns a *gzip.Reader. Needs to be released.
 | 
			
		||||
func (b *BoundedCachedCompressors) AcquireGzipReader() *gzip.Reader {
 | 
			
		||||
	var reader *gzip.Reader
 | 
			
		||||
	select {
 | 
			
		||||
	case reader, _ = <-b.gzipReaders:
 | 
			
		||||
	default:
 | 
			
		||||
		// return a new unmanaged one
 | 
			
		||||
		reader = newGzipReader()
 | 
			
		||||
	}
 | 
			
		||||
	return reader
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReleaseGzipReader accepts a reader (does not have to be one that was cached)
 | 
			
		||||
// only when the cache has room for it. It will ignore it otherwise.
 | 
			
		||||
func (b *BoundedCachedCompressors) ReleaseGzipReader(r *gzip.Reader) {
 | 
			
		||||
	// forget the unmanaged ones
 | 
			
		||||
	if len(b.gzipReaders) < b.readersCapacity {
 | 
			
		||||
		b.gzipReaders <- r
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AcquireZlibWriter returns an resettable *zlib.Writer. Needs to be released.
 | 
			
		||||
func (b *BoundedCachedCompressors) AcquireZlibWriter() *zlib.Writer {
 | 
			
		||||
	var writer *zlib.Writer
 | 
			
		||||
	select {
 | 
			
		||||
	case writer, _ = <-b.zlibWriters:
 | 
			
		||||
	default:
 | 
			
		||||
		// return a new unmanaged one
 | 
			
		||||
		writer = newZlibWriter()
 | 
			
		||||
	}
 | 
			
		||||
	return writer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReleaseZlibWriter accepts a writer (does not have to be one that was cached)
 | 
			
		||||
// only when the cache has room for it. It will ignore it otherwise.
 | 
			
		||||
func (b *BoundedCachedCompressors) ReleaseZlibWriter(w *zlib.Writer) {
 | 
			
		||||
	// forget the unmanaged ones
 | 
			
		||||
	if len(b.zlibWriters) < b.writersCapacity {
 | 
			
		||||
		b.zlibWriters <- w
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										72
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/compressor_pools.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										72
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/compressor_pools.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,5 +1,9 @@
 | 
			
		||||
package restful
 | 
			
		||||
 | 
			
		||||
// Copyright 2015 Ernest Micklei. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a license
 | 
			
		||||
// that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"compress/gzip"
 | 
			
		||||
@@ -7,12 +11,50 @@ import (
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// GzipWriterPool is used to get reusable zippers.
 | 
			
		||||
// The Get() result must be type asserted to *gzip.Writer.
 | 
			
		||||
var GzipWriterPool = &sync.Pool{
 | 
			
		||||
	New: func() interface{} {
 | 
			
		||||
		return newGzipWriter()
 | 
			
		||||
// SyncPoolCompessors is a CompressorProvider that use the standard sync.Pool.
 | 
			
		||||
type SyncPoolCompessors struct {
 | 
			
		||||
	GzipWriterPool *sync.Pool
 | 
			
		||||
	GzipReaderPool *sync.Pool
 | 
			
		||||
	ZlibWriterPool *sync.Pool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewSyncPoolCompessors returns a new ("empty") SyncPoolCompessors.
 | 
			
		||||
func NewSyncPoolCompessors() *SyncPoolCompessors {
 | 
			
		||||
	return &SyncPoolCompessors{
 | 
			
		||||
		GzipWriterPool: &sync.Pool{
 | 
			
		||||
			New: func() interface{} { return newGzipWriter() },
 | 
			
		||||
		},
 | 
			
		||||
		GzipReaderPool: &sync.Pool{
 | 
			
		||||
			New: func() interface{} { return newGzipReader() },
 | 
			
		||||
		},
 | 
			
		||||
		ZlibWriterPool: &sync.Pool{
 | 
			
		||||
			New: func() interface{} { return newZlibWriter() },
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *SyncPoolCompessors) AcquireGzipWriter() *gzip.Writer {
 | 
			
		||||
	return s.GzipWriterPool.Get().(*gzip.Writer)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *SyncPoolCompessors) ReleaseGzipWriter(w *gzip.Writer) {
 | 
			
		||||
	s.GzipWriterPool.Put(w)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *SyncPoolCompessors) AcquireGzipReader() *gzip.Reader {
 | 
			
		||||
	return s.GzipReaderPool.Get().(*gzip.Reader)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *SyncPoolCompessors) ReleaseGzipReader(r *gzip.Reader) {
 | 
			
		||||
	s.GzipReaderPool.Put(r)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *SyncPoolCompessors) AcquireZlibWriter() *zlib.Writer {
 | 
			
		||||
	return s.ZlibWriterPool.Get().(*zlib.Writer)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *SyncPoolCompessors) ReleaseZlibWriter(w *zlib.Writer) {
 | 
			
		||||
	s.ZlibWriterPool.Put(w)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newGzipWriter() *gzip.Writer {
 | 
			
		||||
@@ -24,17 +66,11 @@ func newGzipWriter() *gzip.Writer {
 | 
			
		||||
	return writer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GzipReaderPool is used to get reusable zippers.
 | 
			
		||||
// The Get() result must be type asserted to *gzip.Reader.
 | 
			
		||||
var GzipReaderPool = &sync.Pool{
 | 
			
		||||
	New: func() interface{} {
 | 
			
		||||
		return newGzipReader()
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newGzipReader() *gzip.Reader {
 | 
			
		||||
	// create with an empty reader (but with GZIP header); it will be replaced before using the gzipReader
 | 
			
		||||
	w := GzipWriterPool.Get().(*gzip.Writer)
 | 
			
		||||
	// we can safely use currentCompressProvider because it is set on package initialization.
 | 
			
		||||
	w := currentCompressorProvider.AcquireGzipWriter()
 | 
			
		||||
	defer currentCompressorProvider.ReleaseGzipWriter(w)
 | 
			
		||||
	b := new(bytes.Buffer)
 | 
			
		||||
	w.Reset(b)
 | 
			
		||||
	w.Flush()
 | 
			
		||||
@@ -46,14 +82,6 @@ func newGzipReader() *gzip.Reader {
 | 
			
		||||
	return reader
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ZlibWriterPool is used to get reusable zippers.
 | 
			
		||||
// The Get() result must be type asserted to *zlib.Writer.
 | 
			
		||||
var ZlibWriterPool = &sync.Pool{
 | 
			
		||||
	New: func() interface{} {
 | 
			
		||||
		return newZlibWriter()
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newZlibWriter() *zlib.Writer {
 | 
			
		||||
	writer, err := zlib.NewWriterLevel(new(bytes.Buffer), gzip.BestSpeed)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										53
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/compressors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/compressors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
package restful
 | 
			
		||||
 | 
			
		||||
// Copyright 2015 Ernest Micklei. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a license
 | 
			
		||||
// that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"compress/gzip"
 | 
			
		||||
	"compress/zlib"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type CompressorProvider interface {
 | 
			
		||||
	// Returns a *gzip.Writer which needs to be released later.
 | 
			
		||||
	// Before using it, call Reset().
 | 
			
		||||
	AcquireGzipWriter() *gzip.Writer
 | 
			
		||||
 | 
			
		||||
	// Releases an aqcuired *gzip.Writer.
 | 
			
		||||
	ReleaseGzipWriter(w *gzip.Writer)
 | 
			
		||||
 | 
			
		||||
	// Returns a *gzip.Reader which needs to be released later.
 | 
			
		||||
	AcquireGzipReader() *gzip.Reader
 | 
			
		||||
 | 
			
		||||
	// Releases an aqcuired *gzip.Reader.
 | 
			
		||||
	ReleaseGzipReader(w *gzip.Reader)
 | 
			
		||||
 | 
			
		||||
	// Returns a *zlib.Writer which needs to be released later.
 | 
			
		||||
	// Before using it, call Reset().
 | 
			
		||||
	AcquireZlibWriter() *zlib.Writer
 | 
			
		||||
 | 
			
		||||
	// Releases an aqcuired *zlib.Writer.
 | 
			
		||||
	ReleaseZlibWriter(w *zlib.Writer)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DefaultCompressorProvider is the actual provider of compressors (zlib or gzip).
 | 
			
		||||
var currentCompressorProvider CompressorProvider
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	currentCompressorProvider = NewSyncPoolCompessors()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CurrentCompressorProvider returns the current CompressorProvider.
 | 
			
		||||
// It is initialized using a SyncPoolCompessors.
 | 
			
		||||
func CurrentCompressorProvider() CompressorProvider {
 | 
			
		||||
	return currentCompressorProvider
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CompressorProvider sets the actual provider of compressors (zlib or gzip).
 | 
			
		||||
func SetCompressorProvider(p CompressorProvider) {
 | 
			
		||||
	if p == nil {
 | 
			
		||||
		panic("cannot set compressor provider to nil")
 | 
			
		||||
	}
 | 
			
		||||
	currentCompressorProvider = p
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/container.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/container.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -272,7 +272,7 @@ func (c Container) Handle(pattern string, handler http.Handler) {
 | 
			
		||||
// HandleWithFilter registers the handler for the given pattern.
 | 
			
		||||
// Container's filter chain is applied for handler.
 | 
			
		||||
// If a handler already exists for pattern, HandleWithFilter panics.
 | 
			
		||||
func (c Container) HandleWithFilter(pattern string, handler http.Handler) {
 | 
			
		||||
func (c *Container) HandleWithFilter(pattern string, handler http.Handler) {
 | 
			
		||||
	f := func(httpResponse http.ResponseWriter, httpRequest *http.Request) {
 | 
			
		||||
		if len(c.containerFilters) == 0 {
 | 
			
		||||
			handler.ServeHTTP(httpResponse, httpRequest)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -162,6 +162,11 @@ Default value is false; it will recover from panics. This has performance implic
 | 
			
		||||
SetCacheReadEntity controls whether the response data ([]byte) is cached such that ReadEntity is repeatable.
 | 
			
		||||
If you expect to read large amounts of payload data, and you do not use this feature, you should set it to false.
 | 
			
		||||
 | 
			
		||||
	restful.SetCompressorProvider(NewBoundedCachedCompressors(20, 20))
 | 
			
		||||
 | 
			
		||||
If content encoding is enabled then the default strategy for getting new gzip/zlib writers and readers is to use a sync.Pool.
 | 
			
		||||
Because writers are expensive structures, performance is even more improved when using a preloaded cache. You can also inject your own implementation.
 | 
			
		||||
 | 
			
		||||
Trouble shooting
 | 
			
		||||
 | 
			
		||||
This package has the means to produce detail logging of the complete Http request matching process and filter invocation.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										151
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/entity_accessors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/entity_accessors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,151 @@
 | 
			
		||||
package restful
 | 
			
		||||
 | 
			
		||||
// Copyright 2015 Ernest Micklei. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a license
 | 
			
		||||
// that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"encoding/xml"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// EntityReaderWriter can read and write values using an encoding such as JSON,XML.
 | 
			
		||||
type EntityReaderWriter interface {
 | 
			
		||||
	// Read a serialized version of the value from the request.
 | 
			
		||||
	// The Request may have a decompressing reader. Depends on Content-Encoding.
 | 
			
		||||
	Read(req *Request, v interface{}) error
 | 
			
		||||
 | 
			
		||||
	// Write a serialized version of the value on the response.
 | 
			
		||||
	// The Response may have a compressing writer. Depends on Accept-Encoding.
 | 
			
		||||
	// status should be a valid Http Status code
 | 
			
		||||
	Write(resp *Response, status int, v interface{}) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// entityAccessRegistry is a singleton
 | 
			
		||||
var entityAccessRegistry = &entityReaderWriters{
 | 
			
		||||
	protection: new(sync.RWMutex),
 | 
			
		||||
	accessors:  map[string]EntityReaderWriter{},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// entityReaderWriters associates MIME to an EntityReaderWriter
 | 
			
		||||
type entityReaderWriters struct {
 | 
			
		||||
	protection *sync.RWMutex
 | 
			
		||||
	accessors  map[string]EntityReaderWriter
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	RegisterEntityAccessor(MIME_JSON, entityJSONAccess{ContentType: MIME_JSON})
 | 
			
		||||
	RegisterEntityAccessor(MIME_XML, entityXMLAccess{ContentType: MIME_XML})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RegisterEntityAccessor add/overrides the ReaderWriter for encoding content with this MIME type.
 | 
			
		||||
func RegisterEntityAccessor(mime string, erw EntityReaderWriter) {
 | 
			
		||||
	entityAccessRegistry.protection.Lock()
 | 
			
		||||
	defer entityAccessRegistry.protection.Unlock()
 | 
			
		||||
	entityAccessRegistry.accessors[mime] = erw
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AccessorAt returns the registered ReaderWriter for this MIME type.
 | 
			
		||||
func (r *entityReaderWriters) AccessorAt(mime string) (EntityReaderWriter, bool) {
 | 
			
		||||
	r.protection.RLock()
 | 
			
		||||
	defer r.protection.RUnlock()
 | 
			
		||||
	er, ok := r.accessors[mime]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		// retry with reverse lookup
 | 
			
		||||
		// more expensive but we are in an exceptional situation anyway
 | 
			
		||||
		for k, v := range r.accessors {
 | 
			
		||||
			if strings.Contains(mime, k) {
 | 
			
		||||
				return v, true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return er, ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// entityXMLAccess is a EntityReaderWriter for XML encoding
 | 
			
		||||
type entityXMLAccess struct {
 | 
			
		||||
	// This is used for setting the Content-Type header when writing
 | 
			
		||||
	ContentType string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Read unmarshalls the value from XML
 | 
			
		||||
func (e entityXMLAccess) Read(req *Request, v interface{}) error {
 | 
			
		||||
	return xml.NewDecoder(req.Request.Body).Decode(v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Write marshalls the value to JSON and set the Content-Type Header.
 | 
			
		||||
func (e entityXMLAccess) Write(resp *Response, status int, v interface{}) error {
 | 
			
		||||
	return writeXML(resp, status, e.ContentType, v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// writeXML marshalls the value to JSON and set the Content-Type Header.
 | 
			
		||||
func writeXML(resp *Response, status int, contentType string, v interface{}) error {
 | 
			
		||||
	if v == nil {
 | 
			
		||||
		resp.WriteHeader(status)
 | 
			
		||||
		// do not write a nil representation
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if resp.prettyPrint {
 | 
			
		||||
		// pretty output must be created and written explicitly
 | 
			
		||||
		output, err := xml.MarshalIndent(v, " ", " ")
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		resp.Header().Set(HEADER_ContentType, contentType)
 | 
			
		||||
		resp.WriteHeader(status)
 | 
			
		||||
		_, err = resp.Write([]byte(xml.Header))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		_, err = resp.Write(output)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	// not-so-pretty
 | 
			
		||||
	resp.Header().Set(HEADER_ContentType, contentType)
 | 
			
		||||
	resp.WriteHeader(status)
 | 
			
		||||
	return xml.NewEncoder(resp).Encode(v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// entityJSONAccess is a EntityReaderWriter for JSON encoding
 | 
			
		||||
type entityJSONAccess struct {
 | 
			
		||||
	// This is used for setting the Content-Type header when writing
 | 
			
		||||
	ContentType string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Read unmarshalls the value from JSON
 | 
			
		||||
func (e entityJSONAccess) Read(req *Request, v interface{}) error {
 | 
			
		||||
	decoder := json.NewDecoder(req.Request.Body)
 | 
			
		||||
	decoder.UseNumber()
 | 
			
		||||
	return decoder.Decode(v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Write marshalls the value to JSON and set the Content-Type Header.
 | 
			
		||||
func (e entityJSONAccess) Write(resp *Response, status int, v interface{}) error {
 | 
			
		||||
	return writeJSON(resp, status, e.ContentType, v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// write marshalls the value to JSON and set the Content-Type Header.
 | 
			
		||||
func writeJSON(resp *Response, status int, contentType string, v interface{}) error {
 | 
			
		||||
	if v == nil {
 | 
			
		||||
		resp.WriteHeader(status)
 | 
			
		||||
		// do not write a nil representation
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if resp.prettyPrint {
 | 
			
		||||
		// pretty output must be created and written explicitly
 | 
			
		||||
		output, err := json.MarshalIndent(v, " ", " ")
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		resp.Header().Set(HEADER_ContentType, contentType)
 | 
			
		||||
		resp.WriteHeader(status)
 | 
			
		||||
		_, err = resp.Write(output)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	// not-so-pretty
 | 
			
		||||
	resp.Header().Set(HEADER_ContentType, contentType)
 | 
			
		||||
	resp.WriteHeader(status)
 | 
			
		||||
	return json.NewEncoder(resp).Encode(v)
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
application: datastore-example
 | 
			
		||||
application: <your_app_id>
 | 
			
		||||
version: 1
 | 
			
		||||
runtime: go
 | 
			
		||||
api_version: go1
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,11 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"appengine"
 | 
			
		||||
	"appengine/datastore"
 | 
			
		||||
	"appengine/user"
 | 
			
		||||
	"github.com/emicklei/go-restful"
 | 
			
		||||
	"github.com/emicklei/go-restful/swagger"
 | 
			
		||||
	"google.golang.com/appengine"
 | 
			
		||||
	"google.golang.com/appengine/datastore"
 | 
			
		||||
	"google.golang.com/appengine/user"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,10 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"appengine"
 | 
			
		||||
	"appengine/memcache"
 | 
			
		||||
	"github.com/emicklei/go-restful"
 | 
			
		||||
	"github.com/emicklei/go-restful/swagger"
 | 
			
		||||
	"google.golang.com/appengine"
 | 
			
		||||
	"google.golang.com/appengine/memcache"
 | 
			
		||||
	"net/http"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/examples/restful-CORS-filter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/examples/restful-CORS-filter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -53,7 +53,7 @@ func main() {
 | 
			
		||||
	// Add container filter to enable CORS
 | 
			
		||||
	cors := restful.CrossOriginResourceSharing{
 | 
			
		||||
		ExposeHeaders:  []string{"X-My-Header"},
 | 
			
		||||
		AllowedHeaders: []string{"Content-Type"},
 | 
			
		||||
		AllowedHeaders: []string{"Content-Type", "Accept"},
 | 
			
		||||
		CookiesAllowed: false,
 | 
			
		||||
		Container:      wsContainer}
 | 
			
		||||
	wsContainer.Filter(cors.Filter)
 | 
			
		||||
 
 | 
			
		||||
@@ -100,8 +100,7 @@ func (u *UserResource) createUser(request *restful.Request, response *restful.Re
 | 
			
		||||
	}
 | 
			
		||||
	usr.Id = strconv.Itoa(len(u.users) + 1) // simple id generation
 | 
			
		||||
	u.users[usr.Id] = *usr
 | 
			
		||||
	response.WriteHeader(http.StatusCreated)
 | 
			
		||||
	response.WriteEntity(usr)
 | 
			
		||||
	response.WriteHeaderAndEntity(http.StatusCreated, usr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PUT http://localhost:8080/users/1
 | 
			
		||||
 
 | 
			
		||||
@@ -102,8 +102,7 @@ func (u *UserService) createUser(request *restful.Request, response *restful.Res
 | 
			
		||||
	err := request.ReadEntity(&usr)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		u.users[usr.Id] = usr
 | 
			
		||||
		response.WriteHeader(http.StatusCreated)
 | 
			
		||||
		response.WriteEntity(usr)
 | 
			
		||||
		response.WriteHeaderAndEntity(http.StatusCreated, usr)
 | 
			
		||||
	} else {
 | 
			
		||||
		response.WriteError(http.StatusInternalServerError, err)
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/log/log.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/log/log.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -15,7 +15,7 @@ var Logger StdLogger
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	// default Logger
 | 
			
		||||
	SetLogger(stdlog.New(os.Stdout, "[restful] ", stdlog.LstdFlags|stdlog.Lshortfile))
 | 
			
		||||
	SetLogger(stdlog.New(os.Stderr, "[restful] ", stdlog.LstdFlags|stdlog.Lshortfile))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SetLogger(customLogger StdLogger) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/options_filter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/options_filter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -8,7 +8,8 @@ import "strings"
 | 
			
		||||
 | 
			
		||||
// OPTIONSFilter is a filter function that inspects the Http Request for the OPTIONS method
 | 
			
		||||
// and provides the response with a set of allowed methods for the request URL Path.
 | 
			
		||||
// As for any filter, you can also install it for a particular WebService within a Container
 | 
			
		||||
// As for any filter, you can also install it for a particular WebService within a Container.
 | 
			
		||||
// Note: this filter is not needed when using CrossOriginResourceSharing (for CORS).
 | 
			
		||||
func (c *Container) OPTIONSFilter(req *Request, resp *Response, chain *FilterChain) {
 | 
			
		||||
	if "OPTIONS" != req.Request.Method {
 | 
			
		||||
		chain.ProcessFilter(req, resp)
 | 
			
		||||
@@ -19,6 +20,7 @@ func (c *Container) OPTIONSFilter(req *Request, resp *Response, chain *FilterCha
 | 
			
		||||
 | 
			
		||||
// OPTIONSFilter is a filter function that inspects the Http Request for the OPTIONS method
 | 
			
		||||
// and provides the response with a set of allowed methods for the request URL Path.
 | 
			
		||||
// Note: this filter is not needed when using CrossOriginResourceSharing (for CORS).
 | 
			
		||||
func OPTIONSFilter() FilterFunction {
 | 
			
		||||
	return DefaultContainer.OPTIONSFilter
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/parameter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/parameter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -30,7 +30,7 @@ type Parameter struct {
 | 
			
		||||
// ParameterData represents the state of a Parameter.
 | 
			
		||||
// It is made public to make it accessible to e.g. the Swagger package.
 | 
			
		||||
type ParameterData struct {
 | 
			
		||||
	Name, Description, DataType string
 | 
			
		||||
	Name, Description, DataType, DataFormat string
 | 
			
		||||
	Kind                                    int
 | 
			
		||||
	Required                                bool
 | 
			
		||||
	AllowableValues                         map[string]string
 | 
			
		||||
@@ -95,6 +95,12 @@ func (p *Parameter) DataType(typeName string) *Parameter {
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DataFormat sets the dataFormat field for Swagger UI
 | 
			
		||||
func (p *Parameter) DataFormat(formatName string) *Parameter {
 | 
			
		||||
	p.data.DataFormat = formatName
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DefaultValue sets the default value field and returns the receiver
 | 
			
		||||
func (p *Parameter) DefaultValue(stringRepresentation string) *Parameter {
 | 
			
		||||
	p.data.DefaultValue = stringRepresentation
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										62
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/request.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										62
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/request.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -6,14 +6,9 @@ package restful
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"compress/gzip"
 | 
			
		||||
	"compress/zlib"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"encoding/xml"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var defaultRequestContentType string
 | 
			
		||||
@@ -81,62 +76,43 @@ func (r *Request) HeaderParameter(name string) string {
 | 
			
		||||
	return r.Request.Header.Get(name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReadEntity checks the Accept header and reads the content into the entityPointer
 | 
			
		||||
// May be called multiple times in the request-response flow
 | 
			
		||||
// ReadEntity checks the Accept header and reads the content into the entityPointer.
 | 
			
		||||
func (r *Request) ReadEntity(entityPointer interface{}) (err error) {
 | 
			
		||||
	defer r.Request.Body.Close()
 | 
			
		||||
	contentType := r.Request.Header.Get(HEADER_ContentType)
 | 
			
		||||
	contentEncoding := r.Request.Header.Get(HEADER_ContentEncoding)
 | 
			
		||||
	if doCacheReadEntityBytes {
 | 
			
		||||
		return r.cachingReadEntity(contentType, contentEncoding, entityPointer)
 | 
			
		||||
	}
 | 
			
		||||
	// unmarshall directly from request Body
 | 
			
		||||
	return r.decodeEntity(r.Request.Body, contentType, contentEncoding, entityPointer)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *Request) cachingReadEntity(contentType string, contentEncoding string, entityPointer interface{}) (err error) {
 | 
			
		||||
	var buffer []byte
 | 
			
		||||
	if r.bodyContent != nil {
 | 
			
		||||
		buffer = *r.bodyContent
 | 
			
		||||
	} else {
 | 
			
		||||
		buffer, err = ioutil.ReadAll(r.Request.Body)
 | 
			
		||||
	// OLD feature, cache the body for reads
 | 
			
		||||
	if doCacheReadEntityBytes {
 | 
			
		||||
		if r.bodyContent == nil {
 | 
			
		||||
			data, err := ioutil.ReadAll(r.Request.Body)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		r.bodyContent = &buffer
 | 
			
		||||
			r.bodyContent = &data
 | 
			
		||||
		}
 | 
			
		||||
		r.Request.Body = ioutil.NopCloser(bytes.NewReader(*r.bodyContent))
 | 
			
		||||
	}
 | 
			
		||||
	return r.decodeEntity(bytes.NewReader(buffer), contentType, contentEncoding, entityPointer)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *Request) decodeEntity(reader io.Reader, contentType string, contentEncoding string, entityPointer interface{}) (err error) {
 | 
			
		||||
	entityReader := reader
 | 
			
		||||
 | 
			
		||||
	// check if the request body needs decompression
 | 
			
		||||
	if ENCODING_GZIP == contentEncoding {
 | 
			
		||||
		gzipReader := GzipReaderPool.Get().(*gzip.Reader)
 | 
			
		||||
		gzipReader.Reset(reader)
 | 
			
		||||
		entityReader = gzipReader
 | 
			
		||||
		gzipReader := currentCompressorProvider.AcquireGzipReader()
 | 
			
		||||
		defer currentCompressorProvider.ReleaseGzipReader(gzipReader)
 | 
			
		||||
		gzipReader.Reset(r.Request.Body)
 | 
			
		||||
		r.Request.Body = gzipReader
 | 
			
		||||
	} else if ENCODING_DEFLATE == contentEncoding {
 | 
			
		||||
		zlibReader, err := zlib.NewReader(reader)
 | 
			
		||||
		zlibReader, err := zlib.NewReader(r.Request.Body)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		entityReader = zlibReader
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// decode JSON
 | 
			
		||||
	if strings.Contains(contentType, MIME_JSON) || MIME_JSON == defaultRequestContentType {
 | 
			
		||||
		decoder := json.NewDecoder(entityReader)
 | 
			
		||||
		decoder.UseNumber()
 | 
			
		||||
		return decoder.Decode(entityPointer)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// decode XML
 | 
			
		||||
	if strings.Contains(contentType, MIME_XML) || MIME_XML == defaultRequestContentType {
 | 
			
		||||
		return xml.NewDecoder(entityReader).Decode(entityPointer)
 | 
			
		||||
		r.Request.Body = zlibReader
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// lookup the EntityReader
 | 
			
		||||
	entityReader, ok := entityAccessRegistry.AccessorAt(contentType)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return NewError(http.StatusBadRequest, "Unable to unmarshal content of type:"+contentType)
 | 
			
		||||
	}
 | 
			
		||||
	return entityReader.Read(r, entityPointer)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetAttribute adds or replaces the attribute with the given value.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										177
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/response.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										177
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/response.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -5,8 +5,7 @@ package restful
 | 
			
		||||
// that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"encoding/xml"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
@@ -14,9 +13,7 @@ import (
 | 
			
		||||
// DEPRECATED, use DefaultResponseContentType(mime)
 | 
			
		||||
var DefaultResponseMimeType string
 | 
			
		||||
 | 
			
		||||
//PrettyPrintResponses controls the indentation feature of XML and JSON
 | 
			
		||||
//serialization in the response methods WriteEntity, WriteAsJson, and
 | 
			
		||||
//WriteAsXml.
 | 
			
		||||
//PrettyPrintResponses controls the indentation feature of XML and JSON serialization
 | 
			
		||||
var PrettyPrintResponses = true
 | 
			
		||||
 | 
			
		||||
// Response is a wrapper on the actual http ResponseWriter
 | 
			
		||||
@@ -36,8 +33,7 @@ func NewResponse(httpWriter http.ResponseWriter) *Response {
 | 
			
		||||
	return &Response{httpWriter, "", []string{}, http.StatusOK, 0, PrettyPrintResponses, nil} // empty content-types
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// If Accept header matching fails, fall back to this type, otherwise
 | 
			
		||||
// a "406: Not Acceptable" response is returned.
 | 
			
		||||
// If Accept header matching fails, fall back to this type.
 | 
			
		||||
// Valid values are restful.MIME_JSON and restful.MIME_XML
 | 
			
		||||
// Example:
 | 
			
		||||
// 	restful.DefaultResponseContentType(restful.MIME_JSON)
 | 
			
		||||
@@ -68,117 +64,99 @@ func (r *Response) SetRequestAccepts(mime string) {
 | 
			
		||||
	r.requestAccept = mime
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteEntity marshals the value using the representation denoted by the Accept Header (XML or JSON)
 | 
			
		||||
// If no Accept header is specified (or */*) then return the Content-Type as specified by the first in the Route.Produces.
 | 
			
		||||
// If an Accept header is specified then return the Content-Type as specified by the first in the Route.Produces that is matched with the Accept header.
 | 
			
		||||
// If the value is nil then nothing is written. You may want to call WriteHeader(http.StatusNotFound) instead.
 | 
			
		||||
// Current implementation ignores any q-parameters in the Accept Header.
 | 
			
		||||
func (r *Response) WriteEntity(value interface{}) error {
 | 
			
		||||
	if value == nil { // do not write a nil representation
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
// EntityWriter returns the registered EntityWriter that the entity (requested resource)
 | 
			
		||||
// can write according to what the request wants (Accept) and what the Route can produce or what the restful defaults say.
 | 
			
		||||
// If called before WriteEntity and WriteHeader then a false return value can be used to write a 406: Not Acceptable.
 | 
			
		||||
func (r *Response) EntityWriter() (EntityReaderWriter, bool) {
 | 
			
		||||
	for _, qualifiedMime := range strings.Split(r.requestAccept, ",") {
 | 
			
		||||
		mime := strings.Trim(strings.Split(qualifiedMime, ";")[0], " ")
 | 
			
		||||
		if 0 == len(mime) || mime == "*/*" {
 | 
			
		||||
			for _, each := range r.routeProduces {
 | 
			
		||||
				if MIME_JSON == each {
 | 
			
		||||
					return r.WriteAsJson(value)
 | 
			
		||||
					return entityAccessRegistry.AccessorAt(MIME_JSON)
 | 
			
		||||
				}
 | 
			
		||||
				if MIME_XML == each {
 | 
			
		||||
					return r.WriteAsXml(value)
 | 
			
		||||
					return entityAccessRegistry.AccessorAt(MIME_XML)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} else { // mime is not blank; see if we have a match in Produces
 | 
			
		||||
			for _, each := range r.routeProduces {
 | 
			
		||||
				if mime == each {
 | 
			
		||||
					if MIME_JSON == each {
 | 
			
		||||
						return r.WriteAsJson(value)
 | 
			
		||||
						return entityAccessRegistry.AccessorAt(MIME_JSON)
 | 
			
		||||
					}
 | 
			
		||||
					if MIME_XML == each {
 | 
			
		||||
						return r.WriteAsXml(value)
 | 
			
		||||
						return entityAccessRegistry.AccessorAt(MIME_XML)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	writer, ok := entityAccessRegistry.AccessorAt(r.requestAccept)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		// if not registered then fallback to the defaults (if set)
 | 
			
		||||
		if DefaultResponseMimeType == MIME_JSON {
 | 
			
		||||
		return r.WriteAsJson(value)
 | 
			
		||||
	} else if DefaultResponseMimeType == MIME_XML {
 | 
			
		||||
		return r.WriteAsXml(value)
 | 
			
		||||
	} else {
 | 
			
		||||
			return entityAccessRegistry.AccessorAt(MIME_JSON)
 | 
			
		||||
		}
 | 
			
		||||
		if DefaultResponseMimeType == MIME_XML {
 | 
			
		||||
			return entityAccessRegistry.AccessorAt(MIME_XML)
 | 
			
		||||
		}
 | 
			
		||||
		if trace {
 | 
			
		||||
			traceLogger.Printf("mismatch in mime-types and no defaults; (http)Accept=%v,(route)Produces=%v\n", r.requestAccept, r.routeProduces)
 | 
			
		||||
		}
 | 
			
		||||
		r.WriteHeader(http.StatusNotAcceptable) // for recording only
 | 
			
		||||
		r.ResponseWriter.WriteHeader(http.StatusNotAcceptable)
 | 
			
		||||
		if _, err := r.Write([]byte("406: Not Acceptable")); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
			traceLogger.Printf("no registered EntityReaderWriter found for %s", r.requestAccept)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return writer, ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteEntity calls WriteHeaderAndEntity with Http Status OK (200)
 | 
			
		||||
func (r *Response) WriteEntity(value interface{}) error {
 | 
			
		||||
	return r.WriteHeaderAndEntity(http.StatusOK, value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteHeaderAndEntity marshals the value using the representation denoted by the Accept Header and the registered EntityWriters.
 | 
			
		||||
// If no Accept header is specified (or */*) then respond with the Content-Type as specified by the first in the Route.Produces.
 | 
			
		||||
// If an Accept header is specified then respond with the Content-Type as specified by the first in the Route.Produces that is matched with the Accept header.
 | 
			
		||||
// If the value is nil then no response is send except for the Http status. You may want to call WriteHeader(http.StatusNotFound) instead.
 | 
			
		||||
// If there is no writer available that can represent the value in the requested MIME type then Http Status NotAcceptable is written.
 | 
			
		||||
// Current implementation ignores any q-parameters in the Accept Header.
 | 
			
		||||
// Returns an error if the value could not be written on the response.
 | 
			
		||||
func (r *Response) WriteHeaderAndEntity(status int, value interface{}) error {
 | 
			
		||||
	writer, ok := r.EntityWriter()
 | 
			
		||||
	if !ok {
 | 
			
		||||
		r.WriteHeader(http.StatusNotAcceptable)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return writer.Write(r, status, value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteAsXml is a convenience method for writing a value in xml (requires Xml tags on the value)
 | 
			
		||||
// It uses the standard encoding/xml package for marshalling the valuel ; not using a registered EntityReaderWriter.
 | 
			
		||||
func (r *Response) WriteAsXml(value interface{}) error {
 | 
			
		||||
	var output []byte
 | 
			
		||||
	var err error
 | 
			
		||||
 | 
			
		||||
	if value == nil { // do not write a nil representation
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if r.prettyPrint {
 | 
			
		||||
		output, err = xml.MarshalIndent(value, " ", " ")
 | 
			
		||||
	} else {
 | 
			
		||||
		output, err = xml.Marshal(value)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return r.WriteError(http.StatusInternalServerError, err)
 | 
			
		||||
	}
 | 
			
		||||
	r.Header().Set(HEADER_ContentType, MIME_XML)
 | 
			
		||||
	if r.statusCode > 0 { // a WriteHeader was intercepted
 | 
			
		||||
		r.ResponseWriter.WriteHeader(r.statusCode)
 | 
			
		||||
	}
 | 
			
		||||
	_, err = r.Write([]byte(xml.Header))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if _, err = r.Write(output); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
	return writeXML(r, http.StatusOK, MIME_XML, value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteAsJson is a convenience method for writing a value in json
 | 
			
		||||
// WriteHeaderAndXml is a convenience method for writing a status and value in xml (requires Xml tags on the value)
 | 
			
		||||
// It uses the standard encoding/xml package for marshalling the valuel ; not using a registered EntityReaderWriter.
 | 
			
		||||
func (r *Response) WriteHeaderAndXml(status int, value interface{}) error {
 | 
			
		||||
	return writeXML(r, status, MIME_XML, value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteAsJson is a convenience method for writing a value in json.
 | 
			
		||||
// It uses the standard encoding/json package for marshalling the valuel ; not using a registered EntityReaderWriter.
 | 
			
		||||
func (r *Response) WriteAsJson(value interface{}) error {
 | 
			
		||||
	return r.WriteJson(value, MIME_JSON) // no charset
 | 
			
		||||
	return writeJSON(r, http.StatusOK, MIME_JSON, value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteJson is a convenience method for writing a value in Json with a given Content-Type
 | 
			
		||||
// WriteJson is a convenience method for writing a value in Json with a given Content-Type.
 | 
			
		||||
// It uses the standard encoding/json package for marshalling the valuel ; not using a registered EntityReaderWriter.
 | 
			
		||||
func (r *Response) WriteJson(value interface{}, contentType string) error {
 | 
			
		||||
	var output []byte
 | 
			
		||||
	var err error
 | 
			
		||||
	return writeJSON(r, http.StatusOK, contentType, value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	if value == nil { // do not write a nil representation
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if r.prettyPrint {
 | 
			
		||||
		output, err = json.MarshalIndent(value, " ", " ")
 | 
			
		||||
	} else {
 | 
			
		||||
		output, err = json.Marshal(value)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return r.WriteErrorString(http.StatusInternalServerError, err.Error())
 | 
			
		||||
	}
 | 
			
		||||
	r.Header().Set(HEADER_ContentType, contentType)
 | 
			
		||||
	if r.statusCode > 0 { // a WriteHeader was intercepted
 | 
			
		||||
		r.ResponseWriter.WriteHeader(r.statusCode)
 | 
			
		||||
	}
 | 
			
		||||
	if _, err = r.Write(output); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
// WriteHeaderAndJson is a convenience method for writing the status and a value in Json with a given Content-Type.
 | 
			
		||||
// It uses the standard encoding/json package for marshalling the value ; not using a registered EntityReaderWriter.
 | 
			
		||||
func (r *Response) WriteHeaderAndJson(status int, value interface{}, contentType string) error {
 | 
			
		||||
	return writeJSON(r, status, contentType, value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteError write the http status and the error string on the response.
 | 
			
		||||
@@ -187,16 +165,19 @@ func (r *Response) WriteError(httpStatus int, err error) error {
 | 
			
		||||
	return r.WriteErrorString(httpStatus, err.Error())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteServiceError is a convenience method for a responding with a ServiceError and a status
 | 
			
		||||
// WriteServiceError is a convenience method for a responding with a status and a ServiceError
 | 
			
		||||
func (r *Response) WriteServiceError(httpStatus int, err ServiceError) error {
 | 
			
		||||
	r.WriteHeader(httpStatus) // for recording only
 | 
			
		||||
	return r.WriteEntity(err)
 | 
			
		||||
	r.err = err
 | 
			
		||||
	return r.WriteHeaderAndEntity(httpStatus, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteErrorString is a convenience method for an error status with the actual error
 | 
			
		||||
func (r *Response) WriteErrorString(status int, errorReason string) error {
 | 
			
		||||
	r.statusCode = status // for recording only
 | 
			
		||||
	r.ResponseWriter.WriteHeader(status)
 | 
			
		||||
func (r *Response) WriteErrorString(httpStatus int, errorReason string) error {
 | 
			
		||||
	if r.err == nil {
 | 
			
		||||
		// if not called from WriteError
 | 
			
		||||
		r.err = errors.New(errorReason)
 | 
			
		||||
	}
 | 
			
		||||
	r.WriteHeader(httpStatus)
 | 
			
		||||
	if _, err := r.Write([]byte(errorReason)); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
@@ -204,31 +185,13 @@ func (r *Response) WriteErrorString(status int, errorReason string) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteHeader is overridden to remember the Status Code that has been written.
 | 
			
		||||
// Note that using this method, the status value is only written when
 | 
			
		||||
//  calling WriteEntity,
 | 
			
		||||
//  or directly calling WriteAsXml or WriteAsJson,
 | 
			
		||||
//  or if the status is one for which no response is allowed:
 | 
			
		||||
//
 | 
			
		||||
//  202 = http.StatusAccepted
 | 
			
		||||
//  204 = http.StatusNoContent
 | 
			
		||||
//  206 = http.StatusPartialContent
 | 
			
		||||
//  304 = http.StatusNotModified
 | 
			
		||||
//
 | 
			
		||||
// If this behavior does not fit your need then you can write to the underlying response, such as:
 | 
			
		||||
//   response.ResponseWriter.WriteHeader(http.StatusAccepted)
 | 
			
		||||
// Changes to the Header of the response have no effect after this.
 | 
			
		||||
func (r *Response) WriteHeader(httpStatus int) {
 | 
			
		||||
	r.statusCode = httpStatus
 | 
			
		||||
	// if 202,204,206,304 then WriteEntity will not be called so we need to pass this code
 | 
			
		||||
	if http.StatusNoContent == httpStatus ||
 | 
			
		||||
		http.StatusNotModified == httpStatus ||
 | 
			
		||||
		http.StatusPartialContent == httpStatus ||
 | 
			
		||||
		http.StatusAccepted == httpStatus {
 | 
			
		||||
	r.ResponseWriter.WriteHeader(httpStatus)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StatusCode returns the code that has been written using WriteHeader.
 | 
			
		||||
// If WriteHeader, WriteEntity or WriteAsXml has not been called (yet) then return 200 OK.
 | 
			
		||||
func (r Response) StatusCode() int {
 | 
			
		||||
	if 0 == r.statusCode {
 | 
			
		||||
		// no status code has been written yet; assume OK
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/swagger/CHANGES.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/swagger/CHANGES.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,5 +1,9 @@
 | 
			
		||||
Change history of swagger
 | 
			
		||||
=
 | 
			
		||||
2015-10-16
 | 
			
		||||
- add type override mechanism for swagger models (MR 254, nathanejohnson)
 | 
			
		||||
- replace uses of wildcard in generated apidocs (issue 251)
 | 
			
		||||
 | 
			
		||||
2015-05-25
 | 
			
		||||
- (api break) changed the type of Properties in Model
 | 
			
		||||
- (api break) changed the type of Models in ApiDeclaration
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/swagger/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/swagger/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -29,4 +29,6 @@ type Config struct {
 | 
			
		||||
	ApiVersion string
 | 
			
		||||
	// If set then call this handler after building the complete ApiDeclaration Map
 | 
			
		||||
	PostBuildHandler PostBuildDeclarationMapFunc
 | 
			
		||||
	// Swagger global info struct
 | 
			
		||||
	Info Info
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/swagger/model_builder.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/swagger/model_builder.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -132,9 +132,11 @@ func (b modelBuilder) buildProperty(field reflect.StructField, model *Model, mod
 | 
			
		||||
		modelDescription = tag
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fieldType := field.Type
 | 
			
		||||
 | 
			
		||||
	prop.setPropertyMetadata(field)
 | 
			
		||||
	if prop.Type != nil {
 | 
			
		||||
		return jsonName, modelDescription, prop
 | 
			
		||||
	}
 | 
			
		||||
	fieldType := field.Type
 | 
			
		||||
 | 
			
		||||
	// check if type is doing its own marshalling
 | 
			
		||||
	marshalerType := reflect.TypeOf((*json.Marshaler)(nil)).Elem()
 | 
			
		||||
@@ -212,8 +214,12 @@ func hasNamedJSONTag(field reflect.StructField) bool {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b modelBuilder) buildStructTypeProperty(field reflect.StructField, jsonName string, model *Model) (nameJson string, prop ModelProperty) {
 | 
			
		||||
	fieldType := field.Type
 | 
			
		||||
	prop.setPropertyMetadata(field)
 | 
			
		||||
	// Check for type override in tag
 | 
			
		||||
	if prop.Type != nil {
 | 
			
		||||
		return jsonName, prop
 | 
			
		||||
	}
 | 
			
		||||
	fieldType := field.Type
 | 
			
		||||
	// check for anonymous
 | 
			
		||||
	if len(fieldType.Name()) == 0 {
 | 
			
		||||
		// anonymous
 | 
			
		||||
@@ -263,8 +269,12 @@ func (b modelBuilder) buildStructTypeProperty(field reflect.StructField, jsonNam
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b modelBuilder) buildArrayTypeProperty(field reflect.StructField, jsonName, modelName string) (nameJson string, prop ModelProperty) {
 | 
			
		||||
	fieldType := field.Type
 | 
			
		||||
	// check for type override in tags
 | 
			
		||||
	prop.setPropertyMetadata(field)
 | 
			
		||||
	if prop.Type != nil {
 | 
			
		||||
		return jsonName, prop
 | 
			
		||||
	}
 | 
			
		||||
	fieldType := field.Type
 | 
			
		||||
	var pType = "array"
 | 
			
		||||
	prop.Type = &pType
 | 
			
		||||
	elemTypeName := b.getElementTypeName(modelName, jsonName, fieldType.Elem())
 | 
			
		||||
@@ -284,8 +294,12 @@ func (b modelBuilder) buildArrayTypeProperty(field reflect.StructField, jsonName
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b modelBuilder) buildPointerTypeProperty(field reflect.StructField, jsonName, modelName string) (nameJson string, prop ModelProperty) {
 | 
			
		||||
	fieldType := field.Type
 | 
			
		||||
	prop.setPropertyMetadata(field)
 | 
			
		||||
	// Check for type override in tags
 | 
			
		||||
	if prop.Type != nil {
 | 
			
		||||
		return jsonName, prop
 | 
			
		||||
	}
 | 
			
		||||
	fieldType := field.Type
 | 
			
		||||
 | 
			
		||||
	// override type of pointer to list-likes
 | 
			
		||||
	if fieldType.Elem().Kind() == reflect.Slice || fieldType.Elem().Kind() == reflect.Array {
 | 
			
		||||
@@ -338,7 +352,7 @@ func (b modelBuilder) keyFrom(st reflect.Type) string {
 | 
			
		||||
 | 
			
		||||
// see also https://golang.org/ref/spec#Numeric_types
 | 
			
		||||
func (b modelBuilder) isPrimitiveType(modelName string) bool {
 | 
			
		||||
	return strings.Contains("uint8 uint16 uint32 uint64 int int8 int16 int32 int64 float32 float64 bool string byte rune time.Time", modelName)
 | 
			
		||||
	return strings.Contains("uint uint8 uint16 uint32 uint64 int int8 int16 int32 int64 float32 float64 bool string byte rune time.Time", modelName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// jsonNameOfField returns the name of the field as it should appear in JSON format
 | 
			
		||||
@@ -359,6 +373,7 @@ func (b modelBuilder) jsonNameOfField(field reflect.StructField) string {
 | 
			
		||||
// see also http://json-schema.org/latest/json-schema-core.html#anchor8
 | 
			
		||||
func (b modelBuilder) jsonSchemaType(modelName string) string {
 | 
			
		||||
	schemaMap := map[string]string{
 | 
			
		||||
		"uint":   "integer",
 | 
			
		||||
		"uint8":  "integer",
 | 
			
		||||
		"uint16": "integer",
 | 
			
		||||
		"uint32": "integer",
 | 
			
		||||
@@ -389,6 +404,7 @@ func (b modelBuilder) jsonSchemaFormat(modelName string) string {
 | 
			
		||||
		"int32":      "int32",
 | 
			
		||||
		"int64":      "int64",
 | 
			
		||||
		"byte":       "byte",
 | 
			
		||||
		"uint":       "integer",
 | 
			
		||||
		"uint8":      "byte",
 | 
			
		||||
		"float64":    "double",
 | 
			
		||||
		"float32":    "float",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/swagger/model_property_ext.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/swagger/model_property_ext.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -31,6 +31,12 @@ func (prop *ModelProperty) setMaximum(field reflect.StructField) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (prop *ModelProperty) setType(field reflect.StructField) {
 | 
			
		||||
	if tag := field.Tag.Get("type"); tag != "" {
 | 
			
		||||
		prop.Type = &tag
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (prop *ModelProperty) setMinimum(field reflect.StructField) {
 | 
			
		||||
	if tag := field.Tag.Get("minimum"); tag != "" {
 | 
			
		||||
		prop.Minimum = tag
 | 
			
		||||
@@ -56,4 +62,5 @@ func (prop *ModelProperty) setPropertyMetadata(field reflect.StructField) {
 | 
			
		||||
	prop.setMaximum(field)
 | 
			
		||||
	prop.setUniqueItems(field)
 | 
			
		||||
	prop.setDefaultValue(field)
 | 
			
		||||
	prop.setType(field)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/swagger/swagger.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/swagger/swagger.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -48,7 +48,7 @@ type Info struct {
 | 
			
		||||
	TermsOfServiceUrl string `json:"termsOfServiceUrl,omitempty"`
 | 
			
		||||
	Contact           string `json:"contact,omitempty"`
 | 
			
		||||
	License           string `json:"license,omitempty"`
 | 
			
		||||
	LicensUrl         string `json:"licensUrl,omitempty"`
 | 
			
		||||
	LicenseUrl        string `json:"licenseUrl,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 5.1.5
 | 
			
		||||
@@ -134,7 +134,7 @@ type Api struct {
 | 
			
		||||
 | 
			
		||||
// 5.2.3 Operation Object
 | 
			
		||||
type Operation struct {
 | 
			
		||||
	Type             string            `json:"type"`
 | 
			
		||||
	DataTypeFields
 | 
			
		||||
	Method           string            `json:"method"`
 | 
			
		||||
	Summary          string            `json:"summary,omitempty"`
 | 
			
		||||
	Notes            string            `json:"notes,omitempty"`
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										21
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/swagger/swagger_builder.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/swagger/swagger_builder.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
package swagger
 | 
			
		||||
 | 
			
		||||
type SwaggerBuilder struct {
 | 
			
		||||
	SwaggerService
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewSwaggerBuilder(config Config) *SwaggerBuilder {
 | 
			
		||||
	return &SwaggerBuilder{*newSwaggerService(config)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sb SwaggerBuilder) ProduceListing() ResourceListing {
 | 
			
		||||
	return sb.SwaggerService.produceListing()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sb SwaggerBuilder) ProduceAllDeclarations() map[string]ApiDeclaration {
 | 
			
		||||
	return sb.SwaggerService.produceAllDeclarations()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sb SwaggerBuilder) ProduceDeclarations(route string) (*ApiDeclaration, bool) {
 | 
			
		||||
	return sb.SwaggerService.produceDeclarations(route)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										142
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/swagger/swagger_webservice.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										142
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/swagger/swagger_webservice.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -19,9 +19,35 @@ type SwaggerService struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newSwaggerService(config Config) *SwaggerService {
 | 
			
		||||
	return &SwaggerService{
 | 
			
		||||
	sws := &SwaggerService{
 | 
			
		||||
		config:            config,
 | 
			
		||||
		apiDeclarationMap: new(ApiDeclarationList)}
 | 
			
		||||
 | 
			
		||||
	// Build all ApiDeclarations
 | 
			
		||||
	for _, each := range config.WebServices {
 | 
			
		||||
		rootPath := each.RootPath()
 | 
			
		||||
		// skip the api service itself
 | 
			
		||||
		if rootPath != config.ApiPath {
 | 
			
		||||
			if rootPath == "" || rootPath == "/" {
 | 
			
		||||
				// use routes
 | 
			
		||||
				for _, route := range each.Routes() {
 | 
			
		||||
					entry := staticPathFromRoute(route)
 | 
			
		||||
					_, exists := sws.apiDeclarationMap.At(entry)
 | 
			
		||||
					if !exists {
 | 
			
		||||
						sws.apiDeclarationMap.Put(entry, sws.composeDeclaration(each, entry))
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			} else { // use root path
 | 
			
		||||
				sws.apiDeclarationMap.Put(each.RootPath(), sws.composeDeclaration(each, each.RootPath()))
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// if specified then call the PostBuilderHandler
 | 
			
		||||
	if config.PostBuildHandler != nil {
 | 
			
		||||
		config.PostBuildHandler(sws.apiDeclarationMap)
 | 
			
		||||
	}
 | 
			
		||||
	return sws
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LogInfo is the function that is called when this package needs to log. It defaults to log.Printf
 | 
			
		||||
@@ -57,31 +83,6 @@ func RegisterSwaggerService(config Config, wsContainer *restful.Container) {
 | 
			
		||||
	LogInfo("[restful/swagger] listing is available at %v%v", config.WebServicesUrl, config.ApiPath)
 | 
			
		||||
	wsContainer.Add(ws)
 | 
			
		||||
 | 
			
		||||
	// Build all ApiDeclarations
 | 
			
		||||
	for _, each := range config.WebServices {
 | 
			
		||||
		rootPath := each.RootPath()
 | 
			
		||||
		// skip the api service itself
 | 
			
		||||
		if rootPath != config.ApiPath {
 | 
			
		||||
			if rootPath == "" || rootPath == "/" {
 | 
			
		||||
				// use routes
 | 
			
		||||
				for _, route := range each.Routes() {
 | 
			
		||||
					entry := staticPathFromRoute(route)
 | 
			
		||||
					_, exists := sws.apiDeclarationMap.At(entry)
 | 
			
		||||
					if !exists {
 | 
			
		||||
						sws.apiDeclarationMap.Put(entry, sws.composeDeclaration(each, entry))
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			} else { // use root path
 | 
			
		||||
				sws.apiDeclarationMap.Put(each.RootPath(), sws.composeDeclaration(each, each.RootPath()))
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// if specified then call the PostBuilderHandler
 | 
			
		||||
	if config.PostBuildHandler != nil {
 | 
			
		||||
		config.PostBuildHandler(sws.apiDeclarationMap)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check paths for UI serving
 | 
			
		||||
	if config.StaticHandler == nil && config.SwaggerFilePath != "" && config.SwaggerPath != "" {
 | 
			
		||||
		swaggerPathSlash := config.SwaggerPath
 | 
			
		||||
@@ -138,7 +139,12 @@ func enableCORS(req *restful.Request, resp *restful.Response, chain *restful.Fil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sws SwaggerService) getListing(req *restful.Request, resp *restful.Response) {
 | 
			
		||||
	listing := ResourceListing{SwaggerVersion: swaggerVersion, ApiVersion: sws.config.ApiVersion}
 | 
			
		||||
	listing := sws.produceListing()
 | 
			
		||||
	resp.WriteAsJson(listing)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sws SwaggerService) produceListing() ResourceListing {
 | 
			
		||||
	listing := ResourceListing{SwaggerVersion: swaggerVersion, ApiVersion: sws.config.ApiVersion, Info: sws.config.Info}
 | 
			
		||||
	sws.apiDeclarationMap.Do(func(k string, v ApiDeclaration) {
 | 
			
		||||
		ref := Resource{Path: k}
 | 
			
		||||
		if len(v.Apis) > 0 { // use description of first (could still be empty)
 | 
			
		||||
@@ -146,11 +152,11 @@ func (sws SwaggerService) getListing(req *restful.Request, resp *restful.Respons
 | 
			
		||||
		}
 | 
			
		||||
		listing.Apis = append(listing.Apis, ref)
 | 
			
		||||
	})
 | 
			
		||||
	resp.WriteAsJson(listing)
 | 
			
		||||
	return listing
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sws SwaggerService) getDeclarations(req *restful.Request, resp *restful.Response) {
 | 
			
		||||
	decl, ok := sws.apiDeclarationMap.At(composeRootPath(req))
 | 
			
		||||
	decl, ok := sws.produceDeclarations(composeRootPath(req))
 | 
			
		||||
	if !ok {
 | 
			
		||||
		resp.WriteErrorString(http.StatusNotFound, "ApiDeclaration not found")
 | 
			
		||||
		return
 | 
			
		||||
@@ -180,11 +186,28 @@ func (sws SwaggerService) getDeclarations(req *restful.Request, resp *restful.Re
 | 
			
		||||
				scheme = "https"
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		(&decl).BasePath = fmt.Sprintf("%s://%s", scheme, host)
 | 
			
		||||
		decl.BasePath = fmt.Sprintf("%s://%s", scheme, host)
 | 
			
		||||
	}
 | 
			
		||||
	resp.WriteAsJson(decl)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sws SwaggerService) produceAllDeclarations() map[string]ApiDeclaration {
 | 
			
		||||
	decls := map[string]ApiDeclaration{}
 | 
			
		||||
	sws.apiDeclarationMap.Do(func(k string, v ApiDeclaration) {
 | 
			
		||||
		decls[k] = v
 | 
			
		||||
	})
 | 
			
		||||
	return decls
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sws SwaggerService) produceDeclarations(route string) (*ApiDeclaration, bool) {
 | 
			
		||||
	decl, ok := sws.apiDeclarationMap.At(route)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, false
 | 
			
		||||
	}
 | 
			
		||||
	decl.BasePath = sws.config.WebServicesUrl
 | 
			
		||||
	return &decl, true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// composeDeclaration uses all routes and parameters to create a ApiDeclaration
 | 
			
		||||
func (sws SwaggerService) composeDeclaration(ws *restful.WebService, pathPrefix string) ApiDeclaration {
 | 
			
		||||
	decl := ApiDeclaration{
 | 
			
		||||
@@ -207,13 +230,15 @@ func (sws SwaggerService) composeDeclaration(ws *restful.WebService, pathPrefix
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	pathToRoutes.Do(func(path string, routes []restful.Route) {
 | 
			
		||||
		api := Api{Path: strings.TrimSuffix(path, "/"), Description: ws.Documentation()}
 | 
			
		||||
		api := Api{Path: strings.TrimSuffix(withoutWildcard(path), "/"), Description: ws.Documentation()}
 | 
			
		||||
		voidString := "void"
 | 
			
		||||
		for _, route := range routes {
 | 
			
		||||
			operation := Operation{
 | 
			
		||||
				Method:  route.Method,
 | 
			
		||||
				Summary: route.Doc,
 | 
			
		||||
				Notes:   route.Notes,
 | 
			
		||||
				Type:             asDataType(route.WriteSample),
 | 
			
		||||
				// Type gets overwritten if there is a write sample
 | 
			
		||||
				DataTypeFields:   DataTypeFields{Type: &voidString},
 | 
			
		||||
				Parameters:       []Parameter{},
 | 
			
		||||
				Nickname:         route.Operation,
 | 
			
		||||
				ResponseMessages: composeResponseMessages(route, &decl)}
 | 
			
		||||
@@ -238,6 +263,13 @@ func (sws SwaggerService) composeDeclaration(ws *restful.WebService, pathPrefix
 | 
			
		||||
	return decl
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func withoutWildcard(path string) string {
 | 
			
		||||
	if strings.HasSuffix(path, ":*}") {
 | 
			
		||||
		return path[0:len(path)-3] + "}"
 | 
			
		||||
	}
 | 
			
		||||
	return path
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// composeResponseMessages takes the ResponseErrors (if any) and creates ResponseMessages from them.
 | 
			
		||||
func composeResponseMessages(route restful.Route, decl *ApiDeclaration) (messages []ResponseMessage) {
 | 
			
		||||
	if route.ResponseErrors == nil {
 | 
			
		||||
@@ -299,14 +331,10 @@ func detectCollectionType(st reflect.Type) (bool, reflect.Type) {
 | 
			
		||||
 | 
			
		||||
// addModelFromSample creates and adds (or overwrites) a Model from a sample resource
 | 
			
		||||
func (sws SwaggerService) addModelFromSampleTo(operation *Operation, isResponse bool, sample interface{}, models *ModelList) {
 | 
			
		||||
	st := reflect.TypeOf(sample)
 | 
			
		||||
	isCollection, st := detectCollectionType(st)
 | 
			
		||||
	modelName := modelBuilder{}.keyFrom(st)
 | 
			
		||||
	if isResponse {
 | 
			
		||||
		if isCollection {
 | 
			
		||||
			modelName = "array[" + modelName + "]"
 | 
			
		||||
		}
 | 
			
		||||
		operation.Type = modelName
 | 
			
		||||
		type_, items := asDataType(sample)
 | 
			
		||||
		operation.Type = type_
 | 
			
		||||
		operation.Items = items
 | 
			
		||||
	}
 | 
			
		||||
	modelBuilder{models}.addModelFrom(sample)
 | 
			
		||||
}
 | 
			
		||||
@@ -315,7 +343,7 @@ func asSwaggerParameter(param restful.ParameterData) Parameter {
 | 
			
		||||
	return Parameter{
 | 
			
		||||
		DataTypeFields: DataTypeFields{
 | 
			
		||||
			Type:         ¶m.DataType,
 | 
			
		||||
			Format:       asFormat(param.DataType),
 | 
			
		||||
			Format:       asFormat(param.DataType, param.DataFormat),
 | 
			
		||||
			DefaultValue: Special(param.DefaultValue),
 | 
			
		||||
		},
 | 
			
		||||
		Name:        param.Name,
 | 
			
		||||
@@ -360,7 +388,10 @@ func composeRootPath(req *restful.Request) string {
 | 
			
		||||
	return path + "/" + g
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func asFormat(name string) string {
 | 
			
		||||
func asFormat(dataType string, dataFormat string) string {
 | 
			
		||||
	if dataFormat != "" {
 | 
			
		||||
		return dataFormat
 | 
			
		||||
	}
 | 
			
		||||
	return "" // TODO
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -380,9 +411,30 @@ func asParamType(kind int) string {
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func asDataType(any interface{}) string {
 | 
			
		||||
	if any == nil {
 | 
			
		||||
		return "void"
 | 
			
		||||
func asDataType(any interface{}) (*string, *Item) {
 | 
			
		||||
	// If it's not a collection, return the suggested model name
 | 
			
		||||
	st := reflect.TypeOf(any)
 | 
			
		||||
	isCollection, st := detectCollectionType(st)
 | 
			
		||||
	modelName := modelBuilder{}.keyFrom(st)
 | 
			
		||||
	// if it's not a collection we are done
 | 
			
		||||
	if !isCollection {
 | 
			
		||||
		return &modelName, nil
 | 
			
		||||
	}
 | 
			
		||||
	return reflect.TypeOf(any).Name()
 | 
			
		||||
 | 
			
		||||
	// XXX: This is not very elegant
 | 
			
		||||
	// We create an Item object referring to the given model
 | 
			
		||||
	models := ModelList{}
 | 
			
		||||
	mb := modelBuilder{&models}
 | 
			
		||||
	mb.addModelFrom(any)
 | 
			
		||||
 | 
			
		||||
	elemTypeName := mb.getElementTypeName(modelName, "", st)
 | 
			
		||||
	item := new(Item)
 | 
			
		||||
	if mb.isPrimitiveType(elemTypeName) {
 | 
			
		||||
		mapped := mb.jsonSchemaType(elemTypeName)
 | 
			
		||||
		item.Type = &mapped
 | 
			
		||||
	} else {
 | 
			
		||||
		item.Ref = &elemTypeName
 | 
			
		||||
	}
 | 
			
		||||
	tmp := "array"
 | 
			
		||||
	return &tmp, item
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/swagger/test_package/struct.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/swagger/test_package/struct.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
package test_package
 | 
			
		||||
 | 
			
		||||
type TestStruct struct {
 | 
			
		||||
	TestField string
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/web_service.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										38
									
								
								Godeps/_workspace/src/github.com/emicklei/go-restful/web_service.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,7 +1,9 @@
 | 
			
		||||
package restful
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/emicklei/go-restful/log"
 | 
			
		||||
)
 | 
			
		||||
@@ -21,6 +23,15 @@ type WebService struct {
 | 
			
		||||
	filters        []FilterFunction
 | 
			
		||||
	documentation  string
 | 
			
		||||
	apiVersion     string
 | 
			
		||||
 | 
			
		||||
	dynamicRoutes bool
 | 
			
		||||
 | 
			
		||||
	// protects 'routes' if dynamic routes are enabled
 | 
			
		||||
	routesLock sync.RWMutex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *WebService) SetDynamicRoutes(enable bool) {
 | 
			
		||||
	w.dynamicRoutes = enable
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// compilePathExpression ensures that the path is compiled into a RegEx for those routers that need it.
 | 
			
		||||
@@ -134,11 +145,28 @@ func FormParameter(name, description string) *Parameter {
 | 
			
		||||
 | 
			
		||||
// Route creates a new Route using the RouteBuilder and add to the ordered list of Routes.
 | 
			
		||||
func (w *WebService) Route(builder *RouteBuilder) *WebService {
 | 
			
		||||
	w.routesLock.Lock()
 | 
			
		||||
	defer w.routesLock.Unlock()
 | 
			
		||||
	builder.copyDefaults(w.produces, w.consumes)
 | 
			
		||||
	w.routes = append(w.routes, builder.Build())
 | 
			
		||||
	return w
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RemoveRoute removes the specified route, looks for something that matches 'path' and 'method'
 | 
			
		||||
func (w *WebService) RemoveRoute(path, method string) error {
 | 
			
		||||
	if !w.dynamicRoutes {
 | 
			
		||||
		return fmt.Errorf("dynamic routes are not enabled.")
 | 
			
		||||
	}
 | 
			
		||||
	w.routesLock.Lock()
 | 
			
		||||
	defer w.routesLock.Unlock()
 | 
			
		||||
	for ix := range w.routes {
 | 
			
		||||
		if w.routes[ix].Method == method && w.routes[ix].Path == path {
 | 
			
		||||
			w.routes = append(w.routes[:ix], w.routes[ix+1:]...)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Method creates a new RouteBuilder and initialize its http method
 | 
			
		||||
func (w *WebService) Method(httpMethod string) *RouteBuilder {
 | 
			
		||||
	return new(RouteBuilder).servicePath(w.rootPath).Method(httpMethod)
 | 
			
		||||
@@ -160,7 +188,17 @@ func (w *WebService) Consumes(accepts ...string) *WebService {
 | 
			
		||||
 | 
			
		||||
// Routes returns the Routes associated with this WebService
 | 
			
		||||
func (w WebService) Routes() []Route {
 | 
			
		||||
	if !w.dynamicRoutes {
 | 
			
		||||
		return w.routes
 | 
			
		||||
	}
 | 
			
		||||
	// Make a copy of the array to prevent concurrency problems
 | 
			
		||||
	w.routesLock.RLock()
 | 
			
		||||
	defer w.routesLock.RUnlock()
 | 
			
		||||
	result := make([]Route, len(w.routes))
 | 
			
		||||
	for ix := range w.routes {
 | 
			
		||||
		result[ix] = w.routes[ix]
 | 
			
		||||
	}
 | 
			
		||||
	return result
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RootPath returns the RootPath associated with this WebService. Default "/"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user