size: 2 KiB
| 1 | const std = @import("std"); |
| 2 | const t = std.testing; |
| 3 | const Io = std.Io; |
| 4 | |
| 5 | pub fn escapeAlloc(arena: std.mem.Allocator, text: []const u8) ![]const u8 { |
| 6 | var w = std.Io.Writer.Allocating.init(arena); |
| 7 | try escape(&w.writer, text); |
| 8 | return w.written(); |
| 9 | } |
| 10 | |
| 11 | pub fn escape(out: *std.Io.Writer, text: []const u8) !void { |
| 12 | for (text) |char| { |
| 13 | switch (char) { |
| 14 | '&' => try out.writeAll("&"), |
| 15 | '"' => try out.writeAll("""), |
| 16 | '\'' => try out.writeAll("'"), |
| 17 | '<' => try out.writeAll("<"), |
| 18 | '>' => try out.writeAll(">"), |
| 19 | else => try out.writeByte(char), |
| 20 | } |
| 21 | } |
| 22 | } |
| 23 | |
| 24 | test "escape" { |
| 25 | var buf: [4096]u8 = undefined; |
| 26 | inline for (.{ |
| 27 | .{ |
| 28 | "<script>alert(\"jello\")</script>", |
| 29 | "<script>alert("jello")</script>", |
| 30 | }, |
| 31 | .{ |
| 32 | "&\"'<>", |
| 33 | "&"'<>", |
| 34 | }, |
| 35 | }) |case| { |
| 36 | const input = case[0]; |
| 37 | const expected = case[1]; |
| 38 | var w = std.Io.Writer.fixed(&buf); |
| 39 | try escape(&w, input); |
| 40 | try t.expectEqualStrings(expected, w.buffered()); |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | pub fn percentEncode(out: *std.Io.Writer, text: []const u8) !void { |
| 45 | for (text) |char| { |
| 46 | switch (char) { |
| 47 | ':' => try out.writeAll("%3A"), |
| 48 | '/' => try out.writeAll("%2F"), |
| 49 | '?' => try out.writeAll("%3F"), |
| 50 | '#' => try out.writeAll("%23"), |
| 51 | '[' => try out.writeAll("%5B"), |
| 52 | ']' => try out.writeAll("%5D"), |
| 53 | '@' => try out.writeAll("%40"), |
| 54 | '!' => try out.writeAll("%21"), |
| 55 | '$' => try out.writeAll("%24"), |
| 56 | '&' => try out.writeAll("%26"), |
| 57 | '\'' => try out.writeAll("%27"), |
| 58 | '(' => try out.writeAll("%28"), |
| 59 | ')' => try out.writeAll("%29"), |
| 60 | '*' => try out.writeAll("%2A"), |
| 61 | '+' => try out.writeAll("%2B"), |
| 62 | ',' => try out.writeAll("%2C"), |
| 63 | ';' => try out.writeAll("%3B"), |
| 64 | '=' => try out.writeAll("%3D"), |
| 65 | '%' => try out.writeAll("%25"), |
| 66 | ' ' => try out.writeAll("%20"), |
| 67 | else => try out.writeByte(char), |
| 68 | } |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | pub fn percentEncodeAlloc(arena: std.mem.Allocator, text: []const u8) ![]const u8 { |
| 73 | var w = std.Io.Writer.Allocating.init(arena); |
| 74 | try percentEncode(&w.writer, text); |
| 75 | return w.written(); |
| 76 | } |
| 77 | |
| 78 | pub fn tag(w: *Io.Writer, tag_name: []const u8, text: []const u8) !void { |
| 79 | try w.print("<{s}>", .{tag_name}); |
| 80 | try escape(w, text); |
| 81 | try w.print("</{s}>\n", .{tag_name}); |
| 82 | } |