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