class MyWebServer(socketserver.BaseRequestHandler):
    """ Web server. """

    class ClientDisconnected(Exception):
        """ Raised when a client disconnects while the server
            is waiting for it to transmit.
        """
        pass


    class SocketIterator:
        """ Decoding iterator over a SocketBuffer yielding lines. """
        def __init__(self, sio):
            self.sio = io.TextIOWrapper(
                    io.BufferedReader(sio), newline='\r\n')


        def __next__(self):
            """ Read a line from the socket.

            Returns a line of text (str), with the trailing newline removed.

            Raises ClientDisconnected if the socket has been disconnected
            from the other side.
            """

            text = self.sio.readline()
            if not text: raise self.ClientDisconnected()
            stripped = text.rstrip('\r\n')
            return stripped


    def handle(self):
        self.handler = MyHTTPHandler(WEB_ROOT)
        self.sio = SocketIO(self.request)

        try:
            req = Request.read_from(self.SocketIterator(self.sio))
            if LOG_REQUESTS:
                print(('{}:{} {} {}').format(
                    self.client_address[0],
                    self.client_address[1],
                    req.method, req.path), file=sys.stderr)
            resp = self.handler.handle_request(req)
        except myhttp.ParseError:
            resp = Response(Response.BAD_REQUEST)
        except self.ClientDisconnected:
            # nothing to do, really
            return
        except:
            # Try to send a valid response even if something went wrong
            if LOG_REQUESTS:
                print('500 Internal Server Error', file=sys.stderr)
            self.sio.write(b'HTTP/1.1 500 Internal Server Error\r\n')
            raise

        # Attach required header
        resp.attach_header('Connection', 'close')

        # send
        self._send_response(resp)


    def _send_response(self, resp):
        """ Write an HTTP response as represented by a Response object
            to the socket.

        resp: Response
        """

        assert isinstance(resp, Response)

        # Attach the current date
        gmt_now = time.gmtime()
        ftime = time.strftime('%a, %d %b %Y %H:%M:%S GMT', gmt_now)
        resp.attach_header('Date', ftime)

        # write
        if LOG_REQUESTS:
            print('    {} {}'.format(
                resp.code, resp.status_message()), file=sys.stderr)
        self.sio.write(bytes(resp))