
    }tf                        d Z ddlZddlZddlmZ ddlmZ ddlmZ ddlm	Z	m
Z
mZ ddlZddlmZmZ ddlmZmZ dd	lmZ dd
lmZmZmZ ddlmZ ddlmZmZmZmZm Z m!Z!m"Z"m#Z# ddl$m%Z% ddl&m'Z' ddl(m)Z) ddl*m+Z+m,Z,  G d de%      Z- G d de      Z. G d de+e      Z/ G d de/      Z0 G d de/      Z1 G d de0      Z2 G d de2      Z3d  Z4y)!zw
Authenticated HTTP proxy for Jupyter Notebooks

Some original inspiration from https://github.com/senko/tornado-proxy
    N)Lockcopy)mkdtemp)quoteurlparse
urlunparse)JupyterHandlerutcnow)ensure_asyncurl_path_join)SupervisedProcess)
httpclienthttputilweb)SimpleAsyncHTTPClient)BytesDictInstanceIntegerUnicodeUniondefaultobserve)	HasTraits   )UnixResolvercall_with_asked_args)WebSocketHandlerMixinpingable_ws_connectc                   J    e Zd ZdZ eej                        Z e e	        ee
j                        g      Z e       Z e       Z ed      Z ed      d        Z ed      d	        Z ed
      d        Z ed      d        Z ed
      d        Z fdZd Z xZS )RewritableResponsezJ
    A class to hold the response to be rewritten by rewrite_response
    )klass)trait_typesT)
allow_noneheadersc                 @    t        | j                  j                        S N)r   orig_responser'   selfs    g/var/www/html/software/conda/envs/higlass/lib/python3.12/site-packages/jupyter_server_proxy/handlers.py_default_headersz#RewritableResponse._default_headers+   s    D&&..//    bodyc                 .    | j                   j                  S r)   )r*   r0   r+   s    r-   _default_bodyz RewritableResponse._default_body/       !!&&&r/   codec                 .    | j                   j                  S r)   )r*   r4   r+   s    r-   _default_codez RewritableResponse._default_code3   r3   r/   reasonc                 .    | j                   j                  S r)   )r*   r7   r+   s    r-   _default_reasonz"RewritableResponse._default_reason7   s    !!(((r/   c                     | j                   t        j                  j                  |d   d      k(  r)t        j                  j                  |d   d      | _         y y )NoldUnknownnew)r7   r   	responsesget)r,   changes     r-   _observe_codez RewritableResponse._observe_code;   sK     ;;(,,00	JJ",,00	JDK Kr/   c                 <    t        |   |i | | j                   y r)   )super__init__r4   r,   argskwargs	__class__s      r-   rD   zRewritableResponse.__init__H   s    $)&) 			r/   c                 ,    t        |       } ||       |S )zI
        Apply a function to a copy of self, and return the copy
        r   )r,   funcr=   s      r-   _apply_to_copyz!RewritableResponse._apply_to_copyN   s     4jS	
r/   )__name__
__module____qualname____doc__r   r   HTTPResponser*   r   r   r   HTTPHeadersr'   r   r0   r   r4   r   r7   r   r.   r2   r6   r9   r   rA   rD   rK   __classcell__rH   s   @r-   r#   r#      s     :#:#:;M 8L8L)M NOG7D9D%FY0 0 V_' ' V_' ' X) ) V_
K 
Kr/   r#   c                   4    e Zd ZdZej
                  d        Zy)AddSlashHandlerz*Add trailing slash to URLs that need them.c                     t        | j                  j                        }|j                  |j                  dz         }| j                  t        |             y )N/)path)r   requesturi_replacerX   redirectr	   )r,   rF   srcdests       r-   r?   zAddSlashHandler.getZ   s?    t||''(||C|0j&'r/   N)rL   rM   rN   rO   r   authenticatedr?    r/   r-   rU   rU   W   s    4( (r/   rU   c                        e Zd ZdZdZ fdZddZd Z fdZddZ	ddZ
dd	Zdd
ZddZddZddZd Zd Zd Zd Zd Zd Zd Zd Zd Zd ZddZd Zd Zd Zd Zd Z xZ S ) ProxyHandlera  
    A tornado request handler that proxies HTTP and websockets from
    a given host/port combination. This class is not meant to be
    used directly as a means of overriding CORS. This presents significant
    security risks, and could allow arbitrary remote code access. Instead, it is
    meant to be subclassed and used for proxying URLs from trusted sources.

    Subclasses should implement open, http_get, post, put, delete, head, patch,
    and options.
    Nc                     d| _         |j                  dd      | _        |j                  dddg      | _        |j                  dt	                     | _        d | _        t        |    |i | y )N absolute_urlFhost_allowlist	localhostz	127.0.0.1rewrite_response)	
