- 尝试1 - 不支持socket建立TCP连接
- 尝试2 - 没有内嵌
httpx
模块 - 尝试3 - 不支持导入依赖
- 尝试4 - 不需要异步转同步
- 尝试5 - 不支持asyncio建立TCP连接
- 尝试6 - 当前场景 Pyodide 不支持 loadPackage
事情的起因是发现Cloudflare Worker支持Python
了,虽然还是在Beta,但就是想用来尝试点什么。
于是就想简单的检测一下证书过期时间。
尝试1 - 不支持socket建立TCP连接
直接socket一把梭
import socket,ssl
def get_server_certificate(host, port, sni, **kwargs):
context = ssl.SSLContext()
context.verify_mode = ssl.CERT_NONE
context.check_hostname = False
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(1)
with context.wrap_socket(s, server_hostname=sni) as sslSocket:
sslSocket.connect((host, port))
dercert = sslSocket.getpeercert(True)
return dercert
from js import Response
import json
def on_fetch(request):
config = [
{
"host": "www.baidu.com",
"port": 443,
"sni": "www.baidu.com",
"remarks": "百度"
},
]
cert = get_server_certificate(**config[0])
return Response.new(cert.get("notAfter"))
报错
Error: PythonError: Traceback (most recent call last):
File "/lib/python312.zip/pyodide/code.py", line 105, in relaxed_call
return _do_call(func, sig, args, kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/lib/python312.zip/pyodide/code.py", line 69, in _do_call
return func(*bound.args, **bound.kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/session/metadata/index.py", line 25, in on_fetch
cert = get_server_certificate(**config[0])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/session/metadata/index.py", line 9, in get_server_certificate
with context.wrap_socket(s, server_hostname=sni) as sslSocket:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/session/lib/python3.12/site-packages/ssl.py", line 455, in wrap_socket
return self.sslsocket_class._create(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/session/lib/python3.12/site-packages/ssl.py", line 960, in _create
if sock.getsockopt(SOL_SOCKET, SO_TYPE) != SOCK_STREAM:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
OSError: [Errno 50] Protocol not available
看样子并不支持使用Socket发送TCP报文
尝试2 - 没有内嵌httpx
模块
官方文档说Built-in packages, including FastAPI ↗, Langchain ↗, httpx ↗ and more.
那么我们使用httpx
from httpx.backends.base import lookup_backend
async def _get_server_certificate(host, port, sni):
backend = lookup_backend("auto") # auto asyncio trio
ssl_context = SSLConfig(verify=True,http2=True).ssl_context
ssl_context.check_hostname = False
timeout = Timeout(5)
socket = await backend.open_tcp_stream(host, port, ssl_context, timeout)
ssl_object = socket.stream_writer.get_extra_info("ssl_object")
peercert = ssl_object.getpeercert()
# peercert = ssl.DER_cert_to_PEM_cert(peercert)
await socket.close()
return peercert
def get_server_certificate(host, port, sni, **kwargs):
loop = asyncio.get_event_loop()
peercert = loop.run_until_complete(_get_server_certificate(host, port, sni))
return peercert
from js import Response
import json
def on_fetch(request):
config = [
{
"host": "www.baidu.com",
"port": 443,
"sni": "www.baidu.com",
"remarks": "百度"
},
]
cert = get_server_certificate(**config[0])
return Response.new(cert.get("notAfter"))
报错
Error: PythonError: Traceback (most recent call last):
File "/lib/python312.zip/_pyodide/_base.py", line 629, in pyimport_impl
res = __import__(stem, fromlist=fromlist)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/session/metadata/index.py", line 4, in <module>
from httpx.backends.base import lookup_backend
ModuleNotFoundError: No module named 'httpx'
好吧,说好的Built-in packages
呢?
尝试3 - 不支持导入依赖
参考官方文档:
To import a Python package, add the package name to the
requirements.txt
file within the same directory as yourwrangler.toml
configuration file.`
所以,我加上了requirements.txt
,内容为 httpx
[ERROR] Uncaught (in response) Error: internal error
at async loadBundle (pyodide-internal:loadPackage:36:22)
at async Promise.all (index 7)
at async loadPackages (pyodide-internal:loadPackage:75:21)
at async pyodide:python-entrypoint-helper:61:9
at async setupPackages (pyodide:python-entrypoint-helper:59:12)
at async pyodide:python-entrypoint-helper:86:13
at async preparePython (pyodide:python-entrypoint-helper:100:24)
at async pyodide:python-entrypoint-helper:107:81
at async Object.fetch (pyodide:python-entrypoint-helper:107:32)
算了,这依赖不要也罢。
发现httpx
异步依赖的是asyncio
或者trio
,尝试直接使用asyncio
尝试4 - 不需要异步转同步
尝试直接使用asyncio
import asyncio,ssl
async def _get_server_certificate(host, port, sni):
context = ssl.create_default_context()
# context = SSLConfig(verify=False,http2=True).ssl_context
context.check_hostname = False
reader, writer = await asyncio.open_connection(host, port, server_hostname=sni, ssl=context)
ssl_object = writer.get_extra_info('ssl_object')
peercert = ssl_object.getpeercert()
# peercert = ssl.DER_cert_to_PEM_cert(peercert)
await writer.close()
# return pemcert
return peercert
def get_server_certificate(host, port, sni, **kwargs):
loop = asyncio.get_event_loop()
peercert = loop.run_until_complete(_get_server_certificate(host, port, sni))
return peercert
from js import Response
def on_fetch(request):
config = [
{
"host": "www.baidu.com",
"port": 443,
"sni": "www.baidu.com",
"remarks": "百度"
},
]
cert = get_server_certificate(**config[0])
return Response.new(cert.get("notAfter"))
报错
Error: PythonError: Traceback (most recent call last):
File "/lib/python312.zip/pyodide/code.py", line 105, in relaxed_call
return _do_call(func, sig, args, kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/lib/python312.zip/pyodide/code.py", line 69, in _do_call
return func(*bound.args, **bound.kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/session/metadata/index.py", line 37, in on_fetch
return Response.new(cert.get("notAfter"))
^^^^^^^^
AttributeError: 'PyodideTask' object has no attribute 'get'
看了一下,直接异步就行了,我这个属于脱裤子放屁,多此一举
尝试5 - 不支持asyncio建立TCP连接
尝试直接使用asyncio
,返回异步结果
import asyncio, ssl
async def get_server_certificate(host, port, sni, **kwargs):
context = ssl.create_default_context()
# context = SSLConfig(verify=False,http2=True).ssl_context
context.check_hostname = False
reader, writer = await asyncio.open_connection(host, port, server_hostname=sni, ssl=context)
ssl_object = writer.get_extra_info('ssl_object')
peercert = ssl_object.getpeercert()
# peercert = ssl.DER_cert_to_PEM_cert(peercert)
await writer.close()
# return pemcert
return peercert
from js import Response
async def on_fetch(request):
config = [
{
"host": "www.baidu.com",
"port": 443,
"sni": "www.baidu.com",
"remarks": "百度"
},
]
cert = await get_server_certificate(**config[0])
return Response.new(cert.get("notAfter"))
报错
Error: PythonError: Traceback (most recent call last):
File "/session/metadata/index.py", line 27, in on_fetch
cert = await get_server_certificate(**config[0])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/session/metadata/index.py", line 8, in get_server_certificate
reader, writer = await asyncio.open_connection(host, port, server_hostname=sni, ssl=context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/lib/python312.zip/asyncio/streams.py", line 48, in open_connection
transport, _ = await loop.create_connection(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/lib/python312.zip/asyncio/events.py", line 312, in create_connection
raise NotImplementedError
NotImplementedError
底层asyncio
根本没有实现
尝试6 - 当前场景 Pyodide 不支持 loadPackage
查看Pyodide的说明,尝试导入httpx
或其它aiohttp
模块,后者是Pyodide
和Cloudflare
都声称是Built-in的
async def _get_server_certificate(host, port, sni, **kwargs):
import pyodide_js
await pyodide_js.loadPackage('httpx')
# await pyodide_js.loadPackagesFromImports(pkg);
httpx = pyodide_js.pyimport("httpx");
from httpx.backends.base import lookup_backend
backend = lookup_backend("auto") # auto asyncio trio
ssl_context = SSLConfig(verify=True,http2=True).ssl_context
ssl_context.check_hostname = False
timeout = Timeout(5)
socket = await backend.open_tcp_stream(host, port, ssl_context, timeout)
ssl_object = socket.stream_writer.get_extra_info("ssl_object")
peercert = ssl_object.getpeercert()
# peercert = ssl.DER_cert_to_PEM_cert(peercert)
await socket.close()
return peercert
from js import Response
import json
async def on_fetch(request):
config = [
{
"host": "www.baidu.com",
"port": 443,
"sni": "www.baidu.com",
"remarks": "百度"
},
]
cert = await _get_server_certificate(**config[0])
return Response.new(cert.get("notAfter"))
报错
Error: PythonError: Traceback (most recent call last):
File "/session/metadata/index.py", line 34, in on_fetch
cert = await _get_server_certificate(**config[0])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/session/metadata/index.py", line 5, in _get_server_certificate
await pyodide_js.loadPackage('httpx')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "pyodide-internal:generated/pyodide.asm", line 20, in JsvFunction_CallBound
File "pyodide-internal:setupPackages", line 130, in Object.disabledLoadPackage [as loadPackage]
pyodide.ffi.JsException: Error: pyodide.loadPackage is disabled because packages are encoded in the binary
没救了,等死吧