Skip to content

Commit 364a9d1

Browse files
committed
Merge remote-tracking branch 'origin/main'
2 parents 8929f60 + 234a192 commit 364a9d1

File tree

12 files changed

+670
-607
lines changed

12 files changed

+670
-607
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ cd jupyter-server-proxy
4141
# Install package in development mode, with the latest Jupyter clients
4242
pip install -e ".[test,lab]"
4343
# Link your development version of the extension with JupyterLab and Notebook
44-
jlpm labextension develop --overwrite .
44+
jupyter labextension develop --overwrite .
4545
# Server extension must be manually installed in develop mode
4646
jupyter server extension enable jupyter_server_proxy
4747
```

docs/source/changelog.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,29 @@
11
# Changelog
22

3+
## 4.2
4+
5+
### v4.2.0 - 2024-06-11
6+
7+
This release includes an important security patch for
8+
[CVE-2024-35225 ](https://github.com/jupyterhub/jupyter-server-proxy/security/advisories/GHSA-fvcq-4x64-hqxr).
9+
10+
([full changelog](https://github.com/jupyterhub/jupyter-server-proxy/compare/v4.1.2...v4.2.0))
11+
12+
#### Maintenance and upkeep improvements
13+
14+
- Require jupyter_server 1.24+, tornado 6.1+, traitlets 5.1+ [#467](https://github.com/jupyterhub/jupyter-server-proxy/pull/467) ([@consideRatio](https://github.com/consideRatio))
15+
- Test against Python 3.12 [#450](https://github.com/jupyterhub/jupyter-server-proxy/pull/450) ([@consideRatio](https://github.com/consideRatio))
16+
17+
#### Documentation improvements
18+
19+
- Document the correct default value for new_browser_tab. [#470](https://github.com/jupyterhub/jupyter-server-proxy/pull/470) ([@ryanlovett](https://github.com/ryanlovett))
20+
21+
#### Contributors to this release
22+
23+
([GitHub contributors page for this release](https://github.com/jupyterhub/jupyter-server-proxy/graphs/contributors?from=2024-03-19&to=2024-06-08&type=c))
24+
25+
[@consideRatio](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyter-server-proxy+involves%3AconsideRatio+updated%3A2024-03-19..2024-06-08&type=Issues) | [@ryanlovett](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyter-server-proxy+involves%3Aryanlovett+updated%3A2024-03-19..2024-06-08&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyter-server-proxy+involves%3Awelcome+updated%3A2024-03-19..2024-06-08&type=Issues)
26+
327
## 4.1
428

529
### 4.1.2 - 2024-03-13

docs/source/server-process.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,15 @@ the following keys:
123123
explicit entry.
124124
2. **icon_path**
125125
Full path to an svg icon that could be used with a launcher. Currently only used by the
126-
JupyterLab launcher
126+
JupyterLab launcher, when category is "Notebook" (default) or "Console".
127127
3. **title**
128128
Title to be used for the launcher entry. Defaults to the name of the server if missing.
129+
4. **path_info**
130+
The trailing path that is appended to the user's server URL to access the proxied server.
131+
By default it is the name of the server followed by a trailing slash.
132+
5. **category**
133+
The category for the launcher item. Currently only used by the JupyterLab launcher.
134+
By default it is "Notebook".
129135

130136
### `new_browser_tab`
131137

@@ -151,6 +157,16 @@ One of:
151157
- A callable that takes any {ref}`callable arguments <server-process:callable-arguments>`,
152158
and returns a dictionary of strings that are used & treated same as above.
153159

160+
### `update_last_activity`
161+
162+
Whether to report activity from the proxy to Jupyter Server. If _True_, Jupyter Server
163+
will be notified of new activity. This is primarily used by JupyterHub for idle detection and culling.
164+
165+
Useful if you want to have a seperate way of determining activity through a
166+
proxied application.
167+
168+
Defaults to _True_.
169+
154170
(server-process:callable-arguments)=
155171

156172
### `websockify`

jupyter_server_proxy/api.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ async def get(self):
2222
"enabled": sp.launcher_entry.enabled,
2323
"title": sp.launcher_entry.title,
2424
"path_info": sp.launcher_entry.path_info,
25+
"category": sp.launcher_entry.category,
2526
},
2627
"new_browser_tab": sp.new_browser_tab,
2728
}

jupyter_server_proxy/config.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Traitlets based configuration for jupyter_server_proxy
33
"""
4+
45
import sys
56
from collections import namedtuple
67
from warnings import warn
@@ -25,7 +26,7 @@
2526

2627

2728
LauncherEntry = namedtuple(
28-
"LauncherEntry", ["enabled", "icon_path", "title", "path_info"]
29+
"LauncherEntry", ["enabled", "icon_path", "title", "path_info", "category"]
2930
)
3031
ServerProcess = namedtuple(
3132
"ServerProcess",
@@ -42,6 +43,7 @@
4243
"new_browser_tab",
4344
"request_headers_override",
4445
"rewrite_response",
46+
"update_last_activity",
4547
"websockify",
4648
],
4749
)
@@ -83,6 +85,7 @@ def __init__(self, *args, **kwargs):
8385
self.unix_socket = sp.unix_socket
8486
self.mappath = sp.mappath
8587
self.rewrite_response = sp.rewrite_response
88+
self.update_last_activity = sp.update_last_activity
8689

8790
def get_request_headers_override(self):
8891
return self._realize_rendered_template(sp.request_headers_override)
@@ -101,7 +104,11 @@ def get_entrypoint_server_processes(serverproxy_config):
101104
sps = []
102105
for entry_point in entry_points(group="jupyter_serverproxy_servers"):
103106
name = entry_point.name
104-
server_process_config = entry_point.load()()
107+
try:
108+
server_process_config = entry_point.load()()
109+
except Exception as e:
110+
warn(f"entry_point {name} was unable to be loaded: {str(e)}")
111+
continue
105112
sps.append(make_server_process(name, server_process_config, serverproxy_config))
106113
return sps
107114

@@ -142,6 +149,7 @@ def make_server_process(name, server_process_config, serverproxy_config):
142149
icon_path=le.get("icon_path"),
143150
title=le.get("title", name),
144151
path_info=le.get("path_info", name + "/"),
152+
category=le.get("category", "Notebook"),
145153
),
146154
new_browser_tab=server_process_config.get("new_browser_tab", True),
147155
request_headers_override=server_process_config.get(
@@ -151,6 +159,9 @@ def make_server_process(name, server_process_config, serverproxy_config):
151159
"rewrite_response",
152160
tuple(),
153161
),
162+
update_last_activity=server_process_config.get(
163+
"update_last_activity", True
164+
),
154165
websockify=server_process_config.get("websockify", False),
155166
)
156167

@@ -225,6 +236,10 @@ class ServerProxy(Configurable):
225236
The trailing path that is appended to the user's server URL to access the proxied server.
226237
By default it is the name of the server followed by a trailing slash.
227238
239+
category
240+
The category for the launcher item. Currently only used by the JupyterLab launcher.
241+
By default it is "Notebook".
242+
228243
new_browser_tab
229244
Set to True (default) to make the proxied server interface opened as a new browser tab. Set to False
230245
to have it open a new JupyterLab tab. This has no effect in classic notebook.
@@ -268,6 +283,9 @@ def cats_only(response, path):
268283
instead of "dogs not allowed".
269284
270285
Defaults to the empty tuple ``tuple()``.
286+
287+
update_last_activity
288+
Will cause the proxy to report activity back to jupyter server.
271289
272290
websockify
273291
Proxy websocket requests as a TCP (or unix socket) stream.

jupyter_server_proxy/handlers.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ def __init__(self, *args, **kwargs):
117117
tuple(),
118118
)
119119
self._requested_subprotocols = None
120+
self.update_last_activity = kwargs.pop("update_last_activity", True)
120121
super().__init__(*args, **kwargs)
121122

122123
# Support/use jupyter_server config arguments allow_origin and allow_origin_pat
@@ -234,7 +235,8 @@ def _record_activity(self):
234235
avoids proxied traffic being ignored by the notebook's
235236
internal idle-shutdown mechanism
236237
"""
237-
self.settings["api_last_activity"] = utcnow()
238+
if self.update_last_activity:
239+
self.settings["api_last_activity"] = utcnow()
238240

239241
def _get_context_path(self, host, port):
240242
"""
@@ -323,14 +325,11 @@ async def proxy(self, host, port, proxied_path):
323325
"""
324326

325327
if not self._check_host_allowlist(host):
326-
self.set_status(403)
327-
self.write(
328-
"Host '{host}' is not allowed. "
329-
"See https://jupyter-server-proxy.readthedocs.io/en/latest/arbitrary-ports-hosts.html for info.".format(
330-
host=host
331-
)
328+
raise web.HTTPError(
329+
403,
330+
f"Host '{host}' is not allowed. "
331+
"See https://jupyter-server-proxy.readthedocs.io/en/latest/arbitrary-ports-hosts.html for info.",
332332
)
333-
return
334333

335334
# Remove hop-by-hop headers that don't necessarily apply to the request we are making
336335
# to the backend. See https://github.com/jupyterhub/jupyter-server-proxy/pull/328
@@ -391,9 +390,7 @@ async def proxy(self, host, port, proxied_path):
391390
# Ref: https://www.tornadoweb.org/en/stable/httpclient.html#tornado.httpclient.AsyncHTTPClient.fetch
392391
if err.code == 599:
393392
self._record_activity()
394-
self.set_status(599)
395-
self.write(str(err))
396-
return
393+
raise web.HTTPError(599, str(err))
397394
else:
398395
raise
399396

@@ -402,8 +399,7 @@ async def proxy(self, host, port, proxied_path):
402399

403400
# For all non http errors...
404401
if response.error and type(response.error) is not httpclient.HTTPError:
405-
self.set_status(500)
406-
self.write(str(response.error))
402+
raise web.HTTPError(500, str(response.error))
407403
else:
408404
# Represent the original response as a RewritableResponse object.
409405
original_response = RewritableResponse(orig_response=response)

labextension/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@jupyterhub/jupyter-server-proxy",
3-
"version": "4.1.3-0.dev",
3+
"version": "4.2.1-0.dev",
44
"description": "A JupyterLab extension accompanying the PyPI package jupyter-server-proxy adding launcher items for configured server processes.",
55
"keywords": [
66
"jupyter",

labextension/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ async function activate(
202202
launcher.add({
203203
command: CommandIDs.open,
204204
args: argsForServer(server_process),
205-
category: "Notebook",
205+
category: launcher_entry.category,
206206
kernelIconUrl: launcher_entry.icon_url || void 0,
207207
});
208208
}

labextension/src/tokens.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,5 @@ export interface ILauncherEntry {
102102
path_info: string;
103103
// the `?` means this argument may not exist, but if it does, it must be a string
104104
icon_url?: string;
105+
category?: string;
105106
}

0 commit comments

Comments
 (0)