Compare commits

...

5 Commits

Author SHA1 Message Date
Name
8ecf372eb5
Merge a14cf7c08dc37b7f9308248928aa3b16307f3c2f into 26c3a628655cad2388380cb8102d6ce7d4875f3b 2025-12-25 20:05:59 +08:00
Twacqwq
26c3a62865
chore(response): prevent Flush() panic when http.Flusher (#4479) 2025-12-24 18:35:20 +08:00
dependabot[bot]
22c274c84b
chore(deps): bump actions/cache from 4 to 5 in the actions group (#4469)
Bumps the actions group with 1 update: [actions/cache](https://github.com/actions/cache).


Updates `actions/cache` from 4 to 5
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-24 18:33:46 +08:00
1911860538
a14cf7c08d refactor(render): use WriteJSON when JsonpJson.Callback is empty 2025-11-08 22:06:23 +08:00
1911860538
b7afe5a6af fix(render): improve JsonpJSON content type handling and simplify Context.JSONP 2025-11-08 13:35:02 +08:00
5 changed files with 29 additions and 21 deletions

View File

@ -65,7 +65,7 @@ jobs:
with:
ref: ${{ github.ref }}
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: |
${{ matrix.go-build }}

View File

@ -1165,13 +1165,10 @@ func (c *Context) SecureJSON(code int, obj any) {
// JSONP serializes the given struct as JSON into the response body.
// It adds padding to response body to request data from a server residing in a different domain than the client.
// It also sets the Content-Type as "application/javascript".
//
// When the callback parameter is empty, it behaves equivalently to Context.JSON.
func (c *Context) JSONP(code int, obj any) {
callback := c.DefaultQuery("callback", "")
if callback == "" {
c.Render(code, render.JSON{Data: obj})
return
}
c.Render(code, render.JsonpJSON{Callback: callback, Data: obj})
c.Render(code, render.JsonpJSON{Callback: c.Query("callback"), Data: obj})
}
// JSON serializes the given struct as JSON into the response body.

View File

@ -115,14 +115,14 @@ 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.API.Marshal(r.Data)
if err != nil {
return err
if r.Callback == "" {
return WriteJSON(w, r.Data)
}
if r.Callback == "" {
_, err = w.Write(ret)
r.WriteContentType(w)
ret, err := json.API.Marshal(r.Data)
if err != nil {
return err
}

View File

@ -183,19 +183,28 @@ func TestRenderJsonpJSONError(t *testing.T) {
assert.Equal(t, `write "`+`);`+`" error`, err.Error())
}
func TestRenderJsonpJSONError2(t *testing.T) {
func TestRenderJsonpJSONWithEmptyCallback(t *testing.T) {
w := httptest.NewRecorder()
data := map[string]any{
"foo": "bar",
"num": 42,
"nested": map[string]any{
"key": "value",
},
}
(JsonpJSON{"", data}).WriteContentType(w)
assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type"))
e := (JsonpJSON{"", data}).Render(w)
require.NoError(t, e)
err := (JsonpJSON{Callback: "", Data: data}).Render(w)
assert.JSONEq(t, "{\"foo\":\"bar\"}", w.Body.String())
assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type"))
require.NoError(t, err)
// Verify Content-Type is set to jsonContentType when callback is empty
assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
renderData, err := json.API.Marshal(data)
require.NoError(t, err)
// Verify body contains correct JSON data
assert.JSONEq(t, string(renderData), w.Body.String())
}
func TestRenderJsonpJSONFail(t *testing.T) {

View File

@ -128,7 +128,9 @@ func (w *responseWriter) CloseNotify() <-chan bool {
// Flush implements the http.Flusher interface.
func (w *responseWriter) Flush() {
w.WriteHeaderNow()
w.ResponseWriter.(http.Flusher).Flush()
if f, ok := w.ResponseWriter.(http.Flusher); ok {
f.Flush()
}
}
func (w *responseWriter) Pusher() (pusher http.Pusher) {