Example usage for io.netty.handler.stream ChunkedStream ChunkedStream

List of usage examples for io.netty.handler.stream ChunkedStream ChunkedStream

Introduction

In this page you can find the example usage for io.netty.handler.stream ChunkedStream ChunkedStream.

Prototype

public ChunkedStream(InputStream in, int chunkSize) 

Source Link

Document

Creates a new instance that fetches data from the specified stream.

Usage

From source file:com.corundumstudio.socketio.handler.ResourceHandler.java

License:Apache License

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    if (msg instanceof FullHttpRequest) {
        FullHttpRequest req = (FullHttpRequest) msg;
        QueryStringDecoder queryDecoder = new QueryStringDecoder(req.getUri());
        URL resUrl = resources.get(queryDecoder.path());
        if (resUrl != null) {
            URLConnection fileUrl = resUrl.openConnection();
            long lastModified = fileUrl.getLastModified();
            // check if file has been modified since last request
            if (isNotModified(req, lastModified)) {
                sendNotModified(ctx);/*from   w w w  .jav a  2 s.c  o m*/
                req.release();
                return;
            }
            // create resource input-stream and check existence
            final InputStream is = fileUrl.getInputStream();
            if (is == null) {
                sendError(ctx, NOT_FOUND);
                return;
            }
            // create ok response
            HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.OK);
            // set Content-Length header
            setContentLength(res, fileUrl.getContentLength());
            // set Content-Type header
            setContentTypeHeader(res, fileUrl);
            // set Date, Expires, Cache-Control and Last-Modified headers
            setDateAndCacheHeaders(res, lastModified);
            // write initial response header
            ctx.write(res);

            // write the content stream
            ctx.pipeline().addBefore(SocketIOChannelInitializer.RESOURCE_HANDLER, "chunkedWriter",
                    new ChunkedWriteHandler());
            ChannelFuture writeFuture = ctx.channel().write(new ChunkedStream(is, fileUrl.getContentLength()));
            // add operation complete listener so we can close the channel and the input stream
            writeFuture.addListener(ChannelFutureListener.CLOSE);
            return;
        }
    }
    ctx.fireChannelRead(msg);
}

From source file:gribbit.http.response.InputStreamResponse.java

License:Open Source License

@Override
public void writeResponse(ChannelHandlerContext ctx) {
    isChunked = true;//from w w w  .j  a va 2s .c  o  m
    sendHeaders(ctx);

    if (!request.isHEADRequest()) {
        ctx.write(new HttpChunkedInput(new ChunkedStream(contentStream, 8192)));
    }
    ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
}

From source file:io.scalecube.socketio.pipeline.ResourceHandler.java

License:Apache License

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    // ?/* w ww. j a v  a 2s.c  o m*/
    if (msg instanceof HttpRequest) {
        HttpRequest req = (HttpRequest) msg;
        QueryStringDecoder queryDecoder = new QueryStringDecoder(req.getUri());
        String requestPath = queryDecoder.path();
        URL resUrl = resources.get(requestPath);
        if (resUrl != null) {
            if (log.isDebugEnabled())
                log.debug("Received HTTP resource request: {} {} from channel: {}", req.getMethod(),
                        requestPath, ctx.channel());

            URLConnection fileUrl = resUrl.openConnection();
            long lastModified = fileUrl.getLastModified();
            // check if file has been modified since last request
            if (isNotModified(req, lastModified)) {
                sendNotModified(ctx);
                return;
            }
            // create resource input-stream and check existence
            final InputStream is = fileUrl.getInputStream();
            if (is == null) {
                sendError(ctx, HttpResponseStatus.NOT_FOUND);
                return;
            }
            // create ok response
            HttpResponse res = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
            // set Content-Length header
            HttpHeaders.setContentLength(res, fileUrl.getContentLengthLong());
            // set Content-Type header
            setContentTypeHeader(res, fileUrl);
            // set Date, Expires, Cache-Control and Last-Modified headers
            setDateAndCacheHeaders(res, lastModified);
            // write initial response header
            ctx.write(res);

            // write the content stream
            ctx.pipeline().addBefore(ctx.name(), "chunked-writer-handler", new ChunkedWriteHandler());
            ChannelFuture writeFuture = ctx.writeAndFlush(new ChunkedStream(is, fileUrl.getContentLength()));
            // add operation complete listener so we can close the channel and the input stream
            writeFuture.addListener(ChannelFutureListener.CLOSE);
            ReferenceCountUtil.release(msg);
            return;
        }
    }
    super.channelRead(ctx, msg);
}

From source file:io.werval.server.netty.WervalHttpHandler.java

License:Apache License

