]> git.argeo.org Git - lgpl/argeo-commons.git/blob - internal/kernel/NodeHttp.java
Prepare next development cycle
[lgpl/argeo-commons.git] / internal / kernel / NodeHttp.java
1 package org.argeo.cms.internal.kernel;
2
3 import java.io.IOException;
4 import java.nio.file.Files;
5 import java.nio.file.Path;
6 import java.util.Properties;
7
8 import javax.jcr.Repository;
9 import javax.servlet.ServletException;
10 import javax.servlet.http.HttpServletRequest;
11 import javax.servlet.http.HttpServletResponse;
12
13 import org.apache.commons.logging.Log;
14 import org.apache.commons.logging.LogFactory;
15 import org.apache.jackrabbit.server.SessionProvider;
16 import org.apache.jackrabbit.server.remoting.davex.JcrRemotingServlet;
17 import org.apache.jackrabbit.webdav.simple.SimpleWebdavServlet;
18 import org.argeo.api.NodeConstants;
19 import org.argeo.cms.CmsException;
20 import org.argeo.cms.internal.http.CmsSessionProvider;
21 import org.argeo.cms.internal.http.DataHttpContext;
22 import org.argeo.cms.internal.http.HttpUtils;
23 import org.argeo.cms.internal.http.LinkServlet;
24 import org.argeo.cms.internal.http.PrivateHttpContext;
25 import org.argeo.cms.internal.http.RobotServlet;
26 import org.osgi.framework.BundleContext;
27 import org.osgi.framework.FrameworkUtil;
28 import org.osgi.framework.ServiceReference;
29 import org.osgi.service.http.HttpService;
30 import org.osgi.service.http.NamespaceException;
31 import org.osgi.util.tracker.ServiceTracker;
32
33 /**
34 * Intercepts and enriches http access, mainly focusing on security and
35 * transactionality.
36 */
37 @Deprecated
38 public class NodeHttp implements KernelConstants {
39 private final static Log log = LogFactory.getLog(NodeHttp.class);
40
41 private final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext();
42
43 private ServiceTracker<Repository, Repository> repositories;
44 private final ServiceTracker<HttpService, HttpService> httpServiceTracker;
45
46 private String httpRealm = "Argeo";
47 private String webDavConfig = HttpUtils.WEBDAV_CONFIG;
48 // private final boolean cleanState;
49
50 public NodeHttp() {
51 // this.cleanState = cleanState;
52 httpServiceTracker = new PrepareHttpStc();
53 // httpServiceTracker.open();
54 KernelUtils.asyncOpen(httpServiceTracker);
55 }
56
57 public void destroy() {
58 if (repositories != null)
59 repositories.close();
60 }
61
62 public void registerRepositoryServlets(HttpService httpService, String alias, Repository repository) {
63 if (httpService == null)
64 throw new CmsException("No HTTP service available");
65 try {
66 registerWebdavServlet(httpService, alias, repository);
67 registerRemotingServlet(httpService, alias, repository);
68 if (NodeConstants.EGO_REPOSITORY.equals(alias))
69 registerFilesServlet(httpService, alias, repository);
70 if (log.isTraceEnabled())
71 log.trace("Registered servlets for repository '" + alias + "'");
72 } catch (Exception e) {
73 throw new CmsException("Could not register servlets for repository '" + alias + "'", e);
74 }
75 }
76
77 public static void unregisterRepositoryServlets(HttpService httpService, String alias) {
78 if (httpService == null)
79 return;
80 try {
81 httpService.unregister(webdavPath(alias));
82 httpService.unregister(remotingPath(alias));
83 if (NodeConstants.EGO_REPOSITORY.equals(alias))
84 httpService.unregister(filesPath(alias));
85 if (log.isTraceEnabled())
86 log.trace("Unregistered servlets for repository '" + alias + "'");
87 } catch (Exception e) {
88 log.error("Could not unregister servlets for repository '" + alias + "'", e);
89 }
90 }
91
92 void registerWebdavServlet(HttpService httpService, String alias, Repository repository)
93 throws NamespaceException, ServletException {
94 // WebdavServlet webdavServlet = new WebdavServlet(repository, new
95 // OpenInViewSessionProvider(alias));
96 WebdavServlet webdavServlet = new WebdavServlet(repository, new CmsSessionProvider(alias));
97 String path = webdavPath(alias);
98 Properties ip = new Properties();
99 ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_CONFIG, webDavConfig);
100 ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, path);
101 httpService.registerServlet(path, webdavServlet, ip, new DataHttpContext(httpRealm));
102 }
103
104 void registerFilesServlet(HttpService httpService, String alias, Repository repository)
105 throws NamespaceException, ServletException {
106 WebdavServlet filesServlet = new WebdavServlet(repository, new CmsSessionProvider(alias));
107 String path = filesPath(alias);
108 Properties ip = new Properties();
109 ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_CONFIG, webDavConfig);
110 ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, path);
111 httpService.registerServlet(path, filesServlet, ip, new PrivateHttpContext(httpRealm, true));
112 }
113
114 void registerRemotingServlet(HttpService httpService, String alias, Repository repository)
115 throws NamespaceException, ServletException {
116 RemotingServlet remotingServlet = new RemotingServlet(repository, new CmsSessionProvider(alias));
117 String path = remotingPath(alias);
118 Properties ip = new Properties();
119 ip.setProperty(JcrRemotingServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, path);
120 ip.setProperty(JcrRemotingServlet.INIT_PARAM_AUTHENTICATE_HEADER, "Negotiate");
121
122 // Looks like a bug in Jackrabbit remoting init
123 Path tmpDir;
124 try {
125 tmpDir = Files.createTempDirectory("remoting_" + alias);
126 } catch (IOException e) {
127 throw new CmsException("Cannot create temp directory for remoting servlet", e);
128 }
129 ip.setProperty(RemotingServlet.INIT_PARAM_HOME, tmpDir.toString());
130 ip.setProperty(RemotingServlet.INIT_PARAM_TMP_DIRECTORY, "remoting_" + alias);
131 ip.setProperty(RemotingServlet.INIT_PARAM_PROTECTED_HANDLERS_CONFIG, HttpUtils.DEFAULT_PROTECTED_HANDLERS);
132 ip.setProperty(RemotingServlet.INIT_PARAM_CREATE_ABSOLUTE_URI, "false");
133 httpService.registerServlet(path, remotingServlet, ip, new PrivateHttpContext(httpRealm));
134 }
135
136 static String webdavPath(String alias) {
137 return NodeConstants.PATH_DATA + "/" + alias;
138 }
139
140 static String remotingPath(String alias) {
141 return NodeConstants.PATH_JCR + "/" + alias;
142 }
143
144 static String filesPath(String alias) {
145 return NodeConstants.PATH_FILES;
146 }
147
148 class RepositoriesStc extends ServiceTracker<Repository, Repository> {
149 private final HttpService httpService;
150
151 private final BundleContext bc;
152
153 public RepositoriesStc(BundleContext bc, HttpService httpService) {
154 super(bc, Repository.class, null);
155 this.httpService = httpService;
156 this.bc = bc;
157 }
158
159 @Override
160 public Repository addingService(ServiceReference<Repository> reference) {
161 Repository repository = bc.getService(reference);
162 Object jcrRepoAlias = reference.getProperty(NodeConstants.CN);
163 if (jcrRepoAlias != null) {
164 String alias = jcrRepoAlias.toString();
165 registerRepositoryServlets(httpService, alias, repository);
166 }
167 return repository;
168 }
169
170 @Override
171 public void modifiedService(ServiceReference<Repository> reference, Repository service) {
172 }
173
174 @Override
175 public void removedService(ServiceReference<Repository> reference, Repository service) {
176 Object jcrRepoAlias = reference.getProperty(NodeConstants.CN);
177 if (jcrRepoAlias != null) {
178 String alias = jcrRepoAlias.toString();
179 unregisterRepositoryServlets(httpService, alias);
180 }
181 }
182 }
183
184 private class PrepareHttpStc extends ServiceTracker<HttpService, HttpService> {
185 public PrepareHttpStc() {
186 super(bc, HttpService.class, null);
187 }
188
189 @Override
190 public HttpService addingService(ServiceReference<HttpService> reference) {
191 long begin = System.currentTimeMillis();
192 if (log.isTraceEnabled())
193 log.trace("HTTP prepare starts...");
194 HttpService httpService = addHttpService(reference);
195 if (log.isTraceEnabled())
196 log.trace("HTTP prepare duration: " + (System.currentTimeMillis() - begin) + "ms");
197 return httpService;
198 }
199
200 @Override
201 public void removedService(ServiceReference<HttpService> reference, HttpService service) {
202 repositories.close();
203 repositories = null;
204 }
205
206 private HttpService addHttpService(ServiceReference<HttpService> sr) {
207 HttpService httpService = bc.getService(sr);
208 // TODO find constants
209 Object httpPort = sr.getProperty("http.port");
210 Object httpsPort = sr.getProperty("https.port");
211
212 try {
213 httpService.registerServlet("/!", new LinkServlet(), null, null);
214 httpService.registerServlet("/robots.txt", new RobotServlet(), null, null);
215 // httpService.registerServlet("/html", new HtmlServlet(), null, null);
216 } catch (Exception e) {
217 throw new CmsException("Cannot register filters", e);
218 }
219 // track repositories
220 if (repositories != null)
221 throw new CmsException("An http service is already configured");
222 repositories = new RepositoriesStc(bc, httpService);
223 // repositories.open();
224
225 ///if (cleanState)
226 // FIXME properly publish servlets
227 //KernelUtils.asyncOpen(repositories);
228
229 log.info(httpPortsMsg(httpPort, httpsPort));
230 // httpAvailable = true;
231 // checkReadiness();
232
233 bc.registerService(NodeHttp.class, NodeHttp.this, null);
234 return httpService;
235 }
236
237 private String httpPortsMsg(Object httpPort, Object httpsPort) {
238 return (httpPort != null ? "HTTP " + httpPort + " " : " ")
239 + (httpsPort != null ? "HTTPS " + httpsPort : "");
240 }
241 }
242
243 private static class WebdavServlet extends SimpleWebdavServlet {
244 private static final long serialVersionUID = -4687354117811443881L;
245 private final Repository repository;
246
247 public WebdavServlet(Repository repository, SessionProvider sessionProvider) {
248 this.repository = repository;
249 setSessionProvider(sessionProvider);
250 }
251
252 public Repository getRepository() {
253 return repository;
254 }
255
256 @Override
257 protected void service(final HttpServletRequest request, final HttpServletResponse response)
258 throws ServletException, IOException {
259 WebdavServlet.super.service(request, response);
260 // try {
261 // Subject subject = subjectFromRequest(request);
262 // // TODO make it stronger, with eTags.
263 // // if (CurrentUser.isAnonymous(subject) &&
264 // // request.getMethod().equals("GET")) {
265 // // response.setHeader("Cache-Control", "no-transform, public,
266 // // max-age=300, s-maxage=900");
267 // // }
268 //
269 // Subject.doAs(subject, new PrivilegedExceptionAction<Void>() {
270 // @Override
271 // public Void run() throws Exception {
272 // WebdavServlet.super.service(request, response);
273 // return null;
274 // }
275 // });
276 // } catch (PrivilegedActionException e) {
277 // throw new CmsException("Cannot process webdav request",
278 // e.getException());
279 // }
280 }
281
282 }
283
284 private static class RemotingServlet extends JcrRemotingServlet {
285 private final Log log = LogFactory.getLog(RemotingServlet.class);
286 private static final long serialVersionUID = 4605238259548058883L;
287 private final Repository repository;
288 private final SessionProvider sessionProvider;
289
290 public RemotingServlet(Repository repository, SessionProvider sessionProvider) {
291 this.repository = repository;
292 this.sessionProvider = sessionProvider;
293 }
294
295 @Override
296 protected Repository getRepository() {
297 return repository;
298 }
299
300 @Override
301 protected SessionProvider getSessionProvider() {
302 return sessionProvider;
303 }
304
305 @Override
306 protected void service(final HttpServletRequest request, final HttpServletResponse response)
307 throws ServletException, IOException {
308 if (log.isTraceEnabled())
309 HttpUtils.logRequest(log, request);
310 RemotingServlet.super.service(request, response);
311 }
312 }
313
314 }