Esempio n. 1
0
def copy_range(src_file, start, size, dest):
    total_sent = 0
    src_file.seek(start)
    while size > 0:
        data = eintr_retry_call(src_file.read, min(size, DEFAULT_BUFFER_SIZE))
        if len(data) == 0:
            break  # EOF
        dest.write(data)
        size -= len(data)
        total_sent += len(data)
        del data
    return total_sent
Esempio n. 2
0
    def do_http_basic(self):
        from calibre.srv.errors import HTTPNotFound, HTTPRedirect
        body = 'Requested resource not found'

        def handler(data):
            raise HTTPNotFound(body)

        def raw_send(conn, raw):
            conn.send(raw)
            conn._HTTPConnection__state = http_client._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. / 1024,
                        max_request_body_size=100. / (1024 * 1024)) as server:
            conn = server.connect()
            r = raw_send(conn, b'hello\n')
            self.ae(r.status, http_client.BAD_REQUEST)
            self.ae(r.read(), b'HTTP requires CRLF line terminators')

            r = raw_send(conn, b'\r\nGET /index.html HTTP/1.1\r\n\r\n')
            self.ae(r.status, http_client.NOT_FOUND), self.ae(
                r.read(), b'Requested resource not found')

            r = raw_send(conn, b'\r\n\r\nGET /index.html HTTP/1.1\r\n\r\n')
            self.ae(r.status, http_client.BAD_REQUEST)
            self.ae(r.read(), b'Multiple leading empty lines not allowed')

            r = raw_send(conn, b'hello world\r\n')
            self.ae(r.status, http_client.BAD_REQUEST)
            self.ae(r.read(), b'Malformed Request-Line')

            r = raw_send(conn, b'x' * 200)
            self.ae(r.status, http_client.BAD_REQUEST)
            self.ae(r.read(), b'')

            r = raw_send(conn, b'XXX /index.html HTTP/1.1\r\n\r\n')
            self.ae(r.status,
                    http_client.BAD_REQUEST), self.ae(r.read(),
                                                      b'Unknown HTTP method')

            # Test 404
            conn.request('HEAD', '/moose')
            r = conn.getresponse()
            self.ae(r.status, http_client.NOT_FOUND)
            self.assertIsNotNone(r.getheader('Date', None))
            self.ae(r.getheader('Content-Length'), unicode_type(len(body)))
            self.ae(r.getheader('Content-Type'), 'text/plain; charset=UTF-8')
            self.ae(len(r.getheaders()), 3)
            self.ae(r.read(), b'')
            conn.request('GET', '/choose')
            r = conn.getresponse()
            self.ae(r.status, http_client.NOT_FOUND)
            self.ae(r.read(), b'Requested resource not found')

            # Test 500
            server.change_handler(lambda data: 1 / 0)
            conn = server.connect()
            conn.request('GET', '/test/')
            r = conn.getresponse()
            self.ae(r.status, http_client.INTERNAL_SERVER_ERROR)

            # Test 301
            def handler(data):
                raise HTTPRedirect('/somewhere-else')

            server.change_handler(handler)
            conn = server.connect()
            conn.request('GET', '/')
            r = conn.getresponse()
            self.ae(r.status, http_client.MOVED_PERMANENTLY)
            self.ae(r.getheader('Location'), '/somewhere-else')
            self.ae(b'', r.read())

            server.change_handler(
                lambda data: data.path[0] + data.read().decode('ascii'))
            conn = server.connect(timeout=base_timeout * 5)

            # Test simple GET
            conn.request('GET', '/test/')
            r = conn.getresponse()
            self.ae(r.status, http_client.OK)
            self.ae(r.read(), b'test')

            # Test TRACE
            lines = [
                'TRACE /xxx HTTP/1.1', 'Test: value', 'Xyz: abc, def', '', ''
            ]
            r = raw_send(conn, ('\r\n'.join(lines)).encode('ascii'))
            self.ae(r.status, http_client.OK)
            self.ae(r.read().decode('utf-8'), '\n'.join(lines[:-2]))

            # Test POST with simple body
            conn.request('POST', '/test', 'body')
            r = conn.getresponse()
            self.ae(r.status, http_client.OK)
            self.ae(r.read(), b'testbody')

            # Test POST with chunked transfer encoding
            conn.request('POST',
                         '/test',
                         headers={'Transfer-Encoding': 'chunked'})
            conn.send(b'4\r\nbody\r\na\r\n1234567890\r\n0\r\n\r\n')
            r = conn.getresponse()
            self.ae(r.status, http_client.OK)
            self.ae(r.read(), b'testbody1234567890')

            conn.request('GET', '/test' + ('a' * 200))
            r = conn.getresponse()
            self.ae(r.status, http_client.BAD_REQUEST)

            conn = server.connect()
            conn.request('GET', '/test', ('a' * 200))
            r = conn.getresponse()
            self.ae(r.status, http_client.REQUEST_ENTITY_TOO_LARGE)

            conn = server.connect()
            conn.request('POST',
                         '/test',
                         headers={'Transfer-Encoding': 'chunked'})
            conn.send(b'x\r\nbody\r\n0\r\n\r\n')
            r = conn.getresponse()
            self.ae(r.status, http_client.BAD_REQUEST)
            self.assertIn(b'not a valid chunk size', r.read())

            conn.request('POST',
                         '/test',
                         headers={'Transfer-Encoding': 'chunked'})
            conn.send(b'4\r\nbody\r\n200\r\n\r\n')
            r = conn.getresponse()
            self.ae(r.status, http_client.REQUEST_ENTITY_TOO_LARGE)
            conn.request('POST', '/test', body='a' * 200)
            r = conn.getresponse()
            self.ae(r.status, http_client.REQUEST_ENTITY_TOO_LARGE)

            conn = server.connect()
            conn.request('POST',
                         '/test',
                         headers={'Transfer-Encoding': 'chunked'})
            conn.send(b'3\r\nbody\r\n0\r\n\r\n')
            r = conn.getresponse()
            self.ae(r.status, http_client.BAD_REQUEST), self.ae(
                r.read(), b'Chunk does not have trailing CRLF')

            conn = server.connect(timeout=base_timeout * 5)
            conn.request('POST',
                         '/test',
                         headers={'Transfer-Encoding': 'chunked'})
            conn.send(b'30\r\nbody\r\n0\r\n\r\n')
            r = conn.getresponse()
            self.ae(r.status, http_client.REQUEST_TIMEOUT)
            self.assertIn(b'', r.read())

            conn = server.connect()

            # Test closing
            server.loop.opts.timeout = 10  # ensure socket is not closed because of timeout
            conn.request('GET', '/close', headers={'Connection': 'close'})
            r = conn.getresponse()
            self.ae(r.status, 200), self.ae(r.read(), b'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)

            # Test timeout
            server.loop.opts.timeout = 0.1
            conn = server.connect(timeout=1)
            conn.request('GET', '/something')
            r = conn.getresponse()
            self.ae(r.status, 200), self.ae(r.read(), b'something')
            self.assertIn(b'Request Timeout',
                          eintr_retry_call(conn.sock.recv, 500))
Esempio n. 3
0
    def test_http_basic(self):  # {{{
        'Test basic HTTP protocol conformance'
        from calibre.srv.errors import HTTPNotFound, HTTPRedirect
        body = '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./1024, max_request_body_size=100./(1024*1024)) as server:
            conn = server.connect()
            r = raw_send(conn, b'hello\n')
            self.ae(r.status, httplib.BAD_REQUEST)
            self.ae(r.read(), b'HTTP requires CRLF line terminators')

            r = raw_send(conn, b'\r\nGET /index.html HTTP/1.1\r\n\r\n')
            self.ae(r.status, httplib.NOT_FOUND), self.ae(r.read(), b'Requested resource not found')

            r = raw_send(conn, b'\r\n\r\nGET /index.html HTTP/1.1\r\n\r\n')
            self.ae(r.status, httplib.BAD_REQUEST)
            self.ae(r.read(), b'Multiple leading empty lines not allowed')

            r = raw_send(conn, b'hello world\r\n')
            self.ae(r.status, httplib.BAD_REQUEST)
            self.ae(r.read(), b'Malformed Request-Line')

            r = raw_send(conn, b'x' * 200)
            self.ae(r.status, httplib.BAD_REQUEST)
            self.ae(r.read(), b'')

            r = raw_send(conn, b'XXX /index.html HTTP/1.1\r\n\r\n')
            self.ae(r.status, httplib.BAD_REQUEST), self.ae(r.read(), b'Unknown HTTP method')

            # Test 404
            conn.request('HEAD', '/moose')
            r = conn.getresponse()
            self.ae(r.status, httplib.NOT_FOUND)
            self.assertIsNotNone(r.getheader('Date', None))
            self.ae(r.getheader('Content-Length'), str(len(body)))
            self.ae(r.getheader('Content-Type'), 'text/plain; charset=UTF-8')
            self.ae(len(r.getheaders()), 3)
            self.ae(r.read(), '')
            conn.request('GET', '/choose')
            r = conn.getresponse()
            self.ae(r.status, httplib.NOT_FOUND)
            self.ae(r.read(), b'Requested resource not found')

            # Test 500
            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('GET', '/test/')
            r = conn.getresponse()
            self.ae(r.status, httplib.INTERNAL_SERVER_ERROR)
            server.loop.log.filter_level = orig

            # Test 301
            def handler(data):
                raise HTTPRedirect('/somewhere-else')
            server.change_handler(handler)
            conn = server.connect()
            conn.request('GET', '/')
            r = conn.getresponse()
            self.ae(r.status, httplib.MOVED_PERMANENTLY)
            self.ae(r.getheader('Location'), '/somewhere-else')
            self.ae('', r.read())

            server.change_handler(lambda data:data.path[0] + data.read().decode('ascii'))
            conn = server.connect(timeout=base_timeout * 5)

            # Test simple GET
            conn.request('GET', '/test/')
            r = conn.getresponse()
            self.ae(r.status, httplib.OK)
            self.ae(r.read(), b'test')

            # Test TRACE
            lines = ['TRACE /xxx HTTP/1.1', 'Test: value', 'Xyz: abc, def', '', '']
            r = raw_send(conn, ('\r\n'.join(lines)).encode('ascii'))
            self.ae(r.status, httplib.OK)
            self.ae(r.read().decode('utf-8'), '\n'.join(lines[:-2]))

            # Test POST with simple body
            conn.request('POST', '/test', 'body')
            r = conn.getresponse()
            self.ae(r.status, httplib.OK)
            self.ae(r.read(), b'testbody')

            # Test POST with chunked transfer encoding
            conn.request('POST', '/test', headers={'Transfer-Encoding': 'chunked'})
            conn.send(b'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(), b'testbody1234567890')

            # Test various incorrect input
            orig_level, server.log.filter_level = server.log.filter_level, server.log.ERROR

            conn.request('GET', '/test' + ('a' * 200))
            r = conn.getresponse()
            self.ae(r.status, httplib.BAD_REQUEST)

            conn = server.connect()
            conn.request('GET', '/test', ('a' * 200))
            r = conn.getresponse()
            self.ae(r.status, httplib.REQUEST_ENTITY_TOO_LARGE)

            conn = server.connect()
            conn.request('POST', '/test', headers={'Transfer-Encoding': 'chunked'})
            conn.send(b'x\r\nbody\r\n0\r\n\r\n')
            r = conn.getresponse()
            self.ae(r.status, httplib.BAD_REQUEST)
            self.assertIn(b'not a valid chunk size', r.read())

            conn.request('POST', '/test', headers={'Transfer-Encoding': 'chunked'})
            conn.send(b'4\r\nbody\r\n200\r\n\r\n')
            r = conn.getresponse()
            self.ae(r.status, httplib.REQUEST_ENTITY_TOO_LARGE)
            conn.request('POST', '/test', body='a'*200)
            r = conn.getresponse()
            self.ae(r.status, httplib.REQUEST_ENTITY_TOO_LARGE)

            conn = server.connect()
            conn.request('POST', '/test', headers={'Transfer-Encoding': 'chunked'})
            conn.send(b'3\r\nbody\r\n0\r\n\r\n')
            r = conn.getresponse()
            self.ae(r.status, httplib.BAD_REQUEST), self.ae(r.read(), b'Chunk does not have trailing CRLF')

            conn = server.connect(timeout=base_timeout * 5)
            conn.request('POST', '/test', headers={'Transfer-Encoding': 'chunked'})
            conn.send(b'30\r\nbody\r\n0\r\n\r\n')
            r = conn.getresponse()
            self.ae(r.status, httplib.REQUEST_TIMEOUT)
            self.assertIn(b'', r.read())

            server.log.filter_level = orig_level
            conn = server.connect()
            # Test pipelining
            responses = []
            for i in xrange(10):
                conn._HTTPConnection__state = httplib._CS_IDLE
                conn.request('GET', '/%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(), ('%d' % i).encode('ascii'))
            conn._HTTPConnection__state = httplib._CS_IDLE

            # Test closing
            server.loop.opts.timeout = 10  # ensure socket is not closed because of timeout
            conn.request('GET', '/close', headers={'Connection':'close'})
            r = conn.getresponse()
            self.ae(r.status, 200), self.ae(r.read(), '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)

            # Test timeout
            server.loop.opts.timeout = 0.1
            conn = server.connect(timeout=1)
            conn.request('GET', '/something')
            r = conn.getresponse()
            self.ae(r.status, 200), self.ae(r.read(), 'something')
            self.assertIn('Request Timeout', eintr_retry_call(conn.sock.recv, 500))