public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { URLConnection con = connect(); // since we end up redirecting users to jnlpJars/foo.jar/, set the content disposition // so that browsers can download them in the right file name. // see http://support.microsoft.com/kb/260519 and // http://www.boutell.com/newfaq/creating/forcedownload.html rsp.setHeader("Content-Disposition", "attachment; filename=" + fileName); InputStream in = con.getInputStream(); rsp.serveFile(req, in, con.getLastModified(), con.getContentLength(), "*.jar"); in.close(); }
/** Serves resources in the class loader. */ public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { String path = req.getRestOfPath(); if (!allowedResources.containsKey(path)) { if (!allowResourceToBeServed(path)) { rsp.sendError(SC_FORBIDDEN); return; } // remember URLs that we can serve. but don't remember error ones, as it might be unbounded allowedResources.put(path, path); } if (path.charAt(0) == '/') path = path.substring(1); URL res = classLoader.getResource(path); if (res == null) { throw HttpResponses.error( SC_NOT_FOUND, new IllegalArgumentException("No such adjunct found: " + path)); } else { long expires = MetaClass.NO_CACHE ? 0 : 24L * 60 * 60 * 1000; /*1 day*/ rsp.serveFile(req, res, expires); } }
/** * 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" * @deprecated as of 1.297 Instead of calling this method explicitly, just return the {@link * DirectoryBrowserSupport} object from the {@code doXYZ} method and let Stapler generate a * response for you. */ public void serveFile( StaplerRequest req, StaplerResponse rsp, FilePath root, String icon, boolean serveDirIndex) throws IOException, ServletException, InterruptedException { // handle form submission String pattern = req.getParameter("pattern"); if (pattern == null) pattern = req.getParameter("path"); // compatibility with Hudson<1.129 if (pattern != null) { rsp.sendRedirect2(pattern); return; } String path = getPath(req); if (path.replace('\\', '/').indexOf("/../") != -1) { // don't serve anything other than files in the artifacts dir rsp.sendError(HttpServletResponse.SC_BAD_REQUEST); return; } // split the path to the base directory portion "abc/def/ghi" which doesn't include any // wildcard, // and the GLOB portion "**/*.xml" (the rest) StringBuilder _base = new StringBuilder(); StringBuilder _rest = new StringBuilder(); int restSize = -1; // number of ".." needed to go back to the 'base' level. boolean zip = false; // if we are asked to serve a zip file bundle boolean plain = false; // if asked to serve a plain text directory listing { boolean inBase = true; StringTokenizer pathTokens = new StringTokenizer(path, "/"); while (pathTokens.hasMoreTokens()) { String pathElement = pathTokens.nextToken(); // Treat * and ? as wildcard unless they match a literal filename if ((pathElement.contains("?") || pathElement.contains("*")) && inBase && !(new FilePath(root, (_base.length() > 0 ? _base + "/" : "") + pathElement) .exists())) inBase = false; if (pathElement.equals("*zip*")) { // the expected syntax is foo/bar/*zip*/bar.zip // the last 'bar.zip' portion is to causes browses to set a good default file name. // so the 'rest' portion ends here. zip = true; break; } if (pathElement.equals("*plain*")) { plain = true; break; } StringBuilder sb = inBase ? _base : _rest; if (sb.length() > 0) sb.append('/'); sb.append(pathElement); if (!inBase) restSize++; } } restSize = Math.max(restSize, 0); String base = _base.toString(); String rest = _rest.toString(); // this is the base file/directory FilePath baseFile = new FilePath(root, base); if (baseFile.isDirectory()) { if (zip) { rsp.setContentType("application/zip"); baseFile.zip(rsp.getOutputStream(), rest); return; } if (plain) { rsp.setContentType("text/plain;charset=UTF-8"); OutputStream os = rsp.getOutputStream(); try { for (String kid : baseFile.act(new SimpleChildList())) { os.write(kid.getBytes("UTF-8")); os.write('\n'); } os.flush(); } finally { os.close(); } return; } if (rest.length() == 0) { // if the target page to be displayed is a directory and the path doesn't end with '/', // redirect StringBuffer reqUrl = req.getRequestURL(); if (reqUrl.charAt(reqUrl.length() - 1) != '/') { rsp.sendRedirect2(reqUrl.append('/').toString()); return; } } FileCallable<List<List<Path>>> glob = null; if (rest.length() > 0) { // the rest is Ant glob pattern glob = new PatternScanner(rest, createBackRef(restSize)); } else if (serveDirIndex) { // serve directory index glob = new ChildPathBuilder(); } if (glob != null) { // serve glob req.setAttribute("it", this); List<Path> parentPaths = buildParentPath(base, restSize); req.setAttribute("parentPath", parentPaths); req.setAttribute("backPath", createBackRef(restSize)); req.setAttribute("topPath", createBackRef(parentPaths.size() + restSize)); req.setAttribute("files", baseFile.act(glob)); req.setAttribute("icon", icon); req.setAttribute("path", path); req.setAttribute("pattern", rest); req.setAttribute("dir", baseFile); req.getView(this, "dir.jelly").forward(req, rsp); return; } // convert a directory service request to a single file service request by serving // 'index.html' baseFile = baseFile.child(indexFileName); } // serve a single file if (!baseFile.exists()) { rsp.sendError(HttpServletResponse.SC_NOT_FOUND); return; } boolean view = rest.equals("*view*"); if (rest.equals("*fingerprint*")) { rsp.forward(Hudson.getInstance().getFingerprint(baseFile.digest()), "/", req); return; } ContentInfo ci = baseFile.act(new ContentInfo()); if (LOGGER.isLoggable(Level.FINE)) LOGGER.fine( "Serving " + baseFile + " with lastModified=" + ci.lastModified + ", contentLength=" + ci.contentLength); InputStream in = baseFile.read(); if (view) { // for binary files, provide the file name for download rsp.setHeader("Content-Disposition", "inline; filename=" + baseFile.getName()); // pseudo file name to let the Stapler set text/plain rsp.serveFile(req, in, ci.lastModified, -1, ci.contentLength, "plain.txt"); } else { rsp.serveFile(req, in, ci.lastModified, -1, ci.contentLength, baseFile.getName()); } }