vercel-cli 41.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of vercel-cli might be problematic. Click here for more details.

Files changed (99) hide show
  1. vercel_cli/vendor/LICENSE +202 -0
  2. vercel_cli/vendor/README.md +63 -0
  3. vercel_cli/vendor/dist/VERCEL_DIR_README.txt +11 -0
  4. vercel_cli/vendor/dist/builder-worker.js +62 -0
  5. vercel_cli/vendor/dist/get-latest-worker.js +272 -0
  6. vercel_cli/vendor/dist/index.js +172693 -0
  7. vercel_cli/vendor/dist/vc.js +11 -0
  8. vercel_cli/vendor/node_modules/.package-lock.json +18 -0
  9. vercel_cli/vendor/node_modules/@vercel/build-utils/CHANGELOG.md +488 -0
  10. vercel_cli/vendor/node_modules/@vercel/build-utils/LICENSE +202 -0
  11. vercel_cli/vendor/node_modules/@vercel/build-utils/build.mjs +3 -0
  12. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/clone-env.d.ts +10 -0
  13. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/clone-env.js +43 -0
  14. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/debug.d.ts +1 -0
  15. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/debug.js +31 -0
  16. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/default-cache-path-glob.d.ts +1 -0
  17. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/default-cache-path-glob.js +28 -0
  18. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/edge-function.d.ts +41 -0
  19. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/edge-function.js +40 -0
  20. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/errors.d.ts +39 -0
  21. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/errors.js +95 -0
  22. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/file-blob.d.ts +23 -0
  23. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/file-blob.js +67 -0
  24. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/file-fs-ref.d.ts +27 -0
  25. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/file-fs-ref.js +113 -0
  26. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/file-ref.d.ts +38 -0
  27. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/file-ref.js +147 -0
  28. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/download.d.ts +9 -0
  29. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/download.js +136 -0
  30. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/get-writable-directory.d.ts +1 -0
  31. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/get-writable-directory.js +32 -0
  32. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/glob.d.ts +10 -0
  33. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/glob.js +111 -0
  34. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/node-version.d.ts +9 -0
  35. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/node-version.js +180 -0
  36. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/normalize-path.d.ts +4 -0
  37. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/normalize-path.js +31 -0
  38. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/read-config-file.d.ts +1 -0
  39. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/read-config-file.js +76 -0
  40. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/rename.d.ts +11 -0
  41. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/rename.js +30 -0
  42. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/run-user-scripts.d.ts +206 -0
  43. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/run-user-scripts.js +944 -0
  44. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/stream-to-buffer.d.ts +3 -0
  45. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/fs/stream-to-buffer.js +87 -0
  46. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/get-ignore-filter.d.ts +1 -0
  47. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/get-ignore-filter.js +90 -0
  48. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/get-installed-package-version.d.ts +1 -0
  49. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/get-installed-package-version.js +53 -0
  50. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/get-platform-env.d.ts +5 -0
  51. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/get-platform-env.js +45 -0
  52. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/get-prefixed-env-vars.d.ts +14 -0
  53. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/get-prefixed-env-vars.js +51 -0
  54. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/hard-link-dir.d.ts +1 -0
  55. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/hard-link-dir.js +104 -0
  56. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/index.d.ts +33 -0
  57. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/index.js +24390 -0
  58. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/lambda.d.ts +81 -0
  59. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/lambda.js +231 -0
  60. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/nodejs-lambda.d.ts +16 -0
  61. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/nodejs-lambda.js +44 -0
  62. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/os.d.ts +3 -0
  63. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/os.js +62 -0
  64. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/prerender.d.ts +37 -0
  65. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/prerender.js +169 -0
  66. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/schemas.d.ts +60 -0
  67. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/schemas.js +87 -0
  68. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/should-serve.d.ts +2 -0
  69. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/should-serve.js +47 -0
  70. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/trace/constants.d.ts +2 -0
  71. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/trace/constants.js +31 -0
  72. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/trace/index.d.ts +3 -0
  73. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/trace/index.js +33 -0
  74. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/trace/trace.d.ts +37 -0
  75. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/trace/trace.js +92 -0
  76. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/types.d.ts +503 -0
  77. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/types.js +51 -0
  78. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/validate-npmrc.d.ts +12 -0
  79. vercel_cli/vendor/node_modules/@vercel/build-utils/dist/validate-npmrc.js +41 -0
  80. vercel_cli/vendor/node_modules/@vercel/build-utils/file-blob.js +1 -0
  81. vercel_cli/vendor/node_modules/@vercel/build-utils/file-fs-ref.js +1 -0
  82. vercel_cli/vendor/node_modules/@vercel/build-utils/file-ref.js +1 -0
  83. vercel_cli/vendor/node_modules/@vercel/build-utils/fs/download.js +1 -0
  84. vercel_cli/vendor/node_modules/@vercel/build-utils/fs/get-writable-directory.js +1 -0
  85. vercel_cli/vendor/node_modules/@vercel/build-utils/fs/glob.js +1 -0
  86. vercel_cli/vendor/node_modules/@vercel/build-utils/fs/rename.js +1 -0
  87. vercel_cli/vendor/node_modules/@vercel/build-utils/fs/run-user-scripts.js +1 -0
  88. vercel_cli/vendor/node_modules/@vercel/build-utils/fs/stream-to-buffer.js +1 -0
  89. vercel_cli/vendor/node_modules/@vercel/build-utils/lambda.js +1 -0
  90. vercel_cli/vendor/node_modules/@vercel/build-utils/package.json +60 -0
  91. vercel_cli/vendor/node_modules/@vercel/python/LICENSE +202 -0
  92. vercel_cli/vendor/node_modules/@vercel/python/dist/index.js +3132 -0
  93. vercel_cli/vendor/node_modules/@vercel/python/package.json +36 -0
  94. vercel_cli/vendor/node_modules/@vercel/python/vc_init.py +681 -0
  95. vercel_cli/vendor/package.json +40 -0
  96. vercel_cli-41.1.0.dist-info/METADATA +188 -0
  97. vercel_cli-41.1.0.dist-info/RECORD +99 -0
  98. vercel_cli-41.1.0.dist-info/WHEEL +4 -0
  99. vercel_cli-41.1.0.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,681 @@
