o
    &g                  	   @   s  d Z ddlZddlZddlZddlZddlZddlZddlZddlZddl	Z	ddl
mZ dD ]#\ZZz	eee e< W q. eyQ   de e< edeef  Y q.w ejdkr[ddlZ	ddlmZmZ ddlmZ G d	d
 d
ejZG dd deeZG dd dZdS )ap  
Python WebSocket server base with support for "wss://" encryption.
Copyright 2011 Joel Martin
Copyright 2016 Pierre Ossman
Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3)

You can make a cert/key with openssl using:
openssl req -new -x509 -days 365 -nodes -out self.pem -keyout self.pem
as taken from http://docs.python.org/dev/library/ssl.html#certificates

    N)SimpleHTTPRequestHandler))sslzTLS/SSL/wss is disabled)resourcezdaemonizing is disabledzWARNING: no '%s' module, %swin32)WebSocketWantReadErrorWebSocketWantWriteError)WebSocketRequestHandlerMixInc                   @   s   e Zd Zdd ZdS )CompatibleWebSocketc                 C   s   d|v rdS dS )Nbinary  )self	protocolsr   r   Z/root/parts/websockify/install/lib/python3.10/site-packages/websockify/websockifyserver.pyselect_subprotocol$   s   z&CompatibleWebSocket.select_subprotocolN)__name__
__module____qualname__r   r   r   r   r   r	   #   s    r	   c                       s  e Zd ZdZdZdZeZG dd deZ	 fddZ
dd	 Zd8ddZdd Zdd Zdd Zd9ddZdd Zd:ddZd;ddZd;dd Z fd!d"Zd#d$ Z fd%d&Z fd'd(Zd)d* Zd+d, Zd-d. Z fd/d0Z fd1d2Z fd3d4Zd< fd6d7	Z  Z S )=WebSockifyRequestHandlera  
    WebSocket Request Handler Class, derived from SimpleHTTPRequestHandler.
    Must be sub-classed with new_websocket_client method definition.
    The request handler can be configured by setting optional
    attributes on the server object:

    * only_upgrade: If true, SimpleHTTPRequestHandler will not be enabled,
      only websocket is allowed.
    * verbose: If true, verbose logging is activated.
    * daemon: Running as daemon, do not write to console etc
    * record: Record raw frame data as JavaScript array into specified filename
    * run_once: Handle a single request
    * handler_id: A sequence number for this connection, appended to record filename
    
WebSockifyzHTTP/1.1c                   @      e Zd ZdS )zWebSockifyRequestHandler.CCloseNr   r   r   r   r   r   r   CCloseB       r   c                    s   t |dd| _t |dd| _t |dd| _t |dd| _t |dd| _d | _t |dd| _t |dd| _t |d	d| _	t |d
d| _
t |dd| _t |dd | _| jd u rZt | _t ||| d S )Nonly_upgradeFverbosedaemonrecordrun_once
handler_id	file_onlytrafficweb_auth
host_tokenlogger)getattrr   r   r   r   r   recr   r    r!   r"   r#   r$   WebSockifyServer
get_loggersuper__init__)r   reqaddrserver	__class__r   r   r*   E   s   

