public static boolean isModified(String etag, long last, HttpRequest nettyRequest) { if (nettyRequest.containsHeader(IF_NONE_MATCH)) { final String browserEtag = nettyRequest.getHeader(IF_NONE_MATCH); if (browserEtag.equals(etag)) { return false; } return true; } if (nettyRequest.containsHeader(IF_MODIFIED_SINCE)) { final String ifModifiedSince = nettyRequest.getHeader(IF_MODIFIED_SINCE); if (!StringUtils.isEmpty(ifModifiedSince)) { try { Date browserDate = Utils.getHttpDateFormatter().parse(ifModifiedSince); if (browserDate.getTime() >= last) { return false; } } catch (ParseException ex) { Logger.warn("Can't parse HTTP date", ex); } return true; } } return true; }
private void websocketHandshake(final ChannelHandlerContext ctx, HttpRequest req, MessageEvent e) throws Exception { // Create the WebSocket handshake response. HttpResponse res = new DefaultHttpResponse( HttpVersion.HTTP_1_1, new HttpResponseStatus(101, "Web Socket Protocol Handshake")); res.addHeader(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET); res.addHeader(CONNECTION, HttpHeaders.Values.UPGRADE); // Fill in the headers and contents depending on handshake method. if (req.containsHeader(SEC_WEBSOCKET_KEY1) && req.containsHeader(SEC_WEBSOCKET_KEY2)) { // New handshake method with a challenge: res.addHeader(SEC_WEBSOCKET_ORIGIN, req.getHeader(ORIGIN)); res.addHeader( SEC_WEBSOCKET_LOCATION, "ws://" + req.getHeader(HttpHeaders.Names.HOST) + req.getUri()); String protocol = req.getHeader(SEC_WEBSOCKET_PROTOCOL); if (protocol != null) { res.addHeader(SEC_WEBSOCKET_PROTOCOL, protocol); } // Calculate the answer of the challenge. String key1 = req.getHeader(SEC_WEBSOCKET_KEY1); String key2 = req.getHeader(SEC_WEBSOCKET_KEY2); int a = (int) (Long.parseLong(key1.replaceAll("[^0-9]", "")) / key1.replaceAll("[^ ]", "").length()); int b = (int) (Long.parseLong(key2.replaceAll("[^0-9]", "")) / key2.replaceAll("[^ ]", "").length()); long c = req.getContent().readLong(); ChannelBuffer input = ChannelBuffers.buffer(16); input.writeInt(a); input.writeInt(b); input.writeLong(c); try { ChannelBuffer output = ChannelBuffers.wrappedBuffer(MessageDigest.getInstance("MD5").digest(input.array())); res.setContent(output); } catch (NoSuchAlgorithmException ex) { throw new UnexpectedException(ex); } } else { // Old handshake method with no challenge: res.addHeader(WEBSOCKET_ORIGIN, req.getHeader(ORIGIN)); res.addHeader( WEBSOCKET_LOCATION, "ws://" + req.getHeader(HttpHeaders.Names.HOST) + req.getUri()); String protocol = req.getHeader(WEBSOCKET_PROTOCOL); if (protocol != null) { res.addHeader(WEBSOCKET_PROTOCOL, protocol); } } // Keep the original request Http.Request request = parseRequest(ctx, req); // Route the websocket request request.method = "WS"; Map<String, String> route = Router.route(request.method, request.path); if (!route.containsKey("action")) { // No route found to handle this websocket connection ctx.getChannel() .write(new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND)); return; } // Upgrade the connection and send the handshake response. ChannelPipeline p = ctx.getChannel().getPipeline(); p.remove("aggregator"); p.replace("decoder", "wsdecoder", new WebSocketFrameDecoder()); // Connect ctx.getChannel().write(res); p.replace("encoder", "wsencoder", new WebSocketFrameEncoder()); req.setMethod(new HttpMethod("WEBSOCKET")); // Inbound Http.Inbound inbound = new Http.Inbound() { @Override public boolean isOpen() { return ctx.getChannel().isOpen(); } }; channels.put(ctx, inbound); // Outbound Http.Outbound outbound = new Http.Outbound() { final List<ChannelFuture> writeFutures = Collections.synchronizedList(new ArrayList<ChannelFuture>()); Promise<Void> closeTask; synchronized void writeAndClose(ChannelFuture writeFuture) { if (!writeFuture.isDone()) { writeFutures.add(writeFuture); writeFuture.addListener( new ChannelFutureListener() { public void operationComplete(ChannelFuture cf) throws Exception { writeFutures.remove(cf); futureClose(); } }); } } void futureClose() { if (closeTask != null && writeFutures.isEmpty()) { closeTask.invoke(null); } } @Override public void send(String data) { if (!isOpen()) { throw new IllegalStateException("The outbound channel is closed"); } writeAndClose(ctx.getChannel().write(new DefaultWebSocketFrame(data))); } @Override public void send(byte opcode, byte[] data, int offset, int length) { if (!isOpen()) { throw new IllegalStateException("The outbound channel is closed"); } writeAndClose( ctx.getChannel() .write(new DefaultWebSocketFrame(opcode, wrappedBuffer(data, offset, length)))); } @Override public synchronized boolean isOpen() { return ctx.getChannel().isOpen() && closeTask == null; } @Override public synchronized void close() { closeTask = new Promise<Void>(); closeTask.onRedeem( new Action<Promise<Void>>() { public void invoke(Promise<Void> completed) { writeFutures.clear(); ctx.getChannel().disconnect(); closeTask = null; } }); futureClose(); } }; Invoker.invoke(new WebSocketInvocation(route, request, inbound, outbound, ctx, e)); }