Example #1
0
 def callback(connection):
     stack = connection.connection_info("transaction_start_stack")
     if stack is not None:
         wiking.debug(
             "Unclosed transaction started at:\n%s\n"
             % (string.join(traceback.format_stack(stack), ""),)
         )
Example #2
0
 def _handle(self, req):
     # TODO: the documentation should be processed by LCG first into some
     # reasonable output format.  Now we just search the file in all the
     # source directories and format it.  No global navigation is used.
     path = self._document_path(req)
     wiking.debug('..', path, req.unresolved_path)
     variants = [lang for lang in wiking.module.Application.languages()
                 if os.path.exists('.'.join((path, lang, 'txt')))]
     if not variants:
         # HACK: Try fallback to English if no application language variants
         # are available.  In fact, the application should never return
         # content in any other language, than what is defined by
         # `Application.languages()', but default Wiking documentation is
         # often not translated to application languages and users get a
         # confusing error.  This should avoid the confusion, but a proper
         # solution would be to have all documentation files translated at
         # least to one application language.
         if os.path.exists('.'.join((path, 'en', 'txt'))):
             variants = ['en']
         else:
             raise NotFound()
     lang = req.preferred_language(variants)
     filename = '.'.join((path, lang, 'txt'))
     f = codecs.open(filename, encoding='utf-8')
     text = "".join(f.readlines())
     f.close()
     content = lcg.Parser().parse(text)
     if len(content) == 1 and isinstance(content[0], lcg.Section):
         title = content[0].title()
         content = lcg.Container(content[0].content())
     else:
         title = ' :: '.join(req.unresolved_path)
     if req.param('framed') == '1':
         # Used to display contextual help in an iframe (see pytis-ckeditor.js).
         layout = wiking.Exporter.Layout.FRAME
     else:
         layout = None
     return wiking.Document(title, content, lang=lang, variants=variants, layout=layout)
Example #3
0
    def handle(self, req):
        if not hasattr(self, "_first_request_served"):
            if __debug__:
                wiking.debug("Python optimization off.")
            else:
                wiking.debug("Python optimization on.")
        if wiking.cfg.debug and (wiking.cfg.profile or req.param("profile") == "1"):
            enable_profiling = True
            if not hasattr(self, "_first_request_served"):
                if req.param("ignore_first"):
                    wiking.debug("Profiling disabled for the initial request.")
                    enable_profiling = False
                else:
                    wiking.debug("Profiling note: This is an initial request.")
        else:
            enable_profiling = False
        self._first_request_served = True
        if enable_profiling:
            import cProfile as profile
            import pstats
            import tempfile

            self._profile_req = req
            queries = []

            def query_callback(query, start_time, end_time):
                queries.append((end_time - start_time, query))

            wiking.WikingDefaultDataClass.set_query_callback(query_callback)
            uri = req.uri()
            tmpfile = tempfile.NamedTemporaryFile().name
            profile.run(
                "from wiking.handler import Handler; "
                "self = Handler._instance; "
                "self._result = self._handle(self._profile_req)",
                tmpfile,
            )
            try:
                stats = pstats.Stats(tmpfile)
                stats.strip_dirs()
                stats.sort_stats("cumulative")
                wiking.debug("Profile statistics for %s:" % (uri,))
                stats.stream = sys.stderr
                sys.stderr.write("   ")
                stats.print_stats()
                sys.stderr.flush()
            finally:
                os.remove(tmpfile)
            wiking.debug("Database queries for: %s" % (uri,))
            for q in queries:
                info = ("#" if q[0] >= 0.01 else " ",) + q
                sys.stderr.write("   %s%0.3f %s\n" % info)
            sys.stderr.flush()
            return self._result
        else:
            # result, t1, t2 = timeit(self._handle, req)
            # log(OPERATIONAL, "Request processed in %.1f ms (%.1f ms CPU):" %
            #                   (1000*t2, 1000*t1), req.uri())
            # return result
            try:
                return self._handle(req)
            finally:
                # We can observe pending transactions in Wiking applications,
                # so let's close them all after each request.
                if __debug__ and wiking.cfg.debug_transactions:

                    def callback(connection):
                        stack = connection.connection_info("transaction_start_stack")
                        if stack is not None:
                            wiking.debug(
                                "Unclosed transaction started at:\n%s\n"
                                % (string.join(traceback.format_stack(stack), ""),)
                            )

                else:
                    callback = None
                wiking.WikingDefaultDataClass.close_idle_connections()
                wiking.WikingDefaultDataClass.rollback_connections(callback=callback)
