public MediaResource handle(String relPath, HttpServletRequest request) {
    if (log.isDebug()) log.debug("CPComponent Mapper relPath=" + relPath);

    VFSItem currentItem = mapperRootContainer.resolve(relPath);
    if (currentItem == null || (currentItem instanceof VFSContainer)) {
      return new NotFoundMediaResource(relPath);
    }
    VFSMediaResource vmr = new VFSMediaResource((VFSLeaf) currentItem);
    String encoding = SimpleHtmlParser.extractHTMLCharset(((VFSLeaf) currentItem));
    if (log.isDebug()) log.debug("CPComponent Mapper set encoding=" + encoding);
    vmr.setEncoding(encoding); //
    return vmr;
  }
Пример #2
0
  @Override
  public SearchResults call() throws ParseException {
    IndexSearcher searcher = null;
    try {
      boolean debug = log.isDebug();

      if (!searchService.existIndex()) {
        log.warn("Index does not exist, can't search for queryString: " + queryString);
        throw new ServiceNotAvailableException("Index does not exist");
      }

      if (debug) log.debug("queryString=" + queryString);
      searcher = searchService.getIndexSearcher();
      BooleanQuery query = searchService.createQuery(queryString, condQueries);
      if (debug) log.debug("query=" + query);

      long startTime = System.currentTimeMillis();
      int n = SearchServiceFactory.getService().getSearchModuleConfig().getMaxHits();

      TopDocs docs = searcher.search(query, n);
      long queryTime = System.currentTimeMillis() - startTime;
      if (debug) log.debug("hits.length()=" + docs.totalHits);
      SearchResultsImpl searchResult =
          new SearchResultsImpl(
              searchService.getMainIndexer(),
              searcher,
              docs,
              query,
              searchService.getAnalyzer(),
              identity,
              roles,
              firstResult,
              maxResults,
              doHighlighting,
              false);
      searchResult.setQueryTime(queryTime);
      searchResult.setNumberOfIndexDocuments(docs.totalHits);
      if (debug) log.debug("found=" + docs.totalHits);

      return searchResult;
    } catch (ParseException pex) {
      throw pex;
    } catch (Exception naex) {
      log.error("", naex);
      return null;
    } finally {
      searchService.releaseIndexSearcher(searcher);
      DBFactory.getInstance().commitAndCloseSession();
    }
  }
Пример #3
0
  private boolean isSameFile(VFSLeaf currentFile, VersionsFileImpl versions) {
    boolean same = false;
    if (versions.getRevisions() != null && !versions.getRevisions().isEmpty()) {
      VFSRevision lastRevision = versions.getRevisions().get(versions.getRevisions().size() - 1);

      long lastSize = lastRevision.getSize();
      long currentSize = currentFile.getSize();
      if (currentSize == lastSize
          && currentSize > 0
          && lastRevision instanceof RevisionFileImpl
          && currentFile instanceof LocalFileImpl) {
        RevisionFileImpl lastRev = ((RevisionFileImpl) lastRevision);
        LocalFileImpl current = (LocalFileImpl) currentFile;
        // can be the same file
        try {
          Checksum cm1 =
              FileUtils.checksum(((LocalFileImpl) lastRev.getFile()).getBasefile(), new Adler32());
          Checksum cm2 = FileUtils.checksum(current.getBasefile(), new Adler32());
          same = cm1.getValue() == cm2.getValue();
        } catch (IOException e) {
          log.debug("Error calculating the checksum of files");
        }
      }
    }
    return same;
  }
Пример #4
0
  /**
   * Copy an InputStream to an OutputStream, until EOF. Use only when you don't know the length.
   *
   * @param source InputStream, left open.
   * @param target OutputStream, left open.
   * @return true if the copy was successful.
   */
  @Deprecated
  public static boolean copy(InputStream source, OutputStream target) {
    try {

      int chunkSize = buffSize;
      // code will work even when chunkSize = 0 or chunks = 0;
      // Even for small files, we allocate a big buffer, since we
      // don't know the size ahead of time.
      byte[] ba = new byte[chunkSize];

      while (true) {
        int bytesRead = readBlocking(source, ba, 0, chunkSize);
        if (bytesRead > 0) {
          target.write(ba, 0, bytesRead);
        } else {
          break;
        } // hit eof
      } // end while
    } catch (MalformedStreamException e) {
      throw new OLATRuntimeException("Could not read stream", e);
    } catch (IOException e) {
      // don't log as error - happens all the time (ClientAbortException)
      if (log.isDebug()) log.debug("Could not copy stream::" + e.getMessage());
      return false;
    }
    return true;
  } // end copy
