From 4dda9236caceaace5bab6ac4a1d978b87159a8d6 Mon Sep 17 00:00:00 2001 From: ReaJason Date: Sun, 14 Dec 2025 19:24:25 +0800 Subject: [PATCH] docs: add springweb intro --- web/app/utils/transformer.ts | 5 +- web/bun.lock | 48 +++- web/content/docs/(shelltool)/godzilla.mdx | 4 +- web/content/docs/(shelltool)/suo5.mdx | 6 +- web/content/docs/meta.json | 1 + web/content/docs/servlet/filter.mdx | 2 +- web/content/docs/servlet/index.mdx | 4 +- web/content/docs/servlet/listener.mdx | 2 +- web/content/docs/servlet/servlet.mdx | 5 +- web/content/docs/springweb/controller.mdx | 5 + .../docs/springweb/handler-function.mdx | 5 + web/content/docs/springweb/handler-method.mdx | 5 + web/content/docs/springweb/index.mdx | 220 ++++++++++++++++++ web/content/docs/springweb/interceptor.mdx | 5 + web/content/docs/springweb/meta.json | 11 + web/content/docs/springweb/netty-handler.mdx | 5 + web/content/docs/springweb/webfilter.mdx | 5 + web/package.json | 4 +- 18 files changed, 311 insertions(+), 31 deletions(-) create mode 100644 web/content/docs/springweb/controller.mdx create mode 100644 web/content/docs/springweb/handler-function.mdx create mode 100644 web/content/docs/springweb/handler-method.mdx create mode 100644 web/content/docs/springweb/index.mdx create mode 100644 web/content/docs/springweb/interceptor.mdx create mode 100644 web/content/docs/springweb/meta.json create mode 100644 web/content/docs/springweb/netty-handler.mdx create mode 100644 web/content/docs/springweb/webfilter.mdx diff --git a/web/app/utils/transformer.ts b/web/app/utils/transformer.ts index aeed586f..e5759d30 100644 --- a/web/app/utils/transformer.ts +++ b/web/app/utils/transformer.ts @@ -4,10 +4,7 @@ import type { ShellToolConfig, } from "@/types/memshell"; import type { ProbeConfig, ProbeContentConfig } from "@/types/probeshell"; -import type { - MemShellFormSchema, - ProbeShellFormSchema, -} from "@/types/schema"; +import type { MemShellFormSchema, ProbeShellFormSchema } from "@/types/schema"; export function transformToPostData(formValue: MemShellFormSchema) { const shellConfig: ShellConfig = { diff --git a/web/bun.lock b/web/bun.lock index 0ed70e10..598a56c0 100644 --- a/web/bun.lock +++ b/web/bun.lock @@ -392,21 +392,21 @@ "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.53.3", "", { "os": "win32", "cpu": "x64" }, "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ=="], - "@shikijs/core": ["@shikijs/core@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-L7SrRibU7ZoYi1/TrZsJOFAnnHyLTE1SwHG1yNWjZIVCqjOEmCSuK2ZO9thnRbJG6TOkPp+Z963JmpCNw5nzvA=="], + "@shikijs/core": ["@shikijs/core@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-f2ED7HYV4JEk827mtMDwe/yQ25pRiXZmtHjWF8uzZKuKiEsJR7Ce1nuQ+HhV9FzDcbIo4ObBCD9GPTzNuy9S1g=="], - "@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-ZfWJNm2VMhKkQIKT9qXbs76RRcT0SF/CAvEz0+RkpUDAoDaCx0uFdCGzSRiD9gSlhm6AHkjdieOBJMaO2eC1rQ=="], + "@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-OFx8fHAZuk7I42Z9YAdZ95To6jDePQ9Rnfbw9uSRTSbBhYBp1kEOKv/3jOimcj3VRUKusDYM6DswLauwfhboLg=="], - "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-1hRxtYIJfJSZeM5ivbUXv9hcJP3PWRo5prG/V2sWwiubUKTa+7P62d2qxCW8jiVFX4pgRHhnHNp+qeR7Xl+6kg=="], + "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-Yx3gy7xLzM0ZOjqoxciHjA7dAt5tyzJE3L4uQoM83agahy+PlW244XJSrmJRSBvGYELDhYXPacD4R/cauV5bzQ=="], - "@shikijs/langs": ["@shikijs/langs@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0" } }, "sha512-dBMFzzg1QiXqCVQ5ONc0z2ebyoi5BKz+MtfByLm0o5/nbUu3Iz8uaTCa5uzGiscQKm7lVShfZHU1+OG3t5hgwg=="], + "@shikijs/langs": ["@shikijs/langs@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0" } }, "sha512-le+bssCxcSHrygCWuOrYJHvjus6zhQ2K7q/0mgjiffRbkhM4o1EWu2m+29l0yEsHDbWaWPNnDUTRVVBvBBeKaA=="], - "@shikijs/rehype": ["@shikijs/rehype@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0", "@types/hast": "^3.0.4", "hast-util-to-string": "^3.0.1", "shiki": "3.19.0", "unified": "^11.0.5", "unist-util-visit": "^5.0.0" } }, "sha512-pzp/JVxrTd95HgMimHgYb9lCGSzVYEp1BweWUprFAEgGOF15d9IyX+IVW/+1Z5ZxdT9IUUF27UbC5YdA5oCzjw=="], + "@shikijs/rehype": ["@shikijs/rehype@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0", "@types/hast": "^3.0.4", "hast-util-to-string": "^3.0.1", "shiki": "3.20.0", "unified": "^11.0.5", "unist-util-visit": "^5.0.0" } }, "sha512-/sqob3V/lJK0m2mZ64nkcWPN88im0D9atkI3S3PUBvtJZTHnJXVwZhHQFRDyObgEIa37IpHYHR3CuFtXB5bT2g=="], - "@shikijs/themes": ["@shikijs/themes@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0" } }, "sha512-H36qw+oh91Y0s6OlFfdSuQ0Ld+5CgB/VE6gNPK+Hk4VRbVG/XQgkjnt4KzfnnoO6tZPtKJKHPjwebOCfjd6F8A=="], + "@shikijs/themes": ["@shikijs/themes@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0" } }, "sha512-U1NSU7Sl26Q7ErRvJUouArxfM2euWqq1xaSrbqMu2iqa+tSp0D1Yah8216sDYbdDHw4C8b75UpE65eWorm2erQ=="], - "@shikijs/transformers": ["@shikijs/transformers@3.19.0", "", { "dependencies": { "@shikijs/core": "3.19.0", "@shikijs/types": "3.19.0" } }, "sha512-e6vwrsyw+wx4OkcrDbL+FVCxwx8jgKiCoXzakVur++mIWVcgpzIi8vxf4/b4dVTYrV/nUx5RjinMf4tq8YV8Fw=="], + "@shikijs/transformers": ["@shikijs/transformers@3.20.0", "", { "dependencies": { "@shikijs/core": "3.20.0", "@shikijs/types": "3.20.0" } }, "sha512-PrHHMRr3Q5W1qB/42kJW6laqFyWdhrPF2hNR9qjOm1xcSiAO3hAHo7HaVyHE6pMyevmy3i51O8kuGGXC78uK3g=="], - "@shikijs/types": ["@shikijs/types@3.19.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-Z2hdeEQlzuntf/BZpFG8a+Fsw9UVXdML7w0o3TgSXV3yNESGon+bs9ITkQb3Ki7zxoXOOu5oJWqZ2uto06V9iQ=="], + "@shikijs/types": ["@shikijs/types@3.20.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw=="], "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], @@ -490,7 +490,7 @@ "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], - "@types/node": ["@types/node@25.0.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-czWPzKIAXucn9PtsttxmumiQ9N0ok9FrBwgRWrwmVLlp86BrMExzvXRLFYRJ+Ex3g6yqj+KuaxfX1JTgV2lpfg=="], + "@types/node": ["@types/node@25.0.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-gWEkeiyYE4vqjON/+Obqcoeffmk0NF15WSBwSs7zwVA2bAbTaE0SJ7P0WNGoJn8uE7fiaV5a7dKYIJriEqOrmA=="], "@types/parse-json": ["@types/parse-json@4.0.2", "", {}, "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw=="], @@ -722,7 +722,7 @@ "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - "fumadocs-core": ["fumadocs-core@16.2.4", "", { "dependencies": { "@formatjs/intl-localematcher": "^0.6.2", "@orama/orama": "^3.1.16", "@shikijs/rehype": "^3.19.0", "@shikijs/transformers": "^3.19.0", "estree-util-value-to-estree": "^3.5.0", "github-slugger": "^2.0.0", "hast-util-to-estree": "^3.1.3", "hast-util-to-jsx-runtime": "^2.3.6", "image-size": "^2.0.2", "negotiator": "^1.0.0", "npm-to-yarn": "^3.0.1", "path-to-regexp": "^8.3.0", "remark": "^15.0.1", "remark-gfm": "^4.0.1", "remark-rehype": "^11.1.2", "scroll-into-view-if-needed": "^3.1.0", "shiki": "^3.19.0", "unist-util-visit": "^5.0.0" }, "peerDependencies": { "@mixedbread/sdk": "^0.19.0", "@orama/core": "1.x.x", "@tanstack/react-router": "1.x.x", "@types/react": "*", "algoliasearch": "5.x.x", "lucide-react": "*", "next": "16.x.x", "react": "^19.2.0", "react-dom": "^19.2.0", "react-router": "7.x.x", "waku": "^0.26.0 || ^0.27.0", "zod": "*" }, "optionalPeers": ["@mixedbread/sdk", "@orama/core", "@tanstack/react-router", "@types/react", "algoliasearch", "lucide-react", "next", "react", "react-dom", "react-router", "waku", "zod"] }, "sha512-vCxmRdZz8jNSXao4UF0+KgQQ4HgXww5LFGF883PemyJxHrgYuBbCslkSZP0mgpVWWcJWRE52gChUl4hI9YAxBQ=="], + "fumadocs-core": ["fumadocs-core@16.2.5", "", { "dependencies": { "@formatjs/intl-localematcher": "^0.6.2", "@orama/orama": "^3.1.16", "@shikijs/rehype": "^3.20.0", "@shikijs/transformers": "^3.20.0", "estree-util-value-to-estree": "^3.5.0", "github-slugger": "^2.0.0", "hast-util-to-estree": "^3.1.3", "hast-util-to-jsx-runtime": "^2.3.6", "image-size": "^2.0.2", "negotiator": "^1.0.0", "npm-to-yarn": "^3.0.1", "path-to-regexp": "^8.3.0", "remark": "^15.0.1", "remark-gfm": "^4.0.1", "remark-rehype": "^11.1.2", "scroll-into-view-if-needed": "^3.1.0", "shiki": "^3.20.0", "unist-util-visit": "^5.0.0" }, "peerDependencies": { "@mixedbread/sdk": "^0.19.0", "@orama/core": "1.x.x", "@tanstack/react-router": "1.x.x", "@types/react": "*", "algoliasearch": "5.x.x", "lucide-react": "*", "next": "16.x.x", "react": "^19.2.0", "react-dom": "^19.2.0", "react-router": "7.x.x", "waku": "^0.26.0 || ^0.27.0", "zod": "*" }, "optionalPeers": ["@mixedbread/sdk", "@orama/core", "@tanstack/react-router", "@types/react", "algoliasearch", "lucide-react", "next", "react", "react-dom", "react-router", "waku", "zod"] }, "sha512-u07n2oQJ2XaEQpWOdCyJnICYEasQiZhTFNf40C+Q2AJ3kKFeiz42mHccea0t/sjfBbO9pEDHyvZVHhSf/Cm3AA=="], "fumadocs-mdx": ["fumadocs-mdx@14.1.0", "", { "dependencies": { "@mdx-js/mdx": "^3.1.1", "@standard-schema/spec": "^1.0.0", "chokidar": "^5.0.0", "esbuild": "^0.27.1", "estree-util-value-to-estree": "^3.5.0", "js-yaml": "^4.1.1", "mdast-util-to-markdown": "^2.1.2", "picocolors": "^1.1.1", "picomatch": "^4.0.3", "remark-mdx": "^3.1.1", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.3", "zod": "^4.1.13" }, "peerDependencies": { "@fumadocs/mdx-remote": "^1.4.0", "fumadocs-core": "^15.0.0 || ^16.0.0", "next": "^15.3.0 || ^16.0.0", "react": "*", "vite": "6.x.x || 7.x.x" }, "optionalPeers": ["@fumadocs/mdx-remote", "next", "react", "vite"], "bin": { "fumadocs-mdx": "dist/bin.js" } }, "sha512-6I3nXzM3+dSap5UZvKFQvOaKNKdMfxK5/8Cyu3am6zm0d/acuUxT1r1s1GQpc8H5iB9bFMtwyoZff1WN2qWq8g=="], @@ -1178,7 +1178,7 @@ "shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="], - "shiki": ["shiki@3.19.0", "", { "dependencies": { "@shikijs/core": "3.19.0", "@shikijs/engine-javascript": "3.19.0", "@shikijs/engine-oniguruma": "3.19.0", "@shikijs/langs": "3.19.0", "@shikijs/themes": "3.19.0", "@shikijs/types": "3.19.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-77VJr3OR/VUZzPiStyRhADmO2jApMM0V2b1qf0RpfWya8Zr1PeZev5AEpPGAAKWdiYUtcZGBE4F5QvJml1PvWA=="], + "shiki": ["shiki@3.20.0", "", { "dependencies": { "@shikijs/core": "3.20.0", "@shikijs/engine-javascript": "3.20.0", "@shikijs/engine-oniguruma": "3.20.0", "@shikijs/langs": "3.20.0", "@shikijs/themes": "3.20.0", "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-kgCOlsnyWb+p0WU+01RjkCH+eBVsjL1jOwUYWv0YDWkM2/A46+LDKVs5yZCUXjJG6bj4ndFoAg5iLIIue6dulg=="], "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], @@ -1360,6 +1360,8 @@ "fumadocs-mdx/esbuild": ["esbuild@0.27.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.1", "@esbuild/android-arm": "0.27.1", "@esbuild/android-arm64": "0.27.1", "@esbuild/android-x64": "0.27.1", "@esbuild/darwin-arm64": "0.27.1", "@esbuild/darwin-x64": "0.27.1", "@esbuild/freebsd-arm64": "0.27.1", "@esbuild/freebsd-x64": "0.27.1", "@esbuild/linux-arm": "0.27.1", "@esbuild/linux-arm64": "0.27.1", "@esbuild/linux-ia32": "0.27.1", "@esbuild/linux-loong64": "0.27.1", "@esbuild/linux-mips64el": "0.27.1", "@esbuild/linux-ppc64": "0.27.1", "@esbuild/linux-riscv64": "0.27.1", "@esbuild/linux-s390x": "0.27.1", "@esbuild/linux-x64": "0.27.1", "@esbuild/netbsd-arm64": "0.27.1", "@esbuild/netbsd-x64": "0.27.1", "@esbuild/openbsd-arm64": "0.27.1", "@esbuild/openbsd-x64": "0.27.1", "@esbuild/openharmony-arm64": "0.27.1", "@esbuild/sunos-x64": "0.27.1", "@esbuild/win32-arm64": "0.27.1", "@esbuild/win32-ia32": "0.27.1", "@esbuild/win32-x64": "0.27.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA=="], + "fumadocs-ui/fumadocs-core": ["fumadocs-core@16.2.4", "", { "dependencies": { "@formatjs/intl-localematcher": "^0.6.2", "@orama/orama": "^3.1.16", "@shikijs/rehype": "^3.19.0", "@shikijs/transformers": "^3.19.0", "estree-util-value-to-estree": "^3.5.0", "github-slugger": "^2.0.0", "hast-util-to-estree": "^3.1.3", "hast-util-to-jsx-runtime": "^2.3.6", "image-size": "^2.0.2", "negotiator": "^1.0.0", "npm-to-yarn": "^3.0.1", "path-to-regexp": "^8.3.0", "remark": "^15.0.1", "remark-gfm": "^4.0.1", "remark-rehype": "^11.1.2", "scroll-into-view-if-needed": "^3.1.0", "shiki": "^3.19.0", "unist-util-visit": "^5.0.0" }, "peerDependencies": { "@mixedbread/sdk": "^0.19.0", "@orama/core": "1.x.x", "@tanstack/react-router": "1.x.x", "@types/react": "*", "algoliasearch": "5.x.x", "lucide-react": "*", "next": "16.x.x", "react": "^19.2.0", "react-dom": "^19.2.0", "react-router": "7.x.x", "waku": "^0.26.0 || ^0.27.0", "zod": "*" }, "optionalPeers": ["@mixedbread/sdk", "@orama/core", "@tanstack/react-router", "@types/react", "algoliasearch", "lucide-react", "next", "react", "react-dom", "react-router", "waku", "zod"] }, "sha512-vCxmRdZz8jNSXao4UF0+KgQQ4HgXww5LFGF883PemyJxHrgYuBbCslkSZP0mgpVWWcJWRE52gChUl4hI9YAxBQ=="], + "mime-types/mime-db": ["mime-db@1.33.0", "", {}, "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ=="], "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], @@ -1448,6 +1450,30 @@ "fumadocs-mdx/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.1", "", { "os": "win32", "cpu": "x64" }, "sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw=="], + "fumadocs-ui/fumadocs-core/@shikijs/rehype": ["@shikijs/rehype@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0", "@types/hast": "^3.0.4", "hast-util-to-string": "^3.0.1", "shiki": "3.19.0", "unified": "^11.0.5", "unist-util-visit": "^5.0.0" } }, "sha512-pzp/JVxrTd95HgMimHgYb9lCGSzVYEp1BweWUprFAEgGOF15d9IyX+IVW/+1Z5ZxdT9IUUF27UbC5YdA5oCzjw=="], + + "fumadocs-ui/fumadocs-core/@shikijs/transformers": ["@shikijs/transformers@3.19.0", "", { "dependencies": { "@shikijs/core": "3.19.0", "@shikijs/types": "3.19.0" } }, "sha512-e6vwrsyw+wx4OkcrDbL+FVCxwx8jgKiCoXzakVur++mIWVcgpzIi8vxf4/b4dVTYrV/nUx5RjinMf4tq8YV8Fw=="], + + "fumadocs-ui/fumadocs-core/shiki": ["shiki@3.19.0", "", { "dependencies": { "@shikijs/core": "3.19.0", "@shikijs/engine-javascript": "3.19.0", "@shikijs/engine-oniguruma": "3.19.0", "@shikijs/langs": "3.19.0", "@shikijs/themes": "3.19.0", "@shikijs/types": "3.19.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-77VJr3OR/VUZzPiStyRhADmO2jApMM0V2b1qf0RpfWya8Zr1PeZev5AEpPGAAKWdiYUtcZGBE4F5QvJml1PvWA=="], + "ansi-align/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "fumadocs-ui/fumadocs-core/@shikijs/rehype/@shikijs/types": ["@shikijs/types@3.19.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-Z2hdeEQlzuntf/BZpFG8a+Fsw9UVXdML7w0o3TgSXV3yNESGon+bs9ITkQb3Ki7zxoXOOu5oJWqZ2uto06V9iQ=="], + + "fumadocs-ui/fumadocs-core/@shikijs/transformers/@shikijs/core": ["@shikijs/core@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-L7SrRibU7ZoYi1/TrZsJOFAnnHyLTE1SwHG1yNWjZIVCqjOEmCSuK2ZO9thnRbJG6TOkPp+Z963JmpCNw5nzvA=="], + + "fumadocs-ui/fumadocs-core/@shikijs/transformers/@shikijs/types": ["@shikijs/types@3.19.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-Z2hdeEQlzuntf/BZpFG8a+Fsw9UVXdML7w0o3TgSXV3yNESGon+bs9ITkQb3Ki7zxoXOOu5oJWqZ2uto06V9iQ=="], + + "fumadocs-ui/fumadocs-core/shiki/@shikijs/core": ["@shikijs/core@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-L7SrRibU7ZoYi1/TrZsJOFAnnHyLTE1SwHG1yNWjZIVCqjOEmCSuK2ZO9thnRbJG6TOkPp+Z963JmpCNw5nzvA=="], + + "fumadocs-ui/fumadocs-core/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-ZfWJNm2VMhKkQIKT9qXbs76RRcT0SF/CAvEz0+RkpUDAoDaCx0uFdCGzSRiD9gSlhm6AHkjdieOBJMaO2eC1rQ=="], + + "fumadocs-ui/fumadocs-core/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-1hRxtYIJfJSZeM5ivbUXv9hcJP3PWRo5prG/V2sWwiubUKTa+7P62d2qxCW8jiVFX4pgRHhnHNp+qeR7Xl+6kg=="], + + "fumadocs-ui/fumadocs-core/shiki/@shikijs/langs": ["@shikijs/langs@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0" } }, "sha512-dBMFzzg1QiXqCVQ5ONc0z2ebyoi5BKz+MtfByLm0o5/nbUu3Iz8uaTCa5uzGiscQKm7lVShfZHU1+OG3t5hgwg=="], + + "fumadocs-ui/fumadocs-core/shiki/@shikijs/themes": ["@shikijs/themes@3.19.0", "", { "dependencies": { "@shikijs/types": "3.19.0" } }, "sha512-H36qw+oh91Y0s6OlFfdSuQ0Ld+5CgB/VE6gNPK+Hk4VRbVG/XQgkjnt4KzfnnoO6tZPtKJKHPjwebOCfjd6F8A=="], + + "fumadocs-ui/fumadocs-core/shiki/@shikijs/types": ["@shikijs/types@3.19.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-Z2hdeEQlzuntf/BZpFG8a+Fsw9UVXdML7w0o3TgSXV3yNESGon+bs9ITkQb3Ki7zxoXOOu5oJWqZ2uto06V9iQ=="], } } diff --git a/web/content/docs/(shelltool)/godzilla.mdx b/web/content/docs/(shelltool)/godzilla.mdx index e2bf4df8..06bb891d 100644 --- a/web/content/docs/(shelltool)/godzilla.mdx +++ b/web/content/docs/(shelltool)/godzilla.mdx @@ -53,14 +53,14 @@ import { Step, Steps } from 'fumadocs-ui/components/steps'; -### 生成 Tomcat WebSocket Godzilla 马 +### 生成 WebSocket 马 目前仅支持 Tomcat,当选中 Tomcat Godzilla,可以在内存马挂载类型处选择 WebSocket 内存马 ![godzilla_websocket](../images/godzilla_websocket.png) -### 下载并装载 GZWebsocket.jar 插件 +### 下载并装载插件 下载链接:https://github.com/xsshim/GzWebsocket/blob/main/plugins/GzWebsocket.jar?raw=true diff --git a/web/content/docs/(shelltool)/suo5.mdx b/web/content/docs/(shelltool)/suo5.mdx index ad800907..6cb2e2e5 100644 --- a/web/content/docs/(shelltool)/suo5.mdx +++ b/web/content/docs/(shelltool)/suo5.mdx @@ -12,16 +12,12 @@ import { Step, Steps } from 'fumadocs-ui/components/steps'; ![experience](../images/suo5.gif) -## Suo5 v2 版本主要特性 +## 主要特性 - **优异的传输性能** - 全双工:借助双向 Chunked-Encoding 实现单连接双向通信,传输性能接近 FRP - 半双工:下行长连接 + 上行短连接实现,在 Nginx 反代场景下仍可保持良好性能 - 短链接:上下行均使用短连接,适配多层反代和严格限制长连接的场景,作为兜底方案 -- **良好的服务端兼容性** - - Java 支持 Tomcat、WebLogic、JBoss、Resin 等主流中间件,JDK6 ~ JDK 2x 全版本支持 - - .Net 支持 IIS 下所有 .Net Framework 版本 (>=2.0) - - PHP 支持 Nginx/Apache 等服务器环境,PHP 5.6 ~ PHP 8.x 全版本支持 - **复杂网络环境支持** - 支持一层、两层、多层反向代理下的稳定连接 - 支持通过流量转发和请求重试来支持负载均衡场景 diff --git a/web/content/docs/meta.json b/web/content/docs/meta.json index f1c8c8b7..d1510c1b 100644 --- a/web/content/docs/meta.json +++ b/web/content/docs/meta.json @@ -10,6 +10,7 @@ "---内存马生成器---", "memshell-core-config", "servlet", + "springweb", "custom-memshell", "---内存马工具---", "...(shelltool)", diff --git a/web/content/docs/servlet/filter.mdx b/web/content/docs/servlet/filter.mdx index 71afda94..7110676c 100644 --- a/web/content/docs/servlet/filter.mdx +++ b/web/content/docs/servlet/filter.mdx @@ -1,5 +1,5 @@ --- -title: Filter 内存马 +title: Filter --- > [Servlet 3.1 规范 — Filter 主要概念](https://github.com/waylau/servlet-3.1-specification/blob/master/docs/Filtering/6.2%20Main%20Concepts.md) diff --git a/web/content/docs/servlet/index.mdx b/web/content/docs/servlet/index.mdx index 02468af7..b3710421 100644 --- a/web/content/docs/servlet/index.mdx +++ b/web/content/docs/servlet/index.mdx @@ -2,9 +2,7 @@ title: Java Servlet 规范内存马 --- -Java SE 中我们可以创建 socket 服务端为用户提供服务,但需要用户使用 socket 客户端,当然也可以基于 socket 实现 HTTP 协议,WebFlux 就是这样子的存在。而在 Java EE 中,Java 制定了 Servlet 规范,来规范在 Java 中提供 HTTP 服务的编写方式,其中有两个重要的概念,Servlet 与 Servlet Container。Servlet 是基于 Java 的 Web 组件,由容器进行管理,提供动态内容。Servlet 容器用于提供基于请求/响应发送模式的服务,必须支持 HTTP,并且管理 Servlet 的生命周期,使 Servlet 在一个受限的安全环境中执行。 - -Servlet 规范旨在让开发者基于规范开发的应用,可以部署在任意满足规范的 Web 容器上。每个 Servlet 规范版本都引入了一些新的东西,Servlet 4.0 前的版本变更可查看 [java-servlet-version-history](https://www.codejava.net/java-ee/servlet/java-servlet-version-history)。 +在 Java EE 中,Java 制定了 Servlet 规范,来规范在 Java 中提供 HTTP 服务的编写方式,其中有两个重要的概念,Servlet 与 Servlet Container。Servlet 是基于 Java 的 Web 组件,由容器进行管理,提供动态内容。Servlet 容器用于提供基于请求/响应发送模式的服务,必须支持 HTTP,并且管理 Servlet 的生命周期,使 Servlet 在一个受限的安全环境中执行。Servlet 规范旨在让开发者基于规范开发的应用,可以部署在任意满足规范的 Web 容器上。在 Java Servlet 规范中处理基础的 Servlet Web 组件,还声明了 Filter 和 Listener 两个 Web 组件用于辅助开发,这些 Web 组件都由 ServletContext 进行管理。 目前常见的 Servlet 规范就是 [Servlet 3.1](https://github.com/waylau/servlet-3.1-specification/blob/master/docs), Tomcat 8.x 版本就是 Servlet 3.1 版本,从 Servlet 5.0 开始,Java EE 更名为 Jakarta EE,包路径从 **javax** 改为 **jakarta**。目前最新 Servlet 规范为 Jakarta Servlet 6.1,可前往 https://jakarta.ee/specifications/servlet/ 查看。 diff --git a/web/content/docs/servlet/listener.mdx b/web/content/docs/servlet/listener.mdx index f76bc33b..90750c42 100644 --- a/web/content/docs/servlet/listener.mdx +++ b/web/content/docs/servlet/listener.mdx @@ -1,5 +1,5 @@ --- -title: Listener 内存马 +title: Listener --- > [Servlet 3.1 规范 - 事件监听器](https://github.com/waylau/servlet-3.1-specification/blob/master/docs/Application%20Lifecycle%20Events/11.2%20Event%20Listeners.md) diff --git a/web/content/docs/servlet/servlet.mdx b/web/content/docs/servlet/servlet.mdx index 76a24c00..349f9c9e 100644 --- a/web/content/docs/servlet/servlet.mdx +++ b/web/content/docs/servlet/servlet.mdx @@ -1,10 +1,11 @@ --- -title: Servlet 内存马 +title: Servlet --- > [Servlet 3.1 规范 — 什么是 Servlet](https://github.com/waylau/servlet-3.1-specification/blob/master/docs/Overview/1.1%20What%20is%20a%20Servlet.md) -Servlet 是基于 Java 的 Web 组件,由容器进行管理,提供动态内容。 +Servlet 是基于 Java 的 Web 组件,就是我们常说的 Web 接口,例如 /hello,JSP 技术也是 Java Servlet 规范的一部分,JSP 文件解析之后也会成为 Servlet 提供 HTTP 服务,只不过它的接口是 JSP 文件名,例如 /app/hello.jsp。 +Servlet 规范中规定了,对于非分布式应用来说,Servlet 容器必须确保对于每个 Servlet 定义只存在一个实例,但是 Web 服务是多线程的,所以 Servlet 是线程不安全的,在 Servlet 中的成员变量都是线程不安全的。 ## HttpServlet diff --git a/web/content/docs/springweb/controller.mdx b/web/content/docs/springweb/controller.mdx new file mode 100644 index 00000000..42398cdc --- /dev/null +++ b/web/content/docs/springweb/controller.mdx @@ -0,0 +1,5 @@ +--- +title: WebMVC Controller +--- + +WIP \ No newline at end of file diff --git a/web/content/docs/springweb/handler-function.mdx b/web/content/docs/springweb/handler-function.mdx new file mode 100644 index 00000000..191b8904 --- /dev/null +++ b/web/content/docs/springweb/handler-function.mdx @@ -0,0 +1,5 @@ +--- +title: WebFlux HandlerFunction +--- + +WIP \ No newline at end of file diff --git a/web/content/docs/springweb/handler-method.mdx b/web/content/docs/springweb/handler-method.mdx new file mode 100644 index 00000000..67efdcba --- /dev/null +++ b/web/content/docs/springweb/handler-method.mdx @@ -0,0 +1,5 @@ +--- +title: WebFlux HandlerMethod +--- + +WIP \ No newline at end of file diff --git a/web/content/docs/springweb/index.mdx b/web/content/docs/springweb/index.mdx new file mode 100644 index 00000000..e55a6134 --- /dev/null +++ b/web/content/docs/springweb/index.mdx @@ -0,0 +1,220 @@ +--- +title: Spring Web 框架内存马 +--- + +在 Java 企业级开发生态中,使用最为广泛的当属 Spring 全家桶,从 SSH(Spring + SpringWebMVC + Hibernate)到 SSM(Spring + SpringWebMVC + MyBatis),XML 配置文件到注解配置方式,最后 Spring Boot 以其自动装配原理,可零配置装配各种 Spring 生态得以广泛使用。 +Spring Web 框架中不仅提供了传统的 SpringWebMVC 还提供了异步编程模型的 SpringWebFlux,基于 Netty 开发的 Reactor,常见的 Spring Boot Web 使用的是 SpringWebMVC,而 Spring Gateway(Spring Cloud)则使用的是 SpringWebFlux。 + +SpringWebMVC 衍生出来的内存马有 Interceptor、Controller、HandlerMethod、HandlerFunction 等等 +SpirngWebFlux 衍生出来的内存马有 WebFilter、HandlerMethod、HandlerFunction、NettyHandler 等等。 + +## Spring 框架 + +Java 是一门面向对象语言,需要对象我们就 new 一个,对于一个 Java 大型项目来说一般充斥着成百上千的类,为了提高项目的可维护性,出现了大量 [准则](https://java-design-patterns.com/principles/) 和 [设计模式](https://java-design-patterns.com/patterns/) ,其中单一职责原则是亘古不变的道理也是最难遵守的。 +为了遵守单一职责原则,我们会把同一职责的函数放在一个类中,并在业务类中组合各种类实现功能,久而久之我们业务类可能依赖了超多其他功能类,如果业务没有组织良好,一时半会可能难以发现其依赖关系,例如: + +```java +public class A { + public void f1(){ + // so many code in here + A2 a2 = new A2(); + // do + // so many code in here + A4 a4 = new A4(); + // do + } + + public void f2(){ + // so many code in here + B1 b1 = new B1(); + // do something + + // so many code in here + B6 b6 = new B6(); + // do something + } +} +``` + +因此出现一种设计模式叫作 [依赖注入(Dependency Injection,简称 DI)](https://zh.wikipedia.org/zh-cn/%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5),通过依赖注入实现了 [控制反转(Inversion of Control,缩写为 IoC)](https://zh.wikipedia.org/wiki/%E6%8E%A7%E5%88%B6%E5%8F%8D%E8%BD%AC),Spring 框架正是一款依赖注入的框架,用户不再关心对象的创建,而是需要什么就注入什么,这样既解耦(接口方式传入不同实现类)也方便对类进行测试(传入 mock 类),例如: + +```java +public class A { + private A2 a2; + private A4 a4; + private B1 b1; + private B6 b6; + + // 通过构造方式注入 + public A(A2 a2, A4, a4, B1 b1, B6 b6) { + this.a2 = a2; + this.a4 = a4; + this.b1 = b1; + this.b6 = b6; + } + + public void f1(){ + // so many code in here + this.a2.do(); + // do + // so many code in here + this.a2.do(); + // do + } + + public void f2(){ + // so many code in here + this.b1.do(); + // do something + + // so many code in here + this.b6.do(); + // do something + } +} +``` + +org.springframework.beans 和 org.springframework.context 包是 Spring Framework 的 IoC 容器的基础。BeanFactory 接口提供了一种高级配置机制,能够管理任何类型的对象。 +org.springframework.aop 提供了 Spring 自己定义的 AOP 概念整合 AspectJ 对 Bean 进行增强,使得我们能面向切面编程,例如事务、日志、安全等等。 + +ApplicationContext 是 BeanFactory 的子接口。在漏洞注入中我们常用的是 org.springframework.context.support.ClassPathXmlApplicationContext,解析 XML bean 配置, +而后来 Spring 提供了基于注解的 bean 配置方式,也是目前最常用的,使用的是 org.springframework.context.annotation.AnnotationConfigApplicationContext。因此在 Spring 应用中我们只要想法设法拿到 ApplicationContext 我们就能手动管理业务中几乎所有的 Java 对象。 + +## Spring Web 框架 + +### Spring WebMVC + +> [官方文档 - Spring Web MVC](https://docs.spring.io/spring-framework/reference/web/webmvc.html) + +Spirng WebMVC 对 Java Servlet 规范进行封装实现 MVC 架构,可以部署在任意实现 Java Servlet 规范的容器上。 + +通过 org.springframework.web.servlet.DispatcherServlet 配置 `/*` 的 urlPattern,实现接管业务访问入口,让所有流量进入 Spring WebMVC 框架。其中最重要的方法是 `doDispatcher`,可以从中窥视 Spring WebMVC 处理请求的主流程。 +```java +protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { + HttpServletRequest processedRequest = request; + HandlerExecutionChain mappedHandler = null; + + try { + ModelAndView mv = null; + Exception dispatchException = null; + + try { + // 通过 HandlerMapping 获取 Handler + mappedHandler = getHandler(processedRequest); + if (mappedHandler == null || mappedHandler.getHandler() == null) { + noHandlerFound(processedRequest, response); + return; + } + + // Handler 可以五花八门,为了接口统一会转换成对应的 HandlerAdapter + HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); + + // 执行 Interceptor preHandler 方法,判断是否还需要继续执行 + if (!mappedHandler.applyPreHandle(processedRequest, response)) { + return; + } + + // 处理 Handler 中的逻辑,也就是 Controller 中的具体业务代码 + mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); + + // 执行 Interceptor postHandler 方法 + mappedHandler.applyPostHandle(processedRequest, response, mv); + } + catch (Exception ex) { + dispatchException = ex; + } + catch (Throwable err) { + // ... + } + + // 对返回的 ModelAndView 进行封装转为响应流放回给用户 + processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); + } + catch (Exception ex) { + triggerAfterCompletion(processedRequest, response, mappedHandler, ex); + } + catch (Throwable err) { + triggerAfterCompletion(processedRequest, response, mappedHandler, + new NestedServletException("Handler processing failed", err)); + } + finally { + // ... + } +} + +protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { + // 遍历 handlerMappings,查看有没有能处理当前 request 的 handler。 + for (HandlerMapping hm : this.handlerMappings) { + HandlerExecutionChain handler = hm.getHandler(request); + if (handler != null) { + return handler; + } + } + return null; +} +``` + +所谓 MVC 中的 C 控制器在 Spring WebMVC 实际上是 Handler,并且由 HandlerMapping 管理,因此我们最常注入的就是 Controller 内存马和 Interceptor 内存马。参考 [SpringWeb 内存马变型 - 银针安全](https://mp.weixin.qq.com/s/aWTcq3690F3CmGGo4A-a0w) 也可以实现其他内存马。 + + + 控制器,创建独特的 entrypoint 访问路径 + 拦截器,命中 webshell 逻辑中断请求 + + + + +### Spring WebFlux + +> [官方文档 - Spring WebFlux](https://docs.spring.io/spring-framework/reference/web/webflux.html) + +Spring WebFlux 使用 Reactive Streams 响应式异步非阻塞模型,相较于 Servlet API 阻塞模式,异步非阻塞模型能使用更少的资源提供更高的并发量,默认使用的 Netty 提供 HTTP 服务。 + +处理请求的核心类为 org.springframework.web.reactive.DispatcherHandler,其中最重要的方法是 `handle` 方法: + +```java +@Override +public Mono handle(ServerWebExchange exchange) { + if (this.handlerMappings == null) { + return createNotFoundError(); + } + if (CorsUtils.isPreFlightRequest(exchange.getRequest())) { + return handlePreFlight(exchange); + } + return Flux.fromIterable(this.handlerMappings) + .concatMap(mapping -> mapping.getHandler(exchange)) + .next() + .switchIfEmpty(createNotFoundError()) + .flatMap(handler -> invokeHandler(exchange, handler)) + .flatMap(result -> handleResult(exchange, result)); +} +``` + +和 Spring WebMVC 类似,也是通过遍历 HandlerMapping 找到合适 Handler 进行请求处理。 + +WebFlux 中同样可以使用 `@Controller` 和 `@RequestMapping`,因此也有 Controller 内存马,不过根据实现原理通常叫作 HandlerMethod,而 WebFlux 有个特殊的 RouterFunction 定义路由的方式叫作 HandlerFunction。WebFlux 框架内为了对请求实现过滤的效果,也设有 WebFilter 组件。 +当然底层使用的 Netty 提供的 HTTP 服务,因此也有 Netty Handler 马可以打,所以 WebFlux 常见的内存马就是 WebFilter、HandlerMethod、HandlerFunction 和 NettyHandler 马。 + + +过滤器,总是需要一种方式对所有进入的请求进行处理 + @RequestMapping,WebMVC 式创建路由的方式 + RouterFunction,函数式路由声明方式 + Netty Handler API 允许处理 request 和 response + \ No newline at end of file diff --git a/web/content/docs/springweb/interceptor.mdx b/web/content/docs/springweb/interceptor.mdx new file mode 100644 index 00000000..67def86f --- /dev/null +++ b/web/content/docs/springweb/interceptor.mdx @@ -0,0 +1,5 @@ +--- +title: WebMVC Interceptor +--- + +WIP \ No newline at end of file diff --git a/web/content/docs/springweb/meta.json b/web/content/docs/springweb/meta.json new file mode 100644 index 00000000..10a63797 --- /dev/null +++ b/web/content/docs/springweb/meta.json @@ -0,0 +1,11 @@ +{ + "title": "Spring Web 框架内存马", + "pages": [ + "controller", + "interceptor", + "webfilter", + "handler-method", + "handler-function", + "netty-handler" + ] +} diff --git a/web/content/docs/springweb/netty-handler.mdx b/web/content/docs/springweb/netty-handler.mdx new file mode 100644 index 00000000..8cc122ed --- /dev/null +++ b/web/content/docs/springweb/netty-handler.mdx @@ -0,0 +1,5 @@ +--- +title: WebFlux Netty Handler +--- + +WIP \ No newline at end of file diff --git a/web/content/docs/springweb/webfilter.mdx b/web/content/docs/springweb/webfilter.mdx new file mode 100644 index 00000000..8df5b1c6 --- /dev/null +++ b/web/content/docs/springweb/webfilter.mdx @@ -0,0 +1,5 @@ +--- +title: WebFlux WebFilter +--- + +hello \ No newline at end of file diff --git a/web/package.json b/web/package.json index ffde75d5..df8f813d 100644 --- a/web/package.json +++ b/web/package.json @@ -21,7 +21,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "framer-motion": "^12.23.26", - "fumadocs-core": "^16.2.4", + "fumadocs-core": "^16.2.5", "fumadocs-mdx": "14.1.0", "fumadocs-ui": "16.2.4", "i18next": "^25.7.2", @@ -46,7 +46,7 @@ "@react-router/dev": "^7.10.1", "@tailwindcss/vite": "^4.1.18", "@types/mdx": "^2.0.13", - "@types/node": "^25.0.1", + "@types/node": "^25.0.2", "@types/react": "^19.2.7", "@types/react-copy-to-clipboard": "^5.0.7", "@types/react-dom": "^19.2.3",