123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
- import os
- import sys
- import threading
- import time
- from datetime import datetime
- from xml.etree import ElementTree
-
- import transaction
- import yaml
- from pyramid.paster import get_appsettings
- from wsgidav import util, compat
- from wsgidav.middleware import BaseMiddleware
-
- from tracim import CFG
- from tracim.lib.core.user import UserApi
- from tracim.models import get_engine, get_session_factory, get_tm_session
-
-
- class TracimWsgiDavDebugFilter(BaseMiddleware):
- """
- COPY PASTE OF wsgidav.debug_filter.WsgiDavDebugFilter
- WITH ADD OF DUMP RESPONSE & REQUEST
- """
- def __init__(self, application, config):
- self._application = application
- self._config = config
- # self.out = sys.stderr
- self.out = sys.stdout
- self.passedLitmus = {}
- # These methods boost verbose=2 to verbose=3
- self.debug_methods = config.get("debug_methods", [])
- # Litmus tests containing these string boost verbose=2 to verbose=3
- self.debug_litmus = config.get("debug_litmus", [])
- # Exit server, as soon as this litmus test has finished
- self.break_after_litmus = [
- # "locks: 15",
- ]
-
- self.last_request_time = '__NOT_SET__'
-
- # We disable request content dump for moment
- # if self._config.get('dump_requests'):
- # # Monkey patching
- # old_parseXmlBody = util.parseXmlBody
- # def new_parseXmlBody(environ, allowEmpty=False):
- # xml = old_parseXmlBody(environ, allowEmpty)
- # self._dump_request(environ, xml)
- # return xml
- # util.parseXmlBody = new_parseXmlBody
-
- def __call__(self, environ, start_response):
- """"""
- # srvcfg = environ["wsgidav.config"]
- verbose = self._config.get("verbose", 2)
- self.last_request_time = '{0}_{1}'.format(
- datetime.utcnow().strftime('%Y-%m-%d_%H-%M-%S'),
- int(round(time.time() * 1000)),
- )
-
- method = environ["REQUEST_METHOD"]
-
- debugBreak = False
- dumpRequest = False
- dumpResponse = False
-
- if verbose >= 3 or self._config.get("dump_requests"):
- dumpRequest = dumpResponse = True
-
- # Process URL commands
- if "dump_storage" in environ.get("QUERY_STRING"):
- dav = environ.get("wsgidav.provider")
- if dav.lockManager:
- dav.lockManager._dump()
- if dav.propManager:
- dav.propManager._dump()
-
- # Turn on max. debugging for selected litmus tests
- litmusTag = environ.get("HTTP_X_LITMUS",
- environ.get("HTTP_X_LITMUS_SECOND"))
- if litmusTag and verbose >= 2:
- print("----\nRunning litmus test '%s'..." % litmusTag,
- file=self.out)
- for litmusSubstring in self.debug_litmus:
- if litmusSubstring in litmusTag:
- verbose = 3
- debugBreak = True
- dumpRequest = True
- dumpResponse = True
- break
- for litmusSubstring in self.break_after_litmus:
- if litmusSubstring in self.passedLitmus and litmusSubstring not in litmusTag:
- print(" *** break after litmus %s" % litmusTag,
- file=self.out)
- sys.exit(-1)
- if litmusSubstring in litmusTag:
- self.passedLitmus[litmusSubstring] = True
-
- # Turn on max. debugging for selected request methods
- if verbose >= 2 and method in self.debug_methods:
- verbose = 3
- debugBreak = True
- dumpRequest = True
- dumpResponse = True
-
- # Set debug options to environment
- environ["wsgidav.verbose"] = verbose
- # environ["wsgidav.debug_methods"] = self.debug_methods
- environ["wsgidav.debug_break"] = debugBreak
- environ["wsgidav.dump_request_body"] = dumpRequest
- environ["wsgidav.dump_response_body"] = dumpResponse
-
- # Dump request headers
- if dumpRequest:
- print("<%s> --- %s Request ---" % (
- threading.currentThread().ident, method), file=self.out)
- for k, v in environ.items():
- if k == k.upper():
- print("%20s: '%s'" % (k, v), file=self.out)
- print("\n", file=self.out)
- self._dump_request(environ, xml=None)
-
- # Intercept start_response
- #
- sub_app_start_response = util.SubAppStartResponse()
-
- nbytes = 0
- first_yield = True
- app_iter = self._application(environ, sub_app_start_response)
-
- for v in app_iter:
- # Start response (the first time)
- if first_yield:
- # Success!
- start_response(sub_app_start_response.status,
- sub_app_start_response.response_headers,
- sub_app_start_response.exc_info)
-
- # Dump response headers
- if first_yield and dumpResponse:
- print("<%s> --- %s Response(%s): ---" % (
- threading.currentThread().ident,
- method,
- sub_app_start_response.status),
- file=self.out)
- headersdict = dict(sub_app_start_response.response_headers)
- for envitem in headersdict.keys():
- print("%s: %s" % (envitem, repr(headersdict[envitem])),
- file=self.out)
- print("", file=self.out)
-
- # Check, if response is a binary string, otherwise we probably have
- # calculated a wrong content-length
- assert compat.is_bytes(v), v
-
- # Dump response body
- drb = environ.get("wsgidav.dump_response_body")
- if compat.is_basestring(drb):
- # Middleware provided a formatted body representation
- print(drb, file=self.out)
- elif drb is True:
- # Else dump what we get, (except for long GET responses)
- if method == "GET":
- if first_yield:
- print(v[:50], "...", file=self.out)
- elif len(v) > 0:
- print(v, file=self.out)
-
- if dumpResponse:
- self._dump_response(sub_app_start_response, drb)
-
- drb = environ["wsgidav.dump_response_body"] = None
-
- nbytes += len(v)
- first_yield = False
- yield v
- if hasattr(app_iter, "close"):
- app_iter.close()
-
- # Start response (if it hasn't been done yet)
- if first_yield:
- # Success!
- start_response(sub_app_start_response.status,
- sub_app_start_response.response_headers,
- sub_app_start_response.exc_info)
-
- if dumpResponse:
- print("\n<%s> --- End of %s Response (%i bytes) ---" % (
- threading.currentThread().ident, method, nbytes), file=self.out)
- return
-
- def _dump_response(self, sub_app_start_response, drb):
- dump_to_path = self._config.get(
- 'dump_requests_path',
- '/tmp/wsgidav_dumps',
- )
- os.makedirs(dump_to_path, exist_ok=True)
- dump_file = '{0}/{1}_RESPONSE_{2}.yml'.format(
- dump_to_path,
- self.last_request_time,
- sub_app_start_response.status[0:3],
- )
- with open(dump_file, 'w+') as f:
- dump_content = dict()
- headers = {}
- for header_tuple in sub_app_start_response.response_headers:
- headers[header_tuple[0]] = header_tuple[1]
- dump_content['headers'] = headers
- if isinstance(drb, str):
- dump_content['content'] = drb.replace('PROPFIND XML response body:\n', '')
-
- f.write(yaml.dump(dump_content, default_flow_style=False))
-
- def _dump_request(self, environ, xml):
- dump_to_path = self._config.get(
- 'dump_requests_path',
- '/tmp/wsgidav_dumps',
- )
- os.makedirs(dump_to_path, exist_ok=True)
- dump_file = '{0}/{1}_REQUEST_{2}.yml'.format(
- dump_to_path,
- self.last_request_time,
- environ['REQUEST_METHOD'],
- )
- with open(dump_file, 'w+') as f:
- dump_content = dict()
- dump_content['path'] = environ.get('PATH_INFO', '')
- dump_content['Authorization'] = environ.get('HTTP_AUTHORIZATION', '')
- if xml:
- dump_content['content'] = ElementTree.tostring(xml, 'utf-8')
-
- f.write(yaml.dump(dump_content, default_flow_style=False))
-
-
- class TracimEnforceHTTPS(BaseMiddleware):
-
- def __init__(self, application, config):
- super().__init__(application, config)
- self._application = application
- self._config = config
-
- def __call__(self, environ, start_response):
- # TODO - G.M - 06-03-2018 - Check protocol from http header first
- # see http://www.bortzmeyer.org/7239.html
- # if this params doesn't exist, rely on tracim config
- # from tracim.config.app_cfg import CFG
- # cfg = CFG.get_instance()
- #
- # if cfg.WEBSITE_BASE_URL.startswith('https'):
- # environ['wsgi.url_scheme'] = 'https'
- return self._application(environ, start_response)
-
-
- class TracimEnv(BaseMiddleware):
-
- def __init__(self, application, config):
- super().__init__(application, config)
- self._application = application
- self._config = config
- self.settings = get_appsettings(config['tracim_config'])
- self.engine = get_engine(self.settings)
- self.session_factory = get_session_factory(self.engine)
- self.app_config = CFG(self.settings)
- self.app_config.configure_filedepot()
-
- def __call__(self, environ, start_response):
- with transaction.manager as tm:
- dbsession = get_tm_session(self.session_factory, transaction.manager)
- environ['tracim_tm'] = tm
- environ['tracim_dbsession'] = dbsession
- environ['tracim_cfg'] = self.app_config
-
- return self._application(environ, start_response)
-
-
- class TracimUserSession(BaseMiddleware):
-
- def __init__(self, application, config):
- super().__init__(application, config)
- self._application = application
- self._config = config
-
- def __call__(self, environ, start_response):
- environ['tracim_user'] = UserApi(
- None,
- session=environ['tracim_dbsession'],
- config=environ['tracim_cfg'],
- ).get_one_by_email(environ['http_authenticator.username'])
- return self._application(environ, start_response)
|