1 /*
2 * SessionViewPdf.cpp
3 *
4 * Copyright (C) 2021 by RStudio, PBC
5 *
6 * Unless you have received this program directly from RStudio pursuant
7 * to the terms of a commercial license agreement with RStudio, then
8 * this program is licensed to you under the terms of version 3 of the
9 * GNU Affero General Public License. This program is distributed WITHOUT
10 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
11 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
12 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
13 *
14 */
15
16 #include "SessionViewPdf.hpp"
17
18 #include <shared_core/Error.hpp>
19 #include <shared_core/FilePath.hpp>
20 #include <core/Exec.hpp>
21
22 #include <core/http/Util.hpp>
23
24 #include <session/SessionModuleContext.hpp>
25
26 #define kPdfJsPath "/pdf_js/"
27
28 using namespace rstudio::core;
29
30 namespace rstudio {
31 namespace session {
32 namespace modules {
33 namespace tex {
34 namespace view_pdf {
35
36 namespace {
37
handleViewPdf(const http::Request & request,http::Response * pResponse)38 void handleViewPdf(const http::Request& request, http::Response* pResponse)
39 {
40 // get the file path
41 FilePath filePath(request.queryParamValue("path"));
42 if (!filePath.exists() || !module_context::isPathViewAllowed(filePath))
43 {
44 pResponse->setNotFoundError(request);
45 return;
46 }
47
48 // send it back
49 pResponse->setNoCacheHeaders();
50 pResponse->setFile(filePath, request);
51 pResponse->setContentType("application/pdf");
52 }
53
handlePdfJs(const http::Request & request,http::Response * pResponse)54 void handlePdfJs(const http::Request& request, http::Response* pResponse)
55 {
56 std::string path("pdfjs/");
57 path.append(http::util::pathAfterPrefix(request, kPdfJsPath));
58 if (request.queryString().find("file=") != std::string::npos &&
59 request.queryString() != "file=")
60 {
61 // when a file is specified, we expect it to be empty; deny requests for
62 // specific files (we don't want arbitrary URLs to be loaded)
63 pResponse->setError(
64 http::status::BadRequest,
65 "Incorrect parameters");
66 return;
67 }
68
69 core::FilePath pdfJsResource = options().rResourcesPath().completeChildPath(path);
70 if (pdfJsResource.exists())
71 {
72 pResponse->setCacheableFile(pdfJsResource, request);
73 return;
74 }
75 }
76
77 } // anonymous namespace
78
createViewPdfUrl(const core::FilePath & filePath)79 std::string createViewPdfUrl(const core::FilePath& filePath)
80 {
81 return "view_pdf?path=" + http::util::urlEncode(
82 filePath.getAbsolutePath(),
83 true);
84 }
85
initialize()86 Error initialize()
87 {
88 // install rpc methods
89 using boost::bind;
90 using namespace module_context;
91 ExecBlock initBlock;
92 initBlock.addFunctions()
93 (bind(registerUriHandler, "/view_pdf", handleViewPdf))
94 (bind(registerUriHandler, kPdfJsPath, handlePdfJs))
95 ;
96 return initBlock.execute();
97 }
98
99 } // namespace view_pdf
100 } // namespace tex
101 } // namespace modules
102 } // namespace session
103 } // namespace rstudio
104
105