mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-16 13:22:09 +08:00
debugged function actually working, passed tests
This commit is contained in:
parent
961513d2c1
commit
c716cb94b7
61
context.go
61
context.go
@ -5,6 +5,7 @@
|
||||
package gin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
@ -15,6 +16,7 @@ import (
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@ -956,25 +958,54 @@ 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".
|
||||
func (c *Context) JSONP(code int, obj any) {
|
||||
callback := c.DefaultQuery("callback", "")
|
||||
if callback == "" {
|
||||
c.Render(code, render.JSON{Data: obj})
|
||||
return
|
||||
}
|
||||
|
||||
// Add type checking for the callback function name
|
||||
callbackPattern := `^[\p{L}\p{N}_]+$` // Unicode-aware pattern for alphanumeric characters and underscores
|
||||
isValidCallback := regexp.MustCompile(callbackPattern).MatchString(callback)
|
||||
if !isValidCallback {
|
||||
// Handle the invalid callback function name, e.g., return an error or set a default callback function name
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid callback function name"})
|
||||
func (c *Context) JSONP(code int, obj interface{}) {
|
||||
// Get the callback query parameter from the request or use an empty string as the default value
|
||||
callback := c.DefaultQuery("callback", "")
|
||||
|
||||
// If the callback query parameter is empty, respond with a JSON object
|
||||
if callback == "" {
|
||||
c.Render(code, render.JSON{Data: obj})
|
||||
return
|
||||
}
|
||||
|
||||
c.Render(code, render.JsonpJSON{Callback: callback, Data: obj})
|
||||
|
||||
// Add type checking for the callback function name
|
||||
// Use a Unicode-aware pattern for alphanumeric characters and underscores
|
||||
callbackPattern := `^[\p{L}\p{N}_]+$`
|
||||
isValidCallback := regexp.MustCompile(callbackPattern).MatchString(callback)
|
||||
|
||||
// If the callback function name is not valid, respond with an error message
|
||||
if !isValidCallback {
|
||||
c.JSON(http.StatusBadRequest, H{"error": "Invalid callback function name"})
|
||||
return
|
||||
}
|
||||
|
||||
// Convert the input object to a slice of H (map[string]interface{}) values
|
||||
var data []H
|
||||
if d, ok := obj.([]H); ok {
|
||||
data = d
|
||||
} else if d, ok := obj.(H); ok {
|
||||
data = []H{d}
|
||||
} else {
|
||||
data = []H{{"message": obj}}
|
||||
}
|
||||
|
||||
// Convert the H slice to a slice of empty interface values
|
||||
var anyData []interface{}
|
||||
for _, item := range data {
|
||||
anyData = append(anyData, item)
|
||||
}
|
||||
|
||||
// Marshal the anyData slice to a JSON string
|
||||
jsonString, _ := json.Marshal(anyData)
|
||||
|
||||
// Respond with a JavaScript callback function call that includes the JSON data
|
||||
c.Render(code, render.String{Format: "/**/ typeof " + callback + " === 'function' && " + callback + "(%s);", Data: []interface{}{string(jsonString)}})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// JSON serializes the given struct as JSON into the response body.
|
||||
// It also sets the Content-Type as "application/json".
|
||||
func (c *Context) JSON(code int, obj any) {
|
||||
|
@ -2413,3 +2413,53 @@ func TestInterceptedHeader(t *testing.T) {
|
||||
assert.Equal(t, "", w.Result().Header.Get("X-Test"))
|
||||
assert.Equal(t, "present", w.Result().Header.Get("X-Test-2"))
|
||||
}
|
||||
|
||||
|
||||
func TestJSONPCallbackTypeChecking(t *testing.T) {
|
||||
router := New()
|
||||
router.GET("/jsonp", func(c *Context) {
|
||||
c.JSONP(http.StatusOK, H{"message": "success"})
|
||||
})
|
||||
testCases := []struct {
|
||||
callback string
|
||||
expected string
|
||||
statusCode int
|
||||
description string
|
||||
}{
|
||||
{
|
||||
callback: "validCallback",
|
||||
expected: `/**/ typeof validCallback === 'function' && validCallback([{"message":"success"}]);`,
|
||||
statusCode: http.StatusOK,
|
||||
description: "Valid callback function name",
|
||||
},
|
||||
|
||||
{
|
||||
callback: url.QueryEscape("invalidCallback();"),
|
||||
expected: "{\"error\":\"Invalid callback function name\"}",
|
||||
statusCode: http.StatusBadRequest,
|
||||
description: "Invalid callback function name",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
req, _ := http.NewRequest("GET", "/jsonp?callback="+tc.callback, nil)
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(resp, req)
|
||||
|
||||
if resp.Code != tc.statusCode {
|
||||
t.Errorf("Expected status code %d, got %d", tc.statusCode, resp.Code)
|
||||
}
|
||||
|
||||
actualBody := resp.Body.String()
|
||||
expectedBody := tc.expected
|
||||
if actualBody != expectedBody {
|
||||
t.Errorf("Expected response body %q, got %q", expectedBody, actualBody)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1071,7 +1071,9 @@ func main() {
|
||||
|
||||
#### JSONP
|
||||
|
||||
Using JSONP to request data from a server in a different domain. Add callback to response body if the query parameter callback exists.
|
||||
Using JSONP to request data from a server in a different domain. Add callback to response body if the query parameter `callback` exists and contains a valid callback function name. Valid callback function names consist of alphanumeric characters and underscores.
|
||||
|
||||
Note: To enhance security, Gin performs type checking on the JSONP callback function names. Only alphanumeric characters and underscores are allowed in the callback function names. If an invalid callback function name is provided, Gin will return an error. This type checking mechanism helps prevent attackers from exploiting the JSONP endpoint to bypass content security headers and execute malicious scripts.
|
||||
|
||||
```go
|
||||
func main() {
|
||||
@ -1093,7 +1095,7 @@ func main() {
|
||||
// client
|
||||
// curl http://127.0.0.1:8080/JSONP?callback=x
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### AsciiJSON
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user