private ChannelFuture writeOutcome(ChannelHandlerContext nettyContext, Outcome outcome) {
    // == Build the Netty Response
    ResponseHeader responseHeader = outcome.responseHeader();

    // Netty Version & Status
    HttpVersion responseVersion = HttpVersion.valueOf(responseHeader.version().toString());
    HttpResponseStatus responseStatus = HttpResponseStatus.valueOf(responseHeader.status().code());

    // Netty Headers & Body output
    final HttpResponse nettyResponse;
    final ChannelFuture writeFuture;
    if (outcome instanceof ChunkedInputOutcome) {
        ChunkedInputOutcome chunkedOutcome = (ChunkedInputOutcome) outcome;
        nettyResponse = new DefaultHttpResponse(responseVersion, responseStatus);
        // Headers
        applyResponseHeader(responseHeader, nettyResponse);
        nettyResponse.headers().set(TRANSFER_ENCODING, CHUNKED);
        nettyResponse.headers().set(TRAILER, X_WERVAL_CONTENT_LENGTH);
        // Body/*from www  .  j  av  a 2  s  . c o  m*/
        nettyContext.write(nettyResponse);
        writeFuture = nettyContext.writeAndFlush(new HttpChunkedBodyEncoder(
                new ChunkedStream(chunkedOutcome.inputStream(), chunkedOutcome.chunkSize())));
    } else if (outcome instanceof InputStreamOutcome) {
        InputStreamOutcome streamOutcome = (InputStreamOutcome) outcome;
        nettyResponse = new DefaultFullHttpResponse(responseVersion, responseStatus);
        // Headers
        applyResponseHeader(responseHeader, nettyResponse);
        nettyResponse.headers().set(CONTENT_LENGTH, streamOutcome.contentLength());
        // Body
        try (InputStream bodyInputStream = streamOutcome.bodyInputStream()) {
            ((ByteBufHolder) nettyResponse).content().writeBytes(bodyInputStream,
                    new BigDecimal(streamOutcome.contentLength()).intValueExact());
        } catch (IOException ex) {
            throw new UncheckedIOException(ex);
        }
        writeFuture = nettyContext.writeAndFlush(nettyResponse);
    } else if (outcome instanceof SimpleOutcome) {
        SimpleOutcome simpleOutcome = (SimpleOutcome) outcome;
        byte[] body = simpleOutcome.body().asBytes();
        nettyResponse = new DefaultFullHttpResponse(responseVersion, responseStatus);
        // Headers
        applyResponseHeader(responseHeader, nettyResponse);
        nettyResponse.headers().set(CONTENT_LENGTH, body.length);
        // Body
        ((ByteBufHolder) nettyResponse).content().writeBytes(body);
        writeFuture = nettyContext.writeAndFlush(nettyResponse);
    } else {
        LOG.warn("{} Unhandled Outcome type '{}', no response body.", requestIdentity, outcome.getClass());
        nettyResponse = new DefaultFullHttpResponse(responseVersion, responseStatus);
        applyResponseHeader(responseHeader, nettyResponse);
        writeFuture = nettyContext.writeAndFlush(nettyResponse);
    }

    if (LOG.isTraceEnabled()) {
        LOG.trace("{} Sent a HttpResponse:\n{}", requestIdentity, nettyResponse.toString());
    }

    // Close the connection as soon as the response is sent if not keep alive
    if (!outcome.responseHeader().isKeepAlive() || nettyContext.executor().isShuttingDown()) {
        writeFuture.addListener(ChannelFutureListener.CLOSE);
    }

    // Done!
    return writeFuture;
}

From source file:net.pms.network.RequestV2.java

License:Open Source License

/**
 * Construct a proper HTTP response to a received request. After the response has been
 * created, it is sent and the resulting {@link ChannelFuture} object is returned.
 * See <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html">RFC-2616</a>
 * for HTTP header field definitions./* w  ww.  ja v a 2  s.c o  m*/
 *
 * @param ctx
 * @param output The {@link HttpResponse} object that will be used to construct the response.
 * @param e The {@link io.netty.handler.codec.http.FullHttpRequest} object used to communicate with the client that sent
 *          the request.
 * @param close Set to true to close the channel after sending the response. By default the
 *          channel is not closed after sending.
 * @param startStopListenerDelegate The {@link StartStopListenerDelegate} object that is used
 *          to notify plugins that the {@link DLNAResource} is about to start playing.
 * @return The {@link ChannelFuture} object via which the response was sent.
 * @throws IOException
 */
