예제 #1
0
 def call_at(self, when, callback, *args, **kwargs):
     # asyncio.call_at supports *args but not **kwargs, so bind them here.
     # We do not synchronize self.time and asyncio_loop.time, so
     # convert from absolute to relative.
     return self.asyncio_loop.call_later(
         max(0, when - self.time()), self._run_callback,
         functools.partial(stack_context.wrap(callback), *args, **kwargs))
예제 #2
0
파일: ioloop.py 프로젝트: crimv42/saltstack
 def call_at(self, deadline, callback, *args, **kwargs):
     timeout = _Timeout(
         deadline,
         functools.partial(stack_context.wrap(callback), *args, **kwargs),
         self)
     heapq.heappush(self._timeouts, timeout)
     return timeout
예제 #3
0
    def set_close_callback(self, callback):
        """Sets a callback that will be run when the connection is closed.

        .. deprecated:: 4.0
            Use `.HTTPMessageDelegate.on_connection_close` instead.
        """
        self._close_callback = stack_context.wrap(callback)
예제 #4
0
    def __init__(self, io_loop, client, request, release_callback,
                 final_callback, max_buffer_size, tcp_client, max_header_size,
                 max_body_size):
        self.start_time = io_loop.time()
        self.io_loop = io_loop
        self.client = client
        self.request = request
        self.release_callback = release_callback
        self.final_callback = final_callback
        self.max_buffer_size = max_buffer_size
        self.tcp_client = tcp_client
        self.max_header_size = max_header_size
        self.max_body_size = max_body_size
        self.code = None
        self.headers = None
        self.chunks = []
        self._decompressor = None
        # Timeout handle returned by IOLoop.add_timeout
        self._timeout = None
        self._sockaddr = None
        with stack_context.ExceptionStackContext(self._handle_exception):
            self.parsed = urlparse.urlsplit(_unicode(self.request.url))
            if self.parsed.scheme not in ("http", "https"):
                raise ValueError("Unsupported url scheme: %s" %
                                 self.request.url)
            # urlsplit results have hostname and port results, but they
            # didn't support ipv6 literals until python 2.7.
            netloc = self.parsed.netloc
            if "@" in netloc:
                userpass, _, netloc = netloc.rpartition("@")
            host, port = httputil.split_host_and_port(netloc)
            if port is None:
                port = 443 if self.parsed.scheme == "https" else 80
            if re.match(r'^\[.*\]$', host):
                # raw ipv6 addresses in urls are enclosed in brackets
                host = host[1:-1]
            self.parsed_hostname = host  # save final host for _on_connect

            if request.allow_ipv6 is False:
                af = socket.AF_INET
            else:
                af = socket.AF_UNSPEC

            ssl_options = self._get_ssl_options(self.parsed.scheme)

            timeout = min(self.request.connect_timeout,
                          self.request.request_timeout)
            if timeout:
                self._timeout = self.io_loop.add_timeout(
                    self.start_time + timeout,
                    stack_context.wrap(
                        functools.partial(self._on_timeout,
                                          "while connecting")))
            self.tcp_client.connect(host,
                                    port,
                                    af=af,
                                    ssl_options=ssl_options,
                                    max_buffer_size=self.max_buffer_size,
                                    callback=self._on_connect)
예제 #5
0
 def add_callback(self, callback, *args, **kwargs):
     if self.closing:
         # TODO: this is racy; we need a lock to ensure that the
         # loop isn't closed during call_soon_threadsafe.
         raise RuntimeError("IOLoop is closing")
     self.asyncio_loop.call_soon_threadsafe(
         self._run_callback,
         functools.partial(stack_context.wrap(callback), *args, **kwargs))
