| OLD | NEW |
| (Empty) | |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. |
| 4 |
| 5 import logging |
| 6 import re |
| 7 import urlparse |
| 8 |
| 9 from common.codereview import CodeReview |
| 10 from common.http_client_appengine import HttpClientAppengine |
| 11 |
| 12 |
| 13 _RIETVELD_ISSUE_NUMBER_RE = re.compile('^/(\d+)/?.*') |
| 14 |
| 15 |
| 16 class Rietveld(CodeReview): |
| 17 """The implementation of CodeReview interface for Rietveld.""" |
| 18 HTTP_CLIENT = HttpClientAppengine() |
| 19 |
| 20 def _GetXsrfToken(self, rietveld_url): |
| 21 """Returns the xsrf token for follow-up requests.""" |
| 22 headers = { |
| 23 'X-Requesting-XSRF-Token': '1', |
| 24 'Accept': 'text/plain', |
| 25 } |
| 26 url = '%s/xsrf_token' % rietveld_url |
| 27 status_code, xsrf_token = self.HTTP_CLIENT.Post( |
| 28 url, data=None, headers=headers) |
| 29 if status_code != 200: |
| 30 logging.error('Failed to get xsrf token from %s', rietveld_url) |
| 31 xsrf_token = None |
| 32 return xsrf_token |
| 33 |
| 34 def _GetRietveldUrlAndIssueNumber(self, issue_url): |
| 35 """Parses the given Rietveld issue url. |
| 36 |
| 37 Args: |
| 38 issue_url(str): The url to an issue on Rietveld. |
| 39 Returns: |
| 40 (rietveld_url, issue_number) |
| 41 rietveld_url(str): The root url of the Rietveld app. |
| 42 issue_number(str): The issue number. |
| 43 """ |
| 44 u = urlparse.urlparse(issue_url) |
| 45 rietveld_url = 'https://%s' % u.netloc # Enforces https. |
| 46 issue_number = _RIETVELD_ISSUE_NUMBER_RE.match(u.path).group(1) |
| 47 return rietveld_url, issue_number |
| 48 |
| 49 def _EncodeMultipartFormData(self, fields): |
| 50 """Encodes form fields for multipart/form-data""" |
| 51 BOUNDARY = '-F-I-N-D-I-T-M-E-S-S-A-G-E-' |
| 52 CRLF = '\r\n' |
| 53 lines = [] |
| 54 for key, value in fields.iteritems(): |
| 55 lines.append('--' + BOUNDARY) |
| 56 lines.append('Content-Disposition: form-data; name="%s"' % key) |
| 57 lines.append('') |
| 58 lines.append(str(value)) |
| 59 lines.append('--' + BOUNDARY + '--') |
| 60 lines.append('') |
| 61 body = CRLF.join(lines) |
| 62 content_type = 'multipart/form-data; boundary=%s' % BOUNDARY |
| 63 return content_type, body |
| 64 |
| 65 def PostMessage(self, issue_url, message): |
| 66 rietveld_url, issue_number = self._GetRietveldUrlAndIssueNumber(issue_url) |
| 67 url = '%s/%s/publish' % (rietveld_url, issue_number) |
| 68 xsrf_token = self._GetXsrfToken(rietveld_url) |
| 69 if not xsrf_token: |
| 70 return False |
| 71 form_fields = { |
| 72 'xsrf_token': xsrf_token, |
| 73 'message': message, |
| 74 'message_only': 'True', |
| 75 'add_as_reviewer': 'False', |
| 76 'send_mail': 'True', |
| 77 'no_redirect': 'True', |
| 78 } |
| 79 content_type, body = self._EncodeMultipartFormData(form_fields) |
| 80 headers = { |
| 81 'Content-Type': content_type, |
| 82 'Accept': 'text/plain', |
| 83 } |
| 84 status_code, content = self.HTTP_CLIENT.Post( |
| 85 url, data=body, headers=headers) |
| 86 return status_code == 200 and content == 'OK' |
| OLD | NEW |