public ChannelFuture answer(final ChannelHandlerContext ctx, HttpResponse output, FullHttpRequest e,
        final boolean close, final StartStopListenerDelegate startStopListenerDelegate) throws IOException {
    ChannelFuture future = null;
    long CLoverride = -2; // 0 and above are valid Content-Length values, -1 means omit
    StringBuilder response = new StringBuilder();
    DLNAResource dlna = null;
    boolean xbox360 = mediaRenderer.isXbox360();

    // Samsung 2012 TVs have a problematic preceding slash that needs to be removed.
    if (argument.startsWith("/")) {
        LOGGER.trace("Stripping preceding slash from: " + argument);
        argument = argument.substring(1);
    }

    if ((method.equals("GET") || method.equals("HEAD")) && argument.startsWith("console/")) {
        // Request to output a page to the HTML console.
        output.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/html");
        response.append(HTMLConsole.servePage(argument.substring(8)));
    } else if ((method.equals("GET") || method.equals("HEAD")) && argument.startsWith("get/")) {
        // Request to retrieve a file

        /**
         * Skip the leading "get/"
         * e.g. "get/0$1$5$3$4/Foo.mp4" -> "0$1$5$3$4/Foo.mp4"
         *
         * ExSport: I spotted on Android it is asking for "/get/0$2$4$2$1$3" which generates exception with response:
         * "Http: Response, HTTP/1.1, Status: Internal server error, URL: /get/0$2$4$2$1$3"
         * This should fix it
         */

        // Note: we intentionally include the trailing filename here because it may
        // be used to reconstruct lost Temp items.
        String id = argument.substring(argument.indexOf("get/") + 4);

        // Some clients escape the separators in their request: unescape them.
        id = id.replace("%24", "$");

        // Retrieve the DLNAresource itself.
        dlna = PMS.get().getRootFolder(mediaRenderer).getDLNAResource(id, mediaRenderer);
        String fileName = id.substring(id.indexOf('/') + 1);

        if (transferMode != null) {
            output.headers().set("TransferMode.DLNA.ORG", transferMode);
        }

        if (dlna != null && dlna.isFolder() && !fileName.startsWith("thumbnail0000")) {
            // if we found a folder we MUST be asked for thumbnails
            // otherwise this is not allowed
            dlna = null;
        }

        if (dlna != null) {
            // DLNAresource was found.

            if (fileName.startsWith("thumbnail0000")) {
                // This is a request for a thumbnail file.
                output.headers().set(HttpHeaders.Names.CONTENT_TYPE, dlna.getThumbnailContentType());
                output.headers().set(HttpHeaders.Names.ACCEPT_RANGES, "bytes");
                output.headers().set(HttpHeaders.Names.EXPIRES, getFUTUREDATE() + " GMT");
                output.headers().set(HttpHeaders.Names.CONNECTION, "keep-alive");

                if (!configuration.isShowCodeThumbs() && !dlna.isCodeValid(dlna)) {
                    inputStream = dlna.getGenericThumbnailInputStream(null);
                } else {
                    if (mediaRenderer.isMediaParserV2()) {
                        dlna.checkThumbnail();
                    }
                    inputStream = dlna.getThumbnailInputStream();
                }
                inputStream = UMSUtils.scaleThumb(inputStream, mediaRenderer);
            } else if (dlna.getMedia() != null && fileName.contains("subtitle0000") && dlna.isCodeValid(dlna)) {
                // This is a request for a subtitle file
                output.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/plain");
                output.headers().set(HttpHeaders.Names.EXPIRES, getFUTUREDATE() + " GMT");
                DLNAMediaSubtitle sub = dlna.getMediaSubtitle();
                if (sub != null) {
                    try {
                        // XXX external file is null if the first subtitle track is embedded:
                        // http://www.ps3mediaserver.org/forum/viewtopic.php?f=3&t=15805&p=75534#p75534
                        if (sub.isExternal()) {
                            inputStream = new FileInputStream(sub.getExternalFile());
                            LOGGER.trace("Loading external subtitles: " + sub);
                        } else {
                            LOGGER.trace(
                                    "Not loading external subtitles because they are not external: " + sub);
                        }
                    } catch (NullPointerException npe) {
                        LOGGER.trace("Not loading external subtitles because we could not find them at " + sub);
                    }
                } else {
                    LOGGER.trace("Not loading external subtitles because dlna.getMediaSubtitle returned null");
                }
            } else if (dlna.isCodeValid(dlna)) {
                // This is a request for a regular file.
                DLNAResource.Rendering origRendering = null;
                if (!mediaRenderer.equals(dlna.getDefaultRenderer())) {
                    // Adjust rendering details for this renderer
                    origRendering = dlna.updateRendering(mediaRenderer);
                }
                // If range has not been initialized yet and the DLNAResource has its
                // own start and end defined, initialize range with those values before
                // requesting the input stream.
                Range.Time splitRange = dlna.getSplitRange();

                if (range.getStart() == null && splitRange.getStart() != null) {
                    range.setStart(splitRange.getStart());
                }

                if (range.getEnd() == null && splitRange.getEnd() != null) {
                    range.setEnd(splitRange.getEnd());
                }

                long totalsize = dlna.length(mediaRenderer);
                boolean ignoreTranscodeByteRangeRequests = mediaRenderer.ignoreTranscodeByteRangeRequests();

                // Ignore ByteRangeRequests while media is transcoded
                if (!ignoreTranscodeByteRangeRequests || totalsize != DLNAMediaInfo.TRANS_SIZE
                        || (ignoreTranscodeByteRangeRequests && lowRange == 0
                                && totalsize == DLNAMediaInfo.TRANS_SIZE)) {
                    inputStream = dlna.getInputStream(
                            Range.create(lowRange, highRange, range.getStart(), range.getEnd()), mediaRenderer);
                    if (dlna.isResume()) {
                        // Update range to possibly adjusted resume time
                        range.setStart(dlna.getResume().getTimeOffset() / (double) 1000);
                    }
                }

                Format format = dlna.getFormat();
                if (format != null && format.isVideo()) {
                    if (dlna.getMedia() != null && !configuration.isDisableSubtitles()) {
                        // Some renderers (like Samsung devices) allow a custom header for a subtitle URL
                        String subtitleHttpHeader = mediaRenderer.getSubtitleHttpHeader();
                        if (subtitleHttpHeader != null && !"".equals(subtitleHttpHeader)) {
                            // Device allows a custom subtitle HTTP header; construct it
                            DLNAMediaSubtitle sub = dlna.getMediaSubtitle();
                            if (sub != null) {
                                String subtitleUrl;
                                String subExtension = sub.getType().getExtension();
                                if (isNotBlank(subExtension)) {
                                    subExtension = "." + subExtension;
                                }
                                subtitleUrl = "http://" + PMS.get().getServer().getHost() + ':'
                                        + PMS.get().getServer().getPort() + "/get/"
                                        + id.substring(0, id.indexOf('/')) + "/subtitle0000" + subExtension;

                                output.headers().set(subtitleHttpHeader, subtitleUrl);
                            } else {
                                LOGGER.trace(
                                        "Did not send subtitle headers because dlna.getMediaSubtitle returned null");
                            }
                        } else {
                            LOGGER.trace(
                                    "Did not send subtitle headers because mediaRenderer.getSubtitleHttpHeader returned either null or blank");
                        }
                    } else {
                        LOGGER.trace(
                                "Did not send subtitle headers because dlna.getMedia returned null or configuration.isDisableSubtitles was true");
                    }
                }

                String name = dlna.getDisplayName(mediaRenderer);
                if (dlna.isNoName()) {
                    name = dlna.getName() + " " + dlna.getDisplayName(mediaRenderer);
                }

                if (inputStream == null) {
                    if (!ignoreTranscodeByteRangeRequests) {
                        // No inputStream indicates that transcoding / remuxing probably crashed.
                        LOGGER.error("There is no inputstream to return for " + name);
                    }
                } else {
                    // Notify plugins that the DLNAresource is about to start playing
                    startStopListenerDelegate.start(dlna);

                    // Try to determine the content type of the file
                    String rendererMimeType = getRendererMimeType(dlna.mimeType(), mediaRenderer);

                    if (rendererMimeType != null && !"".equals(rendererMimeType)) {
                        output.headers().set(HttpHeaders.Names.CONTENT_TYPE, rendererMimeType);
                    }

                    // Response generation:
                    // We use -1 for arithmetic convenience but don't send it as a value.
                    // If Content-Length < 0 we omit it, for Content-Range we use '*' to signify unspecified.
                    boolean chunked = mediaRenderer.isChunkedTransfer();

                    // Determine the total size. Note: when transcoding the length is
                    // not known in advance, so DLNAMediaInfo.TRANS_SIZE will be returned instead.
                    if (chunked && totalsize == DLNAMediaInfo.TRANS_SIZE) {
                        // In chunked mode we try to avoid arbitrary values.
                        totalsize = -1;
                    }

                    long remaining = totalsize - lowRange;
                    long requested = highRange - lowRange;

                    if (requested != 0) {
                        // Determine the range (i.e. smaller of known or requested bytes)
                        long bytes = remaining > -1 ? remaining : inputStream.available();

                        if (requested > 0 && bytes > requested) {
                            bytes = requested + 1;
                        }

                        // Calculate the corresponding highRange (this is usually redundant).
                        highRange = lowRange + bytes - (bytes > 0 ? 1 : 0);

                        LOGGER.trace(
                                (chunked ? "Using chunked response. " : "") + "Sending " + bytes + " bytes.");

                        output.headers().set(HttpHeaders.Names.CONTENT_RANGE,
                                "bytes " + lowRange + "-" + (highRange > -1 ? highRange : "*") + "/"
                                        + (totalsize > -1 ? totalsize : "*"));

                        // Content-Length refers to the current chunk size here, though in chunked
                        // mode if the request is open-ended and totalsize is unknown we omit it.
                        if (chunked && requested < 0 && totalsize < 0) {
                            CLoverride = -1;
                        } else {
                            CLoverride = bytes;
                        }
                    } else {
                        // Content-Length refers to the total remaining size of the stream here.
                        CLoverride = remaining;
                    }

                    // Calculate the corresponding highRange (this is usually redundant).
                    highRange = lowRange + CLoverride - (CLoverride > 0 ? 1 : 0);

                    if (contentFeatures != null) {
                        output.headers().set("ContentFeatures.DLNA.ORG",
                                dlna.getDlnaContentFeatures(mediaRenderer));
                    }

                    output.headers().set(HttpHeaders.Names.ACCEPT_RANGES, "bytes");
                    output.headers().set(HttpHeaders.Names.CONNECTION, "keep-alive");
                }
                if (origRendering != null) {
                    // Restore original rendering details
                    dlna.updateRendering(origRendering);
                }
            }
        }
    } else if ((method.equals("GET") || method.equals("HEAD")) && (argument.toLowerCase().endsWith(".png")
            || argument.toLowerCase().endsWith(".jpg") || argument.toLowerCase().endsWith(".jpeg"))) {
        if (argument.toLowerCase().endsWith(".png")) {
            output.headers().set(HttpHeaders.Names.CONTENT_TYPE, "image/png");
        } else {
            output.headers().set(HttpHeaders.Names.CONTENT_TYPE, "image/jpeg");
        }

        output.headers().set(HttpHeaders.Names.ACCEPT_RANGES, "bytes");
        output.headers().set(HttpHeaders.Names.CONNECTION, "keep-alive");
        output.headers().set(HttpHeaders.Names.EXPIRES, getFUTUREDATE() + " GMT");
        inputStream = getResourceInputStream(argument);
    } else if ((method.equals("GET") || method.equals("HEAD"))
            && (argument.equals("description/fetch") || argument.endsWith("1.0.xml"))) {
        output.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/xml; charset=\"utf-8\"");
        output.headers().set(HttpHeaders.Names.CACHE_CONTROL, "no-cache");
        output.headers().set(HttpHeaders.Names.EXPIRES, "0");
        output.headers().set(HttpHeaders.Names.ACCEPT_RANGES, "bytes");
        output.headers().set(HttpHeaders.Names.CONNECTION, "keep-alive");
        inputStream = getResourceInputStream((argument.equals("description/fetch") ? "PMS.xml" : argument));

        if (argument.equals("description/fetch")) {
            byte b[] = new byte[inputStream.available()];
            inputStream.read(b);
            String s = new String(b);
            s = s.replace("[uuid]", PMS.get().usn()); //.substring(0, PMS.get().usn().length()-2));

            String profileName = "";
            if (configuration.isAppendProfileName()) {
                profileName = " [" + configuration.getProfileName() + "]";
            }

            String serverName = configuration.getServerName();

            if (PMS.get().getServer().getHost() != null) {
                s = s.replace("[host]", PMS.get().getServer().getHost());
                s = s.replace("[port]", "" + PMS.get().getServer().getPort());
            }

            if (xbox360) {
                LOGGER.debug("DLNA changes for Xbox 360");
                s = s.replace("Universal Media Server", serverName + profileName + " : Windows Media Connect");
                s = s.replace("<modelName>UMS</modelName>", "<modelName>Windows Media Connect</modelName>");
                s = s.replace("<serviceList>", "<serviceList>" + CRLF + "<service>" + CRLF
                        + "<serviceType>urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1</serviceType>"
                        + CRLF
                        + "<serviceId>urn:microsoft.com:serviceId:X_MS_MediaReceiverRegistrar</serviceId>"
                        + CRLF + "<SCPDURL>/upnp/mrr/scpd</SCPDURL>" + CRLF
                        + "<controlURL>/upnp/mrr/control</controlURL>" + CRLF + "</service>" + CRLF);
            } else {
                s = s.replace("Universal Media Server", serverName + profileName);
            }

            response.append(s);
            inputStream = null;
        }
    } else if (method.equals("POST")
            && (argument.contains("MS_MediaReceiverRegistrar_control") || argument.contains("mrr/control"))) {
        output.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/xml; charset=\"utf-8\"");
        response.append(HTTPXMLHelper.XML_HEADER);
        response.append(CRLF);
        response.append(HTTPXMLHelper.SOAP_ENCODING_HEADER);
        response.append(CRLF);

        if (soapaction != null && soapaction.contains("IsAuthorized")) {
            response.append(HTTPXMLHelper.XBOX_360_2);
            response.append(CRLF);
        } else if (soapaction != null && soapaction.contains("IsValidated")) {
            response.append(HTTPXMLHelper.XBOX_360_1);
            response.append(CRLF);
        }

        response.append(HTTPXMLHelper.BROWSERESPONSE_FOOTER);
        response.append(CRLF);
        response.append(HTTPXMLHelper.SOAP_ENCODING_FOOTER);
        response.append(CRLF);
    } else if (method.equals("POST") && argument.endsWith("upnp/control/connection_manager")) {
        output.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/xml; charset=\"utf-8\"");

        if (soapaction != null && soapaction.contains("ConnectionManager:1#GetProtocolInfo")) {
            response.append(HTTPXMLHelper.XML_HEADER);
            response.append(CRLF);
            response.append(HTTPXMLHelper.SOAP_ENCODING_HEADER);
            response.append(CRLF);
            response.append(HTTPXMLHelper.PROTOCOLINFO_RESPONSE);
            response.append(CRLF);
            response.append(HTTPXMLHelper.SOAP_ENCODING_FOOTER);
            response.append(CRLF);
        }
    } else if (method.equals("POST") && argument.endsWith("upnp/control/content_directory")) {
        output.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/xml; charset=\"utf-8\"");

        if (soapaction != null && soapaction.contains("ContentDirectory:1#GetSystemUpdateID")) {
            response.append(HTTPXMLHelper.XML_HEADER);
            response.append(CRLF);
            response.append(HTTPXMLHelper.SOAP_ENCODING_HEADER);
            response.append(CRLF);
            response.append(HTTPXMLHelper.GETSYSTEMUPDATEID_HEADER);
            response.append(CRLF);
            response.append("<Id>").append(DLNAResource.getSystemUpdateId()).append("</Id>");
            response.append(CRLF);
            response.append(HTTPXMLHelper.GETSYSTEMUPDATEID_FOOTER);
            response.append(CRLF);
            response.append(HTTPXMLHelper.SOAP_ENCODING_FOOTER);
            response.append(CRLF);
        } else if (soapaction != null && soapaction.contains("ContentDirectory:1#X_GetFeatureList")) { // Added for Samsung 2012 TVs
            response.append(HTTPXMLHelper.XML_HEADER);
            response.append(CRLF);
            response.append(HTTPXMLHelper.SOAP_ENCODING_HEADER);
            response.append(CRLF);
            response.append(HTTPXMLHelper.SAMSUNG_ERROR_RESPONSE);
            response.append(CRLF);
            response.append(HTTPXMLHelper.SOAP_ENCODING_FOOTER);
            response.append(CRLF);
        } else if (soapaction != null && soapaction.contains("ContentDirectory:1#GetSortCapabilities")) {
            response.append(HTTPXMLHelper.XML_HEADER);
            response.append(CRLF);
            response.append(HTTPXMLHelper.SOAP_ENCODING_HEADER);
            response.append(CRLF);
            response.append(HTTPXMLHelper.SORTCAPS_RESPONSE);
            response.append(CRLF);
            response.append(HTTPXMLHelper.SOAP_ENCODING_FOOTER);
            response.append(CRLF);
        } else if (soapaction != null && soapaction.contains("ContentDirectory:1#GetSearchCapabilities")) {
            response.append(HTTPXMLHelper.XML_HEADER);
            response.append(CRLF);
            response.append(HTTPXMLHelper.SOAP_ENCODING_HEADER);
            response.append(CRLF);
            response.append(HTTPXMLHelper.SEARCHCAPS_RESPONSE);
            response.append(CRLF);
            response.append(HTTPXMLHelper.SOAP_ENCODING_FOOTER);
            response.append(CRLF);
        } else if (soapaction != null && (soapaction.contains("ContentDirectory:1#Browse")
                || soapaction.contains("ContentDirectory:1#Search"))) {
            //LOGGER.trace(content);
            objectID = getEnclosingValue(content, "<ObjectID", "</ObjectID>");
            String containerID = null;
            if ((objectID == null || objectID.length() == 0)) {
                containerID = getEnclosingValue(content, "<ContainerID", "</ContainerID>");
                if (containerID == null || (xbox360 && !containerID.contains("$"))) {
                    objectID = "0";
                } else {
                    objectID = containerID;
                    containerID = null;
                }
            }
            String sI = getEnclosingValue(content, "<StartingIndex", "</StartingIndex>");
            String rC = getEnclosingValue(content, "<RequestedCount", "</RequestedCount>");
            browseFlag = getEnclosingValue(content, "<BrowseFlag", "</BrowseFlag>");

            if (sI != null) {
                startingIndex = Integer.parseInt(sI);
            }

            if (rC != null) {
                requestCount = Integer.parseInt(rC);
            }

            response.append(HTTPXMLHelper.XML_HEADER);
            response.append(CRLF);
            response.append(HTTPXMLHelper.SOAP_ENCODING_HEADER);
            response.append(CRLF);

            if (soapaction != null && soapaction.contains("ContentDirectory:1#Search")) {
                response.append(HTTPXMLHelper.SEARCHRESPONSE_HEADER);
            } else {
                response.append(HTTPXMLHelper.BROWSERESPONSE_HEADER);
            }

            response.append(CRLF);
            response.append(HTTPXMLHelper.RESULT_HEADER);
            response.append(HTTPXMLHelper.DIDL_HEADER);

            boolean browseDirectChildren = browseFlag != null && browseFlag.equals("BrowseDirectChildren");

            if (soapaction != null && soapaction.contains("ContentDirectory:1#Search")) {
                browseDirectChildren = true;
            }

            // Xbox 360 virtual containers ... d'oh!
            String searchCriteria = null;
            if (xbox360 && configuration.getUseCache() && PMS.get().getLibrary() != null
                    && containerID != null) {
                if (containerID.equals("7") && PMS.get().getLibrary().getAlbumFolder() != null) {
                    objectID = PMS.get().getLibrary().getAlbumFolder().getResourceId();
                } else if (containerID.equals("6") && PMS.get().getLibrary().getArtistFolder() != null) {
                    objectID = PMS.get().getLibrary().getArtistFolder().getResourceId();
                } else if (containerID.equals("5") && PMS.get().getLibrary().getGenreFolder() != null) {
                    objectID = PMS.get().getLibrary().getGenreFolder().getResourceId();
                } else if (containerID.equals("F") && PMS.get().getLibrary().getPlaylistFolder() != null) {
                    objectID = PMS.get().getLibrary().getPlaylistFolder().getResourceId();
                } else if (containerID.equals("4") && PMS.get().getLibrary().getAllFolder() != null) {
                    objectID = PMS.get().getLibrary().getAllFolder().getResourceId();
                } else if (containerID.equals("1")) {
                    String artist = getEnclosingValue(content, "upnp:artist = &quot;", "&quot;)");
                    if (artist != null) {
                        objectID = PMS.get().getLibrary().getArtistFolder().getResourceId();
                        searchCriteria = artist;
                    }
                }
            } else if (soapaction.contains("ContentDirectory:1#Search")) {
                searchCriteria = getEnclosingValue(content, "<SearchCriteria", "</SearchCriteria>");
            }

            List<DLNAResource> files = PMS.get().getRootFolder(mediaRenderer).getDLNAResources(objectID,
                    browseDirectChildren, startingIndex, requestCount, mediaRenderer, searchCriteria);

            if (searchCriteria != null && files != null) {
                UMSUtils.postSearch(files, searchCriteria);
                if (xbox360) {
                    if (files.size() > 0) {
                        files = files.get(0).getChildren();
                    }
                }
            }

            int minus = 0;
            if (files != null) {
                for (DLNAResource uf : files) {
                    if (xbox360 && containerID != null) {
                        uf.setFakeParentId(containerID);
                    }

                    if (uf.isCompatible(mediaRenderer)
                            && (uf.getPlayer() == null || uf.getPlayer().isPlayerCompatible(mediaRenderer))) {
                        response.append(uf.getDidlString(mediaRenderer));
                    } else {
                        minus++;
                    }
                }
            }

            response.append(HTTPXMLHelper.DIDL_FOOTER);
            response.append(HTTPXMLHelper.RESULT_FOOTER);
            response.append(CRLF);

            int filessize = 0;
            if (files != null) {
                filessize = files.size();
            }

            response.append("<NumberReturned>").append(filessize - minus).append("</NumberReturned>");
            response.append(CRLF);
            DLNAResource parentFolder = null;

            if (files != null && filessize > 0) {
                parentFolder = files.get(0).getParent();
            }

            if (browseDirectChildren && mediaRenderer.isMediaParserV2() && mediaRenderer.isDLNATreeHack()) {
                // with the new parser, files are parsed and analyzed *before*
                // creating the DLNA tree, every 10 items (the ps3 asks 10 by 10),
                // so we do not know exactly the total number of items in the DLNA folder to send
                // (regular files, plus the #transcode folder, maybe the #imdb one, also files can be
                // invalidated and hidden if format is broken or encrypted, etc.).
                // let's send a fake total size to force the renderer to ask following items
                int totalCount = startingIndex + requestCount + 1; // returns 11 when 10 asked

                // If no more elements, send the startingIndex
                if (filessize - minus <= 0) {
                    totalCount = startingIndex;
                }

                response.append("<TotalMatches>").append(totalCount).append("</TotalMatches>");
            } else if (browseDirectChildren) {
                response.append("<TotalMatches>")
                        .append(((parentFolder != null) ? parentFolder.childrenNumber() : filessize) - minus)
                        .append("</TotalMatches>");
            } else {
                // From upnp spec: If BrowseMetadata is specified in the BrowseFlags then TotalMatches = 1
                response.append("<TotalMatches>1</TotalMatches>");
            }

            response.append(CRLF);
            response.append("<UpdateID>");

            if (parentFolder != null) {
                response.append(parentFolder.getUpdateId());
            } else {
                response.append("1");
            }

            response.append("</UpdateID>");
            response.append(CRLF);
            if (soapaction != null && soapaction.contains("ContentDirectory:1#Search")) {
                response.append(HTTPXMLHelper.SEARCHRESPONSE_FOOTER);
            } else {
                response.append(HTTPXMLHelper.BROWSERESPONSE_FOOTER);
            }
            response.append(CRLF);
            response.append(HTTPXMLHelper.SOAP_ENCODING_FOOTER);
            response.append(CRLF);
            //LOGGER.trace(response.toString());
        }
    } else if (method.equals("SUBSCRIBE")) {
        output.headers().set("SID", PMS.get().usn());
        output.headers().set("TIMEOUT", "Second-1800");

        if (soapaction != null) {
            String cb = soapaction.replace("<", "").replace(">", "");

            try {
                URL soapActionUrl = new URL(cb);
                String addr = soapActionUrl.getHost();
                int port = soapActionUrl.getPort();
                Socket sock = new Socket(addr, port);
                try (OutputStream out = sock.getOutputStream()) {
                    out.write(("NOTIFY /" + argument + " HTTP/1.1").getBytes());
                    out.write(CRLF.getBytes());
                    out.write(("SID: " + PMS.get().usn()).getBytes());
                    out.write(CRLF.getBytes());
                    out.write(("SEQ: " + 0).getBytes());
                    out.write(CRLF.getBytes());
                    out.write(("NT: upnp:event").getBytes());
                    out.write(CRLF.getBytes());
                    out.write(("NTS: upnp:propchange").getBytes());
                    out.write(CRLF.getBytes());
                    out.write(("HOST: " + addr + ":" + port).getBytes());
                    out.write(CRLF.getBytes());
                    out.flush();
                    sock.close();
                }
            } catch (MalformedURLException ex) {
                LOGGER.debug("Cannot parse address and port from soap action \"" + soapaction + "\"", ex);
            }
        } else {
            LOGGER.debug("Expected soap action in request");
        }

        if (argument.contains("connection_manager")) {
            response.append(HTTPXMLHelper.eventHeader("urn:schemas-upnp-org:service:ConnectionManager:1"));
            response.append(HTTPXMLHelper.eventProp("SinkProtocolInfo"));
            response.append(HTTPXMLHelper.eventProp("SourceProtocolInfo"));
            response.append(HTTPXMLHelper.eventProp("CurrentConnectionIDs"));
            response.append(HTTPXMLHelper.EVENT_FOOTER);
        } else if (argument.contains("content_directory")) {
            response.append(HTTPXMLHelper.eventHeader("urn:schemas-upnp-org:service:ContentDirectory:1"));
            response.append(HTTPXMLHelper.eventProp("TransferIDs"));
            response.append(HTTPXMLHelper.eventProp("ContainerUpdateIDs"));
            response.append(HTTPXMLHelper.eventProp("SystemUpdateID", "" + DLNAResource.getSystemUpdateId()));
            response.append(HTTPXMLHelper.EVENT_FOOTER);
        }
    } else if (method.equals("NOTIFY")) {
        output.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/xml");
        output.headers().set("NT", "upnp:event");
        output.headers().set("NTS", "upnp:propchange");
        output.headers().set("SID", PMS.get().usn());
        output.headers().set("SEQ", "0");
        response.append("<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">");
        response.append("<e:property>");
        response.append("<TransferIDs></TransferIDs>");
        response.append("</e:property>");
        response.append("<e:property>");
        response.append("<ContainerUpdateIDs></ContainerUpdateIDs>");
        response.append("</e:property>");
        response.append("<e:property>");
        response.append("<SystemUpdateID>").append(DLNAResource.getSystemUpdateId())
                .append("</SystemUpdateID>");
        response.append("</e:property>");
        response.append("</e:propertyset>");
    }

    output.headers().set("Server", PMS.get().getServerName());

    if (response.length() > 0) {
        // A response message was constructed; convert it to data ready to be sent.
        byte responseData[] = response.toString().getBytes("UTF-8");
        output.headers().set(HttpHeaders.Names.CONTENT_LENGTH, "" + responseData.length);

        // HEAD requests only require headers to be set, no need to set contents.
        if (!method.equals("HEAD")) {
            // Not a HEAD request, so set the contents of the response.
            ByteBuf buf = Unpooled.copiedBuffer(responseData);
            HttpResponse oldOutput = output;
            output = new DefaultFullHttpResponse(output.getProtocolVersion(), output.getStatus(), buf);
            output.headers().add(oldOutput.headers());
        }

        // Send the response to the client.
        future = ctx.writeAndFlush(output);

        if (close) {
            // Close the channel after the response is sent.
            future.addListener(ChannelFutureListener.CLOSE);
        }
    } else if (inputStream != null) {
        // There is an input stream to send as a response.

        if (CLoverride > -2) {
            // Content-Length override has been set, send or omit as appropriate
            if (CLoverride > -1 && CLoverride != DLNAMediaInfo.TRANS_SIZE) {
                // Since PS3 firmware 2.50, it is wiser not to send an arbitrary Content-Length,
                // as the PS3 will display a network error and request the last seconds of the
                // transcoded video. Better to send no Content-Length at all.
                output.headers().set(HttpHeaders.Names.CONTENT_LENGTH, "" + CLoverride);
            }
        } else {
            int cl = inputStream.available();
            LOGGER.trace("Available Content-Length: " + cl);
            output.headers().set(HttpHeaders.Names.CONTENT_LENGTH, "" + cl);
        }

        if (range.isStartOffsetAvailable() && dlna != null) {
            // Add timeseek information headers.
            String timeseekValue = StringUtil.convertTimeToString(range.getStartOrZero(),
                    StringUtil.DURATION_TIME_FORMAT);
            String timetotalValue = dlna.getMedia().getDurationString();
            String timeEndValue = range.isEndLimitAvailable()
                    ? StringUtil.convertTimeToString(range.getEnd(), StringUtil.DURATION_TIME_FORMAT)
                    : timetotalValue;
            output.headers().set("TimeSeekRange.dlna.org",
                    "npt=" + timeseekValue + "-" + timeEndValue + "/" + timetotalValue);
            output.headers().set("X-Seek-Range",
                    "npt=" + timeseekValue + "-" + timeEndValue + "/" + timetotalValue);
        }

        // Send the response headers to the client.
        future = ctx.write(output);

        if (lowRange != DLNAMediaInfo.ENDFILE_POS && !method.equals("HEAD")) {
            // Send the response body to the client in chunks.
            ChannelFuture chunkWriteFuture = ctx.writeAndFlush(new ChunkedStream(inputStream, BUFFER_SIZE));

            // Add a listener to clean up after sending the entire response body.
            chunkWriteFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) {
                    try {
                        PMS.get().getRegistry().reenableGoToSleep();
                        inputStream.close();
                    } catch (IOException e) {
                        LOGGER.debug("Caught exception", e);
                    }

                    // Always close the channel after the response is sent because of
                    // a freeze at the end of video when the channel is not closed.
                    future.channel().close();
                    startStopListenerDelegate.stop();
                }
            });
        } else {
            // HEAD method is being used, so simply clean up after the response was sent.
            ctx.flush();
            try {
                PMS.get().getRegistry().reenableGoToSleep();
                inputStream.close();
            } catch (IOException ioe) {
                LOGGER.debug("Caught exception", ioe);
            }

            if (close) {
                // Close the channel after the response is sent
                future.addListener(ChannelFutureListener.CLOSE);
            }

            startStopListenerDelegate.stop();
        }
    } else {
        // No response data and no input stream. Seems we are merely serving up headers.
        if (lowRange > 0 && highRange > 0) {
            // FIXME: There is no content, so why set a length?
            output.headers().set(HttpHeaders.Names.CONTENT_LENGTH, "" + (highRange - lowRange + 1));
        } else {
            output.headers().set(HttpHeaders.Names.CONTENT_LENGTH, "0");
        }

        // Send the response headers to the client.
        future = ctx.writeAndFlush(output);

        if (close) {
            // Close the channel after the response is sent.
            future.addListener(ChannelFutureListener.CLOSE);
        }
    }

    // Log trace information
    Iterator<String> it = output.headers().names().iterator();

    while (it.hasNext()) {
        String headerName = it.next();
        LOGGER.trace("Sent to socket: " + headerName + ": " + output.headers().get(headerName));
    }

    return future;
}