Пример #5
0
  /**
   * Copy an InputStream to an OutputStream.
   *
   * @param source InputStream, left open.
   * @param target OutputStream, left open.
   * @param length how many bytes to copy.
   * @return true if the copy was successful.
   */
  public static boolean copy(InputStream source, OutputStream target, long length) {
    if (length == 0) return true;
    try {
      int chunkSize = (int) Math.min(buffSize, length);
      long chunks = length / chunkSize;
      int lastChunkSize = (int) (length % chunkSize);
      // code will work even when chunkSize = 0 or chunks = 0;
      byte[] ba = new byte[chunkSize];

      for (long i = 0; i < chunks; i++) {
        int bytesRead = readBlocking(source, ba, 0, chunkSize);
        if (bytesRead != chunkSize) {
          throw new IOException();
        }
        target.write(ba);
      } // end for
      // R E A D / W R I T E last chunk, if any
      if (lastChunkSize > 0) {
        int bytesRead = readBlocking(source, ba, 0, lastChunkSize);
        if (bytesRead != lastChunkSize) {
          throw new IOException();
        }
        target.write(ba, 0, lastChunkSize);
      } // end if
    } catch (IOException e) {
      // don't log as error - happens all the time (ClientAbortException)
      if (log.isDebug())
        log.debug("Could not copy stream::" + e.getMessage() + " with length::" + length);
      return false;
    }
    return true;
  } // end copy
 @Override
 public boolean isSafelyAllowed(HttpServletRequest request, String safeExamBrowserKeys) {
   boolean safe = false;
   boolean debug = log.isDebug();
   if (StringHelper.containsNonWhitespace(safeExamBrowserKeys)) {
     String safeExamHash = request.getHeader("x-safeexambrowser-requesthash");
     String url = request.getRequestURL().toString();
     for (StringTokenizer tokenizer = new StringTokenizer(safeExamBrowserKeys);
         tokenizer.hasMoreTokens() && !safe; ) {
       String safeExamBrowserKey = tokenizer.nextToken();
       String hash = Encoder.sha256Exam(url + safeExamBrowserKey);
       if (safeExamHash != null && safeExamHash.equals(hash)) {
         safe = true;
       }
       if (debug) {
         log.debug(
             (safeExamHash.equals(hash) ? "Success" : "Failed")
                 + " : "
                 + safeExamHash
                 + " (Header) "
                 + hash
                 + " (Calculated)");
       }
     }
   } else {
     safe = true;
   }
   return safe;
 }
Пример #7
0
 /**
  * Delete all ResultSet for certain identity.
  *
  * @param identity
  */
 public void deleteUserData(Identity identity, String newDeletedUserName) {
   List<QTIResultSet> qtiResults = findQtiResultSets(identity);
   for (QTIResultSet set : qtiResults) {
     deleteResultSet(set);
   }
   if (log.isDebug()) {
     log.debug("Delete all QTI result data in db for identity=" + identity);
   }
 }
 /**
  * @see org.olat.core.gui.components.Component#doDispatchRequest(org.olat.core.gui.UserRequest)
  */
 @Override
 protected void doDispatchRequest(UserRequest ureq) {
   setDirty(true);
   String cmd = ureq.getParameter(VelocityContainer.COMMAND_ID);
   if (log.isDebug()) {
     log.debug("***RATING_CLICKED*** dispatchID::" + ureq.getComponentID() + " rating::" + cmd);
   }
   try {
     float rating = Float.parseFloat(cmd);
     // update GUI
     this.setCurrentRating(rating);
     // notify listeners
     Event event = new RatingEvent(rating);
     fireEvent(ureq, event);
   } catch (NumberFormatException e) {
     log.error("Error while parsing rating value::" + cmd);
   }
 }
