1<%-- 2CDDL HEADER START 3 4The contents of this file are subject to the terms of the 5Common Development and Distribution License (the "License"). 6You may not use this file except in compliance with the License. 7 8See LICENSE.txt included in this distribution for the specific 9language governing permissions and limitations under the License. 10 11When distributing Covered Code, include this CDDL HEADER in each 12file and include the License file at LICENSE.txt. 13If applicable, add the following below this CDDL HEADER, with the 14fields enclosed by brackets "[]" replaced with your own identifying 15information: Portions Copyright [yyyy] [name of copyright owner] 16 17CDDL HEADER END 18 19Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. 20Portions Copyright 2011 Jens Elkner. 21Portions Copyright (c) 2017-2020, Chris Fraire <cfraire@me.com>. 22 23--%> 24<%@page errorPage="error.jsp" import=" 25java.io.BufferedInputStream, 26java.io.File, 27java.io.FileInputStream, 28java.io.InputStreamReader, 29java.io.IOException, 30java.io.Reader, 31java.net.URLEncoder, 32java.nio.charset.StandardCharsets, 33java.util.List, 34java.util.Locale, 35java.util.logging.Level, 36java.util.logging.Logger, 37java.util.Set, 38java.util.TreeSet, 39org.opengrok.indexer.analysis.AnalyzerGuru, 40org.opengrok.indexer.analysis.Definitions, 41org.opengrok.indexer.analysis.AbstractAnalyzer, 42org.opengrok.indexer.analysis.AnalyzerFactory, 43org.opengrok.indexer.analysis.NullableNumLinesLOC, 44org.opengrok.indexer.history.Annotation, 45org.opengrok.indexer.index.IndexDatabase, 46org.opengrok.indexer.logger.LoggerFactory, 47org.opengrok.indexer.search.DirectoryEntry, 48org.opengrok.indexer.search.DirectoryExtraReader, 49org.opengrok.indexer.util.FileExtraZipper, 50org.opengrok.indexer.util.ForbiddenSymlinkException, 51org.opengrok.indexer.util.IOUtils, 52org.opengrok.web.DirectoryListing, 53org.opengrok.indexer.web.SearchHelper" 54%> 55<%@ page import="static org.opengrok.web.PageConfig.DUMMY_REVISION" %> 56<%@ page import="org.opengrok.indexer.web.SortOrder" %> 57<%@ page import="jakarta.servlet.http.Cookie" %> 58<% 59{ 60 // need to set it here since requesting parameters 61 if (request.getCharacterEncoding() == null) { 62 request.setCharacterEncoding("UTF-8"); 63 } 64 65 PageConfig cfg = PageConfig.get(request); 66 cfg.checkSourceRootExistence(); 67 68 String rev = cfg.getRequestedRevision(); 69 if (!cfg.isDir() && rev.length() == 0) { 70 /* 71 * Get the latest revision and redirect so that the revision number 72 * appears in the URL. 73 */ 74 String latestRevision = cfg.getLatestRevision(); 75 if (latestRevision != null) { 76 cfg.evaluateMatchOffset(); 77 String location = cfg.getRevisionLocation(latestRevision); 78 response.sendRedirect(location); 79 return; 80 } 81 if (!cfg.getEnv().isGenerateHtml()) { 82 cfg.evaluateMatchOffset(); 83 /* 84 * Economy mode is on and failed to get the last revision 85 * (presumably running with history turned off). Use dummy 86 * revision string so that xref can be generated from the resource 87 * file directly. 88 */ 89 String location = cfg.getRevisionLocation(DUMMY_REVISION); 90 response.sendRedirect(location); 91 return; 92 } 93 94 if (cfg.evaluateMatchOffset()) { 95 /* 96 * If after calling, a match offset has been translated to a 97 * fragment identifier (specifying a line#), then redirect to self. 98 * This block will not be activated again the second time. 99 */ 100 String location = cfg.getRevisionLocation(""); // empty 101 response.sendRedirect(location); 102 return; 103 } 104 } 105 106 Annotation annotation = cfg.getAnnotation(); 107 if (annotation != null) { 108 int r = annotation.getWidestRevision(); 109 int a = annotation.getWidestAuthor(); 110 cfg.addHeaderData("<style type=\"text/css\">" 111 + ".blame .r { width: " + (r == 0 ? 6 : Math.ceil(r * 0.7)) + "em; } " 112 + ".blame .a { width: " + (a == 0 ? 6 : Math.ceil(a * 0.7)) + "em; } " 113 + "</style>"); 114 } 115} 116%><%@include 117 118file="mast.jsp" 119 120%><script type="text/javascript">/* <![CDATA[ */ 121document.pageReady.push(function() { pageReadyList();}); 122/* ]]> */</script> 123<% 124/* ---------------------- list.jsp start --------------------- */ 125{ 126 final Logger LOGGER = LoggerFactory.getLogger(getClass()); 127 128 PageConfig cfg = PageConfig.get(request); 129 String rev = cfg.getRequestedRevision(); 130 Project project = cfg.getProject(); 131 132 String navigateWindowEnabled = project != null ? Boolean.toString( 133 project.isNavigateWindowEnabled()) : "false"; 134 File resourceFile = cfg.getResourceFile(); 135 String path = cfg.getPath(); 136 String basename = resourceFile.getName(); 137 String rawPath = request.getContextPath() + Prefix.DOWNLOAD_P + path; 138 Reader r = null; 139 if (cfg.isDir()) { 140 // valid resource is requested 141 // mast.jsp assures, that resourceFile is valid and not / 142 // see cfg.resourceNotAvailable() 143 String cookieValue = cfg.getRequestedProjectsAsString(); 144 String projectName = null; 145 if (project != null) { 146 projectName = project.getName(); 147 Set<String> projects = cfg.getRequestedProjects(); 148 if (!projects.contains(projectName)) { 149 projects.add(projectName); 150 // update cookie 151 cookieValue = cookieValue.length() == 0 ? projectName : 152 projectName + ',' + cookieValue; 153 Cookie cookie = new Cookie(PageConfig.OPEN_GROK_PROJECT, URLEncoder.encode(cookieValue, StandardCharsets.UTF_8)); 154 // TODO hmmm, projects.jspf doesn't set a path 155 cookie.setPath(request.getContextPath() + '/'); 156 response.addCookie(cookie); 157 } 158 } 159 // requesting a directory listing 160 DirectoryListing dl = new DirectoryListing(cfg.getEftarReader()); 161 List<String> files = cfg.getResourceFileList(); 162 if (!files.isEmpty()) { 163 List<NullableNumLinesLOC> extras = null; 164 SearchHelper searchHelper = cfg.prepareInternalSearch(SortOrder.RELEVANCY); 165 /* 166 * N.b. searchHelper.destroy() is called via 167 * WebappListener.requestDestroyed() on presence of the following 168 * REQUEST_ATTR. 169 */ 170 request.setAttribute(SearchHelper.REQUEST_ATTR, searchHelper); 171 if (project != null) { 172 searchHelper.prepareExec(project); 173 } else { 174 //noinspection Convert2Diamond 175 searchHelper.prepareExec(new TreeSet<String>()); 176 } 177 178 if (searchHelper.getSearcher() != null) { 179 DirectoryExtraReader extraReader = new DirectoryExtraReader(); 180 String primePath = path; 181 try { 182 primePath = searchHelper.getPrimeRelativePath(projectName, path); 183 } catch (IOException | ForbiddenSymlinkException ex) { 184 LOGGER.log(Level.WARNING, String.format( 185 "Error getting prime relative for %s", path), ex); 186 } 187 extras = extraReader.search(searchHelper.getSearcher(), primePath); 188 } 189 190 FileExtraZipper zipper = new FileExtraZipper(); 191 List<DirectoryEntry> entries = zipper.zip(resourceFile, files, extras); 192 193 List<String> readMes = dl.extraListTo(Util.uriEncodePath(request.getContextPath()), 194 resourceFile, out, path, entries); 195 File[] catfiles = cfg.findDataFiles(readMes); 196 for (int i=0; i < catfiles.length; i++) { 197 if (catfiles[i] == null) { 198 continue; 199 } 200%> 201<% 202 String lcName = readMes.get(i).toLowerCase(Locale.ROOT); 203 if (lcName.endsWith(".md") || lcName.endsWith(".markdown")) { 204 %><div id="src<%=i%>" data-markdown> 205 <div class="markdown-heading"> 206 <h3><%= readMes.get(i) %></h3> 207 </div> 208 <div class="markdown-content" 209 data-markdown-download="<%= request.getContextPath() + Prefix.DOWNLOAD_P + Util.uriEncodePath(cfg.getPath() + readMes.get(i)) %>"> 210 </div> 211 <pre data-markdown-original><% 212 Util.dump(out, catfiles[i], catfiles[i].getName().endsWith(".gz")); 213 %></pre> 214 </div> 215<% } else { %> 216 <h3><%= readMes.get(i) %></h3> 217 <div id="src<%=i%>"> 218 <pre><% 219 Util.dump(out, catfiles[i], catfiles[i].getName().endsWith(".gz")); 220 %></pre> 221 </div> 222<% 223 } 224 225 } 226 } 227 } else if (rev.length() != 0) { 228 // requesting a revision 229 File xrefFile; 230 if (cfg.isLatestRevision(rev) && (xrefFile = cfg.findDataFile()) != null) { 231 if (cfg.annotate()) { 232 // annotate 233 BufferedInputStream bin = new BufferedInputStream(new FileInputStream(resourceFile)); 234 try { 235 AnalyzerFactory a = AnalyzerGuru.find(basename); 236 AbstractAnalyzer.Genre g = AnalyzerGuru.getGenre(a); 237 if (g == null) { 238 a = AnalyzerGuru.find(bin); 239 g = AnalyzerGuru.getGenre(a); 240 } 241 if (g == AbstractAnalyzer.Genre.IMAGE) { 242%> 243<div id="src"> 244 <img src="<%= rawPath %>" alt="Image from Source Repository"/> 245</div><% 246 } else if ( g == AbstractAnalyzer.Genre.HTML) { 247 /* 248 * For backward compatibility, read the OpenGrok-produced 249 * document using the system default charset. 250 */ 251 r = new InputStreamReader(bin); 252 // dumpXref() is also useful here for translating links. 253 Util.dumpXref(out, r, request.getContextPath()); 254 } else if (g == AbstractAnalyzer.Genre.PLAIN) { 255%> 256<div id="src" data-navigate-window-enabled="<%= navigateWindowEnabled %>"> 257 <pre><% 258 // We're generating xref for the latest revision, so we can 259 // find the definitions in the index. 260 Definitions defs = IndexDatabase.getDefinitions(resourceFile); 261 Annotation annotation = cfg.getAnnotation(); 262 // Data under source root is read with UTF-8 as a default. 263 r = IOUtils.createBOMStrippedReader(bin, 264 StandardCharsets.UTF_8.name()); 265 AnalyzerGuru.writeDumpedXref(request.getContextPath(), a, 266 r, out, defs, annotation, project); 267 %></pre> 268</div><% 269 } else { 270%> 271Click <a href="<%= rawPath %>">download <%= basename %></a><% 272 } 273 } finally { 274 if (r != null) { 275 IOUtils.close(r); 276 bin = null; 277 } 278 if (bin != null) { 279 IOUtils.close(bin); 280 bin = null; 281 } 282 } 283 284 } else { 285%> 286<div id="src" data-navigate-window-enabled="<%= navigateWindowEnabled %>"> 287 <pre><% 288 boolean compressed = xrefFile.getName().endsWith(".gz"); 289 Util.dumpXref(out, xrefFile, compressed, 290 request.getContextPath()); 291 %></pre> 292</div> 293<% 294 } 295 } else { 296%> 297<%@ 298 299include file="xref.jspf" 300 301%> 302<% 303 } 304 } else { 305 // Requesting cross referenced file with no known revision. 306 File xrefFile = cfg.findDataFile(); 307 if (xrefFile != null) { 308%> 309<div id="src" data-navigate-window-enabled="<%= navigateWindowEnabled %>"> 310 <pre><% 311 boolean compressed = xrefFile.getName().endsWith(".gz"); 312 Util.dumpXref(out, xrefFile, compressed, request.getContextPath()); 313 %></pre> 314</div> 315<% 316 } else { 317 // Failed to get xref, generate on the fly. 318%> 319<%@ 320 321include file="xref.jspf" 322 323%> 324<% 325 } 326 } 327} 328/* ---------------------- list.jsp end --------------------- */ 329%><%@ 330 331include file="foot.jspf" 332 333%> 334