From source file:nikoladasm.aspark.ResponseImpl.java

License:Open Source License

private void sendChunked() {
    HttpResponse response = new DefaultHttpResponse(version, HttpResponseStatus.valueOf(status));
    setHeades(response);/*  w  ww .ja  v  a2 s  . com*/
    response.headers().set(TRANSFER_ENCODING, CHUNKED);
    cookies.forEach(
            (name, cookie) -> response.headers().add(SET_COOKIE, ServerCookieEncoder.LAX.encode(cookie)));
    ctx.channel().write(response);
    Object body;
    if (!httpMethod.equals(HEAD)) {
        body = new HttpChunkedInput(new ChunkedStream(stream, DEFAULT_CHUNK_SIZE));
    } else {
        body = LastHttpContent.EMPTY_LAST_CONTENT;
    }
    writeObjectToChannel(body).addListener(channelFuture -> stream.close());
}

From source file:org.apache.reef.wake.remote.transport.netty.ChunkedReadWriteHandler.java

License:Apache License

/**
 * Thread-safe since there is no shared instance state.
 * Just prepend size to the message and stream it through
 * a chunked stream and let the base method handle the actual
 * chunking./*from w w w  .  j  a  va  2  s .co  m*/
 * <p/>
 * We do not need to tag the writes since the base class ChunkedWriteHandler
 * serializes access to the channel and first write will complete before
 * the second begins.
 */
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {

    if (msg instanceof ByteBuf) {

        final ByteBuf bf = (ByteBuf) msg;

        if (bf.hasArray()) {
            final byte[] data = bf.array();
            final byte[] size = sizeAsByteArr(data.length);
            final ByteBuf writeBuffer = Unpooled.wrappedBuffer(size, data);
            final ByteBufCloseableStream stream = new ByteBufCloseableStream(writeBuffer);
            final ChunkedStream chunkedStream = new ChunkedStream(stream,
                    NettyChannelInitializer.MAXFRAMELENGTH - 1024);
            super.write(ctx, chunkedStream, promise);
        } else {
            super.write(ctx, msg, promise);
        }

    } else {
        super.write(ctx, msg, promise);
    }
}

