'Test basic HTTP protocol conformance'

def test_http_basic(self):

    from calibre.srv.errors import HTTPNotFound, HTTPRedirect
    body = u'Requested    resource    not    found'
    def handler(data):
        raise HTTPNotFound(body)
    def raw_send(conn, raw):
        conn.send(raw)
        conn._HTTPConnection__state = httplib._CS_REQ_SENT
        return conn.getresponse()
    base_timeout = (0.5 if is_ci else 0.1)
    with TestServer(handler, timeout=base_timeout, max_header_line_size=(100.0 / 1024), max_request_body_size=(100.0 / (1024 * 1024))) as server:
        conn = server.connect()
        r = raw_send(conn, 'hello\n')
        self.ae(r.status, httplib.BAD_REQUEST)
        self.ae(r.read(), 'HTTP    requires    CRLF    line    terminators')
        r = raw_send(conn, '\r\nGET    /index.html    HTTP/1.1\r\n\r\n')
        (self.ae(r.status, httplib.NOT_FOUND), self.ae(r.read(), 'Requested    resource    not    found'))
        r = raw_send(conn, '\r\n\r\nGET    /index.html    HTTP/1.1\r\n\r\n')
        self.ae(r.status, httplib.BAD_REQUEST)
        self.ae(r.read(), 'Multiple    leading    empty    lines    not    allowed')
        r = raw_send(conn, 'hello    world\r\n')
        self.ae(r.status, httplib.BAD_REQUEST)
        self.ae(r.read(), 'Malformed    Request-Line')
        r = raw_send(conn, ('x' * 200))
        self.ae(r.status, httplib.BAD_REQUEST)
        self.ae(r.read(), '')
        r = raw_send(conn, 'XXX    /index.html    HTTP/1.1\r\n\r\n')
        (self.ae(r.status, httplib.BAD_REQUEST), self.ae(r.read(), 'Unknown    HTTP    method'))
        conn.request(u'HEAD', u'/moose')
        r = conn.getresponse()
        self.ae(r.status, httplib.NOT_FOUND)
        self.assertIsNotNone(r.getheader(u'Date', None))
        self.ae(r.getheader(u'Content-Length'), str(len(body)))
        self.ae(r.getheader(u'Content-Type'), u'text/plain;    charset=UTF-8')
        self.ae(len(r.getheaders()), 3)
        self.ae(r.read(), u'')
        conn.request(u'GET', u'/choose')
        r = conn.getresponse()
        self.ae(r.status, httplib.NOT_FOUND)
        self.ae(r.read(), 'Requested    resource    not    found')
        orig = server.loop.log.filter_level
        server.loop.log.filter_level = (server.loop.log.ERROR + 10)
        server.change_handler((lambda data: (1 / 0)))
        conn = server.connect()
        conn.request(u'GET', u'/test/')
        r = conn.getresponse()
        self.ae(r.status, httplib.INTERNAL_SERVER_ERROR)
        server.loop.log.filter_level = orig
        def handler(data):
            raise HTTPRedirect(u'/somewhere-else')
        server.change_handler(handler)
        conn = server.connect()
        conn.request(u'GET', u'/')
        r = conn.getresponse()
        self.ae(r.status, httplib.MOVED_PERMANENTLY)
        self.ae(r.getheader(u'Location'), u'/somewhere-else')
        self.ae(u'', r.read())
        server.change_handler((lambda data: (data.path[0] + data.read().decode(u'ascii'))))
        conn = server.connect(timeout=(base_timeout * 5))
        conn.request(u'GET', u'/test/')
        r = conn.getresponse()
        self.ae(r.status, httplib.OK)
        self.ae(r.read(), 'test')
        lines = [u'TRACE    /xxx    HTTP/1.1', u'Test:    value', u'Xyz:    abc,    def', u'', u'']
        r = raw_send(conn, u'\r\n'.join(lines).encode(u'ascii'))
        self.ae(r.status, httplib.OK)
        self.ae(r.read().decode(u'utf-8'), u'\n'.join(lines[:(-2)]))
        conn.request(u'POST', u'/test', u'body')
        r = conn.getresponse()
        self.ae(r.status, httplib.OK)
        self.ae(r.read(), 'testbody')
        conn.request(u'POST', u'/test', headers={u'Transfer-Encoding': u'chunked'})
        conn.send('4\r\nbody\r\na\r\n1234567890\r\n0\r\n\r\n')
        r = conn.getresponse()
        self.ae(r.status, httplib.OK)
        self.ae(r.read(), 'testbody1234567890')
        (orig_level, server.log.filter_level) = (server.log.filter_level, server.log.ERROR)
        conn.request(u'GET', (u'/test' + (u'a' * 200)))
        r = conn.getresponse()
        self.ae(r.status, httplib.BAD_REQUEST)
        conn = server.connect()
        conn.request(u'GET', u'/test', (u'a' * 200))
        r = conn.getresponse()
        self.ae(r.status, httplib.REQUEST_ENTITY_TOO_LARGE)
        conn = server.connect()
        conn.request(u'POST', u'/test', headers={u'Transfer-Encoding': u'chunked'})
        conn.send('x\r\nbody\r\n0\r\n\r\n')
        r = conn.getresponse()
        self.ae(r.status, httplib.BAD_REQUEST)
        self.assertIn('not    a    valid    chunk    size', r.read())
        conn.request(u'POST', u'/test', headers={u'Transfer-Encoding': u'chunked'})
        conn.send('4\r\nbody\r\n200\r\n\r\n')
        r = conn.getresponse()
        self.ae(r.status, httplib.REQUEST_ENTITY_TOO_LARGE)
        conn.request(u'POST', u'/test', body=(u'a' * 200))
        r = conn.getresponse()
        self.ae(r.status, httplib.REQUEST_ENTITY_TOO_LARGE)
        conn = server.connect()
        conn.request(u'POST', u'/test', headers={u'Transfer-Encoding': u'chunked'})
        conn.send('3\r\nbody\r\n0\r\n\r\n')
        r = conn.getresponse()
        (self.ae(r.status, httplib.BAD_REQUEST), self.ae(r.read(), 'Chunk    does    not    have    trailing    CRLF'))
        conn = server.connect(timeout=(base_timeout * 5))
        conn.request(u'POST', u'/test', headers={u'Transfer-Encoding': u'chunked'})
        conn.send('30\r\nbody\r\n0\r\n\r\n')
        r = conn.getresponse()
        self.ae(r.status, httplib.REQUEST_TIMEOUT)
        self.assertIn('', r.read())
        server.log.filter_level = orig_level
        conn = server.connect()
        responses = []
        for i in xrange(10):
            conn._HTTPConnection__state = httplib._CS_IDLE
            conn.request(u'GET', (u'/%d' % i))
            responses.append(conn.response_class(conn.sock, strict=conn.strict, method=conn._method))
        for i in xrange(10):
            r = responses[i]
            r.begin()
            self.ae(r.read(), (u'%d' % i).encode(u'ascii'))
        conn._HTTPConnection__state = httplib._CS_IDLE
        server.loop.opts.timeout = 10
        conn.request(u'GET', u'/close', headers={u'Connection': u'close'})
        r = conn.getresponse()
        (self.ae(r.status, 200), self.ae(r.read(), u'close'))
        server.loop.wakeup()
        num = 10
        while (num and (server.loop.num_active_connections != 0)):
            time.sleep(0.01)
            num -= 1
        self.ae(server.loop.num_active_connections, 0)
        self.assertIsNone(conn.sock)
        server.loop.opts.timeout = 0.1
        conn = server.connect(timeout=1)
        conn.request(u'GET', u'/something')
        r = conn.getresponse()
        (self.ae(r.status, 200), self.ae(r.read(), u'something'))
        self.assertIn(u'Request    Timeout', eintr_retry_call(conn.sock.recv, 500))