예제 #6
0
 def capitalize(self, request_data, callback=None):
     logging.info("capitalize")
     self.request_data = request_data
     self.stream = IOStream(socket.socket(), io_loop=self.io_loop)
     self.stream.connect(('127.0.0.1', self.port),
                         callback=self.handle_connect)
     self.future = Future()
     if callback is not None:
         self.future.add_done_callback(
             stack_context.wrap(lambda future: callback(future.result())))
     return self.future
예제 #7
0
파일: ioloop.py 프로젝트: crimv42/saltstack
    def add_future(self, future, callback):
        """Schedules a callback on the ``IOLoop`` when the given
        `.Future` is finished.

        The callback is invoked with one argument, the
        `.Future`.
        """
        assert is_future(future)
        callback = stack_context.wrap(callback)
        future.add_done_callback(
            lambda future: self.add_callback(callback, future))
예제 #8
0
 def add_handler(self, fd, handler, events):
     if fd in self.fds:
         raise ValueError('fd %s added twice' % fd)
     fd, fileobj = self.split_fd(fd)
     self.fds[fd] = _FD(fd, fileobj, wrap(handler))
     if events & tornado.ioloop.IOLoop.READ:
         self.fds[fd].reading = True
         self.reactor.addReader(self.fds[fd])
     if events & tornado.ioloop.IOLoop.WRITE:
         self.fds[fd].writing = True
         self.reactor.addWriter(self.fds[fd])
예제 #9
0
    def wrapper(*args, **kwargs):
        future = func(*args, **kwargs)

        def final_callback(future):
            if future.result() is not None:
                raise ReturnValueIgnoredError(
                    "@gen.engine functions cannot return values: %r" %
                    (future.result(),))
        # The engine interface doesn't give us any way to return
        # errors but to raise them into the stack context.
        # Save the stack context here to use when the Future has resolved.
        future.add_done_callback(stack_context.wrap(final_callback))
예제 #10
0
 def make_wrapped_function():
     """Wraps a function in three stack contexts, and returns
     the function along with the deactivation functions.
     """
     # Remove the test's stack context to make sure we can cover
     # the case where the last context is deactivated.
     with NullContext():
         partial = functools.partial
         with StackContext(partial(self.context, 'c0')) as c0:
             with StackContext(partial(self.context, 'c1')) as c1:
                 with StackContext(partial(self.context, 'c2')) as c2:
                     return (wrap(check_contexts), [c0, c1, c2])
예제 #11
0
 def add_timeout(self, deadline, callback, *args, **kwargs):
     # This method could be simplified (since tornado 4.0) by
     # overriding call_at instead of add_timeout, but we leave it
     # for now as a test of backwards-compatibility.
     if isinstance(deadline, numbers.Real):
         delay = max(deadline - self.time(), 0)
     elif isinstance(deadline, datetime.timedelta):
         delay = timedelta_to_seconds(deadline)
     else:
         raise TypeError("Unsupported deadline %r")
     return self.reactor.callLater(
         delay, self._run_callback,
         functools.partial(wrap(callback), *args, **kwargs))
예제 #12
0
 def add_handler(self, fd, handler, events):
     fd, fileobj = self.split_fd(fd)
     if fd in self.handlers:
         raise ValueError("fd %s added twice" % fd)
     self.handlers[fd] = (fileobj, stack_context.wrap(handler))
     if events & IOLoop.READ:
         self.asyncio_loop.add_reader(fd, self._handle_events, fd,
                                      IOLoop.READ)
         self.readers.add(fd)
     if events & IOLoop.WRITE:
         self.asyncio_loop.add_writer(fd, self._handle_events, fd,
                                      IOLoop.WRITE)
         self.writers.add(fd)
예제 #13
0
    def test_pre_wrap(self):
        # A pre-wrapped callback is run in the context in which it was
        # wrapped, not when it was added to the IOLoop.
        def f1():
            self.assertIn('c1', self.active_contexts)
            self.assertNotIn('c2', self.active_contexts)
            self.stop()

        with StackContext(functools.partial(self.context, 'c1')):
            wrapped = wrap(f1)

        with StackContext(functools.partial(self.context, 'c2')):
            self.add_callback(wrapped)

        self.wait()