Example #4
0
    def handle(self, req):
        if not hasattr(self, '_first_request_served'):
            if __debug__:
                wiking.debug("Python optimization off.")
            else:
                wiking.debug("Python optimization on.")
        if wiking.cfg.debug and (wiking.cfg.profile or req.param('profile') == '1'):
            enable_profiling = True
            if not hasattr(self, '_first_request_served'):
                if req.param('ignore_first'):
                    # First request does a lot of unusual suff, so profiling it
                    # usually doesn't make much sense.
                    wiking.debug("Profiling disabled for the initial request.")
                    enable_profiling = False
                else:
                    wiking.debug("Profiling note: This is an initial request.")
        else:
            enable_profiling = False
        self._first_request_served = True
        if enable_profiling:
            import cProfile as profile
            import pstats
            import tempfile
            self._profile_req = req
            queries = []

            def query_callback(query, start_time, end_time):
                queries.append((end_time - start_time, query,))
            wiking.WikingDefaultDataClass.set_query_callback(query_callback)
            uri = req.uri()
            tmpfile = tempfile.NamedTemporaryFile().name
            profile.run('from wiking.handler import Handler; '
                        'self = Handler._instance; '
                        'self._result = self._handle(self._profile_req)',
                        tmpfile)
            try:
                stats = pstats.Stats(tmpfile)
                stats.strip_dirs()
                stats.sort_stats('cumulative')
                wiking.debug("Profile statistics for %s:" % (uri,))
                stats.stream = sys.stderr
                sys.stderr.write('   ')
                stats.print_stats()
                sys.stderr.flush()
            finally:
                os.remove(tmpfile)
            wiking.debug("Database queries for: %s" % (uri,))
            for q in queries:
                info = ('#' if q[0] >= 0.01 else ' ',) + q
                sys.stderr.write('   %s%0.3f %s\n' % info)
            sys.stderr.flush()
            return self._result
        else:
            return self._handle(req)
Example #5
0
 def _handle(self, req):
     try:
         try:
             if wiking.cfg.maintenance and not req.uri().startswith('/_resources/'):
                 # TODO: excluding /_resources/ is here to make stylesheets
                 # available for the maintenance error page.  The URI is
                 # however not necassarily correct (application may change
                 # it).  Better would most likely be including some basic styles
                 # directly in MinimalExporter.
                 return self._handle_maintenance_mode(req)
             # Very basic CSRF prevention
             if req.param('submit') and req.header('Referer'):
                 referer = urllib.parse.urlparse(req.header('Referer'))
                 referer_uri = referer.scheme + '://' + referer.netloc
                 server_uri = req.server_uri(current=True)
                 if referer_uri != server_uri:
                     wiking.debug("Request rejected due to CSRF protection:", referer_uri, server_uri)
                     raise wiking.Redirect(req.server_uri(current=True))
             # Regular processing starts here.
             try:
                 result = self._application.handle(req)
             except wiking.Abort as abort:
                 result = abort.result()
             if isinstance(result, (tuple, list)):
                 # Temporary backwards compatibility conversion.
                 content_type, data = result
                 result = wiking.Response(data, content_type=content_type)
             if req.is_api_request() and isinstance(result, (lcg.Content, wiking.Document)):
                 # This is a very generic detection of invalid API
                 # requests.  We just assume, that the clients, which
                 # indicate that they accept JSON responses are API
                 # clients and they are not interested in responses, which
                 # display human readable content.
                 raise wiking.BadRequest(_("This URI does not belong to server API."))
             if isinstance(result, wiking.Document):
                 # Perform authentication here if it was not performed before
                 # to handle authentication exceptions now and prevent them in
                 # export time.  When the result is a Document, we will always
                 # need to know the authenticated user in order to display the
                 # login control at the top of the page.
                 user = req.user()
                 if user:
                     password_expiration = user.password_expiration()
                     password_change_uri = wiking.module.Application.password_change_uri(req)
                     if ((password_change_uri and password_expiration and
                          password_expiration <= datetime.date.today() and
                          req.uri() != password_change_uri)):
                         req.message(_("Your password expired."), req.ERROR)
                         req.message(_("Access to the application is now restricted "
                                       "until you change your password."))
                         raise wiking.Redirect(password_change_uri)
                 return self._serve_document(req, result)
             elif isinstance(result, lcg.Content):
                 return self._serve_content(req, result)
             elif isinstance(result, wiking.Response):
                 last_modified = result.last_modified()
                 if last_modified is not None and req.cached_since(last_modified):
                     raise wiking.NotModified()
                 for header, value in result.headers():
                     req.set_header(header, value)
                 filename = result.filename()
                 if filename:
                     # When the filename contains non-ascii characters, uwsgi raises:
                     # TypeError: http header must be encodable in latin1
                     # Some context at: https://stackoverflow.com/questions/93551/
                     try:
                         filename.encode('latin-1')
                     except UnicodeEncodeError:
                         filename_info = "filename*=UTF-8''" + urllib.parse.quote(filename)
                     else:
                         filename_info = 'filename="%s"' % filename
                     disposition = 'inline' if result.inline() else 'attachment'
                     req.set_header('Content-Disposition', disposition + '; ' + filename_info)
                 return req.send_response(result.data(), content_type=result.content_type(),
                                          content_length=result.content_length(),
                                          status_code=result.status_code(),
                                          last_modified=result.last_modified())
             else:
                 raise Exception('Invalid handler result: %s' % type(result))
         except wiking.NotModified as error:
             return req.send_response('', status_code=error.status_code(), content_type=None)
         except wiking.Redirect as r:
             return req.redirect(r.uri(), r.args(), status_code=r.status_code())
         except wiking.RequestError as error:
             # Try to authenticate now, but ignore all errors within authentication except
             # for AuthenticationError.
             try:
                 req.user()
             except wiking.RequestError:
                 pass
             except wiking.AuthenticationError as auth_error:
                 error = auth_error
             return self._handle_request_error(req, error)
         except wiking.ClosedConnection:
             return []
     except Exception:
         # Any other unhandled exception is an Internal Server Error.  It is
         # handled in a separate try/except block to chatch also errors in
         # except blocks of the inner level.
         return self._handle_request_error(req, wiking.InternalServerError())
