diff --git a/bytesconv.go b/bytesconv.go
index c430a80..6f8931b 100644
--- a/bytesconv.go
+++ b/bytesconv.go
@@ -12,6 +12,37 @@ import (
"unsafe"
)
+// AppendHTMLEscape appends html-escaped s to dst and returns the extended dst.
+func AppendHTMLEscape(dst []byte, s string) []byte {
+ var prev int
+ var sub string
+ for i, n := 0, len(s); i < n; i++ {
+ sub = ""
+ switch s[i] {
+ case '<':
+ sub = "<"
+ case '>':
+ sub = ">"
+ case '"':
+ sub = """
+ case '\'':
+ sub = "'"
+ }
+ if len(sub) > 0 {
+ dst = append(dst, s[prev:i]...)
+ dst = append(dst, sub...)
+ prev = i + 1
+ }
+ }
+ return append(dst, s[prev:]...)
+}
+
+// AppendHTMLEscapeBytes appends html-escaped s to dst and returns
+// the extended dst.
+func AppendHTMLEscapeBytes(dst, s []byte) []byte {
+ return AppendHTMLEscape(dst, unsafeBytesToStr(s))
+}
+
// AppendIPv4 appends string representation of the given ip v4 to dst
// and returns the extended dst.
func AppendIPv4(dst []byte, ip net.IP) []byte {
diff --git a/bytesconv_test.go b/bytesconv_test.go
index 83eb3d8..fde6f26 100644
--- a/bytesconv_test.go
+++ b/bytesconv_test.go
@@ -9,6 +9,21 @@ import (
"time"
)
+func TestAppendHTMLEscape(t *testing.T) {
+ testAppendHTMLEscape(t, "", "")
+ testAppendHTMLEscape(t, "<", "<")
+ testAppendHTMLEscape(t, "a", "a")
+ testAppendHTMLEscape(t, `><"''`, "><"''")
+ testAppendHTMLEscape(t, "foaxxx", "fo<b x='ss'>a</b>xxx")
+}
+
+func testAppendHTMLEscape(t *testing.T, s, expectedS string) {
+ buf := AppendHTMLEscapeBytes(nil, []byte(s))
+ if string(buf) != expectedS {
+ t.Fatalf("unexpected html-escaped string %q. Expecting %q. Original string %q", buf, expectedS, s)
+ }
+}
+
func TestParseIPv4(t *testing.T) {
testParseIPv4(t, "0.0.0.0", true)
testParseIPv4(t, "255.255.255.255", true)
diff --git a/bytesconv_timing_test.go b/bytesconv_timing_test.go
index e233502..bd416d1 100644
--- a/bytesconv_timing_test.go
+++ b/bytesconv_timing_test.go
@@ -2,10 +2,43 @@ package fasthttp
import (
"bufio"
+ "html"
"net"
"testing"
)
+func BenchmarkAppendHTMLEscape(b *testing.B) {
+ sOrig := "foobarbazxxxyyyzzz"
+ sExpected := string(AppendHTMLEscape(nil, sOrig))
+ b.RunParallel(func(pb *testing.PB) {
+ var buf []byte
+ for pb.Next() {
+ for i := 0; i < 10; i++ {
+ buf = AppendHTMLEscape(buf[:0], sOrig)
+ if string(buf) != sExpected {
+ b.Fatalf("unexpected escaped string: %s. Expecting %s", buf, sExpected)
+ }
+ }
+ }
+ })
+}
+
+func BenchmarkHTMLEscapeString(b *testing.B) {
+ sOrig := "foobarbazxxxyyyzzz"
+ sExpected := html.EscapeString(sOrig)
+ b.RunParallel(func(pb *testing.PB) {
+ var s string
+ for pb.Next() {
+ for i := 0; i < 10; i++ {
+ s = html.EscapeString(sOrig)
+ if s != sExpected {
+ b.Fatalf("unexpected escaped string: %s. Expecting %s", s, sExpected)
+ }
+ }
+ }
+ })
+}
+
func BenchmarkParseIPv4(b *testing.B) {
ipStr := []byte("123.145.167.189")
b.RunParallel(func(pb *testing.PB) {