##// END OF EJS Templates
vcs-http: set user-agent
marcink -
r3860:6741e7c0 default
parent child Browse files
Show More
@@ -1,186 +1,188 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2014-2019 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 Various version Control System version lib (vcs) management abstraction layer
23 23 for Python. Build with server client architecture.
24 24 """
25 25 import atexit
26 26 import logging
27 27 import urlparse
28 28 from cStringIO import StringIO
29 29
30 import rhodecode
30 31 from rhodecode.lib.vcs.conf import settings
31 32 from rhodecode.lib.vcs.backends import get_vcs_instance, get_backend
32 33 from rhodecode.lib.vcs.exceptions import (
33 34 VCSError, RepositoryError, CommitError, VCSCommunicationError)
34 35
35 36 VERSION = (0, 5, 0, 'dev')
36 37
37 38 __version__ = '.'.join((str(each) for each in VERSION[:4]))
38 39
39 40 __all__ = [
40 41 'get_version', 'get_vcs_instance', 'get_backend',
41 42 'VCSError', 'RepositoryError', 'CommitError', 'VCSCommunicationError'
42 43 ]
43 44
44 45 log = logging.getLogger(__name__)
45 46
46 47 # The pycurl library directly accesses C API functions and is not patched by
47 48 # gevent. This will potentially lead to deadlocks due to incompatibility to
48 49 # gevent. Therefore we check if gevent is active and import a gevent compatible
49 50 # wrapper in that case.
50 51 try:
51 52 from gevent import monkey
52 53 if monkey.is_module_patched('__builtin__'):
53 54 import geventcurl as pycurl
54 55 log.debug('Using gevent comapatible pycurl: %s', pycurl)
55 56 else:
56 57 import pycurl
57 58 except ImportError:
58 59 import pycurl
59 60
60 61
61 62 def get_version():
62 63 """
63 64 Returns shorter version (digit parts only) as string.
64 65 """
65 66 return '.'.join((str(each) for each in VERSION[:3]))
66 67
67 68
68 69 def connect_http(server_and_port):
69 70 from rhodecode.lib.vcs import connection, client_http
70 71 from rhodecode.lib.middleware.utils import scm_app
71 72
72 73 session_factory = client_http.ThreadlocalSessionFactory()
73 74
74 75 connection.Git = client_http.RepoMaker(
75 76 server_and_port, '/git', 'git', session_factory)
76 77 connection.Hg = client_http.RepoMaker(
77 78 server_and_port, '/hg', 'hg', session_factory)
78 79 connection.Svn = client_http.RepoMaker(
79 80 server_and_port, '/svn', 'svn', session_factory)
80 81 connection.Service = client_http.ServiceConnection(
81 82 server_and_port, '/_service', session_factory)
82 83
83 84 scm_app.HG_REMOTE_WSGI = client_http.VcsHttpProxy(
84 85 server_and_port, '/proxy/hg')
85 86 scm_app.GIT_REMOTE_WSGI = client_http.VcsHttpProxy(
86 87 server_and_port, '/proxy/git')
87 88
88 89 @atexit.register
89 90 def free_connection_resources():
90 91 connection.Git = None
91 92 connection.Hg = None
92 93 connection.Svn = None
93 94 connection.Service = None
94 95
95 96
96 97 def connect_vcs(server_and_port, protocol):
97 98 """
98 99 Initializes the connection to the vcs server.
99 100
100 101 :param server_and_port: str, e.g. "localhost:9900"
101 102 :param protocol: str or "http"
102 103 """
103 104 if protocol == 'http':
104 105 connect_http(server_and_port)
105 106 else:
106 107 raise Exception('Invalid vcs server protocol "{}"'.format(protocol))
107 108
108 109
109 110 def create_vcsserver_proxy(server_and_port, protocol):
110 111 if protocol == 'http':
111 112 return _create_vcsserver_proxy_http(server_and_port)
112 113 else:
113 114 raise Exception('Invalid vcs server protocol "{}"'.format(protocol))
114 115
115 116
116 117 def _create_vcsserver_proxy_http(server_and_port):
117 118 from rhodecode.lib.vcs import client_http
118 119
119 120 session = _create_http_rpc_session()
120 121 url = urlparse.urljoin('http://%s' % server_and_port, '/server')
121 122 return client_http.RemoteObject(url, session)
122 123
123 124
124 125 class CurlSession(object):
125 126 """
126 127 Modeled so that it provides a subset of the requests interface.
127 128
128 129 This has been created so that it does only provide a minimal API for our
129 130 needs. The parts which it provides are based on the API of the library
130 131 `requests` which allows us to easily benchmark against it.
131 132
132 133 Please have a look at the class :class:`requests.Session` when you extend
133 134 it.
134 135 """
135 136
136 137 def __init__(self):
137 138 curl = pycurl.Curl()
138 139 # TODO: johbo: I did test with 7.19 of libcurl. This version has
139 140 # trouble with 100 - continue being set in the expect header. This
140 141 # can lead to massive performance drops, switching it off here.
141 142 curl.setopt(curl.HTTPHEADER, ["Expect:"])
142 143 curl.setopt(curl.TCP_NODELAY, True)
143 144 curl.setopt(curl.PROTOCOLS, curl.PROTO_HTTP)
145 curl.setopt(curl.USERAGENT, 'RhodeCode HTTP {}'.format(rhodecode.__version__))
144 146 self._curl = curl
145 147
146 148 def post(self, url, data, allow_redirects=False):
147 149 response_buffer = StringIO()
148 150
149 151 curl = self._curl
150 152 curl.setopt(curl.URL, url)
151 153 curl.setopt(curl.POST, True)
152 154 curl.setopt(curl.POSTFIELDS, data)
153 155 curl.setopt(curl.FOLLOWLOCATION, allow_redirects)
154 156 curl.setopt(curl.WRITEDATA, response_buffer)
155 157 curl.perform()
156 158
157 159 status_code = curl.getinfo(pycurl.HTTP_CODE)
158 160
159 161 return CurlResponse(response_buffer, status_code)
160 162
161 163
162 164 class CurlResponse(object):
163 165 """
164 166 The response of a request, modeled after the requests API.
165 167
166 168 This class provides a subset of the response interface known from the
167 169 library `requests`. It is intentionally kept similar, so that we can use
168 170 `requests` as a drop in replacement for benchmarking purposes.
169 171 """
170 172
171 173 def __init__(self, response_buffer, status_code):
172 174 self._response_buffer = response_buffer
173 175 self._status_code = status_code
174 176
175 177 @property
176 178 def content(self):
177 179 return self._response_buffer.getvalue()
178 180
179 181 @property
180 182 def status_code(self):
181 183 return self._status_code
182 184
183 185
184 186 def _create_http_rpc_session():
185 187 session = CurlSession()
186 188 return session
General Comments 0
You need to be logged in to leave comments. Login now