1 package org
.argeo
.cms
.internal
.kernel
;
3 import java
.io
.IOException
;
4 import java
.nio
.file
.Files
;
5 import java
.nio
.file
.Path
;
6 import java
.util
.Properties
;
8 import javax
.jcr
.Repository
;
9 import javax
.servlet
.ServletException
;
10 import javax
.servlet
.http
.HttpServletRequest
;
11 import javax
.servlet
.http
.HttpServletResponse
;
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
;
34 * Intercepts and enriches http access, mainly focusing on security and
38 public class NodeHttp
implements KernelConstants
{
39 private final static Log log
= LogFactory
.getLog(NodeHttp
.class);
41 private final BundleContext bc
= FrameworkUtil
.getBundle(getClass()).getBundleContext();
43 private ServiceTracker
<Repository
, Repository
> repositories
;
44 private final ServiceTracker
<HttpService
, HttpService
> httpServiceTracker
;
46 private String httpRealm
= "Argeo";
47 private String webDavConfig
= HttpUtils
.WEBDAV_CONFIG
;
48 // private final boolean cleanState;
51 // this.cleanState = cleanState;
52 httpServiceTracker
= new PrepareHttpStc();
53 // httpServiceTracker.open();
54 KernelUtils
.asyncOpen(httpServiceTracker
);
57 public void destroy() {
58 if (repositories
!= null)
62 public void registerRepositoryServlets(HttpService httpService
, String alias
, Repository repository
) {
63 if (httpService
== null)
64 throw new CmsException("No HTTP service available");
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
);
77 public static void unregisterRepositoryServlets(HttpService httpService
, String alias
) {
78 if (httpService
== null)
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
);
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
));
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));
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");
122 // Looks like a bug in Jackrabbit remoting init
125 tmpDir
= Files
.createTempDirectory("remoting_" + alias
);
126 } catch (IOException e
) {
127 throw new CmsException("Cannot create temp directory for remoting servlet", e
);
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
));
136 static String
webdavPath(String alias
) {
137 return NodeConstants
.PATH_DATA
+ "/" + alias
;
140 static String
remotingPath(String alias
) {
141 return NodeConstants
.PATH_JCR
+ "/" + alias
;
144 static String
filesPath(String alias
) {
145 return NodeConstants
.PATH_FILES
;
148 class RepositoriesStc
extends ServiceTracker
<Repository
, Repository
> {
149 private final HttpService httpService
;
151 private final BundleContext bc
;
153 public RepositoriesStc(BundleContext bc
, HttpService httpService
) {
154 super(bc
, Repository
.class, null);
155 this.httpService
= httpService
;
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
);
171 public void modifiedService(ServiceReference
<Repository
> reference
, Repository service
) {
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
);
184 private class PrepareHttpStc
extends ServiceTracker
<HttpService
, HttpService
> {
185 public PrepareHttpStc() {
186 super(bc
, HttpService
.class, null);
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");
201 public void removedService(ServiceReference
<HttpService
> reference
, HttpService service
) {
202 repositories
.close();
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");
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
);
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();
226 // FIXME properly publish servlets
227 //KernelUtils.asyncOpen(repositories);
229 log
.info(httpPortsMsg(httpPort
, httpsPort
));
230 // httpAvailable = true;
233 bc
.registerService(NodeHttp
.class, NodeHttp
.this, null);
237 private String
httpPortsMsg(Object httpPort
, Object httpsPort
) {
238 return (httpPort
!= null ?
"HTTP " + httpPort
+ " " : " ")
239 + (httpsPort
!= null ?
"HTTPS " + httpsPort
: "");
243 private static class WebdavServlet
extends SimpleWebdavServlet
{
244 private static final long serialVersionUID
= -4687354117811443881L;
245 private final Repository repository
;
247 public WebdavServlet(Repository repository
, SessionProvider sessionProvider
) {
248 this.repository
= repository
;
249 setSessionProvider(sessionProvider
);
252 public Repository
getRepository() {
257 protected void service(final HttpServletRequest request
, final HttpServletResponse response
)
258 throws ServletException
, IOException
{
259 WebdavServlet
.super.service(request
, response
);
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");
269 // Subject.doAs(subject, new PrivilegedExceptionAction<Void>() {
271 // public Void run() throws Exception {
272 // WebdavServlet.super.service(request, response);
276 // } catch (PrivilegedActionException e) {
277 // throw new CmsException("Cannot process webdav request",
278 // e.getException());
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
;
290 public RemotingServlet(Repository repository
, SessionProvider sessionProvider
) {
291 this.repository
= repository
;
292 this.sessionProvider
= sessionProvider
;
296 protected Repository
getRepository() {
301 protected SessionProvider
getSessionProvider() {
302 return sessionProvider
;
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
);