mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-15 21:06:39 +08:00
Merge 19dff1a81eef28989a427ef31171f104c8857640 into ae15646aba14cd8245fbebd263cc7740c6789ef3
This commit is contained in:
commit
9d13626ec2
@ -15,6 +15,9 @@ type Data struct {
|
|||||||
// Render (Data) writes data with custom ContentType.
|
// Render (Data) writes data with custom ContentType.
|
||||||
func (r Data) Render(w http.ResponseWriter) (err error) {
|
func (r Data) Render(w http.ResponseWriter) (err error) {
|
||||||
r.WriteContentType(w)
|
r.WriteContentType(w)
|
||||||
|
|
||||||
|
writeContentLength(w, len(r.Data))
|
||||||
|
|
||||||
_, err = w.Write(r.Data)
|
_, err = w.Write(r.Data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,11 @@ func (r JSON) WriteContentType(w http.ResponseWriter) {
|
|||||||
writeContentType(w, jsonContentType)
|
writeContentType(w, jsonContentType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WriteContentType (JSON) writes JSON ContentType.
|
||||||
|
func (r JSON) WriteContentLength(w http.ResponseWriter, length int) {
|
||||||
|
writeContentLength(w, length)
|
||||||
|
}
|
||||||
|
|
||||||
// WriteJSON marshals the given interface object and writes it with custom ContentType.
|
// WriteJSON marshals the given interface object and writes it with custom ContentType.
|
||||||
func WriteJSON(w http.ResponseWriter, obj any) error {
|
func WriteJSON(w http.ResponseWriter, obj any) error {
|
||||||
writeContentType(w, jsonContentType)
|
writeContentType(w, jsonContentType)
|
||||||
@ -69,6 +74,9 @@ func WriteJSON(w http.ResponseWriter, obj any) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writeContentLength(w, len(jsonBytes))
|
||||||
|
|
||||||
_, err = w.Write(jsonBytes)
|
_, err = w.Write(jsonBytes)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -80,6 +88,9 @@ func (r IndentedJSON) Render(w http.ResponseWriter) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writeContentLength(w, len(jsonBytes))
|
||||||
|
|
||||||
_, err = w.Write(jsonBytes)
|
_, err = w.Write(jsonBytes)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -96,13 +107,22 @@ func (r SecureJSON) Render(w http.ResponseWriter) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
length := len(jsonBytes)
|
||||||
|
|
||||||
// if the jsonBytes is array values
|
// if the jsonBytes is array values
|
||||||
if bytes.HasPrefix(jsonBytes, bytesconv.StringToBytes("[")) && bytes.HasSuffix(jsonBytes,
|
if bytes.HasPrefix(jsonBytes, bytesconv.StringToBytes("[")) && bytes.HasSuffix(jsonBytes,
|
||||||
bytesconv.StringToBytes("]")) {
|
bytesconv.StringToBytes("]")) {
|
||||||
|
|
||||||
if _, err = w.Write(bytesconv.StringToBytes(r.Prefix)); err != nil {
|
if _, err = w.Write(bytesconv.StringToBytes(r.Prefix)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
length += len(r.Prefix)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writeContentLength(w, length)
|
||||||
|
|
||||||
_, err = w.Write(jsonBytes)
|
_, err = w.Write(jsonBytes)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -115,18 +135,24 @@ func (r SecureJSON) WriteContentType(w http.ResponseWriter) {
|
|||||||
// Render (JsonpJSON) marshals the given interface object and writes it and its callback with custom ContentType.
|
// Render (JsonpJSON) marshals the given interface object and writes it and its callback with custom ContentType.
|
||||||
func (r JsonpJSON) Render(w http.ResponseWriter) (err error) {
|
func (r JsonpJSON) Render(w http.ResponseWriter) (err error) {
|
||||||
r.WriteContentType(w)
|
r.WriteContentType(w)
|
||||||
ret, err := json.Marshal(r.Data)
|
jsonBytes, err := json.Marshal(r.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
length := len(jsonBytes)
|
||||||
|
|
||||||
if r.Callback == "" {
|
if r.Callback == "" {
|
||||||
_, err = w.Write(ret)
|
writeContentLength(w, length)
|
||||||
|
|
||||||
|
_, err = w.Write(jsonBytes)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
callback := template.JSEscapeString(r.Callback)
|
callback := template.JSEscapeString(r.Callback)
|
||||||
if _, err = w.Write(bytesconv.StringToBytes(callback)); err != nil {
|
callbackBytes := bytesconv.StringToBytes(callback)
|
||||||
|
|
||||||
|
if _, err = w.Write(callbackBytes); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +160,7 @@ func (r JsonpJSON) Render(w http.ResponseWriter) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = w.Write(ret); err != nil {
|
if _, err = w.Write(jsonBytes); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,6 +168,10 @@ func (r JsonpJSON) Render(w http.ResponseWriter) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
length += len(callbackBytes) + 3 // 3 = len("();")
|
||||||
|
|
||||||
|
writeContentLength(w, length)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,7 +197,11 @@ func (r AsciiJSON) Render(w http.ResponseWriter) (err error) {
|
|||||||
buffer.WriteString(cvt)
|
buffer.WriteString(cvt)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = w.Write(buffer.Bytes())
|
jsonBytes := buffer.Bytes()
|
||||||
|
|
||||||
|
writeContentLength(w, len(jsonBytes))
|
||||||
|
|
||||||
|
_, err = w.Write(jsonBytes)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,8 @@ func (r ProtoBuf) Render(w http.ResponseWriter) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writeContentLength(w, len(bytes))
|
||||||
|
|
||||||
_, err = w.Write(bytes)
|
_, err = w.Write(bytes)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,10 @@
|
|||||||
|
|
||||||
package render
|
package render
|
||||||
|
|
||||||
import "net/http"
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
// Render interface is to be implemented by JSON, XML, HTML, YAML and so on.
|
// Render interface is to be implemented by JSON, XML, HTML, YAML and so on.
|
||||||
type Render interface {
|
type Render interface {
|
||||||
@ -39,3 +42,7 @@ func writeContentType(w http.ResponseWriter, value []string) {
|
|||||||
header["Content-Type"] = value
|
header["Content-Type"] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func writeContentLength(w http.ResponseWriter, value int) {
|
||||||
|
w.Header().Set("Content-Length", strconv.Itoa(value))
|
||||||
|
}
|
||||||
|
@ -39,6 +39,8 @@ func TestRenderJSON(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\\u003cb\\u003e\"}", w.Body.String())
|
assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\\u003cb\\u003e\"}", w.Body.String())
|
||||||
assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
|
assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
|
||||||
|
assert.Equal(t, "36", w.Header().Get("Content-Length"))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRenderJSONError(t *testing.T) {
|
func TestRenderJSONError(t *testing.T) {
|
||||||
@ -61,6 +63,8 @@ func TestRenderIndentedJSON(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "{\n \"bar\": \"foo\",\n \"foo\": \"bar\"\n}", w.Body.String())
|
assert.Equal(t, "{\n \"bar\": \"foo\",\n \"foo\": \"bar\"\n}", w.Body.String())
|
||||||
assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
|
assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
|
||||||
|
assert.Equal(t, "38", w.Header().Get("Content-Length"))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRenderIndentedJSONPanics(t *testing.T) {
|
func TestRenderIndentedJSONPanics(t *testing.T) {
|
||||||
@ -86,6 +90,7 @@ func TestRenderSecureJSON(t *testing.T) {
|
|||||||
assert.NoError(t, err1)
|
assert.NoError(t, err1)
|
||||||
assert.Equal(t, "{\"foo\":\"bar\"}", w1.Body.String())
|
assert.Equal(t, "{\"foo\":\"bar\"}", w1.Body.String())
|
||||||
assert.Equal(t, "application/json; charset=utf-8", w1.Header().Get("Content-Type"))
|
assert.Equal(t, "application/json; charset=utf-8", w1.Header().Get("Content-Type"))
|
||||||
|
assert.Equal(t, "13", w1.Header().Get("Content-Length"))
|
||||||
|
|
||||||
w2 := httptest.NewRecorder()
|
w2 := httptest.NewRecorder()
|
||||||
datas := []map[string]any{{
|
datas := []map[string]any{{
|
||||||
@ -98,6 +103,7 @@ func TestRenderSecureJSON(t *testing.T) {
|
|||||||
assert.NoError(t, err2)
|
assert.NoError(t, err2)
|
||||||
assert.Equal(t, "while(1);[{\"foo\":\"bar\"},{\"bar\":\"foo\"}]", w2.Body.String())
|
assert.Equal(t, "while(1);[{\"foo\":\"bar\"},{\"bar\":\"foo\"}]", w2.Body.String())
|
||||||
assert.Equal(t, "application/json; charset=utf-8", w2.Header().Get("Content-Type"))
|
assert.Equal(t, "application/json; charset=utf-8", w2.Header().Get("Content-Type"))
|
||||||
|
assert.Equal(t, "38", w2.Header().Get("Content-Length"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRenderSecureJSONFail(t *testing.T) {
|
func TestRenderSecureJSONFail(t *testing.T) {
|
||||||
@ -123,6 +129,7 @@ func TestRenderJsonpJSON(t *testing.T) {
|
|||||||
assert.NoError(t, err1)
|
assert.NoError(t, err1)
|
||||||
assert.Equal(t, "x({\"foo\":\"bar\"});", w1.Body.String())
|
assert.Equal(t, "x({\"foo\":\"bar\"});", w1.Body.String())
|
||||||
assert.Equal(t, "application/javascript; charset=utf-8", w1.Header().Get("Content-Type"))
|
assert.Equal(t, "application/javascript; charset=utf-8", w1.Header().Get("Content-Type"))
|
||||||
|
assert.Equal(t, "17", w1.Header().Get("Content-Length"))
|
||||||
|
|
||||||
w2 := httptest.NewRecorder()
|
w2 := httptest.NewRecorder()
|
||||||
datas := []map[string]any{{
|
datas := []map[string]any{{
|
||||||
@ -135,6 +142,8 @@ func TestRenderJsonpJSON(t *testing.T) {
|
|||||||
assert.NoError(t, err2)
|
assert.NoError(t, err2)
|
||||||
assert.Equal(t, "x([{\"foo\":\"bar\"},{\"bar\":\"foo\"}]);", w2.Body.String())
|
assert.Equal(t, "x([{\"foo\":\"bar\"},{\"bar\":\"foo\"}]);", w2.Body.String())
|
||||||
assert.Equal(t, "application/javascript; charset=utf-8", w2.Header().Get("Content-Type"))
|
assert.Equal(t, "application/javascript; charset=utf-8", w2.Header().Get("Content-Type"))
|
||||||
|
assert.Equal(t, "33", w2.Header().Get("Content-Length"))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type errorWriter struct {
|
type errorWriter struct {
|
||||||
@ -195,6 +204,7 @@ func TestRenderJsonpJSONError2(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String())
|
assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String())
|
||||||
assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type"))
|
assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type"))
|
||||||
|
assert.Equal(t, "13", w.Header().Get("Content-Length"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRenderJsonpJSONFail(t *testing.T) {
|
func TestRenderJsonpJSONFail(t *testing.T) {
|
||||||
@ -218,6 +228,7 @@ func TestRenderAsciiJSON(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "{\"lang\":\"GO\\u8bed\\u8a00\",\"tag\":\"\\u003cbr\\u003e\"}", w1.Body.String())
|
assert.Equal(t, "{\"lang\":\"GO\\u8bed\\u8a00\",\"tag\":\"\\u003cbr\\u003e\"}", w1.Body.String())
|
||||||
assert.Equal(t, "application/json", w1.Header().Get("Content-Type"))
|
assert.Equal(t, "application/json", w1.Header().Get("Content-Type"))
|
||||||
|
assert.Equal(t, "48", w1.Header().Get("Content-Length"))
|
||||||
|
|
||||||
w2 := httptest.NewRecorder()
|
w2 := httptest.NewRecorder()
|
||||||
data2 := 3.1415926
|
data2 := 3.1415926
|
||||||
@ -225,6 +236,8 @@ func TestRenderAsciiJSON(t *testing.T) {
|
|||||||
err = (AsciiJSON{data2}).Render(w2)
|
err = (AsciiJSON{data2}).Render(w2)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "3.1415926", w2.Body.String())
|
assert.Equal(t, "3.1415926", w2.Body.String())
|
||||||
|
assert.Equal(t, "9", w2.Header().Get("Content-Length"))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRenderAsciiJSONFail(t *testing.T) {
|
func TestRenderAsciiJSONFail(t *testing.T) {
|
||||||
@ -286,6 +299,8 @@ b:
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "|4-\n a : Easy!\n b:\n \tc: 2\n \td: [3, 4]\n \t\n", w.Body.String())
|
assert.Equal(t, "|4-\n a : Easy!\n b:\n \tc: 2\n \td: [3, 4]\n \t\n", w.Body.String())
|
||||||
assert.Equal(t, "application/x-yaml; charset=utf-8", w.Header().Get("Content-Type"))
|
assert.Equal(t, "application/x-yaml; charset=utf-8", w.Header().Get("Content-Type"))
|
||||||
|
assert.Equal(t, "56", w.Header().Get("Content-Length"))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type fail struct{}
|
type fail struct{}
|
||||||
@ -314,6 +329,8 @@ func TestRenderTOML(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "foo = 'bar'\nhtml = '<b>'\n", w.Body.String())
|
assert.Equal(t, "foo = 'bar'\nhtml = '<b>'\n", w.Body.String())
|
||||||
assert.Equal(t, "application/toml; charset=utf-8", w.Header().Get("Content-Type"))
|
assert.Equal(t, "application/toml; charset=utf-8", w.Header().Get("Content-Type"))
|
||||||
|
assert.Equal(t, "25", w.Header().Get("Content-Length"))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRenderTOMLFail(t *testing.T) {
|
func TestRenderTOMLFail(t *testing.T) {
|
||||||
@ -342,6 +359,8 @@ func TestRenderProtoBuf(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, string(protoData), w.Body.String())
|
assert.Equal(t, string(protoData), w.Body.String())
|
||||||
assert.Equal(t, "application/x-protobuf", w.Header().Get("Content-Type"))
|
assert.Equal(t, "application/x-protobuf", w.Header().Get("Content-Type"))
|
||||||
|
assert.Equal(t, strconv.Itoa(len(string(protoData))), w.Header().Get("Content-Length"))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRenderProtoBufFail(t *testing.T) {
|
func TestRenderProtoBufFail(t *testing.T) {
|
||||||
@ -419,6 +438,8 @@ func TestRenderData(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "#!PNG some raw data", w.Body.String())
|
assert.Equal(t, "#!PNG some raw data", w.Body.String())
|
||||||
assert.Equal(t, "image/png", w.Header().Get("Content-Type"))
|
assert.Equal(t, "image/png", w.Header().Get("Content-Type"))
|
||||||
|
assert.Equal(t, "19", w.Header().Get("Content-Length"))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRenderString(t *testing.T) {
|
func TestRenderString(t *testing.T) {
|
||||||
@ -451,6 +472,8 @@ func TestRenderStringLenZero(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "hola %s %d", w.Body.String())
|
assert.Equal(t, "hola %s %d", w.Body.String())
|
||||||
assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type"))
|
assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type"))
|
||||||
|
assert.Equal(t, "10", w.Header().Get("Content-Length"))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRenderHTMLTemplate(t *testing.T) {
|
func TestRenderHTMLTemplate(t *testing.T) {
|
||||||
|
@ -36,6 +36,12 @@ func WriteString(w http.ResponseWriter, format string, data []any) (err error) {
|
|||||||
_, err = fmt.Fprintf(w, format, data...)
|
_, err = fmt.Fprintf(w, format, data...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = w.Write(bytesconv.StringToBytes(format))
|
|
||||||
|
bytes := bytesconv.StringToBytes(format)
|
||||||
|
|
||||||
|
writeContentLength(w, len(bytes))
|
||||||
|
|
||||||
|
_, err = w.Write(bytes)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,8 @@ func (r TOML) Render(w http.ResponseWriter) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writeContentLength(w, len(bytes))
|
||||||
|
|
||||||
_, err = w.Write(bytes)
|
_, err = w.Write(bytes)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,8 @@ func (r YAML) Render(w http.ResponseWriter) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writeContentLength(w, len(bytes))
|
||||||
|
|
||||||
_, err = w.Write(bytes)
|
_, err = w.Write(bytes)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user