1
+ import sys
2
+ import base64
3
+ import json
4
+ import inspect
5
+ from importlib import util
6
+ from http.server import BaseHTTPRequestHandler
7
+ import socket
8
+ import os
9
+
10
+ # Import relative path https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly
11
+ __vc_spec = util.spec_from_file_location("__VC_HANDLER_MODULE_NAME", "./__VC_HANDLER_ENTRYPOINT")
12
+ __vc_module = util.module_from_spec(__vc_spec)
13
+ sys.modules["__VC_HANDLER_MODULE_NAME"] = __vc_module
14
+ __vc_spec.loader.exec_module(__vc_module)
15
+ __vc_variables = dir(__vc_module)
16
+
17
+ _use_legacy_asyncio = sys.version_info < (3, 10)
18
+
19
+ def format_headers(headers, decode=False):
20
+ keyToList = {}
21
+ for key, value in headers.items():
22
+ if decode and 'decode' in dir(key) and 'decode' in dir(value):
23
+ key = key.decode()
24
+ value = value.decode()
25
+ if key not in keyToList:
26
+ keyToList[key] = []
27
+ keyToList[key].append(value)
28
+ return keyToList
29
+
30
+ if 'VERCEL_IPC_PATH' in os.environ:
31
+ from http.server import ThreadingHTTPServer
32
+ import http
33
+ import time
34
+ import contextvars
35
+ import functools
36
+ import builtins
37
+ import logging
38
+
39
+ start_time = time.time()
40
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
41
+ sock.connect(os.getenv("VERCEL_IPC_PATH", ""))
42
+
43
+ send_message = lambda message: sock.sendall((json.dumps(message) + '\0').encode())
44
+ storage = contextvars.ContextVar('storage', default=None)
45
+
46
+ # Override urlopen from urllib3 (& requests) to send Request Metrics
47
+ try:
48
+ import urllib3
49
+ from urllib.parse import urlparse
50
+
51
+ def timed_request(func):
52
+ fetchId = 0
53
+ @functools.wraps(func)
54
+ def wrapper(self, method, url, *args, **kwargs):
55
+ nonlocal fetchId
56
+ fetchId += 1
57
+ start_time = int(time.time() * 1000)
58
+ result = func(self, method, url, *args, **kwargs)
59
+ elapsed_time = int(time.time() * 1000) - start_time
60
+ parsed_url = urlparse(url)
61
+ context = storage.get()
62
+ if context is not None:
63
+ send_message({
64
+ "type": "metric",
65
+ "payload": {
66
+ "context": {
67
+ "invocationId": context['invocationId'],
68
+ "requestId": context['requestId'],
69
+ },
70
+ "type": "fetch-metric",
71
+ "payload": {
72
+ "pathname": parsed_url.path,
73
+ "search": parsed_url.query,
74
+ "start": start_time,
75
+ "duration": elapsed_time,
76
+ "host": parsed_url.hostname or self.host,
77
+ "statusCode": result.status,
78
+ "method": method,
79
+ "id": fetchId
80
+ }
81
+ }
82
+ })
83
+ return result
84
+ return wrapper
85
+ urllib3.connectionpool.HTTPConnectionPool.urlopen = timed_request(urllib3.connectionpool.HTTPConnectionPool.urlopen)
86
+ except:
87
+ pass
88
+
89
+ # Override sys.stdout and sys.stderr to map logs to the correct request
90
+ class StreamWrapper:
91
+ def __init__(self, stream, stream_name):
92
+ self.stream = stream
93
+ self.stream_name = stream_name
94
+
95
+ def write(self, message):
96
+ context = storage.get()
97
+ if context is not None:
98
+ send_message({
99
+ "type": "log",
100
+ "payload": {
101
+ "context": {
102
+ "invocationId": context['invocationId'],
103
+ "requestId": context['requestId'],
104
+ },
105
+ "message": base64.b64encode(message.encode()).decode(),
106
+ "stream": self.stream_name,
107
+ }
108
+ })
109
+ else:
110
+ self.stream.write(message)
111
+
112
+ def __getattr__(self, name):
113
+ return getattr(self.stream, name)
114
+
115
+ sys.stdout = StreamWrapper(sys.stdout, "stdout")
116
+ sys.stderr = StreamWrapper(sys.stderr, "stderr")
117
+
118
+ # Override the global print to log to stdout
119
+ def print_wrapper(func):
120
+ @functools.wraps(func)
121
+ def wrapper(*args, **kwargs):
122
+ sys.stdout.write(' '.join(map(str, args)) + '\n')
123
+ return wrapper
124
+ builtins.print = print_wrapper(builtins.print)
125
+
126
+ # Override logging to maps logs to the correct request
127
+ def logging_wrapper(func, level="info"):
128
+ @functools.wraps(func)
129
+ def wrapper(*args, **kwargs):
130
+ context = storage.get()
131
+ if context is not None:
132
+ send_message({
133
+ "type": "log",
134
+ "payload": {
135
+ "context": {
136
+ "invocationId": context['invocationId'],
137
+ "requestId": context['requestId'],
138
+ },
139
+ "message": base64.b64encode(f"{args[0]}".encode()).decode(),
140
+ "level": level,
141
+ }
142
+ })
143
+ else:
144
+ func(*args, **kwargs)
145
+ return wrapper
146
+
147
+ logging.basicConfig(level=logging.INFO)
148
+ logging.debug = logging_wrapper(logging.debug)
149
+ logging.info = logging_wrapper(logging.info)
150
+ logging.warning = logging_wrapper(logging.warning, "warn")
151
+ logging.error = logging_wrapper(logging.error, "error")
152
+ logging.critical = logging_wrapper(logging.critical, "error")
153
+
154
+ class BaseHandler(BaseHTTPRequestHandler):
155
+ # Re-implementation of BaseHTTPRequestHandler's log_message method to
156
+ # log to stdout instead of stderr.
157
+ def log_message(self, format, *args):
158
+ message = format % args
159
+ sys.stdout.write("%s - - [%s] %s\n" %
160
+ (self.address_string(),
161
+ self.log_date_time_string(),
162
+ message.translate(self._control_char_table)))
163
+
164
+ # Re-implementation of BaseHTTPRequestHandler's handle_one_request method
165
+ # to send the end message after the response is fully sent.
166
+ def handle_one_request(self):
167
+ self.raw_requestline = self.rfile.readline(65537)
168
+ if not self.raw_requestline:
169
+ self.close_connection = True
170
+ return
171
+ if not self.parse_request():
172
+ return
173
+
174
+ invocationId = self.headers.get('x-vercel-internal-invocation-id')
175
+ requestId = int(self.headers.get('x-vercel-internal-request-id'))
176
+ del self.headers['x-vercel-internal-invocation-id']
177
+ del self.headers['x-vercel-internal-request-id']
178
+ del self.headers['x-vercel-internal-span-id']
179
+ del self.headers['x-vercel-internal-trace-id']
180
+
181
+ send_message({
182
+ "type": "handler-started",
183
+ "payload": {
184
+ "handlerStartedAt": int(time.time() * 1000),
185
+ "context": {
186
+ "invocationId": invocationId,
187
+ "requestId": requestId,
188
+ }
189
+ }
190
+ })
191
+
192
+ token = storage.set({
193
+ "invocationId": invocationId,
194
+ "requestId": requestId,
195
+ })
196
+
197
+ try:
198
+ self.handle_request()
199
+ finally:
200
+ storage.reset(token)
201
+ send_message({
202
+ "type": "end",
203
+ "payload": {
204
+ "context": {
205
+ "invocationId": invocationId,
206
+ "requestId": requestId,
207
+ }
208
+ }
209
+ })
210
+
211
+ if 'handler' in __vc_variables or 'Handler' in __vc_variables:
212
+ base = __vc_module.handler if ('handler' in __vc_variables) else __vc_module.Handler
213
+ if not issubclass(base, BaseHTTPRequestHandler):
214
+ print('Handler must inherit from BaseHTTPRequestHandler')
215
+ print('See the docs: https://vercel.com/docs/functions/serverless-functions/runtimes/python')
216
+ exit(1)
217
+
218
+ class Handler(BaseHandler, base):
219
+ def handle_request(self):
220
+ mname = 'do_' + self.command
221
+ if not hasattr(self, mname):
222
+ self.send_error(
223
+ http.HTTPStatus.NOT_IMPLEMENTED,
224
+ "Unsupported method (%r)" % self.command)
225
+ return
226
+ method = getattr(self, mname)
227
+ method()
228
+ self.wfile.flush()
229
+ elif 'app' in __vc_variables:
230
+ if (
231
+ not inspect.iscoroutinefunction(__vc_module.app) and
232
+ not inspect.iscoroutinefunction(__vc_module.app.__call__)
233
+ ):
234
+ from io import BytesIO
235
+
236
+ string_types = (str,)
237
+ app = __vc_module.app
238
+
239
+ def wsgi_encoding_dance(s, charset="utf-8", errors="replace"):
240
+ if isinstance(s, str):
241
+ s = s.encode(charset)
242
+ return s.decode("latin1", errors)
243
+
244
+ class Handler(BaseHandler):
245
+ def handle_request(self):
246
+ # Prepare WSGI environment
247
+ if '?' in self.path:
248
+ path, query = self.path.split('?', 1)
249
+ else:
250
+ path, query = self.path, ''
251
+ content_length = int(self.headers.get('Content-Length', 0))
252
+ env = {
253
+ 'CONTENT_LENGTH': str(content_length),
254
+ 'CONTENT_TYPE': self.headers.get('content-type', ''),
255
+ 'PATH_INFO': path,
256
+ 'QUERY_STRING': query,
257
+ 'REMOTE_ADDR': self.headers.get(
258
+ 'x-forwarded-for', self.headers.get(
259
+ 'x-real-ip')),
260
+ 'REQUEST_METHOD': self.command,
261
+ 'SERVER_NAME': self.headers.get('host', 'lambda'),
262
+ 'SERVER_PORT': self.headers.get('x-forwarded-port', '80'),
263
+ 'SERVER_PROTOCOL': 'HTTP/1.1',
264
+ 'wsgi.errors': sys.stderr,
265
+ 'wsgi.input': BytesIO(self.rfile.read(content_length)),
266
+ 'wsgi.multiprocess': False,
267
+ 'wsgi.multithread': False,
268
+ 'wsgi.run_once': False,
269
+ 'wsgi.url_scheme': self.headers.get('x-forwarded-proto', 'http'),
270
+ 'wsgi.version': (1, 0),
271
+ }
272
+ for key, value in env.items():
273
+ if isinstance(value, string_types):
274
+ env[key] = wsgi_encoding_dance(value)
275
+ for k, v in self.headers.items():
276
+ env['HTTP_' + k.replace('-', '_').upper()] = v
277
+ # Response body
278
+ body = BytesIO()
279
+
280
+ def start_response(status, headers, exc_info=None):
281
+ self.send_response(int(status.split(' ')[0]))
282
+ for name, value in headers:
283
+ self.send_header(name, value)
284
+ self.end_headers()
285
+ return body.write
286
+
287
+ # Call the application
288
+ response = app(env, start_response)
289
+ try:
290
+ for data in response:
291
+ if data:
292
+ body.write(data)
293
+ finally:
294
+ if hasattr(response, 'close'):
295
+ response.close()
296
+ body = body.getvalue()
297
+ self.wfile.write(body)
298
+ self.wfile.flush()
299
+ else:
300
+ from urllib.parse import urlparse
301
+ from io import BytesIO
302
+ import asyncio
303
+
304
+ app = __vc_module.app
305
+
306
+ class Handler(BaseHandler):
307
+ def handle_request(self):
308
+ # Prepare ASGI scope
309
+ url = urlparse(self.path)
310
+ headers_encoded = []
311
+ for k, v in self.headers.items():
312
+ # Cope with repeated headers in the encoding.
313
+ if isinstance(v, list):
314
+ headers_encoded.append([k.lower().encode(), [i.encode() for i in v]])
315
+ else:
316
+ headers_encoded.append([k.lower().encode(), v.encode()])
317
+ scope = {
318
+ 'server': (self.headers.get('host', 'lambda'), self.headers.get('x-forwarded-port', 80)),
319
+ 'client': (self.headers.get(
320
+ 'x-forwarded-for', self.headers.get(
321
+ 'x-real-ip')), 0),
322
+ 'scheme': self.headers.get('x-forwarded-proto', 'http'),
323
+ 'root_path': '',
324
+ 'query_string': url.query.encode(),
325
+ 'headers': headers_encoded,
326
+ 'type': 'http',
327
+ 'http_version': '1.1',
328
+ 'method': self.command,
329
+ 'path': url.path,
330
+ 'raw_path': url.path.encode(),
331
+ }
332
+
333
+ if 'content-length' in self.headers:
334
+ content_length = int(self.headers['content-length'])
335
+ body = self.rfile.read(content_length)
336
+ else:
337
+ body = b''
338
+
339
+ if _use_legacy_asyncio:
340
+ loop = asyncio.new_event_loop()
341
+ app_queue = asyncio.Queue(loop=loop)
342
+ else:
343
+ app_queue = asyncio.Queue()
344
+ app_queue.put_nowait({'type': 'http.request', 'body': body, 'more_body': False})
345
+
346
+ # Prepare ASGI receive function
347
+ async def receive():
348
+ message = await app_queue.get()
349
+ return message
350
+
351
+ # Prepare ASGI send function
352
+ response_started = False
353
+ async def send(event):
354
+ nonlocal response_started
355
+ if event['type'] == 'http.response.start':
356
+ self.send_response(event['status'])
357
+ if 'headers' in event:
358
+ for name, value in event['headers']:
359
+ self.send_header(name.decode(), value.decode())
360
+ self.end_headers()
361
+ response_started = True
362
+ elif event['type'] == 'http.response.body':
363
+ self.wfile.write(event['body'])
364
+ if not event.get('more_body', False):
365
+ self.wfile.flush()
366
+
367
+ # Run the ASGI application
368
+ asgi_instance = app(scope, receive, send)
369
+ if _use_legacy_asyncio:
370
+ asgi_task = loop.create_task(asgi_instance)
371
+ loop.run_until_complete(asgi_task)
372
+ else:
373
+ asyncio.run(asgi_instance)
374
+
375
+ if 'Handler' in locals():
376
+ server = ThreadingHTTPServer(('127.0.0.1', 0), Handler)
377
+ send_message({
378
+ "type": "server-started",
379
+ "payload": {
380
+ "initDuration": int((time.time() - start_time) * 1000),
381
+ "httpPort": server.server_address[1],
382
+ }
383
+ })
384
+ server.serve_forever()
385
+
386
+ print('Missing variable `handler` or `app` in file "__VC_HANDLER_ENTRYPOINT".')
387
+ print('See the docs: https://vercel.com/docs/functions/serverless-functions/runtimes/python')
388
+ exit(1)
389
+
390
+ if 'handler' in __vc_variables or 'Handler' in __vc_variables:
391
+ base = __vc_module.handler if ('handler' in __vc_variables) else __vc_module.Handler
392
+ if not issubclass(base, BaseHTTPRequestHandler):
393
+ print('Handler must inherit from BaseHTTPRequestHandler')
394
+ print('See the docs: https://vercel.com/docs/functions/serverless-functions/runtimes/python')
395
+ exit(1)
396
+
397
+ print('using HTTP Handler')
398
+ from http.server import HTTPServer
399
+ import http
400
+ import _thread
401
+
402
+ server = HTTPServer(('127.0.0.1', 0), base)
403
+ port = server.server_address[1]
404
+
405
+ def vc_handler(event, context):
406
+ _thread.start_new_thread(server.handle_request, ())
407
+
408
+ payload = json.loads(event['body'])
409
+ path = payload['path']
410
+ headers = payload['headers']
411
+ method = payload['method']
412
+ encoding = payload.get('encoding')
413
+ body = payload.get('body')
414
+
415
+ if (
416
+ (body is not None and len(body) > 0) and
417
+ (encoding is not None and encoding == 'base64')
418
+ ):
419
+ body = base64.b64decode(body)
420
+
421
+ request_body = body.encode('utf-8') if isinstance(body, str) else body
422
+ conn = http.client.HTTPConnection('127.0.0.1', port)
423
+ try:
424
+ conn.request(method, path, headers=headers, body=request_body)
425
+ except (http.client.HTTPException, socket.error) as ex:
426
+ print ("Request Error: %s" % ex)
427
+ res = conn.getresponse()
428
+
429
+ return_dict = {
430
+ 'statusCode': res.status,
431
+ 'headers': format_headers(res.headers),
432
+ }
433
+
434
+ data = res.read()
435
+
436
+ try:
437
+ return_dict['body'] = data.decode('utf-8')
438
+ except UnicodeDecodeError:
439
+ return_dict['body'] = base64.b64encode(data).decode('utf-8')
440
+ return_dict['encoding'] = 'base64'
441
+
442
+ return return_dict
443
+
444
+ elif 'app' in __vc_variables:
445
+ if (
446
+ not inspect.iscoroutinefunction(__vc_module.app) and
447
+ not inspect.iscoroutinefunction(__vc_module.app.__call__)
448
+ ):
449
+ print('using Web Server Gateway Interface (WSGI)')
450
+ from io import BytesIO
451
+ from urllib.parse import urlparse
452
+ from werkzeug.datastructures import Headers
453
+ from werkzeug.wrappers import Response
454
+
455
+ string_types = (str,)
456
+
457
+ def to_bytes(x, charset=sys.getdefaultencoding(), errors="strict"):
458
+ if x is None:
459
+ return None
460
+ if isinstance(x, (bytes, bytearray, memoryview)):
461
+ return bytes(x)
462
+ if isinstance(x, str):
463
+ return x.encode(charset, errors)
464
+ raise TypeError("Expected bytes")
465
+
466
+ def wsgi_encoding_dance(s, charset="utf-8", errors="replace"):
467
+ if isinstance(s, str):
468
+ s = s.encode(charset)
469
+ return s.decode("latin1", errors)
470
+
471
+ def vc_handler(event, context):
472
+ payload = json.loads(event['body'])
473
+
474
+ headers = Headers(payload.get('headers', {}))
475
+
476
+ body = payload.get('body', '')
477
+ if body != '':
478
+ if payload.get('encoding') == 'base64':
479
+ body = base64.b64decode(body)
480
+ if isinstance(body, string_types):
481
+ body = to_bytes(body, charset='utf-8')
482
+
483
+ url = urlparse(payload['path'])
484
+ query = url.query
485
+ path = url.path
486
+
487
+ environ = {
488
+ 'CONTENT_LENGTH': str(len(body)),
489
+ 'CONTENT_TYPE': headers.get('content-type', ''),
490
+ 'PATH_INFO': path,
491
+ 'QUERY_STRING': query,
492
+ 'REMOTE_ADDR': headers.get(
493
+ 'x-forwarded-for', headers.get(
494
+ 'x-real-ip', payload.get(
495
+ 'true-client-ip', ''))),
496
+ 'REQUEST_METHOD': payload['method'],
497
+ 'SERVER_NAME': headers.get('host', 'lambda'),
498
+ 'SERVER_PORT': headers.get('x-forwarded-port', '80'),
499
+ 'SERVER_PROTOCOL': 'HTTP/1.1',
500
+ 'event': event,
501
+ 'context': context,
502
+ 'wsgi.errors': sys.stderr,
503
+ 'wsgi.input': BytesIO(body),
504
+ 'wsgi.multiprocess': False,
505
+ 'wsgi.multithread': False,
506
+ 'wsgi.run_once': False,
507
+ 'wsgi.url_scheme': headers.get('x-forwarded-proto', 'http'),
508
+ 'wsgi.version': (1, 0),
509
+ }
510
+
511
+ for key, value in environ.items():
512
+ if isinstance(value, string_types):
513
+ environ[key] = wsgi_encoding_dance(value)
514
+
515
+ for key, value in headers.items():
516
+ key = 'HTTP_' + key.upper().replace('-', '_')
517
+ if key not in ('HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH'):
518
+ environ[key] = value
519
+
520
+ response = Response.from_app(__vc_module.app, environ)
521
+
522
+ return_dict = {
523
+ 'statusCode': response.status_code,
524
+ 'headers': format_headers(response.headers)
525
+ }
526
+
527
+ if response.data:
528
+ return_dict['body'] = base64.b64encode(response.data).decode('utf-8')
529
+ return_dict['encoding'] = 'base64'
530
+
531
+ return return_dict
532
+ else:
533
+ print('using Asynchronous Server Gateway Interface (ASGI)')
534
+ # Originally authored by Jordan Eremieff and included under MIT license:
535
+ # https://github.com/erm/mangum/blob/b4d21c8f5e304a3e17b88bc9fa345106acc50ad7/mangum/__init__.py
536
+ # https://github.com/erm/mangum/blob/b4d21c8f5e304a3e17b88bc9fa345106acc50ad7/LICENSE
537
+ import asyncio
538
+ import enum
539
+ from urllib.parse import urlparse
540
+ from werkzeug.datastructures import Headers
541
+
542
+
543
+ class ASGICycleState(enum.Enum):
544
+ REQUEST = enum.auto()
545
+ RESPONSE = enum.auto()
546
+
547
+
548
+ class ASGICycle:
549
+ def __init__(self, scope):
550
+ self.scope = scope
551
+ self.body = b''
552
+ self.state = ASGICycleState.REQUEST
553
+ self.app_queue = None
554
+ self.response = {}
555
+
556
+ def __call__(self, app, body):
557
+ """
558
+ Receives the application and any body included in the request, then builds the
559
+ ASGI instance using the connection scope.
560
+ Runs until the response is completely read from the application.
561
+ """
562
+ if _use_legacy_asyncio:
563
+ loop = asyncio.new_event_loop()
564
+ self.app_queue = asyncio.Queue(loop=loop)
565
+ else:
566
+ self.app_queue = asyncio.Queue()
567
+ self.put_message({'type': 'http.request', 'body': body, 'more_body': False})
568
+
569
+ asgi_instance = app(self.scope, self.receive, self.send)
570
+
571
+ if _use_legacy_asyncio:
572
+ asgi_task = loop.create_task(asgi_instance)
573
+ loop.run_until_complete(asgi_task)
574
+ else:
575
+ asyncio.run(self.run_asgi_instance(asgi_instance))
576
+ return self.response
577
+
578
+ async def run_asgi_instance(self, asgi_instance):
579
+ await asgi_instance
580
+
581
+ def put_message(self, message):
582
+ self.app_queue.put_nowait(message)
583
+
584
+ async def receive(self):
585
+ """
586
+ Awaited by the application to receive messages in the queue.
587
+ """
588
+ message = await self.app_queue.get()
589
+ return message
590
+
591
+ async def send(self, message):
592
+ """
593
+ Awaited by the application to send messages to the current cycle instance.
594
+ """
595
+ message_type = message['type']
596
+
597
+ if self.state is ASGICycleState.REQUEST:
598
+ if message_type != 'http.response.start':
599
+ raise RuntimeError(
600
+ f"Expected 'http.response.start', received: {message_type}"
601
+ )
602
+
603
+ status_code = message['status']
604
+ headers = Headers(message.get('headers', []))
605
+
606
+ self.on_request(headers, status_code)
607
+ self.state = ASGICycleState.RESPONSE
608
+
609
+ elif self.state is ASGICycleState.RESPONSE:
610
+ if message_type != 'http.response.body':
611
+ raise RuntimeError(
612
+ f"Expected 'http.response.body', received: {message_type}"
613
+ )
614
+
615
+ body = message.get('body', b'')
616
+ more_body = message.get('more_body', False)
617
+
618
+ # The body must be completely read before returning the response.
619
+ self.body += body
620
+
621
+ if not more_body:
622
+ self.on_response()
623
+ self.put_message({'type': 'http.disconnect'})
624
+
625
+ def on_request(self, headers, status_code):
626
+ self.response['statusCode'] = status_code
627
+ self.response['headers'] = format_headers(headers, decode=True)
628
+
629
+ def on_response(self):
630
+ if self.body:
631
+ self.response['body'] = base64.b64encode(self.body).decode('utf-8')
632
+ self.response['encoding'] = 'base64'
633
+
634
+ def vc_handler(event, context):
635
+ payload = json.loads(event['body'])
636
+
637
+ headers = payload.get('headers', {})
638
+
639
+ body = payload.get('body', b'')
640
+ if payload.get('encoding') == 'base64':
641
+ body = base64.b64decode(body)
642
+ elif not isinstance(body, bytes):
643
+ body = body.encode()
644
+
645
+ url = urlparse(payload['path'])
646
+ query = url.query.encode()
647
+ path = url.path
648
+
649
+ headers_encoded = []
650
+ for k, v in headers.items():
651
+ # Cope with repeated headers in the encoding.
652
+ if isinstance(v, list):
653
+ headers_encoded.append([k.lower().encode(), [i.encode() for i in v]])
654
+ else:
655
+ headers_encoded.append([k.lower().encode(), v.encode()])
656
+
657
+ scope = {
658
+ 'server': (headers.get('host', 'lambda'), headers.get('x-forwarded-port', 80)),
659
+ 'client': (headers.get(
660
+ 'x-forwarded-for', headers.get(
661
+ 'x-real-ip', payload.get(
662
+ 'true-client-ip', ''))), 0),
663
+ 'scheme': headers.get('x-forwarded-proto', 'http'),
664
+ 'root_path': '',
665
+ 'query_string': query,
666
+ 'headers': headers_encoded,
667
+ 'type': 'http',
668
+ 'http_version': '1.1',
669
+ 'method': payload['method'],
670
+ 'path': path,
671
+ 'raw_path': path.encode(),
672
+ }
673
+
674
+ asgi_cycle = ASGICycle(scope)
675
+ response = asgi_cycle(__vc_module.app, body)
676
+ return response
677
+
678
+ else:
679
+ print('Missing variable `handler` or `app` in file "__VC_HANDLER_ENTRYPOINT".')
680
+ print('See the docs: https://vercel.com/docs/functions/serverless-functions/runtimes/python')
681
+ exit(1)