##// END OF EJS Templates
svn: log response code for SVN calls always even for 200 codes.
marcink -
r2403:a8bbceb1 default
parent child Browse files
Show More
@@ -1,173 +1,175 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 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 import logging
22 22 import urllib
23 23 from urlparse import urljoin
24 24
25 25
26 26 import requests
27 27 from webob.exc import HTTPNotAcceptable
28 28
29 29 from rhodecode.lib.middleware import simplevcs
30 30 from rhodecode.lib.utils import is_valid_repo
31 31 from rhodecode.lib.utils2 import str2bool
32 32
33 33 log = logging.getLogger(__name__)
34 34
35 35
36 36 class SimpleSvnApp(object):
37 37 IGNORED_HEADERS = [
38 38 'connection', 'keep-alive', 'content-encoding',
39 39 'transfer-encoding', 'content-length']
40 40 rc_extras = {}
41 41
42 42
43 43 def __init__(self, config):
44 44 self.config = config
45 45
46 46 def __call__(self, environ, start_response):
47 47 request_headers = self._get_request_headers(environ)
48 48
49 49 data = environ['wsgi.input']
50 50 # johbo: Avoid that we end up with sending the request in chunked
51 51 # transfer encoding (mainly on Gunicorn). If we know the content
52 52 # length, then we should transfer the payload in one request.
53 53 if environ['REQUEST_METHOD'] == 'MKCOL' or 'CONTENT_LENGTH' in environ:
54 54 data = data.read()
55 55
56 56 log.debug('Calling: %s method via `%s`', environ['REQUEST_METHOD'],
57 57 self._get_url(environ['PATH_INFO']))
58 58 response = requests.request(
59 59 environ['REQUEST_METHOD'], self._get_url(environ['PATH_INFO']),
60 60 data=data, headers=request_headers)
61 61
62 62 if response.status_code not in [200, 401]:
63 63 if response.status_code >= 500:
64 64 log.error('Got SVN response:%s with text:`%s`',
65 65 response, response.text)
66 66 else:
67 67 log.debug('Got SVN response:%s with text:`%s`',
68 68 response, response.text)
69 else:
70 log.debug('got response code: %s', response.status_code)
69 71
70 72 response_headers = self._get_response_headers(response.headers)
71 73 start_response(
72 74 '{} {}'.format(response.status_code, response.reason),
73 75 response_headers)
74 76 return response.iter_content(chunk_size=1024)
75 77
76 78 def _get_url(self, path):
77 79 url_path = urljoin(
78 80 self.config.get('subversion_http_server_url', ''), path)
79 81 url_path = urllib.quote(url_path, safe="/:=~+!$,;'")
80 82 return url_path
81 83
82 84 def _get_request_headers(self, environ):
83 85 headers = {}
84 86
85 87 for key in environ:
86 88 if not key.startswith('HTTP_'):
87 89 continue
88 90 new_key = key.split('_')
89 91 new_key = [k.capitalize() for k in new_key[1:]]
90 92 new_key = '-'.join(new_key)
91 93 headers[new_key] = environ[key]
92 94
93 95 if 'CONTENT_TYPE' in environ:
94 96 headers['Content-Type'] = environ['CONTENT_TYPE']
95 97
96 98 if 'CONTENT_LENGTH' in environ:
97 99 headers['Content-Length'] = environ['CONTENT_LENGTH']
98 100
99 101 return headers
100 102
101 103 def _get_response_headers(self, headers):
102 104 headers = [
103 105 (h, headers[h])
104 106 for h in headers
105 107 if h.lower() not in self.IGNORED_HEADERS
106 108 ]
107 109
108 110 return headers
109 111
110 112
111 113 class DisabledSimpleSvnApp(object):
112 114 def __init__(self, config):
113 115 self.config = config
114 116
115 117 def __call__(self, environ, start_response):
116 118 reason = 'Cannot handle SVN call because: SVN HTTP Proxy is not enabled'
117 119 log.warning(reason)
118 120 return HTTPNotAcceptable(reason)(environ, start_response)
119 121
120 122
121 123 class SimpleSvn(simplevcs.SimpleVCS):
122 124
123 125 SCM = 'svn'
124 126 READ_ONLY_COMMANDS = ('OPTIONS', 'PROPFIND', 'GET', 'REPORT')
125 127 DEFAULT_HTTP_SERVER = 'http://localhost:8090'
126 128
127 129 def _get_repository_name(self, environ):
128 130 """
129 131 Gets repository name out of PATH_INFO header
130 132
131 133 :param environ: environ where PATH_INFO is stored
132 134 """
133 135 path = environ['PATH_INFO'].split('!')
134 136 repo_name = path[0].strip('/')
135 137
136 138 # SVN includes the whole path in it's requests, including
137 139 # subdirectories inside the repo. Therefore we have to search for
138 140 # the repo root directory.
139 141 if not is_valid_repo(
140 142 repo_name, self.base_path, explicit_scm=self.SCM):
141 143 current_path = ''
142 144 for component in repo_name.split('/'):
143 145 current_path += component
144 146 if is_valid_repo(
145 147 current_path, self.base_path, explicit_scm=self.SCM):
146 148 return current_path
147 149 current_path += '/'
148 150
149 151 return repo_name
150 152
151 153 def _get_action(self, environ):
152 154 return (
153 155 'pull'
154 156 if environ['REQUEST_METHOD'] in self.READ_ONLY_COMMANDS
155 157 else 'push')
156 158
157 159 def _create_wsgi_app(self, repo_path, repo_name, config):
158 160 if self._is_svn_enabled():
159 161 return SimpleSvnApp(config)
160 162 # we don't have http proxy enabled return dummy request handler
161 163 return DisabledSimpleSvnApp(config)
162 164
163 165 def _is_svn_enabled(self):
164 166 conf = self.repo_vcs_config
165 167 return str2bool(conf.get('vcs_svn_proxy', 'http_requests_enabled'))
166 168
167 169 def _create_config(self, extras, repo_name):
168 170 conf = self.repo_vcs_config
169 171 server_url = conf.get('vcs_svn_proxy', 'http_server_url')
170 172 server_url = server_url or self.DEFAULT_HTTP_SERVER
171 173
172 174 extras['subversion_http_server_url'] = server_url
173 175 return extras
General Comments 0
You need to be logged in to leave comments. Login now