| OLD | NEW | 
|---|
| 1 # coding: utf-8 | 1 # coding: utf-8 | 
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be | 
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. | 
| 5 """Defines class Rietveld to easily access a rietveld instance. | 5 """Defines class Rietveld to easily access a rietveld instance. | 
| 6 | 6 | 
| 7 Security implications: | 7 Security implications: | 
| 8 | 8 | 
| 9 The following hypothesis are made: | 9 The following hypothesis are made: | 
| 10 - Rietveld enforces: | 10 - Rietveld enforces: | 
| (...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 409         if m: | 409         if m: | 
| 410           # Fake an HTTPError exception. Cheezy. :( | 410           # Fake an HTTPError exception. Cheezy. :( | 
| 411           raise urllib2.HTTPError( | 411           raise urllib2.HTTPError( | 
| 412               request_path, int(m.group(1)), msg, None, None) | 412               request_path, int(m.group(1)), msg, None, None) | 
| 413         old_error_exit(msg) | 413         old_error_exit(msg) | 
| 414       upload.ErrorExit = trap_http_500 | 414       upload.ErrorExit = trap_http_500 | 
| 415 | 415 | 
| 416       for retry in xrange(self._maxtries): | 416       for retry in xrange(self._maxtries): | 
| 417         try: | 417         try: | 
| 418           logging.debug('%s' % request_path) | 418           logging.debug('%s' % request_path) | 
| 419           return self.rpc_server.Send(request_path, **kwargs) | 419           result = self.rpc_server.Send(request_path, **kwargs) | 
|  | 420           # Sometimes GAE returns a HTTP 200 but with HTTP 500 as the content. | 
|  | 421           # How nice. | 
|  | 422           return result | 
| 420         except urllib2.HTTPError, e: | 423         except urllib2.HTTPError, e: | 
| 421           if retry >= (self._maxtries - 1): | 424           if retry >= (self._maxtries - 1): | 
| 422             raise | 425             raise | 
| 423           flake_codes = [500, 502, 503] | 426           flake_codes = [500, 502, 503] | 
| 424           if retry_on_404: | 427           if retry_on_404: | 
| 425             flake_codes.append(404) | 428             flake_codes.append(404) | 
| 426           if e.code not in flake_codes: | 429           if e.code not in flake_codes: | 
| 427             raise | 430             raise | 
| 428         except urllib2.URLError, e: | 431         except urllib2.URLError, e: | 
| 429           if retry >= (self._maxtries - 1): | 432           if retry >= (self._maxtries - 1): | 
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 518            extra_headers=None, | 521            extra_headers=None, | 
| 519            **kwargs): | 522            **kwargs): | 
| 520     """Send a POST or GET request to the server. | 523     """Send a POST or GET request to the server. | 
| 521 | 524 | 
| 522     Args: | 525     Args: | 
| 523       request_path: path on the server to hit. This is concatenated with the | 526       request_path: path on the server to hit. This is concatenated with the | 
| 524         value of 'host' provided to the constructor. | 527         value of 'host' provided to the constructor. | 
| 525       payload: request is a POST if not None, GET otherwise | 528       payload: request is a POST if not None, GET otherwise | 
| 526       timeout: in seconds | 529       timeout: in seconds | 
| 527       extra_headers: (dict) | 530       extra_headers: (dict) | 
| 528 |  | 
| 529     Returns: the HTTP response body as a string |  | 
| 530 |  | 
| 531     Raises: |  | 
| 532       urllib2.HTTPError |  | 
| 533     """ | 531     """ | 
| 534     # This method signature should match upload.py:AbstractRpcServer.Send() | 532     # This method signature should match upload.py:AbstractRpcServer.Send() | 
| 535     method = 'GET' | 533     method = 'GET' | 
| 536 | 534 | 
| 537     headers = self.extra_headers.copy() | 535     headers = self.extra_headers.copy() | 
| 538     headers.update(extra_headers or {}) | 536     headers.update(extra_headers or {}) | 
| 539 | 537 | 
| 540     if payload is not None: | 538     if payload is not None: | 
| 541       method = 'POST' | 539       method = 'POST' | 
| 542       headers['Content-Type'] = content_type | 540       headers['Content-Type'] = content_type | 
| 543 | 541 | 
| 544     prev_timeout = self._http.timeout | 542     prev_timeout = self._http.timeout | 
| 545     try: | 543     try: | 
| 546       if timeout: | 544       if timeout: | 
| 547         self._http.timeout = timeout | 545         self._http.timeout = timeout | 
|  | 546       # TODO(pgervais) implement some kind of retry mechanism (see upload.py). | 
| 548       url = self.host + request_path | 547       url = self.host + request_path | 
| 549       if kwargs: | 548       if kwargs: | 
| 550         url += "?" + urllib.urlencode(kwargs) | 549         url += "?" + urllib.urlencode(kwargs) | 
| 551 | 550 | 
| 552       # This weird loop is there to detect when the OAuth2 token has expired. | 551       # This weird loop is there to detect when the OAuth2 token has expired. | 
| 553       # This is specific to appengine *and* rietveld. It relies on the | 552       # This is specific to appengine *and* rietveld. It relies on the | 
| 554       # assumption that a 302 is triggered only by an expired OAuth2 token. This | 553       # assumption that a 302 is triggered only by an expired OAuth2 token. This | 
| 555       # prevents any usage of redirections in pages accessed this way. | 554       # prevents any usage of redirections in pages accessed this way. | 
| 556 | 555 | 
| 557       # This variable is used to make sure the following loop runs only twice. | 556       # This variable is used to make sure the following loop runs only twice. | 
| 558       redirect_caught = False | 557       redirect_caught = False | 
| 559       while True: | 558       while True: | 
| 560         try: | 559         try: | 
| 561           ret = self._http.request(url, | 560           ret = self._http.request(url, | 
| 562                                    method=method, | 561                                    method=method, | 
| 563                                    body=payload, | 562                                    body=payload, | 
| 564                                    headers=headers, | 563                                    headers=headers, | 
| 565                                    redirections=0) | 564                                    redirections=0) | 
| 566         except httplib2.RedirectLimit: | 565         except httplib2.RedirectLimit: | 
| 567           if redirect_caught or method != 'GET': | 566           if redirect_caught or method != 'GET': | 
| 568             logging.error('Redirection detected after logging in. Giving up.') | 567             logging.error('Redirection detected after logging in. Giving up.') | 
| 569             raise | 568             raise | 
| 570           redirect_caught = True | 569           redirect_caught = True | 
| 571           logging.debug('Redirection detected. Trying to log in again...') | 570           logging.debug('Redirection detected. Trying to log in again...') | 
| 572           self.creds.access_token = None | 571           self.creds.access_token = None | 
| 573           continue | 572           continue | 
| 574         break | 573         break | 
| 575 | 574 | 
| 576       if ret[0].status != 200: |  | 
| 577         raise urllib2.HTTPError( |  | 
| 578             request_path, int(ret[0]['status']), ret[1], None, None) |  | 
| 579 |  | 
| 580       return ret[1] | 575       return ret[1] | 
| 581 | 576 | 
| 582     finally: | 577     finally: | 
| 583       self._http.timeout = prev_timeout | 578       self._http.timeout = prev_timeout | 
| 584 | 579 | 
| 585 | 580 | 
| 586 class JwtOAuth2Rietveld(Rietveld): | 581 class JwtOAuth2Rietveld(Rietveld): | 
| 587   """Access to Rietveld using OAuth authentication. | 582   """Access to Rietveld using OAuth authentication. | 
| 588 | 583 | 
| 589   This class is supposed to be used only by bots, since this kind of | 584   This class is supposed to be used only by bots, since this kind of | 
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 742       self, issue, patchset, reason, clobber, revision, builders_and_tests, | 737       self, issue, patchset, reason, clobber, revision, builders_and_tests, | 
| 743       master=None, category='cq'): | 738       master=None, category='cq'): | 
| 744     logging.info('ReadOnlyRietveld: triggering try jobs %r for issue %d' % | 739     logging.info('ReadOnlyRietveld: triggering try jobs %r for issue %d' % | 
| 745         (builders_and_tests, issue)) | 740         (builders_and_tests, issue)) | 
| 746 | 741 | 
| 747   def trigger_distributed_try_jobs(  # pylint:disable=R0201 | 742   def trigger_distributed_try_jobs(  # pylint:disable=R0201 | 
| 748       self, issue, patchset, reason, clobber, revision, masters, | 743       self, issue, patchset, reason, clobber, revision, masters, | 
| 749       category='cq'): | 744       category='cq'): | 
| 750     logging.info('ReadOnlyRietveld: triggering try jobs %r for issue %d' % | 745     logging.info('ReadOnlyRietveld: triggering try jobs %r for issue %d' % | 
| 751         (masters, issue)) | 746         (masters, issue)) | 
| OLD | NEW | 
|---|