/**
   * Detects if we're connecting to a Found Elasticsearch cluster (using pre-configured host
   * suffixes) and adds a SSL handler at the beginning of the pipeline if we're connecting to a
   * SSL-endpoint (using a list of pre-configured ports).
   */
  @Override
  public void connectRequested(final ChannelHandlerContext ctx, final ChannelStateEvent e)
      throws Exception {
    if (e.getValue() instanceof InetSocketAddress) {
      InetSocketAddress inetSocketAddress = (InetSocketAddress) e.getValue();

      for (String suffix : hostSuffixes) {
        isFoundCluster = isFoundCluster || inetSocketAddress.getHostString().endsWith(suffix);
      }

      if (isFoundCluster) {
        for (int sslPort : sslPorts) {
          if (inetSocketAddress.getPort() == sslPort) {
            logger.debug(
                "Enabling SSL on transport layer with unsafeAllowSelfSigned=[{}].",
                unsafeAllowSelfSigned);
            FoundSSLHandler handler =
                FoundSSLUtils.getSSLHandler(unsafeAllowSelfSigned, inetSocketAddress);
            ctx.getPipeline().addFirst("ssl", handler);
            break;
          }
        }
      } else {
        ctx.getPipeline().remove(this);
      }
    }
    super.connectRequested(ctx, e);
  }
  @Override
  public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
    if (handshakeComplete) {
      super.messageReceived(ctx, e);
    } else {
      if (e.getMessage() instanceof ChannelBuffer) {
        ChannelBuffer newBuffer = (ChannelBuffer) e.getMessage();
        buffered = ChannelBuffers.copiedBuffer(buffered, newBuffer);

        if (buffered.readableBytes() < 8) {
          return;
        }
        int payloadLength = buffered.getInt(0);
        int revision = buffered.getInt(4);

        boolean handshakeSuccessful = false;

        if (revision == 1 || revision == -1) {
          if (buffered.readableBytes() < payloadLength + 4) {
            return;
          }
          buffered.skipBytes(8);

          if (revision == 1) {
            handshakeSuccessful = handleRevision1Response(ctx, payloadLength);
          } else {
            handshakeSuccessful = handleGenericResponse(ctx, payloadLength);
          }
        } else {
          handshakeSuccessful = handleUnknownRevisionResponse(ctx);
        }

        if (!handshakeSuccessful) {
          ctx.getChannel().close();
        }

        if (keepAliveInterval.millis() > 0) {
          ctx.getPipeline()
              .addBefore(
                  ctx.getName(),
                  "found-connection-keep-alive",
                  new ConnectionKeepAliveHandler(scheduler, keepAliveInterval));
        }

        handshakeComplete = true;

        ChannelBuffer remaining = buffered.slice();
        if (remaining.readableBytes() > 0) {
          ctx.sendUpstream(
              new UpstreamMessageEvent(
                  ctx.getChannel(), remaining, ctx.getChannel().getRemoteAddress()));
        }

        ctx.getPipeline().remove(this);
      }
    }
  }
  /*
   * (non-Javadoc)
   *
   * @see org.jboss.netty.handler.codec.oneone.OneToOneEncoder#encode(org.jboss
   * .netty.channel.ChannelHandlerContext, org.jboss.netty.channel.Channel, java.lang.Object)
   */
  @Override
  protected Object encode(final ChannelHandlerContext ctx, final Channel channel, final Object msg)
      throws Exception {

    final ChannelBuffer message = (ChannelBuffer) msg;

    final AuthToClientChannelHandler channelHandler =
        (AuthToClientChannelHandler) ctx.getPipeline().getLast();
    final int opcode = message.readUnsignedByte();
    final int size = message.readableBytes();

    final ChannelBuffer frame = ChannelBuffers.buffer(ByteOrder.LITTLE_ENDIAN, (size + 3));
    frame.writeByte(opcode);
    frame.writeShort(size);

    final byte[] tmpa = new byte[message.readableBytes()];
    message.readBytes(tmpa);
    frame.writeBytes(channelHandler.getCrypt().encrypt(tmpa));

    log.debug(String.format("[SEND PACKET] :  0x%02X", opcode));
    final List<String> d =
        breakStringInChunks(new BigInteger(1, tmpa).toString(16).toUpperCase(), 16);
    for (final String string : d) {
      log.debug(string);
    }
    return frame;
  }
  /**
   * Process server response:
   *
   * <pre>
   * HTTP/1.1 101 WebSocket Protocol Handshake
   * Upgrade: WebSocket
   * Connection: Upgrade
   * Sec-WebSocket-Origin: http://example.com
   * Sec-WebSocket-Location: ws://example.com/demo
   * Sec-WebSocket-Protocol: sample
   *
   * 8jKS'y:G*Co,Wxa-
   * </pre>
   *
   * @param ctx Channel context
   * @param response HTTP response returned from the server for the request sent by
   *     beginOpeningHandshake00().
   * @throws WebSocketHandshakeException
   */
  @Override
  public void endOpeningHandshake(ChannelHandlerContext ctx, HttpResponse response)
      throws WebSocketHandshakeException {
    final HttpResponseStatus status = new HttpResponseStatus(101, "WebSocket Protocol Handshake");

    if (!response.getStatus().equals(status)) {
      throw new WebSocketHandshakeException(
          "Invalid handshake response status: " + response.getStatus());
    }

    String upgrade = response.getHeader(Names.UPGRADE);
    if (upgrade == null || !upgrade.equals(Values.WEBSOCKET)) {
      throw new WebSocketHandshakeException(
          "Invalid handshake response upgrade: " + response.getHeader(Names.UPGRADE));
    }

    String connection = response.getHeader(Names.CONNECTION);
    if (connection == null || !connection.equals(Values.UPGRADE)) {
      throw new WebSocketHandshakeException(
          "Invalid handshake response connection: " + response.getHeader(Names.CONNECTION));
    }

    byte[] challenge = response.getContent().array();
    if (!Arrays.equals(challenge, expectedChallengeResponseBytes)) {
      throw new WebSocketHandshakeException("Invalid challenge");
    }

    String protocol = response.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
    this.setSubProtocolResponse(protocol);

    ctx.getPipeline().replace("decoder", "ws-decoder", new WebSocket00FrameDecoder());

    this.setOpenningHandshakeCompleted(true);
    return;
  }