Пример #9
0
 /**
  * Copies the stream to the target leaf.
  *
  * @param source
  * @param target
  * @param closeInput set to false if it's a ZipInputStream
  * @return True on success, false on failure
  */
 public static boolean copyContent(InputStream inStream, VFSLeaf target, boolean closeInput) {
   boolean successful;
   if (inStream != null && target != null) {
     InputStream in = new BufferedInputStream(inStream);
     OutputStream out = new BufferedOutputStream(target.getOutputStream(false));
     // write the input to the output
     try {
       byte[] buf = new byte[FileUtils.BSIZE];
       int i = 0;
       while ((i = in.read(buf)) != -1) {
         out.write(buf, 0, i);
       }
       successful = true;
     } catch (IOException e) {
       // something went wrong.
       successful = false;
       log.error(
           "Error while copying content from source: "
               + inStream
               + " to target: "
               + target.getName(),
           e);
     } finally {
       // Close streams
       try {
         if (out != null) {
           out.flush();
           out.close();
         }
         if (closeInput && in != null) {
           in.close();
         }
       } catch (IOException ex) {
         log.error("Error while closing/cleaning up in- and output streams", ex);
       }
     }
   } else {
     // source or target is null
     successful = false;
     if (log.isDebug())
       log.debug("Either the source or the target is null. Content of leaf cannot be copied.");
   }
   return successful;
 }
Пример #10
0
  /**
   * Copy the contents of the specified input stream to the specified output stream, and ensure that
   * both streams are closed before returning (even in the face of an exception).
   *
   * @param istream The input stream to read from
   * @param ostream The output stream to write to
   * @param start Start of the range which will be copied
   * @param end End of the range which will be copied
   * @return Exception which occurred during processing
   */
  protected IOException copyRange(
      InputStream istream, ServletOutputStream ostream, long start, long end) {

    if (log.isDebug()) {
      log.debug("Serving bytes:" + start + "-" + end);
    }

    long skipped = 0;
    try {
      skipped = istream.skip(start);
    } catch (IOException e) {
      return e;
    }
    if (skipped < start) {
      return new IOException(
          "defaultservlet.skipfail" + Long.valueOf(skipped) + Long.valueOf(start));
    }

    IOException exception = null;
    long bytesToRead = end - start + 1;

    byte buffer[] = new byte[input];
    int len = buffer.length;
    while ((bytesToRead > 0) && (len >= buffer.length)) {
      try {
        len = istream.read(buffer);
        if (bytesToRead >= len) {
          ostream.write(buffer, 0, len);
          bytesToRead -= len;
        } else {
          ostream.write(buffer, 0, (int) bytesToRead);
          bytesToRead = 0;
        }
      } catch (IOException e) {
        exception = e;
        len = -1;
      }
      if (len < buffer.length) break;
    }

    return exception;
  }
Пример #11
0
  /**
   * copy in, copy out (leaves both streams open)
   *
   * <p>
   *
   * @see FileUtils.getBos() which creates a matching BufferedOutputStream
   * @param in BuferedInputStream
   * @param out BufferedOutputStream
   * @param wt What this I/O is about
   */
  public static long cpio(BufferedInputStream in, BufferedOutputStream out, String wt)
      throws IOException {

    byte[] buffer = new byte[BSIZE];

    int c;
    long tot = 0;
    long s = System.nanoTime();
    while ((c = in.read(buffer, 0, buffer.length)) != -1) {
      out.write(buffer, 0, c);
      tot += c;
    }

    long tim = System.nanoTime() - s;
    double dtim =
        tim == 0 ? 0.5 : tim; // avg of those less than 1 nanoseconds is taken as 0.5 nanoseconds
    double bps = tot * 1000 * 1000 / dtim;
    log.debug(
        String.format(
            "cpio %,13d bytes %6.2f ms avg %6.1f Mbps %s%n",
            tot, dtim / 1000 / 1000, bps / 1024, wt));
    return tot;
  }
  public static Document createDocument(
      final SearchResourceContext searchResourceContext, final WikiPage wikiPage) {
    final WikiPageDocument wikiPageDocument = new WikiPageDocument();

    final long userId = wikiPage.getInitalAuthor();
    if (userId != 0) {
      final Identity identity = identityManager.loadIdentityByKey(Long.valueOf(userId));
      wikiPageDocument.setAuthor(identity.getName());
    }
    wikiPageDocument.setTitle(wikiPage.getPageName());
    wikiPageDocument.setContent(getContent(wikiPage));
    wikiPageDocument.setCreatedDate(new Date(wikiPage.getCreationTime()));
    wikiPageDocument.setLastChange(new Date(wikiPage.getModificationTime()));
    wikiPageDocument.setResourceUrl(searchResourceContext.getResourceUrl());
    wikiPageDocument.setDocumentType(searchResourceContext.getDocumentType());
    wikiPageDocument.setCssIcon("o_wiki_icon");
    wikiPageDocument.setParentContextType(searchResourceContext.getParentContextType());
    wikiPageDocument.setParentContextName(searchResourceContext.getParentContextName());

    if (log.isDebug()) {
      log.debug(wikiPageDocument.toString());
    }
    return wikiPageDocument.getLuceneDocument();
  }
