felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rickh...@apache.org
Subject svn commit: r604675 - in /felix/sandbox/rickhall/httpserver: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/felix/ src/main/java/org/apache/felix/sandbox/ src/main/java/org/apache/felix/sandbox/ht...
Date Sun, 16 Dec 2007 19:47:21 GMT
Author: rickhall
Date: Sun Dec 16 11:47:19 2007
New Revision: 604675

URL: http://svn.apache.org/viewvc?rev=604675&view=rev
Log:
Messing around with a very simple HTTP server implementation. Currently,
this only supports file-based requests.

Added:
    felix/sandbox/rickhall/httpserver/   (with props)
    felix/sandbox/rickhall/httpserver/pom.xml   (with props)
    felix/sandbox/rickhall/httpserver/src/
    felix/sandbox/rickhall/httpserver/src/main/
    felix/sandbox/rickhall/httpserver/src/main/java/
    felix/sandbox/rickhall/httpserver/src/main/java/org/
    felix/sandbox/rickhall/httpserver/src/main/java/org/apache/
    felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/
    felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/
    felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/
    felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Activator.java   (with props)
    felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Connection.java   (with props)
    felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HelperInputStream.java   (with props)
    felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HttpRequest.java   (with props)
    felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HttpResponse.java   (with props)
    felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HttpServer.java   (with props)
    felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Logger.java   (with props)
    felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Main.java   (with props)
    felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/ThreadGate.java   (with props)
    felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/ThreadPool.java   (with props)
    felix/sandbox/rickhall/httpserver/src/main/resources/
    felix/sandbox/rickhall/httpserver/src/main/resources/META-INF/
    felix/sandbox/rickhall/httpserver/src/main/resources/META-INF/LICENSE
    felix/sandbox/rickhall/httpserver/src/main/resources/META-INF/NOTICE

Propchange: felix/sandbox/rickhall/httpserver/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Sun Dec 16 11:47:19 2007
@@ -0,0 +1,18 @@
+classes
+target
+*.log
+*.ipr
+*.iws
+*.iml
+lib
+bundle
+dist
+.project
+.classpath
+bin
+build
+.settings
+.wtpmodules
+.deployables
+nbproject
+

Added: felix/sandbox/rickhall/httpserver/pom.xml
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/httpserver/pom.xml?rev=604675&view=auto
==============================================================================
--- felix/sandbox/rickhall/httpserver/pom.xml (added)
+++ felix/sandbox/rickhall/httpserver/pom.xml Sun Dec 16 11:47:19 2007
@@ -0,0 +1,54 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you 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.
+-->
+<project>
+  <parent>
+    <groupId>org.apache.felix</groupId>
+    <artifactId>felix</artifactId>
+    <version>1.0.0</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <packaging>bundle</packaging>
+  <name>Apache Felix HTTP Server</name>
+  <description>A simple HTTP server.</description>
+  <artifactId>org.apache.felix.sandbox.httpserver</artifactId>
+  <dependencies>
+    <dependency>
+      <groupId>${pom.groupId}</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <version>1.0.0</version>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>1.0.0</version>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Private-Package>org.apache.felix.sandbox.httpserver.*</Private-Package>
+            <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
+            <Bundle-Activator>org.apache.felix.sandbox.httpserver.Activator</Bundle-Activator>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>

Propchange: felix/sandbox/rickhall/httpserver/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Activator.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Activator.java?rev=604675&view=auto
==============================================================================
--- felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Activator.java (added)
+++ felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Activator.java Sun Dec 16 11:47:19 2007
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.sandbox.httpserver;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Simple activator to start/stop the HTTP server.
+**/
+public class Activator implements BundleActivator
+{
+    private HttpServer m_server;
+    
+    public void start(BundleContext context) throws Exception
+    {
+        m_server = new HttpServer(null);
+        m_server.start();
+    }
+
+    public void stop(BundleContext context) throws Exception
+    {
+        m_server.stop();
+    }
+}

Propchange: felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Activator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Connection.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Connection.java?rev=604675&view=auto
==============================================================================
--- felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Connection.java (added)
+++ felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Connection.java Sun Dec 16 11:47:19 2007
@@ -0,0 +1,237 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.sandbox.httpserver;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.Socket;
+
+/**
+ * This class represents an accepted connection between the server and
+ * a client. It supports persistent connections for both HTTP 1.0 and 1.1
+ * clients. A given persistent connection is limited in the number of
+ * consecutive requests it is allowed to make before having its connection
+ * closed as well as after a period of inactivity.
+**/
+public class Connection
+{
+    public static final int DEFAULT_CONNECTION_TIMEOUT = 10000;
+    public static final int DEFAULT_CONNECTION_REQUESTLIMIT = 50;
+
+    private HttpServer m_server;
+    private Socket m_socket;
+    private HelperInputStream m_is;
+    private OutputStream m_os;
+    private int m_requestCount = 0;
+    private int m_requestLimit;
+
+    /**
+     * Constructs a connection with a default inactivity timeout and request limit.
+     * @param server The web server associated with the connection.
+     * @param socket The client socket.
+     * @throws java.io.IOException If any I/O error occurs.
+    **/
+    public Connection(HttpServer server, Socket socket)
+        throws IOException
+    {
+        this(server, socket, DEFAULT_CONNECTION_TIMEOUT, DEFAULT_CONNECTION_REQUESTLIMIT);
+    }
+
+    /**
+     * Constructs a connection with the specified inactivity timeout and request limit.
+     * @param server The web server associated with the connection.
+     * @param socket The client socket.
+     * @param timeout The inactivity timeout of the connection in milliseconds.
+     * @param requestLimit The maximum number of consecutive requests.
+     * @throws java.io.IOException If any I/O error occurs.
+     */
+    public Connection(HttpServer server, Socket socket, int timeout, int requestLimit)
+        throws IOException
+    {
+        m_server = server;
+        m_socket = socket;
+        m_socket.setSoTimeout(timeout);
+        m_socket.setTcpNoDelay(true);
+        m_requestLimit = requestLimit;
+        try
+        {
+            m_is = new HelperInputStream(new BufferedInputStream(m_socket.getInputStream()));
+            m_os = new BufferedOutputStream(m_socket.getOutputStream());
+        }
+        catch (IOException ex)
+        {
+            // Make sure we close any opened socket/streams.
+            try
+            {
+                m_socket.close();
+            }
+            catch (IOException ex2)
+            {
+                Logger.log("Error closing socket.", ex);
+            }
+            if (m_is != null)
+            {
+                try
+                {
+                    m_is.close();
+                }
+                catch (IOException ex2)
+                {
+                    Logger.log("Error closing socket input stream.", ex2);
+                }
+            }
+            if (m_os != null)
+            {
+                try
+                {
+                    m_os.close();
+                }
+                catch (IOException ex2)
+                {
+                    Logger.log("Error closing socket output stream.", ex2);
+                }
+            }
+            throw ex;
+        }
+    }
+
+    /**
+     * Performs the actual servicing of the connection and its subsequent requests.
+     * This method will be called by threads in the thread pool. This method
+     * typically exits when the connection is closed due to either an explicit
+     * connection close, the inactivity timeout expires, the maximum request
+     * limit was reached, or an I/O error occurred. When this method returns,
+     * the associated socket will be closed, regardless of whether or not an
+     * expection was thrown.
+     * @throws java.net.SocketTimeoutException If the inactivity timeout expired
+     *         while trying to read from the socket.
+     * @throws java.io.IOException If any I/O error occurs.
+    **/
+    public void process() throws IOException
+    {
+        HttpRequest req = new HttpRequest();
+        HttpResponse res = new HttpResponse(m_server, req);
+
+        try
+        {
+            // Loop until we close the connection.
+            boolean close = false;
+            while (!close)
+            {
+                // Read the next request.
+                req.parseRequestLine(m_is);
+                m_requestCount++;
+
+                // Keep track of whether we have errored or not,
+                // because we still want to read the bytes to clear
+                // the input stream so we can service more requests.
+                boolean error = false;
+
+                Logger.log("Processing request ("
+                    + (m_requestLimit - m_requestCount)
+                    + " remaining) : " + req.getURI());
+
+                // If client is HTTP/1.1, then send continue message.
+                if (req.getVersion().equals(HttpRequest.HTTP11_VERSION))
+                {
+                    HttpResponse.sendContinueResponse(m_os);
+                }
+
+                // Read the header lines of the request.
+                req.parseHeaderLines(m_is);
+
+                // If we have an HTTP/1.0 request without the connection set to
+                // keep-alive or we explicitly have a request to close the connection,
+                // then set close flag to exit the loop rather than trying to read
+                // more requests.
+                String v = req.getHeader(HttpRequest.CONNECTION_HEADER);
+                if ((req.getVersion().equals(HttpRequest.HTTP10_VERSION)
+                    && ((v == null) || (!v.equalsIgnoreCase(HttpRequest.KEEPALIVE_VALUE))))
+                    || ((v != null) && v.equalsIgnoreCase(HttpRequest.CLOSE_VALUE)))
+                {
+                    close = true;
+                }
+                // If we have serviced the maximum number of requests for
+                // this connection, then set close flag so we exit the loop
+                // and close the connection.
+                else if (m_requestCount >= m_requestLimit)
+                {
+                    close = true;
+                }
+
+                // We only service GET and/or HEAD requests, so send
+                // a "not implemented" error otherwise.
+                if (!req.getMethod().equals(HttpRequest.GET_REQUEST)
+                    && !req.getMethod().equals(HttpRequest.HEAD_REQUEST))
+                {
+                    error = true;
+                    HttpResponse.sendNotImplementedResponse(m_os, close);
+                }
+
+                // Ignore if we have already errored, otherwise send error message
+                // if an HTTP/1.1 client did not include HOST header.
+                if (!error && req.getVersion().equals(HttpRequest.HTTP11_VERSION)
+                    && (req.getHeader(HttpRequest.HOST_HEADER) == null))
+                {
+                    error = true;
+                    HttpResponse.sendMissingHostResponse(m_os, close);
+                }
+
+                // Read in any body and ignore.
+                req.parseBody(m_is);
+
+                // Only try to send the file/directory if there was no error.
+                if (!error)
+                {
+                    res.sendFileOrDirectory(m_os, close);
+                }
+            }
+        }
+        finally
+        {
+            try
+            {
+                m_is.close();
+            }
+            catch (IOException ex)
+            {
+                Logger.log("Error closing socket input stream.", ex);
+            }
+            try
+            {
+                m_os.close();
+            }
+            catch (IOException ex)
+            {
+                Logger.log("Error closing socket output stream.", ex);
+            }
+            try
+            {
+                m_socket.close();
+            }
+            catch (IOException ex)
+            {
+                Logger.log("Error closing socket.", ex);
+            }
+        }
+    }
+}
\ No newline at end of file

Propchange: felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Connection.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HelperInputStream.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HelperInputStream.java?rev=604675&view=auto
==============================================================================
--- felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HelperInputStream.java (added)
+++ felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HelperInputStream.java Sun Dec 16 11:47:19 2007
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.sandbox.httpserver;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Simple utility input stream class that provides a method for reading
+ * a line of characters, where a "line" is leniently defined as anything
+ * ending in '\n' or '\r\n'.
+**/
+public class HelperInputStream extends InputStream
+{
+    private InputStream m_is;
+    private StringBuffer m_sb = new StringBuffer();
+
+    public HelperInputStream(InputStream is)
+    {
+        m_is = is;
+    }
+
+    public int available() throws IOException
+    {
+        return m_is.available();
+    }
+
+    public void close() throws IOException
+    {
+        m_is.close();
+    }
+
+    public void mark(int readlimit)
+    {
+        m_is.mark(readlimit);
+    }
+
+    public boolean markSupported()
+    {
+        return m_is.markSupported();
+    }
+
+    public int read() throws IOException
+    {
+        return m_is.read();
+    }
+
+    public int read(byte[] b) throws IOException
+    {
+        return m_is.read(b);
+    }
+
+    public int read(byte[] b, int off, int len) throws IOException
+    {
+        return m_is.read(b, off, len);
+    }
+
+    public String readLine() throws IOException
+    {
+        m_sb.delete(0, m_sb.length());
+        int bytesRead = 0;
+        for (int i = m_is.read(); i >= 0; i = m_is.read())
+        {
+            bytesRead++;
+            if ('\n' == (char) i)
+            {
+                break;
+            }
+            else if ('\r' != (char) i)
+            {
+                m_sb.append((char) i);
+            }
+        }
+        if (bytesRead == 0)
+        {
+            return null;
+        }
+        return m_sb.toString();
+    }
+
+    public void reset() throws IOException
+    {
+        m_is.reset();
+    }
+
+    public long skip(long n) throws IOException
+    {
+        return m_is.skip(n);
+    }
+}
\ No newline at end of file

