~suutari-olli/openlp/click-slide-to-go-live-from-blank

« back to all changes in this revision

Viewing changes to openlp/core/lib/webpagereader.py

  • Committer: Simon Hanna
  • Date: 2016-05-17 08:48:19 UTC
  • mfrom: (2625.1.36 openlp)
  • mto: (2625.1.37 openlp)
  • mto: This revision was merged to the branch mainline in revision 2649.
  • Revision ID: simon.hanna@serve-me.info-20160517084819-lgup78nzyzjympuu
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
 
3
 
 
4
###############################################################################
 
5
# OpenLP - Open Source Lyrics Projection                                      #
 
6
# --------------------------------------------------------------------------- #
 
7
# Copyright (c) 2008-2016 OpenLP Developers                                   #
 
8
# --------------------------------------------------------------------------- #
 
9
# This program is free software; you can redistribute it and/or modify it     #
 
10
# under the terms of the GNU General Public License as published by the Free  #
 
11
# Software Foundation; version 2 of the License.                              #
 
12
#                                                                             #
 
13
# This program is distributed in the hope that it will be useful, but WITHOUT #
 
14
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
 
15
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
 
16
# more details.                                                               #
 
17
#                                                                             #
 
18
# You should have received a copy of the GNU General Public License along     #
 
19
# with this program; if not, write to the Free Software Foundation, Inc., 59  #
 
20
# Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
 
21
###############################################################################
 
22
"""
 
23
The :mod:`openlp.core.utils` module provides the utility libraries for OpenLP.
 
24
"""
 
25
import logging
 
26
import socket
 
27
import sys
 
28
import time
 
29
import urllib.error
 
30
import urllib.parse
 
31
import urllib.request
 
32
from http.client import HTTPException
 
33
from random import randint
 
34
 
 
35
from openlp.core.common import Registry
 
36
 
 
37
log = logging.getLogger(__name__ + '.__init__')
 
38
 
 
39
USER_AGENTS = {
 
40
    'win32': [
 
41
        'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36',
 
42
        'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36',
 
43
        'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36'
 
44
    ],
 
45
    'darwin': [
 
46
        'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) '
 
47
        'Chrome/26.0.1410.43 Safari/537.31',
 
48
        'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/536.11 (KHTML, like Gecko) '
 
49
        'Chrome/20.0.1132.57 Safari/536.11',
 
50
        'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/536.11 (KHTML, like Gecko) '
 
51
        'Chrome/20.0.1132.47 Safari/536.11',
 
52
    ],
 
53
    'linux2': [
 
54
        'Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.22 (KHTML, like Gecko) Ubuntu Chromium/25.0.1364.160 '
 
55
        'Chrome/25.0.1364.160 Safari/537.22',
 
56
        'Mozilla/5.0 (X11; CrOS armv7l 2913.260.0) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.99 '
 
57
        'Safari/537.11',
 
58
        'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.27 (KHTML, like Gecko) Chrome/26.0.1389.0 Safari/537.27'
 
59
    ],
 
60
    'default': [
 
61
        'Mozilla/5.0 (X11; NetBSD amd64; rv:18.0) Gecko/20130120 Firefox/18.0'
 
62
    ]
 
63
}
 
64
CONNECTION_TIMEOUT = 30
 
65
CONNECTION_RETRIES = 2
 
66
 
 
67
 
 
68
class HTTPRedirectHandlerFixed(urllib.request.HTTPRedirectHandler):
 
69
    """
 
70
    Special HTTPRedirectHandler used to work around http://bugs.python.org/issue22248
 
71
    (Redirecting to urls with special chars)
 
72
    """
 
73
    def redirect_request(self, req, fp, code, msg, headers, new_url):
 
74
        #
 
75
        """
 
76
        Test if the new_url can be decoded to ascii
 
77
 
 
78
        :param req:
 
79
        :param fp:
 
80
        :param code:
 
81
        :param msg:
 
82
        :param headers:
 
83
        :param new_url:
 
84
        :return:
 
85
        """
 
86
        try:
 
87
            new_url.encode('latin1').decode('ascii')
 
88
            fixed_url = new_url
 
89
        except Exception:
 
90
            # The url could not be decoded to ascii, so we do some url encoding
 
