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.
|
||||
func (r Data) Render(w http.ResponseWriter) (err error) {
|
||||
r.WriteContentType(w)
|
||||
|
||||
writeContentLength(w, len(r.Data))
|
||||
|
||||
_, err = w.Write(r.Data)
|
||||
return
|
||||
}
|
||||
|
@ -62,6 +62,11 @@ func (r JSON) WriteContentType(w http.ResponseWriter) {
|
||||
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.
|
||||
func WriteJSON(w http.ResponseWriter, obj any) error {
|
||||
writeContentType(w, jsonContentType)
|
||||
@ -69,6 +74,9 @@ func WriteJSON(w http.ResponseWriter, obj any) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
writeContentLength(w, len(jsonBytes))
|
||||
|
||||
_, err = w.Write(jsonBytes)
|
||||
return err
|
||||
}
|
||||
@ -80,6 +88,9 @@ func (r IndentedJSON) Render(w http.ResponseWriter) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
writeContentLength(w, len(jsonBytes))
|
||||
|
||||
_, err = w.Write(jsonBytes)
|
||||
return err
|
||||
}
|
||||
@ -96,13 +107,22 @@ func (r SecureJSON) Render(w http.ResponseWriter) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
length := len(jsonBytes)
|
||||
|
||||
// if the jsonBytes is array values
|
||||
if bytes.HasPrefix(jsonBytes, bytesconv.StringToBytes("[")) && bytes.HasSuffix(jsonBytes,
|
||||
bytesconv.StringToBytes("]")) {
|
||||
|
||||
if _, err = w.Write(bytesconv.StringToBytes(r.Prefix)); err != nil {
|
||||
return err
|
||||
}
|
||||
length += len(r.Prefix)
|
||||
|
||||
}
|
||||
|
||||
writeContentLength(w, length)
|
||||
|
||||
_, err = w.Write(jsonBytes)
|
||||
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.
|
||||
func (r JsonpJSON) Render(w http.ResponseWriter) (err error) {
|
||||
r.WriteContentType(w)
|
||||
ret, err := json.Marshal(r.Data)
|
||||
jsonBytes, err := json.Marshal(r.Data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
length := len(jsonBytes)
|
||||
|
||||
if r.Callback == "" {
|
||||
_, err = w.Write(ret)
|
||||
writeContentLength(w, length)
|
||||
|
||||
_, err = w.Write(jsonBytes)
|
||||
return err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@ -134,7 +160,7 @@ func (r JsonpJSON) Render(w http.ResponseWriter) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = w.Write(ret); err != nil {
|
||||
if _, err = w.Write(jsonBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -142,6 +168,10 @@ func (r JsonpJSON) Render(w http.ResponseWriter) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
length += len(callbackBytes) + 3 // 3 = len("();")
|
||||
|
||||
writeContentLength(w, length)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -167,7 +197,11 @@ func (r AsciiJSON) Render(w http.ResponseWriter) (err error) {
|
||||
buffer.WriteString(cvt)
|
||||
}
|
||||
|
||||
_, err = w.Write(buffer.Bytes())
|
||||
jsonBytes := buffer.Bytes()
|
||||
|
||||
writeContentLength(w, len(jsonBytes))
|
||||
|
||||
_, err = w.Write(jsonBytes)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,8 @@ func (r ProtoBuf) Render(w http.ResponseWriter) error {
|
||||
return err
|
||||
}
|
||||
|
||||
writeContentLength(w, len(bytes))
|
||||
|
||||
_, err = w.Write(bytes)
|
||||
return err
|
||||
}
|
||||
|
@ -4,7 +4,10 @@
|
||||
|
||||
package render
|
||||
|
||||
import "net/http"
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Render interface is to be implemented by JSON, XML, HTML, YAML and so on.
|
||||
type Render interface {
|
||||
@ -39,3 +42,7 @@ func writeContentType(w http.ResponseWriter, value []string) {
|
||||
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.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, "36", w.Header().Get("Content-Length"))
|
||||
|
||||
}
|
||||
|
||||
func TestRenderJSONError(t *testing.T) {
|
||||
@ -61,6 +63,8 @@ func TestRenderIndentedJSON(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
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, "38", w.Header().Get("Content-Length"))
|
||||
|
||||
}
|
||||
|
||||
func TestRenderIndentedJSONPanics(t *testing.T) {
|
||||
@ -86,6 +90,7 @@ func TestRenderSecureJSON(t *testing.T) {
|
||||
assert.NoError(t, err1)
|
||||
assert.Equal(t, "{\"foo\":\"bar\"}", w1.Body.String())
|
||||
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()
|
||||
datas := []map[string]any{{
|
||||
@ -98,6 +103,7 @@ func TestRenderSecureJSON(t *testing.T) {
|
||||
assert.NoError(t, err2)
|
||||
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, "38", w2.Header().Get("Content-Length"))
|
||||
}
|
||||
|
||||
func TestRenderSecureJSONFail(t *testing.T) {
|
||||
@ -123,6 +129,7 @@ func TestRenderJsonpJSON(t *testing.T) {
|
||||
assert.NoError(t, err1)
|
||||
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, "17", w1.Header().Get("Content-Length"))
|
||||
|
||||
w2 := httptest.NewRecorder()
|
||||
datas := []map[string]any{{
|
||||
@ -135,6 +142,8 @@ func TestRenderJsonpJSON(t *testing.T) {
|
||||
assert.NoError(t, err2)
|
||||
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, "33", w2.Header().Get("Content-Length"))
|
||||
|
||||
}
|
||||
|
||||
type errorWriter struct {
|
||||
@ -195,6 +204,7 @@ func TestRenderJsonpJSONError2(t *testing.T) {
|
||||
|
||||
assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String())
|
||||
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) {
|
||||
@ -218,6 +228,7 @@ func TestRenderAsciiJSON(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
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, "48", w1.Header().Get("Content-Length"))
|
||||
|
||||
w2 := httptest.NewRecorder()
|
||||
data2 := 3.1415926
|
||||
@ -225,6 +236,8 @@ func TestRenderAsciiJSON(t *testing.T) {
|
||||
err = (AsciiJSON{data2}).Render(w2)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "3.1415926", w2.Body.String())
|
||||
assert.Equal(t, "9", w2.Header().Get("Content-Length"))
|
||||
|
||||
}
|
||||
|
||||
func TestRenderAsciiJSONFail(t *testing.T) {
|
||||
@ -286,6 +299,8 @@ b:
|
||||
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, "application/x-yaml; charset=utf-8", w.Header().Get("Content-Type"))
|
||||
assert.Equal(t, "56", w.Header().Get("Content-Length"))
|
||||
|
||||
}
|
||||
|
||||
type fail struct{}
|
||||
@ -314,6 +329,8 @@ func TestRenderTOML(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
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, "25", w.Header().Get("Content-Length"))
|
||||
|
||||
}
|
||||
|
||||
func TestRenderTOMLFail(t *testing.T) {
|
||||
@ -342,6 +359,8 @@ func TestRenderProtoBuf(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, string(protoData), w.Body.String())
|
||||
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) {
|
||||
@ -419,6 +438,8 @@ func TestRenderData(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "#!PNG some raw data", w.Body.String())
|
||||
assert.Equal(t, "image/png", w.Header().Get("Content-Type"))
|
||||
assert.Equal(t, "19", w.Header().Get("Content-Length"))
|
||||
|
||||
}
|
||||
|
||||
func TestRenderString(t *testing.T) {
|
||||
@ -451,6 +472,8 @@ func TestRenderStringLenZero(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
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, "10", w.Header().Get("Content-Length"))
|
||||
|
||||
}
|
||||
|
||||
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...)
|
||||
return
|
||||
}
|
||||
_, err = w.Write(bytesconv.StringToBytes(format))
|
||||
|
||||
bytes := bytesconv.StringToBytes(format)
|
||||
|
||||
writeContentLength(w, len(bytes))
|
||||
|
||||
_, err = w.Write(bytes)
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -26,6 +26,8 @@ func (r TOML) Render(w http.ResponseWriter) error {
|
||||
return err
|
||||
}
|
||||
|
||||
writeContentLength(w, len(bytes))
|
||||
|
||||
_, err = w.Write(bytes)
|
||||
return err
|
||||
}
|
||||
|
@ -26,6 +26,8 @@ func (r YAML) Render(w http.ResponseWriter) error {
|
||||
return err
|
||||
}
|
||||
|
||||
writeContentLength(w, len(bytes))
|
||||
|
||||
_, err = w.Write(bytes)
|
||||
return err
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user