Skip to content

Commit

Permalink
Respect settings.py:FORCE_SCRIPT_NAME (#21)
Browse files Browse the repository at this point in the history
Co-authored-by: sarahboyce <sarahvboyce95@gmail.com>
  • Loading branch information
Archmonger and sarahboyce authored Aug 30, 2024
1 parent 4f617f8 commit 8816161
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 17 deletions.
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

0 comments on commit 8816161

Please sign in to comment.