├── .github ├── dependabot.yml └── workflows │ ├── ci-version.yml │ └── ci.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── benches ├── data │ └── vgilante.txt └── encode.rs ├── rustfmt.toml ├── src ├── decode │ ├── element │ │ ├── decode_impl.rs │ │ ├── mod.rs │ │ ├── script.rs │ │ └── style.rs │ ├── html_entity │ │ ├── mod.rs │ │ └── tables.rs │ └── mod.rs ├── encode │ ├── element │ │ ├── encode_impl.rs │ │ ├── mod.rs │ │ ├── script.rs │ │ └── style.rs │ ├── html_entity │ │ ├── mod.rs │ │ └── unquoted_attribute.rs │ └── mod.rs ├── functions.rs └── lib.rs └── tests ├── element.rs └── html_entity.rs /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" -------------------------------------------------------------------------------- /.github/workflows/ci-version.yml: -------------------------------------------------------------------------------- 1 | name: CI-version 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | 8 | env: 9 | CARGO_TERM_COLOR: always 10 | 11 | jobs: 12 | tests: 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | os: 17 | - ubuntu-latest 18 | - macos-latest 19 | - windows-latest 20 | toolchain: 21 | - stable 22 | - nightly 23 | features: 24 | - 25 | - --no-default-features 26 | name: Test ${{ matrix.toolchain }} on ${{ matrix.os }} (${{ matrix.features }}) 27 | runs-on: ${{ matrix.os }} 28 | steps: 29 | - uses: actions/checkout@v4 30 | - uses: actions-rust-lang/setup-rust-toolchain@v1 31 | with: 32 | toolchain: ${{ matrix.toolchain }} 33 | - run: cargo test --release ${{ matrix.features }} 34 | - run: cargo doc --release ${{ matrix.features }} 35 | 36 | MSRV: 37 | strategy: 38 | fail-fast: false 39 | matrix: 40 | os: 41 | - ubuntu-latest 42 | - macos-latest 43 | - windows-latest 44 | toolchain: 45 | - 1.58 46 | features: 47 | - 48 | - --no-default-features 49 | name: Test ${{ matrix.toolchain }} on ${{ matrix.os }} (${{ matrix.features }}) 50 | runs-on: ${{ matrix.os }} 51 | steps: 52 | - uses: actions/checkout@v4 53 | - uses: actions-rust-lang/setup-rust-toolchain@v1 54 | with: 55 | toolchain: ${{ matrix.toolchain }} 56 | - run: cargo test --release --lib --bins ${{ matrix.features }} -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [ push, pull_request ] 4 | 5 | env: 6 | CARGO_TERM_COLOR: always 7 | 8 | jobs: 9 | rustfmt: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - uses: actions-rust-lang/setup-rust-toolchain@v1 14 | with: 15 | toolchain: nightly 16 | components: rustfmt 17 | - uses: actions-rust-lang/rustfmt@v1 18 | 19 | clippy: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v4 23 | - uses: actions-rust-lang/setup-rust-toolchain@v1 24 | with: 25 | components: clippy 26 | - run: cargo clippy --all-targets --all-features -- -D warnings 27 | 28 | tests: 29 | strategy: 30 | fail-fast: false 31 | matrix: 32 | os: 33 | - ubuntu-latest 34 | - macos-latest 35 | - windows-latest 36 | toolchain: 37 | - stable 38 | - nightly 39 | features: 40 | - 41 | - --no-default-features 42 | name: Test ${{ matrix.toolchain }} on ${{ matrix.os }} (${{ matrix.features }}) 43 | runs-on: ${{ matrix.os }} 44 | steps: 45 | - uses: actions/checkout@v4 46 | - uses: actions-rust-lang/setup-rust-toolchain@v1 47 | with: 48 | toolchain: ${{ matrix.toolchain }} 49 | - run: cargo test ${{ matrix.features }} 50 | - run: cargo doc ${{ matrix.features }} 51 | 52 | MSRV: 53 | strategy: 54 | fail-fast: false 55 | matrix: 56 | os: 57 | - ubuntu-latest 58 | - macos-latest 59 | - windows-latest 60 | toolchain: 61 | - 1.58 62 | features: 63 | - 64 | - --no-default-features 65 | name: Test ${{ matrix.toolchain }} on ${{ matrix.os }} (${{ matrix.features }}) 66 | runs-on: ${{ matrix.os }} 67 | steps: 68 | - uses: actions/checkout@v4 69 | - uses: actions-rust-lang/setup-rust-toolchain@v1 70 | with: 71 | toolchain: ${{ matrix.toolchain }} 72 | - run: cargo test --lib --bins ${{ matrix.features }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/intellij+all 2 | 3 | ### Intellij+all ### 4 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 5 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 6 | 7 | # User-specific stuff 8 | .idea/**/workspace.xml 9 | .idea/**/tasks.xml 10 | .idea/**/usage.statistics.xml 11 | .idea/**/dictionaries 12 | .idea/**/shelf 13 | 14 | # Sensitive or high-churn files 15 | .idea/**/dataSources/ 16 | .idea/**/dataSources.ids 17 | .idea/**/dataSources.local.xml 18 | .idea/**/sqlDataSources.xml 19 | .idea/**/dynamic.xml 20 | .idea/**/uiDesigner.xml 21 | .idea/**/dbnavigator.xml 22 | 23 | # Gradle 24 | .idea/**/gradle.xml 25 | .idea/**/libraries 26 | 27 | # Gradle and Maven with auto-import 28 | # When using Gradle or Maven with auto-import, you should exclude module files, 29 | # since they will be recreated, and may cause churn. Uncomment if using 30 | # auto-import. 31 | # .idea/modules.xml 32 | # .idea/*.iml 33 | # .idea/modules 34 | 35 | # CMake 36 | cmake-build-*/ 37 | 38 | # Mongo Explorer plugin 39 | .idea/**/mongoSettings.xml 40 | 41 | # File-based project format 42 | *.iws 43 | 44 | # IntelliJ 45 | out/ 46 | 47 | # mpeltonen/sbt-idea plugin 48 | .idea_modules/ 49 | 50 | # JIRA plugin 51 | atlassian-ide-plugin.xml 52 | 53 | # Cursive Clojure plugin 54 | .idea/replstate.xml 55 | 56 | # Crashlytics plugin (for Android Studio and IntelliJ) 57 | com_crashlytics_export_strings.xml 58 | crashlytics.properties 59 | crashlytics-build.properties 60 | fabric.properties 61 | 62 | # Editor-based Rest Client 63 | .idea/httpRequests 64 | 65 | ### Intellij+all Patch ### 66 | # Ignores the whole .idea folder and all .iml files 67 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 68 | 69 | .idea/ 70 | 71 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 72 | 73 | *.iml 74 | modules.xml 75 | .idea/misc.xml 76 | *.ipr 77 | 78 | 79 | # End of https://www.gitignore.io/api/intellij+all 80 | 81 | 82 | ### Rust ### 83 | # Generated by Cargo 84 | # will have compiled files and executables 85 | /target/ 86 | 87 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 88 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 89 | Cargo.lock 90 | 91 | # These are backup files generated by rustfmt 92 | **/*.rs.bk 93 | 94 | 95 | # End of https://www.gitignore.io/api/rust 96 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "html-escape" 3 | version = "0.2.13" 4 | authors = ["Magic Len "] 5 | edition = "2021" 6 | rust-version = "1.58" 7 | repository = "https://github.com/magiclen/html-escape" 8 | homepage = "https://magiclen.org/html-escape" 9 | keywords = ["html", "escape", "unescape", "encode", "decode"] 10 | categories = ["no-std", "encoding"] 11 | description = "This library is for encoding/escaping special characters in HTML and decoding/unescaping HTML entities as well." 12 | license = "MIT" 13 | include = ["src/**/*", "Cargo.toml", "README.md", "LICENSE", "benches/encode.rs"] 14 | 15 | [dependencies] 16 | utf8-width = "0.1" 17 | 18 | [dev-dependencies] 19 | bencher = "0.1.5" 20 | 21 | [features] 22 | default = ["std"] 23 | std = [] 24 | 25 | [[bench]] 26 | name = "encode" 27 | required-features = ["std"] 28 | harness = false 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 magiclen.org (Ron Li) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | HTML Escape 2 | ==================== 3 | 4 | [![CI](https://github.com/magiclen/html-escape/actions/workflows/ci.yml/badge.svg)](https://github.com/magiclen/html-escape/actions/workflows/ci.yml) 5 | 6 | This library is for encoding/escaping special characters in HTML and decoding/unescaping HTML entities as well. 7 | 8 | ## Usage 9 | 10 | ### Encoding 11 | 12 | This crate provides some `encode_*` functions to encode HTML text in different situations. 13 | 14 | For example, to put a text between a start tag `` and an end tag ``, use the `encode_text` function to escape every `&`, `<`, and `>` in the text. 15 | 16 | ```rust 17 | assert_eq!("a > b && a < c", html_escape::encode_text("a > b && a < c")); 18 | ``` 19 | 20 | The functions suffixed with `_to_writer`, `_to_vec` or `_to_string` are useful to generate HTML. 21 | 22 | ```rust 23 | let mut html = String::from("", &mut html)); 29 | html.push_str("');"); 30 | 31 | assert_eq!("", html); 32 | ``` 33 | 34 | ### Decoding 35 | 36 | ```rust 37 | assert_eq!("Hello world!", html_escape::decode_html_entities("Hello world!")); 38 | ``` 39 | 40 | ```rust 41 | assert_eq!("alert(');'", html_escape::decode_script(r"alert('` 140 | parse_script; 141 | /// Decode text from the `` 156 | /// * `\'` => `'` 157 | parse_script_single_quoted_text; 158 | /// Decode text from a single quoted text in the `` 173 | /// * `\"` => `"` 174 | parse_script_double_quoted_text; 175 | /// Decode text from a double quoted text in the `` 190 | /// * `\"` => `"` 191 | /// * `\'` => `'` 192 | parse_script_quoted_text; 193 | /// Decode text from a quoted text in the `` => `<\/script>` 168 | /// * `');alert('<\!--');", "alert('');alert('\");alert(\\'<\\!--\\');", "alert(\"\");alert('\\\");alert(\\'<\\!--\\');", "alert(\"\");alert('';} label::after { content: '<\!--';}", 220 | "div::after { content: '';} label::after { content: '\");alert(\\'<\\!--\\');", "alert(\"\");alert('\\\");alert(\\'<\\!--\\');", "alert(\"\");alert('