Merge branch 'maintenance' into devel

# Conflicts:
#	CHANGELOG.md
#	src/octoprint/filemanager/storage.py
#	src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2
This commit is contained in:
Gina Häußge 2016-09-09 12:29:21 +02:00
commit b6fbbb353a
17 changed files with 408 additions and 174 deletions

View file

@ -5,7 +5,10 @@ This is a bug and feature tracker, please only use it to report bugs
or request features within OctoPrint (not OctoPi, not any OctoPrint
plugins and not unofficial OctoPrint versions). Mark requests with
a [Request] prefix in the title please. Fully fill out the bug reporting
template for bug reports.
template for bug reports. Do not delete any lines from the template but
those enclosed in [ and ] - and those please do delete, they are only
provided for your information and removing them makes your ticket more
readable :)
Do not seek support here ("I need help with ..."), that belongs on
the mailing list or the G+ community (both linked in the "guidelines
@ -17,11 +20,12 @@ Thank you!
#### What were you doing?
[Please be as specific as possible here. The maintainers will need to reproduce
your issue in order to fix it and that is not possible if they don't know
what you did to get it to happen in the first place. If you encountered
a problem with specific files of any sorts, make sure to also include a link to a file
with which to reproduce the problem.]
[Please be as specific as possible here. The maintainers will need to
reproduce your issue in order to fix it and that is not possible if they
don't know what you did to get it to happen in the first place.
If you encountered a problem with specific files of any sorts, make sure
to also include a link to a file with which to reproduce the problem.]
#### What did you expect to happen?
@ -29,7 +33,7 @@ with which to reproduce the problem.]
#### Branch & Commit or Version of OctoPrint
[Can be found in the lower left corner of the web interface.]
[Can be found in the lower left corner of the web interface. ALWAYS INCLUDE.]
#### Printer model & used firmware incl. version
@ -41,12 +45,17 @@ with which to reproduce the problem.]
#### Link to octoprint.log
[On gist.github.com or pastebin.com. Always include and never truncate.]
[On gist.github.com or pastebin.com. ALWAYS INCLUDE and never truncate.]
#### Link to contents of terminal tab or serial.log
[On gist.github.com or pastebin.com. If applicable, always include if unsure or
reporting communication issues. Never truncate.]
reporting communication issues. Never truncate.
serial.log is usually not written due to performance reasons and must be
enabled explicitly. Provide at the very least the contents of your
terminal tab at the time of the bug occurence, even if you do not have
a serial.log.]
#### Link to contents of Javascript console in the browser

View file

