Skip to content
Open
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
19 changes: 12 additions & 7 deletions huma.go
Original file line number Diff line number Diff line change
Expand Up @@ -1361,7 +1361,12 @@ func setDeepObjectValue(pb *PathBuffer, res *ValidateResult, f reflect.Value, da
}
} else {
if val := field.Tag.Get("default"); val != "" {
setFieldValue(fv, val)
if err := setFieldValue(fv, val); err != nil {
pb.Push(fieldName)
res.Add(pb, val, err.Error())
pb.Pop()
continue
}
result[fieldName] = fv.Interface()
}
}
Expand All @@ -1377,19 +1382,19 @@ func setFieldValue(f reflect.Value, value string) error {
case reflect.Interface:
f.Set(reflect.ValueOf(value))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v, err := strconv.ParseInt(value, 10, 64)
v, err := strconv.ParseInt(value, 10, f.Type().Bits())
if err != nil {
return errors.New("invalid integer")
}
f.SetInt(v)
Comment thread
leonklingele marked this conversation as resolved.
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v, err := strconv.ParseUint(value, 10, 64)
v, err := strconv.ParseUint(value, 10, f.Type().Bits())
if err != nil {
return errors.New("invalid integer")
}
f.SetUint(v)
case reflect.Float32, reflect.Float64:
v, err := strconv.ParseFloat(value, 64)
v, err := strconv.ParseFloat(value, f.Type().Bits())
if err != nil {
return errors.New("invalid float")
}
Expand Down Expand Up @@ -1824,7 +1829,7 @@ func parseInto(ctx Context, f reflect.Value, value string, preSplit []string, p
f.SetString(value)
return value, nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v, err := strconv.ParseInt(value, 10, 64)
v, err := strconv.ParseInt(value, 10, p.Type.Bits())
if err != nil {
return nil, errors.New("invalid integer")
}
Expand All @@ -1833,7 +1838,7 @@ func parseInto(ctx Context, f reflect.Value, value string, preSplit []string, p

return v, nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v, err := strconv.ParseUint(value, 10, 64)
v, err := strconv.ParseUint(value, 10, p.Type.Bits())
if err != nil {
return nil, errors.New("invalid integer")
}
Expand All @@ -1842,7 +1847,7 @@ func parseInto(ctx Context, f reflect.Value, value string, preSplit []string, p

return v, nil
case reflect.Float32, reflect.Float64:
v, err := strconv.ParseFloat(value, 64)
v, err := strconv.ParseFloat(value, p.Type.Bits())
if err != nil {
return nil, errors.New("invalid float")
}
Expand Down
64 changes: 60 additions & 4 deletions huma_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -870,6 +870,28 @@ func TestFeatures(t *testing.T) {
Method: http.MethodGet,
URL: "/test?test[int]=1&test[uint]=12&test[float]=123.0&test[bool]=true&test[string]=foo&test[any]=foo&test2[foo]=a",
},
{
Name: "param-deepObject-default-overflow",
Register: func(t *testing.T, api huma.API) {
huma.Register(api, huma.Operation{
Method: http.MethodGet,
Path: "/test",
}, func(ctx context.Context, i *struct {
Test struct {
Name string `json:"name"`
Value int8 `json:"value" default:"128"`
} `query:"test,deepObject"`
}) (*struct{}, error) {
return nil, nil
})
},
Method: http.MethodGet,
URL: "/test?test[name]=foo",
Assert: func(t *testing.T, resp *httptest.ResponseRecorder) {
assert.Equal(t, http.StatusUnprocessableEntity, resp.Code)
assert.Contains(t, resp.Body.String(), "invalid integer")
},
},
{
Name: "param-deepObject-map-required",
Register: func(t *testing.T, api huma.API) {
Expand Down Expand Up @@ -2919,10 +2941,10 @@ Content-Type: text/plain
},
Method: http.MethodGet,
URL: "/transform",
Assert: func(t *testing.T, resp *httptest.ResponseRecorder) {
assert.Equal(t, http.StatusOK, resp.Code)
assert.JSONEq(t, `null`, resp.Body.String())
},
Assert: func(t *testing.T, resp *httptest.ResponseRecorder) {
assert.Equal(t, http.StatusOK, resp.Code)
assert.JSONEq(t, `null`, resp.Body.String())
},
},
{
Name: "schema-url-from-x-forwarded-host",
Expand Down Expand Up @@ -4975,3 +4997,37 @@ func TestWriteResponseTransformErrorStatus(t *testing.T) {
assert.Equal(t, http.StatusInternalServerError, res.StatusCode)
assert.Contains(t, string(body), "error transforming response")
}

func TestInputOverflowIsRejected(t *testing.T) {
mux, api := humatest.New(t, huma.DefaultConfig("Test API", "1.0.0"))

var handlerCalled bool
var gotVal int8

huma.Register(api, huma.Operation{
Method: http.MethodGet,
Path: "/number",
}, func(_ context.Context, input *struct {
Value int8 `query:"value"`
}) (*struct{}, error) {
handlerCalled = true
gotVal = input.Value
return &struct{}{}, nil
})

req := httptest.NewRequest(
http.MethodGet,
"/number?value=128",
nil,
)
res := httptest.NewRecorder()
mux.ServeHTTP(res, req)

if handlerCalled {
t.Fatalf("handler was called with value=%d, 128 is not representable as int8", gotVal)
}

if got := res.Code; got < 400 || got >= 500 {
t.Fatalf("expected a 4xx response status, got %d", got)
}
}
Loading