z!WebSockifyRequestHandler.__init__c                 G   s(   | j d| jd |  || f  d S )Nz%s - - [%s] %sr   )r$   infoclient_addresslog_date_time_string)r   formatargsr   r   r   log_messageY   s   (z$WebSockifyRequestHandler.log_message.c                 C   s$   | j rtj| tj  dS dS )z Show traffic flow mode. N)r!   sysstdoutwriteflush)r   tokenr   r   r   print_traffic`   s   z&WebSockifyRequestHandler.print_trafficc                 O   4   d| j  }| jjtjd||f g|R i | dS )z( Output message with handler_id prefix. % 3d: %s%sN)r   r$   logloggingINFOr   msgr4   kwargsprefixr   r   r   rD   f      
*zWebSockifyRequestHandler.msgc                 O   r=   ) Same as msg() but as debug. r>   r?   N)r   r$   r@   rA   DEBUGrC   r   r   r   vmsgk   rG   zWebSockifyRequestHandler.vmsgc                 O   r=   ) Same as msg() but as warning. r>   r?   N)r   r$   r@   rA   WARNrC   r   r   r   warnp   rG   zWebSockifyRequestHandler.warnNc                 C   s   t t d | j }|r4|D ]$}| jr-|ddddd}| jd|| | j	
| q| j	r`z| j| j	d  W n tyQ   | d	 Y d
S w | j	d | d | j	s7dS )a"   Encode and send WebSocket frames. Any frames already
        queued will be sent first. If buf is not set then only queued
        frames will be sent. Returns True if any frames could not be
        fully sent, in which case the caller should call again when
        the socket is ready.   latin1unicode_escapeascii'\'z'{{{0}{{{1}',
r   z<.T<F)inttime
start_timer&   decodeencodereplacer9   r3   
send_partsappendrequestsendmsgr   r<   pop)r   bufstdeltabufbufstrr   r   r   send_framesx   s$   


z$WebSockifyRequestHandler.send_framesc                 C   s   d}g }t t d | j }	 z| j }W n ty(   | d Y ||fS w |du r:| jj| jjd}||fS | d | j	r[|
dd	
d
dd}| j	d|| || | j sj	 ||fS q)zg Receive and decode WebSocket frames.

        Returns:
            (bufs_list, closed_string)
        FrN   Tz}.N)codereason}rO   rP   rQ   rR   rS   z'}}{0}}}{1}',
)rU   rV   rW   r]   recvmsgr   r<   
close_codeclose_reasonr&   rX   rY   rZ   r9   r3   r\   pending)r   closedr`   ra   rb   rc   r   r   r   recv_frames   s2   



z$WebSockifyRequestHandler.recv_framesrN   r   c                 C   s   | j tj|| dS )z' Send a WebSocket orderly close frame. N)r]   shutdownsocket	SHUT_RDWR)r   re   rf   r   r   r   
send_close   s   z#WebSockifyRequestHandler.send_close    c                 C      | j | dS )z Send a WebSocket pong frame. N)r]   pongr   datar   r   r   	send_pong      z"WebSockifyRequestHandler.send_pongc                 C   rs   )z Send a WebSocket ping frame. N)r]   pingru   r   r   r   	send_ping   rx   z"WebSockifyRequestHandler.send_pingc                    s   |    |   t   d S N)validate_connectionauth_connectionr)   handle_upgrader   r.   r   r   r~      s   z'WebSockifyRequestHandler.handle_upgradec                 C   s  d| j _g | _d | _tt d | _d}d}z| jd }| jd }W n	 ty,   Y nw |r3d| _	nd| _	| 
d	|| j	 | jd
krK| 
d|| j | jrhd| j| jf }| 
d| t|d| _| jd z|   W d S  | jy   t \}}}| |jd |jd  Y d S w )NTrN   r   Fr      zSSL/TLS (wss://)zPlain non-SSL (ws://)z%s: %s WebSocket connection/z%s: Path: '%s'%s.%szopening record file: %szw+zvar VNC_frame_data = [
   )r-   ws_connectionr[   	recv_partrU   rV   rW   r1   
IndexErrorstyper5   pathr   r   openr&   r9   new_websocket_clientr   r7   exc_inforq   r4   )r   client_addris_sslfname_excr   r   r   handle_websocket   sB   

z)WebSockifyRequestHandler.handle_websocketc                    0   | j r|   | jr| d d S t   d S Ni  )r"   r}   r   
send_errorr)   do_GETr   r.   r   r   r      s
   zWebSockifyRequestHandler.do_GETc                    s    | j r
| d d S t |S )Ni  )r    r   r)   list_directory)r   r   r.   r   r   r     s   z'WebSockifyRequestHandler.list_directoryc                 C   s   t d)3 Do something with a WebSockets client connection. zAWebSocketRequestHandler.new_websocket_client() must be overloaded)	Exceptionr   r   r   r   r     s   z-WebSockifyRequestHandler.new_websocket_clientc                 C      dS )zC Ensure that the connection has a valid token, and set the target. Nr   r   r   r   r   r|        z,WebSockifyRequestHandler.validate_connectionc                 C   r   )z+ Ensure that the connection is authorized. Nr   r   r   r   r   r}     r   z(WebSockifyRequestHandler.auth_connectionc                    r   r   )r"   r}   r   r   r)   do_HEADr   r.   r   r   r     s
   z WebSockifyRequestHandler.do_HEADc                    s*   | j r| j d | j   t   d S )Nz'EOF'];
)r&   r9   closer)   finishr   r.   r   r   r     s   
zWebSockifyRequestHandler.finishc                    s    | j r	|   d S t   d S r{   )r   handle_one_requestr)   handler   r.   r   r   r   "  s   zWebSockifyRequestHandler.handle-c                    s   | j rt || d S d S r{   )r   r)   log_request)r   re   sizer.   r   r   r   +  s   z$WebSockifyRequestHandler.log_request)r6   r{   )rN   r   )rr   )r   r   )!r   r   r   __doc__server_versionprotocol_versionr	   SocketClassr   r   r*   r5   r<   rD   rJ   rM   rd   rm   rq   rw   rz   r~   r   r   r   r   r|   r}   r   r   r   r   __classcell__r   r   r.   r   r   ,   s8    


%

*
		r   c                   @   s   e Zd ZdZdZdZG dd deZG dd deZ		
			
	
	
			d2ddZ	e
dd Ze
	
	
		d3ddZe
d4ddZdd Zdd Zdd Zdd Zdd Zd d! Zd"d# Zd$d% Zd&d' Zd(d) Zd*d+ Zd,d- Zd.d/ Zd0d1 ZdS )5r'   zg
    WebSockets server class.
    As an alternative, the standard library SocketServer can be used
    zY<cross-domain-policy><allow-access-from domain="*" to-ports="*" /></cross-domain-policy>
	websocketc                   @   r   )zWebSockifyServer.ECloseNr   r   r   r   r   EClose:  r   r   c                   @   r   )zWebSockifyServer.TerminateNr   r   r   r   r   	Terminate=  r   r   Nr   Fr   Tc                 C   sT  || _ || _|| _|| _|| _|| _|| _|| _|
| _|| _	|| _
|| _|| _|| _|| _|| _|| _|| _|| _t | _d| _d| _d| _|  | _|| _|| _|| _|| _d | _|	| _t j!"|| _#d | _$ | _%| _&|rwt j!"|| _|rt j!"|| _$|rt j!"|| _%|rt j!"|| _&| j$rt '| j$ | j$ | _(t)s| jrt*d| jrt+st*d| ,d | jd kr| ,d n| jd kr| ,d| j n	| ,d	| j| j | j$r| jr| ,d
| j$ n| ,d| j$ t)rt j!-| j#r| ,d | jr| ,d n| ,d n| ,d | jr| ,d | j%r(| ,d| j% d S d S )NFr   r   z&No 'ssl' module and SSL-only specifiedz'Module 'resource' required to daemonizezWebSocket server settings:z   - Listen for inetd connectionsz  - Listen on unix socket %sz  - Listen on %s:%sz4  - Web server (no directory listings). Web root: %sz  - Web server. Web root: %sz  - SSL/TLS supportz   - Deny non-SSL/TLS connectionsz%  - No SSL/TLS support (no cert file)z(  - No SSL/TLS support (no 'ssl' module)z  - Backgrounding (daemon)z  - Recording to '%s.*').RequestHandlerClassr   	listen_fdunix_listenunix_listen_modelisten_hostlisten_portprefer_ipv6ssl_onlyssl_ciphersssl_optionsverify_clientr   r   timeoutidle_timeoutr!   r    r"   rV   launch_timer   r   terminatingr(   r$   tcp_keepalivetcp_keepcnttcp_keepidletcp_keepintvlkeykey_passwordosr   abspathcertwebr   cafilechdirr   r   r   r   rD   exists)r   r   r   r   r   source_is_ipv6r   r   r   r   r   r   r   r   r   r   r"   r    r   r   r   r!   r   r   r   r   r   r   r   r   r   r   r   r*   @  s   











zWebSockifyServer.__init__c                   C   s   t dtjtjjf S )Nr   )rA   	getLoggerr'   
log_prefixr/   r   r   r   r   r   r(     s   zWebSockifyServer.get_loggerc              	   C   s
  d}| dkrd} |r|s|st d|rtst d|s"|r"t d|s)|tjB }|st| |dtjtj|}|s?t d|  |jdd	 d
 |rM|  t|d d |d d }|r|	tj
tjd |	rq|	tjtj|	 |
r||	tjtj|
 |r|	tjtj| |r||d d  |rt }|j|| d}|S |	tj
tjd ||d d  |d |S |rzt| W n	 ty   Y nw ttjtj}td|A }z|| W t| nt| w |d |S ttjtj}|| |S )z Resolve a host (and optional port) to an IPv4 or IPv6
        address. Create a socket. Bind to it if listen is set,
        otherwise connect to it. Return the socket.
        r   r   NzConnect mode requires a portz6SSL socket requested but Python SSL module not loaded.z,SSL only supported in connect mode (for now)zCould not resolve host '%s'c                 S   s   | d S )Nr   r   )xr   r   r   <lambda>  s    z)WebSockifyServer.socket.<locals>.<lambda>)r   r      )server_hostnamed   i  )r   r   ro   
AI_PASSIVEgetaddrinfoSOCK_STREAMIPPROTO_TCPsortreverse
setsockopt
SOL_SOCKETSO_KEEPALIVESOL_TCPTCP_KEEPCNTTCP_KEEPIDLETCP_KEEPINTVLconnectcreate_default_contextwrap_socketSO_REUSEADDRbindlistenr   unlinkFileNotFoundErrorAF_UNIXumask)hostportr   r   unix_socketunix_socket_modeunix_socket_listenuse_sslr   r   r   r   flagsaddrssockcontextoldmaskr   r   r   ro     sz   	



zWebSockifyServer.socketr   c              	   C   sr  | d u rg } t d |rt | nt d t t   t t   t  dkr1t d t 	  t  dkr@t d t

t
jt
j t

t
jt
j ttjd }|tjkr_d}tt|D ]$}z|| vrqt | W qe ty   t \}}}|jtjkr Y qew t t t jt jtj  t t t jt jtj   t t t jt jtj!  d S )Nr   r   r      )"r   r   r   setgidgetgidsetuidgetuidfork_exitsetsidsignalSIGTERMSIG_IGNSIGINTr   	getrlimitRLIMIT_NOFILERLIM_INFINITYreversedranger   OSErrorr7   r   errnoEBADFdup2r   devnullO_RDWRstdinfilenor8   stderr)keepfdr   maxfdfdr   r   r   r   r   	daemonize  s6   


"zWebSockifyServer.daemonizec           	      C   s  t  |gg g dd }|s| d|dtj}|s | d|d dv rts-| dtj| j	s<| d| j	 d}z@t
tjj}| jdurQ|| j | j|_|j| j	| j| jd	 | jrvtj|_| jrr|j| jd
 n|  |j|dd}W n6 tjy   t \}}}|jd tjkrt |jdkr| |jd | d w | j!r| d|}t |dkr|d |d ||kf}| "|||  |S )a_  
        do_handshake does the following:
        - Peek at the first few bytes from the socket.
        - If the connection is an HTTPS/SSL/TLS connection then SSL
          wrap the socket.
        - Read from the (possibly wrapped) socket.
        - If we have received a HTTP GET request and the webserver
          functionality is enabled, answer it, close the socket and
          return.
        - Assume we have a WebSockets connection, parse the client
          handshake data.
        - Send a WebSockets handshake server response.
        - Return the socket for this WebSocket client.
           r   r   i   )      z"SSL connection but no 'ssl' modulez!SSL connection but '%s' not foundN)certfilekeyfilepassword)r   T)server_sider   zGot SSL_ERROR_EOFz*non-SSL connection received but disallowedr   )#selectr   recvro   MSG_PEEKr   r   r   r   r   r   PurposeCLIENT_AUTHr   set_ciphersr   optionsload_cert_chainr   r   r   CERT_REQUIREDverify_moder   load_verify_locationsset_default_verify_pathsr   SSLErrorr7   r   r4   SSL_ERROR_EOFlenr   r   )	r   r   addressready	handshakeretsockr   r   r   r   r   r   do_handshake  sX   







zWebSockifyServer.do_handshakec                 O       | j jtjg|R i | dS )z Output message as info N)r$   r@   rA   rB   r   r4   rE   r   r   r   rD   l      zWebSockifyServer.msgc                 O   r*  )rH   N)r$   r@   rA   rI   r+  r   r   r   rJ   p  r,  zWebSockifyServer.vmsgc                 O   r*  )rK   N)r$   r@   rA   rL   r+  r   r   r   rM   t  r,  zWebSockifyServer.warnc                 C   s   |  d dS )z! Called after WebSockets startup zWebSockets server startedN)rJ   r   r   r   r   started|  s   zWebSockifyServer.startedc                 C   r   )z1 Run periodically while waiting for connections. Nr   r   r   r   r   poll  s   zWebSockifyServer.pollc                 C   s   | j s
d| _ |  d S )NT)r   r   r   r   r   r   	terminate  s   zWebSockifyServer.terminatec                 C   s   t   d S r{   )multiprocessingactive_childrenr   sigstackr   r   r   multiprocessing_SIGCHLD     z(WebSockifyServer.multiprocessing_SIGCHLDc                 C   s`   z%t dt j}|d r#| d|d   t dt j}|d sW d S W d S  ty/   Y d S w )Nr   zReaped child process %s)r   waitpidWNOHANGrJ   r  )r   r3  r4  resultr   r   r   fallback_SIGCHLD  s   z!WebSockifyServer.fallback_SIGCHLDc                 C      |    d S r{   r/  r2  r   r   r   	do_SIGINT  r6  zWebSockifyServer.do_SIGINTc                 C   r<  r{   r=  r2  r   r   r   
do_SIGTERM  r6  zWebSockifyServer.do_SIGTERMc              	   C   s   d}zez|  ||}W nK | jy/   t \}}}|jd r-| d|d |jd f  Y n( tjy7     tyV   t \}}}| dt	|  | j
ddd Y nw W |rd||krf|  dS dS dS |rs||krt|  w w w )r   Nr   z%s: %shandler exception: %s	exceptionTr   )r)  r   r7   r   r4   rD   r'   r   r   strrJ   r   )r   	startsockr%  clientr   r   r   r   r   top_new_client  s,   

