Skip to content

Commit b5cd5cf

Browse files
committed
Merged in [19839] from jennifer@painless-security.com:
Add timeouts to requests library calls. Fixes ietf-tools#3498. - Legacy-Id: 19851 Note: SVN reference [19839] has been migrated to Git commit 6f3fb69
2 parents 5e57609 + 6f3fb69 commit b5cd5cf

10 files changed

Lines changed: 91 additions & 25 deletions

File tree

ietf/bin/iana-protocols-updates

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,16 @@ syslog.syslog("Updating history log with new RFC entries from IANA protocols pag
3131
# FIXME: this needs to be the date where this tool is first deployed
3232
rfc_must_published_later_than = datetime.datetime(2012, 11, 26, 0, 0, 0)
3333

34-
text = requests.get(settings.IANA_SYNC_PROTOCOLS_URL).text
35-
rfc_numbers = parse_protocol_page(text)
34+
try:
35+
response = requests.get(
36+
settings.IANA_SYNC_PROTOCOLS_URL,
37+
timeout=30,
38+
)
39+
except requests.Timeout as exc:
40+
syslog.syslog(f'GET request timed out retrieving IANA protocols page: {exc}')
41+
sys.exit(1)
42+
43+
rfc_numbers = parse_protocol_page(response.text)
3644
for chunk in chunks(rfc_numbers, 100):
3745
updated = update_rfc_log_from_protocol_page(chunk, rfc_must_published_later_than)
3846

ietf/bin/rfc-editor-index-updates

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@
55

66
import datetime
77
import io
8-
import json
98
import os
109
import requests
11-
import socket
1210
import sys
1311
import syslog
1412
import traceback
@@ -48,11 +46,28 @@ if options.skip_date:
4846
log("Updating document metadata from RFC index going back to %s, from %s" % (skip_date, settings.RFC_EDITOR_INDEX_URL))
4947

5048

51-
socket.setdefaulttimeout(30)
52-
rfc_index_xml = requests.get(settings.RFC_EDITOR_INDEX_URL).text
49+
try:
50+
response = requests.get(
51+
settings.RFC_EDITOR_INDEX_URL,
52+
timeout=30, # seconds
53+
)
54+
except requests.Timeout as exc:
55+
log(f'GET request timed out retrieving RFC editor index: {exc}')
56+
sys.exit(1)
57+
58+
59+
rfc_index_xml = response.text
5360
index_data = ietf.sync.rfceditor.parse_index(io.StringIO(rfc_index_xml))
5461

55-
errata_data = requests.get(settings.RFC_EDITOR_ERRATA_JSON_URL).json()
62+
try:
63+
response = requests.get(
64+
settings.RFC_EDITOR_ERRATA_JSON_URL,
65+
timeout=30, # seconds
66+
)
67+
except requests.Timeout as exc:
68+
log(f'GET request timed out retrieving RFC editor errata: {exc}')
69+
sys.exit(1)
70+
errata_data = response.json()
5671

5772
if len(index_data) < ietf.sync.rfceditor.MIN_INDEX_RESULTS:
5873
log("Not enough index entries, only %s" % len(index_data))

ietf/bin/rfc-editor-queue-updates

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import io
44
import os
55
import requests
6-
import socket
76
import sys
87

98
# boilerplate
@@ -21,9 +20,15 @@ from ietf.utils.log import log
2120

2221
log("Updating RFC Editor queue states from %s" % settings.RFC_EDITOR_QUEUE_URL)
2322

24-
socket.setdefaulttimeout(30)
25-
response = requests.get(settings.RFC_EDITOR_QUEUE_URL).text
26-
drafts, warnings = parse_queue(io.StringIO(response))
23+
try:
24+
response = requests.get(
25+
settings.RFC_EDITOR_QUEUE_URL,
26+
timeout=30, # seconds
27+
)
28+
except requests.Timeout as exc:
29+
log(f'GET request timed out retrieving RFC editor queue: {exc}')
30+
sys.exit(1)
31+
drafts, warnings = parse_queue(io.StringIO(response.text))
2732
for w in warnings:
2833
log(u"Warning: %s" % w)
2934

ietf/doc/views_review.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
close_review_request_states,
4545
close_review_request)
4646
from ietf.review import mailarch
47+
from ietf.utils import log
4748
from ietf.utils.fields import DatepickerDateField
4849
from ietf.utils.text import strip_prefix, xslugify
4950
from ietf.utils.textupload import get_cleaned_text_file_content
@@ -621,9 +622,13 @@ def clean_review_url(self):
621622
url = self.cleaned_data['review_url']
622623
#scheme, netloc, path, parameters, query, fragment = urlparse(url)
623624
if url:
624-
r = requests.get(url)
625+
try:
626+
r = requests.get(url, timeout=settings.DEFAULT_REQUESTS_TIMEOUT)
627+
except requests.Timeout as exc:
628+
log.log(f'GET request timed out for [{url}]: {exc}')
629+
raise forms.ValidationError("Trying to retrieve the URL resulted in a request timeout. Please provide a URL that can be retrieved.") from exc
625630
if r.status_code != 200:
626-
raise forms.ValidationError("Trying to retrieve the URL resulted in status code %s: %s. Please provide an URL that can be retrieved." % (r.status_code, r.reason))
631+
raise forms.ValidationError("Trying to retrieve the URL resulted in status code %s: %s. Please provide a URL that can be retrieved." % (r.status_code, r.reason))
627632
return url
628633

