##// END OF EJS Templates
vcs: added logging into VCS middlewares
marcink -
r753:bb7a4b59 default
parent child Browse files
Show More
@@ -1,81 +1,84 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 """
22 22 SimpleGit middleware for handling git protocol request (push/clone etc.)
23 23 It's implemented with basic auth function
24 24 """
25 25 import re
26 import logging
26 27 import urlparse
27 28
28 29 import rhodecode
29 30 from rhodecode.lib import utils2
30 31 from rhodecode.lib.middleware import simplevcs
31 32
33 log = logging.getLogger(__name__)
34
32 35
33 36 GIT_PROTO_PAT = re.compile(
34 37 r'^/(.+)/(info/refs|git-upload-pack|git-receive-pack)')
35 38
36 39
37 40 class SimpleGit(simplevcs.SimpleVCS):
38 41
39 42 SCM = 'git'
40 43
41 44 def _get_repository_name(self, environ):
42 45 """
43 46 Gets repository name out of PATH_INFO header
44 47
45 48 :param environ: environ where PATH_INFO is stored
46 49 """
47 50 repo_name = GIT_PROTO_PAT.match(environ['PATH_INFO']).group(1)
48 51 return repo_name
49 52
50 53 _ACTION_MAPPING = {
51 54 'git-receive-pack': 'push',
52 55 'git-upload-pack': 'pull',
53 56 }
54 57
55 58 def _get_action(self, environ):
56 59 """
57 60 Maps git request commands into a pull or push command.
58 61 In case of unknown/unexpected data, it returns 'pull' to be safe.
59 62
60 63 :param environ:
61 64 """
62 65 path = environ['PATH_INFO']
63 66
64 67 if path.endswith('/info/refs'):
65 68 query = urlparse.parse_qs(environ['QUERY_STRING'])
66 69 service_cmd = query.get('service', [''])[0]
67 70 return self._ACTION_MAPPING.get(service_cmd, 'pull')
68 71 elif path.endswith('/git-receive-pack'):
69 72 return 'push'
70 73 elif path.endswith('/git-upload-pack'):
71 74 return 'pull'
72 75
73 76 return 'pull'
74 77
75 78 def _create_wsgi_app(self, repo_path, repo_name, config):
76 79 return self.scm_app.create_git_wsgi_app(repo_path, repo_name, config)
77 80
78 81 def _create_config(self, extras, repo_name):
79 82 extras['git_update_server_info'] = utils2.str2bool(
80 83 rhodecode.CONFIG.get('git_update_server_info'))
81 84 return extras
@@ -1,77 +1,80 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 """
22 22 SimpleHG middleware for handling mercurial protocol request
23 23 (push/clone etc.). It's implemented with basic auth function
24 24 """
25 25
26 import logging
26 27 import urlparse
27 28
28 29 from rhodecode.lib import utils
29 30 from rhodecode.lib.ext_json import json
30 31 from rhodecode.lib.middleware import simplevcs
31 32
33 log = logging.getLogger(__name__)
34
32 35
33 36 class SimpleHg(simplevcs.SimpleVCS):
34 37
35 38 SCM = 'hg'
36 39
37 40 def _get_repository_name(self, environ):
38 41 """
39 42 Gets repository name out of PATH_INFO header
40 43
41 44 :param environ: environ where PATH_INFO is stored
42 45 """
43 46 return environ['PATH_INFO'].strip('/')
44 47
45 48 _ACTION_MAPPING = {
46 49 'changegroup': 'pull',
47 50 'changegroupsubset': 'pull',
48 51 'getbundle': 'pull',
49 52 'stream_out': 'pull',
50 53 'listkeys': 'pull',
51 54 'unbundle': 'push',
52 55 'pushkey': 'push',
53 56 }
54 57
55 58 def _get_action(self, environ):
56 59 """
57 60 Maps mercurial request commands into a pull or push command.
58 61 In case of unknown/unexpected data, it returns 'pull' to be safe.
59 62
60 63 :param environ:
61 64 """
62 65 query = urlparse.parse_qs(environ['QUERY_STRING'],
63 66 keep_blank_values=True)
64 67 if 'cmd' in query:
65 68 cmd = query['cmd'][0]
66 69 return self._ACTION_MAPPING.get(cmd, 'pull')
67 70
68 71 return 'pull'
69 72
70 73 def _create_wsgi_app(self, repo_path, repo_name, config):
71 74 return self.scm_app.create_hg_wsgi_app(repo_path, repo_name, config)
72 75
73 76 def _create_config(self, extras, repo_name):
74 77 config = utils.make_db_config(repo=repo_name)
75 78 config.set('rhodecode', 'RC_SCM_DATA', json.dumps(extras))
76 79
77 80 return config.serialize()
@@ -1,136 +1,139 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 import logging
21 22 from urlparse import urljoin
22 23
23 24 import requests
24 25
25 26 import rhodecode
26 27 from rhodecode.lib.middleware import simplevcs
27 28 from rhodecode.lib.utils import is_valid_repo
28 29
30 log = logging.getLogger(__name__)
31
29 32
30 33 class SimpleSvnApp(object):
31 34 IGNORED_HEADERS = [
32 35 'connection', 'keep-alive', 'content-encoding',
33 36 'transfer-encoding', 'content-length']
34 37
35 38 def __init__(self, config):
36 39 self.config = config
37 40
38 41 def __call__(self, environ, start_response):
39 42 request_headers = self._get_request_headers(environ)
40 43
41 44 data = environ['wsgi.input']
42 45 # johbo: Avoid that we end up with sending the request in chunked
43 46 # transfer encoding (mainly on Gunicorn). If we know the content
44 47 # length, then we should transfer the payload in one request.
45 48 if environ['REQUEST_METHOD'] == 'MKCOL' or 'CONTENT_LENGTH' in environ:
46 49 data = data.read()
47 50
48 51 response = requests.request(
49 52 environ['REQUEST_METHOD'], self._get_url(environ['PATH_INFO']),
50 53 data=data, headers=request_headers)
51 54
52 55 response_headers = self._get_response_headers(response.headers)
53 56 start_response(
54 57 '{} {}'.format(response.status_code, response.reason),
55 58 response_headers)
56 59 return response.iter_content(chunk_size=1024)
57 60
58 61 def _get_url(self, path):
59 62 return urljoin(
60 63 self.config.get('subversion_http_server_url', ''), path)
61 64
62 65 def _get_request_headers(self, environ):
63 66 headers = {}
64 67
65 68 for key in environ:
66 69 if not key.startswith('HTTP_'):
67 70 continue
68 71 new_key = key.split('_')
69 72 new_key = [k.capitalize() for k in new_key[1:]]
70 73 new_key = '-'.join(new_key)
71 74 headers[new_key] = environ[key]
72 75
73 76 if 'CONTENT_TYPE' in environ:
74 77 headers['Content-Type'] = environ['CONTENT_TYPE']
75 78
76 79 if 'CONTENT_LENGTH' in environ:
77 80 headers['Content-Length'] = environ['CONTENT_LENGTH']
78 81
79 82 return headers
80 83
81 84 def _get_response_headers(self, headers):
82 85 headers = [
83 86 (h, headers[h])
84 87 for h in headers
85 88 if h.lower() not in self.IGNORED_HEADERS
86 89 ]
87 90
88 91 # Add custom response header to indicate that this is a VCS response
89 92 # and which backend is used.
90 93 headers.append(('X-RhodeCode-Backend', 'svn'))
91 94
92 95 return headers
93 96
94 97
95 98 class SimpleSvn(simplevcs.SimpleVCS):
96 99
97 100 SCM = 'svn'
98 101 READ_ONLY_COMMANDS = ('OPTIONS', 'PROPFIND', 'GET', 'REPORT')
99 102
100 103 def _get_repository_name(self, environ):
101 104 """
102 105 Gets repository name out of PATH_INFO header
103 106
104 107 :param environ: environ where PATH_INFO is stored
105 108 """
106 109 path = environ['PATH_INFO'].split('!')
107 110 repo_name = path[0].strip('/')
108 111
109 112 # SVN includes the whole path in it's requests, including
110 113 # subdirectories inside the repo. Therefore we have to search for
111 114 # the repo root directory.
112 115 if not is_valid_repo(repo_name, self.basepath, self.SCM):
113 116 current_path = ''
114 117 for component in repo_name.split('/'):
115 118 current_path += component
116 119 if is_valid_repo(current_path, self.basepath, self.SCM):
117 120 return current_path
118 121 current_path += '/'
119 122
120 123 return repo_name
121 124
122 125 def _get_action(self, environ):
123 126 return (
124 127 'pull'
125 128 if environ['REQUEST_METHOD'] in self.READ_ONLY_COMMANDS
126 129 else 'push')
127 130
128 131 def _create_wsgi_app(self, repo_path, repo_name, config):
129 132 return SimpleSvnApp(config)
130 133
131 134 def _create_config(self, extras, repo_name):
132 135 server_url = rhodecode.CONFIG.get(
133 136 'rhodecode_subversion_http_server_url', '')
134 137 extras['subversion_http_server_url'] = (
135 138 server_url or 'http://localhost/')
136 139 return extras
General Comments 0
You need to be logged in to leave comments. Login now