Skip to content

Commit caa42e8

Browse files
committed
Only allow explicit subscriptions via allow_subscriptions=True
1 parent f9d2a62 commit caa42e8

File tree

8 files changed

+32
-13
lines changed

8 files changed

+32
-13
lines changed

graphql/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@
120120
# Execute GraphQL queries.
121121
from .execution import ( # no import order
122122
execute,
123+
subscribe,
123124
ResolveInfo,
124125
MiddlewareManager,
125126
middlewares
@@ -254,6 +255,7 @@
254255
'print_ast',
255256
'visit',
256257
'execute',
258+
'subscribe',
257259
'ResolveInfo',
258260
'MiddlewareManager',
259261
'middlewares',

graphql/execution/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@
1818
2) fragment "spreads" e.g. "...c"
1919
3) inline fragment "spreads" e.g. "...on Type { a }"
2020
"""
21-
from .executor import execute
21+
from .executor import execute, subscribe
2222
from .base import ExecutionResult, ResolveInfo
2323
from .middleware import middlewares, MiddlewareManager
2424

2525

2626
__all__ = [
2727
'execute',
28+
'subscribe',
2829
'ExecutionResult',
2930
'ResolveInfo',
3031
'MiddlewareManager',

graphql/execution/base.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ class ExecutionContext(object):
1919
and the fragments defined in the query document"""
2020

2121
__slots__ = 'schema', 'fragments', 'root_value', 'operation', 'variable_values', 'errors', 'context_value', \
22-
'argument_values_cache', 'executor', 'middleware', '_subfields_cache'
22+
'argument_values_cache', 'executor', 'middleware', 'allow_subscriptions', '_subfields_cache'
2323

24-
def __init__(self, schema, document_ast, root_value, context_value, variable_values, operation_name, executor, middleware):
24+
def __init__(self, schema, document_ast, root_value, context_value, variable_values, operation_name, executor, middleware, allow_subscriptions):
2525
"""Constructs a ExecutionContext object from the arguments passed
2626
to execute, which we will pass throughout the other execution
2727
methods."""
@@ -69,6 +69,7 @@ def __init__(self, schema, document_ast, root_value, context_value, variable_val
6969
self.argument_values_cache = {}
7070
self.executor = executor
7171
self.middleware = middleware
72+
self.allow_subscriptions = allow_subscriptions
7273
self._subfields_cache = {}
7374

7475
def get_field_resolver(self, field_resolver):

graphql/execution/executor.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,14 @@
2323
logger = logging.getLogger(__name__)
2424

2525

26+
def subscribe(*args, **kwargs):
27+
allow_subscriptions = kwargs.pop('allow_subscriptions', True)
28+
return execute(*args, allow_subscriptions=allow_subscriptions, **kwargs)
29+
30+
2631
def execute(schema, document_ast, root_value=None, context_value=None,
2732
variable_values=None, operation_name=None, executor=None,
28-
return_promise=False, middleware=None):
33+
return_promise=False, middleware=None, allow_subscriptions=False):
2934
assert schema, 'Must provide schema'
3035
assert isinstance(schema, GraphQLSchema), (
3136
'Schema must be an instance of GraphQLSchema. Also ensure that there are ' +
@@ -51,7 +56,8 @@ def execute(schema, document_ast, root_value=None, context_value=None,
5156
variable_values,
5257
operation_name,
5358
executor,
54-
middleware
59+
middleware,
60+
allow_subscriptions
5561
)
5662

5763
def executor(v):
@@ -93,6 +99,12 @@ def execute_operation(exe_context, operation, root_value):
9399
return execute_fields_serially(exe_context, type, root_value, fields)
94100

95101
if operation.operation == 'subscription':
102+
if not exe_context.allow_subscriptions:
103+
raise Exception(
104+
"Subscriptions are not allowed. "
105+
"You will need to either use the subscribe function "
106+
"or pass allow_subscriptions=True"
107+
)
96108
return subscribe_fields(exe_context, type, root_value, fields)
97109

98110
return execute_fields(exe_context, type, root_value, fields)

graphql/execution/tests/test_executor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ class Data(object):
395395
'a': GraphQLField(GraphQLString, resolver=lambda root, info: Observable.from_(['b']))
396396
})
397397
result = execute(GraphQLSchema(Q, subscription=S),
398-
ast, Data(), operation_name='S')
398+
ast, Data(), operation_name='S', allow_subscriptions=True)
399399
assert isinstance(result, Observable)
400400
l = []
401401
result.subscribe(l.append)

graphql/execution/tests/test_subscribe.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from collections import OrderedDict, namedtuple
22
from rx import Observable, Observer
33
from rx.subjects import Subject
4-
from graphql import parse, GraphQLObjectType, GraphQLString, GraphQLBoolean, GraphQLInt, GraphQLField, GraphQLList, GraphQLSchema, graphql, execute
4+
from graphql import parse, GraphQLObjectType, GraphQLString, GraphQLBoolean, GraphQLInt, GraphQLField, GraphQLList, GraphQLSchema, graphql, subscribe
55

66
Email = namedtuple('Email', 'from_,subject,message,unread')
77

@@ -126,7 +126,8 @@ def send_important_email(new_email):
126126
ast or default_ast,
127127
Root,
128128
None,
129-
vars
129+
vars,
130+
allow_subscriptions=True,
130131
)
131132

132133

@@ -136,7 +137,7 @@ def test_accepts_an_object_with_named_properties_as_arguments():
136137
importantEmail
137138
}
138139
''')
139-
result = execute(
140+
result = subscribe(
140141
email_schema,
141142
document,
142143
root_value=None
@@ -231,7 +232,7 @@ def thrower(root, info):
231232
raise exc
232233

233234
erroring_email_schema = email_schema_with_resolvers(thrower)
234-
result = execute(erroring_email_schema, parse('''
235+
result = subscribe(erroring_email_schema, parse('''
235236
subscription {
236237
importantEmail
237238
}
@@ -389,5 +390,6 @@ def test_event_order_is_correct_for_multiple_publishes():
389390
}
390391

391392
assert len(payload) == 2
393+
print(payload)
392394
assert payload[0].data == expected_payload1
393395
assert payload[1].data == expected_payload2

graphql/graphql.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def graphql(*args, **kwargs):
4040

4141
def execute_graphql(schema, request_string='', root_value=None, context_value=None,
4242
variable_values=None, operation_name=None, executor=None,
43-
return_promise=False, middleware=None):
43+
return_promise=False, middleware=None, allow_subscriptions=False):
4444
try:
4545
if isinstance(request_string, Document):
4646
ast = request_string
@@ -62,7 +62,8 @@ def execute_graphql(schema, request_string='', root_value=None, context_value=No
6262
variable_values=variable_values or {},
6363
executor=executor,
6464
middleware=middleware,
65-
return_promise=return_promise
65+
return_promise=return_promise,
66+
allow_subscriptions=allow_subscriptions,
6667
)
6768
except Exception as e:
6869
return ExecutionResult(

graphql/type/tests/test_enum_type.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ def test_accepts_enum_literals_as_input_arguments_to_mutations():
151151
def test_accepts_enum_literals_as_input_arguments_to_subscriptions():
152152
result = graphql(
153153
Schema, 'subscription x($color: Color!) { subscribeToEnum(color: $color) }', variable_values={
154-
'color': 'GREEN'})
154+
'color': 'GREEN'}, allow_subscriptions=True)
155155
assert isinstance(result, Observable)
156156
l = []
157157
result.subscribe(l.append)

0 commit comments

Comments
 (0)