Propchange: felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HelperInputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HttpRequest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HttpRequest.java?rev=604675&view=auto
==============================================================================
--- felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HttpRequest.java (added)
+++ felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HttpRequest.java Sun Dec 16 11:47:19 2007
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.sandbox.httpserver;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+/**
+ * This class represents an HTTP request, which is parses from a given
+ * input stream.
+**/
+public class HttpRequest
+{
+    public static final String GET_REQUEST = "GET";
+    public static final String HEAD_REQUEST = "HEAD";
+    public static final String HTTP10_VERSION = "HTTP/1.0";
+    public static final String HTTP11_VERSION = "HTTP/1.1";
+    public static final String HOST_HEADER = "Host";
+    public static final String CONNECTION_HEADER = "Connection";
+    public static final String CONTENTLENGTH_HEADER = "Content-Length";
+    public static final String KEEPALIVE_VALUE = "keep-alive";
+    public static final String CLOSE_VALUE = "close";
+
+    private String m_method;
+    private String m_uriHost;
+    private String m_uri;
+    private String m_version;
+    private Map m_headers = new HashMap();
+
+    /**
+     * This method parses the HTTP request line from the specified input stream
+     * and stores the result.
+     * @param is The input stream from which to read the HTTP request.
+     * @throws java.io.IOException If any I/O error occurs.
+    **/
+    public void parseRequestLine(HelperInputStream is) throws IOException
+    {
+        String requestLine = is.readLine();
+        if (requestLine == null)
+        {
+            throw new IOException("Unexpected end of file when reading request line.");
+        }
+        StringTokenizer st = new StringTokenizer(requestLine, " ");
+        if (st.countTokens() != 3)
+        {
+            throw new IOException("Malformed HTTP request: " + requestLine);
+        }
+        m_method = st.nextToken();
+        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);
+        }
+    }
+
+    /**
+     * This method parses the HTTP header lines from the specified input stream
+     * and stores the results.
+     * @param is The input stream from which to read the HTTP header lines.
+     * @throws java.io.IOException If any I/O error occurs.
+    **/
+    public void parseHeaderLines(HelperInputStream is) throws IOException
+    {
+        for (String s = is.readLine(); (s != null) && (s.length() != 0); s = is.readLine())
+        {
+            int idx = s.indexOf(":");
+            if (idx > 0)
+            {
+                String header = s.substring(0, idx).trim();
+                String value = s.substring(idx + 1).trim();
+                m_headers.put(header.toLowerCase(), value);
+            }
+        }
+    }
+
+    /**
+     * This method parses the HTTP body from the specified input stream
+     * and ignores the result.
+     * @param is The input stream from which to read the HTTP body.
+     * @throws java.io.IOException If any I/O error occurs.
+    **/
+    public void parseBody(HelperInputStream is) throws IOException
+    {
+        // If there is any body, just read it in and ignore it.
+        if (getHeader(CONTENTLENGTH_HEADER) != null)
+        {
+            int length = 0;
+            try
+            {
+                length = Integer.parseInt((String) getHeader(CONTENTLENGTH_HEADER));
+            }
+            catch (NumberFormatException ex)
+            {
+                throw new IOException("Unable to parse content length.");
+            }
+            for (int i = 0; i < length; i++)
+            {
+                int ignore = is.read();
+            }
+        }
+    }
+
+    /**
+     * Returns the parsed HTTP request method.
+     * @return The parsed HTTP request method.
+    **/
+    public String getMethod()
+    {
+        return m_method;
+    }
+
+    /**
+     * Returns the parsed HTTP request URI host.
+     * @return The parsed HTTP request URI host.
+    **/
+    public String getURIHost()
+    {
+        return m_uriHost;
+    }
+
+    /**
+     * Returns the parsed HTTP request URI path.
+     * @return The parsed HTTP request URI path.
+    **/
+    public String getURI()
+    {
+        return m_uri;
+    }
+
+    /**
+     * Returns the parsed HTTP version.
+     * @return The parsed HTTP version.
+    **/
+    public String getVersion()
+    {
+        return m_version;
+    }
+
+    /**
+     * Returns the value of the specified header, if present.
+     * @param header The header value to retrieve.
+     * @return The value of the specified header or <tt>null</tt>.
+    **/
+    public String getHeader(String header)
+    {
+        return (String) m_headers.get(header.toLowerCase());
+    }
+}
\ No newline at end of file