From source file:org.jooby.internal.netty.NettyResponse.java

License:Apache License

@Override
public void send(final InputStream stream) throws Exception {
    byte[] chunk = new byte[bufferSize];
    int count = ByteStreams.read(stream, chunk, 0, bufferSize);
    if (count <= 0) {
        return;//w  ww.j ava 2  s.c o m
    }
    ByteBuf buffer = Unpooled.wrappedBuffer(chunk, 0, count);
    if (count < bufferSize) {
        send(buffer);
    } else {
        DefaultHttpResponse rsp = new DefaultHttpResponse(HttpVersion.HTTP_1_1, status);

        if (!headers.contains(HttpHeaderNames.CONTENT_LENGTH)) {
            headers.set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED);
        } else {
            if (keepAlive) {
                headers.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
            }
        }

        // dump headers
        rsp.headers().set(headers);
        ChannelHandlerContext ctx = this.ctx;
        ctx.channel().attr(NettyRequest.NEED_FLUSH).set(false);

        // add chunker
        chunkHandler(ctx.pipeline());

        // group all write
        ctx.channel().eventLoop().execute(() -> {
            // send headers
            ctx.write(rsp);
            // send head chunk
            ctx.write(buffer);
            // send tail
            ctx.write(new ChunkedStream(stream, bufferSize));
            keepAlive(ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT));
        });
    }

    committed = true;
}

