|
12 | 12 | # See the License for the specific language governing permissions and
|
13 | 13 | # limitations under the License.
|
14 | 14 |
|
15 |
| -import enum |
| 15 | +import functools |
16 | 16 | import importlib.util
|
17 |
| -import io |
18 |
| -import json |
19 | 17 | import os.path
|
20 | 18 | import pathlib
|
21 | 19 | import sys
|
22 | 20 | import types
|
23 | 21 |
|
24 |
| -import cloudevents.sdk |
25 |
| -import cloudevents.sdk.event |
26 |
| -import cloudevents.sdk.event.v1 |
27 |
| -import cloudevents.sdk.marshaller |
28 | 22 | import flask
|
29 | 23 | import werkzeug
|
30 | 24 |
|
|
42 | 36 | MAX_CONTENT_LENGTH = 10 * 1024 * 1024
|
43 | 37 |
|
44 | 38 |
|
45 |
| -class _EventType(enum.Enum): |
46 |
| - LEGACY = 1 |
47 |
| - CLOUDEVENT_BINARY = 2 |
48 |
| - CLOUDEVENT_STRUCTURED = 3 |
49 |
| - |
50 |
| - |
51 | 39 | class _Event(object):
|
52 | 40 | """Event passed to background functions."""
|
53 | 41 |
|
@@ -80,83 +68,38 @@ def view_func(path):
|
80 | 68 | return view_func
|
81 | 69 |
|
82 | 70 |
|
83 |
| -def _get_cloudevent_version(): |
84 |
| - return cloudevents.sdk.event.v1.Event() |
85 |
| - |
86 |
| - |
87 |
| -def _run_legacy_event(function, request): |
88 |
| - event_data = request.get_json() |
89 |
| - if not event_data: |
90 |
| - flask.abort(400) |
91 |
| - event_object = _Event(**event_data) |
92 |
| - data = event_object.data |
93 |
| - context = Context(**event_object.context) |
94 |
| - function(data, context) |
95 |
| - |
96 |
| - |
97 |
| -def _run_binary_cloudevent(function, request, cloudevent_def): |
98 |
| - data = io.BytesIO(request.get_data()) |
99 |
| - http_marshaller = cloudevents.sdk.marshaller.NewDefaultHTTPMarshaller() |
100 |
| - event = http_marshaller.FromRequest( |
101 |
| - cloudevent_def, request.headers, data, json.load |
102 |
| - ) |
103 |
| - |
104 |
| - function(event) |
105 |
| - |
106 |
| - |
107 |
| -def _run_structured_cloudevent(function, request, cloudevent_def): |
108 |
| - data = io.StringIO(request.get_data(as_text=True)) |
109 |
| - m = cloudevents.sdk.marshaller.NewDefaultHTTPMarshaller() |
110 |
| - event = m.FromRequest(cloudevent_def, request.headers, data, json.loads) |
111 |
| - function(event) |
112 |
| - |
113 |
| - |
114 |
| -def _get_event_type(request): |
115 |
| - if ( |
| 71 | +def _is_binary_cloud_event(request): |
| 72 | + return ( |
116 | 73 | request.headers.get("ce-type")
|
117 | 74 | and request.headers.get("ce-specversion")
|
118 | 75 | and request.headers.get("ce-source")
|
119 | 76 | and request.headers.get("ce-id")
|
120 |
| - ): |
121 |
| - return _EventType.CLOUDEVENT_BINARY |
122 |
| - elif request.headers.get("Content-Type") == "application/cloudevents+json": |
123 |
| - return _EventType.CLOUDEVENT_STRUCTURED |
124 |
| - else: |
125 |
| - return _EventType.LEGACY |
| 77 | + ) |
126 | 78 |
|
127 | 79 |
|
128 | 80 | def _event_view_func_wrapper(function, request):
|
129 | 81 | def view_func(path):
|
130 |
| - if _get_event_type(request) == _EventType.LEGACY: |
131 |
| - _run_legacy_event(function, request) |
132 |
| - else: |
133 |
| - # here for defensive backwards compatibility in case we make a mistake in rollout. |
134 |
| - flask.abort( |
135 |
| - 400, |
136 |
| - description="The FUNCTION_SIGNATURE_TYPE for this function is set to event " |
137 |
| - "but no Google Cloud Functions Event was given. If you are using CloudEvents set " |
138 |
| - "FUNCTION_SIGNATURE_TYPE=cloudevent", |
| 82 | + if _is_binary_cloud_event(request): |
| 83 | + # Support CloudEvents in binary content mode, with data being the |
| 84 | + # whole request body and context attributes retrieved from request |
| 85 | + # headers. |
| 86 | + data = request.get_data() |
| 87 | + context = Context( |
| 88 | + eventId=request.headers.get("ce-eventId"), |
| 89 | + timestamp=request.headers.get("ce-timestamp"), |
| 90 | + eventType=request.headers.get("ce-eventType"), |
| 91 | + resource=request.headers.get("ce-resource"), |
139 | 92 | )
|
140 |
| - |
141 |
| - return "OK" |
142 |
| - |
143 |
| - return view_func |
144 |
| - |
145 |
| - |
146 |
| -def _cloudevent_view_func_wrapper(function, request): |
147 |
| - def view_func(path): |
148 |
| - cloudevent_def = _get_cloudevent_version() |
149 |
| - event_type = _get_event_type(request) |
150 |
| - if event_type == _EventType.CLOUDEVENT_STRUCTURED: |
151 |
| - _run_structured_cloudevent(function, request, cloudevent_def) |
152 |
| - elif event_type == _EventType.CLOUDEVENT_BINARY: |
153 |
| - _run_binary_cloudevent(function, request, cloudevent_def) |
| 93 | + function(data, context) |
154 | 94 | else:
|
155 |
| - flask.abort( |
156 |
| - 400, |
157 |
| - description="Function was defined with FUNCTION_SIGNATURE_TYPE=cloudevent " |
158 |
| - " but it did not receive a cloudevent as a request.", |
159 |
| - ) |
| 95 | + # This is a regular CloudEvent |
| 96 | + event_data = request.get_json() |
| 97 | + if not event_data: |
| 98 | + flask.abort(400) |
| 99 | + event_object = _Event(**event_data) |
| 100 | + data = event_object.data |
| 101 | + context = Context(**event_object.context) |
| 102 | + function(data, context) |
160 | 103 |
|
161 | 104 | return "OK"
|
162 | 105 |
|
@@ -263,27 +206,19 @@ def create_app(target=None, source=None, signature_type=None):
|
263 | 206 | app.view_functions["run"] = _http_view_func_wrapper(function, flask.request)
|
264 | 207 | app.view_functions["error"] = lambda: flask.abort(404, description="Not Found")
|
265 | 208 | app.after_request(read_request)
|
266 |
| - elif signature_type == "event" or signature_type == "cloudevent": |
| 209 | + elif signature_type == "event": |
267 | 210 | app.url_map.add(
|
268 | 211 | werkzeug.routing.Rule(
|
269 |
| - "/", defaults={"path": ""}, endpoint=signature_type, methods=["POST"] |
| 212 | + "/", defaults={"path": ""}, endpoint="run", methods=["POST"] |
270 | 213 | )
|
271 | 214 | )
|
272 | 215 | app.url_map.add(
|
273 |
| - werkzeug.routing.Rule( |
274 |
| - "/<path:path>", endpoint=signature_type, methods=["POST"] |
275 |
| - ) |
| 216 | + werkzeug.routing.Rule("/<path:path>", endpoint="run", methods=["POST"]) |
276 | 217 | )
|
277 |
| - |
| 218 | + app.view_functions["run"] = _event_view_func_wrapper(function, flask.request) |
278 | 219 | # Add a dummy endpoint for GET /
|
279 | 220 | app.url_map.add(werkzeug.routing.Rule("/", endpoint="get", methods=["GET"]))
|
280 | 221 | app.view_functions["get"] = lambda: ""
|
281 |
| - |
282 |
| - # Add the view functions |
283 |
| - app.view_functions["event"] = _event_view_func_wrapper(function, flask.request) |
284 |
| - app.view_functions["cloudevent"] = _cloudevent_view_func_wrapper( |
285 |
| - function, flask.request |
286 |
| - ) |
287 | 222 | else:
|
288 | 223 | raise FunctionsFrameworkException(
|
289 | 224 | "Invalid signature type: {signature_type}".format(
|
|
0 commit comments