|
1 | 1 | import asyncio, socket, urllib.parse, time, re, base64, hmac, struct, hashlib, io, os
|
2 |
| - |
| 2 | +from . import admin |
3 | 3 | HTTP_LINE = re.compile('([^ ]+) +(.+?) +(HTTP/[^ ]+)$')
|
4 | 4 | packstr = lambda s, n=1: len(s).to_bytes(n, 'big') + s
|
5 | 5 |
|
@@ -404,6 +404,38 @@ async def connect(self, reader_remote, writer_remote, rauth, host_name, port, my
|
404 | 404 | class H3(H2):
|
405 | 405 | pass
|
406 | 406 |
|
| 407 | + |
| 408 | +class HTTPAdmin(HTTP): |
| 409 | + async def accept(self, reader, user, writer, **kw): |
| 410 | + lines = await reader.read_until(b'\r\n\r\n') |
| 411 | + headers = lines[:-4].decode().split('\r\n') |
| 412 | + method, path, ver = HTTP_LINE.match(headers.pop(0)).groups() |
| 413 | + lines = '\r\n'.join(i for i in headers if not i.startswith('Proxy-')) |
| 414 | + headers = dict(i.split(': ', 1) for i in headers if ': ' in i) |
| 415 | + async def reply(code, message, body=None, wait=False): |
| 416 | + writer.write(message) |
| 417 | + if body: |
| 418 | + writer.write(body) |
| 419 | + if wait: |
| 420 | + await writer.drain() |
| 421 | + |
| 422 | + content_length = int(headers.get('Content-Length','0')) |
| 423 | + content = '' |
| 424 | + if content_length > 0: |
| 425 | + content = await reader.read_n(content_length) |
| 426 | + |
| 427 | + url = urllib.parse.urlparse(path) |
| 428 | + if url.hostname is not None: |
| 429 | + raise Exception(f'HTTP Admin Unsupported hostname') |
| 430 | + if method in ["GET", "POST", "PUT", "PATCH", "DELETE"]: |
| 431 | + for path, handler in admin.httpget.items(): |
| 432 | + if path == url.path: |
| 433 | + await handler(reply=reply, ver=ver, method=method, headers=headers, lines=lines, content=content) |
| 434 | + raise Exception('Connection closed') |
| 435 | + raise Exception(f'404 {method} {url.path}') |
| 436 | + raise Exception(f'405 {method} not allowed') |
| 437 | + |
| 438 | + |
407 | 439 | class SSH(BaseProtocol):
|
408 | 440 | async def connect(self, reader_remote, writer_remote, rauth, host_name, port, myhost, **kw):
|
409 | 441 | pass
|
@@ -567,7 +599,7 @@ def udp_accept(protos, data, **kw):
|
567 | 599 | return (proto,) + ret
|
568 | 600 | raise Exception(f'Unsupported protocol {data[:10]}')
|
569 | 601 |
|
570 |
| -MAPPINGS = dict(direct=Direct, http=HTTP, httponly=HTTPOnly, ssh=SSH, socks5=Socks5, socks4=Socks4, socks=Socks5, ss=SS, ssr=SSR, redir=Redir, pf=Pf, tunnel=Tunnel, echo=Echo, ws=WS, trojan=Trojan, h2=H2, h3=H3, ssl='', secure='', quic='') |
| 602 | +MAPPINGS = dict(direct=Direct, http=HTTP, httponly=HTTPOnly, httpadmin=HTTPAdmin, ssh=SSH, socks5=Socks5, socks4=Socks4, socks=Socks5, ss=SS, ssr=SSR, redir=Redir, pf=Pf, tunnel=Tunnel, echo=Echo, ws=WS, trojan=Trojan, h2=H2, h3=H3, ssl='', secure='', quic='') |
571 | 603 | MAPPINGS['in'] = ''
|
572 | 604 |
|
573 | 605 | def get_protos(rawprotos):
|
|
0 commit comments