Пример #13
0
  private String getRelPath(VFSItem item) {
    String relPath = null;
    if (item instanceof NamedContainerImpl) {
      item = ((NamedContainerImpl) item).getDelegate();
    }
    if (item instanceof MergeSource) {
      item = ((MergeSource) item).getRootWriteContainer();
    }
    if (item instanceof OlatRelPathImpl) {
      relPath = ((OlatRelPathImpl) item).getRelPath();
    } else if (item instanceof LocalImpl) {
      LocalImpl impl = (LocalImpl) item;
      String absolutPath = impl.getBasefile().getAbsolutePath();
      if (absolutPath.startsWith(getCanonicalRoot())) {
        relPath = absolutPath.substring(getCanonicalRoot().length());
      }

      Path path = impl.getBasefile().toPath();
      Path relativePath = getCanonicalRootFile().toPath().relativize(path);
      String relPath2 = "/" + relativePath.toString();
      log.debug(relPath + " :: " + relPath2);
    }
    return relPath;
  }
  /**
   * @see
   *     org.olat.search.service.indexer.AbstractHierarchicalIndexer#doIndex(org.olat.search.service.SearchResourceContext,
   *     java.lang.Object, org.olat.search.service.indexer.OlatFullIndexer)
   */
  @Override
  public void doIndex(
      SearchResourceContext parentResourceContext, Object parentObject, OlatFullIndexer indexWriter)
      throws IOException, InterruptedException {
    if (!ContextHelpModule.isContextHelpEnabled()) {
      // don't index context help when disabled
      return;
    }
    long startTime = System.currentTimeMillis();
    Set<String> helpPageIdentifyers = ContextHelpModule.getAllContextHelpPages();
    Set<String> languages = I18nModule.getEnabledLanguageKeys();
    if (log.isDebug())
      log.debug(
          "ContextHelpIndexer helpPageIdentifyers.size::"
              + helpPageIdentifyers.size()
              + " and languages.size::"
              + languages.size());
    // loop over all help pages
    for (String helpPageIdentifyer : helpPageIdentifyers) {
      String[] identifyerSplit = helpPageIdentifyer.split(":");
      String bundleName = identifyerSplit[0];
      String page = identifyerSplit[1];
      // fxdiff: FXOLAT-221: don't use velocity on images
      if (page == null || !page.endsWith(".html")) {
        continue;
      }

      // Translator with default locale. Locale is set to each language in the
      // language iteration below
      Translator pageTranslator = new PackageTranslator(bundleName, I18nModule.getDefaultLocale());
      // Open velocity page for this help page
      String pagePath = bundleName.replace('.', '/') + ContextHelpModule.CHELP_DIR + page;
      VelocityContainer container =
          new VelocityContainer("contextHelpPageVC", pagePath, pageTranslator, null);
      Context ctx = container.getContext();
      GlobalSettings globalSettings =
          new GlobalSettings() {
            public int getFontSize() {
              return 100;
            }

            public AJAXFlags getAjaxFlags() {
              return new EmptyAJAXFlags();
            }

            public ComponentRenderer getComponentRendererFor(Component source) {
              return null;
            }

            public boolean isIdDivsForced() {
              return false;
            }
          };
      Renderer renderer =
          Renderer.getInstance(
              container, pageTranslator, new EmptyURLBuilder(), null, globalSettings);
      // Add render decorator with helper methods
      VelocityRenderDecorator vrdec = new VelocityRenderDecorator(renderer, container, null);
      ctx.put("r", vrdec);
      // Add empty static dir url - only used to not generate error messages
      ctx.put("chelpStaticDirUrl", "");
      // Create document for each language using the velocity context
      for (String langCode : languages) {
        Locale locale = I18nManager.getInstance().getLocaleOrNull(langCode);
        String relPagePath = langCode + "/" + bundleName + "/" + page;
        if (log.isDebug()) log.debug("Indexing help page with path::" + relPagePath);
        SearchResourceContext searchResourceContext =
            new SearchResourceContext(parentResourceContext);
        searchResourceContext.setBusinessControlFor(
            OresHelper.createOLATResourceableType(
                ContextHelpModule.class.getSimpleName())); // to match the list of indexer
        // Create context help document and index now, set translator to current locale
        pageTranslator.setLocale(locale);
        Document document =
            ContextHelpDocument.createDocument(
                searchResourceContext, bundleName, page, pageTranslator, ctx, pagePath);
        indexWriter.addDocument(document);
      }
      IOUtils.closeQuietly(vrdec);
    }
    long indexTime = System.currentTimeMillis() - startTime;
    if (log.isDebug()) log.debug("ContextHelpIndexer finished in " + indexTime + " ms");
  }
