| 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 |