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 PD |
21 | """ |
22 | ||
23 | SUMMARY | |
24 | ------------------------------------------------------ | |
25 | Utility for HTTP based interaction with the arnied web page. | |
26 | ||
27 | Copyright: Intra2net AG | |
28 | ||
29 | ||
30 | INTERFACE | |
31 | ------------------------------------------------------ | |
32 | ||
33 | """ | |
34 | ||
35 | import re | |
1ba3b378 | 36 | import ssl |
f49f6323 PD |
37 | import http.client as client |
38 | import urllib.parse as parse | |
c16498f5 | 39 | import socket |
f49f6323 | 40 | import logging |
7628bc48 | 41 | |
3de8b4d8 | 42 | log = logging.getLogger('pyi2ncommon.web_interface') |
f49f6323 | 43 | |
f49f6323 | 44 | |
c16498f5 CH |
45 | #: FQDN of local machine |
46 | LOCALHOST = socket.gethostname() | |
47 | ||
f49f6323 | 48 | |
897c6e50 | 49 | def find_in_form(regex, form="status", escape=False, check_certs=True): |
f49f6323 | 50 | """ |
7628bc48 | 51 | Find a regex in given I2N web page form. |
f49f6323 PD |
52 | |
53 | :param str regex: regular expression to find | |
7628bc48 | 54 | :param str form: form name to open |
f49f6323 | 55 | :param bool escape: whether to escape the regex |
897c6e50 | 56 | :param check_certs: forwarded to :py:func:`web_page_request`, see doc there |
f49f6323 PD |
57 | :returns: whether the regex was found |
58 | :rtype: bool | |
59 | """ | |
897c6e50 CH |
60 | data = web_page_request(method="GET", url="/arnie?form=" + form, |
61 | check_certs=check_certs) | |
f49f6323 PD |
62 | if escape: |
63 | regex = re.escape(regex) | |
64 | if re.search(regex, data): | |
65 | return True | |
66 | else: | |
67 | log.debug("'%s' could not be found in:\n%s", regex, data) | |
68 | return False | |
69 | ||
70 | ||
897c6e50 | 71 | def web_page_request(method="GET", url="/", body=None, check_certs=True): |
f49f6323 PD |
72 | """ |
73 | Send an HTTPS request and return any response data. | |
74 | ||
897c6e50 CH |
75 | SSL certificates are checked against a default set of certificates |
76 | installed on you system. This can be disabled (not recommended, security | |
77 | implications!) by setting `check_certs` to `False`. To allow a secure | |
78 | connection to host with e.g. a self-signed certificate, the caller can | |
79 | load this certificate by specifying `check_certs=/path/to/cert.pem`. | |
c16498f5 CH |
80 | (see also: :py:meth:`ssl.SSLContext.load_verify_locations`). Note that the |
81 | certificate has to be issued for the same server name that we try to | |
82 | access, i.e. :py:data:`LOCALHOST`. | |
897c6e50 | 83 | |
f49f6323 PD |
84 | :param str method: GET or POST method for the request |
85 | :param str url: url location within the remote host | |
86 | :param body: dictionary to be parsed and added to the url | |
87 | :type body: {str, str} or None | |
897c6e50 CH |
88 | :param check_certs: Whether or not to check ssl certificates for connection |
89 | or file name to a certificate file | |
90 | :type check_certs: bool or str | |
f49f6323 PD |
91 | :returns: data from the response if any |
92 | :rtype: str | |
93 | """ | |
94 | body = parse.urlencode(body) if body is not None else "" | |
95 | headers = {"Content-Type": "application/x-www-form-urlencoded", | |
96 | "Accept": "text/plain"} | |
97 | ||
897c6e50 CH |
98 | if isinstance(check_certs, str): |
99 | context = ssl.create_default_context(cafile=check_certs) | |
100 | elif check_certs: | |
101 | context = ssl.create_default_context() | |
102 | else: | |
103 | # disable certificate checks | |
104 | context = ssl._create_unverified_context() | |
c16498f5 | 105 | conn = client.HTTPSConnection(LOCALHOST, context=context) |
f49f6323 PD |
106 | conn.request(method, url, body, headers) |
107 | resp = conn.getresponse() | |
108 | logging.info("Request status %s and response %s", | |
109 | resp.status, resp.reason) | |
110 | if resp.status != 200: | |
eed487df | 111 | raise client.HTTPException("POST request failed.") |
f49f6323 PD |
112 | data = resp.read().decode() |
113 | conn.close() | |
114 | ||
115 | return data |