2525"""
2626
2727from __future__ import absolute_import
28+
29+ import io
2830import logging
2931import socket
3032import ssl
31- from io import BytesIO
32-
33- from splunklib .six .moves import urllib
34- import io
3533import sys
36-
3734from base64 import b64encode
35+ from contextlib import contextmanager
3836from datetime import datetime
3937from functools import wraps
38+ from io import BytesIO
39+ from xml .etree .ElementTree import XML
40+
41+ from splunklib import six
4042from splunklib .six import StringIO
43+ from splunklib .six .moves import urllib
4144
42- from contextlib import contextmanager
45+ from . data import record
4346
44- from xml .etree .ElementTree import XML
45- from splunklib import six
4647try :
4748 from xml .etree .ElementTree import ParseError
4849except ImportError as e :
4950 from xml .parsers .expat import ExpatError as ParseError
5051
51- from .data import record
5252
5353__all__ = [
5454 "AuthenticationError" ,
@@ -449,6 +449,8 @@ class Context(object):
449449 :type username: ``string``
450450 :param password: The password for the Splunk account.
451451 :type password: ``string``
452+ :param headers: List of extra HTTP headers to send (optional).
453+ :type headers: ``list`` of 2-tuples.
452454 :param handler: The HTTP request handler (optional).
453455 :returns: A ``Context`` instance.
454456
@@ -465,7 +467,8 @@ class Context(object):
465467 c = binding.Context(cookie="splunkd_8089=...")
466468 """
467469 def __init__ (self , handler = None , ** kwargs ):
468- self .http = HttpLib (handler , kwargs .get ("verify" , True ))
470+ self .http = HttpLib (handler , kwargs .get ("verify" , False ), key_file = kwargs .get ("key_file" ),
471+ cert_file = kwargs .get ("cert_file" )) # Default to False for backward compat
469472 self .token = kwargs .get ("token" , _NoAuthenticationToken )
470473 if self .token is None : # In case someone explicitly passes token=None
471474 self .token = _NoAuthenticationToken
@@ -478,6 +481,7 @@ def __init__(self, handler=None, **kwargs):
478481 self .password = kwargs .get ("password" , "" )
479482 self .basic = kwargs .get ("basic" , False )
480483 self .autologin = kwargs .get ("autologin" , False )
484+ self .additional_headers = kwargs .get ("headers" , [])
481485
482486 # Store any cookies in the self.http._cookies dict
483487 if "cookie" in kwargs and kwargs ['cookie' ] not in [None , _NoAuthenticationToken ]:
@@ -613,7 +617,7 @@ def delete(self, path_segment, owner=None, app=None, sharing=None, **query):
613617
614618 @_authentication
615619 @_log_duration
616- def get (self , path_segment , owner = None , app = None , sharing = None , ** query ):
620+ def get (self , path_segment , owner = None , app = None , headers = None , sharing = None , ** query ):
617621 """Performs a GET operation from the REST path segment with the given
618622 namespace and query.
619623
@@ -636,6 +640,8 @@ def get(self, path_segment, owner=None, app=None, sharing=None, **query):
636640 :type owner: ``string``
637641 :param app: The app context of the namespace (optional).
638642 :type app: ``string``
643+ :param headers: List of extra HTTP headers to send (optional).
644+ :type headers: ``list`` of 2-tuples.
639645 :param sharing: The sharing mode of the namespace (optional).
640646 :type sharing: ``string``
641647 :param query: All other keyword arguments, which are used as query
@@ -663,10 +669,14 @@ def get(self, path_segment, owner=None, app=None, sharing=None, **query):
663669 c.logout()
664670 c.get('apps/local') # raises AuthenticationError
665671 """
672+ if headers is None :
673+ headers = []
674+
666675 path = self .authority + self ._abspath (path_segment , owner = owner ,
667676 app = app , sharing = sharing )
668677 logging .debug ("GET request to %s (body: %s)" , path , repr (query ))
669- response = self .http .get (path , self ._auth_headers , ** query )
678+ all_headers = headers + self .additional_headers + self ._auth_headers
679+ response = self .http .get (path , all_headers , ** query )
670680 return response
671681
672682 @_authentication
@@ -738,7 +748,7 @@ def post(self, path_segment, owner=None, app=None, sharing=None, headers=None, *
738748
739749 path = self .authority + self ._abspath (path_segment , owner = owner , app = app , sharing = sharing )
740750 logging .debug ("POST request to %s (body: %s)" , path , repr (query ))
741- all_headers = headers + self ._auth_headers
751+ all_headers = headers + self .additional_headers + self . _auth_headers
742752 response = self .http .post (path , all_headers , ** query )
743753 return response
744754
@@ -804,7 +814,7 @@ def request(self, path_segment, method="GET", headers=None, body="",
804814 path = self .authority \
805815 + self ._abspath (path_segment , owner = owner ,
806816 app = app , sharing = sharing )
807- all_headers = headers + self ._auth_headers
817+ all_headers = headers + self .additional_headers + self . _auth_headers
808818 logging .debug ("%s request to %s (headers: %s, body: %s)" ,
809819 method , path , str (all_headers ), repr (body ))
810820 response = self .http .request (path ,
@@ -858,6 +868,7 @@ def login(self):
858868 self .authority + self ._abspath ("/services/auth/login" ),
859869 username = self .username ,
860870 password = self .password ,
871+ headers = self .additional_headers ,
861872 cookie = "1" ) # In Splunk 6.2+, passing "cookie=1" will return the "set-cookie" header
862873
863874 body = response .body .read ()
@@ -968,6 +979,8 @@ def connect(**kwargs):
968979 :type username: ``string``
969980 :param password: The password for the Splunk account.
970981 :type password: ``string``
982+ :param headers: List of extra HTTP headers to send (optional).
983+ :type headers: ``list`` of 2-tuples.
971984 :param autologin: When ``True``, automatically tries to log in again if the
972985 session terminates.
973986 :type autologin: ``Boolean``
@@ -1108,8 +1121,11 @@ class HttpLib(object):
11081121
11091122 If using the default handler, SSL verification can be disabled by passing verify=False.
11101123 """
1111- def __init__ (self , custom_handler = None , verify = True ):
1112- self .handler = handler (verify = verify ) if custom_handler is None else custom_handler
1124+ def __init__ (self , custom_handler = None , verify = False , key_file = None , cert_file = None ):
1125+ if custom_handler is None :
1126+ self .handler = handler (verify = verify , key_file = key_file , cert_file = cert_file )
1127+ else :
1128+ self .handler = custom_handler
11131129 self ._cookies = {}
11141130
11151131 def delete (self , url , headers = None , ** kwargs ):
@@ -1190,7 +1206,7 @@ def post(self, url, headers=None, **kwargs):
11901206 # to support the receivers/stream endpoint.
11911207 if 'body' in kwargs :
11921208 # We only use application/x-www-form-urlencoded if there is no other
1193- # Content-Type header present. This can happen in cases where we
1209+ # Content-Type header present. This can happen in cases where we
11941210 # send requests as application/json, e.g. for KV Store.
11951211 if len ([x for x in headers if x [0 ].lower () == "content-type" ]) == 0 :
11961212 headers .append (("Content-Type" , "application/x-www-form-urlencoded" ))
@@ -1280,8 +1296,8 @@ def peek(self, size):
12801296
12811297 def close (self ):
12821298 """Closes this response."""
1283- if _connection :
1284- _connection .close ()
1299+ if self . _connection :
1300+ self . _connection .close ()
12851301 self ._response .close ()
12861302
12871303 def read (self , size = None ):
@@ -1317,7 +1333,7 @@ def readinto(self, byte_array):
13171333 return bytes_read
13181334
13191335
1320- def handler (key_file = None , cert_file = None , timeout = None , verify = True ):
1336+ def handler (key_file = None , cert_file = None , timeout = None , verify = False ):
13211337 """This class returns an instance of the default HTTP request handler using
13221338 the values you provide.
13231339
@@ -1341,7 +1357,7 @@ def connect(scheme, host, port):
13411357 if cert_file is not None : kwargs ['cert_file' ] = cert_file
13421358
13431359 # If running Python 2.7.9+, disable SSL certificate validation
1344- if (sys .version_info >= (2 ,7 ,9 ) and key_file is None and cert_file is None ) or not verify :
1360+ if (sys .version_info >= (2 ,7 ,9 ) and key_file is None and cert_file is None ) and not verify :
13451361 kwargs ['context' ] = ssl ._create_unverified_context ()
13461362 return six .moves .http_client .HTTPSConnection (host , port , ** kwargs )
13471363 raise ValueError ("unsupported scheme: %s" % scheme )
@@ -1352,7 +1368,7 @@ def request(url, message, **kwargs):
13521368 head = {
13531369 "Content-Length" : str (len (body )),
13541370 "Host" : host ,
1355- "User-Agent" : "splunk-sdk-python/1.6.5 " ,
1371+ "User-Agent" : "splunk-sdk-python/1.6.6 " ,
13561372 "Accept" : "*/*" ,
13571373 "Connection" : "Close" ,
13581374 } # defaults
0 commit comments