Propchange: felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HttpRequest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HttpResponse.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HttpResponse.java?rev=604675&view=auto
==============================================================================
--- felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HttpResponse.java (added)
+++ felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HttpResponse.java Sun Dec 16 11:47:19 2007
@@ -0,0 +1,364 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.sandbox.httpserver;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * This class represents an HTTP response and handles sending properly
+ * formatted responses to HTTP requests.
+**/
+public class HttpResponse
+{
+    private HttpServer m_server;
+    private HttpRequest m_req;
+    private SimpleDateFormat m_dateFormat;
+
+    /**
+     * Constructs an HTTP response for the specified server and request.
+     * @param server The web server associated with the response.
+     * @param req The HTTP request associated with the response.
+    **/
+    public HttpResponse(HttpServer server, HttpRequest req)
+    {
+        m_server = server;
+        m_req = req;
+        m_dateFormat = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z");
+        m_dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
+    }
+
+    /**
+     * A utility method to send the contents of the file or directory
+     * corresponding to the response's associated HTTP request.
+     * @param os The output stream on which the response is to be sent.
+     * @param close A flag indicating whether or not to send connection close header.
+     * @throws java.io.IOException If any I/O error occurs.
+    **/
+    public void sendFileOrDirectory(OutputStream os, boolean close)
+        throws IOException
+    {
+        String uri = m_req.getURI();
+        File file = new File(m_server.getWebRoot(), uri);
+        if (file.exists())
+        {
+            if (file.isDirectory())
+            {
+                if (!uri.endsWith("/"))
+                {
+                    sendMovedPermanently(os, close, m_server.getHostname(), m_server.getPort(), uri + "/");
+                }
+                else
+                {
+                    // Check if there is an index.html file. If so, return that
+                    // instead of the directory.
+                    File index = new File(file, "index.html");
+                    if (index.exists())
+                    {
+                        sendFile(os, close, index, m_req.getMethod(), m_dateFormat);
+                    }
+                    else
+                    {
+                        sendDirectory(os, close, file, m_req.getURI(), m_req.getMethod(), m_dateFormat);
+                    }
+                }
+            }
+            else
+            {
+                sendFile(os, close, file, m_req.getMethod(), m_dateFormat);
+            }
+        }
+        else
+        {
+            if (close)
+            {
+                os.write(m_notFoundResponseClose404.getBytes());
+            }
+            else
+            {
+                os.write(m_notFoundResponse404.getBytes());
+            }
+            os.flush();
+        }
+    }
+
+    /**
+     * Static utility method to send the contents of a directory.
+     * @param os The output stream on which the response is to be sent.
+     * @param close A flag indicating whether or not to send connection close header.
+     * @param dir The directory whose contents should be sent.
+     * @param uri The URI of the request.
+     * @param method The request method (i.e., GET or HEAD);
+     * @param df The date formatter for output the correct date format.
+     * @throws java.io.IOException If any I/O error occurs.
+    **/
+    private static void sendDirectory(
+        OutputStream os, boolean close, File dir, String uri, String method, DateFormat df)
+        throws IOException
+    {
+        // Determine parent directory.
+        String parentDir;
+        if (uri.equals("/"))
+        {
+            // Special case, parent of "/" is "/".
+            parentDir = "/";
+        }
+        else
+        {
+            // Otherwise, get the entire path minus the last element.
+            parentDir = uri.substring(0, uri.length() - 1);
+            parentDir = (parentDir.lastIndexOf("/") < 0)
+                ? parentDir
+                : parentDir.substring(0, parentDir.lastIndexOf("/") + 1);
+        }
+        File[] children = dir.listFiles();
+        StringBuffer sb = new StringBuffer();
+        sb.append("<html>\n");
+        sb.append("<a href=\"");
+        sb.append(parentDir);
+        sb.append("\">[parent directory]</a><br>\n");
+        for (int i = 0; i < children.length; i++)
+        {
+            sb.append("<a href=\"");
+            sb.append(children[i].getName());
+            if (children[i].isDirectory())
+            {
+                sb.append("/");
+            }
+            sb.append("\">");
+            sb.append(children[i].getName());
+            if (children[i].isDirectory())
+            {
+                sb.append("/");
+            }
+            sb.append("</a><br>\n");
+        }
+        sb.append("</html>\n");
+        int length = sb.length();
+        if (method.equals(HttpRequest.HEAD_REQUEST))
+        {
+            sb.delete(0, sb.length());
+        }
+        sb.insert(0, "\r\n");
+        if (close)
+        {
+            sb.insert(0, "Connection: close\r\n");
+        }
+        else
+        {
+            sb.insert(0, "Connection: keep-alive\r\n");
+        }
+        sb.insert(0, "\r\n");
+        sb.insert(0, df.format(new Date(dir.lastModified())));
+        sb.insert(0, "Last-Modified: ");
+        sb.insert(0, "\r\n");
+        sb.insert(0, df.format(new Date()));
+        sb.insert(0, "Date: ");
+        sb.insert(0, "Content-Type: text/html\r\n");
+        sb.insert(0, "\r\n");
+        sb.insert(0, length);
+        sb.insert(0, "Content-Length: ");
+        sb.insert(0, "HTTP/1.1 200 OK\r\n");
+        os.write(sb.toString().getBytes());
+        os.flush();
+    }
+
+    /**
+     * Static utility method to send the contents of a file.
+     * @param os The output stream on which the response is to be sent.
+     * @param close A flag indicating whether or not to send connection close header.
+     * @param file The file whose contents should be sent.
+     * @param method The request method (i.e., GET or HEAD);
+     * @param df The date formatter for output the correct date format.
+     * @throws java.io.IOException If any I/O error occurs.
+    **/
+    private static void sendFile(
+        OutputStream os, boolean close, File file, String method, DateFormat df)
+        throws IOException
+    {
+        BufferedInputStream bis = null;
+        try
+        {
+            StringBuffer sb = new StringBuffer();
+            sb.append("HTTP/1.1 200 OK\r\n");
+            sb.append("Content-Length: ");
+            sb.append(file.length());
+            sb.append("\r\n");
+            sb.append("Last-Modified: ");
+            sb.append(df.format(new Date(file.lastModified())));
+            sb.append("\r\n");
+            sb.append("Date: ");
+            sb.append(df.format(new Date()));
+            sb.append("\r\n");
+            if (close)
+            {
+                sb.append(("Connection: close\r\n"));
+            }
+            else
+            {
+                sb.append("Connection: Keep-Alive\r\n");
+            }
+            sb.append("\r\n");
+            os.write(sb.toString().getBytes());
+            os.flush();
+            if (method.equals(HttpRequest.GET_REQUEST))
+            {
+                bis = new BufferedInputStream(new FileInputStream(file));
+                byte[] buf = new byte[1024];
+                for (int len = bis.read(buf); len >= 0; len = bis.read(buf))
+                {
+                    os.write(buf, 0, len);
+                }
+                os.flush();
+            }
+        }
+        finally
+        {
+            if (bis != null)
+            {
+                bis.close();
+            }
+        }
+    }
+
+    /**
+     * Static utility method to send a continue response.
+     * @param os The output stream on which the response is to be sent.
+     * @throws java.io.IOException If any I/O error occurs.
+    **/
+    public static void sendContinueResponse(OutputStream os) throws IOException
+    {
+        os.write(m_continueResponse100.getBytes());
+        os.flush();
+    }
+
+    /**
+     * Static utility method to send a missing host response.
+     * @param os The output stream on which the response is to be sent.
+     * @param close A flag indicating whether or not to send connection close header.
+     * @throws java.io.IOException If any I/O error occurs.
+    **/
+    public static void sendMissingHostResponse(OutputStream os, boolean close) throws IOException
+    {
+        if (close)
+        {
+            os.write(m_missingHostResponseClose400.getBytes());
+        }
+        else
+        {
+            os.write(m_missingHostResponse400.getBytes());
+        }
+        os.flush();
+    }
+
+    /**
+     * Static utility method to send a not implemented response.
+     * @param os The output stream on which the response is to be sent.
+     * @param close A flag indicating whether or not to send connection close header.
+     * @throws java.io.IOException If any I/O error occurs.
+    **/
+    public static void sendNotImplementedResponse(OutputStream os, boolean close) throws IOException
+    {
+        if (close)
+        {
+            os.write(m_notImplementedResponseClose501.getBytes());
+        }
+        else
+        {
+            os.write(m_notImplementedResponse501.getBytes());
+        }
+        os.flush();
+    }
+
+    /**
+     * Static utility method to send a moved permanently response.
+     * @param os The output stream on which the response is to be sent.
+     * @param close A flag indicating whether or not to send connection close header.
+     * @param hostname The hostname of the new location.
+     * @param port The port of the new location.
+     * @param newuri The path of the new location.
+     * @throws java.io.IOException If any I/O error occurs.
+    **/
+    public static void sendMovedPermanently(
+        OutputStream os, boolean close, String hostname, int port, String newuri)
+        throws IOException
+    {
+        StringBuffer sb = new StringBuffer();
+        sb.append("HTTP/1.1 301 Moved Permanently\r\n");
+        sb.append("Content-Length: 0\r\n");
+        if (close)
+        {
+            sb.append(("Connection: close\r\n"));
+        }
+        sb.append("Location: http://");
+        sb.append(hostname);
+        if (port != 80)
+        {
+            sb.append(':');
+            sb.append(Integer.toString(port));
+        }
+        sb.append(newuri);
+        sb.append("\r\n");
+        sb.append("\r\n");
+        os.write(sb.toString().getBytes());
+        os.flush();
+    }
+
+    private static final String m_continueResponse100 =
+        "HTTP/1.1 100 Continue\r\n\r\n";
+    private static final String m_missingHostResponse400 =
+        "HTTP/1.1 400 Bad Request\r\n"
+        + "Content-Length: 70\r\n"
+        + "Content-Type: text/html\r\n"
+        + "\r\n"
+        + "<html><h1>HTTP 1.1 requests must include the Host: header.</h1></html>";
+    private static final String m_missingHostResponseClose400 =
+        "HTTP/1.1 400 Bad Request\r\n"
+        + "Content-Length: 70\r\n"
+        + "Content-Type: text/html\r\n"
+        + "Connection: close\r\n"
+        + "\r\n"
+        + "<html><h1>HTTP 1.1 requests must include the Host: header.</h1></html>";
+    private static final String m_notImplementedResponse501 =
+        "HTTP/1.1 501 Not Implemented\r\n\r\n";
+    private static final String m_notImplementedResponseClose501 =
+        "HTTP/1.1 501 Not Implemented\r\n"
+        + "Connection: close\r\n"
+        + "\r\n";
+    private static final String m_notFoundResponse404 =
+        "HTTP/1.1 404 File Not Found\r\n"
+        + "Content-Length: 36\r\n"
+        + "Content-Type: text/html\r\n"
+        + "\r\n"
+        + "<html><h1>File Not Found</h1></html>";
+    private static final String m_notFoundResponseClose404 =
+        "HTTP/1.1 404 File Not Found\r\n"
+        + "Content-Length: 36\r\n"
+        + "Content-Type: text/html\r\n"
+        + "Connection: close\r\n"
+        + "\r\n"
+        + "<html><h1>File Not Found</h1></html>";
+}
\ No newline at end of file

