• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

openmrs / openmrs-core / 23193642646

17 Mar 2026 12:13PM UTC coverage: 63.1% (-0.3%) from 63.429%
23193642646

push

github

rkorytkowski
Fixing: Fix an issue with the ModuleResourceServlet

0 of 2 new or added lines in 1 file covered. (0.0%)

925 existing lines in 17 files now uncovered.

23137 of 36667 relevant lines covered (63.1%)

0.63 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/web/src/main/java/org/openmrs/module/web/ModuleResourcesServlet.java
1
/**
2
 * This Source Code Form is subject to the terms of the Mozilla Public License,
3
 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
4
 * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
5
 * the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
6
 *
7
 * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
8
 * graphic logo is a trademark of OpenMRS Inc.
9
 */
10
package org.openmrs.module.web;
11

12
import javax.servlet.ServletException;
13
import javax.servlet.http.HttpServlet;
14
import javax.servlet.http.HttpServletRequest;
15
import javax.servlet.http.HttpServletResponse;
16
import java.io.File;
17
import java.io.FileInputStream;
18
import java.io.IOException;
19
import java.nio.file.Path;
20
import java.nio.file.Paths;
21

22
import org.openmrs.module.Module;
23
import org.openmrs.module.ModuleUtil;
24
import org.openmrs.util.OpenmrsUtil;
25
import org.slf4j.Logger;
26
import org.slf4j.LoggerFactory;
27

UNCOV
28
public class ModuleResourcesServlet extends HttpServlet {
×
29
        
30
        private static final String MODULE_PATH = "/WEB-INF/view/module/";
31
        
32
        private static final long serialVersionUID = 1239820102030344L;
33
        
UNCOV
34
        private static final Logger log = LoggerFactory.getLogger(ModuleResourcesServlet.class);
×
35
        
36
        /**
37
         * Used for caching purposes
38
         *
39
         * @see javax.servlet.http.HttpServlet#getLastModified(javax.servlet.http.HttpServletRequest)
40
         */
41
        @Override
42
        protected long getLastModified(HttpServletRequest req) {
UNCOV
43
                File f = getFile(req);
×
44
                
45
                if (f == null) {
×
UNCOV
46
                        return super.getLastModified(req);
×
47
                }
48
                
UNCOV
49
                return f.lastModified();
×
50
        }
51
        
52
        @Override
53
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
54
                
UNCOV
55
                log.debug("In service method for module servlet: " + request.getPathInfo());
×
56
                
57
                File f = getFile(request);
×
58
                if (f == null) {
×
59
                        response.setStatus(HttpServletResponse.SC_NOT_FOUND);
×
UNCOV
60
                        return;
×
61
                }
62
                
63
                response.setDateHeader("Last-Modified", f.lastModified());
×
64
                response.setContentLength(Long.valueOf(f.length()).intValue());
×
65
                String mimeType = getServletContext().getMimeType(f.getName());
×
UNCOV
66
                response.setContentType(mimeType);
×
67
                
UNCOV
68
                FileInputStream is = new FileInputStream(f);
×
69
                try {
UNCOV
70
                        OpenmrsUtil.copyFile(is, response.getOutputStream());
×
71
                }
72
                finally {
UNCOV
73
                        OpenmrsUtil.closeStream(is);
×
74
                }
UNCOV
75
        }
×
76
        
77
        /**
78
         * Turns the given request/path into a File object
79
         *
80
         * @param request the current http request
81
         * @return the file being requested or null if not found
82
         */
83
        protected File getFile(HttpServletRequest request) {
84
                
UNCOV
85
                String path = request.getPathInfo();
×
86
                
87
                Module module = ModuleUtil.getModuleForPath(path);
×
88
                if (module == null) {
×
89
                        log.warn("No module handles the path: " + path);
×
UNCOV
90
                        return null;
×
91
                }
92
                
93
                String relativePath = ModuleUtil.getPathForResource(module, path);
×
UNCOV
94
                String realPath = getServletContext().getRealPath("") + MODULE_PATH + module.getModuleIdAsPath() + "/resources"
×
95
                        + relativePath;
96

97
                String basePath;
98

99
                //if in dev mode, load resources from the development directory
UNCOV
100
                File devDir = ModuleUtil.getDevelopmentDirectory(module.getModuleId());
×
UNCOV
101
                if (devDir != null) {
×
102
                        realPath = devDir.getAbsolutePath() + "/omod/target/classes/web/module/resources" + relativePath;
×
UNCOV
103
                        basePath = devDir.getAbsolutePath() + "/omod/target/classes/web/module/resources";
×
104
                } else {
105
                        basePath = getServletContext().getRealPath("") + MODULE_PATH + module.getModuleIdAsPath() + "/resources";
×
106
                }
107

NEW
108
                Path normalizedPath = Paths.get(realPath).normalize();
×
NEW
109
                Path normalizedBase = Paths.get(basePath).normalize();
×
UNCOV
110
                if (!normalizedPath.startsWith(normalizedBase)) {
×
UNCOV
111
                        log.warn("Detected attempted directory traversal with path: " + path);
×
UNCOV
112
                        return null;
×
113
                }
114

UNCOV
115
                File f = normalizedPath.toFile();
×
UNCOV
116
                if (!f.exists()) {
×
UNCOV
117
                        log.warn("No file with path '" + normalizedPath + "' exists for module '" + module.getModuleId() + "'");
×
UNCOV
118
                        return null;
×
119
                }
120
                
UNCOV
121
                return f;
×
122
        }
123
        
124
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc