All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hudson.model.DirectoryHolder Maven / Gradle / Ivy

package hudson.model;

import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.StringTokenizer;

/**
 * Has convenience methods to serve file system.
 *
 * @author Kohsuke Kawaguchi
 */
public abstract class DirectoryHolder extends Actionable {

    /**
     * Serves a file from the file system (Maps the URL to a directory in a file system.)
     *
     * @param icon
     *      The icon file name, like "folder-open.gif"
     * @param serveDirIndex
     *      True to generate the directory index.
     *      False to serve "index.html"
     */
    protected final void serveFile(StaplerRequest req, StaplerResponse rsp, File root, String icon, boolean serveDirIndex) throws IOException, ServletException {
        if(req.getQueryString()!=null) {
            req.setCharacterEncoding("UTF-8");
            String path = req.getParameter("path");
            if(path!=null) {
                rsp.sendRedirect(URLEncoder.encode(path,"UTF-8"));
                return;
            }
        }

        String path = req.getRestOfPath();

        if(path.length()==0)
            path = "/";

        if(path.indexOf("..")!=-1 || path.length()<1) {
            // don't serve anything other than files in the artifacts dir
            rsp.sendError(HttpServletResponse.SC_BAD_REQUEST);
            return;
        }

        File f = new File(root,path.substring(1));

        boolean isFingerprint=false;
        if(f.getName().equals("*fingerprint*")) {
            f = f.getParentFile();
            isFingerprint = true;
        }

        if(!f.exists()) {
            rsp.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        if(f.isDirectory()) {
            if(!req.getRequestURL().toString().endsWith("/")) {
                rsp.sendRedirect2(req.getRequestURL().append('/').toString());
                return;
            }

            if(serveDirIndex) {
                req.setAttribute("it",this);
                List parentPaths = buildParentPath(path);
                req.setAttribute("parentPath",parentPaths);
                req.setAttribute("topPath",
                    parentPaths.isEmpty() ? "." : repeat("../",parentPaths.size()));
                req.setAttribute("files",buildChildPathList(f));
                req.setAttribute("icon",icon);
                req.setAttribute("path",path);
                req.getView(this,"dir.jelly").forward(req,rsp);
                return;
            } else {
                f = new File(f,"index.html");
            }
        }


        if(isFingerprint) {
            FileInputStream in = new FileInputStream(f);
            try {
                Hudson hudson = Hudson.getInstance();
                rsp.forward(hudson.getFingerprint(hudson.getDigestOf(in)),"/",req);
            } finally {
                in.close();
            }
        } else {
            rsp.serveFile(req,f.toURL());
        }
    }

    /**
     * Builds a list of {@link Path} that represents ancestors
     * from a string like "/foo/bar/zot".
     */
    private List buildParentPath(String pathList) {
        List r = new ArrayList();
        StringTokenizer tokens = new StringTokenizer(pathList, "/");
        int total = tokens.countTokens();
        int current=1;
        while(tokens.hasMoreTokens()) {
            String token = tokens.nextToken();
            r.add(new Path(repeat("../",total-current),token,true,0));
            current++;
        }
        return r;
    }

    /**
     * Builds a list of list of {@link Path}. The inner
     * list of {@link Path} represents one child item to be shown
     * (this mechanism is used to skip empty intermediate directory.)
     */
    private List> buildChildPathList(File cur) {
        List> r = new ArrayList>();

        File[] files = cur.listFiles();
        Arrays.sort(files,FILE_SORTER);

        for( File f : files ) {
            Path p = new Path(f.getName(),f.getName(),f.isDirectory(),f.length());
            if(!f.isDirectory()) {
                r.add(Collections.singletonList(p));
            } else {
                // find all empty intermediate directory
                List l = new ArrayList();
                l.add(p);
                String relPath = f.getName();
                while(true) {
                    // files that don't start with '.' qualify for 'meaningful files', nor SCM related files
                    File[] sub = f.listFiles(new FilenameFilter() {
                        public boolean accept(File dir, String name) {
                            return !name.startsWith(".") && !name.equals("CVS") && !name.equals(".svn");
                        }
                    });
                    if(sub.length!=1 || !sub[0].isDirectory())
                        break;
                    f = sub[0];
                    relPath += '/'+f.getName();
                    l.add(new Path(relPath,f.getName(),true,0));
                }
                r.add(l);
            }
        }

        return r;
    }

    private static String repeat(String s,int times) {
        StringBuffer buf = new StringBuffer(s.length()*times);
        for(int i=0; i FILE_SORTER = new Comparator() {
        public int compare(File lhs, File rhs) {
            // directories first, files next
            int r = dirRank(lhs)-dirRank(rhs);
            if(r!=0) return r;
            // otherwise alphabetical
            return lhs.getName().compareTo(rhs.getName());
        }

        private int dirRank(File f) {
            if(f.isDirectory())     return 0;
            else                    return 1;
        }
    };
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy