blob: e11383a00a9983b9dad6c136ff32a6bc7d7e44e0 [file] [log] [blame]
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +00001#!/usr/bin/env python
2#-*- coding: utf-8 -*-
3# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
4#
5# Use of this source code is governed by a BSD-style license
6# that can be found in the LICENSE file in the root of the source
7# tree. An additional intellectual property rights grant can be found
8# in the file PATENTS. All contributing project authors may
9# be found in the AUTHORS file in the root of the source tree.
10
11"""Contains utilities for communicating with the dashboard."""
12
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000013import httplib
14import shelve
15import oauth.oauth as oauth
16
17import constants
18
19
20class FailedToReadRequiredInputFile(Exception):
21 pass
22
23
24class FailedToReportToDashboard(Exception):
25 pass
26
27
28class DashboardConnection:
29 """Helper class for pushing data to the dashboard.
30
31 This class deals with most of details for accessing protected resources
32 (i.e. data-writing operations) on the dashboard. Such operations are
33 authenticated using OAuth. This class requires a consumer secret and a
34 access token.
35
phoglund@webrtc.org914ef272012-02-27 15:42:25 +000036 The access token and consumer secrets are stored as files on disk in the
37 working directory of the scripts. Both files are created by the
38 request_oauth_permission script.
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000039 """
40
41 def __init__(self, consumer_key):
42 self.consumer_key_ = consumer_key
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +000043 self.consumer_secret_ = None
44 self.access_token_string_ = None
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000045
46 def read_required_files(self, consumer_secret_file, access_token_file):
47 """Reads required data for making OAuth requests.
48
49 Args:
phoglund@webrtc.org914ef272012-02-27 15:42:25 +000050 consumer_secret_file: A shelve file with an entry consumer_secret
51 containing the consumer secret in string form.
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000052 access_token_file: A shelve file with an entry access_token
53 containing the access token in string form.
54 """
phoglund@webrtc.org914ef272012-02-27 15:42:25 +000055 self.access_token_string_ = self._read_access_token(access_token_file)
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000056 self.consumer_secret_ = self._read_consumer_secret(consumer_secret_file)
57
phoglund@webrtc.org914ef272012-02-27 15:42:25 +000058 def send_post_request(self, url, parameters):
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000059 """Sends an OAuth request for a protected resource in the dashboard.
60
61 Use this when you want to report new data to the dashboard. You must have
62 called the read_required_files method prior to calling this method, since
63 that method will read in the consumer secret and access token we need to
64 make the OAuth request. These concepts are described in the class
65 description.
66
phoglund@webrtc.org86ce46d2012-02-06 10:55:12 +000067 The server is expected to respond with HTTP status 200 and a completely
68 empty response if the call failed. The server may put diagnostic
69 information in the response.
70
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000071 Args:
phoglund@webrtc.org914ef272012-02-27 15:42:25 +000072 url: An absolute url within the dashboard domain, for example
73 http://webrtc-dashboard.appspot.com/add_coverage_data.
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000074 parameters: A dict which maps from POST parameter names to values.
75
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000076 Raises:
77 FailedToReportToDashboard: If the dashboard didn't respond
phoglund@webrtc.org86ce46d2012-02-06 10:55:12 +000078 with HTTP 200 to our request or if the response is non-empty.
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000079 """
80 consumer = oauth.OAuthConsumer(self.consumer_key_, self.consumer_secret_)
phoglund@webrtc.org914ef272012-02-27 15:42:25 +000081 access_token = oauth.OAuthToken.from_string(self.access_token_string_)
82
83 oauth_request = oauth.OAuthRequest.from_consumer_and_token(
84 consumer,
85 token=access_token,
86 http_method='POST',
87 http_url=url,
88 parameters=parameters)
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000089
90 signature_method_hmac_sha1 = oauth.OAuthSignatureMethod_HMAC_SHA1()
91 oauth_request.sign_request(signature_method_hmac_sha1, consumer,
phoglund@webrtc.org914ef272012-02-27 15:42:25 +000092 access_token)
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000093
94 connection = httplib.HTTPConnection(constants.DASHBOARD_SERVER)
95
96 headers = {'Content-Type': 'application/x-www-form-urlencoded'}
phoglund@webrtc.org914ef272012-02-27 15:42:25 +000097 connection.request('POST', url, body=oauth_request.to_postdata(),
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000098 headers=headers)
99
100 response = connection.getresponse()
101 connection.close()
102
103 if response.status != 200:
phoglund@webrtc.org914ef272012-02-27 15:42:25 +0000104 message = ('Failed to report to %s: got response %d (%s)' %
105 (url, response.status, response.reason))
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +0000106 raise FailedToReportToDashboard(message)
107
phoglund@webrtc.org86ce46d2012-02-06 10:55:12 +0000108 # The response content should be empty on success, so check that:
109 response_content = response.read()
110 if response_content:
111 message = ('Dashboard reported the following error: %s.' %
112 response_content)
113 raise FailedToReportToDashboard(message)
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +0000114
115 def _read_access_token(self, filename):
phoglund@webrtc.org914ef272012-02-27 15:42:25 +0000116 return self._read_shelve(filename, 'access_token')
117
118 def _read_consumer_secret(self, filename):
119 return self._read_shelve(filename, 'consumer_secret')
120
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +0000121
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000122def _read_shelve(filename, key):
123 input_file = shelve.open(filename)
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +0000124
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000125 if not input_file.has_key(key):
126 raise FailedToReadRequiredInputFile('Missing correct %s file in current '
127 'directory. You may have to run '
128 'request_oauth_permission.py.' %
129 filename)
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +0000130
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000131 result = input_file[key]
132 input_file.close()
133
134 return result