@Override
    public void run() {
        Long start = System.nanoTime();
        try {
            client.setSoTimeout(10000);
        } catch (SocketException e) {
            WebServer.triggerInternalError("Socket Timeout Set failed for socket on port " + client.getLocalPort()
                    + ": " + e.getMessage());
            return;
        }

        WebServer.logDebug("Connection Established for with id " + requestID);

        try {
            in = new BufferedReader(new InputStreamReader(client.getInputStream()));
            out = new PrintWriter(client.getOutputStream(), true);
            WebServer.logDebug("Established in and out streams for request " + requestID);
        } catch (IOException e) {
            WebServer.triggerInternalError("Read Failed for streams from request " + requestID);
            return;
        }

        String line;
        int lineNum = 1;

        while (client.isConnected()) {
            // reading all lines from request
            try {
                while ((line = in.readLine()).length() != 0) {
                    rawRequest += line + "\n";
                    WebServer.logInfo("Reading Line " + lineNum++ + " from request: " + requestID + ": " + line);
                }
            } catch (IOException e) {
                break;
            }

            parseHeaders(rawRequest);

            Site site = WebServer.matchSite(variables.get("SERVER_PROTOCOL"), variables.get("HTTP_HOST"),
                    client.getLocalPort());

            if (site != null) {
                WebServer.logDebug("Transferring Request to site: " + site.getName());

                site.run(this);
            } else {
                out.close();
            }
            WebServer.logInfo("Closed Request " + requestID);

            Double estimated = (System.nanoTime() - start) / 1000000000.0;
            WebServer.requestTimes.put(getRequestID(), estimated);

            WebServer.logInfo("Request " + requestID + " was completed in " + estimated + " seconds.  Average of "
                    + Utils.sum(WebServer.requestTimes.values().toArray(new Double[0])) + " Seconds / "
                    + WebServer.requestTimes.size() + " Requests is "
                    + Utils.sum(WebServer.requestTimes.values().toArray(new Double[0]))
                    / (WebServer.requestTimes.size()));
        }
    }