예제 #14
0
파일: ioloop.py 프로젝트: crimv42/saltstack
 def add_callback(self, callback, *args, **kwargs):
     if self._closing:
         return
     # Blindly insert into self._callbacks. This is safe even
     # from signal handlers because deque.append is atomic.
     self._callbacks.append(
         functools.partial(stack_context.wrap(callback), *args, **kwargs))
     if thread.get_ident() != self._thread_ident:
         # This will write one byte but Waker.consume() reads many
         # at once, so it's ok to write even when not strictly
         # necessary.
         self._waker.wake()
     else:
         # If we're on the IOLoop's thread, we don't need to wake anyone.
         pass
예제 #15
0
    def test_pre_wrap_with_args(self):
        # Same as test_pre_wrap, but the function takes arguments.
        # Implementation note: The function must not be wrapped in a
        # functools.partial until after it has been passed through
        # stack_context.wrap
        def f1(foo, bar):
            self.assertIn('c1', self.active_contexts)
            self.assertNotIn('c2', self.active_contexts)
            self.stop((foo, bar))

        with StackContext(functools.partial(self.context, 'c1')):
            wrapped = wrap(f1)

        with StackContext(functools.partial(self.context, 'c2')):
            self.add_callback(wrapped, 1, bar=2)

        result = self.wait()
        self.assertEqual(result, (1, 2))
예제 #16
0
    def set_exit_callback(self, callback):
        """Runs ``callback`` when this process exits.

        The callback takes one argument, the return code of the process.

        This method uses a ``SIGCHLD`` handler, which is a global setting
        and may conflict if you have other libraries trying to handle the
        same signal.  If you are using more than one ``IOLoop`` it may
        be necessary to call `Subprocess.initialize` first to designate
        one ``IOLoop`` to run the signal handlers.

        In many cases a close callback on the stdout or stderr streams
        can be used as an alternative to an exit callback if the
        signal handler is causing a problem.
        """
        self._exit_callback = stack_context.wrap(callback)
        Subprocess.initialize(self.io_loop)
        Subprocess._waiting[self.pid] = self
        Subprocess._try_cleanup_process(self.pid)
예제 #17
0
    def wrapper(*args, **kwargs):
        future = TracebackFuture()
        callback, args, kwargs = replacer.replace(
            lambda value=_NO_RESULT: future.set_result(value), args, kwargs)

        def handle_error(typ, value, tb):
            future.set_exc_info((typ, value, tb))
            return True

        exc_info = None
        with ExceptionStackContext(handle_error):
            try:
                result = f(*args, **kwargs)
                if result is not None:
                    raise ReturnValueIgnoredError(
                        "@return_future should not be used with functions "
                        "that return values")
            except:
                exc_info = sys.exc_info()
                raise
        if exc_info is not None:
            # If the initial synchronous part of f() raised an exception,
            # go ahead and raise it to the caller directly without waiting
            # for them to inspect the Future.
            future.result()

        # If the caller passed in a callback, schedule it to be called
        # when the future resolves.  It is important that this happens
        # just before we return the future, or else we risk confusing
        # stack contexts with multiple exceptions (one here with the
        # immediate exception, and again when the future resolves and
        # the callback triggers its exception by calling future.result()).
        if callback is not None:

            def run_callback(future):
                result = future.result()
                if result is _NO_RESULT:
                    callback()
                else:
                    callback(future.result())

            future.add_done_callback(wrap(run_callback))
        return future
