Skip to content
This repository was archived by the owner on Jan 8, 2024. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions render/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
44 changes: 39 additions & 5 deletions render/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,21 @@ 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)
jsonBytes, err := json.Marshal(obj)
if err != nil {
return err
}

writeContentLength(w, len(jsonBytes))

_, err = w.Write(jsonBytes)
return err
}
Expand All @@ -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
}
Expand All @@ -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
}
Expand All @@ -115,33 +135,43 @@ 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
}

if _, err = w.Write(bytesconv.StringToBytes("(")); err != nil {
return err
}

if _, err = w.Write(ret); err != nil {
if _, err = w.Write(jsonBytes); err != nil {
return err
}

if _, err = w.Write(bytesconv.StringToBytes(");")); err != nil {
return err
}

length += len(callbackBytes) + 3 // 3 = len("();")

writeContentLength(w, length)

return nil
}

Expand All @@ -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
}

Expand Down
2 changes: 2 additions & 0 deletions render/protobuf.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ func (r ProtoBuf) Render(w http.ResponseWriter) error {
return err
}

writeContentLength(w, len(bytes))

_, err = w.Write(bytes)
return err
}
Expand Down
9 changes: 8 additions & 1 deletion render/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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))
}
23 changes: 23 additions & 0 deletions render/render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,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) {
Expand All @@ -60,6 +62,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) {
Expand All @@ -85,6 +89,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{{
Expand All @@ -97,6 +102,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) {
Expand All @@ -122,6 +128,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{{
Expand All @@ -134,6 +141,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"))

}

func TestRenderJsonpJSONError2(t *testing.T) {
Expand All @@ -149,6 +158,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) {
Expand All @@ -172,13 +182,16 @@ 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

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) {
Expand Down Expand Up @@ -240,6 +253,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{}
Expand Down Expand Up @@ -268,6 +283,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) {
Expand Down Expand Up @@ -296,6 +313,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) {
Expand Down Expand Up @@ -373,6 +392,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) {
Expand Down Expand Up @@ -405,6 +426,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) {
Expand Down
8 changes: 7 additions & 1 deletion render/text.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
2 changes: 2 additions & 0 deletions render/toml.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ func (r TOML) Render(w http.ResponseWriter) error {
return err
}

writeContentLength(w, len(bytes))

_, err = w.Write(bytes)
return err
}
Expand Down
2 changes: 2 additions & 0 deletions render/yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ func (r YAML) Render(w http.ResponseWriter) error {
return err
}

writeContentLength(w, len(bytes))

_, err = w.Write(bytes)
return err
}
Expand Down