Example #5
0
  @Override
  public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) throws Exception {

    log.debug(
        "channelIdle on OFChannelHandler {}", String.format("%08x", System.identityHashCode(this)));
    OFChannelHandler handler = ctx.getPipeline().get(OFChannelHandler.class);
    handler.sendEchoRequest();
  }
 public static void replaceDefaultHandler(
     @NotNull ChannelHandlerContext context,
     @NotNull SimpleChannelUpstreamHandler messageChannelHandler) {
   context
       .getPipeline()
       .replace(
           DelegatingHttpRequestHandler.class, "replacedDefaultHandler", messageChannelHandler);
 }
  @BeforeMethod
  public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);

    handler = new SyslogTCPFramingRouterHandler(2048, Delimiters.lineDelimiter());

    when(context.getPipeline()).thenReturn(pipeline);
    when(context.getName()).thenReturn("current");
  }
 private void receivedConnect(NetData.JoinMessage message) {
   logger.info("Received Start Join");
   NetClient client = new NetClient(channelHandlerContext.getChannel(), networkSystem, identity);
   client.setPreferredName(message.getName());
   client.setColor(new Color(message.getColor().getRgba()));
   client.setViewDistanceMode(ViewDistance.forIndex(message.getViewDistanceLevel()));
   channelHandlerContext.getPipeline().remove(this);
   serverHandler.connectionComplete(client);
 }
