Skip to content

Commit

Permalink
Merge pull request #67 from ecederstrand/patch-1
Browse files Browse the repository at this point in the history
Deprecate the _get_shortname_from_docs method
  • Loading branch information
jaghooli authored Jun 4, 2021
2 parents e65decc + f2b95c7 commit 027875a
Show file tree
Hide file tree
Showing 3 changed files with 4 additions and 59 deletions.
14 changes: 2 additions & 12 deletions exchangelib/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from .properties import FreeBusyViewOptions, MailboxData, TimeWindow, TimeZone
from .services import GetServerTimeZones, GetRoomLists, GetRooms, ResolveNames, GetUserAvailability, \
GetSearchableMailboxes
from .transport import get_auth_instance, get_service_authtype, get_docs_authtype, AUTH_TYPE_MAP, DEFAULT_HEADERS
from .transport import get_auth_instance, get_service_authtype, AUTH_TYPE_MAP, DEFAULT_HEADERS
from .util import split_url
from .version import Version, API_VERSIONS

Expand Down Expand Up @@ -225,9 +225,6 @@ def __init__(self, *args, **kwargs):
self.auth_type = get_service_authtype(service_endpoint=self.service_endpoint, versions=API_VERSIONS,
name=self.credentials.username)

# Default to the auth type used by the service. We only need this if 'version' is None
self.docs_auth_type = self.auth_type

# Try to behave nicely with the Exchange server. We want to keep the connection open between requests.
# We also want to re-use sessions, to avoid the NTLM auth handshake on every request.
pool_size = self.pool_size or self.SESSION_POOLSIZE
Expand All @@ -240,11 +237,6 @@ def __init__(self, *args, **kwargs):
self.version = version
else:
# Version.guess() needs auth objects and a working session pool
try:
# Try to get the auth_type of 'types.xsd' so we can fetch it and look at the version contained there
self.docs_auth_type = get_docs_authtype(docs_url=self.types_url)
except TransportError:
pass
self.version = Version.guess(self)

# Used by services to process service requests that are able to run in parallel. Thread pool should be
Expand Down Expand Up @@ -365,14 +357,12 @@ def __str__(self):
Product name: %s
EWS API version: %s
Build number: %s
EWS auth: %s
XSD auth: %s''' % (
EWS auth: %s''' % (
self.service_endpoint,
self.version.fullname,
self.version.api_version,
self.version.build,
self.auth_type,
self.docs_auth_type,
)


Expand Down
9 changes: 0 additions & 9 deletions exchangelib/transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,6 @@ def get_autodiscover_authtype(service_endpoint, data):
return _get_auth_method_from_response(response=r)


def get_docs_authtype(docs_url):
# Get auth type by tasting headers from the server. Don't do HEAD requests. It's too error prone.
log.debug('Getting docs auth type for %s', docs_url)
from .protocol import BaseProtocol
with BaseProtocol.raw_session() as s:
r = s.get(url=docs_url, headers=DEFAULT_HEADERS.copy(), allow_redirects=True, timeout=BaseProtocol.TIMEOUT)
return _get_auth_method_from_response(response=r)


def get_service_authtype(service_endpoint, versions, name):
# Get auth type by tasting headers from the server. Only do POST requests. HEAD is too error prone, and some servers
# are set up to redirect to OWA on all requests except POST to /EWS/Exchange.asmx
Expand Down
40 changes: 2 additions & 38 deletions exchangelib/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,48 +191,12 @@ def guess(cls, protocol):
Tries to ask the server which version it has. We haven't set up an Account object yet, so we generate requests
by hand. We only need a response header containing a ServerVersionInfo element.
The types.xsd document contains a 'shortname' value that we can use as a key for VERSIONS to get the API version
that we need in SOAP headers to generate valid requests. Unfortunately, the Exchagne server may be misconfigured
to either block access to types.xsd or serve up a wrong version of the document. Therefore, we only use
'shortname' as a hint, but trust the SOAP version returned in response headers.
To get API version and build numbers from the server, we need to send a valid SOAP request. We can't do that
without a valid API version. To solve this chicken-and-egg problem, we try all possible API versions that this
package supports, until we get a valid response. If we managed to get a 'shortname' previously, we try the
corresponding API version first.
package supports, until we get a valid response.
"""
log.debug('Asking server for version info')
# We can't use a session object from the protocol pool for docs because sessions are created with service auth.
auth = get_auth_instance(credentials=protocol.credentials, auth_type=protocol.docs_auth_type)
try:
shortname = cls._get_shortname_from_docs(auth=auth, types_url=protocol.types_url)
log.debug('Shortname according to %s: %s', protocol.types_url, shortname)
except (TransportError, ParseError) as e:
log.info(text_type(e))
shortname = None
api_version = VERSIONS[shortname][0] if shortname else None
return cls._guess_version_from_service(protocol=protocol, hint=api_version)

@staticmethod
def _get_shortname_from_docs(auth, types_url):
# Get the server version from types.xsd. We can't necessarily use the service auth type since it may not be the
# same as the auth type for docs.
log.debug('Getting %s with auth type %s', types_url, auth.__class__.__name__)
# Some servers send an empty response if we send 'Connection': 'close' header
from .protocol import BaseProtocol
with BaseProtocol.raw_session() as s:
r = s.get(url=types_url, auth=auth, allow_redirects=False, stream=False)
log.debug('Request headers: %s', r.request.headers)
log.debug('Response code: %s', r.status_code)
log.debug('Response headers: %s', r.headers)
if r.status_code != 200:
raise TransportError('Unexpected HTTP status %s when getting %s (%s)' % (r.status_code, types_url, r.text))
if not is_xml(r.content):
raise TransportError('Unexpected result when getting %s. Maybe this is not an EWS server?%s' % (
types_url,
'\n\n%s[...]' % r.text[:200] if len(r.text) > 200 else '\n\n%s' % r.text if r.text else '',
))
return to_xml(r.content).get('version')
return cls._guess_version_from_service(protocol=protocol)

@classmethod
def _guess_version_from_service(cls, protocol, hint=None):
Expand Down

0 comments on commit 027875a

Please sign in to comment.