@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); }
public Deferred<HttpResponse> process(ChannelHandlerContext context, HttpRequest request) { HttpResponse response = new DefaultHttpResponse(request.getProtocolVersion(), HttpResponseStatus.OK); response.setHeader("content-type", "text/html"); response.setContent( ChannelBuffers.copiedBuffer("Accepted ShutDown Request", Charset.defaultCharset())); Deferred<HttpResponse> deferred = new Deferred<HttpResponse>(); deferred.callback(response); shutdown(); super.doShutdown(context.getChannel()); return deferred; }
private void sendHttpResponse(Channel channel, HttpRequest request, HttpResponse response) { if (!channel.isOpen()) { return; } // response的内容已在各Listener中填充 response.headers().set(Names.CONTENT_LENGTH, response.getContent().readableBytes()); response.headers().set(Names.SERVER, "NAVI/1.1.4(UNIX)"); if (!HttpHeaders.isKeepAlive(request) || response.getStatus() != HttpResponseStatus.OK || ServerConfigure.isChannelClose()) { response.headers().set(Names.CONNECTION, "close"); channel.setAttachment(WRITING); ChannelFuture f = channel.write(response); f.addListener(ChannelFutureListener.CLOSE); f.addListener( new ChannelFutureListener() { public void operationComplete(ChannelFuture f) throws Exception { if (!f.isSuccess()) { log.error(f.getCause().getMessage(), f.getCause()); } } }); } else { if (request.getProtocolVersion() == HttpVersion.HTTP_1_0) { response.headers().add(Names.CONNECTION, "Keep-Alive"); } channel.setAttachment(WRITING); ChannelFuture f = channel.write(response); f.addListener(ChannelFutureListener.CLOSE_ON_FAILURE); f.addListener( new ChannelFutureListener() { public void operationComplete(ChannelFuture f) throws Exception { if (!f.isSuccess()) { log.error(f.getCause().getMessage(), f.getCause()); } } }); } }
private void writeResponse( ChannelHandlerContext ctx, MessageEvent e, RequestV2 request, InetAddress ia) { // Decide whether to close the connection or not. boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase( nettyRequest.headers().get(HttpHeaders.Names.CONNECTION)) || nettyRequest.getProtocolVersion().equals(HttpVersion.HTTP_1_0) && !HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase( nettyRequest.headers().get(HttpHeaders.Names.CONNECTION)); // Build the response object. HttpResponse response; if (request.getLowRange() != 0 || request.getHighRange() != 0) { response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.PARTIAL_CONTENT); } else { String soapAction = nettyRequest.headers().get("SOAPACTION"); if (soapAction != null && soapAction.contains("X_GetFeatureList")) { LOGGER.debug("Invalid action in SOAPACTION: " + soapAction); response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR); } else { response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); } } StartStopListenerDelegate startStopListenerDelegate = new StartStopListenerDelegate(ia.getHostAddress()); // Attach it to the context so it can be invoked if connection is reset unexpectedly ctx.setAttachment(startStopListenerDelegate); try { request.answer(response, e, close, startStopListenerDelegate); } catch (IOException e1) { LOGGER.trace("HTTP request V2 IO error: " + e1.getMessage()); // note: we don't call stop() here in a finally block as // answer() is non-blocking. we only (may) need to call it // here in the case of an exception. it's a no-op if it's // already been called startStopListenerDelegate.stop(); } }
@Override public void handle(HttpRequest request, Channel channel) throws Exception { // 设置调用方ip,X-Forwarded-For 是使用了代理(如nginx)会附加在HTTP头域上的 if (request.headers().contains("X-Forwarded-For")) { request.headers().set(Names.HOST, request.headers().get("X-Forwarded-For")); } else { InetSocketAddress insocket = (InetSocketAddress) channel.getRemoteAddress(); request.headers().set(Names.HOST, insocket.getAddress().getHostAddress()); } HttpResponse response = new NaviHttpResponse(request.getProtocolVersion(), HttpResponseStatus.OK); for (INaviHttpRequestListener listener : listeners) { boolean res = listener.process(request, response); log.debug(listener.getClass().getName() + " is completed!"); if (!res) { break; } } sendHttpResponse(channel, request, response); }
@Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (e.getMessage() instanceof HttpRequest && HttpMethod.GET.equals(((HttpRequest) e.getMessage()).getMethod())) { HttpRequest request = (HttpRequest) e.getMessage(); HttpResponse response = new DefaultHttpResponse(request.getProtocolVersion(), HttpResponseStatus.OK); String resp = ""; for (Component c : Component.values()) { resp += String.format( "name=%-20.20s enabled=%-10.10s local=%-10.10s initialized=%-10.10s\n", c.name(), c.isEnabled(), c.isLocal(), c.isInitialized()); } ChannelBuffer buf = ChannelBuffers.copiedBuffer(resp.getBytes()); response.setContent(buf); response.addHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(buf.readableBytes())); response.addHeader(HttpHeaders.Names.CONTENT_TYPE, "text/plain; charset=UTF-8"); ChannelFuture writeFuture = ctx.getChannel().write(response); writeFuture.addListener(ChannelFutureListener.CLOSE); } else { ctx.sendUpstream(e); } }
@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); } }
/** 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); }
@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 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); }