proxy_basepopre   rf   tuplerh   _requested_subprotocolsrC   rD   rE   s      r-   rD   zProxyHandler.__init__o   sk    "JJ~u=$jj)9K;UV &

G!
 (,$$)&)r/   c                 .    t        j                  | |      S r)   )r
   check_origin)r,   origins     r-   rn   zProxyHandler.check_origin}   s    **488r/   c                     K   t        d      w)Nz0Subclasses of ProxyHandler should implement openNotImplementedErrorr,   portproxied_paths      r-   openzProxyHandler.open   s     !"TUU   c                 d  K   t        |   |i |}|
| d{    | j                  j                  dk(  rY| j                  j                  j                  dd      j                         dk(  r"| j                  st        j                  d      y t        j                  d       |        y7 w)z
        Enforce authentication on *all* requests.

        This method is called *before* any other method for all requests.
        See https://www.tornadoweb.org/en/stable/web.html#tornado.web.RequestHandler.prepare.
        NGETUpgraderd   	websocket  c                      y r)   r`   )request_handlers    r-   <lambda>z&ProxyHandler.prepare.<locals>.<lambda>       r/   )rC   preparerY   methodr'   r?   lowercurrent_userr   	HTTPErrorr_   )r,   rF   rG   	_preparedrH   s       r-   r   zProxyHandler.prepare   s      GOT4V4	 OO LL5($$((B7==?;N$$mmC(( % <C:;DA s   B0B.BB0c                     K   t        d      w)zOur non-websocket GET.z4Subclasses of ProxyHandler should implement http_getrq   r,   hostrt   
proxy_paths       r-   http_getzProxyHandler.http_get   s     !B
 	
rw   c                     t        d      )Nz5Subclasses of ProxyHandler should implement this postrq   r   s       r-   postzProxyHandler.post   s    !C
 	
r/   c                     t        d      )Nz4Subclasses of ProxyHandler should implement this putrq   )r,   rt   r   s      r-   putzProxyHandler.put   s    !B
 	
r/   c                     t        d      )Nz2Subclasses of ProxyHandler should implement deleterq   r   s       r-   deletezProxyHandler.delete   s    !"VWWr/   c                     t        d      )Nz0Subclasses of ProxyHandler should implement headrq   r   s       r-   headzProxyHandler.head   s    !"TUUr/   c                     t        d      )Nz1Subclasses of ProxyHandler should implement patchrq   r   s       r-   patchzProxyHandler.patch   s    !"UVVr/   c                     t        d      )Nz3Subclasses of ProxyHandler should implement optionsrq   r   s       r-   optionszProxyHandler.options   s    !"WXXr/   c                     | j                          t        | d      r,| j                  j                  |t	        |t
                     yy)zh
        Called when we receive a message from our client.

        We proxy it to the backend.
        wsbinaryN)_record_activityhasattrr   write_message
isinstancebytes)r,   messages     r-   
on_messagezProxyHandler.on_message   s=     	4GG!!'*We2L!M r/   c                     | j                   j                  d|        | j                          t        | d      r&| j                  j
                  j                  |       yy)zm
        Called when the client pings our websocket connection.

        We proxy it to the backend.
        zjupyter_server_proxy: on_ping: r   N)logdebugr   r   r   protocol
write_pingr,   datas     r-   on_pingzProxyHandler.on_ping   sO     	8?@4GG''- r/   c                 @    | j                   j                  d|        y)z5
        Called when we receive a ping back.
        zjupyter_server_proxy: on_pong: N)r   r   r   s     r-   on_pongzProxyHandler.on_pong   s     	8?@r/   c                 R    t        | d      r| j                  j                          yy)z~
        Called when the client closes our websocket connection.

        We close our connection to the backend too.
        r   N)r   r   closer+   s    r-   on_closezProxyHandler.on_close   s      4GGMMO r/   c                 2    t               | j                  d<   y)zRecord proxied activity as API activity

        avoids proxied traffic being ignored by the notebook's
        internal idle-shutdown mechanism
        api_last_activityN)r   settingsr+   s    r-   r   zProxyHandler._record_activity   s     .4X)*r/   c                    |dk(  rt        |      n|dz   t        |      z   }| j                  r t        | j                  | j                        S | j                  rt        | j                  dd|      S t        | j                  d|      S )a5  
        Some applications need to know where they are being proxied from.
        This is either:
        - {base_url}/proxy/{port}
        - {base_url}/proxy/{host}:{port}
        - {base_url}/proxy/absolute/{port}
        - {base_url}/proxy/absolute/{host}:{port}
        - {base_url}/{proxy_base}
        rg   :proxyabsolute)strri   r   base_urlre   )r,   r   rt   host_and_ports       r-   _get_context_pathzProxyHandler._get_context_path   sp     &*[%8D	dSj3t9>T?? @@ ]SS GGr/   c                 4   | j                   r| j                  ||      }t        ||      }n|}|j                  d      sd|z   }t	        |d      }dj                  ||||      }| j                  j                  r|d| j                  j                  z   z  }|S )NrW   z:/?#[]@!$&'()*+,;=-._~)safez {protocol}://{host}:{port}{path})r   r   rt   rX   ?)re   r   r   
startswithr   formatrY   query)r,   r   r   rt   ru   context_pathclient_path
client_uris           r-   get_client_urizProxyHandler.get_client_uri  s    11$=L'lCK&K %%c*+K K.FG7>>	 ? 

 <<# 2 222Jr/   c                 "   | j                         }| j                  d|||      }| j                  s!| j                  ||      }||d<   ||d<   ||d<   t	        j
                  |f| j                  j                  |d|d| j                         }|S )NhttpzX-Forwarded-ContextzX-ProxyContextPathzX-Forwarded-PrefixF)r   r0   decompress_responser'   )	proxy_request_headersr   re   r   r   HTTPRequestrY   r   proxy_request_options)	r,   r   rt   ru   r0   r'   r   r   reqs	            r-   _build_proxy_requestz!ProxyHandler._build_proxy_request   s    ,,.((t\J
   11$=L-9G)*,8G(),8G()$$
<<&& %
 ((*
 
r/   c                 l    t        | j                        r| j                  | |      S || j                  v S r)   )callablerf   )r,   r   s     r-   _check_host_allowlistz"ProxyHandler._check_host_allowlist7  s4    D''(&&tT224....r/   c                 j  K   | j                  |      st        j                  dd| d      g d}|D ]2  }|| j                  j                  v s| j                  j                  |= 4 | j                          | j                  j                  j                  dd      j                         dk(  r,| j                  j                  d       | j                  d	       | j                  j                  }|s| j                  j                  d
v rd}nd}| j                  S| j                  j                  d| j                         |dk(  sJ d       t        dt!        | j                              }nt#        j$                         }| j'                  ||||      }| j                  j                  d|j(                          	 |j+                  |d       d{   }	| j                          |	j0                  rNt3        |	j0                        t"        j                  ur)t        j                  d	t/        |	j0                              t5        |	      }| j6                  }t9        |t:        t<        f      r|}n|g}| j                  ||||d|}|D ]   dt4        ffd}|j?                  |      }" | j                  |j,                  |j@                         tC        jD                         | _#        |j                  jI                         D ]  \  }}|dvs| jK                  ||        |j                  r| jM                  |j                         yy7 }# t"        j                  $ rD}
|
j,                  dk(  r/| j                          t        j                  dt/        |
             d}
~
ww xY ww)z
        This serverextension handles:
            {base_url}/proxy/{port([0-9]+)}/{proxied_path}
            {base_url}/proxy/absolute/{port([0-9]+)}/{proxied_path}
            {base_url}/{proxy_base}/{proxied_path}
        r|   zHost 'zp' is not allowed. See https://jupyter-server-proxy.readthedocs.io/en/latest/arbitrary-ports-hosts.html for info.)	zProxy-Connectionz
Keep-AliveTransfer-EncodingTE
ConnectionTrailerrz   zProxy-AuthorizationzProxy-Authenticaterz   rd   r{   z=we wanna websocket, but we don't define WebSocketProxyHandler  >   PUTPOSTr/   Nz Making client for Unix socket %rrg   'Unix sockets only possible on localhostT)force_instanceresolverzProxying request to F)raise_erroriW  )r*   )rY   r*   r   rt   rX   rewritable_responsec                 $    t        d| i      S )Nresponser   )r   !optional_args_to_rewrite_functionrewrites    r-   
rewrite_pez&ProxyHandler.proxy.<locals>.rewrite_pe  s&    /&(;? r/   )zContent-Lengthr   r   )'r   r   r   rY   r'   r   r?   r   r   info
set_statusr0   r   unix_socketr   r   r   r   AsyncHTTPClientr   urlfetchr4   r   errortyper#   rh   r   listrk   rK   r7   r   rQ   _headersget_all
add_headerwrite)r,   r   rt   ru   hop_by_hop_headersheader_to_remover0   clientr   r   erroriginal_responserh   rewrite_responsesrewritten_responser   headervr   r   s                     @@r-   r   zProxyHandler.proxy=  sd     ))$/-- q q 

 !3 	;4<<#7#77LL(()9:	; 	<<##Ir288:kI HHMMO OOC ||  ||""o5'HHNN=t?O?OP;&Q(QQ&*#l4;K;K.LF  //1F''dL$G-cggY78	#\\#5\AAH 	 >>d8>>2*:N:NN--S%899 !3 J  $44 *T5M:$4!%5$6!  <<!2$1- "3, S4F  &8%F%Fz%R"#S( OO.335G5N5NO %002DM/77??A /	!VVOOFA./
 "&&

-223 'S B## 		
 xx3%%'mmCS22		sJ   AN3E0N3M MM D:N3=N3M N0,?N++N00N3c                 *   	K    j                  |      sM j                  d        j                  j                  dj	                  |              j                          y|j                  d      sd|z   } j                  >|dk(  sJ d        j                  j                  d|       t         j                        	nd	 j                  d	|||       j                          fd
 fd	 fd} |        d{    y7 w)z
        Called when a client opens a websocket connection.

        We establish a websocket connection to the proxied backend &
        set up a callback to relay messages through.
        r|   z|Host '{host}' is not allowed. See https://jupyter-server-proxy.readthedocs.io/en/latest/arbitrary-ports-hosts.html for info.)r   NrW   rg   r   z#Opening websocket on Unix socket %rr   c                     j                          | j                          yj                  | t        | t                     y)zz
            Callback when the backend sends messages to us

            We just pass it back to the frontend
            Nr   )r   r   r   r   r   )r   r,   s    r-   
message_cbz+ProxyHandler.proxy_open.<locals>.message_cb  s9     !!#

""7:gu3M"Nr/   c                 H    j                          j                  |        y)zy
            Callback when the backend sends pings to us.

            We just pass it back to the frontend.
            N)r   ping)r   r,   s    r-   ping_cbz(ProxyHandler.proxy_open.<locals>.ping_cb  s     !!#IIdOr/   c            	      (  K   j                   j                  d        j                          t        j                        } t        | j                         d {   _        j                          j                   j                  d        j                  j                  j                  k7  rNj                   j                  dj                  j                   dj                   dj                   d       y y 7 w)	Nz,Trying to establish websocket connection to )r   r'   )rY   on_message_callbackon_ping_callbacksubprotocolsr   z$Websocket connection established to z,Websocket subprotocol between proxy/server (z*) became different than for client/proxy (zd) due to https://github.com/jupyterhub/jupyter-server-proxy/issues/459. Requested subprotocols were .)
r   r   r   r   r   r!   rl   r   selected_subprotocolwarn)rY   r   r'   r   r   r   r,   s    r-   start_websocket_connectionz;ProxyHandler.proxy_open.<locals>.start_websocket_connection  s     HHMMHUV!!# ,,WMG/$.!(!99! DG !!#HHMM@MNww++t/H/HHB477C_C_B` a??C?X?X>Y Z3373O3O2PPQS Is   A#D&D'B*D)r   r   r   r   r   r   r   r   r   r   r   r   )
r,   r   rt   ru   r  r   r'   r   r   r   s
   `    @@@@@r-   
proxy_openzProxyHandler.proxy_open  s     ))$/OOC HHMMqqwqw rx r JJL&&s+-L';&Q(QQ&HHNN@$G#D$4$45HH((tT<H
,,.	O		 	0 )***s   DDDDc                     | j                   j                  j                         }|j                  | j	                                |S )z}A dictionary of headers to be used when constructing
        a tornado.httpclient.HTTPRequest instance for the proxy request.)rY   r'   r   updateget_request_headers_override)r,   r'   s     r-   r   z"ProxyHandler.proxy_request_headers  s6     ,,&&++-t88:;r/   c                     i S )zCAdd additional request headers. Typically overridden in subclasses.r`   r+   s    r-   r	  z)ProxyHandler.get_request_headers_override$  s    	r/   c                     t        ddd      S )z}A dictionary of options to be used when constructing
        a tornado.httpclient.HTTPRequest instance for the proxy request.Fg     @o@g     r@)follow_redirectsconnect_timeoutrequest_timeout)dictr+   s    r-   r   z"ProxyHandler.proxy_request_options(  s     "E5
 	
