hono 4.12.9 → 4.12.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/adapter/aws-lambda/handler.js +9 -2
  2. package/dist/cjs/adapter/aws-lambda/handler.js +9 -2
  3. package/dist/cjs/helper/css/common.js +56 -7
  4. package/dist/cjs/helper/css/index.js +11 -4
  5. package/dist/cjs/helper/ssg/ssg.js +12 -8
  6. package/dist/cjs/helper/ssg/utils.js +9 -0
  7. package/dist/cjs/jsx/base.js +7 -1
  8. package/dist/cjs/jsx/dom/css.js +11 -4
  9. package/dist/cjs/jsx/dom/render.js +39 -17
  10. package/dist/cjs/jsx/jsx-runtime.js +3 -0
  11. package/dist/cjs/jsx/utils.js +155 -5
  12. package/dist/cjs/middleware/body-limit/index.js +21 -30
  13. package/dist/cjs/middleware/cache/index.js +11 -3
  14. package/dist/cjs/middleware/compress/index.js +4 -0
  15. package/dist/cjs/middleware/cors/index.js +2 -5
  16. package/dist/cjs/middleware/ip-restriction/index.js +31 -9
  17. package/dist/cjs/middleware/method-override/index.js +1 -1
  18. package/dist/cjs/middleware/serve-static/index.js +1 -1
  19. package/dist/cjs/middleware/trailing-slash/index.js +2 -2
  20. package/dist/cjs/utils/cookie.js +26 -5
  21. package/dist/cjs/utils/ipaddr.js +10 -4
  22. package/dist/cjs/utils/jwt/jws.js +1 -1
  23. package/dist/cjs/utils/jwt/jwt.js +12 -6
  24. package/dist/helper/css/common.js +56 -7
  25. package/dist/helper/css/index.js +11 -4
  26. package/dist/helper/ssg/ssg.js +19 -9
  27. package/dist/helper/ssg/utils.js +8 -0
  28. package/dist/jsx/base.js +13 -2
  29. package/dist/jsx/dom/css.js +11 -4
  30. package/dist/jsx/dom/render.js +39 -17
  31. package/dist/jsx/jsx-runtime.js +4 -1
  32. package/dist/jsx/utils.js +153 -5
  33. package/dist/middleware/body-limit/index.js +21 -30
  34. package/dist/middleware/cache/index.js +11 -3
  35. package/dist/middleware/compress/index.js +4 -0
  36. package/dist/middleware/cors/index.js +2 -5
  37. package/dist/middleware/ip-restriction/index.js +34 -10
  38. package/dist/middleware/method-override/index.js +1 -1
  39. package/dist/middleware/serve-static/index.js +1 -1
  40. package/dist/middleware/trailing-slash/index.js +2 -2
  41. package/dist/tsconfig.build.tsbuildinfo +1 -1
  42. package/dist/types/helper/css/common.d.ts +20 -3
  43. package/dist/types/helper/css/index.d.ts +9 -2
  44. package/dist/types/helper/ssg/utils.d.ts +1 -0
  45. package/dist/types/jsx/dom/css.d.ts +8 -2
  46. package/dist/types/jsx/utils.d.ts +3 -1
  47. package/dist/types/middleware/cache/index.d.ts +2 -0
  48. package/dist/types/middleware/cors/index.d.ts +1 -1
  49. package/dist/types/middleware/ip-restriction/index.d.ts +38 -2
  50. package/dist/types/middleware/trailing-slash/index.d.ts +16 -0
  51. package/dist/types/types.d.ts +116 -116
  52. package/dist/types/utils/ipaddr.d.ts +12 -0
  53. package/dist/utils/cookie.js +26 -5
  54. package/dist/utils/ipaddr.js +7 -3
  55. package/dist/utils/jwt/jws.js +1 -1
  56. package/dist/utils/jwt/jwt.js +12 -6
  57. package/package.json +1 -1
@@ -45,6 +45,17 @@ var getEventSpec = (key) => {
45
45
  };
