xref: /OpenGrok/opengrok-web/src/main/java/org/opengrok/web/api/v1/controller/FileController.java (revision aaf7676a2d3ce79aef2762ab3e0f25933daa73b3)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * See LICENSE.txt included in this distribution for the specific
9  * language governing permissions and limitations under the License.
10  *
11  * When distributing Covered Code, include this CDDL HEADER in each
12  * file and include the License file at LICENSE.txt.
13  * If applicable, add the following below this CDDL HEADER, with the
14  * fields enclosed by brackets "[]" replaced with your own identifying
15  * information: Portions Copyright [yyyy] [name of copyright owner]
16  *
17  * CDDL HEADER END
18  */
19 
20 /*
21  * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
22  * Portions Copyright (c) 2020, Chris Fraire <cfraire@me.com>.
23  */
24 package org.opengrok.web.api.v1.controller;
25 
26 import jakarta.servlet.http.HttpServletRequest;
27 import jakarta.servlet.http.HttpServletResponse;
28 import jakarta.ws.rs.GET;
29 import jakarta.ws.rs.Path;
30 import jakarta.ws.rs.Produces;
31 import jakarta.ws.rs.QueryParam;
32 import jakarta.ws.rs.core.Context;
33 import jakarta.ws.rs.core.MediaType;
34 import jakarta.ws.rs.core.StreamingOutput;
35 import org.apache.lucene.document.Document;
36 import org.apache.lucene.queryparser.classic.ParseException;
37 import org.opengrok.indexer.analysis.AbstractAnalyzer;
38 import org.opengrok.indexer.search.QueryBuilder;
39 import org.opengrok.web.api.v1.filter.CorsEnable;
40 import org.opengrok.web.api.v1.filter.PathAuthorized;
41 import org.opengrok.web.util.NoPathParameterException;
42 
43 import java.io.File;
44 import java.io.FileInputStream;
45 import java.io.FileNotFoundException;
46 import java.io.IOException;
47 import java.io.InputStream;
48 
49 import static org.opengrok.indexer.index.IndexDatabase.getDocument;
50 import static org.opengrok.web.util.FileUtil.toFile;
51 
52 @Path(FileController.PATH)
53 public class FileController {
54 
55     public static final String PATH = "/file";
56 
transfer(File file)57     private StreamingOutput transfer(File file) throws FileNotFoundException {
58         if (!file.exists()) {
59             throw new FileNotFoundException(String.format("file %s does not exist", file));
60         }
61 
62         return out -> {
63             try (InputStream in = new FileInputStream(file)) {
64                 byte[] buffer = new byte[1024];
65                 int len = in.read(buffer);
66                 while (len != -1) {
67                     out.write(buffer, 0, len);
68                     len = in.read(buffer);
69                 }
70             }
71         };
72     }
73 
74     @GET
75     @CorsEnable
76     @PathAuthorized
77     @Path("/content")
78     @Produces(MediaType.TEXT_PLAIN)
79     public StreamingOutput getContentPlain(@Context HttpServletRequest request,
80                              @Context HttpServletResponse response,
81                              @QueryParam("path") final String path) throws IOException, ParseException, NoPathParameterException {
82 
83         File file = toFile(path);
84 
85         Document doc;
86         if ((doc = getDocument(file)) == null) {
87             response.sendError(HttpServletResponse.SC_NOT_FOUND, "Cannot get document for file");
88             return null;
89         }
90 
91         String fileType = doc.get(QueryBuilder.T);
92         if (!AbstractAnalyzer.Genre.PLAIN.typeName().equals(fileType)) {
93             response.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE, "Not a text file");
94             return null;
95         }
96 
97         return transfer(file);
98     }
99 
100     @GET
101     @CorsEnable
102     @PathAuthorized
103     @Path("/content")
104     @Produces(MediaType.APPLICATION_OCTET_STREAM)
105     public StreamingOutput getContentOctets(@Context HttpServletRequest request,
106                                            @Context HttpServletResponse response,
107                                            @QueryParam("path") final String path) throws IOException, NoPathParameterException {
108 
109         File file = toFile(path);
110 
111         try {
112             return transfer(file);
113         } catch (FileNotFoundException e) {
114             response.sendError(HttpServletResponse.SC_NOT_FOUND, "Cannot find file");
115             return null;
116         }
117     }
118 
119     @GET
120     @CorsEnable
121     @PathAuthorized
122     @Path("/genre")
123     @Produces(MediaType.TEXT_PLAIN)
124     public String getGenre(@Context HttpServletRequest request,
125                            @Context HttpServletResponse response,
126                            @QueryParam("path") final String path) throws IOException, ParseException, NoPathParameterException {
127 
128         File file = toFile(path);
129 
130         Document doc;
131         if ((doc = getDocument(file)) == null) {
132             response.sendError(HttpServletResponse.SC_NOT_FOUND, "Cannot get document for file");
133             return null;
134         }
135 
136         AbstractAnalyzer.Genre genre = AbstractAnalyzer.Genre.get(doc.get(QueryBuilder.T));
137         if (genre == null) {
138             response.sendError(HttpServletResponse.SC_NOT_FOUND, "Cannot get genre from the document");
139             return null;
140         }
141 
142         return genre.toString();
143     }
144 }
145