r/   c                      y)zi
        http://www.tornadoweb.org/en/stable/guide/security.html

        Defer to proxied apps.
        Nr`   r+   s    r-   check_xsrf_cookiezProxyHandler.check_xsrf_cookie/  r   r/   c                 f    |r|nd| _         |r$| j                  j                  d| d       |d   S y)a  
        Select a single Sec-WebSocket-Protocol during handshake.

        Overrides `tornado.websocket.WebSocketHandler.select_subprotocol` that
        includes an informative docstring:
        https://github.com/tornadoweb/tornado/blob/v6.4.0/tornado/websocket.py#L337-L360.
        NzClient sent subprotocols: z, selecting the firstr   )rl   r   r   )r,   r  s     r-   select_subprotocolzProxyHandler.select_subprotocol6  s@     8D|$HHNN,\N:OP  ?"r/   r)   )rd   )!rL   rM   rN   rO   r   rD   rn   rv   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r   r	  r   r  r  rR   rS   s   @r-   rb   rb   a   s    	 K	*9VBB




XVWYN	.A6H$>./L4\O+b
r/   rb   c                   R     e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Z fd
Z xZS )LocalProxyHandleraN  
    A tornado request handler that proxies HTTP and websockets
    from a port on the local system. Same as the above ProxyHandler,
    but specific to 'localhost'.

    The arguments "port" and "proxied_path" in each method are extracted from
    the URL as capture groups in the regex specified in the add_handlers
    method.
    c                 B   K   | j                  ||       d {   S 7 wr)   r   rs   s      r-   r   zLocalProxyHandler.http_get^  s     ZZl3333s   c                 D   K   | j                  d||       d {   S 7 wNrg   r  rs   s      r-   rv   zLocalProxyHandler.opena  s     __[$EEEE     c                 &    | j                  ||      S r)   r  rs   s      r-   r   zLocalProxyHandler.postd      zz$--r/   c                 &    | j                  ||      S r)   r  rs   s      r-   r   zLocalProxyHandler.putg  r  r/   c                 &    | j                  ||      S r)   r  rs   s      r-   r   zLocalProxyHandler.deletej  r  r/   c                 &    | j                  ||      S r)   r  rs   s      r-   r   zLocalProxyHandler.headm  r  r/   c                 &    | j                  ||      S r)   r  rs   s      r-   r   zLocalProxyHandler.patchp  r  r/   c                 &    | j                  ||      S r)   r  rs   s      r-   r   zLocalProxyHandler.optionss  r  r/   c                 &    t         |   d||      S r  rC   r   )r,   rt   ru   rH   s      r-   r   zLocalProxyHandler.proxyv  s    w}[$==r/   )rL   rM   rN   rO   r   rv   r   r   r   r   r   r   r   rR   rS   s   @r-   r  r  S  s;    4F......> >r/   r  c                   R     e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Z fd
Z xZS )RemoteProxyHandlera  
    A tornado request handler that proxies HTTP and websockets
    from a port on a specified remote system.

    The arguments "host", "port" and "proxied_path" in each method are
    extracted from the URL as capture groups in the regex specified in the
    add_handlers method.
    c                 D   K   | j                  |||       d {   S 7 wr)   r  r,   r   rt   ru   s       r-   r   zRemoteProxyHandler.http_get  s     ZZdL9999r  c                 (    | j                  |||      S r)   r  r(  s       r-   r   zRemoteProxyHandler.post      zz$l33r/   c                 (    | j                  |||      S r)   r  r(  s       r-   r   zRemoteProxyHandler.put  r*  r/   c                 (    | j                  |||      S r)   r  r(  s       r-   r   zRemoteProxyHandler.delete  r*  r/   c                 (    | j                  |||      S r)   r  r(  s       r-   r   zRemoteProxyHandler.head  r*  r/   c                 (    | j                  |||      S r)   r  r(  s       r-   r   zRemoteProxyHandler.patch  r*  r/   c                 (    | j                  |||      S r)   r  r(  s       r-   r   zRemoteProxyHandler.options  r*  r/   c                 D   K   | j                  |||       d {   S 7 wr)   r  r(  s       r-   rv   zRemoteProxyHandler.open  s     __T4>>>>r  c                 &    t         |   |||      S r)   r$  )r,   r   rt   ru   rH   s       r-   r   zRemoteProxyHandler.proxy  s    w}T466r/   )rL   rM   rN   rO   r   r   r   r   r   r   r   rv   r   rR   rS   s   @r-   r&  r&  z  s:    :444444?7 7r/   r&  c                   z     e Zd ZdZdZi Zed        Zd Zd Z	 fdZ
d Z fdZd	 Zd
 Zd Zd Zd Zd Z xZS )NamedLocalProxyHandlera^  
    A tornado request handler that proxies HTTP and websockets from a port on
    the local system. The port is specified in config, and associated with a
    name which forms part of the URL.

    Config will create a subclass of this for each named proxy. A further
    subclass below is used for named proxies where we also start the server.
    r   c                 R    | j                   | j                  xs d| j                  dS )Nrd   rt   r   r   r5  r+   s    r-   process_argsz#NamedLocalProxyHandler.process_args  s*     II ,,2
 	
r/   c                    | j                   }t        |      t        u r |j                  di |S t        |      t        u r|D cg c]  }| j                  |       c}S t        |      t        u rB|j                         D ci c]&  \  }}| j                  |      | j                  |      ( c}}S t        dt        |             c c}w c c}}w )NzValue of unrecognized type r`   )	r6  r   r   r   r   _render_templater  items
ValueError)r,   valuerF   r   ks        r-   r8  z'NamedLocalProxyHandler._render_template  s      ;#5<<'$''%[D 6;<D))!,<<%[D  "KKMAq %%a($*?*?*BB 
 :4;-HII =s   C
+Cc                 f    t        |      rt        || j                        }| j                  |      S )z5Call any callables, then render any templated values.)r   r   r6  r8  )r,   	attributes     r-   _realize_rendered_templatez1NamedLocalProxyHandler._realize_rendered_template  s-    I,Y8I8IJI$$Y//r/   c                 *  K   |j                  d      sd|z   }| j                  rJt        | j                        rt        | j                  d|i      }n| j                  j	                  ||      }t        t        |   ||             d {   S 7 w)NrW   rX   )r   mappathr   r   r?   r   rC   r   r,   rt   rX   rH   s      r-   r   zNamedLocalProxyHandler.proxy  su     s#:D<<%+DLL64.I||''d3!%'-d";<<<<s   B	BBBc                 h   K   t        | j                  | j                  |             d {   S 7 wr)   )r   r   rt   r,   rX   s     r-   r   zNamedLocalProxyHandler.http_get  s&     !$**TYY"=>>>>s   )202c                 T   K   t         |   | j                  |       d {   S 7 wr)   )rC   rv   rt   r,   rX   rH   s     r-   rv   zNamedLocalProxyHandler.open  s"     W\$))T2222s   (&(c                 :    | j                  | j                  |      S r)   r   rt   rD  s     r-   r   zNamedLocalProxyHandler.post      zz$))T**r/   c                 :    | j                  | j                  |      S r)   rH  rD  s     r-   r   zNamedLocalProxyHandler.put  rI  r/   c                 :    | j                  | j                  |      S r)   rH  rD  s     r-   r   zNamedLocalProxyHandler.delete  rI  r/   c                 :    | j                  | j                  |      S r)   rH  rD  s     r-   r   zNamedLocalProxyHandler.head  rI  r/   c                 :    | j                  | j                  |      S r)   rH  rD  s     r-   r   zNamedLocalProxyHandler.patch  rI  r/   c                 :    | j                  | j                  |      S r)   rH  rD  s     r-   r   zNamedLocalProxyHandler.options  rI  r/   )rL   rM   rN   rO   rt   rA  propertyr6  r8  r?  r   r   rv   r   r   r   r   r   r   rR   rS   s   @r-   r3  r3    s^     DG
 
