Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Respect settings.py:FORCE_SCRIPT_NAME #21

Merged
merged 7 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ Using the following categories, list your changes in this order:

### Fixed

- Fix compatibility with third-party sync only middleware
- Django middleware now only runs in async mode to avoid clashing with Django's internal usage of `asgiref.AsyncToSync`
- Fix Django compatibility with third-party sync middleware
- ServeStatic Django middleware now only runs in async mode to avoid clashing with Django's internal usage of `asgiref.AsyncToSync`
- Respect Django `settings.py:FORCE_SCRIPT_NAME` configuration value ([Upstream PR](https://github.com/evansd/whitenoise/pull/486))

## [1.1.0](https://github.com/Archmonger/ServeStatic/compare/1.0.0...1.1.0) - 2024-08-27

Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ It's designed to work nicely with a CDN for high-traffic sites so you don't have

`ServeStatic` automatically takes care of best-practices for you, for instance:

- Serving compressed content (gzip and Brotli formats, handling Accept-Encoding and Vary headers correctly)
- Setting far-future cache headers on content which won't change
- Serving compressed content (gzip and Brotli formats, handling Accept-Encoding and Vary headers correctly)
- Setting far-future cache headers on content which won't change

Worried that serving static files with Python is horribly inefficient? Still think you should be using Amazon S3? Have a look at the FAQ below.

Expand Down Expand Up @@ -58,4 +58,4 @@ None of this is rocket science, but it's fiddly and annoying and `ServeStatic` t

---

_This project is a fork of [WhiteNoise](https://github.com/evansd/whitenoise) for continued maintenience and feature updates._
_This project is a fork of [WhiteNoise](https://github.com/evansd/whitenoise) for continued maintenance and feature updates._
14 changes: 7 additions & 7 deletions docs/src/django-settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,23 @@ Don't use this for the bulk of your static files because you won't benefit from

## `SERVESTATIC_AUTOREFRESH`

**Default:** `settings.DEBUG`
**Default:** `settings.py:DEBUG`

Recheck the filesystem to see if any files have changed before responding. This is designed to be used in development where it can be convenient to pick up changes to static files without restarting the server. For both performance and security reasons, this setting should not be used in production.

---

## `SERVESTATIC_USE_FINDERS`

**Default:** `settings.DEBUG`
**Default:** `settings.py:DEBUG`

Instead of only picking up files collected into `STATIC_ROOT`, find and serve files in their original directories using Django's "finders" API. This is useful in development where it matches the behaviour of the old `runserver` command. It's also possible to use this setting in production, avoiding the need to run the `collectstatic` command during the build, so long as you do not wish to use any of the caching and compression features provided by the storage backends.

---

## `SERVESTATIC_MAX_AGE`

**Default:** `60 if not settings.DEBUG else 0`
**Default:** `60 if not settings.py:DEBUG else 0`

Time (in seconds) for which browsers and proxies should cache **non-versioned** files.

Expand Down Expand Up @@ -160,15 +160,15 @@ SERVESTATIC_IMMUTABLE_FILE_TEST = immutable_file_test

## `SERVESTATIC_STATIC_PREFIX`

**Default:** Path component of `settings.STATIC_URL` (with `settings.FORCE_SCRIPT_NAME` removed if set)
**Default:** `settings.py:STATIC_URL`

The URL prefix under which static files will be served.

Usually this can be determined automatically by using the path component of `STATIC_URL`. So if `STATIC_URL` is `https://example.com/static/` then `SERVESTATIC_STATIC_PREFIX` will be `/static/`.
If this setting is unset, this value will automatically determined by analysing your `STATIC_URL` setting. For example, if `STATIC_URL = 'https://example.com/static/'` then `SERVESTATIC_STATIC_PREFIX` will be `/static/`.

If your application is not running at the root of the domain and `FORCE_SCRIPT_NAME` is set then this value will be removed from the `STATIC_URL` path first to give the correct prefix.
Note that `FORCE_SCRIPT_NAME` is also taken into account when automatically determining this value. For example, if `FORCE_SCRIPT_NAME = 'subdir/'` and `STATIC_URL = 'subdir/static/'` then `SERVESTATIC_STATIC_PREFIX` will be `/static/`.

If your deployment is more complicated than this (for instance, if you are using a CDN which is doing path rewriting) then you may need to configure this value directly.
If your deployment is more complicated than this (for instance, if you are using a CDN which is doing [path rewriting](https://blog.nginx.org/blog/creating-nginx-rewrite-rules)) then you may need to configure this value directly.

---

Expand Down
9 changes: 4 additions & 5 deletions src/servestatic/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from django.contrib.staticfiles import finders
from django.contrib.staticfiles.storage import staticfiles_storage
from django.http import FileResponse
from django.urls import get_script_prefix

from servestatic.responders import MissingFileError

Expand Down Expand Up @@ -144,10 +143,10 @@ def __init__(self, get_response, settings=settings):
self.static_prefix = settings.SERVESTATIC_STATIC_PREFIX
except AttributeError:
self.static_prefix = urlparse(settings.STATIC_URL or "").path
script_prefix = get_script_prefix().rstrip("/")
if script_prefix:
if self.static_prefix.startswith(script_prefix):
self.static_prefix = self.static_prefix[len(script_prefix) :]
if settings.FORCE_SCRIPT_NAME:
script_name = settings.FORCE_SCRIPT_NAME.rstrip("/")
if self.static_prefix.startswith(script_name):
self.static_prefix = self.static_prefix[len(script_name) :]
self.static_prefix = ensure_leading_trailing_slash(self.static_prefix)

self.static_root = settings.STATIC_ROOT
Expand Down
9 changes: 9 additions & 0 deletions tests/test_django_whitenoise.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,3 +269,12 @@ def test_error_message(server):
)
assert "•" in response_content
assert str(Path(__file__).parent / "test_files" / "static") in response_content


@override_settings(FORCE_SCRIPT_NAME="/subdir", STATIC_URL="static/")
def test_force_script_name(server, static_files, _collect_static):
url = storage.staticfiles_storage.url(static_files.js_path)
assert url.startswith("/subdir/static/")
response = server.get(url)
assert "/subdir" in response.url
assert response.content == static_files.js_content
Loading