httplite: re-update code after project re-org

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1214819 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/httplite/minimum/src/main/java/org/apache/felix/httplite/osgi/Activator.java b/httplite/minimum/src/main/java/org/apache/felix/httplite/osgi/Activator.java
index a5f0cb6..8974c24 100644
--- a/httplite/minimum/src/main/java/org/apache/felix/httplite/osgi/Activator.java
+++ b/httplite/minimum/src/main/java/org/apache/felix/httplite/osgi/Activator.java
@@ -148,6 +148,8 @@
      */
 	public void stop(final BundleContext context) throws Exception
     {
+		m_server.setStopping();
+		
         if (m_httpServiceReg != null)
         {
             m_httpServiceReg.unregister();
diff --git a/httplite/minimum/src/main/java/org/apache/felix/httplite/osgi/HttpServiceImpl.java b/httplite/minimum/src/main/java/org/apache/felix/httplite/osgi/HttpServiceImpl.java
index c5ef61d..b85dded 100644
--- a/httplite/minimum/src/main/java/org/apache/felix/httplite/osgi/HttpServiceImpl.java
+++ b/httplite/minimum/src/main/java/org/apache/felix/httplite/osgi/HttpServiceImpl.java
@@ -91,6 +91,8 @@
     public void registerResources(final String alias, final String name,
         final HttpContext context) throws NamespaceException
     {
+        validateAlias(alias);
+        
         synchronized (m_servletMap)
         {
             if (m_servletMap.containsKey(alias))
@@ -160,6 +162,8 @@
         final Dictionary initparams, final HttpContext context) throws ServletException,
         NamespaceException
     {
+        validateAlias(alias);
+        
         if (m_servletMap.containsKey(alias))
         {
             throw new NamespaceException("Alias " + alias
@@ -286,7 +290,7 @@
             }
             else
             {
-                return new ResourceHandler(request, response, element);
+                return new ResourceHandler(request, response, element, m_logger);
             }
         }
 
@@ -316,4 +320,27 @@
         return new HttpServletResponseImpl(output);
     }
 
+    /**
+     * Validate that a given alias is legal.
+     * 
+     * @param alias input alias
+     * @throws NamespaceException is thrown if alias is illegal
+     */
+    private void validateAlias( String alias ) throws NamespaceException
+    {
+        if (alias == null)
+        {
+            throw new NamespaceException( "Alias is null." );
+        }
+        
+        if (alias.trim().length() == 0)
+        {
+            throw new NamespaceException( "Alias is an empty string." );
+        }
+        
+        if (!alias.startsWith( "/" )) 
+        {
+            throw new NamespaceException( "Alias must begin with '/'." );
+        }
+    }
 }
diff --git a/httplite/minimum/src/main/java/org/apache/felix/httplite/server/Connection.java b/httplite/minimum/src/main/java/org/apache/felix/httplite/server/Connection.java
index d5ffcb5..4b1d95d 100644
--- a/httplite/minimum/src/main/java/org/apache/felix/httplite/server/Connection.java
+++ b/httplite/minimum/src/main/java/org/apache/felix/httplite/server/Connection.java
@@ -181,8 +181,8 @@
                 boolean error = false;
 
                 m_logger.log(Logger.LOG_DEBUG,
-                    "Processing request (" + (m_requestLimit - m_requestCount)
-                        + " remaining) : " + request.getRequestURI());
+                    "Processing " + request.getRequestURI() + " (" + (m_requestLimit - m_requestCount)
+                        + " remaining)");
 
                 // If client is HTTP/1.1, then send continue message.
                 if (request.getProtocol().equals(HttpConstants.HTTP11_VERSION))
diff --git a/httplite/minimum/src/main/java/org/apache/felix/httplite/server/ResourceHandler.java b/httplite/minimum/src/main/java/org/apache/felix/httplite/server/ResourceHandler.java
index 323cafe..ae0be7c 100644
--- a/httplite/minimum/src/main/java/org/apache/felix/httplite/server/ResourceHandler.java
+++ b/httplite/minimum/src/main/java/org/apache/felix/httplite/server/ResourceHandler.java
@@ -22,6 +22,9 @@
 import java.io.InputStream;
 import java.net.URL;
 
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.httplite.osgi.Logger;
 import org.apache.felix.httplite.osgi.ServiceRegistration;
 import org.apache.felix.httplite.osgi.ServiceRegistrationHandler;
 import org.apache.felix.httplite.servlet.HttpConstants;
@@ -38,19 +41,22 @@
 public class ResourceHandler implements ServiceRegistrationHandler
 {
 
-    private final HttpServletRequestImpl m_request;
+    private static final String INDEX_HTML = "index.html";
+	private final HttpServletRequestImpl m_request;
     private final HttpServletResponseImpl m_response;
 
     private final HttpContext m_httpContext;
     private final String m_name;
     private final String m_alias;
+	private final Logger m_logger;
 
     /**
      * @param req HttpRequest
      * @param res HttpResponse
      * @param resource ServiceRegistration
+     * @param logger Log reference
      */
-    public ResourceHandler(final HttpServletRequestImpl req, final HttpServletResponseImpl res, final ServiceRegistration resource)
+    public ResourceHandler(final HttpServletRequestImpl req, final HttpServletResponseImpl res, final ServiceRegistration resource, final Logger logger)
     {
         if (resource.isServlet())
         {
@@ -62,7 +68,8 @@
         this.m_response = res;
         this.m_httpContext = resource.getContext();
         this.m_name = resource.getName();
-        this.m_alias = resource.getAlias();
+        this.m_alias = resource.getAlias();  
+        this.m_logger = logger;
     }
 
     /* (non-Javadoc)
@@ -75,18 +82,31 @@
         {
 
             //POST, PUT, DELETE operations not valid on resources.
+        	m_logger.log(Logger.LOG_WARNING, "Ignored client " + m_request.getMethod() + " on static resource.");
             return;
         }
 
         if (m_httpContext.handleSecurity(m_request, m_response))
         {
             String resourceName = getResourceName(m_request.getRequestURI());
-
-            URL resource = m_httpContext.getResource(resourceName);
-
+            
+            URL resource = null;
+            
+            if (resourceName.endsWith("/"))
+            {
+            	m_logger.log(Logger.LOG_DEBUG, "Appending " + INDEX_HTML + " to request " + resourceName);
+            	resource = m_httpContext.getResource(resourceName + INDEX_HTML);
+            } 
+            else 
+            {
+            	resource = m_httpContext.getResource(resourceName);	
+            }
+           
             if (resource == null)
             {
-                throw new IOException("Unable to find resource: " + resourceName);
+            	m_logger.log(Logger.LOG_INFO, "Returning HTTP 404 for request for " + resourceName);
+            	m_response.sendError(HttpServletResponse.SC_NOT_FOUND);
+            	return;
             }
 
             InputStream inputStream = resource.openStream();
diff --git a/httplite/minimum/src/main/java/org/apache/felix/httplite/server/Server.java b/httplite/minimum/src/main/java/org/apache/felix/httplite/server/Server.java
index b0b2048..926419d 100644
--- a/httplite/minimum/src/main/java/org/apache/felix/httplite/server/Server.java
+++ b/httplite/minimum/src/main/java/org/apache/felix/httplite/server/Server.java
@@ -106,6 +106,11 @@
     private final int m_connectionRequestLimit;
     private ServiceRegistrationResolver m_resolver;
     private final Logger m_logger;
+    
+	/**
+	 * Set to true when bundle is in a stopping state.  Socket errors will be ignored.
+	 */
+	private boolean m_stopping = false;
 
     /**
      * Construct a web server with the specified configuration. The configuration
@@ -344,8 +349,11 @@
             }
             catch (IOException ex)
             {
-                m_logger.log(Logger.LOG_ERROR,
-                    "The call to accept() terminated with an exception.", ex);
+            	if (!m_stopping)
+            	{
+	                m_logger.log(Logger.LOG_ERROR,
+	                    "The call to accept() terminated with an exception.", ex);
+            	}
             }
         }
 
@@ -387,4 +395,16 @@
         }
         m_logger.log(Logger.LOG_DEBUG, "Shutdown complete.");
     }
+
+	/**
+	 * Sets the stopping flag to true.  Socket exceptions will not be logged.  Method can only be called once.
+	 */
+	public void setStopping() {
+		if (m_stopping) 
+		{
+			throw new IllegalStateException("setStopping() called multiple times.");
+		}
+		
+		m_stopping  = true;
+	}
 }
\ No newline at end of file
diff --git a/httplite/minimum/src/main/java/org/apache/felix/httplite/servlet/HttpServletRequestImpl.java b/httplite/minimum/src/main/java/org/apache/felix/httplite/servlet/HttpServletRequestImpl.java
index bff22e7..e4ca6e2 100644
--- a/httplite/minimum/src/main/java/org/apache/felix/httplite/servlet/HttpServletRequestImpl.java
+++ b/httplite/minimum/src/main/java/org/apache/felix/httplite/servlet/HttpServletRequestImpl.java
@@ -197,16 +197,6 @@
         m_uri = st.nextToken();
         m_version = st.nextToken();
 
-        // If the URI is absolute, break into host and path.
-        m_uriHost = "";
-        int hostIdx = m_uri.indexOf("//");
-        if (hostIdx > 0)
-        {
-            int pathIdx = m_uri.indexOf("/", hostIdx + 2);
-            m_uriHost = m_uri.substring(hostIdx + 2, pathIdx);
-            m_uri = m_uri.substring(pathIdx);
-        }
-
         // If the URI has query string, parse it.
         int qsIdx = m_uri.indexOf("?");
         if (qsIdx > 0)
@@ -214,6 +204,47 @@
             m_queryString = m_uri.substring(qsIdx + 1);
             m_uri = m_uri.substring(0, qsIdx);
         }
+        
+        // If path contains multiple successive path separators (a//b/c a/b////c, etc.), strip them.
+        if (m_uri.indexOf( "//" ) > -1)
+        {
+            // separator
+            
+            m_uri = stripRedundantSeparators(m_uri);         
+        }
+    }
+
+    /**
+     * Remove successive '/' characters.
+     * 
+     * @param in input string
+     * @return stripped string
+     */
+    private String stripRedundantSeparators( String in )
+    {
+        StringBuffer sb = new StringBuffer();
+        boolean lastIsSeparator = false;
+
+        for (int i = 0; i < in.length(); ++i) 
+        {
+            char c = in.charAt( i );
+            
+            if (lastIsSeparator && c == '/')
+            {
+                continue;
+            }
+            
+            sb.append( c );
+            
+            if (c == '/')
+            {
+                lastIsSeparator = true;
+            } else {
+                lastIsSeparator = false;
+            }
+        }
+        
+        return sb.toString();
     }
 
     /**
@@ -230,7 +261,7 @@
      *             If any I/O error occurs.
      **/
     public void parseHeader(final ConcreteServletInputStream is) throws IOException