J0	=?3++++++r/   r3  c                        e Zd ZdZ fdZd ZdZed        Zed        Z	d Z
d Zd	 Zd
 Zd Zd Z fdZ fdZ xZS )SuperviseAndProxyHandlera  
    A tornado request handler that proxies HTTP and websockets from a local
    process which is launched on demand to handle requests. The command and
    other process options are specified in config.

    A subclass of this will be made for each configured server process.
    c                 l    d| _         d| _        i | _        t               | _        t        |   |i | y )Nr   F)requested_portrequested_unix_socketrA  r   commandrC   rD   rE   s      r-   rD   z!SuperviseAndProxyHandler.__init__  s5    %*"v$)&)r/   c                 6    || _         d|vrt               |d<   y y )N	proc_lock)stater   )r,   rX  s     r-   
initializez#SuperviseAndProxyHandler.initialize  s"    
e#!%E+ $r/   processc                 d   | j                   ryd| j                  vr| j                  r| j                  | j                  d<   nat        j                         }|j	                  d| j                  f       |j                         d   | j                  d<   |j                          | j                  d   S )zj
        Allocate either the requested port or a random empty port for use by
        application
        r   rt   rd   r   )rT  rX  rS  socketbindgetsocknamer   )r,   socks     r-   rt   zSuperviseAndProxyHandler.port  s     %%#""%)%8%8