Example #9
0
  @Override
  public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
    // Get the SslHandler in the current pipeline.
    // We added it in SecureChatPipelineFactory.
    final SslHandler sslHandler = ctx.getPipeline().get(SslHandler.class);

    // Get notified when SSL handshake is done.
    ChannelFuture handshakeFuture = sslHandler.handshake();
    handshakeFuture.addListener(new SslLister(sslHandler));
  }
    @Override
    public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {

      // add bind handler to pipeline
      String baseName = ctx.getName();
      String name = format("%s:socket", baseName);
      ctx.getPipeline().addAfter(baseName, name, bindHandler);

      // propagate channel open event
      super.channelOpen(ctx, e);
    }
  @Override
  public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
    ImapSession session = (ImapSession) attributes.get(ctx.getChannel());
    ImapResponseComposer response = (ImapResponseComposer) ctx.getAttachment();
    ImapMessage message = (ImapMessage) e.getMessage();
    ChannelPipeline cp = ctx.getPipeline();

    try {
      if (cp.get(NettyConstants.EXECUTION_HANDLER) != null) {
        cp.addBefore(
            NettyConstants.EXECUTION_HANDLER, NettyConstants.HEARTBEAT_HANDLER, heartbeatHandler);
      } else {
        cp.addBefore(
            NettyConstants.CORE_HANDLER, NettyConstants.HEARTBEAT_HANDLER, heartbeatHandler);
      }
      final ResponseEncoder responseEncoder = new ResponseEncoder(encoder, response, session);
      processor.process(message, responseEncoder, session);

      if (session.getState() == ImapSessionState.LOGOUT) {
        // Make sure we close the channel after all the buffers were flushed out
        Channel channel = ctx.getChannel();
        if (channel.isConnected()) {
          channel.write(ChannelBuffers.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
        }
      }
      final IOException failure = responseEncoder.getFailure();

      if (failure != null) {
        final Logger logger = session.getLog();
        logger.info(failure.getMessage());
        if (logger.isDebugEnabled()) {
          logger.debug("Failed to write " + message, failure);
        }
        throw failure;
      }
    } finally {
      ctx.getPipeline().remove(NettyConstants.HEARTBEAT_HANDLER);
    }

    super.messageReceived(ctx, e);
  }
Example #12
0
 @Override
 public void beforeAdd(ChannelHandlerContext ctx) throws Exception {
   if (ctx.getPipeline().isAttached()) {
     // channelOpen event has been fired already, which means
     // this.channelOpen() will not be invoked.
     // We have to initialize here instead.
     initialize(ctx);
   } else {
     // channelOpen event has not been fired yet.
     // this.channelOpen() will be invoked and initialization will occur there.
   }
 }
Example #13
0
 @Override
 public void handleUpstream(final ChannelHandlerContext ctx, final ChannelEvent e)
     throws Exception {
   Object o = null;
   if ((e instanceof MessageEvent)
       && this.first.compareAndSet(true, false)
       && ((o = ((MessageEvent) e).getMessage()) instanceof ChannelBuffer)
       && !maybeSsl((ChannelBuffer) o)) {
     ctx.getPipeline().removeFirst();
     ctx.sendUpstream(e);
   } else {
     super.handleUpstream(ctx, e);
   }
 }
