Initial attempt at moving over Oscar's Jetty-based HTTP Service implementation
(FELIX-9).


git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@395268 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.http.jetty/src/main/java/org/apache/felix/http/jetty/OsgiResourceHandler.java b/org.apache.felix.http.jetty/src/main/java/org/apache/felix/http/jetty/OsgiResourceHandler.java
new file mode 100644
index 0000000..c65c39c
--- /dev/null
+++ b/org.apache.felix.http.jetty/src/main/java/org/apache/felix/http/jetty/OsgiResourceHandler.java
@@ -0,0 +1,197 @@
+/*
+ *   Copyright 2006 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.felix.http.jetty;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.security.*;
+
+import org.mortbay.http.HttpException;
+import org.mortbay.http.HttpRequest;
+import org.mortbay.http.HttpResponse;
+import org.mortbay.http.handler.AbstractHttpHandler;
+import org.mortbay.jetty.servlet.*;
+
+/**
+ *
+ */
+public class OsgiResourceHandler extends AbstractHttpHandler
+{
+    protected org.osgi.service.http.HttpContext     m_osgiHttpContext;
+    protected String                                m_name;
+    protected OsgiServletHandler                    m_dummyHandler;
+    protected AccessControlContext                  m_acc;
+
+    
+    public OsgiResourceHandler(
+            org.osgi.service.http.HttpContext osgiHttpContext, String name,
+            AccessControlContext acc)
+    {
+        m_osgiHttpContext = osgiHttpContext;
+        m_name = name;
+        // needed for OSGi security handling
+        m_dummyHandler = new OsgiServletHandler(osgiHttpContext);
+        m_acc = acc;
+    }
+
+    
+    public void initialize(org.mortbay.http.HttpContext context)
+    {
+        super.initialize(context);
+        m_dummyHandler.initialize(context);
+    }
+
+    
+    public void handle(String pathInContext,
+                       String pathParams,
+                       HttpRequest request,
+                       HttpResponse response)
+        throws HttpException, IOException
+    {
+        Activator.debug("handle for name:" + m_name
+                + "(path=" + pathInContext + ")");
+
+        ServletHttpRequest servletRequest = new DummyServletHttpRequest(
+                m_dummyHandler, pathInContext, request);
+        ServletHttpResponse servletResponse = new DummyServletHttpResponse(
+                servletRequest, response);
+
+        if (!m_osgiHttpContext.handleSecurity(servletRequest, servletResponse))
+        {
+            // spec doesn't state specific processing here apart from 
+            // "send the response back to the client". We take this to mean
+            // any response generated in the context, and so all we do here
+            // is set handled to "true" to ensure any output is sent back
+            request.setHandled(true);
+            return;
+        }
+
+        // Create resource based name and see if we can resolve it
+        String resName = m_name + pathInContext;
+        Activator.debug("** looking for: " + resName); 
+        URL url = m_osgiHttpContext.getResource(resName);
+
+        if (url == null)
+        {
+            return;
+        }
+        
+        Activator.debug("serving up:" + resName);
+
+        // It doesn't state so in the OSGi spec, but can't see how anything
+        // other than GET and variants would be supported
+        String method=request.getMethod();
+        if (method.equals(HttpRequest.__GET) ||
+            method.equals(HttpRequest.__POST) ||
+            method.equals(HttpRequest.__HEAD))
+        {
+            handleGet(request, response, url, resName);
+        }
+        else
+        {
+            try
+            {
+                response.sendError(HttpResponse.__501_Not_Implemented);
+            }
+            catch(Exception e) {/*TODO: include error logging*/}
+        }
+    }
+
+    
+    public void handleGet(HttpRequest request, final HttpResponse response, 
+            final URL url, String resName)
+        throws IOException
+    {
+        String encoding = m_osgiHttpContext.getMimeType(resName);
+
+        if (encoding == null)
+        {
+            encoding = getHttpContext().getMimeByExtension(resName);
+        }
+
+        if (encoding == null)
+        {
+            encoding = getHttpContext().getMimeByExtension(".default");
+        }
+
+        //TODO: not sure why this is needed, but sometimes get "IllegalState"
+        // errors if not included
+        response.setAcceptTrailer(true);
+        response.setContentType(encoding);
+
+        //TODO: check other http fields e.g. ranges, timestamps etc.
+
+        // make sure we access the resource inside the bundle's access control
+        // context if supplied
+        if (System.getSecurityManager() != null)
+        {
+            try
+            {
+                AccessController.doPrivileged(new PrivilegedExceptionAction()
+                {
+                    public Object run()
+                            throws Exception
+                    {
+                        copyResourceBytes(url, response);
+                        return null;
+                    }
+                }, m_acc);
+            } 
+            catch (PrivilegedActionException ex) 
+            {
+                IOException ioe = (IOException) ex.getException();
+                throw ioe;
+            }
+        }
+        else
+        {
+            copyResourceBytes(url, response);
+        }
+
+        request.setHandled(true);
+        //TODO: set other http fields e.g. __LastModified, __ContentLength
+    }
+    
+    
+    private void copyResourceBytes(URL url, HttpResponse response)
+            throws
+                    IOException
+    {
+        OutputStream os = response.getOutputStream();
+        InputStream is = url.openStream();
+        int len = 0;
+        byte[] buf = new byte[1024];
+        int n = 0;
+
+        while ((n = is.read(buf, 0, buf.length)) >= 0)
+        {
+            os.write(buf, 0, n);
+            len += n;
+        }
+        
+        try 
+        {
+            response.setContentLength(len);
+        } 
+        catch (IllegalStateException ex) 
+        {
+            System.err.println("OsgiResourceHandler: " + ex);
+        }
+    }
+}