blob: 9a6e30f86479b24be688a6fecd351256a8bef081 [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
13__author__ = 'phoglund@webrtc.org (Patrik Höglund)'
14
15import httplib
16import shelve
phoglund@webrtc.org914ef272012-02-27 15:42:25 +000017import urlparse
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000018import oauth.oauth as oauth
19
20import constants
21
22
23class FailedToReadRequiredInputFile(Exception):
24 pass
25
26
27class FailedToReportToDashboard(Exception):
28 pass
29
30
31class DashboardConnection:
32 """Helper class for pushing data to the dashboard.
33
34 This class deals with most of details for accessing protected resources
35 (i.e. data-writing operations) on the dashboard. Such operations are
36 authenticated using OAuth. This class requires a consumer secret and a
37 access token.
38
phoglund@webrtc.org914ef272012-02-27 15:42:25 +000039 The access token and consumer secrets are stored as files on disk in the
40 working directory of the scripts. Both files are created by the
41 request_oauth_permission script.
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000042 """
43
44 def __init__(self, consumer_key):
45 self.consumer_key_ = consumer_key
46
47 def read_required_files(self, consumer_secret_file, access_token_file):
48 """Reads required data for making OAuth requests.
49
50 Args:
phoglund@webrtc.org914ef272012-02-27 15:42:25 +000051 consumer_secret_file: A shelve file with an entry consumer_secret
52 containing the consumer secret in string form.
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000053 access_token_file: A shelve file with an entry access_token
54 containing the access token in string form.
55 """
phoglund@webrtc.org914ef272012-02-27 15:42:25 +000056 self.access_token_string_ = self._read_access_token(access_token_file)
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000057 self.consumer_secret_ = self._read_consumer_secret(consumer_secret_file)
58
phoglund@webrtc.org914ef272012-02-27 15:42:25 +000059 def send_post_request(self, url, parameters):
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000060 """Sends an OAuth request for a protected resource in the dashboard.
61
62 Use this when you want to report new data to the dashboard. You must have
63 called the read_required_files method prior to calling this method, since
64 that method will read in the consumer secret and access token we need to
65 make the OAuth request. These concepts are described in the class
66 description.
67
phoglund@webrtc.org86ce46d2012-02-06 10:55:12 +000068 The server is expected to respond with HTTP status 200 and a completely
69 empty response if the call failed. The server may put diagnostic
70 information in the response.
71
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000072 Args:
phoglund@webrtc.org914ef272012-02-27 15:42:25 +000073 url: An absolute url within the dashboard domain, for example
74 http://webrtc-dashboard.appspot.com/add_coverage_data.
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000075 parameters: A dict which maps from POST parameter names to values.
76
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000077 Raises:
78 FailedToReportToDashboard: If the dashboard didn't respond
phoglund@webrtc.org86ce46d2012-02-06 10:55:12 +000079 with HTTP 200 to our request or if the response is non-empty.
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000080 """
81 consumer = oauth.OAuthConsumer(self.consumer_key_, self.consumer_secret_)
phoglund@webrtc.org914ef272012-02-27 15:42:25 +000082 access_token = oauth.OAuthToken.from_string(self.access_token_string_)
83
84 oauth_request = oauth.OAuthRequest.from_consumer_and_token(
85 consumer,
86 token=access_token,
87 http_method='POST',
88 http_url=url,
89 parameters=parameters)
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000090
91 signature_method_hmac_sha1 = oauth.OAuthSignatureMethod_HMAC_SHA1()
92 oauth_request.sign_request(signature_method_hmac_sha1, consumer,
phoglund@webrtc.org914ef272012-02-27 15:42:25 +000093 access_token)
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000094
95 connection = httplib.HTTPConnection(constants.DASHBOARD_SERVER)
96
97 headers = {'Content-Type': 'application/x-www-form-urlencoded'}
phoglund@webrtc.org914ef272012-02-27 15:42:25 +000098 connection.request('POST', url, body=oauth_request.to_postdata(),
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000099 headers=headers)
100
101 response = connection.getresponse()
102 connection.close()
103
104 if response.status != 200:
phoglund@webrtc.org914ef272012-02-27 15:42:25 +0000105 message = ('Failed to report to %s: got response %d (%s)' %
106 (url, response.status, response.reason))
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +0000107 raise FailedToReportToDashboard(message)
108
phoglund@webrtc.org86ce46d2012-02-06 10:55:12 +0000109 # The response content should be empty on success, so check that:
110 response_content = response.read()
111 if response_content:
112 message = ('Dashboard reported the following error: %s.' %
113 response_content)
114 raise FailedToReportToDashboard(message)
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +0000115
116 def _read_access_token(self, filename):
phoglund@webrtc.org914ef272012-02-27 15:42:25 +0000117 return self._read_shelve(filename, 'access_token')
118
119 def _read_consumer_secret(self, filename):
120 return self._read_shelve(filename, 'consumer_secret')
121
122 def _read_shelve(self, filename, key):
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +0000123 input_file = shelve.open(filename)
124
phoglund@webrtc.org914ef272012-02-27 15:42:25 +0000125 if not input_file.has_key(key):
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +0000126 raise FailedToReadRequiredInputFile('Missing correct %s file in current '
127 'directory. You may have to run '
128 'request_oauth_permission.py.' %
129 filename)
130
phoglund@webrtc.org914ef272012-02-27 15:42:25 +0000131 result = input_file[key]
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +0000132 input_file.close()
133
phoglund@webrtc.org914ef272012-02-27 15:42:25 +0000134 return result