mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-22 09:34:33 +08:00
145 lines
3.7 KiB
Go
145 lines
3.7 KiB
Go
// 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"
|
|
"sync"
|
|
)
|
|
|
|
// RenderType Names
|
|
const (
|
|
JSONRenderType = iota // JSON Render Type
|
|
IntendedJSONRenderType // IntendedJSON Render Type
|
|
PureJSONRenderType // PureJSON Render Type
|
|
AsciiJSONRenderType // AsciiJSON Render Type
|
|
JsonpJSONRenderType // JsonpJSON Render Type
|
|
SecureJSONRenderType // SecureJSON Type
|
|
XMLRenderType // XML Render Type
|
|
YAMLRenderType // YAML Render Type
|
|
MsgPackRenderType // MsgPack Render Type
|
|
ProtoBufRenderType // ProtoBuf Render Type
|
|
EmptyRenderType // Empty Render Type
|
|
unknownRenderType // Unknown Render Type,just used for test
|
|
)
|
|
|
|
var (
|
|
renderPool = &RenderPool{renderPools: make(map[int]sync.Pool)}
|
|
)
|
|
|
|
// Render interface is to be implemented by JSON, XML, HTML, YAML and so on.
|
|
type Render interface {
|
|
// Render writes data with custom ContentType.
|
|
Render(http.ResponseWriter) error
|
|
// WriteContentType writes custom ContentType.
|
|
WriteContentType(w http.ResponseWriter)
|
|
}
|
|
|
|
// RenderRecycler interface is to be implemented by JSON, XML, HTML, YAML and so on.
|
|
type RenderRecycler interface {
|
|
Render
|
|
// Setup set data and opts
|
|
Setup(data interface{}, opts ...interface{})
|
|
// Reset clean data and opts
|
|
Reset()
|
|
}
|
|
|
|
// RenderFactory interface is to be implemented by other Render.
|
|
type RenderFactory interface {
|
|
// Instance a new RenderRecycler instance
|
|
Instance() RenderRecycler
|
|
}
|
|
|
|
// RenderPool contains Render instance
|
|
type RenderPool struct {
|
|
mu sync.RWMutex
|
|
renderPools map[int]sync.Pool
|
|
}
|
|
|
|
func (p *RenderPool) get(name int) RenderRecycler {
|
|
p.mu.RLock()
|
|
defer p.mu.RUnlock()
|
|
|
|
var render RenderRecycler
|
|
if pool, ok := p.renderPools[name]; ok {
|
|
render, _ = pool.Get().(RenderRecycler)
|
|
} else {
|
|
pool, _ = p.renderPools[EmptyRenderType]
|
|
render, _ = pool.Get().(RenderRecycler)
|
|
}
|
|
return render
|
|
}
|
|
|
|
func (p *RenderPool) put(name int, render RenderRecycler) {
|
|
p.mu.RLock()
|
|
defer p.mu.RUnlock()
|
|
|
|
if pool, ok := p.renderPools[name]; ok {
|
|
render.Reset()
|
|
pool.Put(render)
|
|
}
|
|
}
|
|
|
|
func (p *RenderPool) register(name int, factory RenderFactory) {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
|
|
if factory == nil {
|
|
panic("gin: Register RenderFactory is nil")
|
|
}
|
|
if _, dup := p.renderPools[name]; dup {
|
|
panic("gin: Register called twice for RenderFactory")
|
|
}
|
|
|
|
p.renderPools[name] = sync.Pool{
|
|
New: func() interface{} {
|
|
return factory.Instance()
|
|
},
|
|
}
|
|
}
|
|
|
|
// Register makes a binding available by the provided name.
|
|
// If Register is called twice with the same name or if binding is nil,
|
|
// it panics.
|
|
func Register(name int, factory RenderFactory) {
|
|
renderPool.register(name, factory)
|
|
}
|
|
|
|
// Default returns the appropriate Render instance based on the render type.
|
|
func Default(name int) RenderRecycler {
|
|
return renderPool.get(name)
|
|
}
|
|
|
|
// Recycle put render to sync.Pool
|
|
func Recycle(name int, render RenderRecycler) {
|
|
renderPool.put(name, render)
|
|
}
|
|
|
|
var (
|
|
_ RenderRecycler = &JSON{}
|
|
_ RenderRecycler = &IndentedJSON{}
|
|
_ RenderRecycler = &SecureJSON{}
|
|
_ RenderRecycler = &JsonpJSON{}
|
|
_ RenderRecycler = &XML{}
|
|
_ Render = String{}
|
|
_ Render = Redirect{}
|
|
_ Render = Data{}
|
|
_ Render = HTML{}
|
|
_ HTMLRender = HTMLDebug{}
|
|
_ HTMLRender = HTMLProduction{}
|
|
_ RenderRecycler = &YAML{}
|
|
_ RenderRecycler = &MsgPack{}
|
|
_ Render = Reader{}
|
|
_ RenderRecycler = &AsciiJSON{}
|
|
_ RenderRecycler = &ProtoBuf{}
|
|
)
|
|
|
|
func writeContentType(w http.ResponseWriter, value []string) {
|
|
header := w.Header()
|
|
if val := header["Content-Type"]; len(val) == 0 {
|
|
header["Content-Type"] = value
|
|
}
|
|
}
|