private static HttpResponse addEtag( HttpRequest nettyRequest, HttpResponse httpResponse, File file) { if (Play.mode == Play.Mode.DEV) { httpResponse.setHeader(CACHE_CONTROL, "no-cache"); } else { String maxAge = Play.configuration.getProperty("http.cacheControl", "3600"); if (maxAge.equals("0")) { httpResponse.setHeader(CACHE_CONTROL, "no-cache"); } else { httpResponse.setHeader(CACHE_CONTROL, "max-age=" + maxAge); } } boolean useEtag = Play.configuration.getProperty("http.useETag", "true").equals("true"); long last = file.lastModified(); final String etag = "\"" + last + "-" + file.hashCode() + "\""; if (!isModified(etag, last, nettyRequest)) { if (nettyRequest.getMethod().equals(HttpMethod.GET)) { httpResponse.setStatus(HttpResponseStatus.NOT_MODIFIED); } if (useEtag) { httpResponse.setHeader(ETAG, etag); } } else { httpResponse.setHeader(LAST_MODIFIED, Utils.getHttpDateFormatter().format(new Date(last))); if (useEtag) { httpResponse.setHeader(ETAG, etag); } } return httpResponse; }
@Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent me) throws Exception { if (!(me.getMessage() instanceof HttpRequest)) { ctx.sendUpstream(me); return; } HttpRequest request = (HttpRequest) me.getMessage(); Object response; // Look up resource String path = request.getUri(); String host = request.getHeader("host"); log.debug("Received request for path:" + path); boolean showHtml = false; if (path.endsWith("?html")) { showHtml = true; path = path.replace("?html", ""); } for (String service : resources.keySet()) { log.debug("Available Service: " + service); } Model model = resources.get(path); if (model != null) { if (request.getMethod() == HttpMethod.GET) { if (showHtml) { String html = HtmlCreator.createModelPage(model, new URI(path), host); response = ChannelBuffers.wrappedBuffer(html.getBytes(Charset.forName("UTF-8"))); log.debug("Returned html page for resource: " + path); } else { response = new SelfDescription(model, new URI(request.getUri())); log.debug("Resource found: " + path); } } else { response = new DefaultHttpResponse( request.getProtocolVersion(), HttpResponseStatus.METHOD_NOT_ALLOWED); log.debug("Method not allowed: " + request.getMethod()); } } else { response = HttpResponseFactory.createHttpResponse( request.getProtocolVersion(), HttpResponseStatus.NOT_FOUND); log.debug("Resource not found: " + path); } // Send response ChannelFuture future = Channels.write(ctx.getChannel(), response); future.addListener(ChannelFutureListener.CLOSE); }
/** * Interface method implementation. Reads and processes Http commands sent to the service proxy. * Expects data in the Http protocol. * * @see * org.jboss.netty.channel.SimpleChannelUpstreamHandler#handleUpstream(org.jboss.netty.channel.ChannelHandlerContext, * org.jboss.netty.channel.ChannelEvent) */ public void messageReceived(ChannelHandlerContext ctx, MessageEvent messageEvent) throws Exception { HttpRequest request = (HttpRequest) messageEvent.getMessage(); LOGGER.debug("Request is: " + request.getMethod() + " " + request.getUri()); this.processRequestHeaders(request); ChannelBuffer inputBuffer = request.getContent(); byte[] requestData = new byte[inputBuffer.readableBytes()]; inputBuffer.readBytes(requestData, 0, requestData.length); // Prepare request Wrapper HttpRequestWrapper executorHttpRequest = new HttpRequestWrapper(); executorHttpRequest.setData(requestData); executorHttpRequest.setMethod(request.getMethod().toString()); executorHttpRequest.setUri(request.getUri()); executorHttpRequest.setHeaders(request.getHeaders()); executorHttpRequest.setProtocol(request.getProtocolVersion().getProtocolName()); executorHttpRequest.setMajorVersion(request.getProtocolVersion().getMajorVersion()); executorHttpRequest.setMinorVersion(request.getProtocolVersion().getMinorVersion()); // executor String proxy = this.proxyMap.get(this.getRoutingKey(request)); if (proxy == null) { proxy = this.proxyMap.get(RoutingHttpChannelHandler.ALL_ROUTES); LOGGER.info( "Routing key for : " + request.getUri() + " returned null. Using default proxy instead."); } Executor executor = this.repository.getExecutor(proxy, proxy, executorHttpRequest); // execute HttpResponse response = null; try { response = (HttpResponse) executor.execute(); } catch (Exception e) { throw new RuntimeException( "Error in executing HTTP request:" + proxy + " URI:" + request.getUri(), e); } finally { // Publishes event both in case of success and failure. Class eventSource = (executor == null) ? this.getClass() : executor.getClass(); if (eventProducer != null) eventProducer.publishEvent(executor, request.getUri(), eventSource, HTTP_HANDLER); else LOGGER.debug("eventProducer not set, not publishing event"); } // send response writeCommandExecutionResponse(ctx, messageEvent, response); }
private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception { // Allow only GET methods. if (req.getMethod() != GET) { sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN)); return; } // Send the demo page and favicon.ico if (req.getUri().equals("/")) { HttpResponse res = new DefaultHttpResponse(HTTP_1_1, OK); ChannelBuffer content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req)); res.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8"); setContentLength(res, content.readableBytes()); res.setContent(content); sendHttpResponse(ctx, req, res); return; } else if (req.getUri().equals("/favicon.ico")) { HttpResponse res = new DefaultHttpResponse(HTTP_1_1, NOT_FOUND); sendHttpResponse(ctx, req, res); return; } // Handshake WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(this.getWebSocketLocation(req), null, false); this.handshaker = wsFactory.newHandshaker(ctx, req); if (this.handshaker == null) { wsFactory.sendUnsupportedWebSocketVersionResponse(ctx); } else { this.handshaker.executeOpeningHandshake(ctx, req); } }
protected static void writeResponse( ChannelHandlerContext ctx, Response response, HttpResponse nettyResponse, HttpRequest nettyRequest) { Logger.trace("writeResponse: begin"); byte[] content = null; final boolean keepAlive = isKeepAlive(nettyRequest); if (nettyRequest.getMethod().equals(HttpMethod.HEAD)) { content = new byte[0]; } else { content = response.out.toByteArray(); } ChannelBuffer buf = ChannelBuffers.copiedBuffer(content); nettyResponse.setContent(buf); if (keepAlive) { // Add 'Content-Length' header only for a keep-alive connection. Logger.trace("writeResponse: content length [" + response.out.size() + "]"); setContentLength(nettyResponse, response.out.size()); } ChannelFuture f = ctx.getChannel().write(nettyResponse); // Decide whether to close the connection or not. if (!keepAlive) { // Close the connection when the whole content is written out. f.addListener(ChannelFutureListener.CLOSE); } Logger.trace("writeResponse: end"); }
/** * @param factory the factory used to create InterfaceHttpData * @param request the request to encode * @param multipart True if the FORM is a ENCTYPE="multipart/form-data" * @param charset the charset to use as default * @throws NullPointerException for request or charset or factory * @throws ErrorDataEncoderException if the request is not a POST */ public HttpPostRequestEncoder( HttpDataFactory factory, HttpRequest request, boolean multipart, Charset charset) throws ErrorDataEncoderException { if (factory == null) { throw new NullPointerException("factory"); } if (request == null) { throw new NullPointerException("request"); } if (charset == null) { throw new NullPointerException("charset"); } if (request.getMethod() != HttpMethod.POST) { throw new ErrorDataEncoderException("Cannot create a Encoder if not a POST"); } this.request = request; this.charset = charset; this.factory = factory; // Fill default values bodyListDatas = new ArrayList<InterfaceHttpData>(); // default mode isLastChunk = false; isLastChunkSent = false; isMultipart = multipart; multipartHttpDatas = new ArrayList<InterfaceHttpData>(); if (isMultipart) { initDataMultipart(); } }
private static void sendStatus( HttpResponse response, @Nullable HttpRequest request, Channel channel, @Nullable String description) { response.setHeader(CONTENT_TYPE, "text/html"); if (request == null || request.getMethod() != HttpMethod.HEAD) { String message = response.getStatus().toString(); StringBuilder builder = new StringBuilder(); builder .append("<!doctype html><title>") .append(message) .append("</title>") .append("<h1 style=\"text-align: center\">") .append(message) .append("</h1>"); if (description != null) { builder.append("<p>").append(description).append("</p>"); } builder .append("<hr/><p style=\"text-align: center\">") .append(StringUtil.notNullize(getServerHeaderValue(), "")) .append("</p>"); response.setContent(ChannelBuffers.copiedBuffer(builder, CharsetUtil.UTF_8)); } send(response, channel, request); }
@Override public boolean checkAccepts(HttpRequest message) { return (super.checkAccepts(message) && message .getMethod() .getName() .equals(ObjectStorageProperties.HTTPVerb.OPTIONS.toString())); }
private String getUri() { String uri = null; if (HttpMethod.POST == request.getMethod()) { uri = request.getUri() + "?" + request.getContent().toString("ISO-8859-1"); } else { uri = request.getUri(); } return uri; }
@Override public boolean match(HttpRequest req) { if (onlyHttp && req.getMethod().equals(HttpMethod.CONNECT)) { return false; } if (hostRule != null && !StringHelper.wildCardMatch(HttpHeaders.getHost(req), hostRule)) { return false; } if (null != urlRule) { return StringHelper.wildCardMatch(MiscHelper.getURLString(req, true), urlRule); } // System.out.println("###WildcardRule for " + HttpHeaders.getHost(req) + "##" + origin); return true; }
public boolean isSupported(HttpRequest request) { return request.getMethod() == HttpMethod.GET || request.getMethod() == HttpMethod.HEAD; }
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; } }
@Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { RequestV2 request = null; RendererConfiguration renderer = null; String userAgentString = null; StringBuilder unknownHeaders = new StringBuilder(); String separator = ""; HttpRequest nettyRequest = this.nettyRequest = (HttpRequest) e.getMessage(); InetSocketAddress remoteAddress = (InetSocketAddress) e.getChannel().getRemoteAddress(); InetAddress ia = remoteAddress.getAddress(); // Is the request from our own Cling service, i.e. self-originating? boolean isSelf = ia.getHostAddress().equals(PMS.get().getServer().getHost()) && nettyRequest.headers().get(HttpHeaders.Names.USER_AGENT) != null && nettyRequest.headers().get(HttpHeaders.Names.USER_AGENT).contains("UMS/"); // Filter if required if (isSelf || filterIp(ia)) { e.getChannel().close(); LOGGER.trace( isSelf ? ("Ignoring self-originating request from " + ia + ":" + remoteAddress.getPort()) : ("Access denied for address " + ia + " based on IP filter")); return; } LOGGER.trace("Opened request handler on socket " + remoteAddress); PMS.get().getRegistry().disableGoToSleep(); request = new RequestV2(nettyRequest.getMethod().getName(), nettyRequest.getUri().substring(1)); LOGGER.trace( "Request: " + nettyRequest.getProtocolVersion().getText() + " : " + request.getMethod() + " : " + request.getArgument()); if (nettyRequest.getProtocolVersion().getMinorVersion() == 0) { request.setHttp10(true); } HttpHeaders headers = nettyRequest.headers(); // The handler makes a couple of attempts to recognize a renderer from its requests. // IP address matches from previous requests are preferred, when that fails request // header matches are attempted and if those fail as well we're stuck with the // default renderer. // Attempt 1: try to recognize the renderer by its socket address from previous requests renderer = RendererConfiguration.getRendererConfigurationBySocketAddress(ia); // If the renderer exists but isn't marked as loaded it means it's unrecognized // by upnp and we still need to attempt http recognition here. if (renderer == null || !renderer.loaded) { // Attempt 2: try to recognize the renderer by matching headers renderer = RendererConfiguration.getRendererConfigurationByHeaders(headers.entries(), ia); } if (renderer != null) { request.setMediaRenderer(renderer); } Set<String> headerNames = headers.names(); Iterator<String> iterator = headerNames.iterator(); while (iterator.hasNext()) { String name = iterator.next(); String headerLine = name + ": " + headers.get(name); LOGGER.trace("Received on socket: " + headerLine); if (headerLine.toUpperCase().startsWith("USER-AGENT")) { userAgentString = headerLine.substring(headerLine.indexOf(':') + 1).trim(); } try { StringTokenizer s = new StringTokenizer(headerLine); String temp = s.nextToken(); if (temp.toUpperCase().equals("SOAPACTION:")) { request.setSoapaction(s.nextToken()); } else if (temp.toUpperCase().equals("CALLBACK:")) { request.setSoapaction(s.nextToken()); } else if (headerLine.toUpperCase().contains("RANGE: BYTES=")) { String nums = headerLine.substring(headerLine.toUpperCase().indexOf("RANGE: BYTES=") + 13).trim(); StringTokenizer st = new StringTokenizer(nums, "-"); if (!nums.startsWith("-")) { request.setLowRange(Long.parseLong(st.nextToken())); } if (!nums.startsWith("-") && !nums.endsWith("-")) { request.setHighRange(Long.parseLong(st.nextToken())); } else { request.setHighRange(-1); } } else if (headerLine.toLowerCase().contains("transfermode.dlna.org:")) { request.setTransferMode( headerLine .substring(headerLine.toLowerCase().indexOf("transfermode.dlna.org:") + 22) .trim()); } else if (headerLine.toLowerCase().contains("getcontentfeatures.dlna.org:")) { request.setContentFeatures( headerLine .substring(headerLine.toLowerCase().indexOf("getcontentfeatures.dlna.org:") + 28) .trim()); } else { Matcher matcher = TIMERANGE_PATTERN.matcher(headerLine); if (matcher.find()) { String first = matcher.group(1); if (first != null) { request.setTimeRangeStartString(first); } String end = matcher.group(2); if (end != null) { request.setTimeRangeEndString(end); } } else { /** * If we made it to here, none of the previous header checks matched. Unknown headers * make interesting logging info when we cannot recognize the media renderer, so keep * track of the truly unknown ones. */ boolean isKnown = false; // Try to match known headers. String lowerCaseHeaderLine = headerLine.toLowerCase(); for (String knownHeaderString : KNOWN_HEADERS) { if (lowerCaseHeaderLine.startsWith(knownHeaderString)) { isKnown = true; break; } } // It may be unusual but already known if (renderer != null) { String additionalHeader = renderer.getUserAgentAdditionalHttpHeader(); if (StringUtils.isNotBlank(additionalHeader) && lowerCaseHeaderLine.startsWith(additionalHeader)) { isKnown = true; } } if (!isKnown) { // Truly unknown header, therefore interesting. Save for later use. unknownHeaders.append(separator).append(headerLine); separator = ", "; } } } } catch (Exception ee) { LOGGER.error("Error parsing HTTP headers", ee); } } // Still no media renderer recognized? if (request.getMediaRenderer() == null) { // Attempt 3: Not really an attempt; all other attempts to recognize // the renderer have failed. The only option left is to assume the // default renderer. request.setMediaRenderer(RendererConfiguration.resolve(ia, null)); if (request.getMediaRenderer() != null) { LOGGER.trace( "Using default media renderer: " + request.getMediaRenderer().getRendererName()); if (userAgentString != null && !userAgentString.equals("FDSSDP")) { // We have found an unknown renderer LOGGER.info( "Media renderer was not recognized. Possible identifying HTTP headers: User-Agent: " + userAgentString + ("".equals(unknownHeaders.toString()) ? "" : ", " + unknownHeaders.toString())); PMS.get().setRendererFound(request.getMediaRenderer()); } } else { // If RendererConfiguration.resolve() didn't return the default renderer // it means we know via upnp that it's not really a renderer. return; } } else { if (userAgentString != null) { LOGGER.debug("HTTP User-Agent: " + userAgentString); } LOGGER.trace("Recognized media renderer: " + request.getMediaRenderer().getRendererName()); } if (nettyRequest.headers().contains(HttpHeaders.Names.CONTENT_LENGTH)) { byte data[] = new byte[(int) HttpHeaders.getContentLength(nettyRequest)]; ChannelBuffer content = nettyRequest.getContent(); content.readBytes(data); request.setTextContent(new String(data, "UTF-8")); } LOGGER.trace( "HTTP: " + request.getArgument() + " / " + request.getLowRange() + "-" + request.getHighRange()); writeResponse(ctx, e, request, ia); }
private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception { // Allow only GET methods. if (req.getMethod() != GET) { sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN)); return; } // Send the demo page. if (req.getUri().equals("/")) { HttpResponse res = new DefaultHttpResponse(HTTP_1_1, OK); ChannelBuffer content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req)); res.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8"); setContentLength(res, content.readableBytes()); res.setContent(content); sendHttpResponse(ctx, req, res); return; } // Serve the WebSocket handshake request. if (req.getUri().equals(WEBSOCKET_PATH) && Values.UPGRADE.equalsIgnoreCase(req.getHeader(CONNECTION)) && WEBSOCKET.equalsIgnoreCase(req.getHeader(Names.UPGRADE))) { // Create the WebSocket handshake response. HttpResponse res = new DefaultHttpResponse( HTTP_1_1, new HttpResponseStatus(101, "Web Socket Protocol Handshake")); res.addHeader(Names.UPGRADE, WEBSOCKET); res.addHeader(CONNECTION, 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, getWebSocketLocation(req)); 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); ChannelBuffer output = ChannelBuffers.wrappedBuffer(MessageDigest.getInstance("MD5").digest(input.array())); res.setContent(output); } else { // Old handshake method with no challenge: res.addHeader(WEBSOCKET_ORIGIN, req.getHeader(ORIGIN)); res.addHeader(WEBSOCKET_LOCATION, getWebSocketLocation(req)); String protocol = req.getHeader(WEBSOCKET_PROTOCOL); if (protocol != null) { res.addHeader(WEBSOCKET_PROTOCOL, protocol); } } // Upgrade the connection and send the handshake response. ChannelPipeline p = ctx.getChannel().getPipeline(); p.remove("aggregator"); p.replace("decoder", "wsdecoder", new WebSocketFrameDecoder()); ctx.getChannel().write(res); p.replace("encoder", "wsencoder", new WebSocketFrameEncoder()); return; } // Send an error page otherwise. sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN)); }
@Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (!(e.getMessage() instanceof HttpRequest)) { super.messageReceived(ctx, e); } HttpRequest request = (HttpRequest) e.getMessage(); URI uri = entityManager.normalizeURI(getEntityManager().getURIBase() + request.getUri()); String path = uri.getPath(); System.out.println("# received request: " + uri); /* * TODO: * - if GET "$base/entities/create", return entity creation form * - if GET "$base/entities/" || GET "$base/.well-known/servers" return entity list * - if POST "$base/entities/", call createEntity($postdata) * * - if GET "$base/sources/", return sources list * - if GET "$base/sources/edit" return sources edit form * - if POST "$base/sources/", call setSources($postdata) */ if (uri.equals(entityManager.normalizeURI(pathPrefix + "/list-entities"))) { if (request.getMethod() == HttpMethod.GET) { StringBuffer sb = new StringBuffer(); sb.append("<html><head><title>SLSE List</title></head><body><h1>SLSE List</h1><ol>"); for (ServiceLevelSemanticEntity slse : this.slseCache.getAll()) { sb.append("<li>"); sb.append(slse.getURI() + "<pre>" + slse.getDescribes() + "</pre>"); sb.append("</li>"); } sb.append("</ol></body></html>"); Channels.write(ctx.getChannel(), Answer.create(sb.toString())); } } else if (uri.equals(entityManager.normalizeURI(pathPrefix + "/create-entity"))) { if (request.getMethod() == HttpMethod.GET) { // copy into // HttpResponse response = new DefaultHttpResponse(request.getProtocolVersion(), // HttpResponseStatus.OK); // response.setContent(ChannelBuffers.wrappedBuffer(htmlContent)); Channels.write(ctx.getChannel(), Answer.create(new String(htmlContent))); // Channels.write(ctx.getChannel(), // Answer.create(new File("data/slse/ui/create_entity_form.html"))); } else if (request.getMethod() == HttpMethod.POST) { QueryStringDecoder qsd = new QueryStringDecoder( "http://blub.blah/?" + request.getContent().toString(Charset.defaultCharset())); String elementsQuery = ""; String name = ""; boolean dependsOnSensorValues = false; boolean multiNodeQuery = false; for (Map.Entry<String, List<String>> entry : qsd.getParameters().entrySet()) { String key = entry.getKey(); for (String value : entry.getValue()) { if (entry.getKey().equals("elementsQuery")) { elementsQuery = value; } else if (entry.getKey().equals("name")) { name = value; } else if (key.equals("dependsOnSensorValues") && value.equals("yes")) { dependsOnSensorValues = true; } else if (key.equals("multiNodeQuery") && value.equals("yes")) { multiNodeQuery = true; } } } System.out.println( "# adding rule: name=" + name + " dependsOnSensorValues=" + dependsOnSensorValues + " multiNodeQuery=" + multiNodeQuery); slseBuilder.addRule(name, elementsQuery, dependsOnSensorValues, multiNodeQuery); Channels.write( ctx.getChannel(), Answer.create( "<html><head><meta http-equiv=\"REFRESH\" content=\"0;url=/\"></head></html>")); } } else { uri = entityManager.toThing(uri); Model r = ModelFactory.createDefaultModel(); if (waitForPolling) { // System.out.println("# waiting for esecache: " + uri); synchronized (eseCache) { while (!eseCache.isPollComplete()) { try { eseCache.wait(1000); } catch (InterruptedException ex) { ex .printStackTrace(); // To change body of catch statement use File | Settings | // File Templates. } } } } // System.out.println("# waiting for slseCache: " + uri); synchronized (slseCache) { if (slseCache.get(uri.toString()) == null) { System.out.println( "! SLSE not found in cache: " + uri.toString() + " returning empty model"); } else { r.add(slseCache.get(uri.toString()).getModel()); } } ChannelFuture future = Channels.write(ctx.getChannel(), r); if (!HttpHeaders.isKeepAlive(request)) { future.addListener(ChannelFutureListener.CLOSE); } // System.out.println("# done: " + uri); } }
@Override protected void httpMessageReceived( ChannelHandlerContext ctx, MessageEvent e, HttpRequest httpRequest) throws Exception { HttpVersion version = httpRequest.getProtocolVersion(); URI httpLocation = getEffectiveURI(httpRequest); if (httpLocation == null) { // see RFC-7230 section 5.4 Host HttpResponse httpResponse = new DefaultHttpResponse(version, BAD_REQUEST); ChannelFuture future = future(ctx.getChannel()); write(ctx, future, httpResponse); return; } // channel's local address is resolved address so get the bind address from // server channel's attachment ChannelAddress transportCandidate = (ChannelAddress) ctx.getChannel().getParent().getAttachment(); ChannelAddress candidate = new ChannelAddress(httpLocation, transportCandidate); Entry<ChannelAddress, HttpServerChannel> httpBinding = httpBindings.floorEntry(candidate); if (httpBinding == null) { HttpResponse httpResponse = new DefaultHttpResponse(version, NOT_FOUND); ChannelFuture future = future(ctx.getChannel()); write(ctx, future, httpResponse); return; } HttpServerChannel parent = httpBinding.getValue(); ChannelFactory factory = parent.getFactory(); ChannelConfig config = parent.getConfig(); ChannelPipelineFactory pipelineFactory = config.getPipelineFactory(); ChannelPipeline pipeline = pipelineFactory.getPipeline(); ChannelAddress httpLocalAddress = parent.getLocalAddress(); Channel transport = ctx.getChannel(); ChannelAddress remoteAddress = remoteAddress(transport); ChannelAddress httpRemoteAddress = new ChannelAddress(httpLocation, remoteAddress, true); HttpChildChannelSink sink = new HttpChildChannelSink(transport); HttpChildChannel httpChildChannel = new HttpChildChannel(parent, factory, pipeline, sink); HttpChannelConfig httpChildConfig = httpChildChannel.getConfig(); httpChildConfig.setMethod(httpRequest.getMethod()); httpChildConfig.setVersion(version); httpChildConfig.getReadHeaders().set(httpRequest.headers()); httpChildConfig.setReadQuery(new QueryStringDecoder(httpRequest.getUri())); httpChildConfig.setWriteQuery(new QueryStringEncoder(httpRequest.getUri())); httpChildConfig.setStatus(HttpResponseStatus.OK); this.httpChildChannel = httpChildChannel; ChannelBuffer content = httpRequest.getContent(); // update read state before firing channel events if (isTransferEncodingChunked(httpRequest)) { httpChildChannel.readState(HttpReadState.CONTENT_CHUNKED); } else if (isContentLengthSet(httpRequest)) { long contentLength = getContentLength(httpRequest); contentLength -= content.readableBytes(); if (contentLength > 0) { httpChildChannel.readState(HttpReadState.CONTENT_CHUNKED); } else { httpChildChannel.readState(HttpReadState.CONTENT_COMPLETE); } } else { // see RFC-7230 section 3.3 // content indicated by presence of Content-Length or Transfer-Encoding httpChildChannel.readState(HttpReadState.CONTENT_COMPLETE); } fireChannelOpen(httpChildChannel); httpChildChannel.setLocalAddress(httpLocalAddress); httpChildChannel.setBound(); fireChannelBound(httpChildChannel, httpLocalAddress); httpChildChannel.setRemoteAddress(httpRemoteAddress); httpChildChannel.setConnected(); fireChannelConnected(httpChildChannel, httpRemoteAddress); if (content.readable()) { fireMessageReceived(httpChildChannel, content); } // note: status may be set in reaction to one of the above events, such as CONNECTED // so defer status code check until this point if (httpChildConfig.getStatus().getCode() == SWITCHING_PROTOCOLS.getCode()) { httpChildChannel.readState(HttpReadState.UPGRADED); } switch (httpChildChannel.readState()) { case CONTENT_COMPLETE: fireInputShutdown(httpChildChannel); this.httpChildChannel = null; if (httpChildChannel.setReadClosed()) { fireChannelDisconnected(httpChildChannel); fireChannelUnbound(httpChildChannel); fireChannelClosed(httpChildChannel); } break; default: break; } }
@Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent evt) throws Exception { HttpRequest request = (HttpRequest) evt.getMessage(); if (request.getMethod() != GET) { sendError(ctx, METHOD_NOT_ALLOWED); return; } final Map<String, List<String>> q = new QueryStringDecoder(request.getUri()).getParameters(); final List<String> mapIds = splitMaps(q.get("map")); final List<String> reduceQ = q.get("reduce"); final List<String> jobQ = q.get("job"); if (LOG.isInfoEnabled()) { LOG.info( "RECV: " + request.getUri() + "\n mapIds: " + mapIds + "\n reduceId: " + reduceQ + "\n jobId: " + jobQ); } if (mapIds == null || reduceQ == null || jobQ == null) { sendError(ctx, "Required param job, map and reduce", BAD_REQUEST); return; } if (reduceQ.size() != 1 || jobQ.size() != 1) { sendError(ctx, "Too many job/reduce parameters", BAD_REQUEST); return; } int reduceId; String jobId; try { reduceId = Integer.parseInt(reduceQ.get(0)); jobId = jobQ.get(0); } catch (NumberFormatException e) { sendError(ctx, "Bad reduce parameter", BAD_REQUEST); return; } catch (IllegalArgumentException e) { sendError(ctx, "Bad job parameter", BAD_REQUEST); return; } final String reqUri = request.getUri(); if (null == reqUri) { // TODO? add upstream? sendError(ctx, FORBIDDEN); return; } // Generate simple response without security HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); Channel ch = evt.getChannel(); ch.write(response); // TODO refactor the following into the pipeline ChannelFuture lastMap = null; for (String mapId : mapIds) { try { lastMap = sendMapOutput(ctx, ch, jobId, mapId, reduceId); if (null == lastMap) { sendError(ctx, NOT_FOUND); shuffleMetrics.failedOutput(); return; } } catch (IOException e) { LOG.error("Shuffle error ", e); shuffleMetrics.failedOutput(); sendError(ctx, e.getMessage(), INTERNAL_SERVER_ERROR); return; } } lastMap.addListener(ChannelFutureListener.CLOSE); }
private void processRequest(ResponseReceivedEvent event) { HttpRequest request = event.getRequest(); URI uri = null; try { uri = new URI(request.getUri()); } catch (URISyntaxException ex) { logger.error( "Can't create URI from request uri (" + request.getUri() + ")" + ex.getStackTrace()); } events.addElement(request.getMethod() + " | " + request.getUri()); executedEvents.ensureIndexIsVisible(events.getSize() - 1); int id = ++numberOfRequests; event.setId(id); /* URLs */ if (urlBase == null) { protocol = uri.getScheme(); host = uri.getHost(); port = uri.getPort(); urlBase = protocol + "://" + host; urlBaseString = "PROTOCOL + \"://\" + HOST"; if (port != -1) { urlBase += ":" + port; urlBaseString += " + \":\" + PORT"; } } String requestUrlBase = uri.getScheme() + "://" + uri.getHost(); if (uri.getPort() != -1) requestUrlBase += ":" + uri.getPort(); if (requestUrlBase.equals(urlBase)) event.setWithUrlBase(true); else urls.put("url_" + id, requestUrlBase + uri.getPath()); String headerAuthorization = event.getRequest().getHeader("Authorization"); request.removeHeader("Authorization"); if (headerAuthorization != null) { if (basicAuth == null) { // Split on " " and take 2nd group (Basic credentialsInBase64==) String credentials = new String(Base64.decodeBase64(headerAuthorization.split(" ")[1].getBytes())); basicAuth = new BasicAuth(requestUrlBase, credentials.split(":")[0], credentials.split(":")[1]); event.setBasicAuth(basicAuth); } else { if (requestUrlBase.equals(basicAuth.getUrlBase())) event.setBasicAuth(basicAuth); else basicAuth = null; } } /* Headers */ Map<String, String> requestHeaders = new TreeMap<String, String>(); for (Entry<String, String> entry : request.getHeaders()) requestHeaders.put(entry.getKey(), entry.getValue()); requestHeaders.remove("Cookie"); int bestChoice = 0; String headerKey = EMPTY; MapDifference<String, String> diff; Map<String, String> fullHeaders = new TreeMap<String, String>(); boolean containsHeaders = false; if (headers.size() > 0) { for (Entry<String, Map<String, String>> header : headers.entrySet()) { fullHeaders = new TreeMap<String, String>(header.getValue()); containsHeaders = false; if (header.getValue().containsKey("headers")) { fullHeaders.putAll(headers.get(header.getValue().get("headers"))); fullHeaders.remove("headers"); containsHeaders = true; } diff = Maps.difference(fullHeaders, requestHeaders); logger.debug(diff.toString()); if (diff.areEqual()) { headerKey = header.getKey(); bestChoice = 1; break; } else if (diff.entriesOnlyOnLeft().size() == 0 && diff.entriesDiffering().size() == 0 && !containsHeaders) { // header are included in requestHeaders headerKey = header.getKey(); bestChoice = 2; } else if (bestChoice > 2 && diff.entriesOnlyOnRight().size() == 0 && diff.entriesDiffering().size() == 0 && !containsHeaders) { // requestHeaders are included in header headerKey = header.getKey(); bestChoice = 3; } } } switch (bestChoice) { case 1: event.setHeadersId(headerKey); break; case 2: diff = Maps.difference(headers.get(headerKey), requestHeaders); TreeMap<String, String> tm2 = new TreeMap<String, String>(diff.entriesOnlyOnRight()); headers.put("headers_" + id, tm2); headers.get("headers_" + id).put("headers", headerKey); event.setHeadersId("headers_" + id); break; case 3: diff = Maps.difference(headers.get(headerKey), requestHeaders); TreeMap<String, String> tm3 = new TreeMap<String, String>(diff.entriesInCommon()); headers.put("headers_" + id, tm3); event.setHeadersId("headers_" + id); headers.remove(headerKey); tm3 = new TreeMap<String, String>(diff.entriesOnlyOnLeft()); headers.put(headerKey, tm3); headers.get(headerKey).put("headers", "headers_" + id); break; default: headers.put("headers_" + id, requestHeaders); event.setHeadersId("headers_" + id); } /* Add check if status is not in 20X */ if ((event.getResponse().getStatus().getCode() < 200) || (event.getResponse().getStatus().getCode() > 210)) event.setWithCheck(true); /* Params */ QueryStringDecoder decoder = new QueryStringDecoder(request.getUri()); event.getRequestParams().putAll((decoder.getParameters())); /* Content */ if (request.getContent().capacity() > 0) { String content = new String(request.getContent().array()); // We check if it's a form validation and so we extract post params if ("application/x-www-form-urlencoded".equals(request.getHeader("Content-Type"))) { decoder = new QueryStringDecoder("http://localhost/?" + content); event.getRequestParams().putAll(decoder.getParameters()); } else { event.setWithBody(true); dumpRequestBody(id, content); } } listEvents.add(event); }
@Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { RequestV2 request = null; RendererConfiguration renderer = null; String userAgentString = null; StringBuilder unknownHeaders = new StringBuilder(); String separator = ""; boolean isWindowsMediaPlayer = false; HttpRequest nettyRequest = this.nettyRequest = (HttpRequest) e.getMessage(); InetSocketAddress remoteAddress = (InetSocketAddress) e.getChannel().getRemoteAddress(); InetAddress ia = remoteAddress.getAddress(); // Apply the IP filter if (filterIp(ia)) { e.getChannel().close(); LOGGER.trace("Access denied for address " + ia + " based on IP filter"); return; } LOGGER.trace("Opened request handler on socket " + remoteAddress); PMS.get().getRegistry().disableGoToSleep(); if (HttpMethod.GET.equals(nettyRequest.getMethod())) { request = new RequestV2("GET", nettyRequest.getUri().substring(1)); } else if (HttpMethod.POST.equals(nettyRequest.getMethod())) { request = new RequestV2("POST", nettyRequest.getUri().substring(1)); } else if (HttpMethod.HEAD.equals(nettyRequest.getMethod())) { request = new RequestV2("HEAD", nettyRequest.getUri().substring(1)); } else { request = new RequestV2(nettyRequest.getMethod().getName(), nettyRequest.getUri().substring(1)); } LOGGER.trace( "Request: " + nettyRequest.getProtocolVersion().getText() + " : " + request.getMethod() + " : " + request.getArgument()); if (nettyRequest.getProtocolVersion().getMinorVersion() == 0) { request.setHttp10(true); } // The handler makes a couple of attempts to recognize a renderer from its requests. // IP address matches from previous requests are preferred, when that fails request // header matches are attempted and if those fail as well we're stuck with the // default renderer. // Attempt 1: try to recognize the renderer by its socket address from previous requests renderer = RendererConfiguration.getRendererConfigurationBySocketAddress(ia); if (renderer != null) { if (!"WMP".equals(renderer.getRendererName())) { PMS.get().setRendererfound(renderer); request.setMediaRenderer(renderer); LOGGER.trace( "Matched media renderer \"" + renderer.getRendererName() + "\" based on address " + ia); } else { LOGGER.trace("Detected and blocked Windows Media Player"); isWindowsMediaPlayer = true; } } for (String name : nettyRequest.getHeaderNames()) { String headerLine = name + ": " + nettyRequest.getHeader(name); LOGGER.trace("Received on socket: " + headerLine); if (renderer == null && headerLine != null && headerLine.toUpperCase().startsWith("USER-AGENT")) { userAgentString = headerLine.substring(headerLine.indexOf(":") + 1).trim(); // Attempt 2: try to recognize the renderer by matching the "User-Agent" header renderer = RendererConfiguration.getRendererConfigurationByUA(userAgentString); if (renderer != null) { if (!"WMP".equals(renderer.getRendererName())) { request.setMediaRenderer(renderer); renderer.associateIP(ia); // Associate IP address for later requests PMS.get().setRendererfound(renderer); LOGGER.trace( "Matched media renderer \"" + renderer.getRendererName() + "\" based on header \"" + headerLine + "\""); } else if (!isWindowsMediaPlayer) { LOGGER.trace("Detected and blocked Windows Media Player"); isWindowsMediaPlayer = true; } } } if (renderer == null && headerLine != null) { // Attempt 3: try to recognize the renderer by matching an additional header renderer = RendererConfiguration.getRendererConfigurationByUAAHH(headerLine); if (renderer != null) { request.setMediaRenderer(renderer); renderer.associateIP(ia); // Associate IP address for later requests PMS.get().setRendererfound(renderer); LOGGER.trace( "Matched media renderer \"" + renderer.getRendererName() + "\" based on header \"" + headerLine + "\""); } } try { StringTokenizer s = new StringTokenizer(headerLine); String temp = s.nextToken(); if (temp.toUpperCase().equals("SOAPACTION:")) { request.setSoapaction(s.nextToken()); } else if (temp.toUpperCase().equals("CALLBACK:")) { request.setSoapaction(s.nextToken()); } else if (headerLine.toUpperCase().indexOf("RANGE: BYTES=") > -1) { String nums = headerLine.substring(headerLine.toUpperCase().indexOf("RANGE: BYTES=") + 13).trim(); StringTokenizer st = new StringTokenizer(nums, "-"); if (!nums.startsWith("-")) { request.setLowRange(Long.parseLong(st.nextToken())); } if (!nums.startsWith("-") && !nums.endsWith("-")) { request.setHighRange(Long.parseLong(st.nextToken())); } else { request.setHighRange(-1); } } else if (headerLine.toLowerCase().indexOf("transfermode.dlna.org:") > -1) { request.setTransferMode( headerLine .substring(headerLine.toLowerCase().indexOf("transfermode.dlna.org:") + 22) .trim()); } else if (headerLine.toLowerCase().indexOf("getcontentfeatures.dlna.org:") > -1) { request.setContentFeatures( headerLine .substring(headerLine.toLowerCase().indexOf("getcontentfeatures.dlna.org:") + 28) .trim()); } else { Matcher matcher = TIMERANGE_PATTERN.matcher(headerLine); if (matcher.find()) { String first = matcher.group(1); if (first != null) { request.setTimeRangeStartString(first); } String end = matcher.group(2); if (end != null) { request.setTimeRangeEndString(end); } } else { // If we made it to here, none of the previous header checks matched. // Unknown headers make interesting logging info when we cannot recognize // the media renderer, so keep track of the truly unknown ones. boolean isKnown = false; // Try to match possible known headers. for (String knownHeaderString : KNOWN_HEADERS) { if (headerLine.toLowerCase().startsWith(knownHeaderString.toLowerCase())) { isKnown = true; break; } } if (!isKnown) { // Truly unknown header, therefore interesting. Save for later use. unknownHeaders.append(separator).append(headerLine); separator = ", "; } } } } catch (Exception ee) { LOGGER.error("Error parsing HTTP headers", ee); } } if (!isWindowsMediaPlayer) { if (request != null) { // Still no media renderer recognized? if (request.getMediaRenderer() == null) { // Attempt 4: Not really an attempt; all other attempts to recognize // the renderer have failed. The only option left is to assume the // default renderer. request.setMediaRenderer(RendererConfiguration.getDefaultConf()); LOGGER.trace( "Using default media renderer: " + request.getMediaRenderer().getRendererName()); if (userAgentString != null && !userAgentString.equals("FDSSDP")) { // We have found an unknown renderer LOGGER.info( "Media renderer was not recognized. Possible identifying HTTP headers: User-Agent: " + userAgentString + ("".equals(unknownHeaders.toString()) ? "" : ", " + unknownHeaders.toString())); PMS.get().setRendererfound(request.getMediaRenderer()); } } else { if (userAgentString != null) { LOGGER.debug("HTTP User-Agent: " + userAgentString); } LOGGER.trace( "Recognized media renderer: " + request.getMediaRenderer().getRendererName()); } } if (HttpHeaders.getContentLength(nettyRequest) > 0) { byte data[] = new byte[(int) HttpHeaders.getContentLength(nettyRequest)]; ChannelBuffer content = nettyRequest.getContent(); content.readBytes(data); request.setTextContent(new String(data, "UTF-8")); } if (request != null) { LOGGER.trace( "HTTP: " + request.getArgument() + " / " + request.getLowRange() + "-" + request.getHighRange()); } writeResponse(e, request, ia); } }
public void serveStatic( RenderStatic renderStatic, ChannelHandlerContext ctx, Request request, Response response, HttpRequest nettyRequest, MessageEvent e) { Logger.trace("serveStatic: begin"); HttpResponse nettyResponse = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(response.status)); if (exposePlayServer) { nettyResponse.setHeader(SERVER, signature); } try { VirtualFile file = Play.getVirtualFile(renderStatic.file); if (file != null && file.exists() && file.isDirectory()) { file = file.child("index.html"); if (file != null) { renderStatic.file = file.relativePath(); } } if ((file == null || !file.exists())) { serve404( new NotFound("The file " + renderStatic.file + " does not exist"), ctx, request, nettyRequest); } else { boolean raw = false; for (PlayPlugin plugin : Play.plugins) { if (plugin.serveStatic(file, Request.current(), Response.current())) { raw = true; break; } } if (raw) { copyResponse(ctx, request, response, nettyRequest); } else { final File localFile = file.getRealFile(); final boolean keepAlive = isKeepAlive(nettyRequest); nettyResponse = addEtag(nettyRequest, nettyResponse, localFile); if (nettyResponse.getStatus().equals(HttpResponseStatus.NOT_MODIFIED)) { Channel ch = e.getChannel(); // Write the initial line and the header. ChannelFuture writeFuture = ch.write(nettyResponse); if (!keepAlive) { // Write the content. writeFuture.addListener(ChannelFutureListener.CLOSE); } } else { final RandomAccessFile raf = new RandomAccessFile(localFile, "r"); try { long fileLength = raf.length(); Logger.trace("keep alive " + keepAlive); Logger.trace( "content type " + (MimeTypes.getContentType(localFile.getName(), "text/plain"))); if (keepAlive && !nettyResponse.getStatus().equals(HttpResponseStatus.NOT_MODIFIED)) { // Add 'Content-Length' header only for a keep-alive connection. Logger.trace("file length " + fileLength); setContentLength(nettyResponse, fileLength); } nettyResponse.setHeader( CONTENT_TYPE, (MimeTypes.getContentType(localFile.getName(), "text/plain"))); Channel ch = e.getChannel(); // Write the initial line and the header. ChannelFuture writeFuture = ch.write(nettyResponse); // Write the content. if (!nettyRequest.getMethod().equals(HttpMethod.HEAD)) { writeFuture = ch.write(new ChunkedFile(raf, 0, fileLength, 8192)); } else { raf.close(); } if (!keepAlive) { // Close the connection when the whole content is written out. writeFuture.addListener(ChannelFutureListener.CLOSE); } } catch (Throwable exx) { try { raf.close(); } catch (Throwable ex) { /* Left empty */ } try { ctx.getChannel().close(); } catch (Throwable ex) { /* Left empty */ } } } } } } catch (Throwable ez) { Logger.error(ez, "serveStatic for request %s", request.method + " " + request.url); try { HttpResponse errorResponse = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR); ChannelBuffer buf = ChannelBuffers.copiedBuffer("Internal Error (check logs)".getBytes("utf-8")); errorResponse.setContent(buf); ChannelFuture future = ctx.getChannel().write(errorResponse); future.addListener(ChannelFutureListener.CLOSE); } catch (Exception ex) { Logger.error(ez, "serveStatic for request %s", request.method + " " + request.url); } } Logger.trace("serveStatic: end"); }
public Request parseRequest(ChannelHandlerContext ctx, HttpRequest nettyRequest) throws Exception { Logger.trace("parseRequest: begin"); Logger.trace("parseRequest: URI = " + nettyRequest.getUri()); int index = nettyRequest.getUri().indexOf("?"); String querystring = ""; String uri = nettyRequest.getUri(); // Remove domain and port from URI if it's present. if (uri.startsWith("http://") || uri.startsWith("https://")) { // Begins searching / after 9th character (last / of https://) uri = uri.substring(uri.indexOf("/", 9)); } String path = URLDecoder.decode(uri, "UTF-8"); if (index != -1) { path = URLDecoder.decode(uri.substring(0, index), "UTF-8"); querystring = uri.substring(index + 1); } final Request request = new Request(); request.remoteAddress = getRemoteIPAddress(ctx); request.method = nettyRequest.getMethod().getName(); request.path = path; request.querystring = querystring; final String contentType = nettyRequest.getHeader(CONTENT_TYPE); if (contentType != null) { request.contentType = contentType.split(";")[0].trim().toLowerCase(); } else { request.contentType = "text/html"; } if (nettyRequest.getHeader("X-HTTP-Method-Override") != null) { request.method = nettyRequest.getHeader("X-HTTP-Method-Override").intern(); } ChannelBuffer b = nettyRequest.getContent(); if (b instanceof FileChannelBuffer) { FileChannelBuffer buffer = (FileChannelBuffer) b; // An error occurred Integer max = Integer.valueOf(Play.configuration.getProperty("play.netty.maxContentLength", "-1")); request.body = buffer.getInputStream(); if (!(max == -1 || request.body.available() < max)) { request.body = new ByteArrayInputStream(new byte[0]); } } else { ByteArrayOutputStream out = new ByteArrayOutputStream(); IOUtils.copy(new ChannelBufferInputStream(b), out); byte[] n = out.toByteArray(); request.body = new ByteArrayInputStream(n); } request.url = uri; request.host = nettyRequest.getHeader(HOST); request.isLoopback = ((InetSocketAddress) ctx.getChannel().getRemoteAddress()).getAddress().isLoopbackAddress() && request.host.matches("^127\\.0\\.0\\.1:?[0-9]*$"); if (request.host == null) { request.host = ""; request.port = 80; request.domain = ""; } else { if (request.host.contains(":")) { final String[] host = request.host.split(":"); request.port = Integer.parseInt(host[1]); request.domain = host[0]; } else { request.port = 80; request.domain = request.host; } } if (Play.configuration.containsKey("XForwardedSupport") && nettyRequest.getHeader("X-Forwarded-For") != null) { if (!Arrays.asList( Play.configuration.getProperty("XForwardedSupport", "127.0.0.1").split(",")) .contains(request.remoteAddress)) { throw new RuntimeException( "This proxy request is not authorized: " + request.remoteAddress); } else { request.secure = ("https".equals(Play.configuration.get("XForwardedProto")) || "https".equals(nettyRequest.getHeader("X-Forwarded-Proto")) || "on".equals(nettyRequest.getHeader("X-Forwarded-Ssl"))); if (Play.configuration.containsKey("XForwardedHost")) { request.host = (String) Play.configuration.get("XForwardedHost"); } else if (nettyRequest.getHeader("X-Forwarded-Host") != null) { request.host = nettyRequest.getHeader("X-Forwarded-Host"); } if (nettyRequest.getHeader("X-Forwarded-For") != null) { request.remoteAddress = nettyRequest.getHeader("X-Forwarded-For"); } } } addToRequest(nettyRequest, request); request.resolveFormat(); request._init(); Logger.trace("parseRequest: end"); return request; }
public void copyResponse( ChannelHandlerContext ctx, Request request, Response response, HttpRequest nettyRequest) throws Exception { Logger.trace("copyResponse: begin"); // response.out.flush(); // Decide whether to close the connection or not. HttpResponse nettyResponse = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(response.status)); if (exposePlayServer) { nettyResponse.setHeader(SERVER, signature); } if (response.contentType != null) { nettyResponse.setHeader( CONTENT_TYPE, response.contentType + (response.contentType.startsWith("text/") && !response.contentType.contains("charset") ? "; charset=utf-8" : "")); } else { nettyResponse.setHeader(CONTENT_TYPE, "text/plain; charset=utf-8"); } addToResponse(response, nettyResponse); final Object obj = response.direct; File file = null; ChunkedInput stream = null; InputStream is = null; if (obj instanceof File) { file = (File) obj; } else if (obj instanceof InputStream) { is = (InputStream) obj; } else if (obj instanceof ChunkedInput) { stream = (ChunkedInput) obj; } final boolean keepAlive = isKeepAlive(nettyRequest); if (file != null && file.isFile()) { try { nettyResponse = addEtag(nettyRequest, nettyResponse, file); if (nettyResponse.getStatus().equals(HttpResponseStatus.NOT_MODIFIED)) { Channel ch = ctx.getChannel(); // Write the initial line and the header. ChannelFuture writeFuture = ch.write(nettyResponse); if (!keepAlive) { // Close the connection when the whole content is written out. writeFuture.addListener(ChannelFutureListener.CLOSE); } } else { nettyResponse.setHeader( CONTENT_TYPE, MimeTypes.getContentType(file.getName(), "text/plain")); final RandomAccessFile raf = new RandomAccessFile(file, "r"); try { long fileLength = raf.length(); if (keepAlive) { // Add 'Content-Length' header only for a keep-alive connection. Logger.trace("file length is [" + fileLength + "]"); setContentLength(nettyResponse, fileLength); } Channel ch = ctx.getChannel(); // Write the initial line and the header. ChannelFuture writeFuture = ch.write(nettyResponse); // Write the content. // If it is not a HEAD if (!nettyRequest.getMethod().equals(HttpMethod.HEAD)) { writeFuture = ch.write(new ChunkedFile(raf, 0, fileLength, 8192)); } else { raf.close(); } if (!keepAlive) { // Close the connection when the whole content is written out. writeFuture.addListener(ChannelFutureListener.CLOSE); } } catch (Throwable exx) { try { raf.close(); } catch (Throwable ex) { /* Left empty */ } try { ctx.getChannel().close(); } catch (Throwable ex) { /* Left empty */ } } } } catch (Exception e) { throw e; } } else if (is != null) { ChannelFuture writeFuture = ctx.getChannel().write(nettyResponse); if (!nettyRequest.getMethod().equals(HttpMethod.HEAD) && !nettyResponse.getStatus().equals(HttpResponseStatus.NOT_MODIFIED)) { writeFuture = ctx.getChannel().write(new ChunkedStream(is)); } else { is.close(); } if (!keepAlive) { writeFuture.addListener(ChannelFutureListener.CLOSE); } } else if (stream != null) { ChannelFuture writeFuture = ctx.getChannel().write(nettyResponse); if (!nettyRequest.getMethod().equals(HttpMethod.HEAD) && !nettyResponse.getStatus().equals(HttpResponseStatus.NOT_MODIFIED)) { writeFuture = ctx.getChannel().write(stream); } else { stream.close(); } if (!keepAlive) { writeFuture.addListener(ChannelFutureListener.CLOSE); } } else { writeResponse(ctx, response, nettyResponse, nettyRequest); } Logger.trace("copyResponse: end"); }
@Override public void populateCamelHeaders( HttpRequest request, Map<String, Object> headers, Exchange exchange, NettyHttpConfiguration configuration) throws Exception { LOG.trace("populateCamelHeaders: {}", request); // NOTE: these headers is applied using the same logic as camel-http/camel-jetty to be // consistent headers.put(Exchange.HTTP_METHOD, request.getMethod().getName()); // strip query parameters from the uri String s = request.getUri(); if (s.contains("?")) { s = ObjectHelper.before(s, "?"); } // we want the full path for the url, as the client may provide the url in the HTTP headers as // absolute or relative, eg // /foo // http://servername/foo String http = configuration.isSsl() ? "https://" : "http://"; if (!s.startsWith(http)) { if (configuration.getPort() != 80) { s = http + configuration.getHost() + ":" + configuration.getPort() + s; } else { s = http + configuration.getHost() + s; } } headers.put(Exchange.HTTP_URL, s); // uri is without the host and port URI uri = new URI(request.getUri()); // uri is path and query parameters headers.put(Exchange.HTTP_URI, uri.getPath()); headers.put(Exchange.HTTP_QUERY, uri.getQuery()); headers.put(Exchange.HTTP_RAW_QUERY, uri.getRawQuery()); // strip the starting endpoint path so the path is relative to the endpoint uri String path = uri.getPath(); if (configuration.getPath() != null && path.startsWith(configuration.getPath())) { path = path.substring(configuration.getPath().length()); } headers.put(Exchange.HTTP_PATH, path); if (LOG.isTraceEnabled()) { LOG.trace("HTTP-Method {}", request.getMethod().getName()); LOG.trace("HTTP-Uri {}", request.getUri()); } for (String name : request.headers().names()) { // mapping the content-type if (name.toLowerCase(Locale.US).equals("content-type")) { name = Exchange.CONTENT_TYPE; } if (name.toLowerCase(Locale.US).equals("authorization")) { String value = request.headers().get(name); // store a special header that this request was authenticated using HTTP Basic if (value != null && value.trim().startsWith("Basic")) { if (headerFilterStrategy != null && !headerFilterStrategy.applyFilterToExternalHeaders( NettyHttpConstants.HTTP_AUTHENTICATION, "Basic", exchange)) { NettyHttpHelper.appendHeader(headers, NettyHttpConstants.HTTP_AUTHENTICATION, "Basic"); } } } // add the headers one by one, and use the header filter strategy List<String> values = request.headers().getAll(name); Iterator<?> it = ObjectHelper.createIterator(values); while (it.hasNext()) { Object extracted = it.next(); Object decoded = shouldUrlDecodeHeader(configuration, name, extracted, "UTF-8"); LOG.trace("HTTP-header: {}", extracted); if (headerFilterStrategy != null && !headerFilterStrategy.applyFilterToExternalHeaders(name, decoded, exchange)) { NettyHttpHelper.appendHeader(headers, name, decoded); } } } // add uri parameters as headers to the Camel message if (request.getUri().contains("?")) { String query = ObjectHelper.after(request.getUri(), "?"); Map<String, Object> uriParameters = URISupport.parseQuery(query, false, true); for (Map.Entry<String, Object> entry : uriParameters.entrySet()) { String name = entry.getKey(); Object values = entry.getValue(); Iterator<?> it = ObjectHelper.createIterator(values); while (it.hasNext()) { Object extracted = it.next(); Object decoded = shouldUrlDecodeHeader(configuration, name, extracted, "UTF-8"); LOG.trace("URI-Parameter: {}", extracted); if (headerFilterStrategy != null && !headerFilterStrategy.applyFilterToExternalHeaders(name, decoded, exchange)) { NettyHttpHelper.appendHeader(headers, name, decoded); } } } } // if body is application/x-www-form-urlencoded then extract the body as query string and append // as headers // if it is a bridgeEndpoint we need to skip this part of work if (request.getMethod().getName().equals("POST") && request.headers().get(Exchange.CONTENT_TYPE) != null && request .headers() .get(Exchange.CONTENT_TYPE) .startsWith(NettyHttpConstants.CONTENT_TYPE_WWW_FORM_URLENCODED) && !configuration.isBridgeEndpoint()) { String charset = "UTF-8"; // Push POST form params into the headers to retain compatibility with DefaultHttpBinding String body = request.getContent().toString(Charset.forName(charset)); if (ObjectHelper.isNotEmpty(body)) { for (String param : body.split("&")) { String[] pair = param.split("=", 2); if (pair.length == 2) { String name = shouldUrlDecodeHeader(configuration, "", pair[0], charset); String value = shouldUrlDecodeHeader(configuration, name, pair[1], charset); if (headerFilterStrategy != null && !headerFilterStrategy.applyFilterToExternalHeaders(name, value, exchange)) { NettyHttpHelper.appendHeader(headers, name, value); } } else { throw new IllegalArgumentException( "Invalid parameter, expected to be a pair but was " + param); } } } } }
@Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { HttpRequest request = (HttpRequest) e.getMessage(); if (request.getMethod() != GET) { sendError(ctx, METHOD_NOT_ALLOWED); return; } // Parsing the URL into key-values final Map<String, List<String>> params = new QueryStringDecoder(request.getUri()).getParameters(); final List<String> types = params.get("type"); final List<String> taskIdList = params.get("ta"); final List<String> subQueryIds = params.get("sid"); final List<String> partitionIds = params.get("p"); if (types == null || taskIdList == null || subQueryIds == null || partitionIds == null) { sendError(ctx, "Required type, taskIds, subquery Id, and partition id", BAD_REQUEST); return; } if (types.size() != 1 || subQueryIds.size() != 1) { sendError(ctx, "Required type, taskIds, subquery Id, and partition id", BAD_REQUEST); return; } final List<FileChunk> chunks = Lists.newArrayList(); String repartitionType = types.get(0); String sid = subQueryIds.get(0); String partitionId = partitionIds.get(0); List<String> taskIds = splitMaps(taskIdList); // the working dir of tajo worker for each query String queryBaseDir = queryId + "/output" + "/"; LOG.info( "PullServer request param: repartitionType=" + repartitionType + ", sid=" + sid + ", partitionId=" + partitionId + ", taskIds=" + taskIdList); String taskLocalDir = conf.get(ConfVars.WORKER_TEMPORAL_DIR.varname); if (taskLocalDir == null || taskLocalDir.equals("")) { LOG.error("Tajo local directory should be specified."); } LOG.info("PullServer baseDir: " + taskLocalDir + "/" + queryBaseDir); // if a subquery requires a range partitioning if (repartitionType.equals("r")) { String ta = taskIds.get(0); Path path = localFS.makeQualified( lDirAlloc.getLocalPathToRead( queryBaseDir + "/" + sid + "/" + ta + "/output/", conf)); String startKey = params.get("start").get(0); String endKey = params.get("end").get(0); boolean last = params.get("final") != null; FileChunk chunk; try { chunk = getFileCunks(path, startKey, endKey, last); } catch (Throwable t) { LOG.error("ERROR Request: " + request.getUri(), t); sendError(ctx, "Cannot get file chunks to be sent", BAD_REQUEST); return; } if (chunk != null) { chunks.add(chunk); } // if a subquery requires a hash repartition } else if (repartitionType.equals("h")) { for (String ta : taskIds) { Path path = localFS.makeQualified( lDirAlloc.getLocalPathToRead( queryBaseDir + "/" + sid + "/" + ta + "/output/" + partitionId, conf)); File file = new File(path.toUri()); FileChunk chunk = new FileChunk(file, 0, file.length()); chunks.add(chunk); } } else { LOG.error("Unknown repartition type: " + repartitionType); return; } // Write the content. Channel ch = e.getChannel(); if (chunks.size() == 0) { HttpResponse response = new DefaultHttpResponse(HTTP_1_1, NO_CONTENT); ch.write(response); if (!isKeepAlive(request)) { ch.close(); } } else { FileChunk[] file = chunks.toArray(new FileChunk[chunks.size()]); HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); long totalSize = 0; for (FileChunk chunk : file) { totalSize += chunk.length(); } setContentLength(response, totalSize); // Write the initial line and the header. ch.write(response); ChannelFuture writeFuture = null; for (FileChunk chunk : file) { writeFuture = sendFile(ctx, ch, chunk); if (writeFuture == null) { sendError(ctx, NOT_FOUND); return; } } // Decide whether to close the connection or not. if (!isKeepAlive(request)) { // Close the connection when the whole content is written out. writeFuture.addListener(ChannelFutureListener.CLOSE); } } }
@Override public boolean match(HttpRequest request) { return method.equals(request.getMethod()); }
@Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { HttpRequest request = (HttpRequest) e.getMessage(); if (request.getMethod() != GET) { sendError(ctx, METHOD_NOT_ALLOWED); return; } String base = ContainerLocalizer.USERCACHE + "/" + userName + "/" + ContainerLocalizer.APPCACHE + "/" + appId + "/output" + "/"; final Map<String, List<String>> params = new QueryStringDecoder(request.getUri()).getParameters(); List<FileChunk> chunks = Lists.newArrayList(); List<String> taskIds = splitMaps(params.get("ta")); int sid = Integer.valueOf(params.get("sid").get(0)); int partitionId = Integer.valueOf(params.get("p").get(0)); for (String ta : taskIds) { File file = new File(base + "/" + sid + "/" + ta + "/output/" + partitionId); FileChunk chunk = new FileChunk(file, 0, file.length()); chunks.add(chunk); } FileChunk[] file = chunks.toArray(new FileChunk[chunks.size()]); // try { // file = retriever.handle(ctx, request); // } catch (FileNotFoundException fnf) { // LOG.error(fnf); // sendError(ctx, NOT_FOUND); // return; // } catch (IllegalArgumentException iae) { // LOG.error(iae); // sendError(ctx, BAD_REQUEST); // return; // } catch (FileAccessForbiddenException fafe) { // LOG.error(fafe); // sendError(ctx, FORBIDDEN); // return; // } catch (IOException ioe) { // LOG.error(ioe); // sendError(ctx, INTERNAL_SERVER_ERROR); // return; // } // Write the content. Channel ch = e.getChannel(); if (file == null) { HttpResponse response = new DefaultHttpResponse(HTTP_1_1, NO_CONTENT); ch.write(response); if (!isKeepAlive(request)) { ch.close(); } } else { HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); long totalSize = 0; for (FileChunk chunk : file) { totalSize += chunk.length(); } setContentLength(response, totalSize); // Write the initial line and the header. ch.write(response); ChannelFuture writeFuture = null; for (FileChunk chunk : file) { writeFuture = sendFile(ctx, ch, chunk); if (writeFuture == null) { sendError(ctx, NOT_FOUND); return; } } // Decide whether to close the connection or not. if (!isKeepAlive(request)) { // Close the connection when the whole content is written out. writeFuture.addListener(ChannelFutureListener.CLOSE); } } }