zWebSockifyServer.top_new_clientc                 C   s4   g }| j jjD ]}t|tjr||j  q|S )zu
        Get file descriptors for the loggers.
        They should not be closed when the process is forked.
        )	r$   parenthandlers
isinstancerA   FileHandlerr\   streamr	  )r   descriptorshandlerr   r   r   
get_log_fd  s   zWebSockifyServer.get_log_fdc                 C   s  z7| j dkrt| j tjtj}n%| jdkr"| jd| j| jdd}n| j| j| jd| j	| j
| j| j| jd}W n% ty\ } z| dt| | jddd t  W Y d}~nd}~ww | jrs|  }||  | j|| jd	 |   tjttjtjttji}ttd
ddurttj |tj < ttj| j! ttj| j" ttd
ddurttj | j# | j$}z	 zz#d}d }}d}	t%t&' }	t(( | j$ }
| j)r|
| j)kr| d| j)  W W |r|*  nZ| j+r'd}|	dkrt(( | }nd}t(( }|| j+kr'|	dkr'| d| j+  W W |r%|*  n$z2| ,  t--|gg g dd }||v rM|. \}}| jdkrL| jg}nW W W |rW|*  qW nI | j/yc     t0y   t1 \}}}t2|dr{|j3}nt2|dr|j4d }n|d }|t3j5kr| d Y W W |r|*  q w | j6r| 7|| | j8r| d|d   W W |r|*  nn| d|d   t&j9| j7||fd}|:  |  j;d7  _;W nS | j/t<t=fy   | d | j6st&' }|D ]}| d|j>  |?  qY W |r|*  n2 t0y7   t1 d }| dt| | jddd Y nw W |r@|*  n	|rI|*  w w qW | d| j| j |*  |@ D ]\}}t|| q]dS | d| j| j |*  |@ D ]\}}t|| q|w )a  
        Daemonize if requested. Listen for for connections. Run
        do_handshake() method for each connection. If the connection
        is a WebSockets client then call new_websocket_client() method (which must
        be overridden) for each new client connection.
        NT)r   r   r   r   F)r   r   r   r   zOpenening socket failed: %srA  rB  )r  r   SIGCHLDr   z!listener exit due to --timeout %sz&listener exit due to --idle-timeout %sr   r  r4   zIgnoring interrupted syscallz%s: exiting due to --run-oncez%s: new handler Process)targetr4   zIn exitzTerminating child %sr@  z!Closing socket listening at %s:%s)Ar   ro   fromfdAF_INETr   r   r   r   r   r   r   r   r   r   r  rD   rC  rJ   r7   exitr   rN  r\   r	  r  r   r-  r   r   	getsignalr   r%   rO  r>  r?  r5  r   r$  r0  r1  rV   r   r   r   r.  r  acceptr   r   r   hasattrr  r4   EINTRr   rF  r   Processstartr   
SystemExitKeyboardInterruptpidr/  items)r   lsocker  original_signalslast_active_timerD  r\  errchild_counttime_elapsed	idle_timer&  r%  r   r   pchildrenchildr3  funcr   r   r   start_server  s6  

M
@
4
'

_zWebSockifyServer.start_server)Nr   NFFr   r   NNFNFr   r   FFFr   r   FTNNNNr   NN)NFFNNFFTNNN)Nr   )r   r   r   r   policy_responser   r   r   r   r*   staticmethodr(   ro   r  r)  rD   rJ   rM   r-  r.  r/  r5  r;  r>  r?  rF  rN  rj  r   r   r   r   r'   0  sR    
e
G&Rr'   )r   r   r7   rV   r  r   ro   r  rA   r0  http.serverr   modrD   
__import__globalsImportErrorprintplatformmultiprocessing.reductionwebsockify.websocketr   r   websockify.websocketserverr   r   r	   r   r'   r   r   r   r   <module>   s(   @

	  