Propchange: felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HttpResponse.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HttpServer.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HttpServer.java?rev=604675&view=auto
==============================================================================
--- felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HttpServer.java (added)
+++ felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HttpServer.java Sun Dec 16 11:47:19 2007
@@ -0,0 +1,345 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.sandbox.httpserver;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class implements a simple file-based, multi-threaded web server. It
+ * only supports GET/HEAD requests. The web server has various configurable
+ * properties that can be passed into the constructor; see the constructor
+ * for more information about configuration properties.
+**/
+public class HttpServer
+{
+    private static final String SERVER_PORT_PROP = "server.port";
+    private static final String SERVER_WEBROOT_PROP = "server.webroot";
+    private static final String THREADPOOL_LIMIT_PROP = "threadpool.limit";
+    private static final String THREADPOOL_TIMEOUT_PROP = "threadpool.timeout";
+    private static final String CONNECTION_REQUESTLIMIT_PROP = "connection.requestlimit";
+    private static final String CONNECTION_TIMEOUT_PROP = "connection.timeout";
+
+    private static final int DEFAULT_PORT = 8080;
+    private static final String DEFAULT_WEBROOT = "www";
+    private static final int DEFAULT_THREADPOOL_LIMIT = 10;
+
+    public static final int INACTIVE_STATE = 0;
+    public static final int ACTIVE_STATE = 1;
+    public static final int STOPPING_STATE = 2;
+
+    private String m_hostname;
+    private int m_port;
+
+    private int m_state;
+    private ThreadGate m_shutdownGate;
+
+    private Thread m_serverThread;
+    private ServerSocket m_serverSocket;
+    private ThreadPool m_threadPool;
+    private File m_webroot;
+
+    private int m_connectionTimeout;
+    private int m_connectionRequestLimit;
+
+    /**
+     * Construct a web server with the specified configuration. The configuration
+     * map may contain the following properties:
+     * <ul>
+     *   <li><tt>server.port</tt> - the port on which it listens for connections;
+     *       the default is 8080.
+     *   </li>
+     *   <li><tt>server.webroot</tt> - the directory that serves as the root of
+     *       the web site; the default is "www" in the current directory.
+     *   </li>
+     *   <li><tt>threadpool.limit</tt> - the maximum number of threads in the
+     *       thread pool; the default value is 10.
+     *   </li>
+     *   <li><tt>threadpool.timeout</tt> - the inactivity timeout for threads in
+     *       the thread pool after which time the threads will terminate; the
+     *       default value is 60000 milliseconds.
+     *   </li>
+     *   <li><tt>connection.requestlimit</tt> - the maximum number of requests that
+     *       will be accepted over a persistent connection before closing the
+     *       connection; the default value is 50.
+     *   </li>
+     *   <li><tt>connection.timeout</tt> - the inactivity timeout for persistent
+     *       connections after which the connection is closed; the default value
+     *       is 10000 milliseconds.
+     *   </li>
+     * </ul>
+     * The configuration properties cannot be changed after construction. The
+     * web server is not active until it is started.
+     * @param configMap The map of configuration properties; can be <tt>null</tt>.
+    **/
+    public HttpServer(Map configMap)
+    {
+        m_state = INACTIVE_STATE;
+
+        configMap = (configMap == null) ? new HashMap() : configMap;
+
+        // Read in the configured properties or their default values.
+        m_port = (configMap.get(SERVER_PORT_PROP) == null)
+            ? DEFAULT_PORT
+            : Integer.parseInt((String) configMap.get(SERVER_PORT_PROP));
+        m_webroot = (configMap.get(SERVER_WEBROOT_PROP) == null)
+            ? new File(DEFAULT_WEBROOT)
+            : new File((String) configMap.get(SERVER_WEBROOT_PROP));
+        int threadLimit = (configMap.get(THREADPOOL_LIMIT_PROP) == null)
+            ? DEFAULT_THREADPOOL_LIMIT
+            : Integer.parseInt((String) configMap.get(THREADPOOL_LIMIT_PROP));
+        int threadTimeout = (configMap.get(THREADPOOL_TIMEOUT_PROP) == null)
+            ? ThreadPool.DEFAULT_THREAD_TIMEOUT
+            : Integer.parseInt((String) configMap.get(THREADPOOL_TIMEOUT_PROP));
+        m_threadPool = new ThreadPool(threadLimit, threadTimeout);
+        m_connectionTimeout = (configMap.get(CONNECTION_TIMEOUT_PROP) == null)
+            ? Connection.DEFAULT_CONNECTION_TIMEOUT
+            : Integer.parseInt((String) configMap.get(CONNECTION_TIMEOUT_PROP));
+        m_connectionRequestLimit = (configMap.get(CONNECTION_REQUESTLIMIT_PROP) == null)
+            ? Connection.DEFAULT_CONNECTION_REQUESTLIMIT
+            : Integer.parseInt((String) configMap.get(CONNECTION_REQUESTLIMIT_PROP));
+    }
+
+    /**
+     * This method returns the current state of the web server, which is one
+     * of the following values:
+     * <ul>
+     *   <li><tt>HttpServer.INACTIVE_STATE</tt> - the web server is currently
+     *       not active.
+     *   </li>
+     *   <li><tt>HttpServer.ACTIVE_STATE</tt> - the web server is active and
+     *       serving files.
+     *   </li>
+     *   <li><tt>HttpServer.STOPPING_STATE</tt> - the web server is in the
+     *       process of shutting down.
+     *   </li>
+     * </li>
+     * @return The current state of the web server.
+    **/
+    public synchronized int getState()
+    {
+        return m_state;
+    }
+
+    /**
+     * Returns the hostname associated with the web server.
+     * @return The hostname associated with the web server.
+    **/
+    public synchronized String getHostname()
+    {
+        if (m_hostname == null)
+        {
+            try
+            {
+                m_hostname = InetAddress.getLocalHost().getHostName();
+            }
+            catch (UnknownHostException ex)
+            {
+                Logger.log("Unable to get hostname, setting to localhost.", ex);
+                m_hostname = "localhost";
+            }
+        }
+        return m_hostname;
+    }
+
+    /**
+     * Returns the port associated with the web server.
+     * @return The port associated with the web server.
+    **/
+    public synchronized int getPort()
+    {
+        return m_port;
+    }
+
+    /**
+     * Returns the web root associated with the web server.
+     * @return The web root associated with the web server.
+    **/
+    public synchronized File getWebRoot()
+    {
+        return m_webroot;
+    }
+
+    /**
+     * This method starts the web server if it is not already active.
+     * @throws java.io.IOException If there are any networking issues.
+     * @throws java.lang.IllegalStateException If the server is in the
+     *         <tt>HttpServer.STOPPING_STATE</tt> state.
+    **/
+    public synchronized void start() throws IOException
+    {
+        if (m_state == INACTIVE_STATE)
+        {
+            // If inactive, then create server socket, server thread, and
+            // set state to active.
+            m_serverSocket = new ServerSocket(m_port);
+            m_serverThread = new Thread(new Runnable() {
+                public void run()
+                {
+                    acceptConnections();
+                }
+            }, "HttpServer");
+            m_state = ACTIVE_STATE;
+            m_serverThread.start();
+        }
+        else if (m_state == STOPPING_STATE)
+        {
+            throw new IllegalStateException("Server is in process of stopping.");
+        }
+    }
+
+    /**
+     * This method stops the web server if it is currently active. This method
+     * will block the calling thread until the web server is completely stopped.
+     * This can potentially take a long time, since it allows all existing
+     * connections to be processed before shutting down. Subsequent calls to
+     * this method will also block the caller. If a blocked thread is interrupted,
+     * the method will release the blocked thread by throwing an interrupted
+     * exception. In such a case, the web server will still continue its
+     * shutdown process.
+     * @throws java.lang.InterruptedException If the calling thread is interrupted.
+    **/
+    public void stop() throws InterruptedException
+    {
+        ThreadGate gate = null;
+
+        synchronized (this)
+        {
+            // If we are active or stopping, allow the caller to shutdown the
+            // server socket and grab a local copy of the shutdown gate to
+            // wait for the server to stop.
+            if (m_state != INACTIVE_STATE)
+            {
+                Logger.log("Shutting down, be patient...waiting for all threads to finish.");
+
+                // If there is no shutdown gate, create one and save its
+                // reference both in the field and locally. All threads
+                // that call stop() while the server is stopping will wait
+                // on this gate.
+                if (m_shutdownGate == null)
+                {
+                    m_shutdownGate = new ThreadGate();
+                }
+                gate = m_shutdownGate;
+
+                // Close the server socket, which will cause the server thread
+                // to exit its accept() loop.
+                try
+                {
+                    m_serverSocket.close();
+                }
+                catch (IOException ex)
+                {
+                }
+            }
+        }
+
+        // Wait on gate for server thread to shutdown.
+        if (gate != null)
+        {
+            gate.await();
+        }
+    }
+
+    /**
+     * This method is the main server loop for accepting connection. This is
+     * only ever called by the server thread.
+    **/
+    private void acceptConnections()
+    {
+        // Start the thread pool.
+        m_threadPool.start();
+
+        Socket socket;
+
+        // Now listen for connections until interrupted.
+        while (m_serverSocket.isBound() && !m_serverSocket.isClosed())
+        {
+            try
+            {
+                Logger.log("Waiting for connections.");
+                socket = m_serverSocket.accept();
+                try
+                {
+                    // Create connection object and add it to the thread pool
+                    // to be serviced.
+                    Connection connection = new Connection(
+                        this, socket, m_connectionTimeout, m_connectionRequestLimit);
+                    Logger.log("Accepted a new connection.");
+                    m_threadPool.addConnection(connection);
+                }
+                catch (IOException ex)
+                {
+                    // If we have any difficulty creating the connection
+                    // then just ignore it, because the socket will be
+                    // closed in the connection constructor.
+                    Logger.log("Error creating connection.", ex);
+                }
+            }
+            catch (IOException ex)
+            {
+                Logger.log("The call to accept() terminated with an exception.", ex);
+            }
+        }
+
+        // Shutdown the server.
+        shutdown();
+    }
+
+    /**
+     * This method shuts down the server; it is only ever called by the
+     * server thread.
+    **/
+    private void shutdown()
+    {
+        Logger.log("Waiting for thread pool threads to stop.");
+
+        while (true)
+        {
+            try
+            {
+                // Wait for thread pool to stop servicing connections.
+                m_threadPool.stop();
+                break;
+            }
+            catch (InterruptedException ex)
+            {
+                // Only the server thread will call this and we don't interrupt
+                // it, so this should never happen, but just in case we will loop
+                // until the thread pool is actually stopped.
+            }
+        }
+
+        synchronized (this)
+        {
+            // Now that the thread pool is stopped, open the shutdown
+            // gate and set the state to inactive.
+            m_shutdownGate.open();
+            m_shutdownGate = null;
+            m_state = INACTIVE_STATE;
+        }
+        Logger.log("Shutdown complete.");
+    }
+}
\ No newline at end of file

