fix(websocket): keep upgraded WebSocket tunnels on dedicated lifecycle timeouts
This commit is contained in:
@@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
## Pending
|
## Pending
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
- keep upgraded WebSocket tunnels on dedicated WebSocket lifecycle timeouts instead of the HTTP socket timeout (rustproxy)
|
||||||
|
- keep upgraded WebSocket tunnels on dedicated lifecycle timeouts (websocket)
|
||||||
|
- Track active upgraded tunnels so HTTP idle and max-lifetime watchdogs do not terminate WebSocket connections
|
||||||
|
- Use dedicated default WebSocket inactivity and max-lifetime timeouts in rustproxy passthrough listeners
|
||||||
|
- Add end-to-end coverage for idle WebSockets surviving short HTTP socket timeouts
|
||||||
|
|
||||||
## 2026-05-24 - 27.11.0
|
## 2026-05-24 - 27.11.0
|
||||||
|
|
||||||
|
|||||||
Generated
+20
-137
@@ -1008,9 +1008,6 @@ packages:
|
|||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
'@push.rocks/consolecolor@2.0.3':
|
|
||||||
resolution: {integrity: sha512-hA+m0BMqEwZNSAS7c2aQFfoPkpX/dNdsHzkdLdeERUOy7BLacb9ItTUofGtjtginP0yDj4NSpqSjNYyX3Y8Y/w==}
|
|
||||||
|
|
||||||
'@push.rocks/consolecolor@2.0.4':
|
'@push.rocks/consolecolor@2.0.4':
|
||||||
resolution: {integrity: sha512-rQJfuSJLzm117PBpsfyemX8Q/rpKh8ZVc2AqDVu6RXJMJkmGkKsADe0/rnttuHZYss8IP7yJIN9E6Vnx+jyy0A==}
|
resolution: {integrity: sha512-rQJfuSJLzm117PBpsfyemX8Q/rpKh8ZVc2AqDVu6RXJMJkmGkKsADe0/rnttuHZYss8IP7yJIN9E6Vnx+jyy0A==}
|
||||||
|
|
||||||
@@ -1023,9 +1020,6 @@ packages:
|
|||||||
'@push.rocks/levelcache@3.2.2':
|
'@push.rocks/levelcache@3.2.2':
|
||||||
resolution: {integrity: sha512-g44xp3XmtSPlcTHQ8qoaNV0AK7w4cuLd6h7sGXXxldN3NLgjOUpUqnnyDBU9i5hpIIxqssxe8WRQz10bi9W+tA==}
|
resolution: {integrity: sha512-g44xp3XmtSPlcTHQ8qoaNV0AK7w4cuLd6h7sGXXxldN3NLgjOUpUqnnyDBU9i5hpIIxqssxe8WRQz10bi9W+tA==}
|
||||||
|
|
||||||
'@push.rocks/lik@6.3.1':
|
|
||||||
resolution: {integrity: sha512-UWDwGBaVx5yPtAFXqDDBtQZCzETUOA/7myQIXb+YBsuiIw4yQuhNZ23uY2ChQH2Zn6DLqdNSgQcYC0WywMZBNQ==}
|
|
||||||
|
|
||||||
'@push.rocks/lik@6.4.1':
|
'@push.rocks/lik@6.4.1':
|
||||||
resolution: {integrity: sha512-W5M2zoJWUxYnCVqUB7jaxMB4W1kfhs1P6SXvWGqwDpJAjMjCnZeAXD+w0akECgSBY1zCCT2qMj7YK4Gza0t25g==}
|
resolution: {integrity: sha512-W5M2zoJWUxYnCVqUB7jaxMB4W1kfhs1P6SXvWGqwDpJAjMjCnZeAXD+w0akECgSBY1zCCT2qMj7YK4Gza0t25g==}
|
||||||
|
|
||||||
@@ -1062,9 +1056,6 @@ packages:
|
|||||||
'@push.rocks/smartdata@7.1.7':
|
'@push.rocks/smartdata@7.1.7':
|
||||||
resolution: {integrity: sha512-HDI/Q9dKybfsJ68oCzlE+S63Xpij9qXnMfi28yznKP0Li1ECVZZMDDGIW5IjsXlHjO+Q+RJMcVd72Pjt3QLY5Q==}
|
resolution: {integrity: sha512-HDI/Q9dKybfsJ68oCzlE+S63Xpij9qXnMfi28yznKP0Li1ECVZZMDDGIW5IjsXlHjO+Q+RJMcVd72Pjt3QLY5Q==}
|
||||||
|
|
||||||
'@push.rocks/smartdelay@3.0.5':
|
|
||||||
resolution: {integrity: sha512-mUuI7kj2f7ztjpic96FvRIlf2RsKBa5arw81AHNsndbxO6asRcxuWL8dTVxouEIK8YsBUlj0AsrCkHhMbLQdHw==}
|
|
||||||
|
|
||||||
'@push.rocks/smartdelay@3.1.0':
|
'@push.rocks/smartdelay@3.1.0':
|
||||||
resolution: {integrity: sha512-59xveBMbWmbFhh/rqhQnYG/klg/VONG9hV8+RQ7ftqsNRkcmUT+VM5etAbODgAUvsF4lxK+xVR0tbZOo0kGhRQ==}
|
resolution: {integrity: sha512-59xveBMbWmbFhh/rqhQnYG/klg/VONG9hV8+RQ7ftqsNRkcmUT+VM5etAbODgAUvsF4lxK+xVR0tbZOo0kGhRQ==}
|
||||||
|
|
||||||
@@ -1074,9 +1065,6 @@ packages:
|
|||||||
'@push.rocks/smartenv@5.0.13':
|
'@push.rocks/smartenv@5.0.13':
|
||||||
resolution: {integrity: sha512-ACXmUcHZHl2CF2jnVuRw9saRRrZvJblCRs2d+K5aLR1DfkYFX3eA21kcMlKeLisI3aGNbIj9vz/rowN5qkRkfA==}
|
resolution: {integrity: sha512-ACXmUcHZHl2CF2jnVuRw9saRRrZvJblCRs2d+K5aLR1DfkYFX3eA21kcMlKeLisI3aGNbIj9vz/rowN5qkRkfA==}
|
||||||
|
|
||||||
'@push.rocks/smartenv@6.0.0':
|
|
||||||
resolution: {integrity: sha512-ktW5MqOFs0492sB4vrvl4lgRFQ/sQ4AyREgB+sCIzGqszHWGVvGXR95Y2a3z66jkLPYML2CUWHzmMlfv8fkG+A==}
|
|
||||||
|
|
||||||
'@push.rocks/smartenv@6.1.0':
|
'@push.rocks/smartenv@6.1.0':
|
||||||
resolution: {integrity: sha512-pKm5knYEkcHHc9XaYJ41Ya8/WfZB6fy1ZDB+TSLC85lvMrrRFLSsujjDehdDXl/mJr3MqecauTh2QzQIszTrjQ==}
|
resolution: {integrity: sha512-pKm5knYEkcHHc9XaYJ41Ya8/WfZB6fy1ZDB+TSLC85lvMrrRFLSsujjDehdDXl/mJr3MqecauTh2QzQIszTrjQ==}
|
||||||
|
|
||||||
@@ -1098,9 +1086,6 @@ packages:
|
|||||||
'@push.rocks/smartguard@3.1.0':
|
'@push.rocks/smartguard@3.1.0':
|
||||||
resolution: {integrity: sha512-J23q84f1O+TwFGmd4lrO9XLHUh2DaLXo9PN/9VmTWYzTkQDv5JehmifXVI0esophXcCIfbdIu6hbt7/aHlDF4A==}
|
resolution: {integrity: sha512-J23q84f1O+TwFGmd4lrO9XLHUh2DaLXo9PN/9VmTWYzTkQDv5JehmifXVI0esophXcCIfbdIu6hbt7/aHlDF4A==}
|
||||||
|
|
||||||
'@push.rocks/smarthash@3.2.6':
|
|
||||||
resolution: {integrity: sha512-Mq/WNX0Tjjes3X1gHd/ZBwOOKSrAG/Z3Xoc0OcCm3P20WKpniihkMpsnlE7wGjvpHLi/ZRe/XkB3KC3d5r9X4g==}
|
|
||||||
|
|
||||||
'@push.rocks/smarthash@3.2.7':
|
'@push.rocks/smarthash@3.2.7':
|
||||||
resolution: {integrity: sha512-y6iyu9l8Hslsa8W4e8UktX5d0yFZqipNgxxIik6NT0yHUM1zagx2cjemUtdV49uq1u+086Wr7nvrzLROWDzReA==}
|
resolution: {integrity: sha512-y6iyu9l8Hslsa8W4e8UktX5d0yFZqipNgxxIik6NT0yHUM1zagx2cjemUtdV49uq1u+086Wr7nvrzLROWDzReA==}
|
||||||
|
|
||||||
@@ -1110,9 +1095,6 @@ packages:
|
|||||||
'@push.rocks/smartjimp@1.2.1':
|
'@push.rocks/smartjimp@1.2.1':
|
||||||
resolution: {integrity: sha512-tIVS2sEqBjZTPX5U7a+dDBSZ+kfz7CdQwkEIhW6DEl6cuJ9uz2eH+pnPY0oZhw4g3q8hyW9Lf6lb8+nMmTyudw==}
|
resolution: {integrity: sha512-tIVS2sEqBjZTPX5U7a+dDBSZ+kfz7CdQwkEIhW6DEl6cuJ9uz2eH+pnPY0oZhw4g3q8hyW9Lf6lb8+nMmTyudw==}
|
||||||
|
|
||||||
'@push.rocks/smartjson@5.2.0':
|
|
||||||
resolution: {integrity: sha512-710e8UwovRfPgUtaBHcd6unaODUjV5fjxtGcGCqtaTcmvOV6VpasdVfT66xMDzQmWH2E9ZfHDJeso9HdDQzNQA==}
|
|
||||||
|
|
||||||
'@push.rocks/smartjson@6.0.1':
|
'@push.rocks/smartjson@6.0.1':
|
||||||
resolution: {integrity: sha512-iIw860jpjBcl83bLtq97QrjJxQkgxIKkhrX53EnpsVsZVNBgPCymLp0xNqY2jMpak5MKCEIWUVXkrmWVXj/TlQ==}
|
resolution: {integrity: sha512-iIw860jpjBcl83bLtq97QrjJxQkgxIKkhrX53EnpsVsZVNBgPCymLp0xNqY2jMpak5MKCEIWUVXkrmWVXj/TlQ==}
|
||||||
|
|
||||||
@@ -1158,9 +1140,6 @@ packages:
|
|||||||
'@push.rocks/smartpdf@4.2.2':
|
'@push.rocks/smartpdf@4.2.2':
|
||||||
resolution: {integrity: sha512-xQWRChCLcM/sUrRuanvIcND/dKrnCYfL8Rr3kzSIPgSoDSmdDbd4kz7lLAHEPTsCezIwg2VqxFidW+zMNZ5Z1Q==}
|
resolution: {integrity: sha512-xQWRChCLcM/sUrRuanvIcND/dKrnCYfL8Rr3kzSIPgSoDSmdDbd4kz7lLAHEPTsCezIwg2VqxFidW+zMNZ5Z1Q==}
|
||||||
|
|
||||||
'@push.rocks/smartpromise@4.2.3':
|
|
||||||
resolution: {integrity: sha512-Ycg/TJR+tMt+S3wSFurOpEoW6nXv12QBtKXgBcjMZ4RsdO28geN46U09osPn9N9WuwQy1PkmTV5J/V4F9U8qEw==}
|
|
||||||
|
|
||||||
'@push.rocks/smartpromise@4.2.4':
|
'@push.rocks/smartpromise@4.2.4':
|
||||||
resolution: {integrity: sha512-8FUyYt94hOIY9mqHjitn4h69u0jbEtTF2RKKw2DpiTVFjpDTk9gXbVHZ/V+xEcBrN4mrzdQES0OiDmkNPoddEQ==}
|
resolution: {integrity: sha512-8FUyYt94hOIY9mqHjitn4h69u0jbEtTF2RKKw2DpiTVFjpDTk9gXbVHZ/V+xEcBrN4mrzdQES0OiDmkNPoddEQ==}
|
||||||
|
|
||||||
@@ -1200,9 +1179,6 @@ packages:
|
|||||||
'@push.rocks/smartstream@3.4.2':
|
'@push.rocks/smartstream@3.4.2':
|
||||||
resolution: {integrity: sha512-JsjFjaNIlCBUglciM/IrXH0mH+oOQTLYQ6UMwqsew2XSUTXxER3ev2NeKMDBV6ONf2HF21EPnOZuKfgvtNGnUg==}
|
resolution: {integrity: sha512-JsjFjaNIlCBUglciM/IrXH0mH+oOQTLYQ6UMwqsew2XSUTXxER3ev2NeKMDBV6ONf2HF21EPnOZuKfgvtNGnUg==}
|
||||||
|
|
||||||
'@push.rocks/smartstring@4.1.0':
|
|
||||||
resolution: {integrity: sha512-Q4py/Nm3KTDhQ9EiC75yBtSTLR0KLMwhKM+8gGcutgKotZT6wJ3gncjmtD8LKFfNhb4lSaFMgPJgLrCHTOH6Iw==}
|
|
||||||
|
|
||||||
'@push.rocks/smartstring@4.1.1':
|
'@push.rocks/smartstring@4.1.1':
|
||||||
resolution: {integrity: sha512-FlEpp2PcQ819ymmxjWb5/2gD8uPic/+IvOrSP2+KTdXLHOI4GSyK9YW/YBF541LVGl0GC3VGFmypcPNUzkPfYw==}
|
resolution: {integrity: sha512-FlEpp2PcQ819ymmxjWb5/2gD8uPic/+IvOrSP2+KTdXLHOI4GSyK9YW/YBF541LVGl0GC3VGFmypcPNUzkPfYw==}
|
||||||
|
|
||||||
@@ -1234,9 +1210,6 @@ packages:
|
|||||||
'@push.rocks/websetup@3.0.20':
|
'@push.rocks/websetup@3.0.20':
|
||||||
resolution: {integrity: sha512-7TJ2ryFEpuSocGQwhhdEL6x8d7H0q3N4MJIJS46nc7r5XM5oXAXaIj/8gX2/TSNQWUt35CNSpJPkznoLpp95Jw==}
|
resolution: {integrity: sha512-7TJ2ryFEpuSocGQwhhdEL6x8d7H0q3N4MJIJS46nc7r5XM5oXAXaIj/8gX2/TSNQWUt35CNSpJPkznoLpp95Jw==}
|
||||||
|
|
||||||
'@push.rocks/webstore@2.0.20':
|
|
||||||
resolution: {integrity: sha512-Z3L4OHGcw/Gs9aXpMUwebEPTh0nK/C7R6YwPfCLcGVu9yd/ZShaQ8QZEYE243Cu9J1Mn+CEtz4jpPLnHiizHQA==}
|
|
||||||
|
|
||||||
'@push.rocks/webstore@2.0.22':
|
'@push.rocks/webstore@2.0.22':
|
||||||
resolution: {integrity: sha512-EdWfcNo0m6adSgTq7NtZusvmubUtRiCRADfFIbbgGZhCr9xLxmyB1nCtO/wzUrWZEbnR+Q9+fYkJFnDFOmZ4wA==}
|
resolution: {integrity: sha512-EdWfcNo0m6adSgTq7NtZusvmubUtRiCRADfFIbbgGZhCr9xLxmyB1nCtO/wzUrWZEbnR+Q9+fYkJFnDFOmZ4wA==}
|
||||||
|
|
||||||
@@ -1580,9 +1553,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-G/gWDykZNL0NVcd1qXkoKm45jxJECp6q53DSomM5QKMsyAMEsGksVq+HwgonqYxfFJEzzHi6ljtWKXVS1pl0/Q==}
|
resolution: {integrity: sha512-G/gWDykZNL0NVcd1qXkoKm45jxJECp6q53DSomM5QKMsyAMEsGksVq+HwgonqYxfFJEzzHi6ljtWKXVS1pl0/Q==}
|
||||||
engines: {node: '>=18.0.0'}
|
engines: {node: '>=18.0.0'}
|
||||||
|
|
||||||
'@tempfix/idb@8.0.3':
|
|
||||||
resolution: {integrity: sha512-hPJQKO7+oAIY+pDNImrZ9QAINbz9KmwT+yO4iRVwdPanok2YKpaUxdJzIvCUwY0YgAawlvYdffbLvRLV5hbs2g==}
|
|
||||||
|
|
||||||
'@tempfix/lenis@1.3.20':
|
'@tempfix/lenis@1.3.20':
|
||||||
resolution: {integrity: sha512-ypeB0FuHLHOCQXW4d0RQ69txPJJH+1CHcpsZIUdcv2t1vR0IVyQr2vHihtde9UOXhjzqEnUphWon/UcJNsa0YA==}
|
resolution: {integrity: sha512-ypeB0FuHLHOCQXW4d0RQ69txPJJH+1CHcpsZIUdcv2t1vR0IVyQr2vHihtde9UOXhjzqEnUphWon/UcJNsa0YA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -1637,9 +1607,6 @@ packages:
|
|||||||
'@types/mime-types@2.1.4':
|
'@types/mime-types@2.1.4':
|
||||||
resolution: {integrity: sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==}
|
resolution: {integrity: sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==}
|
||||||
|
|
||||||
'@types/minimatch@5.1.2':
|
|
||||||
resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==}
|
|
||||||
|
|
||||||
'@types/ms@2.1.0':
|
'@types/ms@2.1.0':
|
||||||
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
|
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
|
||||||
|
|
||||||
@@ -2092,10 +2059,6 @@ packages:
|
|||||||
engines: {node: '>= 10.17.0'}
|
engines: {node: '>= 10.17.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
fake-indexeddb@5.0.2:
|
|
||||||
resolution: {integrity: sha512-cB507r5T3D55DfclY01GLkninZLfU7HXV/mhVRTnTRm5k2u+fY7Fof2dBkr80p5t7G7dlA/G5dI87QiMdPpMCQ==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
|
|
||||||
fake-indexeddb@6.2.5:
|
fake-indexeddb@6.2.5:
|
||||||
resolution: {integrity: sha512-CGnyrvbhPlWYMngksqrSSUT1BAVP49dZocrHuK0SvtR0D5TMs5wP0o3j7jexDJW01KSadjBp1M/71o/KR3nD1w==}
|
resolution: {integrity: sha512-CGnyrvbhPlWYMngksqrSSUT1BAVP49dZocrHuK0SvtR0D5TMs5wP0o3j7jexDJW01KSadjBp1M/71o/KR3nD1w==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -2230,10 +2193,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
|
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
hasown@2.0.2:
|
|
||||||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
hasown@2.0.3:
|
hasown@2.0.3:
|
||||||
resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==}
|
resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -2376,9 +2335,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
|
resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
lodash.clonedeep@4.5.0:
|
|
||||||
resolution: {integrity: sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=}
|
|
||||||
|
|
||||||
longest-streak@3.1.0:
|
longest-streak@3.1.0:
|
||||||
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
|
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
|
||||||
|
|
||||||
@@ -2650,10 +2606,6 @@ packages:
|
|||||||
no-case@2.3.2:
|
no-case@2.3.2:
|
||||||
resolution: {integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==}
|
resolution: {integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==}
|
||||||
|
|
||||||
node-forge@1.3.3:
|
|
||||||
resolution: {integrity: sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==}
|
|
||||||
engines: {node: '>= 6.13.0'}
|
|
||||||
|
|
||||||
node-forge@1.4.0:
|
node-forge@1.4.0:
|
||||||
resolution: {integrity: sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==}
|
resolution: {integrity: sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==}
|
||||||
engines: {node: '>= 6.13.0'}
|
engines: {node: '>= 6.13.0'}
|
||||||
@@ -4698,10 +4650,6 @@ snapshots:
|
|||||||
- react-native-b4a
|
- react-native-b4a
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@push.rocks/consolecolor@2.0.3':
|
|
||||||
dependencies:
|
|
||||||
ansi-256-colors: 1.1.0
|
|
||||||
|
|
||||||
'@push.rocks/consolecolor@2.0.4':
|
'@push.rocks/consolecolor@2.0.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
ansi-256-colors: 1.1.0
|
ansi-256-colors: 1.1.0
|
||||||
@@ -4725,17 +4673,6 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- aws-crt
|
- aws-crt
|
||||||
|
|
||||||
'@push.rocks/lik@6.3.1':
|
|
||||||
dependencies:
|
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
|
||||||
'@push.rocks/smartmatch': 2.0.0
|
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
|
||||||
'@push.rocks/smartrx': 3.0.10
|
|
||||||
'@push.rocks/smarttime': 4.2.3
|
|
||||||
'@types/minimatch': 5.1.2
|
|
||||||
'@types/symbol-tree': 3.2.5
|
|
||||||
symbol-tree: 3.2.4
|
|
||||||
|
|
||||||
'@push.rocks/lik@6.4.1':
|
'@push.rocks/lik@6.4.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartdelay': 3.1.0
|
'@push.rocks/smartdelay': 3.1.0
|
||||||
@@ -4838,9 +4775,9 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/smartclickhouse@2.2.0':
|
'@push.rocks/smartclickhouse@2.2.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.1.0
|
||||||
'@push.rocks/smartobject': 1.0.12
|
'@push.rocks/smartobject': 1.0.12
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.4
|
||||||
'@push.rocks/smartrx': 3.0.10
|
'@push.rocks/smartrx': 3.0.10
|
||||||
'@push.rocks/smarturl': 3.1.0
|
'@push.rocks/smarturl': 3.1.0
|
||||||
'@push.rocks/webrequest': 4.0.5
|
'@push.rocks/webrequest': 4.0.5
|
||||||
@@ -4864,9 +4801,9 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/smartcrypto@2.0.4':
|
'@push.rocks/smartcrypto@2.0.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.4
|
||||||
'@types/node-forge': 1.3.14
|
'@types/node-forge': 1.3.14
|
||||||
node-forge: 1.3.3
|
node-forge: 1.4.0
|
||||||
|
|
||||||
'@push.rocks/smartdata@7.1.7(socks@2.8.9)':
|
'@push.rocks/smartdata@7.1.7(socks@2.8.9)':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -4898,10 +4835,6 @@ snapshots:
|
|||||||
- supports-color
|
- supports-color
|
||||||
- vue
|
- vue
|
||||||
|
|
||||||
'@push.rocks/smartdelay@3.0.5':
|
|
||||||
dependencies:
|
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
|
||||||
|
|
||||||
'@push.rocks/smartdelay@3.1.0':
|
'@push.rocks/smartdelay@3.1.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartpromise': 4.2.4
|
'@push.rocks/smartpromise': 4.2.4
|
||||||
@@ -4920,11 +4853,7 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/smartenv@5.0.13':
|
'@push.rocks/smartenv@5.0.13':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.4
|
||||||
|
|
||||||
'@push.rocks/smartenv@6.0.0':
|
|
||||||
dependencies:
|
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
|
||||||
|
|
||||||
'@push.rocks/smartenv@6.1.0':
|
'@push.rocks/smartenv@6.1.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -4970,14 +4899,6 @@ snapshots:
|
|||||||
'@push.rocks/smartpromise': 4.2.4
|
'@push.rocks/smartpromise': 4.2.4
|
||||||
'@push.rocks/smartrequest': 2.1.0
|
'@push.rocks/smartrequest': 2.1.0
|
||||||
|
|
||||||
'@push.rocks/smarthash@3.2.6':
|
|
||||||
dependencies:
|
|
||||||
'@push.rocks/smartenv': 5.0.13
|
|
||||||
'@push.rocks/smartjson': 5.2.0
|
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
|
||||||
'@types/through2': 2.0.41
|
|
||||||
through2: 4.0.2
|
|
||||||
|
|
||||||
'@push.rocks/smarthash@3.2.7':
|
'@push.rocks/smarthash@3.2.7':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartenv': 6.1.0
|
'@push.rocks/smartenv': 6.1.0
|
||||||
@@ -5006,17 +4927,10 @@ snapshots:
|
|||||||
- aws-crt
|
- aws-crt
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@push.rocks/smartjson@5.2.0':
|
|
||||||
dependencies:
|
|
||||||
'@push.rocks/smartenv': 5.0.13
|
|
||||||
'@push.rocks/smartstring': 4.1.0
|
|
||||||
fast-json-stable-stringify: 2.1.0
|
|
||||||
lodash.clonedeep: 4.5.0
|
|
||||||
|
|
||||||
'@push.rocks/smartjson@6.0.1':
|
'@push.rocks/smartjson@6.0.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartenv': 6.0.0
|
'@push.rocks/smartenv': 6.1.0
|
||||||
'@push.rocks/smartstring': 4.1.0
|
'@push.rocks/smartstring': 4.1.1
|
||||||
fast-json-stable-stringify: 2.1.0
|
fast-json-stable-stringify: 2.1.0
|
||||||
|
|
||||||
'@push.rocks/smartlog-destination-local@9.0.2':
|
'@push.rocks/smartlog-destination-local@9.0.2':
|
||||||
@@ -5033,11 +4947,11 @@ snapshots:
|
|||||||
'@push.rocks/smartlog@3.2.2':
|
'@push.rocks/smartlog@3.2.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@api.global/typedrequest-interfaces': 3.0.19
|
'@api.global/typedrequest-interfaces': 3.0.19
|
||||||
'@push.rocks/consolecolor': 2.0.3
|
'@push.rocks/consolecolor': 2.0.4
|
||||||
'@push.rocks/isounique': 1.0.5
|
'@push.rocks/isounique': 1.0.5
|
||||||
'@push.rocks/smartclickhouse': 2.2.0
|
'@push.rocks/smartclickhouse': 2.2.0
|
||||||
'@push.rocks/smarthash': 3.2.6
|
'@push.rocks/smarthash': 3.2.7
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.4
|
||||||
'@push.rocks/smarttime': 4.2.3
|
'@push.rocks/smarttime': 4.2.3
|
||||||
'@push.rocks/webrequest': 4.0.5
|
'@push.rocks/webrequest': 4.0.5
|
||||||
'@tsclass/tsclass': 9.5.1
|
'@tsclass/tsclass': 9.5.1
|
||||||
@@ -5128,7 +5042,7 @@ snapshots:
|
|||||||
'@push.rocks/smartnftables@1.2.0':
|
'@push.rocks/smartnftables@1.2.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartlog': 3.2.2
|
'@push.rocks/smartlog': 3.2.2
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.4
|
||||||
|
|
||||||
'@push.rocks/smartnpm@2.1.0':
|
'@push.rocks/smartnpm@2.1.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -5182,8 +5096,6 @@ snapshots:
|
|||||||
- typescript
|
- typescript
|
||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
|
|
||||||
'@push.rocks/smartpromise@4.2.3': {}
|
|
||||||
|
|
||||||
'@push.rocks/smartpromise@4.2.4': {}
|
'@push.rocks/smartpromise@4.2.4': {}
|
||||||
|
|
||||||
'@push.rocks/smartpuppeteer@2.0.6(typescript@6.0.3)':
|
'@push.rocks/smartpuppeteer@2.0.6(typescript@6.0.3)':
|
||||||
@@ -5229,7 +5141,7 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/smartrx@3.0.10':
|
'@push.rocks/smartrx@3.0.10':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.4
|
||||||
rxjs: 7.8.2
|
rxjs: 7.8.2
|
||||||
|
|
||||||
'@push.rocks/smartserve@2.0.4':
|
'@push.rocks/smartserve@2.0.4':
|
||||||
@@ -5283,19 +5195,15 @@ snapshots:
|
|||||||
'@push.rocks/smartpromise': 4.2.4
|
'@push.rocks/smartpromise': 4.2.4
|
||||||
'@push.rocks/smartrx': 3.0.10
|
'@push.rocks/smartrx': 3.0.10
|
||||||
|
|
||||||
'@push.rocks/smartstring@4.1.0':
|
|
||||||
dependencies:
|
|
||||||
'@push.rocks/isounique': 1.0.5
|
|
||||||
|
|
||||||
'@push.rocks/smartstring@4.1.1':
|
'@push.rocks/smartstring@4.1.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/isounique': 1.0.5
|
'@push.rocks/isounique': 1.0.5
|
||||||
|
|
||||||
'@push.rocks/smarttime@4.2.3':
|
'@push.rocks/smarttime@4.2.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.1
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.1.0
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.4
|
||||||
croner: 10.0.1
|
croner: 10.0.1
|
||||||
date-fns: 4.1.0
|
date-fns: 4.1.0
|
||||||
dayjs: 1.11.20
|
dayjs: 1.11.20
|
||||||
@@ -5347,28 +5255,17 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/webrequest@4.0.5':
|
'@push.rocks/webrequest@4.0.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.1.0
|
||||||
'@push.rocks/smartenv': 6.0.0
|
'@push.rocks/smartenv': 6.1.0
|
||||||
'@push.rocks/smartjson': 6.0.1
|
'@push.rocks/smartjson': 6.0.1
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.4
|
||||||
'@push.rocks/webstore': 2.0.20
|
'@push.rocks/webstore': 2.0.22
|
||||||
|
|
||||||
'@push.rocks/websetup@3.0.20':
|
'@push.rocks/websetup@3.0.20':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartpromise': 4.2.4
|
'@push.rocks/smartpromise': 4.2.4
|
||||||
'@tsclass/tsclass': 9.5.1
|
'@tsclass/tsclass': 9.5.1
|
||||||
|
|
||||||
'@push.rocks/webstore@2.0.20':
|
|
||||||
dependencies:
|
|
||||||
'@api.global/typedrequest-interfaces': 3.0.19
|
|
||||||
'@push.rocks/lik': 6.3.1
|
|
||||||
'@push.rocks/smartenv': 5.0.13
|
|
||||||
'@push.rocks/smartjson': 5.2.0
|
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
|
||||||
'@push.rocks/smartrx': 3.0.10
|
|
||||||
'@tempfix/idb': 8.0.3
|
|
||||||
fake-indexeddb: 5.0.2
|
|
||||||
|
|
||||||
'@push.rocks/webstore@2.0.22':
|
'@push.rocks/webstore@2.0.22':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@api.global/typedrequest-interfaces': 3.0.19
|
'@api.global/typedrequest-interfaces': 3.0.19
|
||||||
@@ -5702,8 +5599,6 @@ snapshots:
|
|||||||
'@smithy/core': 3.24.1
|
'@smithy/core': 3.24.1
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
'@tempfix/idb@8.0.3': {}
|
|
||||||
|
|
||||||
'@tempfix/lenis@1.3.20': {}
|
'@tempfix/lenis@1.3.20': {}
|
||||||
|
|
||||||
'@tokenizer/inflate@0.4.1':
|
'@tokenizer/inflate@0.4.1':
|
||||||
@@ -5757,8 +5652,6 @@ snapshots:
|
|||||||
|
|
||||||
'@types/mime-types@2.1.4': {}
|
'@types/mime-types@2.1.4': {}
|
||||||
|
|
||||||
'@types/minimatch@5.1.2': {}
|
|
||||||
|
|
||||||
'@types/ms@2.1.0': {}
|
'@types/ms@2.1.0': {}
|
||||||
|
|
||||||
'@types/mute-stream@0.0.4':
|
'@types/mute-stream@0.0.4':
|
||||||
@@ -6221,8 +6114,6 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
fake-indexeddb@5.0.2: {}
|
|
||||||
|
|
||||||
fake-indexeddb@6.2.5: {}
|
fake-indexeddb@6.2.5: {}
|
||||||
|
|
||||||
fast-deep-equal@3.1.3: {}
|
fast-deep-equal@3.1.3: {}
|
||||||
@@ -6329,7 +6220,7 @@ snapshots:
|
|||||||
get-proto: 1.0.1
|
get-proto: 1.0.1
|
||||||
gopd: 1.2.0
|
gopd: 1.2.0
|
||||||
has-symbols: 1.1.0
|
has-symbols: 1.1.0
|
||||||
hasown: 2.0.2
|
hasown: 2.0.3
|
||||||
math-intrinsics: 1.1.0
|
math-intrinsics: 1.1.0
|
||||||
|
|
||||||
get-proto@1.0.1:
|
get-proto@1.0.1:
|
||||||
@@ -6383,10 +6274,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
has-symbols: 1.1.0
|
has-symbols: 1.1.0
|
||||||
|
|
||||||
hasown@2.0.2:
|
|
||||||
dependencies:
|
|
||||||
function-bind: 1.1.2
|
|
||||||
|
|
||||||
hasown@2.0.3:
|
hasown@2.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
function-bind: 1.1.2
|
function-bind: 1.1.2
|
||||||
@@ -6570,8 +6457,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
p-locate: 4.1.0
|
p-locate: 4.1.0
|
||||||
|
|
||||||
lodash.clonedeep@4.5.0: {}
|
|
||||||
|
|
||||||
longest-streak@3.1.0: {}
|
longest-streak@3.1.0: {}
|
||||||
|
|
||||||
lower-case@1.1.4: {}
|
lower-case@1.1.4: {}
|
||||||
@@ -7027,8 +6912,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
lower-case: 1.1.4
|
lower-case: 1.1.4
|
||||||
|
|
||||||
node-forge@1.3.3: {}
|
|
||||||
|
|
||||||
node-forge@1.4.0: {}
|
node-forge@1.4.0: {}
|
||||||
|
|
||||||
object-keys@1.1.1: {}
|
object-keys@1.1.1: {}
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ pub struct ConnActivity {
|
|||||||
/// increments on creation and decrements on Drop, keeping the watchdog aware that
|
/// increments on creation and decrements on Drop, keeping the watchdog aware that
|
||||||
/// a response body is still streaming after the request handler has returned.
|
/// a response body is still streaming after the request handler has returned.
|
||||||
active_requests: Option<Arc<AtomicU64>>,
|
active_requests: Option<Arc<AtomicU64>>,
|
||||||
|
/// Active upgraded tunnel counter. When set, upgraded WebSocket streams keep the
|
||||||
|
/// HTTP keep-alive/lifetime watchdog out of the tunnel lifecycle.
|
||||||
|
active_upgrades: Option<Arc<AtomicU64>>,
|
||||||
/// Protocol cache key for Alt-Svc discovery. When set, `build_streaming_response`
|
/// Protocol cache key for Alt-Svc discovery. When set, `build_streaming_response`
|
||||||
/// checks the backend's original response headers for Alt-Svc before our
|
/// checks the backend's original response headers for Alt-Svc before our
|
||||||
/// ResponseFilter injects its own. None when not in auto-detect mode or after H3 failure.
|
/// ResponseFilter injects its own. None when not in auto-detect mode or after H3 failure.
|
||||||
@@ -61,6 +64,7 @@ impl ConnActivity {
|
|||||||
last_activity: Arc::new(AtomicU64::new(0)),
|
last_activity: Arc::new(AtomicU64::new(0)),
|
||||||
start: std::time::Instant::now(),
|
start: std::time::Instant::now(),
|
||||||
active_requests: None,
|
active_requests: None,
|
||||||
|
active_upgrades: None,
|
||||||
alt_svc_cache_key: None,
|
alt_svc_cache_key: None,
|
||||||
alt_svc_request_url: None,
|
alt_svc_request_url: None,
|
||||||
}
|
}
|
||||||
@@ -488,6 +492,7 @@ impl HttpProxyService {
|
|||||||
// (no request in progress and none started recently).
|
// (no request in progress and none started recently).
|
||||||
let last_activity = Arc::new(AtomicU64::new(0));
|
let last_activity = Arc::new(AtomicU64::new(0));
|
||||||
let active_requests = Arc::new(AtomicU64::new(0));
|
let active_requests = Arc::new(AtomicU64::new(0));
|
||||||
|
let active_upgrades = Arc::new(AtomicU64::new(0));
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
|
|
||||||
// Connection-level frontend protocol tracker: the first request detects
|
// Connection-level frontend protocol tracker: the first request detects
|
||||||
@@ -498,6 +503,7 @@ impl HttpProxyService {
|
|||||||
|
|
||||||
let la_inner = Arc::clone(&last_activity);
|
let la_inner = Arc::clone(&last_activity);
|
||||||
let ar_inner = Arc::clone(&active_requests);
|
let ar_inner = Arc::clone(&active_requests);
|
||||||
|
let au_inner = Arc::clone(&active_upgrades);
|
||||||
let cancel_inner = cancel.clone();
|
let cancel_inner = cancel.clone();
|
||||||
let vpn_info = Arc::new(vpn_info);
|
let vpn_info = Arc::new(vpn_info);
|
||||||
let service = hyper::service::service_fn(move |req: Request<Incoming>| {
|
let service = hyper::service::service_fn(move |req: Request<Incoming>| {
|
||||||
@@ -522,6 +528,7 @@ impl HttpProxyService {
|
|||||||
last_activity: Arc::clone(&la_inner),
|
last_activity: Arc::clone(&la_inner),
|
||||||
start,
|
start,
|
||||||
active_requests: Some(Arc::clone(&ar_inner)),
|
active_requests: Some(Arc::clone(&ar_inner)),
|
||||||
|
active_upgrades: Some(Arc::clone(&au_inner)),
|
||||||
alt_svc_cache_key: None,
|
alt_svc_cache_key: None,
|
||||||
alt_svc_request_url: None,
|
alt_svc_request_url: None,
|
||||||
};
|
};
|
||||||
@@ -572,8 +579,14 @@ impl HttpProxyService {
|
|||||||
loop {
|
loop {
|
||||||
tokio::time::sleep(check_interval).await;
|
tokio::time::sleep(check_interval).await;
|
||||||
|
|
||||||
// Check max connection lifetime (unconditional — even active connections
|
// Upgraded tunnels have their own WebSocket watchdog and lifetime.
|
||||||
// must eventually be recycled to prevent resource accumulation).
|
if active_upgrades.load(Ordering::Relaxed) > 0 {
|
||||||
|
last_seen = last_activity.load(Ordering::Relaxed);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check max connection lifetime (unconditional for regular HTTP — even active
|
||||||
|
// connections must eventually be recycled to prevent resource accumulation).
|
||||||
if start.elapsed() >= max_lifetime {
|
if start.elapsed() >= max_lifetime {
|
||||||
debug!("HTTP connection exceeded max lifetime ({}s) from {}",
|
debug!("HTTP connection exceeded max lifetime ({}s) from {}",
|
||||||
max_lifetime.as_secs(), peer_addr);
|
max_lifetime.as_secs(), peer_addr);
|
||||||
@@ -789,11 +802,7 @@ impl HttpProxyService {
|
|||||||
cancel,
|
cancel,
|
||||||
&ip_str,
|
&ip_str,
|
||||||
is_h2_websocket,
|
is_h2_websocket,
|
||||||
if is_h2_websocket {
|
Some(conn_activity.clone()),
|
||||||
Some(conn_activity.clone())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
// Note: for WebSocket, connection_ended is called inside
|
// Note: for WebSocket, connection_ended is called inside
|
||||||
@@ -3286,8 +3295,19 @@ impl HttpProxyService {
|
|||||||
let upstream_key_owned = upstream_key.to_string();
|
let upstream_key_owned = upstream_key.to_string();
|
||||||
let ws_inactivity_timeout = self.ws_inactivity_timeout;
|
let ws_inactivity_timeout = self.ws_inactivity_timeout;
|
||||||
let ws_max_lifetime = self.ws_max_lifetime;
|
let ws_max_lifetime = self.ws_max_lifetime;
|
||||||
|
let ws_request_guard = conn_activity
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|ca| ca.active_requests.as_ref())
|
||||||
|
.map(|counter| ActiveRequestGuard::new(Arc::clone(counter)));
|
||||||
|
let ws_upgrade_guard = conn_activity
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|ca| ca.active_upgrades.as_ref())
|
||||||
|
.map(|counter| ActiveRequestGuard::new(Arc::clone(counter)));
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
|
let _ws_request_guard = ws_request_guard;
|
||||||
|
let _ws_upgrade_guard = ws_upgrade_guard;
|
||||||
|
|
||||||
// RAII guard: ensures connection_ended is called even if this task panics
|
// RAII guard: ensures connection_ended is called even if this task panics
|
||||||
struct WsUpstreamGuard {
|
struct WsUpstreamGuard {
|
||||||
selector: UpstreamSelector,
|
selector: UpstreamSelector,
|
||||||
|
|||||||
@@ -154,6 +154,9 @@ pub struct ConnectionConfig {
|
|||||||
pub max_connections: u64,
|
pub max_connections: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DEFAULT_WS_INACTIVITY_TIMEOUT_MS: u64 = 3_600_000;
|
||||||
|
const DEFAULT_WS_MAX_LIFETIME_MS: u64 = 86_400_000;
|
||||||
|
|
||||||
impl Default for ConnectionConfig {
|
impl Default for ConnectionConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -225,8 +228,8 @@ impl TcpListenerManager {
|
|||||||
http_proxy_svc.set_connection_timeouts(
|
http_proxy_svc.set_connection_timeouts(
|
||||||
std::time::Duration::from_millis(conn_config.socket_timeout_ms),
|
std::time::Duration::from_millis(conn_config.socket_timeout_ms),
|
||||||
std::time::Duration::from_millis(conn_config.max_connection_lifetime_ms),
|
std::time::Duration::from_millis(conn_config.max_connection_lifetime_ms),
|
||||||
std::time::Duration::from_millis(conn_config.socket_timeout_ms),
|
std::time::Duration::from_millis(DEFAULT_WS_INACTIVITY_TIMEOUT_MS),
|
||||||
std::time::Duration::from_millis(conn_config.max_connection_lifetime_ms),
|
std::time::Duration::from_millis(DEFAULT_WS_MAX_LIFETIME_MS),
|
||||||
);
|
);
|
||||||
let http_proxy = Arc::new(http_proxy_svc);
|
let http_proxy = Arc::new(http_proxy_svc);
|
||||||
let conn_tracker = Arc::new(ConnectionTracker::new(
|
let conn_tracker = Arc::new(ConnectionTracker::new(
|
||||||
@@ -266,8 +269,8 @@ impl TcpListenerManager {
|
|||||||
http_proxy_svc.set_connection_timeouts(
|
http_proxy_svc.set_connection_timeouts(
|
||||||
std::time::Duration::from_millis(conn_config.socket_timeout_ms),
|
std::time::Duration::from_millis(conn_config.socket_timeout_ms),
|
||||||
std::time::Duration::from_millis(conn_config.max_connection_lifetime_ms),
|
std::time::Duration::from_millis(conn_config.max_connection_lifetime_ms),
|
||||||
std::time::Duration::from_millis(conn_config.socket_timeout_ms),
|
std::time::Duration::from_millis(DEFAULT_WS_INACTIVITY_TIMEOUT_MS),
|
||||||
std::time::Duration::from_millis(conn_config.max_connection_lifetime_ms),
|
std::time::Duration::from_millis(DEFAULT_WS_MAX_LIFETIME_MS),
|
||||||
);
|
);
|
||||||
let http_proxy = Arc::new(http_proxy_svc);
|
let http_proxy = Arc::new(http_proxy_svc);
|
||||||
let conn_tracker = Arc::new(ConnectionTracker::new(
|
let conn_tracker = Arc::new(ConnectionTracker::new(
|
||||||
@@ -313,8 +316,8 @@ impl TcpListenerManager {
|
|||||||
http_proxy_svc.set_connection_timeouts(
|
http_proxy_svc.set_connection_timeouts(
|
||||||
std::time::Duration::from_millis(config.socket_timeout_ms),
|
std::time::Duration::from_millis(config.socket_timeout_ms),
|
||||||
std::time::Duration::from_millis(config.max_connection_lifetime_ms),
|
std::time::Duration::from_millis(config.max_connection_lifetime_ms),
|
||||||
std::time::Duration::from_millis(config.socket_timeout_ms),
|
std::time::Duration::from_millis(DEFAULT_WS_INACTIVITY_TIMEOUT_MS),
|
||||||
std::time::Duration::from_millis(config.max_connection_lifetime_ms),
|
std::time::Duration::from_millis(DEFAULT_WS_MAX_LIFETIME_MS),
|
||||||
);
|
);
|
||||||
self.http_proxy = Arc::new(http_proxy_svc);
|
self.http_proxy = Arc::new(http_proxy_svc);
|
||||||
|
|
||||||
|
|||||||
@@ -415,4 +415,68 @@ tap.test('should handle large WebSocket messages', async () => {
|
|||||||
await assertPortsFree([PROXY_PORT, BACKEND_PORT]);
|
await assertPortsFree([PROXY_PORT, BACKEND_PORT]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── Test 7: Idle WebSocket outlives short HTTP socket timeout ───
|
||||||
|
tap.test('should keep idle WebSocket open beyond HTTP socket timeout', async (tools) => {
|
||||||
|
tools.timeout(15000);
|
||||||
|
|
||||||
|
const [PROXY_PORT, BACKEND_PORT] = await findFreePorts(2);
|
||||||
|
let proxy: SmartProxy | undefined;
|
||||||
|
let ws: WebSocket | undefined;
|
||||||
|
|
||||||
|
const backendServer = http.createServer();
|
||||||
|
const wss = new WebSocketServer({ server: backendServer });
|
||||||
|
|
||||||
|
wss.on('connection', (backendWs) => {
|
||||||
|
backendWs.on('message', (data) => {
|
||||||
|
backendWs.send(`echo: ${data.toString()}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await new Promise<void>((resolve) => {
|
||||||
|
backendServer.listen(BACKEND_PORT, '127.0.0.1', () => resolve());
|
||||||
|
});
|
||||||
|
|
||||||
|
proxy = new SmartProxy({
|
||||||
|
socketTimeout: 1000,
|
||||||
|
maxConnectionLifetime: 1000,
|
||||||
|
routes: [{
|
||||||
|
name: 'ws-idle-timeout-route',
|
||||||
|
match: { ports: PROXY_PORT },
|
||||||
|
action: {
|
||||||
|
type: 'forward',
|
||||||
|
targets: [{ host: '127.0.0.1', port: BACKEND_PORT }],
|
||||||
|
websocket: { enabled: true },
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
await proxy.start();
|
||||||
|
|
||||||
|
const connection = connectWs(
|
||||||
|
`ws://127.0.0.1:${PROXY_PORT}/`,
|
||||||
|
{ Host: 'test.local' },
|
||||||
|
);
|
||||||
|
ws = connection.ws;
|
||||||
|
await connection.opened;
|
||||||
|
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 6500));
|
||||||
|
expect(ws.readyState).toEqual(WebSocket.OPEN);
|
||||||
|
|
||||||
|
ws.send('still open');
|
||||||
|
await waitFor(() => connection.messages.length >= 1);
|
||||||
|
expect(connection.messages[0]).toEqual('echo: still open');
|
||||||
|
} finally {
|
||||||
|
if (ws && ws.readyState !== WebSocket.CLOSED) {
|
||||||
|
await closeWs(ws);
|
||||||
|
}
|
||||||
|
if (proxy) {
|
||||||
|
await proxy.stop();
|
||||||
|
}
|
||||||
|
wss.close();
|
||||||
|
await new Promise<void>((resolve) => backendServer.close(() => resolve()));
|
||||||
|
await new Promise((r) => setTimeout(r, 500));
|
||||||
|
await assertPortsFree([PROXY_PORT, BACKEND_PORT]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export default tap.start();
|
export default tap.start();
|
||||||
|
|||||||
Reference in New Issue
Block a user