Пример #15
0
  /**
   * Serve the specified resource, optionally including the data content.
   *
   * @param request The servlet request we are processing
   * @param response The servlet response we are creating
   * @param content Should the content be included?
   * @param encoding The encoding to use if it is necessary to access the source as characters
   *     rather than as bytes
   * @exception IOException if an input/output error occurs
   * @exception ServletException if a servlet-specified error occurs
   */
  protected void serveResource(
      HttpServletRequest request, HttpServletResponse response, boolean content, String encoding)
      throws IOException, ServletException {

    boolean serveContent = content;
    boolean debug = log.isDebug();

    // Identify the requested resource path
    String path = getRelativePath(request);
    if (debug) {
      if (serveContent)
        log.debug(
            "DefaultServlet.serveResource:  Serving resource '" + path + "' headers and data");
      else log.debug("DefaultServlet.serveResource:  Serving resource '" + path + "' headers only");
    }

    WebResourceRoot resources = getResources(request);
    WebResource resource = resources.getResource(path);

    if (!resource.exists()) {
      // Check if we're included so we can return the appropriate
      // missing resource name in the error
      String requestUri = (String) request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI);
      if (requestUri == null) {
        requestUri = request.getRequestURI();
      } else {
        // We're included
        // SRV.9.3 says we must throw a FNFE
        throw new FileNotFoundException("defaultServlet.missingResource");
      }

      response.sendError(HttpServletResponse.SC_NOT_FOUND, requestUri);
      return;
    }

    // If the resource is not a collection, and the resource path
    // ends with "/" or "\", return NOT FOUND
    if (resource.isFile() && path.endsWith("/") || path.endsWith("\\")) {
      // Check if we're included so we can return the appropriate
      // missing resource name in the error
      String requestUri = (String) request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI);
      if (requestUri == null) {
        requestUri = request.getRequestURI();
      }
      response.sendError(HttpServletResponse.SC_NOT_FOUND, requestUri);
      return;
    }

    boolean isError = response.getStatus() >= HttpServletResponse.SC_BAD_REQUEST;

    boolean included = false;
    // Check if the conditions specified in the optional If headers are
    // satisfied.
    if (resource.isFile()) {
      // Checking If headers
      included = (request.getAttribute(RequestDispatcher.INCLUDE_CONTEXT_PATH) != null);
      if (!included && !isError && !checkIfHeaders(request, response, resource)) {
        return;
      }
    }

    // Find content type.
    String contentType = resource.getMimeType();
    if (contentType == null) {
      contentType = request.getServletContext().getMimeType(resource.getName());
      resource.setMimeType(contentType);
    }

    // These need to reflect the original resource, not the potentially
    // gzip'd version of the resource so get them now if they are going to
    // be needed later
    String eTag = null;
    String lastModifiedHttp = null;
    if (resource.isFile() && !isError) {
      eTag = resource.getETag();
      lastModifiedHttp = resource.getLastModifiedHttp();
    }

    // Serve a gzipped version of the file if present
    boolean usingGzippedVersion = false;
    if (gzip && !included && resource.isFile() && !path.endsWith(".gz")) {
      WebResource gzipResource = resources.getResource(path + ".gz");
      if (gzipResource.exists() && gzipResource.isFile()) {
        Collection<String> varyHeaders = response.getHeaders("Vary");
        boolean addRequired = true;
        for (String varyHeader : varyHeaders) {
          if ("*".equals(varyHeader) || "accept-encoding".equalsIgnoreCase(varyHeader)) {
            addRequired = false;
            break;
          }
        }
        if (addRequired) {
          response.addHeader("Vary", "accept-encoding");
        }
        if (checkIfGzip(request)) {
          response.addHeader("Content-Encoding", "gzip");
          resource = gzipResource;
          usingGzippedVersion = true;
        }
      }
    }

    ArrayList<Range> ranges = null;
    long contentLength = -1L;

    if (resource.isDirectory()) {
      contentType = "text/html;charset=UTF-8";
    } else {
      if (!isError) {
        if (useAcceptRanges) {
          // Accept ranges header
          response.setHeader("Accept-Ranges", "bytes");
        }

        // Parse range specifier
        ranges = parseRange(request, response, resource);

        // ETag header
        response.setHeader("ETag", eTag);

        // Last-Modified header
        response.setHeader("Last-Modified", lastModifiedHttp);
      }

      // Get content length
      contentLength = resource.getContentLength();
      // Special case for zero length files, which would cause a
      // (silent) ISE when setting the output buffer size
      if (contentLength == 0L) {
        serveContent = false;
      }
    }

    ServletOutputStream ostream = null;
    PrintWriter writer = null;

    if (serveContent) {
      // Trying to retrieve the servlet output stream
      try {
        ostream = response.getOutputStream();
      } catch (IllegalStateException e) {
        // If it fails, we try to get a Writer instead if we're
        // trying to serve a text file
        if (!usingGzippedVersion
            && ((contentType == null)
                || (contentType.startsWith("text"))
                || (contentType.endsWith("xml"))
                || (contentType.contains("/javascript")))) {
          writer = response.getWriter();
          // Cannot reliably serve partial content with a Writer
          ranges = FULL;
        } else {
          throw e;
        }
      }
    }

    // Check to see if a Filter, Valve of wrapper has written some content.
    // If it has, disable range requests and setting of a content length
    // since neither can be done reliably.
    ServletResponse r = response;
    long contentWritten = 0;
    while (r instanceof ServletResponseWrapper) {
      r = ((ServletResponseWrapper) r).getResponse();
    }

    if (contentWritten > 0) {
      ranges = FULL;
    }

    if (resource.isDirectory()
        || isError
        || ((ranges == null || ranges.isEmpty()) && request.getHeader("Range") == null)
        || ranges == FULL) {

      // Set the appropriate output headers
      if (contentType != null) {
        if (debug) log.debug("DefaultServlet.serveFile:  contentType='" + contentType + "'");
        response.setContentType(contentType);
      }
      if (resource.isFile() && contentLength >= 0 && (!serveContent || ostream != null)) {
        if (debug) log.debug("DefaultServlet.serveFile:  contentLength=" + contentLength);
        // Don't set a content length if something else has already
        // written to the response.
        if (contentWritten == 0) {
          response.setContentLengthLong(contentLength);
        }
      }

      InputStream renderResult = null;
      if (resource.isDirectory()) {
        if (serveContent) {
          // Serve the directory browser
          renderResult = null; // TODO tomcat render(getPathPrefix(request), resource);
        }
      }

      // Copy the input stream to our output stream (if requested)
      if (serveContent) {
        resource.increaseDownloadCount();

        try {
          response.setBufferSize(output);
        } catch (IllegalStateException e) {
          // Silent catch
        }

        if (ostream == null) {
          // Output via a writer so can't use sendfile or write
          // content directly.
          if (resource.isDirectory()) {
            renderResult = null; // render(getPathPrefix(request), resource);
          } else {
            renderResult = resource.getInputStream();
          }
          copy(resource, renderResult, writer, encoding);
        } else {
          // Output is via an InputStream
          if (resource.isDirectory()) {
            renderResult = null; // render(getPathPrefix(request), resource);
          } else {
            renderResult = resource.getInputStream();
          }
          // If a stream was configured, it needs to be copied to
          // the output (this method closes the stream)
          if (renderResult != null) {
            copy(renderResult, ostream);
          }
        }
      }

    } else {
      // download counter
      resource.increaseDownloadCount();

      if ((ranges == null) || (ranges.isEmpty())) return;

      // Partial content response.

      response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);

      if (ranges.size() == 1) {

        Range range = ranges.get(0);
        response.addHeader(
            "Content-Range", "bytes " + range.start + "-" + range.end + "/" + range.length);
        long length = range.end - range.start + 1;
        response.setContentLengthLong(length);

        if (contentType != null) {
          if (debug) log.debug("DefaultServlet.serveFile:  contentType='" + contentType + "'");
          response.setContentType(contentType);
        }

        if (serveContent) {
          try {
            response.setBufferSize(output);
          } catch (IllegalStateException e) {
            // Silent catch
          }
          if (ostream != null) {
            copy(resource, ostream, range);
          } else {
            // we should not get here
            throw new IllegalStateException();
          }
        }
      } else {
        response.setContentType("multipart/byteranges; boundary=" + mimeSeparation);
        if (serveContent) {
          try {
            response.setBufferSize(output);
          } catch (IllegalStateException e) {
            // Silent catch
          }
          if (ostream != null) {
            copy(resource, ostream, ranges.iterator(), contentType);
          } else {
            // we should not get here
            throw new IllegalStateException();
          }
        }
      }
    }
  }