From aa847e52ac23da72c6f24a347955695a6e834e1a Mon Sep 17 00:00:00 2001 From: Olivier Biesmans Date: Sun, 19 Mar 2017 20:08:39 +0000 Subject: [PATCH 1/7] Add reverse proxy support --- beetsplug/web/__init__.py | 39 ++++++++++++++++++++++++++++++ beetsplug/web/static/beets.js | 6 ++--- beetsplug/web/templates/index.html | 2 +- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/beetsplug/web/__init__.py b/beetsplug/web/__init__.py index bd4677bd8..e49fde046 100644 --- a/beetsplug/web/__init__.py +++ b/beetsplug/web/__init__.py @@ -327,6 +327,7 @@ class WebPlugin(BeetsPlugin): 'host': u'127.0.0.1', 'port': 8337, 'cors': '', + 'reverse_proxy': False, 'include_paths': False, }) @@ -358,9 +359,47 @@ class WebPlugin(BeetsPlugin): r"/*": {"origins": self.config['cors'].get(str)} } CORS(app) + + # Allow serving behind a reverse proxy + if self.config['reverse_proxy']: + app.wsgi_app = ReverseProxied(app.wsgi_app) + # Start the web application. app.run(host=self.config['host'].as_str(), port=self.config['port'].get(int), debug=opts.debug, threaded=True) cmd.func = func return [cmd] + +class ReverseProxied(object): + '''Wrap the application in this middleware and configure the + front-end server to add these headers, to let you quietly bind + this to a URL other than / and to an HTTP scheme that is + different than what is used locally. + + In nginx: + location /myprefix { + proxy_pass http://192.168.0.1:5001; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Scheme $scheme; + proxy_set_header X-Script-Name /myprefix; + } + + :param app: the WSGI application + ''' + def __init__(self, app): + self.app = app + + def __call__(self, environ, start_response): + script_name = environ.get('HTTP_X_SCRIPT_NAME', '') + if script_name: + environ['SCRIPT_NAME'] = script_name + path_info = environ['PATH_INFO'] + if path_info.startswith(script_name): + environ['PATH_INFO'] = path_info[len(script_name):] + + scheme = environ.get('HTTP_X_SCHEME', '') + if scheme: + environ['wsgi.url_scheme'] = scheme + return self.app(environ, start_response) diff --git a/beetsplug/web/static/beets.js b/beetsplug/web/static/beets.js index 757f2cdab..ec9aae9b3 100644 --- a/beetsplug/web/static/beets.js +++ b/beetsplug/web/static/beets.js @@ -147,7 +147,7 @@ var BeetsRouter = Backbone.Router.extend({ }, itemQuery: function(query) { var queryURL = query.split(/\s+/).map(encodeURIComponent).join('/'); - $.getJSON('/item/query/' + queryURL, function(data) { + $.getJSON('item/query/' + queryURL, function(data) { var models = _.map( data['results'], function(d) { return new Item(d); } @@ -161,7 +161,7 @@ var router = new BeetsRouter(); // Model. var Item = Backbone.Model.extend({ - urlRoot: '/item' + urlRoot: 'item' }); var Items = Backbone.Collection.extend({ model: Item @@ -264,7 +264,7 @@ var AppView = Backbone.View.extend({ $('#extra-detail').empty().append(extraDetailView.render().el); }, playItem: function(item) { - var url = '/item/' + item.get('id') + '/file'; + var url = 'item/' + item.get('id') + '/file'; $('#player audio').attr('src', url); $('#player audio').get(0).play(); diff --git a/beetsplug/web/templates/index.html b/beetsplug/web/templates/index.html index 7c37c82d6..0fdd46d15 100644 --- a/beetsplug/web/templates/index.html +++ b/beetsplug/web/templates/index.html @@ -82,7 +82,7 @@ <% } %>
File
- download + download
<% if (lyrics) { %>
Lyrics
From 68fa666644cf7fab24e89b5830f172216253a16e Mon Sep 17 00:00:00 2001 From: Olivier Biesmans Date: Sun, 19 Mar 2017 20:45:26 +0000 Subject: [PATCH 2/7] Document the `reverse_proxy' option --- docs/changelog.rst | 2 ++ docs/plugins/web.rst | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index cb8999726..b8f0a59ef 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -42,6 +42,8 @@ New features: resulting lists of tracks are concatenated. :bug:`2468` * :doc:`/plugins/missing`: A new mode lets you see missing albums from artists you have in your library. Thanks to :user:`qlyoung`. :bug:`2481` +* :doc:`plugins/web` : Add new `reverse_proxy` config option to allow serving + the web plugins under a reverse proxy. Fixes: diff --git a/docs/plugins/web.rst b/docs/plugins/web.rst index 9f1bbcd99..91b5457bf 100644 --- a/docs/plugins/web.rst +++ b/docs/plugins/web.rst @@ -63,6 +63,8 @@ configuration file. The available options are: Default: 8337. - **cors**: The CORS allowed origin (see :ref:`web-cors`, below). Default: CORS is disabled. +- **reverse_proxy**: Enable reverse proxy suppport (see :ref:`reverse-proxy`, below). + Default: reverse proxy support is disabled. - **include_paths**: If true, includes paths in item objects. Default: false. @@ -111,6 +113,26 @@ For example:: host: 0.0.0.0 cors: 'http://example.com' +.. _reverse-proxy: +Reverse Proxy support. +______________________ + +When the ``web`` plugin server is running behind a reverse proxy, you may want +the application to appear below some path other than / or let the reverse +proxy terminate TLS connections. This option lets you control this by setting +some HTTP Headers. +When ``reverse_proxy`` is enabled, the ``X-Script-Name`` and ``X-Scheme`` HTTP +headers control the ``SCRIPT_NAME`` and the ``wsgi.url_scheme`` environ keys, +respectively. + +``Nginx`` configuration that serves the web plugin under the /beets directory:: + location /beets { + proxy_pass http://127.0.0.1:8080; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Scheme $scheme; + proxy_set_header X-Script-Name /beets; + } JSON API -------- From 18b3e6a9fd4fbdcfaaf4e407099355f55c0095df Mon Sep 17 00:00:00 2001 From: obiesmans Date: Sun, 19 Mar 2017 22:00:01 +0100 Subject: [PATCH 3/7] Update changelog.rst --- docs/changelog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index b8f0a59ef..47cfddfea 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -42,7 +42,7 @@ New features: resulting lists of tracks are concatenated. :bug:`2468` * :doc:`/plugins/missing`: A new mode lets you see missing albums from artists you have in your library. Thanks to :user:`qlyoung`. :bug:`2481` -* :doc:`plugins/web` : Add new `reverse_proxy` config option to allow serving +* :doc:`/plugins/web` : Add new `reverse_proxy` config option to allow serving the web plugins under a reverse proxy. Fixes: From be85825b6033b15e0fd6ebb5e38c42abc0b95117 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sun, 19 Mar 2017 21:20:14 -0400 Subject: [PATCH 4/7] Typo and formatting fixes in docs --- docs/plugins/web.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/plugins/web.rst b/docs/plugins/web.rst index 91b5457bf..74b3e6f6e 100644 --- a/docs/plugins/web.rst +++ b/docs/plugins/web.rst @@ -63,7 +63,7 @@ configuration file. The available options are: Default: 8337. - **cors**: The CORS allowed origin (see :ref:`web-cors`, below). Default: CORS is disabled. -- **reverse_proxy**: Enable reverse proxy suppport (see :ref:`reverse-proxy`, below). +- **reverse_proxy**: Enable reverse proxy support (see :ref:`reverse-proxy`, below). Default: reverse proxy support is disabled. - **include_paths**: If true, includes paths in item objects. Default: false. @@ -114,8 +114,9 @@ For example:: cors: 'http://example.com' .. _reverse-proxy: -Reverse Proxy support. -______________________ + +Reverse Proxy Support +--------------------- When the ``web`` plugin server is running behind a reverse proxy, you may want the application to appear below some path other than / or let the reverse @@ -137,7 +138,6 @@ respectively. JSON API -------- - ``GET /item/`` ++++++++++++++ From 095f596e5c7ed6739a8f63abf595490461c01ba3 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sun, 19 Mar 2017 21:25:18 -0400 Subject: [PATCH 5/7] Clarity in the reverse_proxy docs --- docs/plugins/web.rst | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/docs/plugins/web.rst b/docs/plugins/web.rst index 74b3e6f6e..d726911aa 100644 --- a/docs/plugins/web.rst +++ b/docs/plugins/web.rst @@ -118,15 +118,19 @@ For example:: Reverse Proxy Support --------------------- -When the ``web`` plugin server is running behind a reverse proxy, you may want -the application to appear below some path other than / or let the reverse -proxy terminate TLS connections. This option lets you control this by setting -some HTTP Headers. -When ``reverse_proxy`` is enabled, the ``X-Script-Name`` and ``X-Scheme`` HTTP -headers control the ``SCRIPT_NAME`` and the ``wsgi.url_scheme`` environ keys, -respectively. +When the server is running behind a reverse proxy, you can tell the plugin to +respect forwarded headers. Specifically, this can help when you host the +plugin at a base URL other than the root ``/`` or when you use the proxy to +handle secure connections. Enable the ``reverse_proxy`` configuration option +if you do this. + +Technically, this option lets the proxy provide ``X-Script-Name`` and +``X-Scheme`` HTTP headers to control the plugin's the ``SCRIPT_NAME`` and its +``wsgi.url_scheme`` parameter. + +Here's a sample `Nginx`_ configuration that serves the web plugin under the +/beets directory:: -``Nginx`` configuration that serves the web plugin under the /beets directory:: location /beets { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; @@ -135,6 +139,8 @@ respectively. proxy_set_header X-Script-Name /beets; } +.. _Nginx: https://www.nginx.com + JSON API -------- From 9b383f87f456303824f72d571853068ae8e43f55 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sun, 19 Mar 2017 21:27:00 -0400 Subject: [PATCH 6/7] Docs: consistent description of a Boolean option --- docs/plugins/web.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/plugins/web.rst b/docs/plugins/web.rst index d726911aa..73a2b9147 100644 --- a/docs/plugins/web.rst +++ b/docs/plugins/web.rst @@ -63,8 +63,9 @@ configuration file. The available options are: Default: 8337. - **cors**: The CORS allowed origin (see :ref:`web-cors`, below). Default: CORS is disabled. -- **reverse_proxy**: Enable reverse proxy support (see :ref:`reverse-proxy`, below). - Default: reverse proxy support is disabled. +- **reverse_proxy**: If true, enable reverse proxy support (see + :ref:`reverse-proxy`, below). + Default: false. - **include_paths**: If true, includes paths in item objects. Default: false. From cf384109f0c6f0358c05b4d2a68e2c048ea168a8 Mon Sep 17 00:00:00 2001 From: Olivier Biesmans Date: Sun, 19 Mar 2017 21:16:26 +0000 Subject: [PATCH 7/7] Make falke8 happy and reference flask doc for the ReverseProxied class --- beetsplug/web/__init__.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/beetsplug/web/__init__.py b/beetsplug/web/__init__.py index e49fde046..3c18ebd5d 100644 --- a/beetsplug/web/__init__.py +++ b/beetsplug/web/__init__.py @@ -371,10 +371,11 @@ class WebPlugin(BeetsPlugin): cmd.func = func return [cmd] + class ReverseProxied(object): - '''Wrap the application in this middleware and configure the - front-end server to add these headers, to let you quietly bind - this to a URL other than / and to an HTTP scheme that is + '''Wrap the application in this middleware and configure the + front-end server to add these headers, to let you quietly bind + this to a URL other than / and to an HTTP scheme that is different than what is used locally. In nginx: @@ -386,6 +387,8 @@ class ReverseProxied(object): proxy_set_header X-Script-Name /myprefix; } + From: http://flask.pocoo.org/snippets/35/ + :param app: the WSGI application ''' def __init__(self, app):