-    {
+    {              
         for (String s = is.readLine(); (s != null) && (s.length() != 0); s = is.readLine())
         {
             int idx = s.indexOf(":");
@@ -268,6 +299,11 @@
                 }
             }
         }
+        
+        if (m_headers.containsKey( "Host" )) 
+        {          
+            m_uriHost = m_headers.get( "Host" ).toString();         
+        }
     }
 
     /**
@@ -502,6 +538,19 @@
      */
     public Map getParameterMap()
     {
+        if (m_parameters == null)
+        {
+            try
+            {
+                m_parameters = parseParameters();
+            }
+            catch (UnsupportedEncodingException e)
+            {
+                m_logger.log(Logger.LOG_ERROR, "Failed to parse request parameters.", e);
+                return null;
+            }
+        }
+        
         return m_parameters;
     }
 
@@ -512,6 +561,19 @@
      */
     public Enumeration getParameterNames()
     {
+        if (m_parameters == null)
+        {
+            try
+            {
+                m_parameters = parseParameters();
+            }
+            catch (UnsupportedEncodingException e)
+            {
+                m_logger.log(Logger.LOG_ERROR, "Failed to parse request parameters.", e);
+                return null;
+            }
+        }
+        
         return Collections.enumeration(m_parameters.keySet());
     }
 