629634
def clean(self):

ietf/meeting/utils.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from ietf.person.models import Person
2929
from ietf.secr.proceedings.proc_utils import import_audio_files
3030
from ietf.utils.html import sanitize_document
31+
from ietf.utils.log import log
3132

3233

3334
def session_time_for_sorting(session, use_meeting_date):
@@ -123,9 +124,10 @@ def create_proceedings_templates(meeting):
123124
# Get meeting attendees from registration system
124125
url = settings.STATS_REGISTRATION_ATTENDEES_JSON_URL.format(number=meeting.number)
125126
try:
126-
attendees = requests.get(url).json()
127-
except (ValueError, HTTPError):
127+
attendees = requests.get(url, timeout=settings.DEFAULT_REQUESTS_TIMEOUT).json()
128+
except (ValueError, HTTPError, requests.Timeout) as exc:
128129
attendees = []
130+
log(f'Failed to retrieve meeting attendees from [{url}]: {exc}')
129131

130132
if attendees:
131133
attendees = sorted(attendees, key = lambda a: a['LastName'])

ietf/settings.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,6 +1232,10 @@ def skip_unreadable_post(record):
12321232
-----END PRIVATE KEY-----
12331233
"""
12341234

1235+
1236+
# Default timeout for HTTP requests via the requests library
1237+
DEFAULT_REQUESTS_TIMEOUT = 20 # seconds
1238+
12351239
# Put the production SECRET_KEY in settings_local.py, and also any other
12361240
# sensitive or site-specific changes. DO NOT commit settings_local.py to svn.
12371241
from ietf.settings_local import * # pyflakes:ignore pylint: disable=wildcard-import

ietf/stats/utils.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from ietf.name.models import CountryName
1616
from ietf.person.models import Person, Email, Alias
1717
from ietf.person.name import unidecode_name
18+
from ietf.utils.log import log
1819

1920

2021
def compile_affiliation_ending_stripping_regexp():
@@ -230,7 +231,14 @@ def get_meeting_registration_data(meeting):
230231
"""
231232
num_created = 0
232233
num_processed = 0
233-
response = requests.get(settings.STATS_REGISTRATION_ATTENDEES_JSON_URL.format(number=meeting.number))
234+
try:
235+
response = requests.get(
236+
settings.STATS_REGISTRATION_ATTENDEES_JSON_URL.format(number=meeting.number),
237+
timeout=settings.DEFAULT_REQUESTS_TIMEOUT,
238+
)
239+
except requests.Timeout as exc:
240+
log(f'GET request timed out for [{settings.STATS_REGISTRATION_ATTENDEES_JSON_URL}]: {exc}')
241+
raise RuntimeError("Timeout retrieving data from registrations API") from exc
234242
if response.status_code == 200:
235243
decoded = []
236244
try:

ietf/sync/iana.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from ietf.doc.models import Document, DocEvent, State, StateDocEvent, StateType
2020
from ietf.doc.utils import add_state_change_event
2121
from ietf.person.models import Person
22+
from ietf.utils.log import log
2223
from ietf.utils.mail import parseaddr, get_payload_text
2324
from ietf.utils.timezone import local_timezone_to_utc, email_time_to_local_timezone, utc_to_local_timezone
2425

@@ -69,8 +70,12 @@ def fetch_changes_json(url, start, end):
6970
username = "ietfsync"
7071
password = settings.IANA_SYNC_PASSWORD
7172
headers = { "Authorization": "Basic %s" % force_str(base64.encodebytes(smart_bytes("%s:%s" % (username, password)))).replace("\n", "") }
72-
text = requests.get(url, headers=headers).text
73-
return text
73+
try:
74+
response = requests.get(url, headers=headers, timeout=settings.DEFAULT_REQUESTS_TIMEOUT)
75+
except requests.Timeout as exc:
76+
log(f'GET request failed for [{url}]: {exc}')
77+
raise RuntimeError(f'Timeout retrieving [{url}]') from exc
78+
return response.text
7479

7580
def parse_changes_json(text):
7681
response = json.loads(text)

ietf/sync/rfceditor.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,12 @@ def post_approved_draft(url, name):
558558
text = error = ""
559559

560560
try:
561-
r = requests.post(url, headers=headers, data=smart_bytes(urlencode({ 'draft': name })), timeout=20)
561+
r = requests.post(
562+
url,
563+
headers=headers,
564+
data=smart_bytes(urlencode({ 'draft': name })),
565+
timeout=settings.DEFAULT_REQUESTS_TIMEOUT,
566+
)
562567

563568
log("RFC-Editor notification result for draft '%s': %s:'%s'" % (name, r.status_code, r.text))
564569

ietf/utils/hedgedoc.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,13 @@ def get_source(self):
3939
"""
4040
if self._source is None:
4141
try:
42-
r = requests.get(urljoin(self.base_url, f'{self.id}/download'), allow_redirects=True)
43-
except requests.RequestException:
44-
raise ServerNoteError
42+
r = requests.get(
43+
urljoin(self.base_url, f'{self.id}/download'),
44+
allow_redirects=True,
45+
timeout=settings.DEFAULT_REQUESTS_TIMEOUT,
46+
)
47+
except requests.RequestException as exc:
48+
raise ServerNoteError from exc
4549
if r.status_code != 200:
4650
raise NoteNotFound
4751
self._source = self.preprocess_source(r.text)
@@ -69,9 +73,13 @@ def get_update_time(self):
6973
def _retrieve_metadata(self):
7074
if self._metadata is None:
7175
try:
72-
r = requests.get(urljoin(self.base_url, f'{self.id}/info'), allow_redirects=True)
73-
except requests.RequestException:
74-
raise ServerNoteError
76+
r = requests.get(
77+
urljoin(self.base_url, f'{self.id}/info'),
78+
allow_redirects=True,
79+
timeout=settings.DEFAULT_REQUESTS_TIMEOUT,
80+
)
81+
except requests.RequestException as exc:
82+
raise ServerNoteError from exc
7583
if r.status_code != 200:
7684
raise NoteNotFound
7785
try:
@@ -109,6 +117,7 @@ def __init__(self, *args, **kwargs):
109117
class ServerNoteError(NoteError):
110118
default_message = 'Could not reach the notes server'
111119

120+
112121
class NoteNotFound(NoteError):
113122
default_message = 'Note did not exist or could not be loaded'
114123

0 commit comments

Comments
 (0)