diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2011, Aristid Breitkreuz
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Aristid Breitkreuz nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Network/HTTP/Types.hs b/Network/HTTP/Types.hs
new file mode 100644
--- /dev/null
+++ b/Network/HTTP/Types.hs
@@ -0,0 +1,264 @@
+module Network.HTTP.Types
+(
+  -- * Case insensitive HTTP ByteStrings
+  HttpCIByteString(..)
+, mkHttpCIByteString
+  -- * Methods
+, Method
+, methodGet
+, methodPost
+, methodHead
+, methodPut
+, methodDelete
+, methodTrace
+, methodConnect
+, methodOptions
+, MethodADT(GET, POST, HEAD, PUT, DELETE, TRACE, CONNECT, OPTIONS)
+, methodToADT
+, methodFromADT
+, stringToMethodADT
+, methodADTToString
+  -- * Versions
+, HttpVersion(httpMajor, httpMinor)
+, http09
+, http10
+, http11
+  -- * Status
+, Status(statusCode, statusMessage)
+, status200, statusOK
+, status201, statusCreated
+, status301, statusMovedPermanently
+, status302, statusFound
+, status303, statusSeeOther
+, status400, statusBadRequest
+, status401, statusUnauthorized
+, status403, statusForbidden
+, status404, statusNotFound
+, status405, statusNotAllowed
+, status500, statusServerError
+  -- * Headers
+, RequestHeaders
+, ResponseHeaders
+  -- * Query string
+, Query
+, QuerySimple
+)
+where
+
+import           Data.Char
+import           Data.Maybe
+import           Data.String
+import qualified Data.ByteString       as B
+import qualified Data.ByteString.Char8 as Ascii
+
+localError :: String -> String -> a
+localError f s = error $ "Network.HTTP.Types." ++ f ++ ": " ++ s
+
+-- | Case-insensitive HTTP ByteStrings, mostly for use in Header names.
+data HttpCIByteString
+    = HttpCIByteString {
+        ciOriginal :: !B.ByteString
+      , ciLowerCase :: !B.ByteString
+      }
+
+mkHttpCIByteString :: B.ByteString -> HttpCIByteString
+mkHttpCIByteString orig = HttpCIByteString {
+                            ciOriginal = orig
+                          , ciLowerCase = Ascii.map toLower orig
+                          }
+
+instance Eq HttpCIByteString where
+    HttpCIByteString { ciLowerCase = a } == HttpCIByteString { ciLowerCase = b } 
+        = a == b
+
+instance Ord HttpCIByteString where
+    compare HttpCIByteString { ciLowerCase = a } HttpCIByteString { ciLowerCase = b } 
+        = compare a b
+
+instance Show HttpCIByteString where
+    show = show . ciOriginal
+
+instance IsString HttpCIByteString where
+    fromString = mkHttpCIByteString . Ascii.pack
+
+-- | HTTP method (flat string type).
+type Method = B.ByteString
+
+-- | HTTP Method constants.
+methodGet, methodPost, methodHead, methodPut, methodDelete, methodTrace, methodConnect, methodOptions :: Method
+methodGet     = Ascii.pack "GET"
+methodPost    = Ascii.pack "POST"
+methodHead    = Ascii.pack "HEAD"
+methodPut     = Ascii.pack "PUT"
+methodDelete  = Ascii.pack "DELETE"
+methodTrace   = Ascii.pack "TRACE"
+methodConnect = Ascii.pack "CONNECT"
+methodOptions = Ascii.pack "OPTIONS"
+
+-- | HTTP method (ADT version).
+-- 
+-- Note that the Show instance is only for debugging and should NOT be used to generate HTTP method strings; use 'methodToByteString' instead.
+-- 
+-- The constructor 'OtherMethod' is not exported for forwards compatibility reasons.
+data MethodADT
+    = GET
+    | POST
+    | HEAD  
+    | PUT
+    | DELETE
+    | TRACE
+    | CONNECT
+    | OPTIONS
+    | OtherMethod B.ByteString
+    deriving (Show, Eq, Ord)
+
+-- These are ordered by suspected frequency. More popular methods should go first.
+-- The reason is that methodListA and methodListB are used with lookup.
+-- lookup is probably faster for these few cases than setting up an elaborate data structure.
+methodListA :: [(Method, MethodADT)]
+methodListA 
+    = [ (methodGet, GET)
+      , (methodPost, POST)
+      , (methodHead, HEAD)
+      , (methodPut, PUT)
+      , (methodDelete, DELETE)
+      , (methodTrace, TRACE)
+      , (methodConnect, CONNECT)
+      , (methodOptions, OPTIONS)
+      ]
+
+methodListB :: [(MethodADT, Method)]
+methodListB = map (\(a, b) -> (b, a)) methodListA
+
+-- | Convert a method 'ByteString' to a 'MethodADT'.
+methodToADT :: Method -> MethodADT
+methodToADT bs = fromMaybe (OtherMethod bs) $ lookup bs methodListA
+
+-- | Convert a 'MethodADT' to a 'ByteString'.
+methodFromADT :: MethodADT -> Method
+methodFromADT m
+    = case m of
+        OtherMethod bs -> bs
+        _ -> fromMaybe (localError "methodToByteString" "This should not happen (methodListB is incomplete)") $
+             lookup m methodListB
+
+-- | Convert a method 'String' to a 'MethodADT'.
+stringToMethodADT :: String -> MethodADT
+stringToMethodADT = methodToADT . Ascii.pack
+
+-- | Convert a 'MethodADT' to a 'String'.
+methodADTToString :: MethodADT -> String
+methodADTToString = Ascii.unpack . methodFromADT
+
+-- | HTTP Version.
+-- 
+-- Note that the Show instance is intended merely for debugging.
+data HttpVersion 
+    = HttpVersion {
+        httpMajor :: !Int 
+      , httpMinor :: !Int
+      }
+    deriving (Eq, Ord)
+
+instance Show HttpVersion where
+    show (HttpVersion major minor) = "HTTP/" ++ show major ++ "." ++ show minor
+
+-- | HTTP 0.9
+http09 :: HttpVersion
+http09 = HttpVersion 0 9
+
+-- | HTTP 1.0
+http10 :: HttpVersion
+http10 = HttpVersion 1 0
+
+-- | HTTP 1.1
+http11 :: HttpVersion
+http11 = HttpVersion 1 1
+
+-- | HTTP Status.
+-- 
+-- Only the 'statusCode' is used for comparisons.
+-- 
+-- Note that the Show instance is only for debugging.
+data Status
+    = Status {
+        statusCode :: Int
+      , statusMessage :: B.ByteString
+      }
+    deriving (Show)
+
+instance Eq Status where
+    Status { statusCode = a } == Status { statusCode = b } = a == b
+
+instance Ord Status where
+    compare Status { statusCode = a } Status { statusCode = b } = a `compare` b
+
+-- | OK
+status200, statusOK :: Status
+status200 = Status 200 $ Ascii.pack "OK"
+statusOK = status200
+
+-- | Created
+status201, statusCreated :: Status
+status201 = Status 200 $ Ascii.pack "Created"
+statusCreated = status201
+
+-- | Moved Permanently
+status301, statusMovedPermanently :: Status
+status301 = Status 301 $ Ascii.pack "Moved Permanently"
+statusMovedPermanently = status301
+
+-- | Found
+status302, statusFound :: Status
+status302 = Status 302 $ Ascii.pack "Found"
+statusFound = status302
+
+-- | See Other
+status303, statusSeeOther :: Status
+status303 = Status 303 $ Ascii.pack "See Other"
+statusSeeOther = status303
+
+-- | Bad Request
+status400, statusBadRequest :: Status
+status400 = Status 400 $ Ascii.pack "Bad Request"
+statusBadRequest = status400
+
+-- | Unauthorized
+status401, statusUnauthorized :: Status
+status401 = Status 401 $ Ascii.pack "Unauthorized"
+statusUnauthorized = status401
+
+-- | Forbidden
+status403, statusForbidden :: Status
+status403 = Status 403 $ Ascii.pack "Forbidden"
+statusForbidden = status403
+
+-- | Not Found
+status404, statusNotFound :: Status
+status404 = Status 404 $ Ascii.pack "Not Found"
+statusNotFound = status404
+
+-- | Method Not Allowed
+status405, statusNotAllowed :: Status
+status405 = Status 405 $ Ascii.pack "Method Not Allowed"
+statusNotAllowed = status405
+
+-- | Internal Server Error
+status500, statusServerError :: Status
+status500 = Status 500 $ Ascii.pack "Internal Server Error"
+statusServerError = status500
+
+-- | Request Header
+type RequestHeaders = [(HttpCIByteString, B.ByteString)]
+
+-- | Response Headers
+type ResponseHeaders = [(HttpCIByteString, B.ByteString)]
+
+-- | Query.
+-- 
+-- General form: a=b&c=d, but if the value is Nothing, it becomes
+-- a&c=d.
+type Query = [(B.ByteString, Maybe B.ByteString)]
+
+-- | Simplified Query type without support for parameter-less items.
+type QuerySimple = [(B.ByteString, B.ByteString)]
diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,1 @@
+Generic HTTP types for Haskell (for both client and server code).
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/http-types.cabal b/http-types.cabal
new file mode 100644
--- /dev/null
+++ b/http-types.cabal
@@ -0,0 +1,64 @@
+-- http-types.cabal auto-generated by cabal init. For additional
+-- options, see
+-- http://www.haskell.org/cabal/release/cabal-latest/doc/users-guide/authors.html#pkg-descr.
+-- The name of the package.
+Name:                http-types
+
+-- The package version. See the Haskell package versioning policy
+-- (http://www.haskell.org/haskellwiki/Package_versioning_policy) for
+-- standards guiding when and how versions should be incremented.
+Version:             0.1
+
+-- A short (one-line) description of the package.
+Synopsis:            Generic HTTP types for Haskell (for both client and server code).
+
+-- A longer description of the package.
+Description:         Generic HTTP types for Haskell (for both client and server code).
+
+-- URL for the project homepage or repository.
+Homepage:            https://github.com/aristidb/http-types
+
+-- The license under which the package is released.
+License:             BSD3
+
+-- The file containing the license text.
+License-file:        LICENSE
+
+-- The package author(s).
+Author:              Aristid Breitkreuz
+
+-- An email address to which users can send suggestions, bug reports,
+-- and patches.
+Maintainer:          aristidb@googlemail.com
+
+-- A copyright notice.
+Copyright:           (C) 2011 Aristid Breitkreuz
+
+Category:            Network, Web
+
+Build-type:          Simple
+
+-- Extra files to be distributed with the package, such as examples or
+-- a README.
+Extra-source-files:  README
+
+-- Constraint on the version of Cabal needed to build this package.
+Cabal-version:       >=1.8
+
+
+Library
+  -- Modules exported by the library.
+  Exposed-modules:     Network.HTTP.Types
+
+  -- GHC Options.
+  GHC-Options:         -Wall
+  
+  -- Packages needed in order to build this package.
+  Build-depends:       base >= 4 && < 5, bytestring >=0.9.1.5 && <0.10
+  
+  -- Modules not exported by this package.
+  -- Other-modules:       
+  
+  -- Extra tools (e.g. alex, hsc2hs, ...) needed to build the source.
+  -- Build-tools:         
+  