@@ -522,6 +584,19 @@
      */
     public String[] getParameterValues(String arg0)
     {
+        if (m_parameters == null)
+        {
+            try
+            {
+                m_parameters = parseParameters();
+            }
+            catch (UnsupportedEncodingException e)
+            {
+                m_logger.log(Logger.LOG_ERROR, "Failed to parse request parameters.", e);
+                return null;
+            }
+        }
+        
         return (String[]) m_parameters.values().toArray(new String[m_parameters.size()]);
     }
 
@@ -810,7 +885,10 @@
     public StringBuffer getRequestURL()
     {
         StringBuffer sb = new StringBuffer();
-        sb.append(m_uriHost);
+        if (m_uriHost != null)
+        {
+            sb.append(m_uriHost);
+        }
         sb.append(m_uri);
 
         return sb;
@@ -903,12 +981,12 @@
             parseParameterString(queryString, params);
         }
 
-        if (m_requestBody != null)
+        if (m_requestBody != null && m_requestBody.length > 0)
         {
             parseParameterString(new String(m_requestBody), params);
         }
 
-        return params;
+        return Collections.unmodifiableMap( params );
     }
 
     /**
@@ -957,7 +1035,7 @@
     {
         if (m_method != null && m_uri != null)
         {
-            return m_method + m_uri;
+            return m_method + " " + m_uri;
         }
 
         return super.toString();
diff --git a/httplite/minimum/src/main/java/org/apache/felix/httplite/servlet/HttpServletResponseImpl.java b/httplite/minimum/src/main/java/org/apache/felix/httplite/servlet/HttpServletResponseImpl.java
index 5c7025b..45dd509 100644
--- a/httplite/minimum/src/main/java/org/apache/felix/httplite/servlet/HttpServletResponseImpl.java
+++ b/httplite/minimum/src/main/java/org/apache/felix/httplite/servlet/HttpServletResponseImpl.java
@@ -60,7 +60,7 @@
     private boolean m_getOutputStreamCalled = false;
     private boolean m_getWriterCalled = false;
     private ServletOutputStreamImpl m_servletOutputStream;
-    private ServletPrintWriter m_servletPrintWriter;
+    private PrintWriter m_servletPrintWriter;
 
     private int m_statusCode = HttpURLConnection.HTTP_OK;
     private String m_customStatusMessage = null;
@@ -341,8 +341,7 @@
         if (m_servletPrintWriter == null)
         {
             m_buffer = new ByteArrayOutputStream(m_bufferSize);
-            m_servletPrintWriter = new ServletPrintWriter(m_buffer,
-                getCharacterEncoding());
+            m_servletPrintWriter = new PrintWriter(m_buffer);
         }
 
         return m_servletPrintWriter;
@@ -665,8 +664,12 @@
         buffer.append(' ');
         buffer.append(code);
         buffer.append(' ');
-        buffer.append("HTTP Error ");
-        buffer.append(code);
+        
+        if (code > 399)
+        {
+	        buffer.append("HTTP Error ");
+	        buffer.append(code);
+        }
         buffer.append(HttpConstants.HEADER_DELEMITER);
         if (code == 100)
         {
@@ -698,6 +701,7 @@
         //Only append error HTML messages if the return code is in the error range.
         if (code > 399)
         {
+        	//TODO: Consider disabling the HTML generation, optionally, so clients have full control of the response content.
             if (htmlStartTag == null)
             {
                 htmlStartTag = HttpConstants.DEFAULT_HTML_HEADER;