Example #14
0
 /**
  * {@inheritDoc}
  *
  * @see
  *     org.jboss.netty.channel.ChannelUpstreamHandler#handleUpstream(org.jboss.netty.channel.ChannelHandlerContext,
  *     org.jboss.netty.channel.ChannelEvent)
  */
 @Override
 public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
   if (e instanceof MessageEvent) {
     MessageEvent me = (MessageEvent) e;
     if (me.getMessage() instanceof ChannelBuffer) {
       ChannelBuffer postDetectBuffer =
           protocolSwitch(ctx, e.getChannel(), (ChannelBuffer) me.getMessage(), e);
       if (postDetectBuffer != null) {
         ctx.getPipeline().remove(this);
         ctx.sendUpstream(
             new UpstreamMessageEvent(
                 e.getChannel(), postDetectBuffer, ((MessageEvent) e).getRemoteAddress()));
       }
     }
   } else {
     ctx.sendUpstream(e);
   }
 }
  @Override
  public void messageReceived(ChannelHandlerContext ctx, MessageEvent messageEvent)
      throws Exception {
    messageReceived = true;

    if (LOG.isTraceEnabled()) {
      LOG.trace("Message received: {}", messageEvent);
    }

    if (producer.getConfiguration().getRequestTimeout() > 0) {
      ChannelHandler handler = ctx.getPipeline().get("timeout");
      if (handler != null) {
        LOG.trace("Removing timeout channel as we received message");
        ctx.getPipeline().remove(handler);
      }
    }

    Exchange exchange = getExchange(ctx);
    if (exchange == null) {
      // we just ignore the received message as the channel is closed
      return;
    }
    AsyncCallback callback = getAsyncCallback(ctx);

    Message message;
    try {
      message = getResponseMessage(exchange, messageEvent);
    } catch (Exception e) {
      exchange.setException(e);
      callback.done(false);
      return;
    }

    // set the result on either IN or OUT on the original exchange depending on its pattern
    if (ExchangeHelper.isOutCapable(exchange)) {
      exchange.setOut(message);
    } else {
      exchange.setIn(message);
    }

    try {
      // should channel be closed after complete?
      Boolean close;
      if (ExchangeHelper.isOutCapable(exchange)) {
        close =
            exchange
                .getOut()
                .getHeader(NettyConstants.NETTY_CLOSE_CHANNEL_WHEN_COMPLETE, Boolean.class);
      } else {
        close =
            exchange
                .getIn()
                .getHeader(NettyConstants.NETTY_CLOSE_CHANNEL_WHEN_COMPLETE, Boolean.class);
      }

      // check the setting on the exchange property
      if (close == null) {
        close =
            exchange.getProperty(NettyConstants.NETTY_CLOSE_CHANNEL_WHEN_COMPLETE, Boolean.class);
      }

      // should we disconnect, the header can override the configuration
      boolean disconnect = producer.getConfiguration().isDisconnect();
      if (close != null) {
        disconnect = close;
      }
      if (disconnect) {
        if (LOG.isTraceEnabled()) {
          LOG.trace(
              "Closing channel when complete at address: {}",
              producer.getConfiguration().getAddress());
        }
        NettyHelper.close(ctx.getChannel());
      }
    } finally {
      // signal callback
      callback.done(false);
    }
  }
  @Override
  public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
    if (LOG.isDebugEnabled()) {
      LOG.debug("messageReceived: Got " + e.getMessage().getClass());
    }

    WritableRequest writableRequest = (WritableRequest) e.getMessage();
    // Simulate a closed connection on the first request (if desired)
    // TODO: Move out into a separate, dedicated handler.
    if (closeFirstRequest && !ALREADY_CLOSED_FIRST_REQUEST) {
      LOG.info(
          "messageReceived: Simulating closing channel on first "
              + "request "
              + writableRequest.getRequestId()
              + " from "
              + writableRequest.getClientId());
      setAlreadyClosedFirstRequest();
      ctx.getChannel().close();
      return;
    }

    if (writableRequest.getType() == RequestType.SASL_TOKEN_MESSAGE_REQUEST) {
      // initialize server-side SASL functionality, if we haven't yet
      // (in which case we are looking at the first SASL message from the
      // client).
      SaslNettyServer saslNettyServer =
          NettyServer.CHANNEL_SASL_NETTY_SERVERS.get(ctx.getChannel());
      if (saslNettyServer == null) {
        if (LOG.isDebugEnabled()) {
          LOG.debug(
              "No saslNettyServer for "
                  + ctx.getChannel()
                  + " yet; creating now, with secret manager: "
                  + secretManager);
        }
        saslNettyServer = new SaslNettyServer(secretManager);
        NettyServer.CHANNEL_SASL_NETTY_SERVERS.set(ctx.getChannel(), saslNettyServer);
      } else {
        if (LOG.isDebugEnabled()) {
          LOG.debug(
              "Found existing saslNettyServer on server:"
                  + ctx.getChannel().getLocalAddress()
                  + " for client "
                  + ctx.getChannel().getRemoteAddress());
        }
      }

      ((SaslTokenMessageRequest) writableRequest).processToken(saslNettyServer);
      // Send response to client.
      ctx.getChannel().write(writableRequest);
      if (saslNettyServer.isComplete()) {
        // If authentication of client is complete, we will also send a
        // SASL-Complete message to the client.
        if (LOG.isDebugEnabled()) {
          LOG.debug(
              "SASL authentication is complete for client with "
                  + "username: "******"Removing SaslServerHandler from pipeline since SASL "
                  + "authentication is complete.");
        }
        ctx.getPipeline().remove(this);
      }
      // do not send upstream to other handlers: no further action needs to be
      // done for SASL_TOKEN_MESSAGE_REQUEST requests.
      return;
    } else {
      // Client should not be sending other-than-SASL messages before
      // SaslServerHandler has removed itself from the pipeline. Such non-SASL
      // requests will be denied by the Authorize channel handler (the next
      // handler upstream in the server pipeline) if SASL authentication has
      // not completed.
      LOG.warn("Sending upstream an unexpected non-SASL message :  " + writableRequest);
      ctx.sendUpstream(e);
    }
  }
 @SuppressWarnings("unchecked")
 @Override
 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
   ctx.getPipeline().remove(this);
   future.setResult(FutureResult.create(e.getCause()));
 }
 @Override
 public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
   super.channelOpen(ctx, e);
   this.channelHandlerContext = ctx;
   serverHandler = ctx.getPipeline().get(ServerHandler.class);
 }
  /** Expected Message types: - HTTP Requests */
  @Override
  public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {

    if (!(e.getMessage() instanceof HttpRequest)) {
      super.messageReceived(ctx, e);
      return;
    }

    HttpRequest httpRequest = (HttpRequest) e.getMessage();
    URI targetUri =
        toThing(URI.create("http://" + httpRequest.getHeader("HOST") + httpRequest.getUri()));

    log.debug("Received HTTP request for " + targetUri);

    if (httpRequest.getHeader("HOST").contains(DNS_WILDCARD_POSTFIX)) {
      String targetUriHost = InetAddress.getByName(targetUri.getHost()).getHostAddress();
      // remove leading zeros per block
      targetUriHost = targetUriHost.replaceAll(":0000", ":0");
      targetUriHost = targetUriHost.replaceAll(":000", ":0");
      targetUriHost = targetUriHost.replaceAll(":00", ":0");
      targetUriHost = targetUriHost.replaceAll("(:0)([ABCDEFabcdef123456789])", ":$2");

      // return shortened IP
      targetUriHost =
          targetUriHost.replaceAll("((?:(?:^|:)0\\b){2,}):?(?!\\S*\\b\\1:0\\b)(\\S*)", "::$2");
      log.debug("Target host: " + targetUriHost);

      String targetUriPath = targetUri.getRawPath();
      log.debug("Target path: " + targetUriPath);

      if (IPAddressUtil.isIPv6LiteralAddress(targetUriHost)) {
        targetUriHost = "[" + targetUriHost + "]";
      }

      targetUri = toThing(URI.create("http://" + targetUriHost + httpRequest.getUri()));
      log.debug("Shortened target URI: " + targetUri);
    }

    URI uriToCheck = targetUri;
    if ((uriToCheck.getQuery() != null) && (uriToCheck.getQuery().equals("html"))) {
      uriToCheck = toThing(URI.create("http://" + targetUri.getHost() + targetUri.getPath()));
    }

    if (entities.containsKey(uriToCheck)) {
      Backend backend = entities.get(uriToCheck);
      try {
        ctx.getPipeline().remove("Backend to handle request");
      } catch (NoSuchElementException ex) {
        // Fine. There was no handler to be removed.
      }
      ctx.getPipeline().addLast("Backend to handle request", backend);
      log.debug("Forward request to " + backend);
    } else if (virtualEntities.containsKey(uriToCheck)) {
      Backend backend = virtualEntities.get(uriToCheck);
      try {
        ctx.getPipeline().remove("Backend to handle request");
      } catch (NoSuchElementException ex) {
        // Fine. There was no handler to be removed.
      }
      ctx.getPipeline().addLast("Backend to handle request", backend);
      log.debug("Forward request to " + backend);
    }

    //        else if (targetUriPath.equals(PATH_TO_SERVER_LIST)) {
    //            // Handle request for resource at path ".well-known/core"
    //            StringBuilder buf = new StringBuilder();
    //            for(URI entity: getServices()) {
    //                buf.append(toThing(entity).toString() + "\n");
    //            }
    //            Channels.write(ctx.getChannel(),
    // Answer.create(buf.toString()).setMime("text/plain"));
    //            return;
    //        }

    //        else if("/visualizer".equals(targetUriPath)){
    //            try {
    //                ctx.getPipeline().remove("Backend to handle request");
    //            }
    //            catch(NoSuchElementException ex) {
    //                //Fine. There was no handler to be removed.
    //            }
    //            ctx.getPipeline().addLast("VisualizerService", VisualizerService.getInstance());
    //            log.debug("Forward request to visualizer.");
    //        }

    /*else if(targetUriPath.startsWith(SERVER_PATH_TO_SLSE_UI)) {
    	String f = LOCAL_PATH_TO_SLSE_UI + targetUriPath.substring(SERVER_PATH_TO_SLSE_UI.length());
    	Channels.write(ctx.getChannel(), Answer.create(new File(f)).setMime("text/n3"));
    }*/

    else if ("/".equals(targetUri.getRawPath())) {
      HttpResponse httpResponse =
          new DefaultHttpResponse(httpRequest.getProtocolVersion(), HttpResponseStatus.OK);

      httpResponse.setContent(getHtmlListOfServices());
      ChannelFuture future = Channels.write(ctx.getChannel(), httpResponse);
      future.addListener(ChannelFutureListener.CLOSE);
      return;
    } else if (httpRequest.getUri().endsWith("spitfire-logo.png")
        || (httpRequest.getUri().endsWith("favicon.ico"))) {
      File img;
      if (httpRequest.getUri().endsWith("spitfire-logo.png")) {
        img = new File("spitfire-logo.png");
      } else {
        img = new File("favicon.ico");
      }

      int imgLength = (int) img.length();

      FileInputStream in = new FileInputStream(img);
      byte[] imgMemory = new byte[imgLength];
      in.read(imgMemory);
      in.close();

      HttpResponse httpResponse =
          new DefaultHttpResponse(httpRequest.getProtocolVersion(), HttpResponseStatus.OK);
      httpResponse.setContent(ChannelBuffers.wrappedBuffer(imgMemory));
      ChannelFuture future = Channels.write(ctx.getChannel(), httpResponse);
      future.addListener(ChannelFutureListener.CLOSE);

      if (httpRequest.getUri().endsWith("spitfire-logo.png")) {
        log.debug("Served request for Spitfire image.");
      } else {
        log.debug("Served favicon.");
      }

      return;
    }

    ctx.sendUpstream(e);
  }