예제 #18
0
    def write(self, chunk, callback=None):
        """Implements `.HTTPConnection.write`.

        For backwards compatibility is is allowed but deprecated to
        skip `write_headers` and instead call `write()` with a
        pre-encoded header block.
        """
        future = None
        if self.stream.closed():
            future = self._write_future = Future()
            self._write_future.set_exception(iostream.StreamClosedError())
            self._write_future.exception()
        else:
            if callback is not None:
                self._write_callback = stack_context.wrap(callback)
            else:
                future = self._write_future = Future()
            self._pending_write = self.stream.write(self._format_chunk(chunk))
            self._pending_write.add_done_callback(self._on_write_complete)
        return future
예제 #19
0
 def library_function(callback):
     # capture the caller's context before introducing our own
     callback = wrap(callback)
     with StackContext(functools.partial(self.context, 'library')):
         self.io_loop.add_callback(
             functools.partial(library_inner_callback, callback))
예제 #20
0
 def f1():
     with NullContext():
         wrapped = wrap(f2)
     with StackContext(functools.partial(self.context, 'c2')):
         wrapped()
예제 #21
0
파일: ioloop.py 프로젝트: crimv42/saltstack
 def add_handler(self, fd, handler, events):
     fd, obj = self.split_fd(fd)
     self._handlers[fd] = (obj, stack_context.wrap(handler))
     self._impl.register(fd, events | self.ERROR)
예제 #22
0
 def result_callback(self, key):
     return stack_context.wrap(_argument_adapter(
         functools.partial(self.set_result, key)))
예제 #23
0
 def prepare_curl_callback(self, value):
     self._prepare_curl_callback = stack_context.wrap(value)
예제 #24
0
 def header_callback(self, value):
     self._header_callback = stack_context.wrap(value)
예제 #25
0
 def streaming_callback(self, value):
     self._streaming_callback = stack_context.wrap(value)
예제 #26
0
 def body_producer(self, value):
     self._body_producer = stack_context.wrap(value)
예제 #27
0
    def fetch(self, request, callback=None, raise_error=True, **kwargs):
        """Executes a request, asynchronously returning an `HTTPResponse`.

        The request may be either a string URL or an `HTTPRequest` object.
        If it is a string, we construct an `HTTPRequest` using any additional
        kwargs: ``HTTPRequest(request, **kwargs)``

        This method returns a `.Future` whose result is an
        `HTTPResponse`. By default, the ``Future`` will raise an
        `HTTPError` if the request returned a non-200 response code
        (other errors may also be raised if the server could not be
        contacted). Instead, if ``raise_error`` is set to False, the
        response will always be returned regardless of the response
        code.

        If a ``callback`` is given, it will be invoked with the `HTTPResponse`.
        In the callback interface, `HTTPError` is not automatically raised.
        Instead, you must check the response's ``error`` attribute or
        call its `~HTTPResponse.rethrow` method.
        """
        if self._closed:
            raise RuntimeError("fetch() called on closed AsyncHTTPClient")
        if not isinstance(request, HTTPRequest):
            request = HTTPRequest(url=request, **kwargs)
        else:
            if kwargs:
                raise ValueError(
                    "kwargs can't be used if request is an HTTPRequest object")
        # We may modify this (to add Host, Accept-Encoding, etc),
        # so make sure we don't modify the caller's object.  This is also
        # where normal dicts get converted to HTTPHeaders objects.
        request.headers = httputil.HTTPHeaders(request.headers)
        request = _RequestProxy(request, self.defaults)
        future = TracebackFuture()
        if callback is not None:
            callback = stack_context.wrap(callback)

            def handle_future(future):
                exc = future.exception()
                if isinstance(exc, HTTPError) and exc.response is not None:
                    response = exc.response
                elif exc is not None:
                    response = HTTPResponse(request,
                                            599,
                                            error=exc,
                                            request_time=time.time() -
                                            request.start_time)
                else:
                    response = future.result()
                self.io_loop.add_callback(callback, response)

            future.add_done_callback(handle_future)

        def handle_response(response):
            if raise_error and response.error:
                future.set_exception(response.error)
            else:
                future.set_result(response)

        self.fetch_impl(request, handle_response)
        return future
