diff --git a/v2/maker.go b/v2/maker.go index b5db335..cc27992 100644 --- a/v2/maker.go +++ b/v2/maker.go @@ -34,6 +34,7 @@ var makers = map[string]MakeCheckFunc{ nameRequired: makeRequired, nameTrimSpace: makeTrimSpace, nameURL: makeURL, + nameURLEscape: makeURLEscape, } // makeChecks take a checker config and returns the check functions. diff --git a/v2/url_escape.go b/v2/url_escape.go new file mode 100644 index 0000000..9792281 --- /dev/null +++ b/v2/url_escape.go @@ -0,0 +1,37 @@ +// Copyright (c) 2023-2024 Onur Cinar. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. +// https://github.com/cinar/checker + +package v2 + +import ( + "net/url" + "reflect" +) + +const ( + // nameURLEscape is the name of the URL escape normalizer. + nameURLEscape = "url-escape" +) + +// normalizeURLEscape applies URL escaping to special characters. +// Uses net.url.QueryEscape for the actual escape operation. +func normalizeURLEscape(value string) (string, error) { + return url.QueryEscape(value), nil +} + +// checkURLEscape checks if the value is a valid URL escape string. +func checkURLEscape(value reflect.Value) (reflect.Value, error) { + escaped, err := normalizeURLEscape(value.Interface().(string)) + if err != nil { + return value, err + } + value.SetString(escaped) + return value, nil +} + +// makeURLEscape makes a normalizer function for the URL escape normalizer. +func makeURLEscape(_ string) CheckFunc[reflect.Value] { + return checkURLEscape +} diff --git a/v2/url_escape_test.go b/v2/url_escape_test.go new file mode 100644 index 0000000..9d64352 --- /dev/null +++ b/v2/url_escape_test.go @@ -0,0 +1,43 @@ +// Copyright (c) 2023-2024 Onur Cinar. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. +// https://github.com/cinar/checker + +package v2_test + +import ( + "testing" + + v2 "github.com/cinar/checker/v2" +) + +func TestNormalizeURLEscapeNonString(t *testing.T) { + defer FailIfNoPanic(t, "expected panic") + + type Request struct { + Query int `checkers:"url-escape"` + } + + request := &Request{} + + v2.CheckStruct(request) +} + +func TestNormalizeURLEscape(t *testing.T) { + type Request struct { + Query string `checkers:"url-escape"` + } + + request := &Request{ + Query: "param1/param2 = 1 + 2 & 3 + 4", + } + + _, valid := v2.CheckStruct(request) + if !valid { + t.Fail() + } + + if request.Query != "param1%2Fparam2+%3D+1+%2B+2+%26+3+%2B+4" { + t.Fail() + } +}