91
            fixed_url = urllib.parse.quote(new_url.encode('latin1').decode('utf-8', 'replace'), safe='/:')
 
92
        return super(HTTPRedirectHandlerFixed, self).redirect_request(req, fp, code, msg, headers, fixed_url)
 
93
 
 
94
 
 
95
def _get_user_agent():
 
96
    """
 
97
    Return a user agent customised for the platform the user is on.
 
98
    """
 
99
    browser_list = USER_AGENTS.get(sys.platform, None)
 
100
    if not browser_list:
 
101
        browser_list = USER_AGENTS['default']
 
102
    random_index = randint(0, len(browser_list) - 1)
 
103
    return browser_list[random_index]
 
104
 
 
105
 
 
106
def get_web_page(url, header=None, update_openlp=False):
 
107
    """
 
108
    Attempts to download the webpage at url and returns that page or None.
 
109
 
 
110
    :param url: The URL to be downloaded.
 
111
    :param header:  An optional HTTP header to pass in the request to the web server.
 
112
    :param update_openlp: Tells OpenLP to update itself if the page is successfully downloaded.
 
113
        Defaults to False.
 
114
    """
 
115
    # TODO: Add proxy usage. Get proxy info from OpenLP settings, add to a
 
116
    # proxy_handler, build into an opener and install the opener into urllib2.
 
117
    # http://docs.python.org/library/urllib2.html
 
118
    if not url:
 
119
        return None
 
120
    # This is needed to work around http://bugs.python.org/issue22248 and https://bugs.launchpad.net/openlp/+bug/1251437
 
121
    opener = urllib.request.build_opener(HTTPRedirectHandlerFixed())
 
122
    urllib.request.install_opener(opener)
 
123
    req = urllib.request.Request(url)
 
124
    if not header or header[0].lower() != 'user-agent':
 
125
        user_agent = _get_user_agent()
 
126
        req.add_header('User-Agent', user_agent)
 
127
    if header:
 
128
        req.add_header(header[0], header[1])
 
129
    log.debug('Downloading URL = %s' % url)
 
130
    retries = 0
 
131
    while retries <= CONNECTION_RETRIES:
 
132
        retries += 1
 
133
        time.sleep(0.1)
 
134
        try:
 
135
            page = urllib.request.urlopen(req, timeout=CONNECTION_TIMEOUT)
 
136
            log.debug('Downloaded page {}'.format(page.geturl()))
 
137
            break
 
138
        except urllib.error.URLError as err:
 
139
            log.exception('URLError on {}'.format(url))
 
140
            log.exception('URLError: {}'.format(err.reason))
 
141
            page = None
 
142
            if retries > CONNECTION_RETRIES:
 
143
                raise
 
144
        except socket.timeout:
 
145
            log.exception('Socket timeout: {}'.format(url))
 
146
            page = None
 
147
            if retries > CONNECTION_RETRIES:
 
148
                raise
 
149
        except socket.gaierror:
 
150
            log.exception('Socket gaierror: {}'.format(url))
 
151
            page = None
 
152
            if retries > CONNECTION_RETRIES:
 
153
                raise
 
154
        except ConnectionRefusedError:
 
155
            log.exception('ConnectionRefused: {}'.format(url))
 
156
            page = None
 
157
            if retries > CONNECTION_RETRIES:
 
158
                raise
 
159
            break
 
160
        except ConnectionError:
 
161
            log.exception('Connection error: {}'.format(url))
 
162
            page = None
 
163
            if retries > CONNECTION_RETRIES:
 
164
                raise
 
165
        except HTTPException:
 
166
            log.exception('HTTPException error: {}'.format(url))
 
167
            page = None
 
168
            if retries > CONNECTION_RETRIES:
 
169
                raise
 
170
        except:
 
171
            # Don't know what's happening, so reraise the original
 
172
            raise
 
173
    if update_openlp:
 
174
        Registry().get('application').process_events()
 
175
    if not page:
 
176
        log.exception('{} could not be downloaded'.format(url))
 
177
        return None
 
178
    log.debug(page)
 
179
    return page
 
180
 
 
181
 
 
182
__all__ = ['get_application_version', 'check_latest_version',
 
183
           'get_web_page']