예제 #28
0
 def add_parse_callback(self, callback):
     """Adds a parse callback, to be invoked when option parsing is done."""
     self._parse_callbacks.append(stack_context.wrap(callback))
예제 #29
0
 def add_callback(self, callback, *args, **kwargs):
     self.reactor.callFromThread(
         self._run_callback,
         functools.partial(wrap(callback), *args, **kwargs))
예제 #30
0
 def _on_connect(self, stream):
     if self.final_callback is None:
         # final_callback is cleared if we've hit our timeout.
         stream.close()
         return
     self.stream = stream
     self.stream.set_close_callback(self.on_connection_close)
     self._remove_timeout()
     if self.final_callback is None:
         return
     if self.request.request_timeout:
         self._timeout = self.io_loop.add_timeout(
             self.start_time + self.request.request_timeout,
             stack_context.wrap(
                 functools.partial(self._on_timeout, "during request")))
     if (self.request.method not in self._SUPPORTED_METHODS
             and not self.request.allow_nonstandard_methods):
         raise KeyError("unknown method %s" % self.request.method)
     for key in ('network_interface', 'proxy_host', 'proxy_port',
                 'proxy_username', 'proxy_password', 'proxy_auth_mode'):
         if getattr(self.request, key, None):
             raise NotImplementedError('%s not supported' % key)
     if "Connection" not in self.request.headers:
         self.request.headers["Connection"] = "close"
     if "Host" not in self.request.headers:
         if '@' in self.parsed.netloc:
             self.request.headers["Host"] = self.parsed.netloc.rpartition(
                 '@')[-1]
         else:
             self.request.headers["Host"] = self.parsed.netloc
     username, password = None, None
     if self.parsed.username is not None:
         username, password = self.parsed.username, self.parsed.password
     elif self.request.auth_username is not None:
         username = self.request.auth_username
         password = self.request.auth_password or ''
     if username is not None:
         if self.request.auth_mode not in (None, "basic"):
             raise ValueError("unsupported auth_mode %s",
                              self.request.auth_mode)
         auth = utf8(username) + b":" + utf8(password)
         self.request.headers["Authorization"] = (b"Basic " +
                                                  base64.b64encode(auth))
     if self.request.user_agent:
         self.request.headers["User-Agent"] = self.request.user_agent
     if not self.request.allow_nonstandard_methods:
         # Some HTTP methods nearly always have bodies while others
         # almost never do. Fail in this case unless the user has
         # opted out of sanity checks with allow_nonstandard_methods.
         body_expected = self.request.method in ("POST", "PATCH", "PUT")
         body_present = (self.request.body is not None
                         or self.request.body_producer is not None)
         if ((body_expected and not body_present)
                 or (body_present and not body_expected)):
             raise ValueError(
                 'Body must %sbe None for method %s (unless '
                 'allow_nonstandard_methods is true)' %
                 ('not ' if body_expected else '', self.request.method))
     if self.request.expect_100_continue:
         self.request.headers["Expect"] = "100-continue"
     if self.request.body is not None:
         # When body_producer is used the caller is responsible for
         # setting Content-Length (or else chunked encoding will be used).
         self.request.headers["Content-Length"] = str(len(
             self.request.body))
     if (self.request.method == "POST"
             and "Content-Type" not in self.request.headers):
         self.request.headers[
             "Content-Type"] = "application/x-www-form-urlencoded"
     if self.request.decompress_response:
         self.request.headers["Accept-Encoding"] = "gzip"
     req_path = ((self.parsed.path or '/') +
                 (('?' + self.parsed.query) if self.parsed.query else ''))
     self.connection = self._create_connection(stream)
     start_line = httputil.RequestStartLine(self.request.method, req_path,
                                            '')
     self.connection.write_headers(start_line, self.request.headers)
     if self.request.expect_100_continue:
         self._read_response()
     else:
         self._write_body(True)