Propchange: felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/HttpServer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Logger.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Logger.java?rev=604675&view=auto
==============================================================================
--- felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Logger.java (added)
+++ felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Logger.java Sun Dec 16 11:47:19 2007
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.sandbox.httpserver;
+
+/**
+ * A simple logger that prints a message along with the calling thread.
+**/
+public class Logger
+{
+    public static void log(String msg)
+    {
+        System.err.println("[" + Thread.currentThread().getName() + "] " + msg);
+    }
+
+    public static void log(String msg, Exception ex)
+    {
+        System.err.println("[" + Thread.currentThread().getName() + "] " + msg
+            + " (" + ex.getMessage() + ")");
+    }
+}
\ No newline at end of file

Propchange: felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Logger.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Main.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Main.java?rev=604675&view=auto
==============================================================================
--- felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Main.java (added)
+++ felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Main.java Sun Dec 16 11:47:19 2007
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.sandbox.httpserver;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+/**
+ * Simple launcher for the web server. Allows you to optionally specify a Java
+ * properties file on the command line to use to configure the web server. Also
+ * registers a shutdown hook with the JVM so that you can shutdown the web
+ * server using "<tt>control-C</tt>".
+**/
+public class Main
+{
+    public static void main(String[] args)
+    {
+        // Verify that we have at most one argument.
+        if (args.length > 1)
+        {
+            System.out.println("usage: [<config-properties-file>]");
+            System.exit(-1);
+        }
+
+        // If we have an argument, then make a file out of it and try
+        // to load it as a properties file.
+        File file = (args.length == 1) ? new File(args[0]) : null;
+        try
+        {
+            Properties props = null;
+            if (file != null)
+            {
+                props = new Properties();
+                FileInputStream fis = new FileInputStream(file);
+                props.load(fis);
+                fis.close();
+            }
+
+            // Create a web server instance using the properties.
+            final HttpServer server = new HttpServer(props);
+
+            // Add a shutdown hook to stop the web server.
+            Runtime.getRuntime().addShutdownHook(new Thread() {
+                public void run()
+                {
+                    try
+                    {
+                        server.stop();
+                    }
+                    catch (InterruptedException ex)
+                    {
+                        // This should not happen; the shutdown hook thread
+                        // should normally just wait until the server stops.
+                        Logger.log("Shutdown hook thread was interrupted while waiting for shutdown.");
+                    }
+                }
+            });
+
+            // Start the web server.
+            server.start();
+        }
+        catch (IOException ex)
+        {
+            Logger.log("Error starting web server.", ex);
+        }
+    }
+}
\ No newline at end of file

