diff --git a/include/rew/decoder/http_connection.h b/include/rew/decoder/http_connection.h
index c76e62df515ffc9277582b55686a0ba7a90dc4e6..925f7134d0e65f2da993ba12854fbaad9f7988c0 100644
--- a/include/rew/decoder/http_connection.h
+++ b/include/rew/decoder/http_connection.h
@@ -2,6 +2,8 @@
 #define REW_HTTP_CONNECTION_H
 
 #include "../config.h"
+#include "http_response.h"
+#include "http_request.h"
 
 REW_NAMESPACE {
     class HttpServer;
@@ -16,10 +18,12 @@ REW_NAMESPACE {
 
         virtual void start() = 0;
         virtual void stop() = 0;
-        void send(const std::string& contentType, int status, const std::string& body);
-        virtual void sendRaw(std::shared_ptr<std::string> payload) = 0;
+
     protected:
-        void receive(const std::string& payload);
+        void receive(const std::string& address, const std::string& payload);
+        void send(const HttpRequest& req, const HttpResponse& res);
+        virtual void sendRaw(std::shared_ptr<std::string> payload) = 0;
+        HttpRequest getRequest(const std::string& address, const std::string& payload) const;
     private:
         HttpServer& server;
     };
diff --git a/include/rew/decoder/http_request.h b/include/rew/decoder/http_request.h
new file mode 100644
index 0000000000000000000000000000000000000000..53ad777e696e71c538e2c726c3fd331e480244f3
--- /dev/null
+++ b/include/rew/decoder/http_request.h
@@ -0,0 +1,18 @@
+#ifndef REW_HTTP_REQUEST_H
+#define REW_HTTP_REQUEST_H
+
+#include "../config.h"
+
+REW_NAMESPACE {
+    /*!
+     * @ingroup decoder
+     */
+    struct HttpRequest {
+        std::string method;
+        std::string path;
+        std::string type;
+        std::string address;
+    };
+}
+
+#endif
diff --git a/include/rew/decoder/http_response.h b/include/rew/decoder/http_response.h
new file mode 100644
index 0000000000000000000000000000000000000000..e62c538191a7eb177d9fca111e96f6eff84c17f2
--- /dev/null
+++ b/include/rew/decoder/http_response.h
@@ -0,0 +1,17 @@
+#ifndef REW_HTTP_RESPONSE_H
+#define REW_HTTP_RESPONSE_H
+
+#include "../config.h"
+
+REW_NAMESPACE {
+    /*!
+     * @ingroup decoder
+     */
+    struct HttpResponse {
+        std::string contentType;
+        int status;
+        std::string body;
+    };
+}
+
+#endif
diff --git a/include/rew/decoder/http_server.h b/include/rew/decoder/http_server.h
index 30a0e8f90c16006097df1697cc57a0a08f2fcec4..3cd2b9577d7a8a9159c8294b8e9afe3a1a232676 100644
--- a/include/rew/decoder/http_server.h
+++ b/include/rew/decoder/http_server.h
@@ -9,6 +9,8 @@
 #include <list>
 #include "../common/input.h"
 #include "../common/named_raw_file.h"
+#include "http_request.h"
+#include "http_response.h"
 
 REW_NAMESPACE {
     class HttpConnection;
@@ -22,7 +24,7 @@ REW_NAMESPACE {
         virtual ~HttpServer() = default;
 
         void process(const NamedRawFile* data, size_t length) override;
-        void serve(HttpConnection& con, const std::string& file);
+        HttpResponse serve(const HttpRequest& request);
         void disconnect(const std::shared_ptr<HttpConnection>& connection);
         virtual void start() = 0;
         virtual void stop() = 0;
diff --git a/include/rew/decoder/tcp_http_connection.h b/include/rew/decoder/tcp_http_connection.h
index bd1d98b980320e58faf2a59a302df105a6393b0f..135326e84434fcfe145913b30864f140afb7f5fc 100644
--- a/include/rew/decoder/tcp_http_connection.h
+++ b/include/rew/decoder/tcp_http_connection.h
@@ -16,7 +16,7 @@ REW_NAMESPACE {
 
         void start() override;
         void stop() override;
-        void sendRaw(std::shared_ptr<std::string> payload) override;
+        void sendRaw(std::shared_ptr<std::string> payload);
     private:
         void doRead();
 
diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt
index 268f60f0df5d57bd11d4f7a5b8b1683d7ef7fa35..e69ca893fdcf2db8299aec87c1bd568358ceff95 100644
--- a/libs/CMakeLists.txt
+++ b/libs/CMakeLists.txt
@@ -54,7 +54,7 @@ endif()
 ExternalProject_Add(libui
   DOWNLOAD_COMMAND ""
   SOURCE_DIR ${CMAKE_SOURCE_DIR}/libs/libui-cmake
-  CMAKE_ARGS -DLIBUI_BUILD_EXAMPLES=OFF -DLIBUI_BUILD_SHARED_LIBS=OFF
+  CMAKE_ARGS -DLIBUI_BUILD_EXAMPLES=OFF -DLIBUI_BUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=MinSizeRel
   BUILD_COMMAND cmake --build .
   INSTALL_COMMAND ""
   TEST_COMMAND ""
diff --git a/src/rew/decoder-cli/main.cpp b/src/rew/decoder-cli/main.cpp
index 8c1ebef7a34593e5f2c4e45c5ba945f120aecfcf..44c6e4280473b4c4d391652858414320fc4e24ae 100644
--- a/src/rew/decoder-cli/main.cpp
+++ b/src/rew/decoder-cli/main.cpp
@@ -140,7 +140,7 @@ private:
 int main (const int argc, char* argv[]) {
     static bool terminate = false;
 #ifdef _WIN32
-    SetConsoleCtrlHandler([](const DWORD fdwCtrlType) -> BOOL {
+    SetConsoleCtrlHandler([](const DWORD fdwCtrlType) WINAPI -> BOOL {
         switch (fdwCtrlType) {
             case CTRL_C_EVENT:
             case CTRL_CLOSE_EVENT:
diff --git a/src/rew/decoder/http_connection.cpp b/src/rew/decoder/http_connection.cpp
index 5149579b4827310962ceb1888520f5be7d755166..9b664b3604f04ddbb00517298cbbcf7a2e4c915f 100644
--- a/src/rew/decoder/http_connection.cpp
+++ b/src/rew/decoder/http_connection.cpp
@@ -3,6 +3,49 @@
 #include <rew/decoder/http_server.h>
 #include <rew/common/tokenizer.h>
 
+static const std::unordered_map<int, std::string> statusCodes = {
+    {100, "Continue"},
+    {101, "Switching Protocols"},
+    {200, "OK"},
+    {201, "Created"},
+    {202, "Accepted"},
+    {203, "Non-Authoritative Information"},
+    {204, "No Content"},
+    {205, "Reset Content"},
+    {206, "Partial Content"},
+    {300, "Multiple Choices"},
+    {301, "Moved Permanently"},
+    {302, "Found"},
+    {303, "See Other"},
+    {304, "Not Modified"},
+    {305, "Use Proxy"},
+    {307, "Temporary Redirect"},
+    {400, "Bad Request"},
+    {401, "Unauthorized"},
+    {402, "Payment Required"},
+    {403, "Forbidden"},
+    {404, "Not Found"},
+    {405, "Method Not Allowed"},
+    {406, "Not Acceptable"},
+    {407, "Proxy Authentication Required"},
+    {408, "Request Time-out"},
+    {409, "Conflict"},
+    {410, "Gone"},
+    {411, "Length Required"},
+    {412, "Precondition Failed"},
+    {413, "Request Entity Too Large"},
+    {414, "Request-URI Too Large"},
+    {415, "Unsupported Media Type"},
+    {416, "Requested range not satisfiable"},
+    {417, "Expectation Failed"},
+    {500, "Internal Server Error"},
+    {501, "Not Implemented"},
+    {502, "Bad Gateway"},
+    {503, "Service Unavailable"},
+    {504, "Gateway Time-out"},
+    {505, "HTTP Version not supported"},  
+};
+
 ///=====================================================================================================================
 rew::HttpConnection::HttpConnection(HttpServer& server)
     :server(server) {
@@ -10,35 +53,65 @@ rew::HttpConnection::HttpConnection(HttpServer& server)
 }
 
 ///=====================================================================================================================
-void rew::HttpConnection::send(const std::string& contentType, int status, const std::string& body) {
+void rew::HttpConnection::send(const HttpRequest& req, const HttpResponse& res) {
     std::stringstream ss;
-    ss << "HTTP/1.1 200 OK\n";
+    ss << "HTTP/1.1 " << res.status << " " << statusCodes.at(res.status) << "\n";
     ss << "Server: Decoder\n";
     ss << "Accept-Ranges: bytes\n";
-    ss << "Content-Length: " << std::to_string(body.size()) << "\n";
+    ss << "Content-Length: " << std::to_string(res.body.size()) << "\n";
     ss << "Connection: close\n";
-    ss << "Content-Type: " << contentType << "\n";
+    ss << "Content-Type: " << res.contentType << "\n";
     ss << "\n";
-    ss << body;
+    ss << res.body;
     sendRaw(std::make_shared<std::string>(ss.str()));
+    std::cout 
+        << req.address 
+        << " \"" 
+        << req.method 
+        << " " 
+        << req.path 
+        << " " 
+        << req.type 
+        << "\" " 
+        << res.status 
+        << " " 
+        << res.body.size() 
+        << std::endl;
 }
 
 ///=====================================================================================================================
-void rew::HttpConnection::receive(const std::string& payload) {
+void rew::HttpConnection::receive(const std::string& address, const std::string& payload) {
+    HttpRequest req;
     try {
-        const auto tokens = getTokens(payload, "\n");
-        if (tokens.size() < 1) {
-            send("text/plain", 400, "Bad request");
+        req = getRequest(address, payload);
+    } catch (std::exception& e) {
+        send(HttpRequest{"", "", "", address}, HttpResponse{"text/plain", 400, "Bad request"});
+        return;
+    }
+    
+    try {
+        if (req.method != "GET") {
+            send(req, HttpResponse{"text/plain", 405, "Method not allowed"});
         } else {
-            const auto words = getTokens(tokens[0], " ");
-            if (words.size() < 2 || words[0] != "GET") {
-                send("text/plain", 400, "Bad request");
-            } else {
-                server.serve(*this, words[1]);
-            }
+            const auto res = server.serve(req);
+            send(req, res);
         }
     } catch (std::exception& e) {
-        send("text/plain", 500, "Internal server error");
+        send(req, HttpResponse{"text/plain", 500, "Internal server error"});
     }
 }
 
+///=====================================================================================================================
+rew::HttpRequest rew::HttpConnection::getRequest(const std::string& address, const std::string& payload) const {
+    const auto tokens = getTokens(payload, "\r\n");
+    if (tokens.size() < 1) {
+        throw std::runtime_error("Invalid http request");
+    } else {
+        const auto words = getTokens(tokens[0], " ");
+        if (words.size() != 3) {
+            throw std::runtime_error("Invalid http request");
+        } else {
+            return HttpRequest{words[0], words[1], words[2], address};
+        }
+    }
+}
diff --git a/src/rew/decoder/http_server.cpp b/src/rew/decoder/http_server.cpp
index 1da8da76beac39a57fbefa6dfd4e91c062cba4ac..9a35b9e5733a0789146829a8e5a808e3eef6324d 100644
--- a/src/rew/decoder/http_server.cpp
+++ b/src/rew/decoder/http_server.cpp
@@ -1,6 +1,119 @@
 #include <rew/decoder/http_server.h>
 #include <rew/decoder/http_connection.h>
 
+// The following list adopted from:
+// https://github.com/nginx/nginx/blob/master/conf/mime.types
+static const std::unordered_map<std::string, std::string> mimeTypes = {
+    {"html",  "text/html"},
+    {"htm",  "text/html"},
+    {"shtml",  "text/html"},
+    {"css",  "text/css"},
+    {"xml",  "text/xml"},
+    {"gif",  "image/gif"},
+    {"jpeg",  "image/jpeg"},
+    {"jpg",  "image/jpeg"},
+    {"js",  "application/javascript"},
+    {"atom",  "application/atom+xml"},
+    {"rss",  "application/rss+xml"},
+    {"mml",  "text/mathml"},
+    {"txt",  "text/plain"},
+    {"jad",  "text/vnd.sun.j2me.app-descriptor"},
+    {"wml",  "text/vnd.wap.wml"},
+    {"htc",  "text/x-component"},
+    {"png",  "image/png"},
+    {"svg",  "image/svg+xml"},
+    {"svgz",  "image/svg+xml"},
+    {"tif",  "image/tiff"},
+    {"tiff",  "image/tiff"},
+    {"wbmp",  "image/vnd.wap.wbmp"},
+    {"webp",  "image/webp"},
+    {"ico",  "image/x-icon"},
+    {"jng",  "image/x-jng"},
+    {"bmp",  "image/x-ms-bmp"},
+    {"woff",  "font/woff"},
+    {"woff2",  "font/woff2"},
+    {"jar",  "application/java-archive"},
+    {"war",  "application/java-archive"},
+    {"ear",  "application/java-archive"},
+    {"json",  "application/json"},
+    {"hqx",  "application/mac-binhex40"},
+    {"doc",  "application/msword"},
+    {"pdf",  "application/pdf"},
+    {"ps",  "application/postscript"},
+    {"eps",  "application/postscript"},
+    {"ai",  "application/postscript"},
+    {"rtf",  "application/rtf"},
+    {"m3u8",  "application/vnd.apple.mpegurl"},
+    {"kml",  "application/vnd.google-earth.kml+xml"},
+    {"kmz",  "application/vnd.google-earth.kmz"},
+    {"xls",  "application/vnd.ms-excel"},
+    {"eot",  "application/vnd.ms-fontobject"},
+    {"ppt",  "application/vnd.ms-powerpoint"},
+    {"odg",  "application/vnd.oasis.opendocument.graphics"},
+    {"odp",  "application/vnd.oasis.opendocument.presentation"},
+    {"ods",  "application/vnd.oasis.opendocument.spreadsheet"},
+    {"odt",  "application/vnd.oasis.opendocument.text"},
+    {"pptx",  "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
+    {"xlsx",  "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
+    {"docx",  "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
+    {"wmlc",  "application/vnd.wap.wmlc"},
+    {"7z",  "application/x-7z-compressed"},
+    {"cco",  "application/x-cocoa"},
+    {"jardiff",  "application/x-java-archive-diff"},
+    {"jnlp",  "application/x-java-jnlp-file"},
+    {"run",  "application/x-makeself"},
+    {"pl",  "application/x-perl"},
+    {"pm",  "application/x-perl"},
+    {"prc",  "application/x-pilot"},
+    {"pdb",  "application/x-pilot"},
+    {"rar",  "application/x-rar-compressed"},
+    {"rpm",  "application/x-redhat-package-manager"},
+    {"sea",  "application/x-sea"},
+    {"swf",  "application/x-shockwave-flash"},
+    {"sit",  "application/x-stuffit"},
+    {"tcl",  "application/x-tcl"},
+    {"tk",  "application/x-tcl"},
+    {"der",  "application/x-x509-ca-cert"},
+    {"pem",  "application/x-x509-ca-cert"},
+    {"crt",  "application/x-x509-ca-cert"},
+    {"xpi",  "application/x-xpinstall"},
+    {"xhtml",  "application/xhtml+xml"},
+    {"xspf",  "application/xspf+xml"},
+    {"zip",  "application/zip"},
+    {"bin",  "application/octet-stream"},
+    {"exe",  "application/octet-stream"},
+    {"dll",  "application/octet-stream"},
+    {"deb",  "application/octet-stream"},
+    {"dmg",  "application/octet-stream"},
+    {"iso",  "application/octet-stream"},
+    {"img",  "application/octet-stream"},
+    {"msi",  "application/octet-stream"},
+    {"msp",  "application/octet-stream"},
+    {"msm",  "application/octet-stream"},
+    {"mid",  "audio/midi"},
+    {"midi",  "audio/midi"},
+    {"kar",  "audio/midi"},
+    {"mp3",  "audio/mpeg"},
+    {"ogg",  "audio/ogg"},
+    {"m4a",  "audio/x-m4a"},
+    {"ra",  "audio/x-realaudio"},
+    {"3gpp",  "video/3gpp"},
+    {"3gp",  "video/3gpp"},
+    {"ts",  "video/mp2t"},
+    {"mp4",  "video/mp4"},
+    {"mpeg",  "video/mpeg"},
+    {"mpg",  "video/mpeg"},
+    {"mov",  "video/quicktime"},
+    {"webm",  "video/webm"},
+    {"flv",  "video/x-flv"},
+    {"m4v",  "video/x-m4v"},
+    {"mng",  "video/x-mng"},
+    {"asx",  "video/x-ms-asf"},
+    {"asf",  "video/x-ms-asf"},
+    {"wmv",  "video/x-ms-wmv"},
+    {"avi",  "video/x-msvideo"},
+};
+
 ///=====================================================================================================================
 void rew::HttpServer::process(const NamedRawFile* data, size_t length) {
     for (size_t i = 0; i < length; i++) {
@@ -33,13 +146,20 @@ void rew::HttpServer::process(const NamedRawFile* data, size_t length) {
 }
 
 ///=====================================================================================================================
-void rew::HttpServer::serve(HttpConnection& con, const std::string& file) {
+rew::HttpResponse rew::HttpServer::serve(const HttpRequest& request) {
     std::lock_guard<std::mutex> guard{mutex};
-    const auto it = files.find(file);
+    const auto it = files.find(request.path);
     if (it == files.end()) {
-        con.send("text/plain", 404, "Not found");
+        return HttpResponse{"text/plain", 404, "Not found"};
     } else {
-        con.send("text/plain", 200, it->second);
+        const auto extPos = request.path.find_last_of(".");
+        const auto ext = request.path.substr(extPos + 1);
+        const auto mime = mimeTypes.find(ext);
+        auto mimeType = "application/octet-stream";
+        if (mime != mimeTypes.end()) {
+            mimeType = mime->second.c_str();
+        }
+        return HttpResponse{mimeType, 200, it->second};
     }
 }
 
diff --git a/src/rew/decoder/tcp_http_connection.cpp b/src/rew/decoder/tcp_http_connection.cpp
index 6615294226011447d5db7b3824e6e90570b06fa7..eeee664cf3249b2329addcbe242da89c91e76b0a 100644
--- a/src/rew/decoder/tcp_http_connection.cpp
+++ b/src/rew/decoder/tcp_http_connection.cpp
@@ -49,7 +49,7 @@ void rew::TcpHttpConnection::doRead() {
     pimpl->socket.async_read_some(asio::buffer(pimpl->buffer), [this, self](const std::error_code ec, const size_t length) {
         if (!ec){
             const auto payload = std::string(reinterpret_cast<const char*>(pimpl->buffer.data()), length);
-            self->receive(payload);
+            self->receive(self->pimpl->socket.remote_endpoint().address().to_string(), payload);
         } else if (ec != asio::error::operation_aborted) {
             pimpl->server.disconnect(shared_from_this());
         }