From source file:org.restnext.server.ServerHandler.java

License:Apache License

private void write(ChannelHandlerContext ctx, Response response, boolean keepAlive) {
    HttpVersion version = fromVersion(response.getVersion());
    HttpResponseStatus status = fromStatus(response.getStatus());
    ByteBuf content = response.hasContent() ? Unpooled.wrappedBuffer(response.getContent())
            : Unpooled.EMPTY_BUFFER;/*  w  w w .  ja v  a  2 s .c  o  m*/

    boolean chunked = response.isChunked();

    // create netty response
    HttpResponse resp;
    HttpChunkedInput chunkedResp = chunked
            ? new HttpChunkedInput(new ChunkedStream(new ByteBufInputStream(content), response.getChunkSize()))
            : null;

    if (chunked) {
        resp = new DefaultHttpResponse(version, status);
        HttpUtil.setTransferEncodingChunked(resp, true);
        createOutboutHeaders(resp, response, keepAlive);
        // Write the initial line and the header.
        ctx.write(resp);
    } else {
        resp = new DefaultFullHttpResponse(version, status, content);
        createOutboutHeaders(resp, response, keepAlive);
    }

    if (keepAlive) {
        if (chunked) {
            ctx.write(chunkedResp);
        } else {
            HttpUtil.setContentLength(resp, content.readableBytes());
            ctx.write(resp);
        }
    } else {
        ChannelFuture channelFuture;
        if (chunked) {
            channelFuture = ctx.writeAndFlush(chunkedResp);
        } else {
            channelFuture = ctx.writeAndFlush(resp);
        }
        // Close the connection after the write operation is done if necessary.
        channelFuture.addListener(ChannelFutureListener.CLOSE);
    }
}