46
46
  var toAttributeName = (element, key) => nameSpaceContext && element instanceof SVGElement && /[A-Z]/.test(key) && (key in element.style || // Presentation attributes are findable in style object. "clip-path", "font-size", "stroke-width", etc.
47
47
  key.match(/^(?:o|pai|str|u|ve)/)) ? key.replace(/([A-Z])/g, "-$1").toLowerCase() : key;
48
+ var normalizeFormValue = (value) => value === null || value === void 0 || value === false ? null : value;
49
+ var applySelectValue = (select, props) => {
50
+ if (!("value" in props)) {
51
+ return;
52
+ }
53
+ select.value = normalizeFormValue(props["value"]);
54
+ if (!select.multiple && select.selectedIndex === -1) {
55
+ select.selectedIndex = 0;
56
+ }
57
+ };
58
+ var isIgnorableAttributeError = (error) => error instanceof DOMException && error.name === "InvalidCharacterError";
48
59
  var applyProps = (container, attributes, oldAttributes) => {
49
60
  attributes ||= {};
50
61
  for (let key in attributes) {
@@ -88,18 +99,14 @@ var applyProps = (container, attributes, oldAttributes) => {
88
99
  } else {
89
100
  if (key === "value") {
90
101
  const nodeName = container.nodeName;
91
- if (nodeName === "INPUT" || nodeName === "TEXTAREA" || nodeName === "SELECT") {
102
+ if (nodeName === "SELECT") {
103
+ continue;
104
+ } else if (nodeName === "INPUT" || nodeName === "TEXTAREA") {
92
105
  ;
93
- container.value = value === null || value === void 0 || value === false ? null : value;
106
+ container.value = normalizeFormValue(value);
94
107
  if (nodeName === "TEXTAREA") {
95
108
  container.textContent = value;
96
109
  continue;
97
- } else if (nodeName === "SELECT") {
98
- if (container.selectedIndex === -1) {
99
- ;
100
- container.selectedIndex = 0;
101
- }
102
- continue;
103
110
  }
104
111
  }
105
112
  } else if (key === "checked" && container.nodeName === "INPUT" || key === "selected" && container.nodeName === "OPTION") {
@@ -107,14 +114,20 @@ var applyProps = (container, attributes, oldAttributes) => {
107
114
  container[key] = value;
108
115
  }
109
116
  const k = toAttributeName(container, key);
110
- if (value === null || value === void 0 || value === false) {
111
- container.removeAttribute(k);
112
- } else if (value === true) {
113
- container.setAttribute(k, "");
114
- } else if (typeof value === "string" || typeof value === "number") {
115
- container.setAttribute(k, value);
116
- } else {
117
- container.setAttribute(k, value.toString());
117
+ try {
118
+ if (value === null || value === void 0 || value === false) {
119
+ container.removeAttribute(k);
120
+ } else if (value === true) {
121
+ container.setAttribute(k, "");
122
+ } else if (typeof value === "string" || typeof value === "number") {
123
+ container.setAttribute(k, value);
124
+ } else {
125
+ container.setAttribute(k, value.toString());
126
+ }
127
+ } catch (e) {
128
+ if (!isIgnorableAttributeError(e)) {
129
+ throw e;
130
+ }
118
131
  }
119
132
  }
120
133
  }
@@ -130,7 +143,13 @@ var applyProps = (container, attributes, oldAttributes) => {
130
143
  } else if (key === "ref") {
131
144
  refCleanupMap.get(container)?.();
132
145
  } else {
133
- container.removeAttribute(toAttributeName(container, key));
146
+ try {
147
+ container.removeAttribute(toAttributeName(container, key));
148
+ } catch (e) {
149
+ if (!isIgnorableAttributeError(e)) {
150
+ throw e;
151
+ }
152
+ }
134
153
  }
135
154
  }
136
155
  }
@@ -268,6 +287,9 @@ var applyNodeObject = (node, container, isNew) => {
268
287
  el = child.e ||= child.n ? document.createElementNS(child.n, child.tag) : document.createElement(child.tag);
269
288
  applyProps(el, child.props, child.pP);
270
289
  applyNodeObject(child, el, isNewLocal);
290
+ if (child.tag === "select") {
291
+ applySelectValue(el, child.props);
292
+ }
271
293
  }
272
294
  }
273
295
  if (child.tag === HONO_PORTAL_ELEMENT) {
@@ -3,8 +3,11 @@ import { jsxDEV, Fragment } from "./jsx-dev-runtime.js";
3
3
  import { jsxDEV as jsxDEV2 } from "./jsx-dev-runtime.js";
4
4
  import { html, raw } from "../helper/html/index.js";
5
5
  import { escapeToBuffer, stringBufferToString } from "../utils/html.js";
6
- import { styleObjectForEach } from "./utils.js";
6
+ import { isValidAttributeName, styleObjectForEach } from "./utils.js";
7
7
  var jsxAttr = (key, v) => {
8
+ if (!isValidAttributeName(key)) {
9
+ return raw("");
10
+ }
8
11
  const buffer = [`${key}="`];
9
12
  if (key === "style" && typeof v === "object") {
10
13
  let styleStr = "";
package/dist/jsx/utils.js CHANGED
@@ -10,18 +10,166 @@ var normalizeElementKeyMap = /* @__PURE__ */ new Map([
10
10
  ["formAction", "formaction"]
11
11
  ]);
12
12
  var normalizeIntrinsicElementKey = (key) => normalizeElementKeyMap.get(key) || key;
13
+ var invalidAttributeNameCharRe = /[\s"'<>/=`\\\x00-\x1f\x7f-\x9f]/;
14
+ var validAttributeNameCache = /* @__PURE__ */ new Set();
15
+ var validAttributeNameCacheMax = 1024;
16
+ var invalidTagNameCharRe = /^[!?]|[\s"'<>/=`\\\x00-\x1f\x7f-\x9f]/;
17
+ var validTagNameCache = /* @__PURE__ */ new Set();
18
+ var validTagNameCacheMax = 256;
19
+ var cacheValidName = (cache, max, name) => {
20
+ if (cache.size >= max) {
21
+ cache.clear();
22
+ }
23
+ cache.add(name);
24
+ };
25
+ var isValidTagName = (name) => {
26
+ if (validTagNameCache.has(name)) {
27
+ return true;
28
+ }
29
+ if (typeof name !== "string") {
30
+ return false;
31
+ }
32
+ if (name.length === 0) {
33
+ return true;
34
+ }
35
+ if (invalidTagNameCharRe.test(name)) {
36
+ return false;
37
+ }
38
+ cacheValidName(validTagNameCache, validTagNameCacheMax, name);
39
+ return true;
40
+ };
41
+ var isValidAttributeName = (name) => {
42
+ if (validAttributeNameCache.has(name)) {
43
+ return true;
44
+ }
45
+ const len = name.length;
46
+ if (len === 0) {
47
+ return false;
48
+ }
49
+ for (let i = 0; i < len; i++) {
50
+ const c = name.charCodeAt(i);
51
+ if (!(c >= 97 && c <= 122 || // a-z
52
+ c >= 65 && c <= 90 || // A-Z
53
+ c >= 48 && c <= 57 || // 0-9
54
+ c === 45 || // -
55
+ c === 95 || // _
56
+ c === 46 || // .
57
+ c === 58)) {
58
+ if (!invalidAttributeNameCharRe.test(name)) {
59
+ cacheValidName(validAttributeNameCache, validAttributeNameCacheMax, name);
60
+ return true;
61
+ } else {
62
+ return false;
63
+ }
64
+ }
65
+ }
66
+ cacheValidName(validAttributeNameCache, validAttributeNameCacheMax, name);
67
+ return true;
68
+ };
69
+ var invalidStylePropertyNameCharRe = /[\s"'():;\\/\[\]{}\x00-\x1f\x7f-\x9f]/;
70
+ var validStylePropertyNameCache = /* @__PURE__ */ new Set();
71
+ var validStylePropertyNameCacheMax = 1024;
72
+ var isValidStylePropertyName = (name) => {
73
+ if (validStylePropertyNameCache.has(name)) {
74
+ return true;
75
+ }
76
+ const len = name.length;
77
+ if (len === 0) {
78
+ return false;
79
+ }
80
+ for (let i = 0; i < len; i++) {
81
+ const c = name.charCodeAt(i);
82
+ if (!(c >= 97 && c <= 122 || // a-z
83
+ c >= 65 && c <= 90 || // A-Z
84
+ c >= 48 && c <= 57 || // 0-9
85
+ c === 45 || // -
86
+ c === 95)) {
87
+ if (!invalidStylePropertyNameCharRe.test(name)) {
88
+ cacheValidName(validStylePropertyNameCache, validStylePropertyNameCacheMax, name);
89
+ return true;
90
+ } else {
91
+ return false;
92
+ }
93
+ }
94
+ }
95
+ cacheValidName(validStylePropertyNameCache, validStylePropertyNameCacheMax, name);
96
+ return true;
97
+ };
98
+ var unsafeStyleValueCharRe = /[;"'\\/\[\](){}]/;
99
+ var hasUnsafeStyleValue = (value) => {
100
+ if (!unsafeStyleValueCharRe.test(value)) {
101
+ return false;
102
+ }
103
+ let quote = 0;
104
+ const blockStack = [];
105
+ for (let i = 0, len = value.length; i < len; i++) {
106
+ const c = value.charCodeAt(i);
107
+ if (c === 92) {
108
+ if (i === len - 1) {
109
+ return true;
110
+ }
111
+ i++;
112
+ } else if (quote !== 0) {
113
+ if (c === 10 || c === 12 || c === 13) {
114
+ return true;
115
+ }
116
+ if (c === quote) {
117
+ quote = 0;
118
+ }
119
+ } else if (c === 47 && value.charCodeAt(i + 1) === 42) {
120
+ const end = value.indexOf("*/", i + 2);
121
+ if (end === -1) {
122
+ return true;
123
+ }
124
+ i = end + 1;
125
+ } else if (c === 34 || c === 39) {
126
+ quote = c;
127
+ } else if (c === 40) {
128
+ blockStack.push(41);
129
+ } else if (c === 91) {
130
+ blockStack.push(93);
131
+ } else if (c === 123 || c === 125) {
132
+ return true;
133
+ } else if (c === 41 || c === 93) {
134
+ if (blockStack[blockStack.length - 1] !== c) {
135
+ return true;
136
+ }
137
+ blockStack.pop();
138
+ } else if (c === 59 && blockStack.length === 0) {
139
+ return true;
140
+ }
141
+ }
142
+ return quote !== 0 || blockStack.length !== 0;
143
+ };
13
144
  var styleObjectForEach = (style, fn) => {
14
145
  for (const [k, v] of Object.entries(style)) {
15
146
  const key = k[0] === "-" || !/[A-Z]/.test(k) ? k : k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
16
- fn(
17
- key,
18
- v == null ? null : typeof v === "number" ? !key.match(
147
+ if (!isValidStylePropertyName(key)) {
148
+ continue;
149
+ }
150
+ if (v == null) {
151
+ fn(key, null);
152
+ continue;
153
+ }
154
+ let value;
155
+ if (typeof v === "number") {
156
+ value = !key.match(
19
157
  /^(?:a|border-im|column(?:-c|s)|flex(?:$|-[^b])|grid-(?:ar|[^a])|font-w|li|or|sca|st|ta|wido|z)|ty$/
20
- ) ? `${v}px` : `${v}` : v
21
- );
158
+ ) ? `${v}px` : `${v}`;
159
+ } else if (typeof v === "string") {
160
+ if (hasUnsafeStyleValue(v)) {
161
+ continue;
162
+ }
163
+ value = v;
164
+ } else {
165
+ continue;
166
+ }
167
+ fn(key, value);
22
168
  }
23
169
  };
24
170
  export {
171
+ isValidAttributeName,
172
+ isValidTagName,
25
173
  normalizeIntrinsicElementKey,
26
174
  styleObjectForEach
27
175
  };
@@ -1,12 +1,6 @@
1
1
  // src/middleware/body-limit/index.ts
2
2
  import { HTTPException } from "../../http-exception.js";
3
3
  var ERROR_MESSAGE = "Payload Too Large";
4
- var BodyLimitError = class extends Error {
5
- constructor(message) {
6
- super(message);
7
- this.name = "BodyLimitError";
8
- }
9
- };
10
4
  var bodyLimit = (options) => {
11
5
  const onError = options.onError || (() => {
12
6
  const res = new Response(ERROR_MESSAGE, {
@@ -21,40 +15,37 @@ var bodyLimit = (options) => {
21
15
  }
22
16
  const hasTransferEncoding = c.req.raw.headers.has("transfer-encoding");
23
17
  const hasContentLength = c.req.raw.headers.has("content-length");
24
- if (hasTransferEncoding && hasContentLength) {
25
- }
26
18
  if (hasContentLength && !hasTransferEncoding) {
27
19
  const contentLength = parseInt(c.req.raw.headers.get("content-length") || "0", 10);
28
20
  return contentLength > maxSize ? onError(c) : next();
29
21
  }
30
22
  let size = 0;
23
+ const chunks = [];
31
24
  const rawReader = c.req.raw.body.getReader();
32
- const reader = new ReadableStream({
33
- async start(controller) {
34
- try {
35
- for (; ; ) {
36
- const { done, value } = await rawReader.read();
37
- if (done) {
38
- break;
39
- }
40
- size += value.length;
41
- if (size > maxSize) {
42
- controller.error(new BodyLimitError(ERROR_MESSAGE));
43
- break;
44
- }
45
- controller.enqueue(value);
25
+ for (; ; ) {
26
+ const { done, value } = await rawReader.read();
27
+ if (done) {
28
+ break;
29
+ }
30
+ size += value.length;
31
+ if (size > maxSize) {
32
+ return onError(c);
33
+ }
34
+ chunks.push(value);
35
+ }
36
+ const requestInit = {
37
+ body: new ReadableStream({
38
+ start(controller) {
39
+ for (const chunk of chunks) {
40
+ controller.enqueue(chunk);
46
41
  }
47
- } finally {
48
42
  controller.close();
49
43
  }
50
- }
51
- });
52
- const requestInit = { body: reader, duplex: "half" };
44
+ }),
45
+ duplex: "half"
46
+ };
53
47
  c.req.raw = new Request(c.req.raw, requestInit);
54
- await next();
55
- if (c.error instanceof BodyLimitError) {
56
- c.res = await onError(c);
57
- }
48
+ return next();
58
49
  };
59
50
  };
60
51
  export {
@@ -1,8 +1,7 @@
1
1
  // src/middleware/cache/index.ts
2
2
  var defaultCacheableStatusCodes = [200];
3
3
  var shouldSkipCache = (res) => {
4
- const vary = res.headers.get("Vary");
5
- if (vary && vary.includes("*")) {
4
+ if (res.headers.has("Vary")) {
6
5
  return true;
7
6
  }
8
7
  const cacheControl = res.headers.get("Cache-Control");
@@ -16,7 +15,12 @@ var shouldSkipCache = (res) => {
16
15
  };
17
16
  var cache = (options) => {
18
17
  if (!globalThis.caches) {
19
- console.log("Cache Middleware is not enabled because caches is not defined.");
18
+ if (options.onCacheNotAvailable === false) {
19
+ } else if (options.onCacheNotAvailable) {
20
+ options.onCacheNotAvailable();
21
+ } else {
22
+ console.log("Cache Middleware is not enabled because caches is not defined.");
23
+ }
20
24
  return async (_c, next) => await next();
21
25
  }
22
26
  if (options.wait === void 0) {
@@ -58,6 +62,10 @@ var cache = (options) => {
58
62
  }
59
63
  };
60
64
  return async function cache2(c, next) {
65
+ if (c.req.method !== "GET" || c.req.raw.headers.has("Authorization")) {
66
+ await next();
67
+ return;
68
+ }
61
69
  let key = c.req.url;
62
70
  if (options.keyGenerator) {
63
71
  key = await options.keyGenerator(c);
@@ -24,6 +24,10 @@ var compress = (options) => {
24
24
  ctx.res = new Response(ctx.res.body.pipeThrough(stream), ctx.res);
25
25
  ctx.res.headers.delete("Content-Length");
26
26
  ctx.res.headers.set("Content-Encoding", encoding);
27
+ const etag = ctx.res.headers.get("ETag");
28
+ if (etag && !etag.startsWith("W/")) {
29
+ ctx.res.headers.set("ETag", `W/${etag}`);
30
+ }
27
31
  };
28
32
  };
29
33
  var shouldCompress = (res) => {
@@ -1,13 +1,10 @@
1
1
  // src/middleware/cors/index.ts
2
2
  var cors = (options) => {
3
- const defaults = {
3
+ const opts = {
4
4
  origin: "*",
5
5
  allowMethods: ["GET", "HEAD", "PUT", "POST", "DELETE", "PATCH"],
6
6
  allowHeaders: [],
7
- exposeHeaders: []
8
- };
9
- const opts = {
10
- ...defaults,
7
+ exposeHeaders: [],
11
8
  ...options
12
9
  };
13
10
  const findAllowOrigin = ((optsOrigin) => {
@@ -1,10 +1,12 @@
1
1
  // src/middleware/ip-restriction/index.ts
2
2
  import { HTTPException } from "../../http-exception.js";
3
3
  import {
4
+ convertIPv4MappedIPv6ToIPv4,
4
5
  convertIPv4ToBinary,
5
6
  convertIPv6BinaryToString,
6
7
  convertIPv6ToBinary,
7
- distinctRemoteAddr
8
+ distinctRemoteAddr,
9
+ isIPv4MappedIPv6
8
10
  } from "../../utils/ipaddr.js";
9
11
  var IS_CIDR_NOTATION_REGEX = /\/[0-9]{0,3}$/;
10
12
  var buildMatcher = (rules) => {
@@ -24,12 +26,17 @@ var buildMatcher = (rules) => {
24
26
  if (type2 === void 0) {
25
27
  throw new TypeError(`Invalid rule: ${rule}`);
26
28
  }
27
- const isIPv4 = type2 === "IPv4";
28
- const prefix = parseInt(separatedRule[1]);
29
+ let isIPv4 = type2 === "IPv4";
30
+ let prefix = parseInt(separatedRule[1]);
29
31
  if (isIPv4 ? prefix === 32 : prefix === 128) {
30
32
  rule = addrStr;
31
33
  } else {
32
- const addr = (isIPv4 ? convertIPv4ToBinary : convertIPv6ToBinary)(addrStr);
34
+ let addr = (isIPv4 ? convertIPv4ToBinary : convertIPv6ToBinary)(addrStr);
35
+ if (type2 === "IPv6" && isIPv4MappedIPv6(addr) && prefix >= 96) {
36
+ isIPv4 = true;
37
+ addr = convertIPv4MappedIPv6ToIPv4(addr);
38
+ prefix -= 96;
39
+ }
33
40
  const mask = (1n << BigInt(prefix)) - 1n << BigInt((isIPv4 ? 32 : 128) - prefix);
34
41
  cidrRules.push([isIPv4, addr & mask, mask]);
35
42
  continue;
@@ -39,21 +46,38 @@ var buildMatcher = (rules) => {
39
46
  if (type === void 0) {
40
47
  throw new TypeError(`Invalid rule: ${rule}`);
41
48
  }
42
- staticRules.add(
43
- type === "IPv4" ? rule : convertIPv6BinaryToString(convertIPv6ToBinary(rule))
44
- // normalize IPv6 address (e.g. 0000:0000:0000:0000:0000:0000:0000:0001 => ::1)
45
- );
49
+ if (type === "IPv4") {
50
+ staticRules.add(rule);
51
+ staticRules.add(`::ffff:${rule}`);
52
+ } else {
53
+ const ipv6binary = convertIPv6ToBinary(rule);
54
+ const ipv6Addr = convertIPv6BinaryToString(ipv6binary);
55
+ staticRules.add(ipv6Addr);
56
+ if (isIPv4MappedIPv6(ipv6binary)) {
57
+ staticRules.add(ipv6Addr.substring(7));
58
+ }
59
+ }
46
60
  }
47
61
  }
48
62
  return (remote) => {
49
63
  if (staticRules.has(remote.addr)) {
50
64
  return true;
51
65
  }
66
+ const remoteAddr = remote.binaryAddr ||= (remote.isIPv4 ? convertIPv4ToBinary : convertIPv6ToBinary)(remote.addr);
67
+ const remoteIPv4Addr = remote.isIPv4 || isIPv4MappedIPv6(remoteAddr) ? remote.isIPv4 ? remoteAddr : convertIPv4MappedIPv6ToIPv4(remoteAddr) : void 0;
52
68
  for (const [isIPv4, addr, mask] of cidrRules) {
53
- if (isIPv4 !== remote.isIPv4) {
69
+ if (isIPv4) {
70
+ if (remoteIPv4Addr === void 0) {
71
+ continue;
72
+ }
73
+ if ((remoteIPv4Addr & mask) === addr) {
74
+ return true;
75
+ }
76
+ continue;
77
+ }
78
+ if (remote.isIPv4) {
54
79
  continue;
55
80
  }
56
- const remoteAddr = remote.binaryAddr ||= (isIPv4 ? convertIPv4ToBinary : convertIPv6ToBinary)(remote.addr);
57
81
  if ((remoteAddr & mask) === addr) {
58
82
  return true;
59
83
  }
@@ -28,7 +28,7 @@ var methodOverride = (options) => async function methodOverride2(c, next) {
28
28
  return app.fetch(request, c.env, getExecutionCtx(c));
29
29
  }
30
30
  }
31
- if (contentType === "application/x-www-form-urlencoded") {
31
+ if (contentType?.startsWith("application/x-www-form-urlencoded")) {
32
32
  const params = await parseBody(clonedRequest);
33
33
  const method = params[methodFormName];
34
34
  if (method) {
@@ -24,7 +24,7 @@ var serveStatic = (options) => {
24
24
  } else {
25
25
  try {
26
26
  filename = tryDecodeURI(c.req.path);
27
- if (/(?:^|[\/\\])\.\.(?:$|[\/\\])/.test(filename)) {
27
+ if (/(?:^|[\/\\])\.{1,2}(?:$|[\/\\])|[\/\\]{2,}/.test(filename)) {
28
28
  throw new Error();
29
29
  }
30
30
  } catch {
@@ -19,14 +19,14 @@ var trimTrailingSlash = (options) => {
19
19
  var appendTrailingSlash = (options) => {
20
20
  return async function appendTrailingSlash2(c, next) {
21
21
  if (options?.alwaysRedirect) {
22
- if ((c.req.method === "GET" || c.req.method === "HEAD") && c.req.path.at(-1) !== "/") {
22
+ if ((c.req.method === "GET" || c.req.method === "HEAD") && c.req.path.at(-1) !== "/" && !options.skip?.(c.req.path)) {
23
23
  const url = new URL(c.req.url);
24
24
  url.pathname += "/";
25
25
  return c.redirect(url.toString(), 301);
26
26
  }
27
27
  }
28
28
  await next();
29
- if (!options?.alwaysRedirect && c.res.status === 404 && (c.req.method === "GET" || c.req.method === "HEAD") && c.req.path.at(-1) !== "/") {
29
+ if (!options?.alwaysRedirect && c.res.status === 404 && (c.req.method === "GET" || c.req.method === "HEAD") && c.req.path.at(-1) !== "/" && !options?.skip?.(c.req.path)) {
30
30
  const url = new URL(c.req.url);
31
31
  url.pathname += "/";
32
32
  c.res = c.redirect(url.toString(), 301);