@ -74,6 +74,27 @@
* [#1047](https://github.com/foosel/OctoPrint/issues/1047) - Fixed 90 degree
webcam rotation for iOS Safari.
## 1.2.16rc1 (2016-09-08)
### Improvements
* [#1434](https://github.com/foosel/OctoPrint/issues/1434): Make sure to sanitize any file names in the upload folder that do not match OctoPrint's file name "sanitization standard" automatically when creating a file listing. This should solve issues with UI functionality like selecting a file for printing or deleting a file to not work with files that were uploaded manually to the ``uploads`` folder. As a side note: Please don't do this, use the ``watched`` folder if you want to SCP/FTP/copy files directly to OctoPrint.
* [#1434](https://github.com/foosel/OctoPrint/issues/1434): Allow `[` and `]` in uploaded file names.
* [#1481](https://github.com/foosel/OctoPrint/issues/1481): Bring back non-fuzzy layer time estimates in the GCODE viewer.
* Improved fuzzy print time displays in the frontend. Rounding now takes overall duration into account - durations over a day will be rounded up/down to half days, durations over an hour will be rounded up/down to half hours, durations over 30min will be rounded to 10min segments, durations below 30min will be rounded up or down to the next minute depending on the seconds and finally if we are talking about less than a minute, durations over 30s will return "less than a minute", durations under 30s will return "a couple of seconds".
* Improved intermediary loading page: Don't report server as ready and reload until preliminary caching has been done, IF preliminary caching will be done.
* Added release channels to OctoPrint's bundled Software Update plugin. You will now be able to subscribe to OctoPrint's `maintenance` or `devel` release candidates in addition to stable versions. [Read more about Release Channels on the wiki](https://github.com/foosel/OctoPrint/wiki/Using-Release-Channels).
### Bug Fixes
* [#1448](https://github.com/foosel/OctoPrint/issues/1448): Don't "eat" first line of the pause script after a pause triggering `M0` but send it to the printer instead
* [#1477](https://github.com/foosel/OctoPrint/issues/1477): Only report files enqueued for analysis which actually are (as in, don't claim to have queued STL files for GCODE analysis)
* [#1478](https://github.com/foosel/OctoPrint/issues/1478): Don't display inaccurate linear estimate ("6 days remaining") until 30 *minutes* have passed, even if nothing else is available. Potentially related to [#1428](https://github.com/foosel/OctoPrint/issues/1428).
* [#1479](https://github.com/foosel/OctoPrint/issues/1479): Make sure set cookies are post fixed with a port specific suffix and that the path they are set on takes the script root from the request into account.
* [#1483](https://github.com/foosel/OctoPrint/issues/1483): Filenames in file uploads may also now be encoded in ISO-8859-1, as defined in [RFC 7230](https://tools.ietf.org/html/rfc7230#section-3.2.4). Solves an issue when sending files with non-ASCII-characters in the file name from Slic3r.
([Commits](https://github.com/foosel/OctoPrint/compare/1.2.15...1.2.16rc1))
## 1.2.15 (2016-07-30)
### Improvements

View file

@ -123,17 +123,18 @@ following section *completely*. Thank you! :)
### What should I include in a bug report?
Always use the following template (you can remove what's within `[...]`, that's
Always use the following template (please remove what's within `[...]`, that's
only provided here as some additional information for you), **even if only adding a
"me too" to an existing ticket**:
#### What were you doing?
[Please be as specific as possible here. The maintainers will need to reproduce
your issue in order to fix it and that is not possible if they don't know
what you did to get it to happen in the first place. If you encountered
a problem with specific files of any sorts, make sure to also include a link to a file
with which to reproduce the problem.]
[Please be as specific as possible here. The maintainers will need to
reproduce your issue in order to fix it and that is not possible if they
don't know what you did to get it to happen in the first place.
If you encountered a problem with specific files of any sorts, make sure
to also include a link to a file with which to reproduce the problem.]
#### What did you expect to happen?
@ -141,7 +142,7 @@ only provided here as some additional information for you), **even if only addin
#### Branch & Commit or Version of OctoPrint
[Can be found in the lower left corner of the web interface.]
[Can be found in the lower left corner of the web interface. ALWAYS INCLUDE.]
#### Printer model & used firmware incl. version
@ -153,12 +154,17 @@ only provided here as some additional information for you), **even if only addin
#### Link to octoprint.log
[On gist.github.com or pastebin.com. Always include and never truncate.]
[On gist.github.com or pastebin.com. ALWAYS INCLUDE and never truncate.]
#### Link to contents of terminal tab or serial.log
[On gist.github.com or pastebin.com. If applicable, always include if unsure or
reporting communication issues. Never truncate.]
reporting communication issues. Never truncate.
serial.log is usually not written due to performance reasons and must be
enabled explicitly. Provide at the very least the contents of your
terminal tab at the time of the bug occurence, even if you do not have
a serial.log.]
#### Link to contents of Javascript console in the browser
@ -376,6 +382,7 @@ the local version identifier to allow for an exact determination of the active c
tickets as well, explained issue with "me too" red herrings.
* 2016-03-14: Some more requirements for PRs, and a PR template.
* 2016-06-08: New `prerelease` and `rc` branches explained.
* 2016-09-09: New `rc/*` branches explained.
## Footnotes
* [1] - If you are wondering why, the problem is that anything that you add

View file

@ -1,4 +1,4 @@
# Supporters
# Supporters
Development of this version of OctoPrint wouldn't have been possible without
[financial support by the community](http://octoprint.org/support-octoprint/) -
@ -12,11 +12,13 @@ thanks to everyone who contributed!
* Arnljot Arntsen
* Aurelio Bernal Ramírez
* Bart Zudell
* Boris Hussein
* Brad Jackson
* Brad Mooneyham
* Brent Fiegle
* Brian E. Tyler
* Charles Mitchell
* Christopher Day
* Christian Petropolis
* COLLE+McVOY
* CreativeTools
@ -33,6 +35,7 @@ thanks to everyone who contributed!
* J. Eckert
* Jason Galarneau
* Joe Korzeniewski
* Josh Daniels
* Joshua Gregory
* Kaile Riser
* Kale Stedman
@ -45,11 +48,11 @@ thanks to everyone who contributed!
* Mark Walker
* Masayoshi Mitsui
* Michael McDargh
* Miguel Angel Salmeron
* Mikey
* Miles Flavel
* Mohammed Khorakiwala
* Noe Ruiz
* Patrick McGinnis
* Paul Generes
* Peter Grace
* Peter Schmehl
@ -64,8 +67,9 @@ thanks to everyone who contributed!
* stefi davis
* Steven Pearson
* Sven Mueller
* Terrance Shaw
* Thomas Hatley
* Thomas Sanladerer
* Trent Shumay
* Xpandedreality
and 844 more wonderful people pledging on the [Patreon campaign](https://patreon.com/foosel)!
and 905 more wonderful people pledging on the [Patreon campaign](https://patreon.com/foosel)!

View file

@ -168,18 +168,10 @@ Upload file or create folder
Content-Disposition: form-data; name="file"; filename="whistle_v2.gcode"
Content-Type: application/octet-stream
;Generated with Cura_SteamEngine 13.11.2
M109 T0 S220.000000
T0
;Sliced at: Wed 11-12-2013 16:53:12
;Basic settings: Layer height: 0.2 Walls: 0.8 Fill: 20
;Print time: #P_TIME#
;Filament used: #F_AMNT#m #F_WGHT#g
;Filament cost: #F_COST#
;M190 S70 ;Uncomment to add your own bed temperature line
;M109 S220 ;Uncomment to add your own temperature line
G21 ;metric values
G90 ;absolute positioning
G21
G90
...
------WebKitFormBoundaryDeC2E3iWbTv1PwMC
Content-Disposition: form-data; name="select"
@ -195,7 +187,7 @@ Upload file or create folder
HTTP/1.1 200 OK
Content-Type: application/json
Location: http://example.com/api/files/sdcard/whistle_.gcode
Location: http://example.com/api/files/sdcard/whistle_v2.gcode
{
"files": {
@ -217,6 +209,46 @@ Upload file or create folder
}
}
},
"done": false
}
**Example with UTF-8 encoded filename following RFC 5987**
.. sourcecode:: http
POST /api/files/local HTTP/1.1
Host: example.com
X-Api-Key: abcdef...
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryDeC2E3iWbTv1PwMC
------WebKitFormBoundaryDeC2E3iWbTv1PwMC
Content-Disposition: form-data; name="file"; filename*=utf-8''20mm-%C3%BCml%C3%A4ut-b%C3%B6x.gcode
Content-Type: application/octet-stream
M109 T0 S220.000000
T0
G21
G90
...
------WebKitFormBoundaryDeC2E3iWbTv1PwMC--
.. sourcecode:: http
HTTP/1.1 200 OK
Content-Type: application/json
Location: http://example.com/api/files/local/20mm-umlaut-box.gcode
{
"files": {
"local": {
"name": "20mm-umlaut-box",
"origin": "local",
"refs": {
"resource": "http://example.com/api/files/local/whistle_v2.gcode",
"download": "http://example.com/downloads/files/local/whistle_v2.gcode"
}
}
},
"done": true
}

View file

@ -74,7 +74,19 @@ Encoding
OctoPrint uses UTF-8 as charset.
.. _sec-api-cross-origin:
That also includes headers in ``multipart/form-data`` requests, in order to allow the full UTF-8 range of characters
for uploaded filenames. If a ``multipart/form-data`` sub header cannot be decoded as UTF-8, OctoPrint will also attempt
to decode it as ISO-8859-1.
Additionally, OctoPrint supports replacing the ``filename`` field in the ``Content-Disposition`` header of a
multipart field with a ``filename*`` field following `RFC 5987, Section 3.2 <https://tools.ietf.org/html/rfc5987#section-3.2>`_,
which allows defining the charset used for encoding the filename. If both ``filename`` and ``filename*`` fields are
present, following the recommendation of the RFC ``filename*`` will be used.
For an example on how to send a request utilizing RFC 5987 for the ``filename*`` attribute, see the second example
in :ref:`Upload file <sec-api-fileops-uploadfile>`.
.. _sec-api-general-crossorigin:
Cross-origin requests
=====================

View file

@ -496,7 +496,7 @@ class LocalFileStorage(StorageInterface):
else:
path = self.basefolder
base = ""
return self._list_folder(path, base=base, filter=filter, recursive=recursive)
return self._list_folder(path, base=base, entry_filter=filter, recursive=recursive)
def add_folder(self, path, ignore_existing=True):
path, name = self.sanitize(path)
@ -805,6 +805,30 @@ class LocalFileStorage(StorageInterface):
raise ValueError("path not contained in base folder: {path}".format(**locals()))
return path
def _sanitize_entry(self, entry, path, entry_path):
sanitized = self.sanitize_name(entry)
if sanitized != entry:
# entry is not sanitized yet, let's take care of that
sanitized_path = os.path.join(path, sanitized)
sanitized_name, sanitized_ext = os.path.splitext(sanitized)
counter = 1
while os.path.exists(sanitized_path):
counter += 1
sanitized = self.sanitize_name("{}_({}){}".format(sanitized_name, counter, sanitized_ext))
sanitized_path = os.path.join(path, sanitized)
try:
shutil.move(entry_path, sanitized_path)
self._logger.info("Sanitized \"{}\" to \"{}\"".format(entry_path, sanitized_path))
return sanitized, sanitized_path
except:
self._logger.exception("Error while trying to rename \"{}\" to \"{}\", ignoring file".format(entry_path, sanitized_path))
raise
return entry, entry_path
def path_in_storage(self, path):
if isinstance(path, (tuple, list)):
path = self.join_path(*path)
@ -1044,7 +1068,10 @@ class LocalFileStorage(StorageInterface):
if metadata_dirty:
self._save_metadata(path, metadata)
def _list_folder(self, path, base="", filter=None, recursive=True):
def _list_folder(self, path, base="", entry_filter=None, recursive=True, **kwargs):
if entry_filter is None:
entry_filter = kwargs.get("filter", None)
metadata = self._get_metadata(path)
if not metadata:
metadata = dict()
@ -1058,27 +1085,11 @@ class LocalFileStorage(StorageInterface):
entry_path = os.path.join(path, entry)
sanitized = self.sanitize_name(entry)
if sanitized != entry:
# entry is not sanitized yet, let's take care of that
sanitized_path = os.path.join(path, sanitized)
sanitized_name, sanitized_ext = os.path.splitext(sanitized)
counter = 1
while os.path.exists(sanitized_path):
counter += 1
sanitized = self.sanitize_name("{}_({}){}".format(sanitized_name, counter, sanitized_ext))
sanitized_path = os.path.join(path, sanitized)
try:
shutil.move(entry_path, sanitized_path)
self._logger.info("Sanitized \"{}\" to \"{}\"".format(entry_path, sanitized_path))
entry = sanitized
entry_path = sanitized_path
except:
self._logger.exception("Error while trying to rename \"{}\" to \"{}\", ignoring file".format(entry_path, sanitized_path))
continue
try:
entry, entry_path = self._sanitize_entry(entry, path, entry_path)
except:
# error while trying to rename the file, we'll continue here and ignore it
continue
path_in_location = entry if not base else base + entry
@ -1099,7 +1110,7 @@ class LocalFileStorage(StorageInterface):
# TODO extract model hash from source if possible to recreate link
if not filter or filter(entry, entry_data):
if not entry_filter or entry_filter(entry, entry_data):
# only add files passing the optional filter
extended_entry_data = dict()
extended_entry_data.update(entry_data)
@ -1123,11 +1134,11 @@ class LocalFileStorage(StorageInterface):
type_path=["folder"]
)
if recursive:
sub_result = self._list_folder(entry_path, base=path_in_location + "/", filter=filter,
sub_result = self._list_folder(entry_path, base=path_in_location + "/", entry_filter=entry_filter,
recursive=recursive)
entry_data["children"] = sub_result
if not filter or filter(entry, entry_data):
if not entry_filter or entry_filter(entry, entry_data):
def get_size():
total_size = 0
for element in entry_data["children"].values():

View file

@ -2,5 +2,6 @@
<label class="control-label">{{ _('OctoPrint Release Channel') }}</label>
<div class="controls">
<select data-bind="value: config_releaseChannel, options: config_availableReleaseChannels, optionsText: 'name', optionsValue: 'key'"></select>
<span class="help-inline">{{ _('Make sure you have read <a href="%(url)s" target="_blank" rel="noreferrer noopener">"Using Release Channels"</a> before switching to a release channel other than "Stable"', url="https://github.com/foosel/OctoPrint/wiki/Using-Release-Channels") }}</span>
</div>
</div>

View file

@ -321,6 +321,14 @@ class ReverseProxiedEnvironment(object):
environ["HTTP_HOST"] = host
environ["SERVER_NAME"] = server
environ["SERVER_PORT"] = port
elif environ.get("HTTP_HOST", None) is not None:
# if we have a Host header, we use that and make sure our server name and port properties match it
host = environ["HTTP_HOST"]
server, port = host_to_server_and_port(host, url_scheme)
environ["SERVER_NAME"] = server
environ["SERVER_PORT"] = port
else:
# else we take a look at the server and port headers and if we have
# something there we derive the host from it
@ -335,15 +343,12 @@ class ReverseProxiedEnvironment(object):
if port is not None:
environ["SERVER_PORT"] = port
# make sure HTTP_HOST matches SERVER_NAME and SERVER_PORT
expected_server, expected_port = host_to_server_and_port(environ.get("HTTP_HOST", None), url_scheme)
if expected_server != environ["SERVER_NAME"] or expected_port != environ["SERVER_PORT"]:
# there's a difference, fix it!
if url_scheme == "http" and environ["SERVER_PORT"] == "80" or url_scheme == "https" and environ["SERVER_PORT"] == "443":
# default port for scheme, can be skipped
environ["HTTP_HOST"] = environ["SERVER_NAME"]
else:
environ["HTTP_HOST"] = environ["SERVER_NAME"] + ":" + environ["SERVER_PORT"]
# reconstruct host header
if url_scheme == "http" and environ["SERVER_PORT"] == "80" or url_scheme == "https" and environ["SERVER_PORT"] == "443":
# default port for scheme, can be skipped
environ["HTTP_HOST"] = environ["SERVER_NAME"]
else:
environ["HTTP_HOST"] = environ["SERVER_NAME"] + ":" + environ["SERVER_PORT"]
# call wrapped app with rewritten environment
return environ
@ -364,10 +369,16 @@ class OctoPrintFlaskRequest(flask.Request):
# strip cookie_suffix from all cookies in the request, return result
cookies = flask.Request.cookies.__get__(self)
def cookie_name_converter(key):
return key[:-len(self.cookie_suffix)] if key.endswith(self.cookie_suffix) else key
result = dict()
desuffixed = dict()
for key, value in cookies.items():
if key.endswith(self.cookie_suffix):
desuffixed[key[:-len(self.cookie_suffix)]] = value
else:
result[key] = value
return dict((cookie_name_converter(key), value) for key, value in cookies.items())
result.update(desuffixed)
return result
@cached_property
def server_name(self):

View file

@ -303,7 +303,7 @@ class UploadStorageFallbackHandler(tornado.web.RequestHandler):
filename = _extended_header_value(filename)
except:
# parse error, this is not RFC 5987 compliant after all
self._logger.warn("extended filename* value {!r} is not RFC 5987 compliant")
self._logger.warn("extended filename* value {!r} is not RFC 5987 compliant".format(filename))
self.send_error(400)
return
else:
@ -494,11 +494,11 @@ def _extended_header_value(value):
# RFC 5987 section 3.2
from urllib import unquote
encoding, _, value = value.split("'", 2)
return unquote(value).decode(encoding)
return unquote(octoprint.util.to_str(value, encoding="iso-8859-1")).decode(encoding)
else:
# no encoding provided, strip potentially present quotes and call it a day
return _strip_value_quotes(value)
return octoprint.util.to_unicode(_strip_value_quotes(value), encoding="utf-8")
class WsgiInputContainer(object):

View file

@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: OctoPrint\n"
"Report-Msgid-Bugs-To: i18n@octoprint.org\n"
"POT-Creation-Date: 2016-09-07 12:06+0200\n"
"PO-Revision-Date: 2016-09-07 12:09+0100\n"
"POT-Creation-Date: 2016-09-09 11:35+0200\n"
"PO-Revision-Date: 2016-09-09 11:48+0100\n"
"Last-Translator: Gina Häußge <osd@foosel.net>\n"
"Language: de\n"
"Language-Team: German (http://www.transifex.com/projects/p/octoprint/"
@ -190,7 +190,6 @@ msgid "Overwrite existing file"
msgstr "Vorhandene Datei überschreiben"
#: src/octoprint/plugins/cura/templates/cura_settings.jinja2:113
#, fuzzy
msgid ""
"\n"
" You can import your existing profile <code>.ini</code> files "
@ -738,7 +737,7 @@ msgstr "Repository-Cache TTL"
#: src/octoprint/plugins/pluginmanager/templates/pluginmanager_settings.jinja2:239
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate.jinja2:26
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2:107
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2:108
#: src/octoprint/templates/dialogs/confirmation.jinja2:11
#: src/octoprint/templates/dialogs/slicing.jinja2:50
#: src/octoprint/templates/sidebar/state.jinja2:25
@ -746,7 +745,7 @@ msgid "Cancel"
msgstr "Abbruch"
#: src/octoprint/plugins/pluginmanager/templates/pluginmanager_settings.jinja2:240
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2:108
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2:109
msgid "Save"
msgstr "Speichern"
@ -1063,7 +1062,18 @@ msgstr "Versionstracking für OctoPrint"
msgid "OctoPrint Release Channel"
msgstr "OctoPrint Release Channel"
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2:96
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2:93
#, python-format
msgid ""
"Make sure you have read <a href=\"%(url)s\" target=\"_blank\" rel="
"\"noreferrer noopener\">\"Using Release Channels\"</a> before switching to a "
"release channel other than \"Stable\""
msgstr ""
"Bitte lies <a href=\"%(url)s\" target=\"_blank\" rel=\"noreferrer noopener\">"
"\"Using Release Channels\"</a> bevor du auf einen anderen Release Channel "
"als \"Stable\" wechselst"
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2:97
msgid "Version cache TTL"
msgstr "TTL des Versionscaches"

View file

@ -103,27 +103,29 @@ class ReverseProxiedEnvironmentTest(unittest.TestCase):
"wsgi.url_scheme": "https"
}),
# server and port headers set -> host derived with port
# host set, server and port differ -> updated, standard port
({
"HTTP_X_FORWARDED_SERVER": "example2.com",
"HTTP_X_FORWARDED_PORT": "444",
"HTTP_X_FORWARDED_PROTO": "https"
}, {
"HTTP_HOST": "example2.com:444",
"SERVER_NAME": "example2.com",
"SERVER_PORT": "444",
"wsgi.url_scheme": "https"
}),
"HTTP_HOST": "example.com",
"wsgi.url_scheme": "https",
"SERVER_NAME": "localhost",
"SERVER_PORT": "80"
}, {
"HTTP_HOST": "example.com",
"SERVER_NAME": "example.com",
"SERVER_PORT": "443",
}),
# server and port headers set, standard port -> host derived, no port
# host set, server and port differ -> updated, non standard port
({
"HTTP_X_FORWARDED_SERVER": "example.com",
"HTTP_X_FORWARDED_PORT": "80",
}, {
"HTTP_HOST": "example.com",
"HTTP_HOST": "example.com:444",
"wsgi.url_scheme": "https",
"SERVER_NAME": "localhost",
"SERVER_PORT": "80"
}, {
"HTTP_HOST": "example.com:444",
"SERVER_NAME": "example.com",
"SERVER_PORT": "80",
}),
"SERVER_PORT": "444",
}),
# multiple scheme entries -> only use first one
({
@ -132,7 +134,7 @@ class ReverseProxiedEnvironmentTest(unittest.TestCase):
"wsgi.url_scheme": "https"
}),
# host = none -> should never happen but you never know...
# host = none (should never happen but you never know) -> server & port used for reconstruction
({
"HTTP_HOST": None,
"HTTP_X_FORWARDED_SERVER": "example.com",
@ -158,6 +160,67 @@ class ReverseProxiedEnvironmentTest(unittest.TestCase):
self.assertDictEqual(merged_expected, actual)
@data(
# server and port headers set -> host derived with port
({
"SERVER_NAME": "example2.com",
"SERVER_PORT": "444",
"HTTP_X_FORWARDED_PROTO": "https"
}, {
"HTTP_HOST": "example2.com:444",
"SERVER_NAME": "example2.com",
"SERVER_PORT": "444",
"wsgi.url_scheme": "https"
}),
# server and port headers set, standard port -> host derived, no port
({
"SERVER_NAME": "example.com",
"SERVER_PORT": "80",
}, {
"HTTP_HOST": "example.com",
"SERVER_NAME": "example.com",
"SERVER_PORT": "80",
}),
# server and port forwarded headers set -> host derived with port
({
"HTTP_X_FORWARDED_SERVER": "example2.com",
"HTTP_X_FORWARDED_PORT": "444",
"HTTP_X_FORWARDED_PROTO": "https"
}, {
"HTTP_HOST": "example2.com:444",
"SERVER_NAME": "example2.com",
"SERVER_PORT": "444",
"wsgi.url_scheme": "https"
}),
# server and port forwarded headers set, standard port -> host derived, no port
({
"HTTP_X_FORWARDED_SERVER": "example.com",
"HTTP_X_FORWARDED_PORT": "80",
}, {
"HTTP_HOST": "example.com",
"SERVER_NAME": "example.com",
"SERVER_PORT": "80",
}),
)
@unpack
def test_nohost(self, environ, expected):
reverse_proxied = ReverseProxiedEnvironment()
merged_environ = dict(standard_environ)
merged_environ.update(environ)
del merged_environ["HTTP_HOST"]
actual = reverse_proxied(merged_environ)
merged_expected = dict(standard_environ)
merged_expected.update(environ)
merged_expected.update(expected)
self.assertDictEqual(merged_expected, actual)
@data(
# prefix overridden
({
@ -195,57 +258,7 @@ class ReverseProxiedEnvironmentTest(unittest.TestCase):
"SERVER_PORT": "81"
}),
# server overridden
({
"server": "example.com"
}, {
}, {
"HTTP_HOST": "example.com:5000",
"SERVER_NAME": "example.com",
"SERVER_PORT": "5000"
}),
# port overridden, standard port
({
"port": "80"
}, {
}, {
"HTTP_HOST": "localhost",
"SERVER_PORT": "80"
}),
# port overridden, non standard port
({
"port": "81"
}, {
}, {
"HTTP_HOST": "localhost:81",
"SERVER_PORT": "81"
}),
# server and port overridden, default port
({
"server": "example.com",
"port": "80"
}, {
}, {
"HTTP_HOST": "example.com",
"SERVER_NAME": "example.com",
"SERVER_PORT": "80"
}),
# server and port overridden, non default port
({
"server": "example.com",
"port": "81"
}, {
}, {
"HTTP_HOST": "example.com:81",
"SERVER_NAME": "example.com",
"SERVER_PORT": "81"
}),
# prefix not really overridden
# prefix not really overridden, forwarded headers take precedence
({
"prefix": "/octoprint"
}, {
@ -253,7 +266,7 @@ class ReverseProxiedEnvironmentTest(unittest.TestCase):
}, {
}),
# scheme not really overridden
# scheme not really overridden, forwarded headers take precedence
({
"scheme": "https"
}, {
@ -261,7 +274,7 @@ class ReverseProxiedEnvironmentTest(unittest.TestCase):
}, {
}),
# scheme 2 not really overridden
# scheme 2 not really overridden, forwarded headers take precedence
({
"scheme": "https"
}, {
@ -269,7 +282,7 @@ class ReverseProxiedEnvironmentTest(unittest.TestCase):
}, {
}),
# host not really overridden
# host not really overridden, forwarded headers take precedence
({
"host": "example.com:444"
}, {
@ -277,7 +290,7 @@ class ReverseProxiedEnvironmentTest(unittest.TestCase):
}, {
}),
# server not really overridden
# server not really overridden, forwarded headers take precedence
({
"server": "example.com"
}, {
@ -285,12 +298,20 @@ class ReverseProxiedEnvironmentTest(unittest.TestCase):
}, {
}),
# port not really overridden
# port not really overridden, forwarded headers take precedence
({
"port": "444"
}, {
"HTTP_X_FORWARDED_PORT": "5000"
}, {
}),
# server and port not really overridden, Host header wins
({
"server": "example.com",
"port": "80"
}, {
}, {
})
)
@unpack
@ -308,6 +329,74 @@ class ReverseProxiedEnvironmentTest(unittest.TestCase):
self.assertDictEqual(merged_expected, actual)
@data(
# server overridden
({
"server": "example.com"
}, {
}, {
"HTTP_HOST": "example.com:5000",
"SERVER_NAME": "example.com",
"SERVER_PORT": "5000"
}),
# port overridden, standard port
({
"port": "80"
}, {
}, {
"HTTP_HOST": "localhost",
"SERVER_PORT": "80"
}),
# port overridden, non standard port
({
"port": "81"
}, {
}, {
"HTTP_HOST": "localhost:81",
"SERVER_PORT": "81"
}),
# server and port overridden, default port
({
"server": "example.com",
"port": "80"
}, {
}, {
"HTTP_HOST": "example.com",
"SERVER_NAME": "example.com",
"SERVER_PORT": "80"
}),
# server and port overridden, non default port
({
"server": "example.com",
"port": "81"
}, {
}, {
"HTTP_HOST": "example.com:81",
"SERVER_NAME": "example.com",
"SERVER_PORT": "81"
}),
)
@unpack
def test_fallbacks_nohost(self, fallbacks, environ, expected):
reverse_proxied = ReverseProxiedEnvironment(**fallbacks)
merged_environ = dict(standard_environ)
merged_environ.update(environ)
del merged_environ["HTTP_HOST"]
actual = reverse_proxied(merged_environ)
merged_expected = dict(standard_environ)
merged_expected.update(environ)
merged_expected.update(expected)
self.assertDictEqual(merged_expected, actual)
def test_header_config_ok(self):
result = ReverseProxiedEnvironment.to_header_candidates(["prefix-header1", "prefix-header2"])
self.assertEquals(result, ["HTTP_PREFIX_HEADER1", "HTTP_PREFIX_HEADER2"])
@ -344,28 +433,32 @@ class OctoPrintFlaskRequestTest(unittest.TestCase):
def test_server_name(self):
request = OctoPrintFlaskRequest(standard_environ)
self.assertEquals(request.server_name, "localhost")
self.assertEquals("localhost", request.server_name)
def test_server_port(self):
request = OctoPrintFlaskRequest(standard_environ)
self.assertEquals(request.server_port, "5000")
self.assertEquals("5000", request.server_port)
def test_cookie_suffix(self):
request = OctoPrintFlaskRequest(standard_environ)
self.assertEquals(request.cookie_suffix, "_P5000")
self.assertEquals("_P5000", request.cookie_suffix)
def test_cookies(self):
environ = dict(standard_environ)
environ["HTTP_COOKIE"] = "postfixed_P5000=postfixed_value; " \
"postfixed_wrong_P5001=postfixed_wrong_value; " \
"unpostfixed=unpostfixed_value"
"unpostfixed=unpostfixed_value; " \
"both_P5000=both_postfixed_value; " \
"both=both_unpostfixed_value;"
request = OctoPrintFlaskRequest(environ)
cookies = request.cookies
self.assertDictEqual(cookies, {"postfixed": "postfixed_value",
"postfixed_wrong_P5001": "postfixed_wrong_value",
"unpostfixed": "unpostfixed_value"})
self.assertDictEqual({"postfixed": u"postfixed_value",
"postfixed_wrong_P5001": u"postfixed_wrong_value",
"unpostfixed": u"unpostfixed_value",
"both": u"both_postfixed_value"},
cookies)
##~~

View file

@ -76,9 +76,14 @@ class StripValueQuotesTest(unittest.TestCase):
class ExtendedHeaderValueTest(unittest.TestCase):
@data(
("", u""),
(u"", u""),
(None, None),
(u'"quoted-string"', u"quoted-string"),
(u'"qüöted-string"', u"qüöted-string"),
(u"iso-8859-1'en'%A3%20rates", u"£ rates"),
(u"UTF-8''%c2%a3%20and%20%e2%82%ac%20rates", u"£ and € rates"),
('"quoted-string"', u"quoted-string"),
('"qüöted-string"', u"qüöted-string"),
("iso-8859-1'en'%A3%20rates", u"£ rates"),
("UTF-8''%c2%a3%20and%20%e2%82%ac%20rates", u"£ and € rates")
)

View file

@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: OctoPrint\n"
"Report-Msgid-Bugs-To: i18n@octoprint.org\n"
"POT-Creation-Date: 2016-09-07 12:06+0200\n"
"PO-Revision-Date: 2016-09-07 12:09+0100\n"
"POT-Creation-Date: 2016-09-09 11:35+0200\n"
"PO-Revision-Date: 2016-09-09 11:48+0100\n"
"Last-Translator: Gina Häußge <osd@foosel.net>\n"
"Language: de\n"
"Language-Team: German (http://www.transifex.com/projects/p/octoprint/"
@ -190,7 +190,6 @@ msgid "Overwrite existing file"
msgstr "Vorhandene Datei überschreiben"
#: src/octoprint/plugins/cura/templates/cura_settings.jinja2:113
#, fuzzy
msgid ""
"\n"
" You can import your existing profile <code>.ini</code> files "
@ -738,7 +737,7 @@ msgstr "Repository-Cache TTL"
#: src/octoprint/plugins/pluginmanager/templates/pluginmanager_settings.jinja2:239
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate.jinja2:26
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2:107
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2:108
#: src/octoprint/templates/dialogs/confirmation.jinja2:11
#: src/octoprint/templates/dialogs/slicing.jinja2:50
#: src/octoprint/templates/sidebar/state.jinja2:25
@ -746,7 +745,7 @@ msgid "Cancel"
msgstr "Abbruch"
#: src/octoprint/plugins/pluginmanager/templates/pluginmanager_settings.jinja2:240
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2:108
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2:109
msgid "Save"
msgstr "Speichern"
@ -1063,7 +1062,18 @@ msgstr "Versionstracking für OctoPrint"
msgid "OctoPrint Release Channel"
msgstr "OctoPrint Release Channel"
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2:96
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2:93
#, python-format
msgid ""
"Make sure you have read <a href=\"%(url)s\" target=\"_blank\" rel="
"\"noreferrer noopener\">\"Using Release Channels\"</a> before switching to a "
"release channel other than \"Stable\""
msgstr ""
"Bitte lies <a href=\"%(url)s\" target=\"_blank\" rel=\"noreferrer noopener\">"
"\"Using Release Channels\"</a> bevor du auf einen anderen Release Channel "
"als \"Stable\" wechselst"
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2:97
msgid "Version cache TTL"
msgstr "TTL des Versionscaches"

View file

@ -6,9 +6,9 @@
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: OctoPrint 1.2.16.dev36+g2256a1e\n"
"Project-Id-Version: OctoPrint 1.2.16.dev44+ge19ecb0\n"
"Report-Msgid-Bugs-To: i18n@octoprint.org\n"
"POT-Creation-Date: 2016-09-07 12:06+0200\n"
"POT-Creation-Date: 2016-09-09 11:35+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -655,7 +655,7 @@ msgstr ""
#: src/octoprint/plugins/pluginmanager/templates/pluginmanager_settings.jinja2:239
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate.jinja2:26
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2:107
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2:108
#: src/octoprint/templates/dialogs/confirmation.jinja2:11
#: src/octoprint/templates/dialogs/slicing.jinja2:50
#: src/octoprint/templates/sidebar/state.jinja2:25
@ -663,7 +663,7 @@ msgid "Cancel"
msgstr ""
#: src/octoprint/plugins/pluginmanager/templates/pluginmanager_settings.jinja2:240
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2:108
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2:109
msgid "Save"
msgstr ""
@ -935,7 +935,15 @@ msgstr ""
msgid "OctoPrint Release Channel"
msgstr ""
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2:96
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2:93
#, python-format
msgid ""
"Make sure you have read <a href=\"%(url)s\" target=\"_blank\" "
"rel=\"noreferrer noopener\">\"Using Release Channels\"</a> before "
"switching to a release channel other than \"Stable\""
msgstr ""
#: src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2:97
msgid "Version cache TTL"
msgstr ""