25
25
"""
26
26
27
27
from __future__ import absolute_import
28
+
29
+ import io
28
30
import logging
29
31
import socket
30
32
import ssl
31
- from io import BytesIO
32
-
33
- from splunklib .six .moves import urllib
34
- import io
35
33
import sys
36
-
37
34
from base64 import b64encode
35
+ from contextlib import contextmanager
38
36
from datetime import datetime
39
37
from functools import wraps
38
+ from io import BytesIO
39
+ from xml .etree .ElementTree import XML
40
+
41
+ from splunklib import six
40
42
from splunklib .six import StringIO
43
+ from splunklib .six .moves import urllib
41
44
42
- from contextlib import contextmanager
45
+ from . data import record
43
46
44
- from xml .etree .ElementTree import XML
45
- from splunklib import six
46
47
try :
47
48
from xml .etree .ElementTree import ParseError
48
49
except ImportError as e :
49
50
from xml .parsers .expat import ExpatError as ParseError
50
51
51
- from .data import record
52
52
53
53
__all__ = [
54
54
"AuthenticationError" ,
@@ -449,6 +449,8 @@ class Context(object):
449
449
:type username: ``string``
450
450
:param password: The password for the Splunk account.
451
451
:type password: ``string``
452
+ :param headers: List of extra HTTP headers to send (optional).
453
+ :type headers: ``list`` of 2-tuples.
452
454
:param handler: The HTTP request handler (optional).
453
455
:returns: A ``Context`` instance.
454
456
@@ -465,7 +467,8 @@ class Context(object):
465
467
c = binding.Context(cookie="splunkd_8089=...")
466
468
"""
467
469
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
469
472
self .token = kwargs .get ("token" , _NoAuthenticationToken )
470
473
if self .token is None : # In case someone explicitly passes token=None
471
474
self .token = _NoAuthenticationToken
@@ -478,6 +481,7 @@ def __init__(self, handler=None, **kwargs):
478
481
self .password = kwargs .get ("password" , "" )
479
482
self .basic = kwargs .get ("basic" , False )
480
483
self .autologin = kwargs .get ("autologin" , False )
484
+ self .additional_headers = kwargs .get ("headers" , [])
481
485
482
486
# Store any cookies in the self.http._cookies dict
483
487
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):
613
617
614
618
@_authentication
615
619
@_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 ):
617
621
"""Performs a GET operation from the REST path segment with the given
618
622
namespace and query.
619
623
@@ -636,6 +640,8 @@ def get(self, path_segment, owner=None, app=None, sharing=None, **query):
636
640
:type owner: ``string``
637
641
:param app: The app context of the namespace (optional).
638
642
:type app: ``string``
643
+ :param headers: List of extra HTTP headers to send (optional).
644
+ :type headers: ``list`` of 2-tuples.
639
645
:param sharing: The sharing mode of the namespace (optional).
640
646
:type sharing: ``string``
641
647
: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):
663
669
c.logout()
664
670
c.get('apps/local') # raises AuthenticationError
665
671
"""
672
+ if headers is None :
673
+ headers = []
674
+
666
675
path = self .authority + self ._abspath (path_segment , owner = owner ,
667
676
app = app , sharing = sharing )
668
677
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 )
670
680
return response
671
681
672
682
@_authentication
@@ -738,7 +748,7 @@ def post(self, path_segment, owner=None, app=None, sharing=None, headers=None, *
738
748
739
749
path = self .authority + self ._abspath (path_segment , owner = owner , app = app , sharing = sharing )
740
750
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
742
752
response = self .http .post (path , all_headers , ** query )
743
753
return response
744
754
@@ -804,7 +814,7 @@ def request(self, path_segment, method="GET", headers=None, body="",
804
814
path = self .authority \
805
815
+ self ._abspath (path_segment , owner = owner ,
806
816
app = app , sharing = sharing )
807
- all_headers = headers + self ._auth_headers
817
+ all_headers = headers + self .additional_headers + self . _auth_headers
808
818
logging .debug ("%s request to %s (headers: %s, body: %s)" ,
809
819
method , path , str (all_headers ), repr (body ))
810
820
response = self .http .request (path ,
@@ -858,6 +868,7 @@ def login(self):
858
868
self .authority + self ._abspath ("/services/auth/login" ),
859
869
username = self .username ,
860
870
password = self .password ,
871
+ headers = self .additional_headers ,
861
872
cookie = "1" ) # In Splunk 6.2+, passing "cookie=1" will return the "set-cookie" header
862
873
863
874
body = response .body .read ()
@@ -968,6 +979,8 @@ def connect(**kwargs):
968
979
:type username: ``string``
969
980
:param password: The password for the Splunk account.
970
981
:type password: ``string``
982
+ :param headers: List of extra HTTP headers to send (optional).
983
+ :type headers: ``list`` of 2-tuples.
971
984
:param autologin: When ``True``, automatically tries to log in again if the
972
985
session terminates.
973
986
:type autologin: ``Boolean``
@@ -1108,8 +1121,11 @@ class HttpLib(object):
1108
1121
1109
1122
If using the default handler, SSL verification can be disabled by passing verify=False.
1110
1123
"""
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
1113
1129
self ._cookies = {}
1114
1130
1115
1131
def delete (self , url , headers = None , ** kwargs ):
@@ -1190,7 +1206,7 @@ def post(self, url, headers=None, **kwargs):
1190
1206
# to support the receivers/stream endpoint.
1191
1207
if 'body' in kwargs :
1192
1208
# 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
1194
1210
# send requests as application/json, e.g. for KV Store.
1195
1211
if len ([x for x in headers if x [0 ].lower () == "content-type" ]) == 0 :
1196
1212
headers .append (("Content-Type" , "application/x-www-form-urlencoded" ))
@@ -1280,8 +1296,8 @@ def peek(self, size):
1280
1296
1281
1297
def close (self ):
1282
1298
"""Closes this response."""
1283
- if _connection :
1284
- _connection .close ()
1299
+ if self . _connection :
1300
+ self . _connection .close ()
1285
1301
self ._response .close ()
1286
1302
1287
1303
def read (self , size = None ):
@@ -1317,7 +1333,7 @@ def readinto(self, byte_array):
1317
1333
return bytes_read
1318
1334
1319
1335
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 ):
1321
1337
"""This class returns an instance of the default HTTP request handler using
1322
1338
the values you provide.
1323
1339
@@ -1341,7 +1357,7 @@ def connect(scheme, host, port):
1341
1357
if cert_file is not None : kwargs ['cert_file' ] = cert_file
1342
1358
1343
1359
# 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 :
1345
1361
kwargs ['context' ] = ssl ._create_unverified_context ()
1346
1362
return six .moves .http_client .HTTPSConnection (host , port , ** kwargs )
1347
1363
raise ValueError ("unsupported scheme: %s" % scheme )
@@ -1352,7 +1368,7 @@ def request(url, message, **kwargs):
1352
1368
head = {
1353
1369
"Content-Length" : str (len (body )),
1354
1370
"Host" : host ,
1355
- "User-Agent" : "splunk-sdk-python/1.6.5 " ,
1371
+ "User-Agent" : "splunk-sdk-python/1.6.6 " ,
1356
1372
"Accept" : "*/*" ,
1357
1373
"Connection" : "Close" ,
1358
1374
} # defaults
0 commit comments