Example #6
0
 def _handle(self, req):
     try:
         try:
             if wiking.cfg.maintenance and not req.uri().startswith('/_resources/'):
                 # TODO: excluding /_resources/ is here to make stylesheets
                 # available for the maintenance error page.  The URI is
                 # however not necassarily correct (application may change
                 # it).  Better would most likely be including some basic styles
                 # directly in MinimalExporter.
                 return self._handle_maintenance_mode(req)
             # Very basic CSRF prevention
             if req.param('submit') and req.header('Referer'):
                 referer = urlparse.urlparse(req.header('Referer'))
                 referer_uri = (referer.scheme + '://' + referer.netloc +
                                urllib.unquote(referer.path))
                 request_uri = req.server_uri() + urlparse.urlparse(req.uri()).path
                 if referer_uri != request_uri:
                     wiking.debug("Request rejected due to CSRF protection:",
                                  referer_uri, request_uri)
                     raise wiking.Redirect(req.server_uri(current=True))
             # Regular processing starts here.
             try:
                 result = self._application.handle(req)
             except wiking.Abort as abort:
                 result = abort.result()
             if isinstance(result, (tuple, list)):
                 # Temporary backwards compatibility conversion.
                 content_type, data = result
                 result = wiking.Response(data, content_type=content_type)
             if isinstance(result, (lcg.Content, wiking.Document)):
                 if req.is_api_request():
                     # This is a very generic detection of invalid API
                     # requests.  We just assume, that the clients, which
                     # indicate that they accept JSON responses are API
                     # clients and they are not interested in responses, which
                     # display human readable content.
                     raise wiking.BadRequest(_("This URI does not belong to server API."))
                 # Always perform authentication (if it was not performed
                 # before) to handle authentication exceptions here and
                 # prevent them in export time.  If the result is a
                 # document, we will surely need to authenticate anyway,
                 # because we need to display the login control at the top
                 # of the page.
                 req.user()
                 if isinstance(result, wiking.Document):
                     return self._serve_document(req, result)
                 else:
                     return self._serve_content(req, result)
             elif isinstance(result, wiking.Response):
                 last_modified = result.last_modified()
                 if last_modified is not None and req.cached_since(last_modified):
                     raise wiking.NotModified()
                 for header, value in result.headers():
                     req.set_header(header, value)
                 filename = result.filename()
                 if filename:
                     req.set_header('Content-Disposition',
                                    'attachment; filename="%s"' % filename)
                 return req.send_response(result.data(), content_type=result.content_type(),
                                          content_length=result.content_length(),
                                          status_code=result.status_code(),
                                          last_modified=result.last_modified())
             else:
                 raise Exception('Invalid wiking handler result: %s' % type(result))
         except wiking.NotModified as error:
             return req.send_response('', status_code=error.status_code(), content_type=None)
         except wiking.Redirect as r:
             return req.redirect(r.uri(), r.args(), status_code=r.status_code())
         except wiking.RequestError as error:
             # Try to authenticate now, but ignore all errors within authentication except
             # for AuthenticationError.
             try:
                 req.user()
             except wiking.RequestError:
                 pass
             except wiking.AuthenticationError as auth_error:
                 error = auth_error
             return self._handle_request_error(req, error)
         except wiking.ClosedConnection:
             return []
     except Exception:
         # Any other unhandled exception is an Internal Server Error.  It is
         # handled in a separate try/except block to chatch also errors in
         # except blocks of the inner level.
         einfo = sys.exc_info()
         self._application.send_bug_report(req, einfo)
         self._application.log_traceback(req, einfo)
         return self._handle_request_error(req, wiking.InternalServerError(einfo))