Propchange: felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/Main.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/ThreadGate.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/ThreadGate.java?rev=604675&view=auto
==============================================================================
--- felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/ThreadGate.java (added)
+++ felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/ThreadGate.java Sun Dec 16 11:47:19 2007
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.sandbox.httpserver;
+
+/**
+ * This class implements a simple one-shot gate for threads. The gate
+ * starts closed and will block any threads that try to wait on it. Once
+ * opened, all waiting threads will be released. The gate cannot be reused.
+**/
+public class ThreadGate
+{
+    private boolean m_open = false;
+
+    /**
+     * Open the gate and release any waiting threads.
+    **/
+    public synchronized void open()
+    {
+        m_open = true;
+        notifyAll();
+    }
+
+    /**
+     * Wait for the gate to open.
+     * @throws java.lang.InterruptedException If the calling thread is interrupted;
+     *         the gate still remains closed until opened.
+    **/
+    public synchronized void await() throws InterruptedException
+    {
+        while (!m_open)
+        {
+            wait();
+        }
+    }
+}
\ No newline at end of file

Propchange: felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/ThreadGate.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/ThreadPool.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/ThreadPool.java?rev=604675&view=auto
==============================================================================
--- felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/ThreadPool.java (added)
+++ felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/ThreadPool.java Sun Dec 16 11:47:19 2007
@@ -0,0 +1,307 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.sandbox.httpserver;
+
+import java.io.IOException;
+import java.net.SocketTimeoutException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class implements a simple thread pool for servicing HTTP connections.
+ * The thread pool does not create any threads initially, but waits for
+ * connections to be added to create threads. As connections are added, threads
+ * are only created if they are needed up until the thread limit. If threads
+ * are inactive for a period of time, then the threads terminate; the default
+ * is 60000 milliseconds.
+**/
+public class ThreadPool
+{
+    public static final int DEFAULT_THREAD_TIMEOUT = 60000;
+    private int m_threadTimeout;
+
+    public static final int INACTIVE_STATE = 0;
+    public static final int ACTIVE_STATE = 1;
+    public static final int STOPPING_STATE = 2;
+
+    private ThreadGroup m_group = new ThreadGroup("ThreadPoolGroup");
+    private int m_state;
+    private ThreadGate m_shutdownGate;
+    private int m_threadName = 0;
+    private int m_threadLimit = 0;
+    private int m_threadCount = 0;
+    private int m_threadAvailable = 0;
+    private List m_connectionList = new ArrayList();
+
+    /**
+     * Constructs a thread pool with the specified thread limit and with
+     * the default inactivity timeout.
+     * @param threadLimit The maximum number of threads in the pool.
+    **/
+    public ThreadPool(int threadLimit)
+    {
+        this(threadLimit, DEFAULT_THREAD_TIMEOUT);
+    }
+
+    /**
+     * Constructs a thread pool with the specified thread limit and inactivity
+     * timeout.
+     * @param threadLimit The maximum number of threads in the pool.
+     * @param threadTimeout The inactivity timeout for threads in milliseconds.
+    **/
+    public ThreadPool(int threadLimit, int threadTimeout)
+    {
+        m_threadLimit = threadLimit;
+        m_threadTimeout = threadTimeout;
+        m_state = INACTIVE_STATE;
+    }
+
+    /**
+     * This method returns the current state of the thread pool, which is one
+     * of the following values:
+     * <ul>
+     *   <li><tt>ThreadPool.INACTIVE_STATE</tt> - the thread pool is currently
+     *       not active.
+     *   </li>
+     *   <li><tt>ThreadPool.ACTIVE_STATE</tt> - the thread pool is active and
+     *       servicing connections.
+     *   </li>
+     *   <li><tt>ThreadPool.STOPPING_STATE</tt> - the thread pool is in the
+     *       process of shutting down.
+     *   </li>
+     * </li>
+     * @return The current state of the thread pool.
+    **/
+    public synchronized int getState()
+    {
+        return m_state;
+    }
+
+    /**
+     * Starts the thread pool if it is not already active, allowing it to
+     * service connections.
+     * @throws java.lang.IllegalStateException If the thread pool is in the
+     *         <tt>ThreadPool.STOPPING_STATE</tt> state.
+    **/
+    public synchronized void start()
+    {
+        if (m_state != STOPPING_STATE)
+        {
+            m_state = ACTIVE_STATE;
+        }
+        else
+        {
+            throw new IllegalStateException("Thread pool is in process of stopping.");
+        }
+    }
+
+    /**
+     * This method stops the thread pool if it is currently active. This method
+     * will block the calling thread until the thread pool is completely stopped.
+     * This can potentially take a long time, since it allows all existing
+     * connections to be processed before shutting down. Subsequent calls to
+     * this method will also block the caller. If a blocked thread is interrupted,
+     * the method will release the blocked thread by throwing an interrupted
+     * exception. In such a case, the thread pool will still continue its
+     * shutdown process.
+     * @throws java.lang.InterruptedException If the calling thread is interrupted.
+    **/
+    public void stop() throws InterruptedException
+    {
+        ThreadGate gate = null;
+
+        synchronized (this)
+        {
+            if (m_state != INACTIVE_STATE)
+            {
+                // If there is no shutdown gate, create one and save its
+                // reference both in the field and locally. All threads
+                // that call stop() while the server is stopping will wait
+                // on this gate.
+                if ((m_shutdownGate == null) && (m_threadCount > 0))
+                {
+                    m_shutdownGate = new ThreadGate();
+                }
+                gate = m_shutdownGate;
+                m_state = STOPPING_STATE;
+                // Interrupt all threads that have been created by the
+                // thread pool.
+                m_group.interrupt();
+            }
+        }
+
+        // Wait on gate for thread pool shutdown to complete.
+        if (gate != null)
+        {
+            gate.await();
+        }
+    }
+
+    /**
+     * This method adds an HTTP connection to the thread pool for servicing.
+     * @param connection
+     * @throws java.lang.IllegalStateException If the thread pool is not in the
+     *         <tt>ThreadPool.ACTIVE_STATE</tt> state.
+    **/
+    public synchronized void addConnection(Connection connection)
+    {
+        if (m_state == ACTIVE_STATE)
+        {
+            // Add the new connection to the connection list.
+            m_connectionList.add(connection);
+            notify();
+
+            // If there are not enough available threads to handle all outstanding
+            // connections and we still haven't reached our thread limit, then
+            // add another thread.
+            if ((m_threadAvailable < m_connectionList.size()) && (m_threadCount < m_threadLimit))
+            {
+                // Increase our thread count, but not number of available threads,
+                // since the new thread will be used to service the new connection
+                // and thus is not available.
+                m_threadCount++;
+                // Use simple integer for thread name for logging purposes.
+                if (m_threadName == Integer.MAX_VALUE)
+                {
+                    m_threadName = 1;
+                }
+                else
+                {
+                    m_threadName++;
+                }
+                // Create and start thread into our thread group.
+                new Thread(m_group, new Runnable() {
+                    public void run()
+                    {
+                        processConnections();
+                    }
+                }, Integer.toString(m_threadName)).start();
+                Logger.log("Created new thread for pool; count = "
+                    + m_threadCount + ", max = " + m_threadLimit + ".");
+            }
+        }
+        else
+        {
+            throw new IllegalStateException("The thread pool is not active.");
+        }
+    }
+
+    /**
+     * This method is the main loop for all threads servicing connections.
+    **/
+    private void processConnections()
+    {
+        Connection connection;
+        while (true)
+        {
+            synchronized (this)
+            {
+                // Any new threads entering this region are now available to
+                // process a connection, so increment the available count.
+                m_threadAvailable++;
+
+                try
+                {
+                    // Keep track of when we start to wait so that we
+                    // know if our timeout expires.
+                    long start = System.currentTimeMillis();
+                    long current = start;
+                    // Wait until there is a connection to service or until
+                    // the timeout expires; if the timeout is zero, then there
+                    // is no timeout.
+                    while ((m_connectionList.size() == 0)
+                        && ((m_threadTimeout == 0) || ((current - start) < m_threadTimeout)))
+                    {
+                        // Try to wait for another connection, but our timeout
+                        // expires then commit suicide.
+                        wait(m_threadTimeout - (current - start));
+                        current = System.currentTimeMillis();
+                    }
+                }
+                catch (InterruptedException ex)
+                {
+                    // This generally happens when we are shutting down.
+                    Thread.currentThread().interrupt();
+                }
+
+                // Set connection to null if we are going to commit suicide;
+                // otherwise get the first available connection for servicing.
+                if (m_connectionList.size() == 0)
+                {
+                    connection = null;
+                }
+                else
+                {
+                    connection = (Connection) m_connectionList.remove(0);
+                }
+
+                // Decrement number of available threads, since we will either
+                // start to service a connection at this point or we will commit
+                // suicide.
+                m_threadAvailable--;
+
+                // If we do not have a connection, then we are committing
+                // suicide due to inactivity or because we were interrupted
+                // and are stopping the thread pool.
+                if (connection == null)
+                {
+                    // One less thread in use.
+                    m_threadCount--;
+                    if (Thread.interrupted())
+                    {
+                        Logger.log("Pool thread dying due to interrupt.");
+                    }
+                    else
+                    {
+                        Logger.log("Pool thread dying due to inactivity.");
+                    }
+                    // If we are stopping and the last thread is dead, then
+                    // open the shutdown gate to release all threads waiting
+                    // for us to stop.
+                    if ((m_state == STOPPING_STATE) && (m_threadCount == 0))
+                    {
+                        m_shutdownGate.open();
+                        m_shutdownGate = null;
+                        m_state = INACTIVE_STATE;
+                    }
+                    // Return to kill the thread by exiting our run method.
+                    return;
+                }
+            }
+
+            // Otherwise, we have a connection so process it.
+            // Note, we might have outstanding connections to
+            // process even if we are stopping, so we cleaning
+            // service those remaining connections before stopping.
+            try
+            {
+                connection.process();
+                Logger.log("Connection closed normally.");
+            }
+            catch (SocketTimeoutException ex)
+            {
+                Logger.log("Connection closed due to inactivity.", ex);
+            }
+            catch (IOException ex)
+            {
+                Logger.log("Connection close due to unknown reason.", ex);
+            }
+        }
+    }
+}
\ No newline at end of file

Propchange: felix/sandbox/rickhall/httpserver/src/main/java/org/apache/felix/sandbox/httpserver/ThreadPool.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/sandbox/rickhall/httpserver/src/main/resources/META-INF/LICENSE
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/httpserver/src/main/resources/META-INF/LICENSE?rev=604675&view=auto
==============================================================================
--- felix/sandbox/rickhall/httpserver/src/main/resources/META-INF/LICENSE (added)
+++ felix/sandbox/rickhall/httpserver/src/main/resources/META-INF/LICENSE Sun Dec 16 11:47:19 2007
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.

Added: felix/sandbox/rickhall/httpserver/src/main/resources/META-INF/NOTICE
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/httpserver/src/main/resources/META-INF/NOTICE?rev=604675&view=auto
==============================================================================
--- felix/sandbox/rickhall/httpserver/src/main/resources/META-INF/NOTICE (added)
+++ felix/sandbox/rickhall/httpserver/src/main/resources/META-INF/NOTICE Sun Dec 16 11:47:19 2007
@@ -0,0 +1,5 @@
+Apache Felix HTTP Server
+Copyright 2006 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).



Mime
View raw message