1 # Copyright (c) 2016 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
6 # http://www.apache.org/licenses/LICENSE-2.0
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
14 """Implements HTTP requests GET, PUT, POST, DELETE used in communication with
18 from requests import request, RequestException, Timeout, TooManyRedirects, \
19 HTTPError, ConnectionError
20 from requests.auth import HTTPBasicAuth
22 from robot.api import logger
23 from robot.api.deco import keyword
26 HTTP_CODES = {"OK": 200,
30 "SERVICE_UNAVAILABLE": 503}
33 class HTTPRequestError(Exception):
34 """Exception raised by HTTPRequest objects."""
36 def __init__(self, msg, enable_logging=True):
37 """Sets the exception message and enables / disables logging
39 It is not wanted to log errors when using these keywords together
40 with keywords like "Wait until keyword succeeds".
42 :param msg: Message to be displayed and logged
43 :param enable_logging: When True, logging is enabled, otherwise
46 :type enable_logging: bool
48 super(HTTPRequestError, self).__init__()
50 self._repr_msg = self.__module__ + '.' + \
51 self.__class__.__name__ + ": " + self._msg
54 logger.error(self._msg)
55 logger.debug(self._repr_msg)
58 return repr(self._repr_msg)
61 return str(self._repr_msg)
64 class HTTPRequest(object):
65 """A class implementing HTTP requests."""
71 def create_full_url(ip_addr, port, path):
72 """Creates full url including IP, port, and path to data.
74 :param ip_addr: Server IP
75 :param port: Communication port
76 :param path: Path to data
78 :type port: str or int
83 return "http://{ip}:{port}{path}".format(ip=ip_addr, port=port,
87 def _http_request(method, node, path, enable_logging=True, **kwargs):
88 """Sends specified HTTP request and returns status code and
91 :param method: The method to be performed on the resource identified by
93 :param node: honeycomb node
94 :param path: URL path, e.g. /index.html
95 :param enable_logging: used to suppress errors when checking
96 honeycomb state during suite setup and teardown
97 :param kwargs: named parameters accepted by request.request:
98 params -- (optional) Dictionary or bytes to be sent in the query
99 string for the Request.
100 data -- (optional) Dictionary, bytes, or file-like object to
101 send in the body of the Request.
102 json -- (optional) json data to send in the body of the Request.
103 headers -- (optional) Dictionary of HTTP Headers to send with
105 cookies -- (optional) Dict or CookieJar object to send with the
107 files -- (optional) Dictionary of 'name': file-like-objects
108 (or {'name': ('filename', fileobj)}) for multipart encoding upload.
109 timeout (float or tuple) -- (optional) How long to wait for the
110 server to send data before giving up, as a float, or a (connect
111 timeout, read timeout) tuple.
112 allow_redirects (bool) -- (optional) Boolean. Set to True if POST/
113 PUT/DELETE redirect following is allowed.
114 proxies -- (optional) Dictionary mapping protocol to the URL of
116 verify -- (optional) whether the SSL cert will be verified.
117 A CA_BUNDLE path can also be provided. Defaults to True.
118 stream -- (optional) if False, the response content will be
119 immediately downloaded.
120 cert -- (optional) if String, path to ssl client cert file (.pem).
121 If Tuple, ('cert', 'key') pair.
125 :type enable_logging: bool
127 :return: Status code and content of response
129 :raises HTTPRequestError: If
130 1. it is not possible to connect
131 2. invalid HTTP response comes from server
132 3. request exceeded the configured number of maximum re-directions
134 5. there is any other unexpected HTTP request exception
136 timeout = kwargs["timeout"]
137 url = HTTPRequest.create_full_url(node['host'],
138 node['honeycomb']['port'],
141 auth = HTTPBasicAuth(node['honeycomb']['user'],
142 node['honeycomb']['passwd'])
143 rsp = request(method, url, auth=auth, **kwargs)
144 return rsp.status_code, rsp.content
146 except ConnectionError as err:
147 # Switching the logging on / off is needed only for
148 # "requests.ConnectionError"
150 raise HTTPRequestError("Not possible to connect to {0}\n".
151 format(url) + repr(err))
153 raise HTTPRequestError("Not possible to connect to {0}\n".
154 format(url) + repr(err),
155 enable_logging=False)
156 except HTTPError as err:
157 raise HTTPRequestError("Invalid HTTP response from {0}\n".
158 format(url) + repr(err))
159 except TooManyRedirects as err:
160 raise HTTPRequestError("Request exceeded the configured number "
161 "of maximum re-directions\n" + repr(err))
162 except Timeout as err:
163 raise HTTPRequestError("Request timed out. Timeout is set to "
164 "{0}\n".format(timeout) + repr(err))
165 except RequestException as err:
166 raise HTTPRequestError("Unexpected HTTP request exception.\n" +
170 @keyword(name="HTTP Get")
171 def get(node, path, headers=None, timeout=10, enable_logging=True):
172 """Sends a GET request and returns the response and status code.
174 :param node: honeycomb node
175 :param path: URL path, e.g. /index.html
176 :param headers: Dictionary of HTTP Headers to send with the Request.
177 :param timeout: How long to wait for the server to send data before
178 giving up, as a float, or a (connect timeout, read timeout) tuple.
179 :param enable_logging: Used to suppress errors when checking
180 honeycomb state during suite setup and teardown. When True, logging
181 is enabled, otherwise logging is disabled.
185 :type timeout: float or tuple
186 :type enable_logging: bool
187 :return: Status code and content of response
190 return HTTPRequest._http_request('GET', node, path,
191 enable_logging=enable_logging,
192 headers=headers, timeout=timeout)
195 @keyword(name="HTTP Put")
196 def put(node, path, headers=None, payload=None, timeout=10):
197 """Sends a PUT request and returns the response and status code.
199 :param node: honeycomb node
200 :param path: URL path, e.g. /index.html
201 :param headers: Dictionary of HTTP Headers to send with the Request.
202 :param payload: Dictionary, bytes, or file-like object to send in
203 the body of the Request.
204 :param timeout: How long to wait for the server to send data before
205 giving up, as a float, or a (connect timeout, read timeout) tuple.
209 :type payload: dict, bytes, or file-like object
210 :type timeout: float or tuple
211 :return: Status code and content of response
214 return HTTPRequest._http_request('PUT', node, path, headers=headers,
215 data=payload, timeout=timeout)
218 @keyword(name="HTTP Post")
219 def post(node, path, headers=None, payload=None, json=None, timeout=10):
220 """Sends a POST request and returns the response and status code.
222 :param node: honeycomb node
223 :param path: URL path, e.g. /index.html
224 :param headers: Dictionary of HTTP Headers to send with the Request.
225 :param payload: Dictionary, bytes, or file-like object to send in
226 the body of the Request.
227 :param json: json data to send in the body of the Request
228 :param timeout: How long to wait for the server to send data before
229 giving up, as a float, or a (connect timeout, read timeout) tuple.
233 :type payload: dict, bytes, or file-like object
235 :type timeout: float or tuple
236 :return: Status code and content of response
239 return HTTPRequest._http_request('POST', node, path, headers=headers,
240 data=payload, json=json,
244 @keyword(name="HTTP Delete")
245 def delete(node, path, timeout=10):
246 """Sends a DELETE request and returns the response and status code.
248 :param node: honeycomb node
249 :param path: URL path, e.g. /index.html
250 :param timeout: How long to wait for the server to send data before
251 giving up, as a float, or a (connect timeout, read timeout) tuple.
254 :type timeout: float or tuple
255 :return: Status code and content of response
258 return HTTPRequest._http_request('DELETE', node, path, timeout=timeout)