6"}}		2t2234%)%5%5%7%:

6"

zz&!!r/   c                    d| j                   vre| j                  du r-t        d      }t        j                  j                  |d      }n| j                  r| j                  }nd }|| j                   d<   | j                   d   S )Nr   Tzjupyter-server-proxy-)prefixr\  )rX  rT  r   osrX   join)r,   sock_dir	sock_paths      r-   r   z$SuperviseAndProxyHandler.unix_socket  sq    

*))T1"*ABGGLL8<	++ 66	 	(1DJJ}%zz-((r/   c                 8    | j                  | j                        S r)   )r?  rU  r+   s    r-   get_cmdz SuperviseAndProxyHandler.get_cmd&  s    ..t||<<r/   c                 *    t        j                         S )zGet the current working directory for our process

        Override in subclass to launch the process in a directory
        other than the current.
        )rb  getcwdr+   s    r-   get_cwdz SuperviseAndProxyHandler.get_cwd)  s     yy{r/   c                     i S )z[Set up extra environment variables for process. Typically
        overridden in subclasses.r`   r+   s    r-   get_envz SuperviseAndProxyHandler.get_env1  s	     	r/   c                      y)zU
        Return timeout (in s) to wait before giving up on process readiness
           r`   r+   s    r-   get_timeoutz$SuperviseAndProxyHandler.get_timeout6  s     r/   c                   K   | j                   "d}t        j                  | j                         }nd| j                   }d }t        j                  |      4 d {   }	 |j                  |d      4 d {   }| j                  j                  d|j                   d|        	 d d d       d {    d d d       d {    y7 n7 S7 7 # 1 d {  7  sw Y   nxY wnI# t        j                  $ r3 | j                  j                  d	| d
       Y d d d       d {  7   yw xY wd d d       d {  7   y # 1 d {  7  sw Y   y xY ww)Nzhttp://localhostzhttp://localhost:)	connectorF)allow_redirectsz	Got code z back from TzConnection to z refused)
r   aiohttpUnixConnectorrt   ClientSessionr?   r   r   statusClientConnectionError)r,   pr   rq  sessionresps         r-   _http_ready_funcz)SuperviseAndProxyHandler._http_ready_func<  s?    '$C--d.>.>?I%dii[1CI((9= 		 		";;sE;B    d HHNNYt{{m;se#LM	   		 		 		   		       
 00 uH=>		 		 				 		 		 		 		s   AECE E"C)9C:C)=-C*C)5C6C):ECEC)C)EC%	CC%	!C)(E)2D/EE'D*(E.D//E2E=E >EE
EEEc           	      D  K   | j                   d   4 d{    d| j                   vr/| j                         }|s!d| j                   d<   	 ddd      d{    yt        j                  j	                         }|j                  | j                                | j                         }t        | j                  g||| j                  || j                  d}|| j                   d<   	 |j                          d{    |j                          d{   }|s<|j                          d{    t        j                   dd| j                   d      	 ddd      d{    y7 T7 7 r7 \7 D#  | j                   d=  xY w7 $# 1 d{  7  sw Y   yxY ww)	z#
        Start the process
        rW  Nprocz+process not managed by jupyter-server-proxy)env
ready_funcready_timeoutr   r   zcould not start z in time)rX  rg  rb  environr   r  rl  ro  r   namer{  r   startreadykillr   r   )r,   cmd
server_envtimeoutr}  is_readys         r-   ensure_processz'SuperviseAndProxyHandler.ensure_processN  s~     ::k* (	 (	TZZ' lln)VDJJv&(	 (	 (	  ZZ__.
!!$,,.1**,(II ##44") &*

6"**,&&%)ZZ\1H#"iik))!mmC3CDII;h1WXX $E(	 (	 (	 (	< '1 *

6*Q(	 (	 (	 (	s   F E*F 2FF E-F BF*E6=E0>E6E2E6/E40(E6FF $F	%F -F 0E62E64E66FF	F FFFF c                    K   | j                          d {    t        t        |   ||             d {   S 7 %7 wr)   )r  r   rC   r   rB  s      r-   r   zSuperviseAndProxyHandler.proxy  s;     !!###!%'-d";<<< 	$<s   A= A?AAc                 r   K   | j                          d {    t        | 	  |       d {   S 7 7 wr)   )r  rC   rv   rF  s     r-   rv   zSuperviseAndProxyHandler.open  s4     !!###W\$''' 	$'s   737577)rL   rM   rN   rO   rD   rY  r  rO  rt   r   rg  rj  rl  ro  r{  r  r   rv   rR   rS   s   @r-   rQ  rQ    sm    *(
 D" "& 
) 
)=
$0d=( (r/   rQ  c                 l   |j                   }|j                  }| j                  dt        | j                  d   d      t
        d||dft        | j                  d   d      t
        d||dft        | j                  d   d      t        d|d	ft        | j                  d   d
      t        d|d	fg       y )Nz.*r   z/proxy/([^/:@]+):(\d+)(/.*|)F)re   rf   rh   z%/proxy/absolute/([^/:@]+):(\d+)(/.*|)Tz/proxy/(\d+)(/.*|))re   rh   z/proxy/absolute/(\d+)(/.*|))rf   non_service_rewrite_responseadd_handlersr   r   r&  r  )web_appserverproxy_configrf   rh   s       r-   setup_handlersr    s    '66N)FF $$Z03 #$)&4(8 $$Z0< #$(&4(8 $$Z0) "$)(8
 $$Z02 "$((8
I/	
2r/   )5rO   rb  r\  asyncior   r   tempfiler   urllib.parser   r   r	   rs  jupyter_server.base.handlersr
   r   jupyter_server.utilsr   r   simpervisorr   tornador   r   r   tornado.simple_httpclientr   	traitletsr   r   r   r   r   r   r   r   traitlets.traitletsr   unixsockr   utilsr   r{   r    r!   r#   rU   rb   r  r&  r3  rQ  r  r`   r/   r-   <module>r     s    
     4 4  ? < ) - - ; V V V ) " ' A8 8v(n (o(. od$> $>N#7 #7LJ+. J+\X(5 X(v5r/   