##// END OF EJS Templates
mercurial: protocol security updates....
marcink -
r2724:7a057a98 default
parent child Browse files
Show More
@@ -25,6 +25,7 b' SimpleHG middleware for handling mercuri'
25 25
26 26 import logging
27 27 import urlparse
28 import urllib
28 29
29 30 from rhodecode.lib import utils
30 31 from rhodecode.lib.ext_json import json
@@ -51,24 +52,94 b' class SimpleHg(simplevcs.SimpleVCS):'
51 52 'getbundle': 'pull',
52 53 'stream_out': 'pull',
53 54 'listkeys': 'pull',
55 'between': 'pull',
56 'branchmap': 'pull',
57 'branches': 'pull',
58 'clonebundles': 'pull',
59 'capabilities': 'pull',
60 'debugwireargs': 'pull',
61 'heads': 'pull',
62 'lookup': 'pull',
63 'hello': 'pull',
64 'known': 'pull',
65
66 # largefiles
67 'putlfile': 'push',
68 'getlfile': 'pull',
69 'statlfile': 'pull',
70 'lheads': 'pull',
71
54 72 'unbundle': 'push',
55 73 'pushkey': 'push',
56 74 }
57 75
76 @classmethod
77 def _get_xarg_headers(cls, environ):
78 i = 1
79 chunks = [] # gather chunks stored in multiple 'hgarg_N'
80 while True:
81 head = environ.get('HTTP_X_HGARG_{}'.format(i))
82 if not head:
83 break
84 i += 1
85 chunks.append(urllib.unquote_plus(head))
86 full_arg = ''.join(chunks)
87 pref = 'cmds='
88 if full_arg.startswith(pref):
89 # strip the cmds= header defining our batch commands
90 full_arg = full_arg[len(pref):]
91 cmds = full_arg.split(';')
92 return cmds
93
94 @classmethod
95 def _get_batch_cmd(cls, environ):
96 """
97 Handle batch command send commands. Those are ';' separated commands
98 sent by batch command that server needs to execute. We need to extract
99 those, and map them to our ACTION_MAPPING to get all push/pull commands
100 specified in the batch
101 """
102 default = 'push'
103 batch_cmds = []
104 try:
105 cmds = cls._get_xarg_headers(environ)
106 for pair in cmds:
107 parts = pair.split(' ', 1)
108 if len(parts) != 2:
109 continue
110 # entry should be in a format `key ARGS`
111 cmd, args = parts
112 action = cls._ACTION_MAPPING.get(cmd, default)
113 batch_cmds.append(action)
114 except Exception:
115 log.exception('Failed to extract batch commands operations')
116
117 # in case we failed, (e.g malformed data) assume it's PUSH sub-command
118 # for safety
119 return batch_cmds or [default]
120
58 121 def _get_action(self, environ):
59 122 """
60 123 Maps mercurial request commands into a pull or push command.
61 In case of unknown/unexpected data, it returns 'pull' to be safe.
124 In case of unknown/unexpected data, it returns 'push' to be safe.
62 125
63 126 :param environ:
64 127 """
128 default = 'push'
65 129 query = urlparse.parse_qs(environ['QUERY_STRING'],
66 130 keep_blank_values=True)
131
67 132 if 'cmd' in query:
68 133 cmd = query['cmd'][0]
69 return self._ACTION_MAPPING.get(cmd, 'pull')
134 if cmd == 'batch':
135 cmds = self._get_batch_cmd(environ)
136 if 'push' in cmds:
137 return 'push'
138 else:
139 return 'pull'
140 return self._ACTION_MAPPING.get(cmd, default)
70 141
71 return 'pull'
142 return default
72 143
73 144 def _create_wsgi_app(self, repo_path, repo_name, config):
74 145 return self.scm_app.create_hg_wsgi_app(
@@ -47,11 +47,14 b' def get_environ(url):'
47 47 ('/foo/bar?cmd=pushkey&key=tip', 'push'),
48 48 ('/foo/bar?cmd=listkeys&key=tip', 'pull'),
49 49 ('/foo/bar?cmd=changegroup&key=tip', 'pull'),
50 # Edge case: unknown argument: assume pull
51 ('/foo/bar?cmd=unknown&key=tip', 'pull'),
52 ('/foo/bar?cmd=&key=tip', 'pull'),
50 ('/foo/bar?cmd=hello', 'pull'),
51 ('/foo/bar?cmd=batch', 'push'),
52 ('/foo/bar?cmd=putlfile', 'push'),
53 # Edge case: unknown argument: assume push
54 ('/foo/bar?cmd=unknown&key=tip', 'push'),
55 ('/foo/bar?cmd=&key=tip', 'push'),
53 56 # Edge case: not cmd argument
54 ('/foo/bar?key=tip', 'pull'),
57 ('/foo/bar?key=tip', 'push'),
55 58 ])
56 59 def test_get_action(url, expected_action, request_stub):
57 60 app = simplehg.SimpleHg(config={'auth_ret_code': '', 'base_path': ''},
@@ -60,6 +63,34 b' def test_get_action(url, expected_action'
60 63
61 64
62 65 @pytest.mark.parametrize(
66 'environ, expected_xargs, expected_batch',
67 [
68 ({},
69 [''], ['push']),
70
71 ({'HTTP_X_HGARG_1': ''},
72 [''], ['push']),
73
74 ({'HTTP_X_HGARG_1': 'cmds=listkeys+namespace%3Dphases'},
75 ['listkeys namespace=phases'], ['pull']),
76
77 ({'HTTP_X_HGARG_1': 'cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'},
78 ['pushkey namespace=bookmarks,key=bm,old=,new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'], ['push']),
79
80 ({'HTTP_X_HGARG_1': 'namespace=phases'},
81 ['namespace=phases'], ['push']),
82
83 ])
84 def test_xarg_and_batch_commands(environ, expected_xargs, expected_batch):
85 app = simplehg.SimpleHg
86
87 result = app._get_xarg_headers(environ)
88 result_batch = app._get_batch_cmd(environ)
89 assert expected_xargs == result
90 assert expected_batch == result_batch
91
92
93 @pytest.mark.parametrize(
63 94 'url, expected_repo_name',
64 95 [
65 96 ('/foo?cmd=unbundle&key=tip', 'foo'),
General Comments 0
You need to be logged in to leave comments. Login now