Flash安全策略

客户端发送字符串以NULL结尾的请求字符串<policy-file-request/>到服务器
服务器返回策略文件响应,内容如下:

<?xml version="1.0"?> 
<!DOCTYPE cross-domain-policy SYSTEM "/xml/dtds/cross-domain-policy.dtd">
<!-- Policy file for xmlsocket://socks.example.com --> 
<cross-domain-policy> 
<!-- This is a master-policy file --> 
  <site-control permitted-cross-domain-policies="master-only"/> 
  <!-- Instead of setting to-ports="*", administrators can use ranges and commas --> 
  <!-- This will allow access to ports 123, 456, 457, and 458 --> 
  <allow-access-from domain="swf.example.com" to-ports="123,456-458" /> 
</cross-domain-policy> 

使用Netty的NIO方式实现

传统的ServerSocket.accept()方式会在每次调用都会阻塞,每一个Socket连接都需要启动新线程。 Netty则可以用非阻塞异步的方式处理请求,而且自带大部分编解码器可以完成需求。

  • DelimiterBasedFrameDecoder 将接收到的ByteBuf按指定分隔符分割,此处需要用到Delimiters.nulDelimiter()
  • StringDecoder和StringEncoder 将读入或写出的ByteBUf解编码为String
  • IdleStateHandler 读超时事件触发时,可以及时关闭Channel

此外,还需要自己实现一个Handler返回策略文件内容。

Java代码

public class FlashPolicyHandler  extends SimpleChannelInboundHandler<String> {
  private static String xml = "<?xml version=\"1.0\"?>" +
    "<!DOCTYPE cross-domain-policy SYSTEM \"/xml/dtds/cross-domain-policy.dtd\">" +
    "<cross-domain-policy>"
    + "<allow-access-from domain=\"*\" to-ports=\"80,8080\"/>"
    + "</cross-domain-policy>\0";


  @Override
  public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
    if (evt instanceof IdleStateEvent) {
      IdleStateEvent state = (IdleStateEvent) evt;
      if (state.state() == IdleState.READER_IDLE) {
        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
      }
    }
    super.userEventTriggered(ctx, evt);
  }

  private boolean validate(String msg) {
    return msg.indexOf("<policy-file-request/>") >= 0;
  }

  @Override
  protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
    if (validate(msg)) {
      ctx.writeAndFlush(xml).addListener(ChannelFutureListener.CLOSE);
    } else {
      ctx.writeAndFlush("Quest Error \0").addListener(ChannelFutureListener.CLOSE);
    }
  }
}

完整代码
see also