##// END OF EJS Templates
dirty fix for https working.
marcink -
r203:be6d8aad default
parent child Browse files
Show More
@@ -1,70 +1,69
1 """Pylons middleware initialization"""
1 """Pylons middleware initialization"""
2 from beaker.middleware import SessionMiddleware
2 from beaker.middleware import SessionMiddleware
3 from paste.cascade import Cascade
3 from paste.cascade import Cascade
4 from paste.registry import RegistryManager
4 from paste.registry import RegistryManager
5 from paste.urlparser import StaticURLParser
5 from paste.urlparser import StaticURLParser
6 from paste.deploy.converters import asbool
6 from paste.deploy.converters import asbool
7 from pylons.middleware import ErrorHandler, StatusCodeRedirect
7 from pylons.middleware import ErrorHandler, StatusCodeRedirect
8 from pylons.wsgiapp import PylonsApp
8 from pylons.wsgiapp import PylonsApp
9 from routes.middleware import RoutesMiddleware
9 from routes.middleware import RoutesMiddleware
10 from paste.auth.basic import AuthBasicHandler
11 from pylons_app.lib.simplehg import SimpleHg
10 from pylons_app.lib.simplehg import SimpleHg
12 from pylons_app.config.environment import load_environment
11 from pylons_app.config.environment import load_environment
13
12
14 def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
13 def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
15 """Create a Pylons WSGI application and return it
14 """Create a Pylons WSGI application and return it
16
15
17 ``global_conf``
16 ``global_conf``
18 The inherited configuration for this application. Normally from
17 The inherited configuration for this application. Normally from
19 the [DEFAULT] section of the Paste ini file.
18 the [DEFAULT] section of the Paste ini file.
20
19
21 ``full_stack``
20 ``full_stack``
22 Whether or not this application provides a full WSGI stack (by
21 Whether or not this application provides a full WSGI stack (by
23 default, meaning it handles its own exceptions and errors).
22 default, meaning it handles its own exceptions and errors).
24 Disable full_stack when this application is "managed" by
23 Disable full_stack when this application is "managed" by
25 another WSGI middleware.
24 another WSGI middleware.
26
25
27 ``app_conf``
26 ``app_conf``
28 The application's local configuration. Normally specified in
27 The application's local configuration. Normally specified in
29 the [app:<name>] section of the Paste ini file (where <name>
28 the [app:<name>] section of the Paste ini file (where <name>
30 defaults to main).
29 defaults to main).
31
30
32 """
31 """
33 # Configure the Pylons environment
32 # Configure the Pylons environment
34 config = load_environment(global_conf, app_conf)
33 config = load_environment(global_conf, app_conf)
35
34
36
35
37 # The Pylons WSGI app
36 # The Pylons WSGI app
38 app = PylonsApp(config=config)
37 app = PylonsApp(config=config)
39
38
40
39
41 # Routing/Session/Cache Middleware
40 # Routing/Session/Cache Middleware
42 app = RoutesMiddleware(app, config['routes.map'])
41 app = RoutesMiddleware(app, config['routes.map'])
43 app = SessionMiddleware(app, config)
42 app = SessionMiddleware(app, config)
44
43
45 # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
44 # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
46 app = SimpleHg(app, config)
45 app = SimpleHg(app, config)
47
46
48 if asbool(full_stack):
47 if asbool(full_stack):
49 # Handle Python exceptions
48 # Handle Python exceptions
50 app = ErrorHandler(app, global_conf, **config['pylons.errorware'])
49 app = ErrorHandler(app, global_conf, **config['pylons.errorware'])
51
50
52 # Display error documents for 401, 403, 404 status codes (and
51 # Display error documents for 401, 403, 404 status codes (and
53 # 500 when debug is disabled)
52 # 500 when debug is disabled)
54 if asbool(config['debug']):
53 if asbool(config['debug']):
55 app = StatusCodeRedirect(app)
54 app = StatusCodeRedirect(app)
56 else:
55 else:
57 app = StatusCodeRedirect(app, [400, 401, 403, 404, 500])
56 app = StatusCodeRedirect(app, [400, 401, 403, 404, 500])
58
57
59 # Establish the Registry for this application
58 # Establish the Registry for this application
60 app = RegistryManager(app)
59 app = RegistryManager(app)
61
60
62 if asbool(static_files):
61 if asbool(static_files):
63 # Serve static files
62 # Serve static files
64 static_app = StaticURLParser(config['pylons.paths']['static_files'])
63 static_app = StaticURLParser(config['pylons.paths']['static_files'])
65 app = Cascade([static_app, app])
64 app = Cascade([static_app, app])
66
65
67 app.config = config
66 app.config = config
68
67
69 return app
68 return app
70
69
@@ -1,139 +1,141
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 #
3 #
4 # Copyright (c) 2010 marcink. All rights reserved.
4 # Copyright (c) 2010 marcink. All rights reserved.
5 #
5 #
6 """
6 """
7 Created on 2010-04-28
7 Created on 2010-04-28
8
8
9 @author: marcink
9 @author: marcink
10 SimpleHG middleware for handling mercurial protocol request (push/clone etc.)
10 SimpleHG middleware for handling mercurial protocol request (push/clone etc.)
11 It's implemented with basic auth function
11 It's implemented with basic auth function
12 """
12 """
13 from datetime import datetime
13 from datetime import datetime
14 from mercurial.hgweb import hgweb
14 from mercurial.hgweb import hgweb
15 from mercurial.hgweb.request import wsgiapplication
15 from mercurial.hgweb.request import wsgiapplication
16 from paste.auth.basic import AuthBasicAuthenticator
16 from paste.auth.basic import AuthBasicAuthenticator
17 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
17 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
18 from pylons_app.lib.auth import authfunc
18 from pylons_app.lib.auth import authfunc
19 from pylons_app.lib.utils import is_mercurial, make_ui, invalidate_cache
19 from pylons_app.lib.utils import is_mercurial, make_ui, invalidate_cache
20 from pylons_app.model import meta
20 from pylons_app.model import meta
21 from pylons_app.model.db import UserLogs, Users
21 from pylons_app.model.db import UserLogs, Users
22 from webob.exc import HTTPNotFound
22 from webob.exc import HTTPNotFound
23 import logging
23 import logging
24 import os
24 import os
25 log = logging.getLogger(__name__)
25 log = logging.getLogger(__name__)
26
26
27 class SimpleHg(object):
27 class SimpleHg(object):
28
28
29 def __init__(self, application, config):
29 def __init__(self, application, config):
30 self.application = application
30 self.application = application
31 self.config = config
31 self.config = config
32 #authenticate this mercurial request using
32 #authenticate this mercurial request using
33 realm = '%s %s' % (config['hg_app_name'], 'mercurial repository')
33 realm = '%s %s' % (config['hg_app_name'], 'mercurial repository')
34 self.authenticate = AuthBasicAuthenticator(realm, authfunc)
34 self.authenticate = AuthBasicAuthenticator(realm, authfunc)
35
35
36 def __call__(self, environ, start_response):
36 def __call__(self, environ, start_response):
37 #dirty fix for https
38 environ['wsgi.url_scheme'] = 'https'
37 if not is_mercurial(environ):
39 if not is_mercurial(environ):
38 return self.application(environ, start_response)
40 return self.application(environ, start_response)
39 else:
41 else:
40 #===================================================================
42 #===================================================================
41 # AUTHENTICATE THIS MERCURIAL REQUEST
43 # AUTHENTICATE THIS MERCURIAL REQUEST
42 #===================================================================
44 #===================================================================
43 username = REMOTE_USER(environ)
45 username = REMOTE_USER(environ)
44 if not username:
46 if not username:
45 result = self.authenticate(environ)
47 result = self.authenticate(environ)
46 if isinstance(result, str):
48 if isinstance(result, str):
47 AUTH_TYPE.update(environ, 'basic')
49 AUTH_TYPE.update(environ, 'basic')
48 REMOTE_USER.update(environ, result)
50 REMOTE_USER.update(environ, result)
49 else:
51 else:
50 return result.wsgi_application(environ, start_response)
52 return result.wsgi_application(environ, start_response)
51
53
52 try:
54 try:
53 repo_name = environ['PATH_INFO'].split('/')[1]
55 repo_name = environ['PATH_INFO'].split('/')[1]
54 except:
56 except:
55 return HTTPNotFound()(environ, start_response)
57 return HTTPNotFound()(environ, start_response)
56
58
57 #since we wrap into hgweb, just reset the path
59 #since we wrap into hgweb, just reset the path
58 environ['PATH_INFO'] = '/'
60 environ['PATH_INFO'] = '/'
59 self.baseui = make_ui()
61 self.baseui = make_ui()
60 self.basepath = self.baseui.configitems('paths')[0][1]\
62 self.basepath = self.baseui.configitems('paths')[0][1]\
61 .replace('*', '')
63 .replace('*', '')
62 self.repo_path = os.path.join(self.basepath, repo_name)
64 self.repo_path = os.path.join(self.basepath, repo_name)
63 try:
65 try:
64 app = wsgiapplication(self.__make_app)
66 app = wsgiapplication(self.__make_app)
65 except Exception as e:
67 except Exception as e:
66 return HTTPNotFound()(environ, start_response)
68 return HTTPNotFound()(environ, start_response)
67
69
68 action = self.__get_action(environ)
70 action = self.__get_action(environ)
69 #invalidate cache on push
71 #invalidate cache on push
70 if action == 'push':
72 if action == 'push':
71 self.__invalidate_cache(repo_name)
73 self.__invalidate_cache(repo_name)
72
74
73 if action:
75 if action:
74 username = self.__get_environ_user(environ)
76 username = self.__get_environ_user(environ)
75 self.__log_user_action(username, action, repo_name)
77 self.__log_user_action(username, action, repo_name)
76 return app(environ, start_response)
78 return app(environ, start_response)
77
79
78 def __make_app(self):
80 def __make_app(self):
79 hgserve = hgweb(self.repo_path)
81 hgserve = hgweb(self.repo_path)
80 return self.load_web_settings(hgserve)
82 return self.load_web_settings(hgserve)
81
83
82 def __get_environ_user(self, environ):
84 def __get_environ_user(self, environ):
83 return environ.get('REMOTE_USER')
85 return environ.get('REMOTE_USER')
84
86
85 def __get_action(self, environ):
87 def __get_action(self, environ):
86 """
88 """
87 Maps mercurial request commands into a pull or push command.
89 Maps mercurial request commands into a pull or push command.
88 @param environ:
90 @param environ:
89 """
91 """
90 mapping = {
92 mapping = {
91 'changegroup': 'pull',
93 'changegroup': 'pull',
92 'changegroupsubset': 'pull',
94 'changegroupsubset': 'pull',
93 'unbundle': 'push',
95 'unbundle': 'push',
94 'stream_out': 'pull',
96 'stream_out': 'pull',
95 }
97 }
96 for qry in environ['QUERY_STRING'].split('&'):
98 for qry in environ['QUERY_STRING'].split('&'):
97 if qry.startswith('cmd'):
99 if qry.startswith('cmd'):
98 cmd = qry.split('=')[-1]
100 cmd = qry.split('=')[-1]
99 if mapping.has_key(cmd):
101 if mapping.has_key(cmd):
100 return mapping[cmd]
102 return mapping[cmd]
101
103
102 def __log_user_action(self, username, action, repo):
104 def __log_user_action(self, username, action, repo):
103 sa = meta.Session
105 sa = meta.Session
104 try:
106 try:
105 user = sa.query(Users)\
107 user = sa.query(Users)\
106 .filter(Users.username == username).one()
108 .filter(Users.username == username).one()
107 user_log = UserLogs()
109 user_log = UserLogs()
108 user_log.user_id = user.user_id
110 user_log.user_id = user.user_id
109 user_log.action = action
111 user_log.action = action
110 user_log.repository = repo.replace('/', '')
112 user_log.repository = repo.replace('/', '')
111 user_log.action_date = datetime.now()
113 user_log.action_date = datetime.now()
112 sa.add(user_log)
114 sa.add(user_log)
113 sa.commit()
115 sa.commit()
114 log.info('Adding user %s, action %s on %s',
116 log.info('Adding user %s, action %s on %s',
115 username, action, repo)
117 username, action, repo)
116 except Exception as e:
118 except Exception as e:
117 sa.rollback()
119 sa.rollback()
118 log.error('could not log user action:%s', str(e))
120 log.error('could not log user action:%s', str(e))
119
121
120 def __invalidate_cache(self, repo_name):
122 def __invalidate_cache(self, repo_name):
121 """we know that some change was made to repositories and we should
123 """we know that some change was made to repositories and we should
122 invalidate the cache to see the changes right away but only for
124 invalidate the cache to see the changes right away but only for
123 push requests"""
125 push requests"""
124 invalidate_cache('cached_repo_list')
126 invalidate_cache('cached_repo_list')
125 invalidate_cache('full_changelog', repo_name)
127 invalidate_cache('full_changelog', repo_name)
126
128
127
129
128 def load_web_settings(self, hgserve):
130 def load_web_settings(self, hgserve):
129 repoui = make_ui(os.path.join(self.repo_path, '.hg', 'hgrc'), False)
131 repoui = make_ui(os.path.join(self.repo_path, '.hg', 'hgrc'), False)
130 #set the global ui for hgserve
132 #set the global ui for hgserve
131 hgserve.repo.ui = self.baseui
133 hgserve.repo.ui = self.baseui
132
134
133 if repoui:
135 if repoui:
134 #set the repository based config
136 #set the repository based config
135 hgserve.repo.ui = repoui
137 hgserve.repo.ui = repoui
136
138
137 return hgserve
139 return hgserve
138
140
139
141
General Comments 0
You need to be logged in to leave comments. Login now