Skip to content

Commit 5a3f143

Browse files
committed
feat(external): #469 Add HttpFallbackHandler to determine if it's a WebSocket upgrade request.
1 parent bd2e585 commit 5a3f143

File tree

4 files changed

+115
-0
lines changed

4 files changed

+115
-0
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* ioGame
3+
* Copyright (C) 2021 - present 渔民小镇 (262610965@qq.com、luoyizhu@gmail.com) . All Rights Reserved.
4+
* # iohao.com . 渔民小镇
5+
*
6+
* This program is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU Affero General Public License as
8+
* published by the Free Software Foundation, either version 3 of the
9+
* License, or (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Affero General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Affero General Public License
17+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
package com.iohao.game.external.core.netty.handler.check;
20+
21+
import io.netty.channel.ChannelHandler;
22+
import io.netty.channel.ChannelHandlerContext;
23+
import io.netty.channel.SimpleChannelInboundHandler;
24+
import io.netty.handler.codec.http.*;
25+
26+
/**
27+
* @author 渔民小镇
28+
* @date 2025-06-28
29+
* @since 21.29
30+
*/
31+
@ChannelHandler.Sharable
32+
public final class HttpFallbackHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
33+
34+
@Override
35+
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) {
36+
// 检查是否是 WebSocket 升级请求
37+
if ("websocket".equalsIgnoreCase(req.headers().get(HttpHeaderNames.UPGRADE))) {
38+
ctx.fireChannelRead(req.retain());
39+
} else {
40+
ctx.close();
41+
}
42+
}
43+
44+
private HttpFallbackHandler() {
45+
}
46+
47+
public static HttpFallbackHandler me() {
48+
return Holder.ME;
49+
}
50+
51+
/** 通过 JVM 的类加载机制, 保证只加载一次 (singleton) */
52+
private static class Holder {
53+
static final HttpFallbackHandler ME = new HttpFallbackHandler();
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* ioGame
3+
* Copyright (C) 2021 - present 渔民小镇 (262610965@qq.com、luoyizhu@gmail.com) . All Rights Reserved.
4+
* # iohao.com . 渔民小镇
5+
*
6+
* This program is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU Affero General Public License as
8+
* published by the Free Software Foundation, either version 3 of the
9+
* License, or (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Affero General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Affero General Public License
17+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
package com.iohao.game.external.core.netty.handler.check;
20+
21+
import com.iohao.game.external.core.config.ExternalGlobalConfig;
22+
import io.netty.buffer.ByteBuf;
23+
import io.netty.channel.ChannelHandler;
24+
import io.netty.channel.ChannelHandlerContext;
25+
import io.netty.handler.codec.ByteToMessageDecoder;
26+
27+
import java.util.List;
28+
29+
/**
30+
* @author 渔民小镇
31+
* @date 2025-06-28
32+
* @since 21.29
33+
*/
34+
public final class TcpProtocolSanityCheckHandler extends ByteToMessageDecoder {
35+
private boolean closed = false;
36+
37+
@Override
38+
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
39+
40+
if (closed || in.readableBytes() < 4) {
41+
return;
42+
}
43+
44+
in.markReaderIndex();
45+
int length = in.readInt();
46+
in.resetReaderIndex();
47+
48+
if (length <= 0 || length > ExternalGlobalConfig.CoreOption.packageMaxSize) {
49+
closed = true;
50+
ctx.close();
51+
} else {
52+
ctx.pipeline().remove(this);
53+
}
54+
}
55+
}

external/external-netty/src/main/java/com/iohao/game/external/core/netty/micro/TcpMicroBootstrapFlow.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ public void option(ServerBootstrap bootstrap) {
6060

6161
@Override
6262
public void pipelineCodec(PipelineContext context) {
63+
// context.addLast("tcp-check", new TcpProtocolSanityCheckHandler());
64+
6365
// 数据包长度 = 长度域的值 + lengthFieldOffset + lengthFieldLength + lengthAdjustment。
6466
context.addLast(new LengthFieldBasedFrameDecoder(
6567
ExternalGlobalConfig.CoreOption.packageMaxSize,

external/external-netty/src/main/java/com/iohao/game/external/core/netty/micro/WebSocketMicroBootstrapFlow.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.iohao.game.external.core.config.ExternalGlobalConfig;
2323
import com.iohao.game.external.core.micro.PipelineContext;
2424
import com.iohao.game.external.core.netty.handler.codec.WebSocketExternalCodec;
25+
import com.iohao.game.external.core.netty.handler.check.HttpFallbackHandler;
2526
import com.iohao.game.external.core.netty.handler.ws.WebSocketVerifyHandler;
2627
import io.netty.bootstrap.ServerBootstrap;
2728
import io.netty.channel.ChannelOption;
@@ -140,5 +141,7 @@ protected void httpHandler(PipelineContext context) {
140141
* 到完整的 Http 请求或响应
141142
*/
142143
context.addLast("aggregator", new HttpObjectAggregator(65536));
144+
145+
context.addLast("http-fallback", HttpFallbackHandler.me());
143146
}
144147
}

0 commit comments

Comments
 (0)