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