Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 42 additions & 1 deletion sendgrid/sendgrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
from socket import timeout
from .version import __version__
try:
import http.client as http_client
import urllib.request as urllib_request
from urllib.parse import urlencode
from urllib.error import HTTPError
except ImportError: # Python 2
import httplib as http_client
import urllib2 as urllib_request
from urllib2 import HTTPError
from urllib import urlencode
Expand Down Expand Up @@ -50,6 +52,8 @@ def __init__(self, username_or_apikey, password=None, **opts):
self._raise_errors = opts.get('raise_errors', False)
# urllib cannot connect to SSL servers using proxies
self.proxies = opts.get('proxies', None)
self._server = None
self._max_retry = 3

def _build_body(self, message):
if sys.version_info < (3, 0):
Expand Down Expand Up @@ -92,7 +96,7 @@ def _build_body(self, message):
values['content[' + content + ']'] = message.content[content]
return values

def _make_request(self, message):
def _make_nonpersistent_request(self, message):
if self.proxies:
proxy_support = urllib_request.ProxyHandler(self.proxies)
opener = urllib_request.build_opener(proxy_support)
Expand All @@ -109,6 +113,43 @@ def _make_request(self, message):
body = response.read()
return response.getcode(), body

def _make_persistent_request(self, message):
data = urlencode(self._build_body(message), True).encode('utf-8')
domain = self.host.lstrip('http://').lstrip('https://')
headers = {
'User-Agent': self.useragent,
'Host': domain + ':' + self.port,
'Content-Type': 'application/x-www-form-urlencoded',
'Connection': 'Keep-Alive',
}
if self.username is None:
# Using API key
headers['Authorization'] = 'Bearer ' + self.password
for _ in range(self._max_retry):
if self._server is None:
self._server = http_client.HTTPSConnection(domain,
int(self.port))
self._server.request('POST', self.endpoint, data, headers=headers)
try:
response = self._server.getresponse()
body = response.read()
return response.status, body
except http_client.BadStatusLine:
# Persistent request timeout reached. Retrying...
self._server.close()
self._server = None
raise timeout("Unable to start persistent connection")

def _make_request(self, message):
if not self.proxies:
try:
return self._make_persistent_request(message)
except timeout:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we want to ignore timeout for persistent requests?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm launching a non-persistent call as a fall-back when the persistent call fails (timeout).
That's why I'm ignoring the error.

But I agree that it looks a bit odd...

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps the comment could be Timeout on persistent request, falling back to non-persistent request.

Btw, will falling back to non-persistent requests going to help?

# Timeout on persistent request, falling back to
# non-persistent request
pass
return self._make_nonpersistent_request(message)

def send(self, message):
if self._raise_errors:
return self._raising_send(message)
Expand Down