Example #20
0
  private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req, MessageEvent e)
      throws Exception {
    /* 获取请求头中的cookie字段 */
    String cookieInReqHeader = req.getHeader(COOKIE);

    /*
     * 根据URL地址判断当前的请求处理方式
     *      1.如果URL为ServerHandler.ROOT_DIR,那么处理用户登录过程
     *      2.如果URL为WebSocketHandler.WEBSOCKET_PATH,则处理连接WebSocket建立过程
     *      3.........(等待后续添加)
     */
    if (req.getUri().equals(ServerHandler.ROOT_DIR)) // 判断URL为根目录地址
    {
      HttpResponse res = new DefaultHttpResponse(HTTP_1_1, OK);

      /*
       * 判断当前请求头中的cookie是否为空
       * 如果为空,需要强制要求浏览器设置cookie
       */
      if (cookieInReqHeader == null) {
        String sessionId = Session.produceSessionId();
        ServerHandler.sessionManager.add(
            new Session(sessionId, Session.INDEX, ctx.getChannel().getId()));
        ChannelBuffer content = ServerWritePage.getContent(Session.INDEX);
        buildResponse(res, true, sessionId, content, content.readableBytes());
        sendHttpResponse(ctx, req, res);
      } else {
        /* 即使浏览器请求头中的cookie不为空
         * 可能服务器的Session集合中并不包含对应的cookie,此时仍然需要强制浏览器重设cookie
         */
        if (!ServerHandler.sessionManager.contain(cookieInReqHeader)) {
          String sessionId = Session.produceSessionId();
          ServerHandler.sessionManager.add(
              new Session(sessionId, Session.INDEX, ctx.getChannel().getId()));
          ChannelBuffer content = ServerWritePage.getContent(Session.INDEX);
          buildResponse(res, true, sessionId, content, content.readableBytes());
          sendHttpResponse(ctx, req, res);
        } else {
          int sessionState = ServerHandler.sessionManager.find(cookieInReqHeader).getCurrentState();
          if (sessionState == Session.INDEX) // 判断当前的Session状态是否为登录页面状态
          {
            if (req.getMethod() == GET) // 如果当前网页被重复刷新,需要始终维持此Session并向用户送回登陆页面
            {
              ServerHandler.sessionManager.sessionActiveTimeUpdate(cookieInReqHeader);
              ChannelBuffer content = ServerWritePage.getContent(Session.INDEX);
              buildResponse(res, false, null, content, content.readableBytes());
              sendHttpResponse(ctx, req, res);
            }
            if (req.getMethod() == POST) // 如果用户点击了登录按钮
            {
              HashMap<String, String> parameterList = getPostParameter(req); // 获取POST请求参数
              if (parameterList.get("navigatorName").equals("Firefox")
                  || parameterList.get("navigatorName").equals("Chrome")
                  || parameterList
                      .get("navigatorName")
                      .equals("Safari")) // 暂时简单判断浏览器版本,并根据浏览器版本发回连接建立页面
              {
                try {
                  // session的状态和活动时间都被相继更新
                  ServerHandler.sessionManager.sessionStateUpdate(
                      cookieInReqHeader, Session.WEBSOCKET);
                  ServerHandler.sessionManager.sessionActiveTimeUpdate(cookieInReqHeader);
                  ChannelBuffer content = ServerWritePage.getContent(Session.WEBSOCKET);
                  buildResponse(res, false, null, content, content.readableBytes());
                  sendHttpResponse(ctx, req, res);
                } catch (Exception a) {
                  a.printStackTrace();
                }
              } else // 根据其他浏览器版本选择 long Polling或者streaming方式同样建立连接
              {
                /* To deal with long polling and streaming */
                /* To send back the correspondent page */
              }
            }
          } else if (sessionState == Session.WEBSOCKET) // 当前的Session状态是否为WebSocket连接建立状态
          {
            /*
             * 如果已经是连接建立状态,但用户刷新了此页面,此时仍然需要维持Session
             * WebSocket连接已经建立的情况下,刷新页面之后用户将不需要重新登录
             * 但是先前的WebSocket连接将被强制关闭,并且重新发出新的连接建立请求
             * 即强制一个用户只能向服务器请求一条WebSocket连接
             */
            if (req.getMethod() == GET) {
              if (ServerHandler.clientChannelGroup.find(
                      ServerHandler.sessionManager.find(cookieInReqHeader).getChannelId())
                  != null) {
                ServerHandler.clientChannelGroup
                    .find(ServerHandler.sessionManager.find(cookieInReqHeader).getChannelId())
                    .close();
              }
              ServerHandler.sessionManager.sessionActiveTimeUpdate(cookieInReqHeader);
              ChannelBuffer content = ServerWritePage.getContent(Session.WEBSOCKET);
              buildResponse(res, false, null, content, content.readableBytes());
              sendHttpResponse(ctx, req, res);
            }
          }
        }
      }

    } else if (req.getUri().equals(WebSocketHandler.WEBSOCKET_PATH)) // 根据地址判断WebSocket请求是否被发送
    {
      ServerHandler.sessionManager.sessionChannelIdUpdate(
          cookieInReqHeader, ctx.getChannel().getId());
      ctx.getPipeline()
          .addLast("websocket", new WebSocketHandler()); // 将WebSocketHandler加入到当前的Pipeline中
      ctx.getPipeline().remove(this); // 将当前的Handler移除掉
      ctx.sendUpstream(e); // 将Pipeline中的事件传递到WebSocketHandler中
      ServerHandler.clientChannelGroup.add(ctx.getChannel()); // 并且将当前的Channel加入到Group中
    } else { // 如果请求到了其他地址,发回请求地址无法响应的回复
      HttpResponse res = new DefaultHttpResponse(HTTP_1_1, NOT_FOUND);
      sendHttpResponse(ctx, req, res);
      return;
    }
  }
  /**
   * Sends the opening request to the server:
   *
   * <pre>
   * GET /demo HTTP/1.1
   * Upgrade: WebSocket
   * Connection: Upgrade
   * Host: example.com
   * Origin: http://example.com
   * Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5
   * Sec-WebSocket-Key2: 12998 5 Y3 1  .P00
   *
   * ^n:ds[4U
   * </pre>
   *
   * @param ctx Channel context
   * @param channel Channel into which we can write our request
   */
  @Override
  public void beginOpeningHandshake(ChannelHandlerContext ctx, Channel channel) {
    // Make keys
    int spaces1 = createRandomNumber(1, 12);
    int spaces2 = createRandomNumber(1, 12);

    int max1 = Integer.MAX_VALUE / spaces1;
    int max2 = Integer.MAX_VALUE / spaces2;

    int number1 = createRandomNumber(0, max1);
    int number2 = createRandomNumber(0, max2);

    int product1 = number1 * spaces1;
    int product2 = number2 * spaces2;

    String key1 = Integer.toString(product1);
    String key2 = Integer.toString(product2);

    key1 = insertRandomCharacters(key1);
    key2 = insertRandomCharacters(key2);

    key1 = insertSpaces(key1, spaces1);
    key2 = insertSpaces(key2, spaces2);

    byte[] key3 = createRandomBytes(8);

    ByteBuffer buffer = ByteBuffer.allocate(4);
    buffer.putInt(number1);
    byte[] number1Array = buffer.array();
    buffer = ByteBuffer.allocate(4);
    buffer.putInt(number2);
    byte[] number2Array = buffer.array();

    byte[] challenge = new byte[16];
    System.arraycopy(number1Array, 0, challenge, 0, 4);
    System.arraycopy(number2Array, 0, challenge, 4, 4);
    System.arraycopy(key3, 0, challenge, 8, 8);
    this.expectedChallengeResponseBytes = md5(challenge);

    // Get path
    URI wsURL = this.getWebSocketURL();
    String path = wsURL.getPath();
    if (wsURL.getQuery() != null && wsURL.getQuery().length() > 0) {
      path = wsURL.getPath() + "?" + wsURL.getQuery();
    }

    // Format request
    HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
    request.addHeader(Names.UPGRADE, Values.WEBSOCKET);
    request.addHeader(Names.CONNECTION, Values.UPGRADE);
    request.addHeader(Names.HOST, wsURL.getHost());
    request.addHeader(Names.ORIGIN, "http://" + wsURL.getHost());
    request.addHeader(Names.SEC_WEBSOCKET_KEY1, key1);
    request.addHeader(Names.SEC_WEBSOCKET_KEY2, key2);
    if (this.getSubProtocolRequest() != null && !this.getSubProtocolRequest().equals("")) {
      request.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, this.getSubProtocolRequest());
    }
    request.setContent(ChannelBuffers.copiedBuffer(key3));

    channel.write(request);

    ctx.getPipeline().replace("encoder", "ws-encoder", new WebSocket00FrameEncoder());
  }