Commit | Line | Data |
---|---|---|
11cbb815 PD |
1 | # The software in this package is distributed under the GNU General |
2 | # Public License version 2 (with a special exception described below). | |
3 | # | |
4 | # A copy of GNU General Public License (GPL) is included in this distribution, | |
5 | # in the file COPYING.GPL. | |
6 | # | |
7 | # As a special exception, if other files instantiate templates or use macros | |
8 | # or inline functions from this file, or you compile this file and link it | |
9 | # with other works to produce a work based on this file, this file | |
10 | # does not by itself cause the resulting work to be covered | |
11 | # by the GNU General Public License. | |
12 | # | |
13 | # However the source code for this file must still be made available | |
14 | # in accordance with section (3) of the GNU General Public License. | |
15 | # | |
16 | # This exception does not invalidate any other reasons why a work based | |
17 | # on this file might be covered by the GNU General Public License. | |
18 | # | |
19 | # Copyright (c) 2016-2018 Intra2net AG <info@intra2net.com> | |
20 | ||
f49f6323 | 21 | """ |
f49f6323 PD |
22 | Utility for HTTP based interaction with the arnied web page. |
23 | ||
24 | Copyright: Intra2net AG | |
f49f6323 PD |
25 | """ |
26 | ||
27 | import re | |
1ba3b378 | 28 | import ssl |
f49f6323 PD |
29 | import http.client as client |
30 | import urllib.parse as parse | |
c16498f5 | 31 | import socket |
f49f6323 | 32 | import logging |
7628bc48 | 33 | |
3de8b4d8 | 34 | log = logging.getLogger('pyi2ncommon.web_interface') |
f49f6323 | 35 | |
f49f6323 | 36 | |
c16498f5 CH |
37 | #: FQDN of local machine |
38 | LOCALHOST = socket.gethostname() | |
39 | ||
f49f6323 | 40 | |
897c6e50 | 41 | def find_in_form(regex, form="status", escape=False, check_certs=True): |
f49f6323 | 42 | """ |
7628bc48 | 43 | Find a regex in given I2N web page form. |
f49f6323 PD |
44 | |
45 | :param str regex: regular expression to find | |
7628bc48 | 46 | :param str form: form name to open |
f49f6323 | 47 | :param bool escape: whether to escape the regex |
897c6e50 | 48 | :param check_certs: forwarded to :py:func:`web_page_request`, see doc there |
f49f6323 PD |
49 | :returns: whether the regex was found |
50 | :rtype: bool | |
51 | """ | |
897c6e50 CH |
52 | data = web_page_request(method="GET", url="/arnie?form=" + form, |
53 | check_certs=check_certs) | |
f49f6323 PD |
54 | if escape: |
55 | regex = re.escape(regex) | |
56 | if re.search(regex, data): | |
57 | return True | |
58 | else: | |
59 | log.debug("'%s' could not be found in:\n%s", regex, data) | |
60 | return False | |
61 | ||
62 | ||
897c6e50 | 63 | def web_page_request(method="GET", url="/", body=None, check_certs=True): |
f49f6323 PD |
64 | """ |
65 | Send an HTTPS request and return any response data. | |
66 | ||
897c6e50 CH |
67 | SSL certificates are checked against a default set of certificates |
68 | installed on you system. This can be disabled (not recommended, security | |
69 | implications!) by setting `check_certs` to `False`. To allow a secure | |
70 | connection to host with e.g. a self-signed certificate, the caller can | |
71 | load this certificate by specifying `check_certs=/path/to/cert.pem`. | |
c16498f5 CH |
72 | (see also: :py:meth:`ssl.SSLContext.load_verify_locations`). Note that the |
73 | certificate has to be issued for the same server name that we try to | |
74 | access, i.e. :py:data:`LOCALHOST`. | |
897c6e50 | 75 | |
f49f6323 PD |
76 | :param str method: GET or POST method for the request |
77 | :param str url: url location within the remote host | |
78 | :param body: dictionary to be parsed and added to the url | |
79 | :type body: {str, str} or None | |
897c6e50 CH |
80 | :param check_certs: Whether or not to check ssl certificates for connection |
81 | or file name to a certificate file | |
82 | :type check_certs: bool or str | |
f49f6323 PD |
83 | :returns: data from the response if any |
84 | :rtype: str | |
85 | """ | |
86 | body = parse.urlencode(body) if body is not None else "" | |
87 | headers = {"Content-Type": "application/x-www-form-urlencoded", | |
88 | "Accept": "text/plain"} | |
89 | ||
897c6e50 CH |
90 | if isinstance(check_certs, str): |
91 | context = ssl.create_default_context(cafile=check_certs) | |
92 | elif check_certs: | |
93 | context = ssl.create_default_context() | |
94 | else: | |
95 | # disable certificate checks | |
96 | context = ssl._create_unverified_context() | |
c16498f5 | 97 | conn = client.HTTPSConnection(LOCALHOST, context=context) |
f49f6323 PD |
98 | conn.request(method, url, body, headers) |
99 | resp = conn.getresponse() | |
100 | logging.info("Request status %s and response %s", | |
101 | resp.status, resp.reason) | |
102 | if resp.status != 200: | |
eed487df | 103 | raise client.HTTPException("POST request failed.") |
f49f6323 PD |
104 | data = resp.read().decode() |
105 | conn.close() | |
106 | ||
107 | return data |