From c42fcbead3a5fc4e6fda7831839f0248432b5f62 Mon Sep 17 00:00:00 2001 From: Andreas Jaeger Date: Mon, 17 Apr 2017 19:38:14 +0200 Subject: [PATCH] Retire repo This repo was created by accident, use deb-python-oslo.middleware instead. Needed-By: I1ac1a06931c8b6dd7c2e73620a0302c29e605f03 Change-Id: I81894aea69b9d09b0977039623c26781093a397a --- .coveragerc | 8 - .gitignore | 52 - .gitreview | 4 - .mailmap | 3 - .testr.conf | 7 - CONTRIBUTING.rst | 16 - HACKING.rst | 4 - LICENSE | 175 --- README.rst | 21 - README.txt | 13 + babel.cfg | 1 - doc/source/api.rst | 19 - doc/source/conf.py | 77 - doc/source/contributing.rst | 5 - doc/source/cors.rst | 112 -- doc/source/healthcheck_plugins.rst | 16 - doc/source/history.rst | 1 - doc/source/index.rst | 22 - doc/source/installation.rst | 12 - doc/source/oslo_config.rst | 57 - oslo/__init__.py | 13 - oslo/middleware/__init__.py | 52 - oslo_middleware/__init__.py | 31 - oslo_middleware/_i18n.py | 35 - oslo_middleware/base.py | 144 -- oslo_middleware/catch_errors.py | 43 - oslo_middleware/correlation_id.py | 27 - oslo_middleware/cors.py | 452 ------ oslo_middleware/debug.py | 60 - oslo_middleware/healthcheck/__init__.py | 377 ----- oslo_middleware/healthcheck/__main__.py | 69 - .../healthcheck/disable_by_file.py | 111 -- oslo_middleware/healthcheck/pluginbase.py | 40 - oslo_middleware/http_proxy_to_wsgi.py | 91 -- .../LC_MESSAGES/oslo_middleware-log-error.po | 27 - .../locale/de/LC_MESSAGES/oslo_middleware.po | 26 - .../LC_MESSAGES/oslo_middleware-log-error.po | 27 - .../en_GB/LC_MESSAGES/oslo_middleware.po | 26 - .../LC_MESSAGES/oslo_middleware-log-error.po | 27 - .../locale/fr/LC_MESSAGES/oslo_middleware.po | 26 - .../locale/oslo_middleware-log-error.pot | 25 - oslo_middleware/locale/oslo_middleware.pot | 25 - oslo_middleware/opts.py | 157 -- oslo_middleware/request_id.py | 40 - oslo_middleware/sizelimit.py | 95 -- oslo_middleware/ssl.py | 48 - oslo_middleware/tests/__init__.py | 0 oslo_middleware/tests/test_base.py | 102 -- oslo_middleware/tests/test_catch_errors.py | 47 - oslo_middleware/tests/test_correlation_id.py | 53 - oslo_middleware/tests/test_cors.py | 1371 ----------------- oslo_middleware/tests/test_entry_points.py | 38 - oslo_middleware/tests/test_healthcheck.py | 189 --- .../tests/test_http_proxy_to_wsgi.py | 131 -- oslo_middleware/tests/test_opts.py | 31 - oslo_middleware/tests/test_request_id.py | 39 - oslo_middleware/tests/test_sizelimit.py | 108 -- oslo_middleware/tests/test_ssl.py | 57 - requirements.txt | 14 - setup.cfg | 74 - setup.py | 29 - test-requirements.txt | 12 - tox.ini | 37 - 63 files changed, 13 insertions(+), 5038 deletions(-) delete mode 100644 .coveragerc delete mode 100644 .gitignore delete mode 100644 .gitreview delete mode 100644 .mailmap delete mode 100644 .testr.conf delete mode 100644 CONTRIBUTING.rst delete mode 100644 HACKING.rst delete mode 100644 LICENSE delete mode 100644 README.rst create mode 100644 README.txt delete mode 100644 babel.cfg delete mode 100644 doc/source/api.rst delete mode 100755 doc/source/conf.py delete mode 100644 doc/source/contributing.rst delete mode 100644 doc/source/cors.rst delete mode 100644 doc/source/healthcheck_plugins.rst delete mode 100644 doc/source/history.rst delete mode 100644 doc/source/index.rst delete mode 100644 doc/source/installation.rst delete mode 100644 doc/source/oslo_config.rst delete mode 100644 oslo/__init__.py delete mode 100644 oslo/middleware/__init__.py delete mode 100644 oslo_middleware/__init__.py delete mode 100644 oslo_middleware/_i18n.py delete mode 100644 oslo_middleware/base.py delete mode 100644 oslo_middleware/catch_errors.py delete mode 100644 oslo_middleware/correlation_id.py delete mode 100644 oslo_middleware/cors.py delete mode 100644 oslo_middleware/debug.py delete mode 100644 oslo_middleware/healthcheck/__init__.py delete mode 100644 oslo_middleware/healthcheck/__main__.py delete mode 100644 oslo_middleware/healthcheck/disable_by_file.py delete mode 100644 oslo_middleware/healthcheck/pluginbase.py delete mode 100644 oslo_middleware/http_proxy_to_wsgi.py delete mode 100644 oslo_middleware/locale/de/LC_MESSAGES/oslo_middleware-log-error.po delete mode 100644 oslo_middleware/locale/de/LC_MESSAGES/oslo_middleware.po delete mode 100644 oslo_middleware/locale/en_GB/LC_MESSAGES/oslo_middleware-log-error.po delete mode 100644 oslo_middleware/locale/en_GB/LC_MESSAGES/oslo_middleware.po delete mode 100644 oslo_middleware/locale/fr/LC_MESSAGES/oslo_middleware-log-error.po delete mode 100644 oslo_middleware/locale/fr/LC_MESSAGES/oslo_middleware.po delete mode 100644 oslo_middleware/locale/oslo_middleware-log-error.pot delete mode 100644 oslo_middleware/locale/oslo_middleware.pot delete mode 100644 oslo_middleware/opts.py delete mode 100644 oslo_middleware/request_id.py delete mode 100644 oslo_middleware/sizelimit.py delete mode 100644 oslo_middleware/ssl.py delete mode 100644 oslo_middleware/tests/__init__.py delete mode 100644 oslo_middleware/tests/test_base.py delete mode 100644 oslo_middleware/tests/test_catch_errors.py delete mode 100644 oslo_middleware/tests/test_correlation_id.py delete mode 100644 oslo_middleware/tests/test_cors.py delete mode 100644 oslo_middleware/tests/test_entry_points.py delete mode 100644 oslo_middleware/tests/test_healthcheck.py delete mode 100644 oslo_middleware/tests/test_http_proxy_to_wsgi.py delete mode 100644 oslo_middleware/tests/test_opts.py delete mode 100644 oslo_middleware/tests/test_request_id.py delete mode 100644 oslo_middleware/tests/test_sizelimit.py delete mode 100644 oslo_middleware/tests/test_ssl.py delete mode 100644 requirements.txt delete mode 100644 setup.cfg delete mode 100644 setup.py delete mode 100644 test-requirements.txt delete mode 100644 tox.ini diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index e739053..0000000 --- a/.coveragerc +++ /dev/null @@ -1,8 +0,0 @@ -[run] -branch = True -source = oslo_middleware -omit = oslo_middleware/tests/* - -[report] -ignore_errors = True -precision = 2 diff --git a/.gitignore b/.gitignore deleted file mode 100644 index ed88334..0000000 --- a/.gitignore +++ /dev/null @@ -1,52 +0,0 @@ -*.py[cod] - -# C extensions -*.so - -# Packages -*.egg -*.egg-info -dist -build -eggs -parts -bin -var -sdist -develop-eggs -.installed.cfg -lib -lib64 - -# Installer logs -pip-log.txt - -# Unit test / coverage reports -.coverage -cover -.tox -nosetests.xml -.testrepository - -# Translations -*.mo - -# Mr Developer -.mr.developer.cfg -.project -.pydevproject - -# Complexity -output/*.html -output/*/index.html - -# Sphinx -doc/build - -# pbr generates these -AUTHORS -ChangeLog - -# Editors -*~ -.*.swp diff --git a/.gitreview b/.gitreview deleted file mode 100644 index 343cba3..0000000 --- a/.gitreview +++ /dev/null @@ -1,4 +0,0 @@ -[gerrit] -host=review.openstack.org -port=29418 -project=openstack/oslo.middleware.git \ No newline at end of file diff --git a/.mailmap b/.mailmap deleted file mode 100644 index cc92f17..0000000 --- a/.mailmap +++ /dev/null @@ -1,3 +0,0 @@ -# Format is: -# -# \ No newline at end of file diff --git a/.testr.conf b/.testr.conf deleted file mode 100644 index 6d83b3c..0000000 --- a/.testr.conf +++ /dev/null @@ -1,7 +0,0 @@ -[DEFAULT] -test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \ - OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \ - OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \ - ${PYTHON:-python} -m subunit.run discover -t ./ . $LISTOPT $IDOPTION -test_id_option=--load-list $IDFILE -test_list_option=--list diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index 414d566..0000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,16 +0,0 @@ -If you would like to contribute to the development of OpenStack, -you must follow the steps in this page: - - http://docs.openstack.org/infra/manual/developers.html - -Once those steps have been completed, changes to OpenStack -should be submitted for review via the Gerrit tool, following -the workflow documented at: - - http://docs.openstack.org/infra/manual/developers.html#development-workflow - -Pull requests submitted through GitHub will be ignored. - -Bugs should be filed on Launchpad, not GitHub: - - https://bugs.launchpad.net/oslo.middleware diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index f67b666..0000000 --- a/HACKING.rst +++ /dev/null @@ -1,4 +0,0 @@ -oslo.middleware Style Commandments -================================== - -Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/ diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 67db858..0000000 --- a/LICENSE +++ /dev/null @@ -1,175 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. diff --git a/README.rst b/README.rst deleted file mode 100644 index 5bd6c32..0000000 --- a/README.rst +++ /dev/null @@ -1,21 +0,0 @@ -=================================== -oslo.middleware -=================================== - -.. image:: https://img.shields.io/pypi/v/oslo.middleware.svg - :target: https://pypi.python.org/pypi/oslo.middleware/ - :alt: Latest Version - -.. image:: https://img.shields.io/pypi/dm/oslo.middleware.svg - :target: https://pypi.python.org/pypi/oslo.middleware/ - :alt: Downloads - -Oslo middleware library includes components that can be injected into -wsgi pipelines to intercept request/response flows. The base class can be -enhanced with functionality like add/delete/modification of http headers -and support for limiting size/connection etc. - -* Free software: Apache license -* Documentation: http://docs.openstack.org/developer/oslo.middleware -* Source: http://git.openstack.org/cgit/openstack/oslo.middleware -* Bugs: http://bugs.launchpad.net/oslo.middleware diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..d9381b5 --- /dev/null +++ b/README.txt @@ -0,0 +1,13 @@ +This project is no longer maintained. + +The contents of this repository are still available in the Git +source code management system. To see the contents of this +repository before it reached its end of life, please check out the +previous commit with "git checkout HEAD^1". + +Use instead the project deb-python-oslo.middleware at +http://git.openstack.org/cgit/openstack/deb-python-oslo.middleware . + +For any further questions, please email +openstack-dev@lists.openstack.org or join #openstack-dev on +Freenode. diff --git a/babel.cfg b/babel.cfg deleted file mode 100644 index efceab8..0000000 --- a/babel.cfg +++ /dev/null @@ -1 +0,0 @@ -[python: **.py] diff --git a/doc/source/api.rst b/doc/source/api.rst deleted file mode 100644 index 50ad06d..0000000 --- a/doc/source/api.rst +++ /dev/null @@ -1,19 +0,0 @@ -===== - API -===== - -.. automodule:: oslo_middleware - :members: - -Configuration Options -===================== - -RequestBodySizeLimiter -~~~~~~~~~~~~~~~~~~~~~~ - -.. show-options:: oslo.middleware.sizelimit - -SSLMiddleware -~~~~~~~~~~~~~ - -.. show-options:: oslo.middleware.ssl diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100755 index a5301af..0000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,77 +0,0 @@ -# -*- coding: utf-8 -*- -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import os -import sys - -sys.path.insert(0, os.path.abspath('../..')) -# -- General configuration ---------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [ - 'sphinx.ext.autodoc', - #'sphinx.ext.intersphinx', - 'oslosphinx', - 'oslo_config.sphinxext', - 'stevedore.sphinxext', -] - -# autodoc generation is a bit aggressive and a nuisance when doing heavy -# text edit cycles. -# execute "export SPHINX_DEBUG=1" in your terminal to disable - -# The suffix of source filenames. -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'oslo.middleware' -copyright = u'2014, OpenStack Foundation' - -# If true, '()' will be appended to :func: etc. cross-reference text. -add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -add_module_names = True - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# -- Options for HTML output -------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. -# html_theme_path = ["."] -# html_theme = '_theme' -# html_static_path = ['static'] - -# Output file base name for HTML help builder. -htmlhelp_basename = '%sdoc' % project - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass -# [howto/manual]). -latex_documents = [ - ('index', - '%s.tex' % project, - u'%s Documentation' % project, - u'OpenStack Foundation', 'manual'), -] - -# Example configuration for intersphinx: refer to the Python standard library. -#intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/doc/source/contributing.rst b/doc/source/contributing.rst deleted file mode 100644 index 2ca75d1..0000000 --- a/doc/source/contributing.rst +++ /dev/null @@ -1,5 +0,0 @@ -============== - Contributing -============== - -.. include:: ../../CONTRIBUTING.rst diff --git a/doc/source/cors.rst b/doc/source/cors.rst deleted file mode 100644 index 765a681..0000000 --- a/doc/source/cors.rst +++ /dev/null @@ -1,112 +0,0 @@ -=============== -CORS Middleware -=============== - -This middleware provides a comprehensive, configurable implementation of the -CORS_ (Cross Origin Resource Sharing) specification as oslo-supported python -wsgi middleware. - -.. note:: - - While this middleware supports the use of the `*` wildcard origin in the - specification, this feature is not recommended for security reasons. It - is provided to simplify basic use of CORS, practically meaning "I don't - care how this is used." In an intranet setting, this could lead to leakage - of data beyond the intranet and therefore should be avoided. - -Quickstart ----------- -First, include the middleware in your application:: - - from oslo_middleware import cors - - app = cors.CORS(your_wsgi_application) - -Secondly, add as many allowed origins as you would like:: - - app.add_origin(allowed_origin='https://website.example.com:443', - allow_credentials=True, - max_age=3600, - allow_methods=['GET','PUT','POST','DELETE'], - allow_headers=['X-Custom-Header'], - expose_headers=['X-Custom-Header']) - - # ... add more origins here. - - -Configuration for oslo_config ------------------------------ - -A factory method has been provided to simplify configuration of your CORS -domain, using oslo_config:: - - from oslo_middleware import cors - from oslo_config import cfg - - app = cors.CORS(your_wsgi_application, cfg.CONF) - -In your application's config file, then include a configuration block -something like this:: - - [cors] - allowed_origin=https://website.example.com:443,https://website2.example.com:443 - max_age=3600 - allow_methods=GET,POST,PUT,DELETE - allow_headers=X-Custom-Header - expose_headers=X-Custom-Header - -If your software requires specific headers or methods for proper operation, you -may include these as latent properties. These will be evaluated in addition -to any found in configuration:: - - from oslo_middleware import cors - - app = cors.CORS(your_wsgi_application) - app.set_latent(allow_headers=['X-System-Header'], - expose_headers=['X-System-Header'], - allow_methods=['GET','PATCH']) - - -Configuration for pastedeploy ------------------------------ - -If your application is using pastedeploy, the following configuration block -will add CORS support.:: - - [filter:cors] - paste.filter_factory = oslo_middleware.cors:filter_factory - allowed_origin=https://website.example.com:443,https://website2.example.com:443 - max_age=3600 - allow_methods=GET,POST,PUT,DELETE - allow_headers=X-Custom-Header - expose_headers=X-Custom-Header - -If your application is using pastedeploy, but would also like to use the -existing configuration from oslo_config in order to simplify the points of -configuration, this may be done as follows.:: - - [filter:cors] - paste.filter_factory = oslo_middleware.cors:filter_factory - oslo_config_project = oslo_project_name - - # Optional field, in case the program name is different from the project: - oslo_config_program = oslo_project_name-api - - # This method also permits setting latent properties, for any origins set - # in oslo config. - latent_allow_headers=X-Auth-Token - latent_expose_headers=X-Auth-Token - latent_methods=GET,PUT,POST - -Configuration Options ---------------------- - -.. show-options:: oslo.middleware.cors - -Module Documentation --------------------- - -.. automodule:: oslo_middleware.cors - :members: - -.. _CORS: http://www.w3.org/TR/cors/ diff --git a/doc/source/healthcheck_plugins.rst b/doc/source/healthcheck_plugins.rst deleted file mode 100644 index 3ea93c5..0000000 --- a/doc/source/healthcheck_plugins.rst +++ /dev/null @@ -1,16 +0,0 @@ -================================ - Healthcheck middleware plugins -================================ - -.. automodule:: oslo_middleware.healthcheck - :members: - -.. automodule:: oslo_middleware.healthcheck.disable_by_file - :members: - - -Available Plugins ------------------- - -.. list-plugins:: oslo.middleware.healthcheck - :detailed: diff --git a/doc/source/history.rst b/doc/source/history.rst deleted file mode 100644 index 69ed4fe..0000000 --- a/doc/source/history.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../ChangeLog diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index f53e5bd..0000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,22 +0,0 @@ -.. include:: ../../README.rst - -Contents -======== - -.. toctree:: - :maxdepth: 2 - - installation - api - healthcheck_plugins - cors - oslo_config - contributing - -Release Notes -============= - -.. toctree:: - :maxdepth: 1 - - history diff --git a/doc/source/installation.rst b/doc/source/installation.rst deleted file mode 100644 index 4fd1d47..0000000 --- a/doc/source/installation.rst +++ /dev/null @@ -1,12 +0,0 @@ -============ -Installation -============ - -At the command line:: - - $ pip install oslo.middleware - -Or, if you have virtualenvwrapper installed:: - - $ mkvirtualenv oslo.middleware - $ pip install oslo.middleware \ No newline at end of file diff --git a/doc/source/oslo_config.rst b/doc/source/oslo_config.rst deleted file mode 100644 index 6e772c6..0000000 --- a/doc/source/oslo_config.rst +++ /dev/null @@ -1,57 +0,0 @@ -============================= -Middlewares and configuration -============================= - -Middlewares can be configured in multiple fashion depending of the -application needs. Here is some use-cases: - -Configuration from the application ----------------------------------- - -The application code will looks like:: - - from oslo_middleware import sizelimit - from oslo_config import cfg - - conf = cfg.ConfigOpts() - app = sizelimit.RequestBodySizeLimiter(your_wsgi_application, conf) - - -Configuration with paste-deploy and the oslo.config ---------------------------------------------------- - -The paste filter (in /etc/my_app/api-paste.ini) will looks like:: - - [filter:sizelimit] - paste.filter_factory = oslo_middleware.sizelimit:RequestBodySizeLimiter.factory - # In case of the application doesn't use the global oslo.config - # object. The middleware must known the app name to load - # the application configuration, by setting this: - # oslo_config_project = my_app - - # In some cases, you may need to specify the program name for the project - # as well. - # oslo_config_program = my_app-api - -The oslo.config file of the application (eg: /etc/my_app/my_app.conf) will looks like:: - - [oslo_middleware] - max_request_body_size=1000 - - -Configuration with pastedeploy only ------------------------------------ - -The paste filter (in /etc/my_app/api-paste.ini) will looks like:: - - [filter:sizelimit] - paste.filter_factory = oslo_middleware.sizelimit:RequestBodySizeLimiter.factory - max_request_body_size=1000 - -This will override any configuration done via oslo.config - - -.. note:: - - healtcheck middleware does not yet use oslo.config, see :doc:`healthcheck_plugins` - diff --git a/oslo/__init__.py b/oslo/__init__.py deleted file mode 100644 index dc130d6..0000000 --- a/oslo/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -__import__('pkg_resources').declare_namespace(__name__) diff --git a/oslo/middleware/__init__.py b/oslo/middleware/__init__.py deleted file mode 100644 index 844bf9d..0000000 --- a/oslo/middleware/__init__.py +++ /dev/null @@ -1,52 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import sys -import warnings - -def deprecated(): - new_name = __name__.replace('.', '_') - warnings.warn( - ('The oslo namespace package is deprecated. Please use %s instead.' % - new_name), - DeprecationWarning, - stacklevel=3, - ) - - -# NOTE(dims): We cannot remove the deprecation or redirects below -# until Liberty-EOL -deprecated() - -from oslo_middleware import base -from oslo_middleware import catch_errors -from oslo_middleware import correlation_id -from oslo_middleware import debug -from oslo_middleware import request_id -from oslo_middleware import sizelimit - -sys.modules['oslo.middleware.base'] = base -sys.modules['oslo.middleware.catch_errors'] = catch_errors -sys.modules['oslo.middleware.correlation_id'] = correlation_id -sys.modules['oslo.middleware.debug'] = debug -sys.modules['oslo.middleware.request_id'] = request_id -sys.modules['oslo.middleware.sizelimit'] = sizelimit - -from oslo_middleware.catch_errors import CatchErrors -from oslo_middleware.correlation_id import CorrelationId -from oslo_middleware.cors import CORS -from oslo_middleware.debug import Debug -from oslo_middleware.healthcheck import Healthcheck -from oslo_middleware.http_proxy_to_wsgi import HTTPProxyToWSGI -from oslo_middleware.request_id import RequestId -from oslo_middleware.sizelimit import RequestBodySizeLimiter -from oslo_middleware.ssl import SSLMiddleware \ No newline at end of file diff --git a/oslo_middleware/__init__.py b/oslo_middleware/__init__.py deleted file mode 100644 index ea1c12d..0000000 --- a/oslo_middleware/__init__.py +++ /dev/null @@ -1,31 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -__all__ = ['CatchErrors', - 'CorrelationId', - 'CORS', - 'Debug', - 'Healthcheck', - 'HTTPProxyToWSGI', - 'RequestId', - 'RequestBodySizeLimiter', - 'SSLMiddleware'] - -from oslo_middleware.catch_errors import CatchErrors -from oslo_middleware.correlation_id import CorrelationId -from oslo_middleware.cors import CORS -from oslo_middleware.debug import Debug -from oslo_middleware.healthcheck import Healthcheck -from oslo_middleware.http_proxy_to_wsgi import HTTPProxyToWSGI -from oslo_middleware.request_id import RequestId -from oslo_middleware.sizelimit import RequestBodySizeLimiter -from oslo_middleware.ssl import SSLMiddleware diff --git a/oslo_middleware/_i18n.py b/oslo_middleware/_i18n.py deleted file mode 100644 index f9bbda1..0000000 --- a/oslo_middleware/_i18n.py +++ /dev/null @@ -1,35 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""oslo.i18n integration module. - -See http://docs.openstack.org/developer/oslo.i18n/usage.html - -""" - -import oslo_i18n - - -_translators = oslo_i18n.TranslatorFactory(domain='oslo_middleware') - -# The primary translation function using the well-known name "_" -_ = _translators.primary - -# Translators for log levels. -# -# The abbreviated names are meant to reflect the usual use of a short -# name like '_'. The "L" is for "log" and the other letter comes from -# the level. -_LI = _translators.log_info -_LW = _translators.log_warning -_LE = _translators.log_error -_LC = _translators.log_critical diff --git a/oslo_middleware/base.py b/oslo_middleware/base.py deleted file mode 100644 index 27689a1..0000000 --- a/oslo_middleware/base.py +++ /dev/null @@ -1,144 +0,0 @@ -# Copyright 2011 OpenStack Foundation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""Base class(es) for WSGI Middleware.""" - -from inspect import getargspec -import webob.dec -import webob.request -import webob.response - -from oslo_config import cfg - - -class NoContentTypeResponse(webob.response.Response): - - default_content_type = None # prevents webob assigning content type - - -class NoContentTypeRequest(webob.request.Request): - - ResponseClass = NoContentTypeResponse - - -class ConfigurableMiddleware(object): - """Base WSGI middleware wrapper. - - These classes require an application to be initialized that will be called - next. By default the middleware will simply call its wrapped app, or you - can override __call__ to customize its behavior. - """ - - @classmethod - def factory(cls, global_conf, **local_conf): - """Factory method for paste.deploy. - - :param global_conf: dict of options for all middlewares - (usually the [DEFAULT] section of the paste deploy - configuration file) - :param local_conf: options dedicated to this middleware - (usually the option defined in the middleware - section of the paste deploy configuration file) - """ - conf = global_conf.copy() if global_conf else {} - conf.update(local_conf) - - def middleware_filter(app): - return cls(app, conf) - - return middleware_filter - - def __init__(self, application, conf=None): - """Base middleware constructor - - :param conf: a dict of options or a cfg.ConfigOpts object - """ - self.application = application - - # NOTE(sileht): If the configuration come from oslo.config - # just use it. - if isinstance(conf, cfg.ConfigOpts): - self.conf = {} - self.oslo_conf = conf - else: - self.conf = conf or {} - if "oslo_config_project" in self.conf: - if 'oslo_config_file' in self.conf: - default_config_files = [self.conf['oslo_config_file']] - else: - default_config_files = None - - if 'oslo_config_program' in self.conf: - program = self.conf['oslo_config_program'] - else: - program = None - - self.oslo_conf = cfg.ConfigOpts() - self.oslo_conf([], - project=self.conf['oslo_config_project'], - prog=program, - default_config_files=default_config_files, - validate_default_values=True) - - else: - # Fallback to global object - self.oslo_conf = cfg.CONF - - def _conf_get(self, key, group="oslo_middleware"): - if key in self.conf: - # Validate value type - self.oslo_conf.set_override(key, self.conf[key], group=group, - enforce_type=True) - return getattr(getattr(self.oslo_conf, group), key) - - @staticmethod - def process_request(req): - """Called on each request. - - If this returns None, the next application down the stack will be - executed. If it returns a response then that response will be returned - and execution will stop here. - """ - return None - - @staticmethod - def process_response(response, request=None): - """Do whatever you'd like to the response.""" - return response - - @webob.dec.wsgify(RequestClass=NoContentTypeRequest) - def __call__(self, req): - response = self.process_request(req) - if response: - return response - response = req.get_response(self.application) - - (args, varargs, varkw, defaults) = getargspec(self.process_response) - if 'request' in args: - return self.process_response(response, request=req) - return self.process_response(response) - - -class Middleware(ConfigurableMiddleware): - """Legacy base WSGI middleware wrapper. - - Legacy interface that doesn't pass configuration options - to the middleware when it's loaded via paste.deploy. - """ - - @classmethod - def factory(cls, global_conf, **local_conf): - """Factory method for paste.deploy.""" - return cls diff --git a/oslo_middleware/catch_errors.py b/oslo_middleware/catch_errors.py deleted file mode 100644 index 43d085f..0000000 --- a/oslo_middleware/catch_errors.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright (c) 2013 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging - -import webob.dec -import webob.exc - -from oslo_middleware._i18n import _LE -from oslo_middleware import base - - -LOG = logging.getLogger(__name__) - - -class CatchErrors(base.ConfigurableMiddleware): - """Middleware that provides high-level error handling. - - It catches all exceptions from subsequent applications in WSGI pipeline - to hide internal errors from API response. - """ - - @webob.dec.wsgify - def __call__(self, req): - try: - response = req.get_response(self.application) - except Exception: - LOG.exception(_LE('An error occurred during ' - 'processing the request: %s'), req) - response = webob.exc.HTTPInternalServerError() - return response diff --git a/oslo_middleware/correlation_id.py b/oslo_middleware/correlation_id.py deleted file mode 100644 index 773dcba..0000000 --- a/oslo_middleware/correlation_id.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (c) 2013 Rackspace Hosting -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from oslo_middleware import base - - -class CorrelationId(base.ConfigurableMiddleware): - "Middleware that attaches a correlation id to WSGI request" - - def process_request(self, req): - correlation_id = (req.headers.get("X_CORRELATION_ID") or - str(uuid.uuid4())) - req.headers['X_CORRELATION_ID'] = correlation_id diff --git a/oslo_middleware/cors.py b/oslo_middleware/cors.py deleted file mode 100644 index 9da5d24..0000000 --- a/oslo_middleware/cors.py +++ /dev/null @@ -1,452 +0,0 @@ -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. See the License for the specific language governing permissions and -# limitations under the License. - -import copy -import logging - -import debtcollector -from oslo_config import cfg -from oslo_middleware import base -import six -import webob.exc - - -LOG = logging.getLogger(__name__) - -CORS_OPTS = [ - cfg.ListOpt('allowed_origin', - default=None, - help='Indicate whether this resource may be shared with the ' - 'domain received in the requests "origin" header. ' - 'Format: "://[:]", no trailing ' - 'slash. Example: https://horizon.example.com'), - cfg.BoolOpt('allow_credentials', - default=True, - help='Indicate that the actual request can include user ' - 'credentials'), - cfg.ListOpt('expose_headers', - default=[], - help='Indicate which headers are safe to expose to the API. ' - 'Defaults to HTTP Simple Headers.'), - cfg.IntOpt('max_age', - default=3600, - help='Maximum cache age of CORS preflight requests.'), - cfg.ListOpt('allow_methods', - default=['OPTIONS', 'GET', 'HEAD', 'POST', 'PUT', 'DELETE', - 'TRACE', 'PATCH'], # RFC 2616, RFC 5789 - help='Indicate which methods can be used during the actual ' - 'request.'), - cfg.ListOpt('allow_headers', - default=[], - help='Indicate which header field names may be used during ' - 'the actual request.') -] - - -def set_defaults(**kwargs): - """Override the default values for configuration options. - - This method permits a project to override the default CORS option values. - For example, it may wish to offer a set of sane default headers which - allow it to function with only minimal additional configuration. - - :param allow_credentials: Whether to permit credentials. - :type allow_credentials: bool - :param expose_headers: A list of headers to expose. - :type expose_headers: List of Strings - :param max_age: Maximum cache duration in seconds. - :type max_age: Int - :param allow_methods: List of HTTP methods to permit. - :type allow_methods: List of Strings - :param allow_headers: List of HTTP headers to permit from the client. - :type allow_headers: List of Strings - """ - # Since 'None' is a valid config override, we have to use kwargs. Else - # there's no good way for a user to override only one option, because all - # the others would be overridden to 'None'. - - valid_params = set(k.name for k in CORS_OPTS - if k.name != 'allowed_origin') - passed_params = set(k for k in kwargs) - - wrong_params = passed_params - valid_params - if wrong_params: - raise AttributeError('Parameter(s) [%s] invalid, please only use [%s]' - % (wrong_params, valid_params)) - - # Set global defaults. - cfg.set_defaults(CORS_OPTS, **kwargs) - - -class InvalidOriginError(Exception): - """Exception raised when Origin is invalid.""" - - def __init__(self, origin): - self.origin = origin - super(InvalidOriginError, self).__init__( - 'CORS request from origin \'%s\' not permitted.' % origin) - - -class CORS(base.ConfigurableMiddleware): - """CORS Middleware. - - This middleware allows a WSGI app to serve CORS headers for multiple - configured domains. - - For more information, see http://www.w3.org/TR/cors/ - """ - - simple_headers = [ - 'Accept', - 'Accept-Language', - 'Content-Type', - 'Cache-Control', - 'Content-Language', - 'Expires', - 'Last-Modified', - 'Pragma' - ] - - def __init__(self, application, *args, **kwargs): - super(CORS, self).__init__(application, *args, **kwargs) - # Begin constructing our configuration hash. - self.allowed_origins = {} - self._init_conf() - - def sanitize(csv_list): - try: - return [str.strip(x) for x in csv_list.split(',')] - except Exception: - return None - - self.set_latent( - allow_headers=sanitize(self.conf.get('latent_allow_headers')), - expose_headers=sanitize(self.conf.get('latent_expose_headers')), - allow_methods=sanitize(self.conf.get('latent_allow_methods')) - ) - - @classmethod - def factory(cls, global_conf, **local_conf): - """factory method for paste.deploy - - allowed_origin: Protocol, host, and port for the allowed origin. - allow_credentials: Whether to permit credentials. - expose_headers: A list of headers to expose. - max_age: Maximum cache duration. - allow_methods: List of HTTP methods to permit. - allow_headers: List of HTTP headers to permit from the client. - """ - if ('allowed_origin' not in local_conf - and 'oslo_config_project' not in local_conf): - raise TypeError("allowed_origin or oslo_config_project " - "is required") - return super(CORS, cls).factory(global_conf, **local_conf) - - def _init_conf(self): - '''Initialize this middleware from an oslo.config instance.''' - - # Set up a location for our latent configuration options - self._latent_configuration = { - 'allow_headers': [], - 'expose_headers': [], - 'methods': [] - } - - # First, check the configuration and register global options. - self.oslo_conf.register_opts(CORS_OPTS, 'cors') - - allowed_origin = self._conf_get('allowed_origin', 'cors') - allow_credentials = self._conf_get('allow_credentials', 'cors') - expose_headers = self._conf_get('expose_headers', 'cors') - max_age = self._conf_get('max_age', 'cors') - allow_methods = self._conf_get('allow_methods', 'cors') - allow_headers = self._conf_get('allow_headers', 'cors') - - # Clone our original CORS_OPTS, and set the defaults to whatever is - # set in the global conf instance. This is done explicitly (instead - # of **kwargs), since we don't accidentally want to catch - # allowed_origin. - subgroup_opts = copy.deepcopy(CORS_OPTS) - cfg.set_defaults(subgroup_opts, - allow_credentials=allow_credentials, - expose_headers=expose_headers, - max_age=max_age, - allow_methods=allow_methods, - allow_headers=allow_headers) - - # If the default configuration contains an allowed_origin, don't - # forget to register that. - self.add_origin(allowed_origin=allowed_origin, - allow_credentials=allow_credentials, - expose_headers=expose_headers, - max_age=max_age, - allow_methods=allow_methods, - allow_headers=allow_headers) - - # Iterate through all the loaded config sections, looking for ones - # prefixed with 'cors.' - for section in self.oslo_conf.list_all_sections(): - if section.startswith('cors.'): - debtcollector.deprecate('Multiple configuration blocks are ' - 'deprecated and will be removed in ' - 'future versions. Please consolidate ' - 'your configuration in the [cors] ' - 'configuration block.') - # Register with the preconstructed defaults - self.oslo_conf.register_opts(subgroup_opts, section) - self.add_origin(**self.oslo_conf[section]) - - def add_origin(self, allowed_origin, allow_credentials=True, - expose_headers=None, max_age=None, allow_methods=None, - allow_headers=None): - '''Add another origin to this filter. - - :param allowed_origin: Protocol, host, and port for the allowed origin. - :param allow_credentials: Whether to permit credentials. - :param expose_headers: A list of headers to expose. - :param max_age: Maximum cache duration. - :param allow_methods: List of HTTP methods to permit. - :param allow_headers: List of HTTP headers to permit from the client. - :return: - ''' - - # NOTE(dims): Support older code that still passes in - # a string for allowed_origin instead of a list - if isinstance(allowed_origin, six.string_types): - # TODO(krotscheck): https://review.openstack.org/#/c/312687/ - LOG.warning('DEPRECATED: The `allowed_origin` keyword argument in ' - '`add_origin()` should be a list, found String.') - allowed_origin = [allowed_origin] - - if allowed_origin: - for origin in allowed_origin: - - if origin in self.allowed_origins: - LOG.warning('Allowed origin [%s] already exists, skipping' - % (allowed_origin,)) - continue - - self.allowed_origins[origin] = { - 'allow_credentials': allow_credentials, - 'expose_headers': expose_headers, - 'max_age': max_age, - 'allow_methods': allow_methods, - 'allow_headers': allow_headers - } - - def set_latent(self, allow_headers=None, allow_methods=None, - expose_headers=None): - '''Add a new latent property for this middleware. - - Latent properties are those values which a system requires for - operation. API-specific headers, for example, may be added by an - engineer so that they ship with the codebase, and thus do not require - extra documentation or passing of institutional knowledge. - - :param allow_headers: HTTP headers permitted in client requests. - :param allow_methods: HTTP methods permitted in client requests. - :param expose_headers: HTTP Headers exposed to clients. - ''' - - if allow_headers: - if isinstance(allow_headers, list): - self._latent_configuration['allow_headers'] = allow_headers - else: - raise TypeError("allow_headers must be a list or None.") - - if expose_headers: - if isinstance(expose_headers, list): - self._latent_configuration['expose_headers'] = expose_headers - else: - raise TypeError("expose_headers must be a list or None.") - - if allow_methods: - if isinstance(allow_methods, list): - self._latent_configuration['methods'] = allow_methods - else: - raise TypeError("allow_methods parameter must be a list or" - " None.") - - def process_response(self, response, request=None): - '''Check for CORS headers, and decorate if necessary. - - Perform two checks. First, if an OPTIONS request was issued, let the - application handle it, and (if necessary) decorate the response with - preflight headers. In this case, if a 404 is thrown by the underlying - application (i.e. if the underlying application does not handle - OPTIONS requests, the response code is overridden. - - In the case of all other requests, regular request headers are applied. - ''' - - # Sanity precheck: If we detect CORS headers provided by something in - # in the middleware chain, assume that it knows better. - if 'Access-Control-Allow-Origin' in response.headers: - return response - - # Doublecheck for an OPTIONS request. - if request.method == 'OPTIONS': - return self._apply_cors_preflight_headers(request=request, - response=response) - - # Apply regular CORS headers. - self._apply_cors_request_headers(request=request, response=response) - - # Finally, return the response. - return response - - @staticmethod - def _split_header_values(request, header_name): - """Convert a comma-separated header value into a list of values.""" - values = [] - if header_name in request.headers: - for value in request.headers[header_name].rsplit(','): - value = value.strip() - if value: - values.append(value) - return values - - def _apply_cors_preflight_headers(self, request, response): - """Handle CORS Preflight (Section 6.2) - - Given a request and a response, apply the CORS preflight headers - appropriate for the request. - """ - - # If the response contains a 2XX code, we have to assume that the - # underlying middleware's response content needs to be persisted. - # Otherwise, create a new response. - if 200 > response.status_code or response.status_code >= 300: - response = base.NoContentTypeResponse(status=webob.exc.HTTPOk.code) - - # Does the request have an origin header? (Section 6.2.1) - if 'Origin' not in request.headers: - return response - - # Is this origin registered? (Section 6.2.2) - try: - origin, cors_config = self._get_cors_config_by_origin( - request.headers['Origin']) - except InvalidOriginError: - return response - - # If there's no request method, exit. (Section 6.2.3) - if 'Access-Control-Request-Method' not in request.headers: - LOG.debug('CORS request does not contain ' - 'Access-Control-Request-Method header.') - return response - request_method = request.headers['Access-Control-Request-Method'] - - # Extract Request headers. If parsing fails, exit. (Section 6.2.4) - try: - request_headers = \ - self._split_header_values(request, - 'Access-Control-Request-Headers') - except Exception: - LOG.debug('Cannot parse request headers.') - return response - - # Compare request method to permitted methods (Section 6.2.5) - permitted_methods = ( - cors_config['allow_methods'] + - self._latent_configuration['methods'] - ) - if request_method not in permitted_methods: - LOG.debug('Request method \'%s\' not in permitted list: %s' - % (request_method, permitted_methods)) - return response - - # Compare request headers to permitted headers, case-insensitively. - # (Section 6.2.6) - permitted_headers = [header.upper() for header in - (cors_config['allow_headers'] + - self.simple_headers + - self._latent_configuration['allow_headers'])] - for requested_header in request_headers: - upper_header = requested_header.upper() - if upper_header not in permitted_headers: - LOG.debug('Request header \'%s\' not in permitted list: %s' - % (requested_header, permitted_headers)) - return response - - # Set the default origin permission headers. (Sections 6.2.7, 6.4) - response.headers['Vary'] = 'Origin' - response.headers['Access-Control-Allow-Origin'] = origin - - # Does this CORS configuration permit credentials? (Section 6.2.7) - if cors_config['allow_credentials']: - response.headers['Access-Control-Allow-Credentials'] = 'true' - - # Attach Access-Control-Max-Age if appropriate. (Section 6.2.8) - if 'max_age' in cors_config and cors_config['max_age']: - response.headers['Access-Control-Max-Age'] = \ - str(cors_config['max_age']) - - # Attach Access-Control-Allow-Methods. (Section 6.2.9) - response.headers['Access-Control-Allow-Methods'] = request_method - - # Attach Access-Control-Allow-Headers. (Section 6.2.10) - if request_headers: - response.headers['Access-Control-Allow-Headers'] = \ - ','.join(request_headers) - - return response - - def _get_cors_config_by_origin(self, origin): - if origin not in self.allowed_origins: - if '*' in self.allowed_origins: - origin = '*' - else: - LOG.debug('CORS request from origin \'%s\' not permitted.' - % origin) - raise InvalidOriginError(origin) - return origin, self.allowed_origins[origin] - - def _apply_cors_request_headers(self, request, response): - """Handle Basic CORS Request (Section 6.1) - - Given a request and a response, apply the CORS headers appropriate - for the request to the response. - """ - - # Does the request have an origin header? (Section 6.1.1) - if 'Origin' not in request.headers: - return - - # Is this origin registered? (Section 6.1.2) - try: - origin, cors_config = self._get_cors_config_by_origin( - request.headers['Origin']) - except InvalidOriginError: - return - - # Set the default origin permission headers. (Sections 6.1.3 & 6.4) - if 'Vary' in response.headers: - response.headers['Vary'] += ',Origin' - else: - response.headers['Vary'] = 'Origin' - response.headers['Access-Control-Allow-Origin'] = origin - - # Does this CORS configuration permit credentials? (Section 6.1.3) - if cors_config['allow_credentials']: - response.headers['Access-Control-Allow-Credentials'] = 'true' - - # Attach the exposed headers and exit. (Section 6.1.4) - if cors_config['expose_headers']: - response.headers['Access-Control-Expose-Headers'] = \ - ','.join(cors_config['expose_headers'] + - self._latent_configuration['expose_headers']) - -# NOTE(sileht): Shortcut for backwards compatibility -filter_factory = CORS.factory diff --git a/oslo_middleware/debug.py b/oslo_middleware/debug.py deleted file mode 100644 index fb2fc82..0000000 --- a/oslo_middleware/debug.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2011 OpenStack Foundation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""Debug middleware""" - -from __future__ import print_function - -import sys - -import six -import webob.dec - -from oslo_middleware import base - - -class Debug(base.ConfigurableMiddleware): - """Helper class that returns debug information. - - Can be inserted into any WSGI application chain to get information about - the request and response. - """ - - @webob.dec.wsgify - def __call__(self, req): - print(("*" * 40) + " REQUEST ENVIRON") - for key, value in req.environ.items(): - print(key, "=", value) - print() - resp = req.get_response(self.application) - - print(("*" * 40) + " RESPONSE HEADERS") - for (key, value) in six.iteritems(resp.headers): - print(key, "=", value) - print() - - resp.app_iter = self.print_generator(resp.app_iter) - - return resp - - @staticmethod - def print_generator(app_iter): - """Prints the contents of a wrapper string iterator when iterated.""" - print(("*" * 40) + " BODY") - for part in app_iter: - sys.stdout.write(part) - sys.stdout.flush() - yield part - print() diff --git a/oslo_middleware/healthcheck/__init__.py b/oslo_middleware/healthcheck/__init__.py deleted file mode 100644 index a821233..0000000 --- a/oslo_middleware/healthcheck/__init__.py +++ /dev/null @@ -1,377 +0,0 @@ -# Copyright 2011 OpenStack Foundation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import collections -import gc -import json -import platform -import socket -import sys -import traceback - -import jinja2 -from oslo_utils import reflection -from oslo_utils import strutils -from oslo_utils import timeutils -import six -import stevedore -import webob.dec -import webob.exc -import webob.response - -try: - import greenlet -except ImportError: - greenlet = None - -from oslo_middleware import base - - -def _find_objects(t): - return [o for o in gc.get_objects() if isinstance(o, t)] - - -def _expand_template(contents, params): - tpl = jinja2.Template(source=contents, - undefined=jinja2.StrictUndefined) - return tpl.render(**params) - - -class Healthcheck(base.ConfigurableMiddleware): - """Healthcheck middleware used for monitoring. - - If the path is /healthcheck, it will respond 200 with "OK" as the body. - Or 503 with the reason as the body if one of the backend report - an application issue. - - This is useful for the following reasons: - - 1. Load balancers can 'ping' this url to determine service availability. - 2. Provides an endpoint that is similar to 'mod_status' in apache which - can provide details (or no details, depending on if configured) about - the activity of the server. - - Example requests/responses: - - $ curl -i -X HEAD "http://0.0.0.0:8775/status" - HTTP/1.1 204 No Content - Content-Type: text/plain; charset=UTF-8 - Content-Length: 0 - Date: Fri, 11 Sep 2015 18:55:08 GMT - - $ curl -i "http://0.0.0.0:8775/status" - HTTP/1.1 200 OK - Content-Type: text/plain; charset=UTF-8 - Content-Length: 2 - Date: Fri, 11 Sep 2015 18:55:43 GMT - - OK - - Example of paste configuration: - - .. code-block:: ini - - [filter:healthcheck] - paste.filter_factory = oslo_middleware:Healthcheck.factory - path = /healthcheck - backends = disable_by_file - disable_by_file_path = /var/run/nova/healthcheck_disable - - [pipeline:public_api] - pipeline = healthcheck sizelimit [...] public_service - - - Multiple filter sections can be defined if it desired to have - pipelines with different healthcheck configuration, example: - - .. code-block:: ini - - [pipeline:public_api] - pipeline = healthcheck_public sizelimit [...] public_service - - [pipeline:admin_api] - pipeline = healthcheck_admin sizelimit [...] admin_service - - [filter:healthcheck_public] - paste.filter_factory = oslo_middleware:Healthcheck.factory - path = /healthcheck_public - backends = disable_by_file - disable_by_file_path = /var/run/nova/healthcheck_public_disable - - [filter:healthcheck_admin] - paste.filter_factory = oslo_middleware:Healthcheck.factory - path = /healthcheck_admin - backends = disable_by_file - disable_by_file_path = /var/run/nova/healthcheck_admin_disable - - More details on available backends and their configuration can be found - on this page: :doc:`healthcheck_plugins`. - - """ - - NAMESPACE = "oslo.middleware.healthcheck" - HEALTHY_TO_STATUS_CODES = { - True: webob.exc.HTTPOk.code, - False: webob.exc.HTTPServiceUnavailable.code, - } - HEAD_HEALTHY_TO_STATUS_CODES = { - True: webob.exc.HTTPNoContent.code, - False: webob.exc.HTTPServiceUnavailable.code, - } - PLAIN_RESPONSE_TEMPLATE = """ -{% for reason in reasons %} -{% if reason %}{{reason}}{% endif -%} -{% endfor %} -""" - - HTML_RESPONSE_TEMPLATE = """ - -Healthcheck Status - -{% if detailed -%} -

Server status

-{% if hostname -%} -Server hostname:
{{hostname|e}}
-{%- endif %} -Current time:
{{now|e}}
-Python version:
{{python_version|e}}
-Platform:
{{platform|e}}
-
-

Garbage collector:

-Counts:
{{gc.counts|e}}
-Thresholds:
{{gc.threshold|e}}
-
-{%- endif %} -

Result of {{results|length}} checks:

- - - -{% if detailed -%} - - - -{% else %} - -{%- endif %} - -{% for result in results -%} -{% if result.reason -%} - -{% if detailed -%} - -{%- endif %} - -{% if detailed -%} - -{%- endif %} - -{%- endif %} -{%- endfor %} - -
-Kind - -Reason - -Details - -Reason -
{{result.class|e}}{{result.reason|e}}{{result.details|e}}
-
-{% if detailed -%} -{% if greenthreads -%} -

{{greenthreads|length}} greenthread(s) active:

- - -{% for stack in greenthreads -%} - - - -{%- endfor %} - -
{{stack|e}}
-
-{%- endif %} -{% if threads -%} -

{{threads|length}} thread(s) active:

- - -{% for stack in threads -%} - - - -{%- endfor %} - -
{{stack|e}}
-{%- endif %} -{%- endif %} - - -""" - - def __init__(self, application, conf): - super(Healthcheck, self).__init__(application) - self._path = conf.get('path', '/healthcheck') - self._show_details = strutils.bool_from_string(conf.get('detailed')) - self._backend_names = [] - backends = conf.get('backends') - if backends: - self._backend_names = backends.split(',') - self._backends = stevedore.NamedExtensionManager( - self.NAMESPACE, self._backend_names, - name_order=True, invoke_on_load=True, - invoke_args=(conf,)) - self._accept_to_functor = collections.OrderedDict([ - # Order here matters... - ('text/plain', self._make_text_response), - ('text/html', self._make_html_response), - ('application/json', self._make_json_response), - ]) - self._accept_order = tuple(six.iterkeys(self._accept_to_functor)) - # When no accept type matches instead of returning 406 we will - # always return text/plain (because sending an error from this - # middleware actually can cause issues). - self._default_accept = 'text/plain' - - @staticmethod - def _get_threadstacks(): - threadstacks = [] - try: - active_frames = sys._current_frames() - except AttributeError: - pass - else: - buf = six.StringIO() - for stack in six.itervalues(active_frames): - traceback.print_stack(stack, file=buf) - threadstacks.append(buf.getvalue()) - buf.seek(0) - buf.truncate() - return threadstacks - - @staticmethod - def _get_greenstacks(): - greenstacks = [] - if greenlet is not None: - buf = six.StringIO() - for gt in _find_objects(greenlet.greenlet): - traceback.print_stack(gt.gr_frame, file=buf) - greenstacks.append(buf.getvalue()) - buf.seek(0) - buf.truncate() - return greenstacks - - @staticmethod - def _pretty_json_dumps(contents): - return json.dumps(contents, indent=4, sort_keys=True) - - @staticmethod - def _are_results_healthy(results): - for result in results: - if not result.available: - return False - return True - - def _make_text_response(self, results, healthy): - params = { - 'reasons': [result.reason for result in results], - 'detailed': self._show_details, - } - body = _expand_template(self.PLAIN_RESPONSE_TEMPLATE, params) - return (body.strip(), 'text/plain') - - def _make_json_response(self, results, healthy): - if self._show_details: - body = { - 'detailed': True, - 'python_version': sys.version, - 'now': str(timeutils.utcnow()), - 'platform': platform.platform(), - 'gc': { - 'counts': gc.get_count(), - 'threshold': gc.get_threshold(), - }, - } - reasons = [] - for result in results: - reasons.append({ - 'reason': result.reason, - 'details': result.details or '', - 'class': reflection.get_class_name(result, - fully_qualified=False), - }) - body['reasons'] = reasons - body['greenthreads'] = self._get_greenstacks() - body['threads'] = self._get_threadstacks() - else: - body = { - 'reasons': [result.reason for result in results], - 'detailed': False, - } - return (self._pretty_json_dumps(body), 'application/json') - - def _make_head_response(self, results, healthy): - return ( "", "text/plain") - - def _make_html_response(self, results, healthy): - try: - hostname = socket.gethostname() - except socket.error: - hostname = None - translated_results = [] - for result in results: - translated_results.append({ - 'details': result.details or '', - 'reason': result.reason, - 'class': reflection.get_class_name(result, - fully_qualified=False), - }) - params = { - 'healthy': healthy, - 'hostname': hostname, - 'results': translated_results, - 'detailed': self._show_details, - 'now': str(timeutils.utcnow()), - 'python_version': sys.version, - 'platform': platform.platform(), - 'gc': { - 'counts': gc.get_count(), - 'threshold': gc.get_threshold(), - }, - 'threads': self._get_threadstacks(), - 'greenthreads': self._get_threadstacks(), - } - body = _expand_template(self.HTML_RESPONSE_TEMPLATE, params) - return (body.strip(), 'text/html') - - @webob.dec.wsgify - def process_request(self, req): - if req.path != self._path: - return None - results = [ext.obj.healthcheck(req.server_port) - for ext in self._backends] - healthy = self._are_results_healthy(results) - if req.method == "HEAD": - functor = self._make_head_response - status = self.HEAD_HEALTHY_TO_STATUS_CODES[healthy] - else: - status = self.HEALTHY_TO_STATUS_CODES[healthy] - accept_type = req.accept.best_match(self._accept_order) - if not accept_type: - accept_type = self._default_accept - functor = self._accept_to_functor[accept_type] - body, content_type = functor(results, healthy) - return webob.response.Response(status=status, body=body, - content_type=content_type) diff --git a/oslo_middleware/healthcheck/__main__.py b/oslo_middleware/healthcheck/__main__.py deleted file mode 100644 index 217fff6..0000000 --- a/oslo_middleware/healthcheck/__main__.py +++ /dev/null @@ -1,69 +0,0 @@ -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import argparse - -from six.moves import SimpleHTTPServer # noqa -from six.moves import socketserver -import webob - -from oslo_middleware import healthcheck - - -class HttpHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): - def do_GET(self): - @webob.dec.wsgify - def dummy_application(req): - return 'test' - app = healthcheck.Healthcheck(dummy_application, {'detailed': True}) - req = webob.Request.blank("/healthcheck", accept='text/html', - method='GET') - res = req.get_response(app) - self.send_response(res.status_code) - for header_name, header_value in res.headerlist: - self.send_header(header_name, header_value) - self.end_headers() - self.wfile.write(res.body) - self.wfile.close() - - -def positive_int(blob): - value = int(blob) - if value < 0: - msg = "%r is not a positive integer" % blob - raise argparse.ArgumentTypeError(msg) - return value - - -def create_server(port=0): - handler = HttpHandler - server = socketserver.TCPServer(("", port), handler) - return server - - -def main(args=None): - """Runs a basic http server to show healthcheck functionality.""" - parser = argparse.ArgumentParser() - parser.add_argument("-p", "--port", - help="Unused port to run the tiny" - " http server on (or zero to select a" - " random unused port)", - type=positive_int, required=True) - args = parser.parse_args(args=args) - server = create_server(args.port) - print("Serving at port: %s" % server.server_address[1]) - server.serve_forever() - - -if __name__ == '__main__': - main() diff --git a/oslo_middleware/healthcheck/disable_by_file.py b/oslo_middleware/healthcheck/disable_by_file.py deleted file mode 100644 index 7fbb14b..0000000 --- a/oslo_middleware/healthcheck/disable_by_file.py +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright 2011 OpenStack Foundation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging -import os - -from oslo_middleware._i18n import _LW -from oslo_middleware.healthcheck import pluginbase - -LOG = logging.getLogger(__name__) - - -class DisableByFilesPortsHealthcheck(pluginbase.HealthcheckBaseExtension): - """DisableByFilesPorts healthcheck middleware plugin - - This plugin checks presence of a file that is provided for a application - running on a certain port to report if the service is unavailable - or not. - - Example of middleware configuration: - - .. code-block:: ini - - [filter:healthcheck] - paste.filter_factory = oslo_middleware:Healthcheck.factory - path = /healthcheck - backends = disable_by_files_ports - disable_by_file_paths = 5000:/var/run/keystone/healthcheck_disable, \ - 35357:/var/run/keystone/admin_healthcheck_disable - """ - def __init__(self, conf): - super(DisableByFilesPortsHealthcheck, self).__init__(conf) - self.status_files = {} - self.status_files.update( - self._iter_paths_ports(self.conf.get('disable_by_file_paths'))) - - @staticmethod - def _iter_paths_ports(paths): - if paths: - for port_path in paths.split(","): - port_path = port_path.strip() - if port_path: - # On windows, drive letters are followed by colons, - # which makes split() return 3 elements in this case - port, path = port_path.split(":", 1) - port = int(port) - yield (port, path) - - def healthcheck(self, server_port): - path = self.status_files.get(server_port) - if not path: - LOG.warning(_LW('DisableByFilesPorts healthcheck middleware' - ' enabled without disable_by_file_paths set' - ' for port %s') % server_port) - return pluginbase.HealthcheckResult(available=True, - reason="OK") - else: - if not os.path.exists(path): - return pluginbase.HealthcheckResult(available=True, - reason="OK") - else: - return pluginbase.HealthcheckResult(available=False, - reason="DISABLED BY FILE") - - -class DisableByFileHealthcheck(pluginbase.HealthcheckBaseExtension): - """DisableByFile healthcheck middleware plugin - - This plugin checks presence of a file to report if the service - is unavailable or not. - - Example of middleware configuration: - - .. code-block:: ini - - [filter:healthcheck] - paste.filter_factory = oslo_middleware:Healthcheck.factory - path = /healthcheck - backends = disable_by_file - disable_by_file_path = /var/run/nova/healthcheck_disable - """ - - def healthcheck(self, server_port): - path = self.conf.get('disable_by_file_path') - if path is None: - LOG.warning(_LW('DisableByFile healthcheck middleware enabled ' - 'without disable_by_file_path set')) - return pluginbase.HealthcheckResult( - available=True, reason="OK", - details="No 'disable_by_file_path' configuration value" - " specified") - elif not os.path.exists(path): - return pluginbase.HealthcheckResult( - available=True, reason="OK", - details="Path '%s' was not found" % path) - else: - return pluginbase.HealthcheckResult( - available=False, reason="DISABLED BY FILE", - details="Path '%s' was found" % path) diff --git a/oslo_middleware/healthcheck/pluginbase.py b/oslo_middleware/healthcheck/pluginbase.py deleted file mode 100644 index e370967..0000000 --- a/oslo_middleware/healthcheck/pluginbase.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2011 OpenStack Foundation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import abc - -import six - - -class HealthcheckResult(object): - """Result of a ``healthcheck`` method call should be this object.""" - - def __init__(self, available, reason, details=None): - self.available = available - self.reason = reason - self.details = details - - -@six.add_metaclass(abc.ABCMeta) -class HealthcheckBaseExtension(object): - def __init__(self, conf): - self.conf = conf - - @abc.abstractmethod - def healthcheck(self, server_port): - """method called by the healthcheck middleware - - return: HealthcheckResult object - """ diff --git a/oslo_middleware/http_proxy_to_wsgi.py b/oslo_middleware/http_proxy_to_wsgi.py deleted file mode 100644 index 84bc32b..0000000 --- a/oslo_middleware/http_proxy_to_wsgi.py +++ /dev/null @@ -1,91 +0,0 @@ -# -*- encoding: utf-8 -*- -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. See the License for the specific language governing permissions and -# limitations under the License. -from debtcollector import removals -from oslo_config import cfg -from oslo_middleware import base - - -OPTS = [ - cfg.BoolOpt('enable_proxy_headers_parsing', - default=False, - help="Whether the application is behind a proxy or not. " - "This determines if the middleware should parse the " - "headers or not.") -] - - -class HTTPProxyToWSGI(base.ConfigurableMiddleware): - """HTTP proxy to WSGI termination middleware. - - This middleware overloads WSGI environment variables with the one provided - by the remote HTTP reverse proxy. - - """ - - def __init__(self, application, *args, **kwargs): - super(HTTPProxyToWSGI, self).__init__(application, *args, **kwargs) - self.oslo_conf.register_opts(OPTS, group='oslo_middleware') - - @staticmethod - def _parse_rfc7239_header(header): - """Parses RFC7239 Forward headers. - - e.g. for=192.0.2.60;proto=http, for=192.0.2.60;by=203.0.113.43 - - """ - result = [] - for proxy in header.split(","): - entry = {} - for d in proxy.split(";"): - key, _, value = d.partition("=") - entry[key.lower()] = value - result.append(entry) - return result - - def process_request(self, req): - if not self._conf_get('enable_proxy_headers_parsing'): - return - fwd_hdr = req.environ.get("HTTP_FORWARDED") - if fwd_hdr: - proxies = self._parse_rfc7239_header(fwd_hdr) - # Let's use the value from the first proxy - if proxies: - proxy = proxies[0] - - forwarded_proto = proxy.get("proto") - if forwarded_proto: - req.environ['wsgi.url_scheme'] = forwarded_proto - - forwarded_host = proxy.get("host") - if forwarded_host: - req.environ['HTTP_HOST'] = forwarded_host - - else: - # World before RFC7239 - forwarded_proto = req.environ.get("HTTP_X_FORWARDED_PROTO") - if forwarded_proto: - req.environ['wsgi.url_scheme'] = forwarded_proto - - forwarded_host = req.environ.get("HTTP_X_FORWARDED_HOST") - if forwarded_host: - req.environ['HTTP_HOST'] = forwarded_host - - v = req.environ.get("HTTP_X_FORWARDED_PREFIX") - if v: - req.environ['SCRIPT_NAME'] = v + req.environ['SCRIPT_NAME'] - - -@removals.remove -class HTTPProxyToWSGIMiddleware(HTTPProxyToWSGI): - """Placeholder for backward compatibility""" diff --git a/oslo_middleware/locale/de/LC_MESSAGES/oslo_middleware-log-error.po b/oslo_middleware/locale/de/LC_MESSAGES/oslo_middleware-log-error.po deleted file mode 100644 index 6ba0ef2..0000000 --- a/oslo_middleware/locale/de/LC_MESSAGES/oslo_middleware-log-error.po +++ /dev/null @@ -1,27 +0,0 @@ -# Translations template for oslo.middleware. -# Copyright (C) 2015 ORGANIZATION -# This file is distributed under the same license as the oslo.middleware -# project. -# -# Translators: -# Andreas Jaeger , 2014 -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.middleware 3.7.1.dev18\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-04-19 23:53+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2014-09-07 08:10+0000\n" -"Last-Translator: Andreas Jaeger \n" -"Language: de\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Generated-By: Babel 2.0\n" -"X-Generator: Zanata 3.7.3\n" -"Language-Team: German\n" - -#, python-format -msgid "An error occurred during processing the request: %s" -msgstr "Ein Fehler trat auf während die Anfrage behandelt wurde: %s" diff --git a/oslo_middleware/locale/de/LC_MESSAGES/oslo_middleware.po b/oslo_middleware/locale/de/LC_MESSAGES/oslo_middleware.po deleted file mode 100644 index 5176208..0000000 --- a/oslo_middleware/locale/de/LC_MESSAGES/oslo_middleware.po +++ /dev/null @@ -1,26 +0,0 @@ -# Translations template for oslo.middleware. -# Copyright (C) 2015 ORGANIZATION -# This file is distributed under the same license as the oslo.middleware -# project. -# -# Translators: -# Andreas Jaeger , 2014 -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.middleware 3.7.1.dev18\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-04-19 23:53+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2014-09-07 08:09+0000\n" -"Last-Translator: Andreas Jaeger \n" -"Language: de\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Generated-By: Babel 2.0\n" -"X-Generator: Zanata 3.7.3\n" -"Language-Team: German\n" - -msgid "Request is too large." -msgstr "Die Anfrage ist zu groß." diff --git a/oslo_middleware/locale/en_GB/LC_MESSAGES/oslo_middleware-log-error.po b/oslo_middleware/locale/en_GB/LC_MESSAGES/oslo_middleware-log-error.po deleted file mode 100644 index 5a24b6e..0000000 --- a/oslo_middleware/locale/en_GB/LC_MESSAGES/oslo_middleware-log-error.po +++ /dev/null @@ -1,27 +0,0 @@ -# Translations template for oslo.middleware. -# Copyright (C) 2015 ORGANIZATION -# This file is distributed under the same license as the oslo.middleware -# project. -# -# Translators: -# Andi Chandler , 2014 -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.middleware 3.7.1.dev18\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-04-19 23:53+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2014-11-03 11:03+0000\n" -"Last-Translator: Andi Chandler \n" -"Language: en-GB\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Generated-By: Babel 2.0\n" -"X-Generator: Zanata 3.7.3\n" -"Language-Team: English (United Kingdom)\n" - -#, python-format -msgid "An error occurred during processing the request: %s" -msgstr "An error occurred during processing the request: %s" diff --git a/oslo_middleware/locale/en_GB/LC_MESSAGES/oslo_middleware.po b/oslo_middleware/locale/en_GB/LC_MESSAGES/oslo_middleware.po deleted file mode 100644 index 84e7a10..0000000 --- a/oslo_middleware/locale/en_GB/LC_MESSAGES/oslo_middleware.po +++ /dev/null @@ -1,26 +0,0 @@ -# Translations template for oslo.middleware. -# Copyright (C) 2015 ORGANIZATION -# This file is distributed under the same license as the oslo.middleware -# project. -# -# Translators: -# Andi Chandler , 2014 -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.middleware 3.7.1.dev18\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-04-19 23:53+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2014-11-03 11:03+0000\n" -"Last-Translator: Andi Chandler \n" -"Language: en-GB\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Generated-By: Babel 2.0\n" -"X-Generator: Zanata 3.7.3\n" -"Language-Team: English (United Kingdom)\n" - -msgid "Request is too large." -msgstr "Request is too large." diff --git a/oslo_middleware/locale/fr/LC_MESSAGES/oslo_middleware-log-error.po b/oslo_middleware/locale/fr/LC_MESSAGES/oslo_middleware-log-error.po deleted file mode 100644 index 4b90d25..0000000 --- a/oslo_middleware/locale/fr/LC_MESSAGES/oslo_middleware-log-error.po +++ /dev/null @@ -1,27 +0,0 @@ -# Translations template for oslo.middleware. -# Copyright (C) 2015 ORGANIZATION -# This file is distributed under the same license as the oslo.middleware -# project. -# -# Translators: -# Maxime COQUEREL , 2014 -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.middleware 3.7.1.dev18\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-04-19 23:53+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2014-09-25 09:01+0000\n" -"Last-Translator: Maxime COQUEREL \n" -"Language: fr\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" -"Generated-By: Babel 2.0\n" -"X-Generator: Zanata 3.7.3\n" -"Language-Team: French\n" - -#, python-format -msgid "An error occurred during processing the request: %s" -msgstr "Une erreur s'est produite lors du traitement de la demande: %s" diff --git a/oslo_middleware/locale/fr/LC_MESSAGES/oslo_middleware.po b/oslo_middleware/locale/fr/LC_MESSAGES/oslo_middleware.po deleted file mode 100644 index 7d15ab3..0000000 --- a/oslo_middleware/locale/fr/LC_MESSAGES/oslo_middleware.po +++ /dev/null @@ -1,26 +0,0 @@ -# Translations template for oslo.middleware. -# Copyright (C) 2015 ORGANIZATION -# This file is distributed under the same license as the oslo.middleware -# project. -# -# Translators: -# Maxime COQUEREL , 2014 -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.middleware 3.7.1.dev18\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-04-19 23:53+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2014-09-17 09:06+0000\n" -"Last-Translator: Maxime COQUEREL \n" -"Language: fr\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" -"Generated-By: Babel 2.0\n" -"X-Generator: Zanata 3.7.3\n" -"Language-Team: French\n" - -msgid "Request is too large." -msgstr "Demande trop importante." diff --git a/oslo_middleware/locale/oslo_middleware-log-error.pot b/oslo_middleware/locale/oslo_middleware-log-error.pot deleted file mode 100644 index 6df63c0..0000000 --- a/oslo_middleware/locale/oslo_middleware-log-error.pot +++ /dev/null @@ -1,25 +0,0 @@ -# Translations template for oslo.middleware. -# Copyright (C) 2016 ORGANIZATION -# This file is distributed under the same license as the oslo.middleware -# project. -# FIRST AUTHOR , 2016. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: oslo.middleware 3.7.1.dev18\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-04-21 06:02+0000\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.2.0\n" - -#: oslo_middleware/catch_errors.py:40 -#, python-format -msgid "An error occurred during processing the request: %s" -msgstr "" - diff --git a/oslo_middleware/locale/oslo_middleware.pot b/oslo_middleware/locale/oslo_middleware.pot deleted file mode 100644 index 009ca69..0000000 --- a/oslo_middleware/locale/oslo_middleware.pot +++ /dev/null @@ -1,25 +0,0 @@ -# Translations template for oslo.middleware. -# Copyright (C) 2016 ORGANIZATION -# This file is distributed under the same license as the oslo.middleware -# project. -# FIRST AUTHOR , 2016. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: oslo.middleware 3.7.1.dev18\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-04-21 06:02+0000\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.2.0\n" - -#: oslo_middleware/sizelimit.py:59 oslo_middleware/sizelimit.py:73 -#: oslo_middleware/sizelimit.py:90 -msgid "Request is too large." -msgstr "" - diff --git a/oslo_middleware/opts.py b/oslo_middleware/opts.py deleted file mode 100644 index e66e723..0000000 --- a/oslo_middleware/opts.py +++ /dev/null @@ -1,157 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -__all__ = [ - 'list_opts', - 'list_opts_sizelimit', - 'list_opts_ssl', - 'list_opts_cors', - 'list_opts_http_proxy_to_wsgi', -] - - -import copy -import itertools - -from oslo_middleware import cors -from oslo_middleware import http_proxy_to_wsgi -from oslo_middleware import sizelimit -from oslo_middleware import ssl - - -def list_opts(): - """Return a list of oslo.config options for ALL of the middleware classes. - - The returned list includes all oslo.config options which may be registered - at runtime by the library. - - Each element of the list is a tuple. The first element is the name of the - group under which the list of elements in the second element will be - registered. A group name of None corresponds to the [DEFAULT] group in - config files. - - This function is also discoverable via the 'oslo.middleware' entry point - under the 'oslo.config.opts' namespace. - - The purpose of this is to allow tools like the Oslo sample config file - generator to discover the options exposed to users by this library. - - :returns: a list of (group_name, opts) tuples - """ - return list( - itertools.chain( - list_opts_sizelimit(), - list_opts_ssl(), - list_opts_cors(), - list_opts_http_proxy_to_wsgi(), - ) - ) - - -def list_opts_sizelimit(): - """Return a list of oslo.config options for the sizelimit middleware. - - The returned list includes all oslo.config options which may be registered - at runtime by the library. - - Each element of the list is a tuple. The first element is the name of the - group under which the list of elements in the second element will be - registered. A group name of None corresponds to the [DEFAULT] group in - config files. - - This function is also discoverable via the 'oslo.middleware' entry point - under the 'oslo.config.opts' namespace. - - The purpose of this is to allow tools like the Oslo sample config file - generator to discover the options exposed to users by this library. - - :returns: a list of (group_name, opts) tuples - """ - return [ - ('oslo_middleware', copy.deepcopy(sizelimit._opts)), - ] - - -def list_opts_ssl(): - """Return a list of oslo.config options for the SSL middleware. - - The returned list includes all oslo.config options which may be registered - at runtime by the library. - - Each element of the list is a tuple. The first element is the name of the - group under which the list of elements in the second element will be - registered. A group name of None corresponds to the [DEFAULT] group in - config files. - - This function is also discoverable via the 'oslo.middleware' entry point - under the 'oslo.config.opts' namespace. - - The purpose of this is to allow tools like the Oslo sample config file - generator to discover the options exposed to users by this library. - - :returns: a list of (group_name, opts) tuples - """ - return [ - ('oslo_middleware', copy.deepcopy(ssl.OPTS)), - ] - - -def list_opts_cors(): - """Return a list of oslo.config options for the cors middleware. - - The returned list includes all oslo.config options which may be registered - at runtime by the library. - - Each element of the list is a tuple. The first element is the name of the - group under which the list of elements in the second element will be - registered. A group name of None corresponds to the [DEFAULT] group in - config files. - - This function is also discoverable via the 'oslo.middleware' entry point - under the 'oslo.config.opts' namespace. - - The purpose of this is to allow tools like the Oslo sample config file - generator to discover the options exposed to users by this library. - - :returns: a list of (group_name, opts) tuples - """ - return [ - ('cors', copy.deepcopy(cors.CORS_OPTS)), - ('cors.subdomain', copy.deepcopy(cors.CORS_OPTS)) - ] - - -def list_opts_http_proxy_to_wsgi(): - """Return a list of oslo.config options for http_proxy_to_wsgi. - - The returned list includes all oslo.config options which may be registered - at runtime by the library. - - Each element of the list is a tuple. The first element is the name of the - group under which the list of elements in the second element will be - registered. A group name of None corresponds to the [DEFAULT] group in - config files. - - This function is also discoverable via the 'oslo.middleware' entry point - under the 'oslo.config.opts' namespace. - - The purpose of this is to allow tools like the Oslo sample config file - generator to discover the options exposed to users by this library. - - :returns: a list of (group_name, opts) tuples - """ - return [ - ('oslo_middleware', copy.deepcopy(http_proxy_to_wsgi.OPTS)), - ] diff --git a/oslo_middleware/request_id.py b/oslo_middleware/request_id.py deleted file mode 100644 index 31a433b..0000000 --- a/oslo_middleware/request_id.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (c) 2013 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_context import context -import webob.dec - -from oslo_middleware import base - - -ENV_REQUEST_ID = 'openstack.request_id' -HTTP_RESP_HEADER_REQUEST_ID = 'x-openstack-request-id' - - -class RequestId(base.ConfigurableMiddleware): - """Middleware that ensures request ID. - - It ensures to assign request ID for each API request and set it to - request environment. The request ID is also added to API response. - """ - - @webob.dec.wsgify - def __call__(self, req): - req_id = context.generate_request_id() - req.environ[ENV_REQUEST_ID] = req_id - response = req.get_response(self.application) - if HTTP_RESP_HEADER_REQUEST_ID not in response.headers: - response.headers.add(HTTP_RESP_HEADER_REQUEST_ID, req_id) - return response diff --git a/oslo_middleware/sizelimit.py b/oslo_middleware/sizelimit.py deleted file mode 100644 index bba9886..0000000 --- a/oslo_middleware/sizelimit.py +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright (c) 2012 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -Request Body limiting middleware. - -""" - -from oslo_config import cfg -import webob.dec -import webob.exc - -from oslo_middleware._i18n import _ -from oslo_middleware import base - - -_oldopts = [cfg.DeprecatedOpt('osapi_max_request_body_size', - group='DEFAULT'), - cfg.DeprecatedOpt('max_request_body_size', - group='DEFAULT')] - -_opts = [ - # default request size is 112k - cfg.IntOpt('max_request_body_size', - default=114688, - help='The maximum body size for each ' - ' request, in bytes.', - deprecated_opts=_oldopts) -] - - -class LimitingReader(object): - """Reader to limit the size of an incoming request.""" - def __init__(self, data, limit): - """Initiates LimitingReader object. - - :param data: Underlying data object - :param limit: maximum number of bytes the reader should allow - """ - self.data = data - self.limit = limit - self.bytes_read = 0 - - def __iter__(self): - for chunk in self.data: - self.bytes_read += len(chunk) - if self.bytes_read > self.limit: - msg = _("Request is too large.") - raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg) - else: - yield chunk - - def read(self, i=None): - # NOTE(jamielennox): We can't simply provide the default to the read() - # call as the expected default differs between mod_wsgi and eventlet - if i is None: - result = self.data.read() - else: - result = self.data.read(i) - self.bytes_read += len(result) - if self.bytes_read > self.limit: - msg = _("Request is too large.") - raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg) - return result - - -class RequestBodySizeLimiter(base.ConfigurableMiddleware): - """Limit the size of incoming requests.""" - - def __init__(self, application, conf=None): - super(RequestBodySizeLimiter, self).__init__(application, conf) - self.oslo_conf.register_opts(_opts, group='oslo_middleware') - - @webob.dec.wsgify - def __call__(self, req): - max_size = self._conf_get('max_request_body_size') - if (req.content_length is not None and - req.content_length > max_size): - msg = _("Request is too large.") - raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg) - if req.content_length is None and req.is_body_readable: - limiter = LimitingReader(req.body_file, max_size) - req.body_file = limiter - return self.application diff --git a/oslo_middleware/ssl.py b/oslo_middleware/ssl.py deleted file mode 100644 index 7853dc1..0000000 --- a/oslo_middleware/ssl.py +++ /dev/null @@ -1,48 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. See the License for the specific language governing permissions and -# limitations under the License. -from debtcollector import removals -from oslo_config import cfg -from oslo_middleware import base - - -OPTS = [ - cfg.StrOpt('secure_proxy_ssl_header', - default='X-Forwarded-Proto', - deprecated_for_removal=True, - help="The HTTP Header that will be used to determine what " - "the original request protocol scheme was, even if it was " - "hidden by an SSL termination proxy.") -] - - -removals.removed_module(__name__, - "oslo_middleware.http_proxy_to_wsgi") - - -class SSLMiddleware(base.ConfigurableMiddleware): - """SSL termination proxies middleware. - - This middleware overloads wsgi.url_scheme with the one provided in - secure_proxy_ssl_header header. This is useful when behind a SSL - termination proxy. - """ - - def __init__(self, application, *args, **kwargs): - super(SSLMiddleware, self).__init__(application, *args, **kwargs) - self.oslo_conf.register_opts(OPTS, group='oslo_middleware') - - def process_request(self, req): - self.header_name = 'HTTP_{0}'.format( - self._conf_get('secure_proxy_ssl_header').upper() - .replace('-', '_')) - req.environ['wsgi.url_scheme'] = req.environ.get( - self.header_name, req.environ['wsgi.url_scheme']) diff --git a/oslo_middleware/tests/__init__.py b/oslo_middleware/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/oslo_middleware/tests/test_base.py b/oslo_middleware/tests/test_base.py deleted file mode 100644 index 425ff9a..0000000 --- a/oslo_middleware/tests/test_base.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import webob - -from oslo_middleware.base import ConfigurableMiddleware -from oslo_middleware.base import Middleware -from oslotest.base import BaseTestCase - - -@webob.dec.wsgify -def application(req): - return 'Hello, World!!!' - - -class TestBase(BaseTestCase): - """Test the base middleware class.""" - - def test_extend_with_request(self): - """Assert that a newer middleware behaves as appropriate. - - This tests makes sure that the request is passed to the - middleware's implementation. - """ - # Bootstrap the application - self.application = RequestBase(application) - - # Send a request through. - request = webob.Request({}, method='GET') - request.get_response(self.application) - - self.assertTrue(self.application.called_with_request) - - def test_extend_without_request(self): - """Assert that an older middleware behaves as appropriate. - - This tests makes sure that the request method is NOT passed to the - middleware's implementation, and that there are no other expected - errors. - """ - # Bootstrap the application - self.application = NoRequestBase(application) - - # Send a request through. - request = webob.Request({}, method='GET') - request.get_response(self.application) - - self.assertTrue(self.application.called_without_request) - - def test_no_content_type_added(self): - class TestMiddleware(Middleware): - @staticmethod - def process_request(req): - return "foobar" - - m = TestMiddleware(None) - request = webob.Request({}, method='GET') - response = request.get_response(m) - self.assertNotIn('Content-Type', response.headers) - - def test_paste_deploy_legacy(self): - app = LegacyMiddlewareTest.factory( - {'global': True}, local=True)(application) - self.assertEqual(app.conf, {}) - - def test_paste_deploy_configurable(self): - app = ConfigurableMiddlewareTest.factory( - {'global': True}, local=True)(application) - self.assertEqual(app.conf, {'global': True, 'local': True}) - - -class NoRequestBase(Middleware): - """Test middleware, implements old model.""" - def process_response(self, response): - self.called_without_request = True - return response - - -class RequestBase(Middleware): - """Test middleware, implements new model.""" - def process_response(self, response, request): - self.called_with_request = True - return response - - -class ConfigurableMiddlewareTest(ConfigurableMiddleware): - pass - - -class LegacyMiddlewareTest(Middleware): - pass diff --git a/oslo_middleware/tests/test_catch_errors.py b/oslo_middleware/tests/test_catch_errors.py deleted file mode 100644 index 920bbe2..0000000 --- a/oslo_middleware/tests/test_catch_errors.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (c) 2013 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock -from oslotest import base as test_base -import webob.dec -import webob.exc - -from oslo_middleware import catch_errors - - -class CatchErrorsTest(test_base.BaseTestCase): - - def _test_has_request_id(self, application, expected_code=None): - app = catch_errors.CatchErrors(application) - req = webob.Request.blank('/test') - res = req.get_response(app) - self.assertEqual(expected_code, res.status_int) - - def test_success_response(self): - @webob.dec.wsgify - def application(req): - return 'Hello, World!!!' - - self._test_has_request_id(application, webob.exc.HTTPOk.code) - - def test_internal_server_error(self): - @webob.dec.wsgify - def application(req): - raise Exception() - - with mock.patch.object(catch_errors.LOG, 'exception') as log_exc: - self._test_has_request_id(application, - webob.exc.HTTPInternalServerError.code) - self.assertEqual(1, log_exc.call_count) diff --git a/oslo_middleware/tests/test_correlation_id.py b/oslo_middleware/tests/test_correlation_id.py deleted file mode 100644 index 6dde5d8..0000000 --- a/oslo_middleware/tests/test_correlation_id.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright (c) 2013 Rackspace Hosting -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -import mock -from oslotest import base as test_base -from oslotest import moxstubout - -from oslo_middleware import correlation_id - - -class CorrelationIdTest(test_base.BaseTestCase): - - def setUp(self): - super(CorrelationIdTest, self).setUp() - self.stubs = self.useFixture(moxstubout.MoxStubout()).stubs - - def test_process_request(self): - app = mock.Mock() - req = mock.Mock() - req.headers = {} - - mock_uuid4 = mock.Mock() - mock_uuid4.return_value = "fake_uuid" - self.stubs.Set(uuid, 'uuid4', mock_uuid4) - - middleware = correlation_id.CorrelationId(app) - middleware(req) - - self.assertEqual(req.headers.get("X_CORRELATION_ID"), "fake_uuid") - - def test_process_request_should_not_regenerate_correlation_id(self): - app = mock.Mock() - req = mock.Mock() - req.headers = {"X_CORRELATION_ID": "correlation_id"} - - middleware = correlation_id.CorrelationId(app) - middleware(req) - - self.assertEqual(req.headers.get("X_CORRELATION_ID"), "correlation_id") diff --git a/oslo_middleware/tests/test_cors.py b/oslo_middleware/tests/test_cors.py deleted file mode 100644 index 5e0822f..0000000 --- a/oslo_middleware/tests/test_cors.py +++ /dev/null @@ -1,1371 +0,0 @@ -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_config import fixture -from oslotest import base as test_base -import webob -import webob.dec -import webob.exc as exc - -from oslo_middleware import cors - - -@webob.dec.wsgify -def test_application(req): - if req.path_info == '/server_cors': - # Mirror back the origin in the request. - response = webob.Response(status=200) - response.headers['Access-Control-Allow-Origin'] = \ - req.headers['Origin'] - response.headers['X-Server-Generated-Response'] = '1' - return response - - if req.path_info == '/server_cors_vary': - # Mirror back the origin in the request. - response = webob.Response(status=200) - response.headers['Vary'] = 'Custom-Vary' - return response - - if req.path_info == '/server_no_cors': - # Send a response with no CORS headers. - response = webob.Response(status=200) - return response - - if req.method == 'OPTIONS': - raise exc.HTTPNotFound() - - return 'Hello World' - - -class CORSTestBase(test_base.BaseTestCase): - """Base class for all CORS tests. - - Sets up applications and helper methods. - """ - - def setUp(self): - """Setup the tests.""" - super(CORSTestBase, self).setUp() - - # Set up the config fixture. - self.config_fixture = self.useFixture(fixture.Config()) - self.config = self.config_fixture.conf - - def assertCORSResponse(self, response, - status='200 OK', - allow_origin=None, - max_age=None, - allow_methods=None, - allow_headers=None, - allow_credentials=None, - expose_headers=None, - vary='Origin', - has_content_type=False): - """Test helper for CORS response headers. - - Assert all the headers in a given response. By default, we assume - the response is empty. - """ - - # Assert response status. - self.assertEqual(response.status, status) - - # Assert the Access-Control-Allow-Origin header. - self.assertHeader(response, - 'Access-Control-Allow-Origin', - allow_origin) - - # Assert the Access-Control-Max-Age header. - self.assertHeader(response, - 'Access-Control-Max-Age', - max_age) - - # Assert the Access-Control-Allow-Methods header. - self.assertHeader(response, - 'Access-Control-Allow-Methods', - allow_methods) - - # Assert the Access-Control-Allow-Headers header. - self.assertHeader(response, - 'Access-Control-Allow-Headers', - allow_headers) - - # Assert the Access-Control-Allow-Credentials header. - self.assertHeader(response, - 'Access-Control-Allow-Credentials', - allow_credentials) - - # Assert the Access-Control-Expose-Headers header. - self.assertHeader(response, - 'Access-Control-Expose-Headers', - expose_headers) - - # Assert no Content-Type added. - if not has_content_type: - self.assertHeader(response, 'Content-Type') - - # If we're expecting an origin response, also assert that the - # Vary: Origin header is set, since this implementation of the CORS - # specification permits multiple origin domains. - if allow_origin: - self.assertHeader(response, 'Vary', vary) - - def assertHeader(self, response, header, value=None): - if value: - self.assertIn(header, response.headers) - self.assertEqual(str(value), - response.headers[header]) - else: - self.assertNotIn(header, response.headers) - - -class CORSTestDefaultOverrides(CORSTestBase): - def setUp(self): - super(CORSTestDefaultOverrides, self).setUp() - - fixture = self.config_fixture # Line length accommodation - - fixture.load_raw_values(group='cors', - allowed_origin='http://valid.example.com') - - fixture.load_raw_values(group='cors.override_creds', - allowed_origin='http://creds.example.com', - allow_credentials='True') - - fixture.load_raw_values(group='cors.override_headers', - allowed_origin='http://headers.example.com', - expose_headers='X-Header-1,X-Header-2', - allow_headers='X-Header-1,X-Header-2') - - self.override_opts = { - 'expose_headers': ['X-Header-1'], - 'allow_headers': ['X-Header-2'], - 'allow_methods': ['GET', 'DELETE'], - 'allow_credentials': False, - 'max_age': 10 - } - - def test_config_defaults(self): - """Assert that using set_defaults overrides the appropriate values.""" - - cors.set_defaults(**self.override_opts) - - for opt in cors.CORS_OPTS: - if opt.dest in self.override_opts: - self.assertEqual(opt.default, self.override_opts[opt.dest]) - - def test_invalid_default_option(self): - """Assert that using set_defaults only permits valid options.""" - - self.assertRaises(AttributeError, - cors.set_defaults, - allowed_origin='test') - - def test_cascading_override(self): - """Assert that using set_defaults overrides cors.* config values.""" - - # set defaults - cors.set_defaults(**self.override_opts) - - # Now that the config is set up, create our application. - self.application = cors.CORS(test_application, self.config) - - # Check the global configuration for expected values: - gc = self.config.cors - self.assertEqual(gc.allowed_origin, ['http://valid.example.com']) - self.assertEqual(gc.allow_credentials, - self.override_opts['allow_credentials']) - self.assertEqual(gc.expose_headers, - self.override_opts['expose_headers']) - self.assertEqual(gc.max_age, 10) - self.assertEqual(gc.allow_methods, - self.override_opts['allow_methods']) - self.assertEqual(gc.allow_headers, - self.override_opts['allow_headers']) - - # Check the child configuration for expected values: - cc = self.config['cors.override_creds'] - self.assertEqual(cc.allowed_origin, ['http://creds.example.com']) - self.assertTrue(cc.allow_credentials) - self.assertEqual(cc.expose_headers, - self.override_opts['expose_headers']) - self.assertEqual(cc.max_age, 10) - self.assertEqual(cc.allow_methods, - self.override_opts['allow_methods']) - self.assertEqual(cc.allow_headers, - self.override_opts['allow_headers']) - - # Check the other child configuration for expected values: - ec = self.config['cors.override_headers'] - self.assertEqual(ec.allowed_origin, ['http://headers.example.com']) - self.assertEqual(ec.allow_credentials, - self.override_opts['allow_credentials']) - self.assertEqual(ec.expose_headers, ['X-Header-1', 'X-Header-2']) - self.assertEqual(ec.max_age, 10) - self.assertEqual(ec.allow_methods, - self.override_opts['allow_methods']) - self.assertEqual(ec.allow_headers, ['X-Header-1', 'X-Header-2']) - - -class CORSTestFilterFactory(CORSTestBase): - """Test the CORS filter_factory method.""" - - def test_filter_factory(self): - self.config([]) - - # Test a valid filter. - filter = cors.filter_factory(None, - allowed_origin='http://valid.example.com', - allow_credentials='False', - max_age='', - expose_headers='', - allow_methods='GET', - allow_headers='') - application = filter(test_application) - - self.assertIn('http://valid.example.com', application.allowed_origins) - - config = application.allowed_origins['http://valid.example.com'] - self.assertEqual(False, config['allow_credentials']) - self.assertIsNone(config['max_age']) - self.assertEqual([], config['expose_headers']) - self.assertEqual(['GET'], config['allow_methods']) - self.assertEqual([], config['allow_headers']) - - def test_filter_factory_multiorigin(self): - self.config([]) - - # Test a valid filter. - filter = cors.filter_factory(None, - allowed_origin='http://valid.example.com,' - 'http://other.example.com') - application = filter(test_application) - - self.assertIn('http://valid.example.com', application.allowed_origins) - self.assertIn('http://other.example.com', application.allowed_origins) - - def test_no_origin_fail(self): - '''Assert that a filter factory with no allowed_origin fails.''' - self.assertRaises(TypeError, - cors.filter_factory, - global_conf=None, - # allowed_origin=None, # Expected value. - allow_credentials='False', - max_age='', - expose_headers='', - allow_methods='GET', - allow_headers='') - - def test_no_origin_but_oslo_config_project(self): - '''Assert that a filter factory with oslo_config_project succeed.''' - cors.filter_factory(global_conf=None, oslo_config_project='foobar') - - def test_cor_config_sections_with_defaults(self): - '''Assert cors.* config sections with default values work.''' - - # Set up the config fixture. - self.config_fixture.load_raw_values(group='cors.subdomain') - - # Now that the config is set up, create our application. - self.application = cors.CORS(test_application, self.config) - - def test_factory_latent_properties(self): - '''Assert latent properties in paste.ini config. - - If latent_* properties are added to a paste.ini config, assert that - they are persisted in the middleware. - ''' - - # Spaces in config are deliberate to frobb the config parsing. - filter = cors.filter_factory(global_conf=None, - oslo_config_project='foobar', - latent_expose_headers=' X-Header-1 , X-2', - latent_allow_headers='X-Header-1 , X-2', - latent_allow_methods='GET,PUT, POST') - app = filter(test_application) - - # Ensure that the properties are in latent configuration. - self.assertEqual(['X-Header-1', 'X-2'], - app._latent_configuration['expose_headers']) - self.assertEqual(['X-Header-1', 'X-2'], - app._latent_configuration['allow_headers']) - self.assertEqual(['GET', 'PUT', 'POST'], - app._latent_configuration['methods']) - - -class CORSRegularRequestTest(CORSTestBase): - """CORS Specification Section 6.1 - - http://www.w3.org/TR/cors/#resource-requests - """ - - # List of HTTP methods (other than OPTIONS) to test with. - methods = ['POST', 'PUT', 'DELETE', 'GET', 'TRACE', 'HEAD'] - - def setUp(self): - """Setup the tests.""" - super(CORSRegularRequestTest, self).setUp() - - fixture = self.config_fixture # Line length accommodation - fixture.load_raw_values(group='cors', - allowed_origin='http://valid.example.com', - allow_credentials='False', - max_age='', - expose_headers='', - allow_methods='GET', - allow_headers='') - - fixture.load_raw_values(group='cors.credentials', - allowed_origin='http://creds.example.com', - allow_credentials='True') - - fixture.load_raw_values(group='cors.exposed-headers', - allowed_origin='http://headers.example.com', - expose_headers='X-Header-1,X-Header-2', - allow_headers='X-Header-1,X-Header-2') - - fixture.load_raw_values(group='cors.cached', - allowed_origin='http://cached.example.com', - max_age='3600') - - fixture.load_raw_values(group='cors.get-only', - allowed_origin='http://get.example.com', - allow_methods='GET') - fixture.load_raw_values(group='cors.all-methods', - allowed_origin='http://all.example.com', - allow_methods='GET,PUT,POST,DELETE,HEAD') - - fixture.load_raw_values(group='cors.duplicate', - allowed_origin='http://domain1.example.com,' - 'http://domain2.example.com') - - # Now that the config is set up, create our application. - self.application = cors.CORS(test_application, self.config) - - def test_config_overrides(self): - """Assert that the configuration options are properly registered.""" - - # Confirm global configuration - gc = self.config.cors - self.assertEqual(gc.allowed_origin, ['http://valid.example.com']) - self.assertEqual(gc.allow_credentials, False) - self.assertEqual(gc.expose_headers, []) - self.assertEqual(gc.max_age, None) - self.assertEqual(gc.allow_methods, ['GET']) - self.assertEqual(gc.allow_headers, []) - - # Confirm credentials overrides. - cc = self.config['cors.credentials'] - self.assertEqual(cc.allowed_origin, ['http://creds.example.com']) - self.assertEqual(cc.allow_credentials, True) - self.assertEqual(cc.expose_headers, gc.expose_headers) - self.assertEqual(cc.max_age, gc.max_age) - self.assertEqual(cc.allow_methods, gc.allow_methods) - self.assertEqual(cc.allow_headers, gc.allow_headers) - - # Confirm exposed-headers overrides. - ec = self.config['cors.exposed-headers'] - self.assertEqual(ec.allowed_origin, ['http://headers.example.com']) - self.assertEqual(ec.allow_credentials, gc.allow_credentials) - self.assertEqual(ec.expose_headers, ['X-Header-1', 'X-Header-2']) - self.assertEqual(ec.max_age, gc.max_age) - self.assertEqual(ec.allow_methods, gc.allow_methods) - self.assertEqual(ec.allow_headers, ['X-Header-1', 'X-Header-2']) - - # Confirm cached overrides. - chc = self.config['cors.cached'] - self.assertEqual(chc.allowed_origin, ['http://cached.example.com']) - self.assertEqual(chc.allow_credentials, gc.allow_credentials) - self.assertEqual(chc.expose_headers, gc.expose_headers) - self.assertEqual(chc.max_age, 3600) - self.assertEqual(chc.allow_methods, gc.allow_methods) - self.assertEqual(chc.allow_headers, gc.allow_headers) - - # Confirm get-only overrides. - goc = self.config['cors.get-only'] - self.assertEqual(goc.allowed_origin, ['http://get.example.com']) - self.assertEqual(goc.allow_credentials, gc.allow_credentials) - self.assertEqual(goc.expose_headers, gc.expose_headers) - self.assertEqual(goc.max_age, gc.max_age) - self.assertEqual(goc.allow_methods, ['GET']) - self.assertEqual(goc.allow_headers, gc.allow_headers) - - # Confirm all-methods overrides. - ac = self.config['cors.all-methods'] - self.assertEqual(ac.allowed_origin, ['http://all.example.com']) - self.assertEqual(ac.allow_credentials, gc.allow_credentials) - self.assertEqual(ac.expose_headers, gc.expose_headers) - self.assertEqual(ac.max_age, gc.max_age) - self.assertEqual(ac.allow_methods, - ['GET', 'PUT', 'POST', 'DELETE', 'HEAD']) - self.assertEqual(ac.allow_headers, gc.allow_headers) - - # Confirm duplicate domains. - ac = self.config['cors.duplicate'] - self.assertEqual(ac.allowed_origin, ['http://domain1.example.com', - 'http://domain2.example.com']) - self.assertEqual(ac.allow_credentials, gc.allow_credentials) - self.assertEqual(ac.expose_headers, gc.expose_headers) - self.assertEqual(ac.max_age, gc.max_age) - self.assertEqual(ac.allow_methods, gc.allow_methods) - self.assertEqual(ac.allow_headers, gc.allow_headers) - - def test_no_origin_header(self): - """CORS Specification Section 6.1.1 - - If the Origin header is not present terminate this set of steps. The - request is outside the scope of this specification. - """ - for method in self.methods: - request = webob.Request.blank('/') - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin=None, - max_age=None, - allow_methods=None, - allow_headers=None, - allow_credentials=None, - expose_headers=None, - has_content_type=True) - - def test_origin_headers(self): - """CORS Specification Section 6.1.2 - - If the value of the Origin header is not a case-sensitive match for - any of the values in list of origins, do not set any additional - headers and terminate this set of steps. - """ - - # Test valid origin header. - for method in self.methods: - request = webob.Request.blank('/') - request.method = method - request.headers['Origin'] = 'http://valid.example.com' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin='http://valid.example.com', - max_age=None, - allow_methods=None, - allow_headers=None, - allow_credentials=None, - expose_headers=None, - has_content_type=True) - - # Test origin header not present in configuration. - for method in self.methods: - request = webob.Request.blank('/') - request.method = method - request.headers['Origin'] = 'http://invalid.example.com' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin=None, - max_age=None, - allow_methods=None, - allow_headers=None, - allow_credentials=None, - expose_headers=None, - has_content_type=True) - - # Test valid, but case-mismatched origin header. - for method in self.methods: - request = webob.Request.blank('/') - request.method = method - request.headers['Origin'] = 'http://VALID.EXAMPLE.COM' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin=None, - max_age=None, - allow_methods=None, - allow_headers=None, - allow_credentials=None, - expose_headers=None, - has_content_type=True) - - # Test valid header from list of duplicates. - for method in self.methods: - request = webob.Request.blank('/') - request.method = method - request.headers['Origin'] = 'http://domain2.example.com' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin='http://domain2.example.com', - max_age=None, - allow_methods=None, - allow_headers=None, - allow_credentials=None, - expose_headers=None, - has_content_type=True) - - def test_supports_credentials(self): - """CORS Specification Section 6.1.3 - - If the resource supports credentials add a single - Access-Control-Allow-Origin header, with the value of the Origin header - as value, and add a single Access-Control-Allow-Credentials header with - the case-sensitive string "true" as value. - - Otherwise, add a single Access-Control-Allow-Origin header, with - either the value of the Origin header or the string "*" as value. - - NOTE: We never use the "*" as origin. - """ - # Test valid origin header without credentials. - for method in self.methods: - request = webob.Request.blank('/') - request.method = method - request.headers['Origin'] = 'http://valid.example.com' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin='http://valid.example.com', - max_age=None, - allow_methods=None, - allow_headers=None, - allow_credentials=None, - expose_headers=None, - has_content_type=True) - - # Test valid origin header with credentials - for method in self.methods: - request = webob.Request.blank('/') - request.method = method - request.headers['Origin'] = 'http://creds.example.com' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin='http://creds.example.com', - max_age=None, - allow_methods=None, - allow_headers=None, - allow_credentials="true", - expose_headers=None, - has_content_type=True) - - def test_expose_headers(self): - """CORS Specification Section 6.1.4 - - If the list of exposed headers is not empty add one or more - Access-Control-Expose-Headers headers, with as values the header field - names given in the list of exposed headers. - """ - for method in self.methods: - request = webob.Request.blank('/') - request.method = method - request.headers['Origin'] = 'http://headers.example.com' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin='http://headers.example.com', - max_age=None, - allow_methods=None, - allow_headers=None, - allow_credentials=None, - expose_headers='X-Header-1,X-Header-2', - has_content_type=True) - - def test_application_options_response(self): - """Assert that an application provided OPTIONS response is honored. - - If the underlying application, via middleware or other, provides a - CORS response, its response should be honored. - """ - test_origin = 'http://creds.example.com' - - request = webob.Request.blank('/server_cors') - request.method = "GET" - request.headers['Origin'] = test_origin - request.headers['Access-Control-Request-Method'] = 'GET' - - response = request.get_response(self.application) - - # If the regular CORS handling catches this request, it should set - # the allow credentials header. This makes sure that it doesn't. - self.assertNotIn('Access-Control-Allow-Credentials', response.headers) - self.assertEqual(response.headers['Access-Control-Allow-Origin'], - test_origin) - self.assertEqual(response.headers['X-Server-Generated-Response'], - '1') - - def test_application_vary_respected(self): - """Assert that an application's provided Vary header is persisted. - - If the underlying application, via middleware or other, provides a - Vary header, its response should be honored. - """ - - request = webob.Request.blank('/server_cors_vary') - request.method = "GET" - request.headers['Origin'] = 'http://valid.example.com' - request.headers['Access-Control-Request-Method'] = 'GET' - - response = request.get_response(self.application) - - self.assertCORSResponse(response, - status='200 OK', - allow_origin='http://valid.example.com', - max_age=None, - allow_methods=None, - allow_headers=None, - allow_credentials=None, - expose_headers=None, - vary='Custom-Vary,Origin', - has_content_type=True) - - -class CORSPreflightRequestTest(CORSTestBase): - """CORS Specification Section 6.2 - - http://www.w3.org/TR/cors/#resource-preflight-requests - """ - - def setUp(self): - super(CORSPreflightRequestTest, self).setUp() - - fixture = self.config_fixture # Line length accommodation - fixture.load_raw_values(group='cors', - allowed_origin='http://valid.example.com', - allow_credentials='False', - max_age='', - expose_headers='', - allow_methods='GET', - allow_headers='') - - fixture.load_raw_values(group='cors.credentials', - allowed_origin='http://creds.example.com', - allow_credentials='True') - - fixture.load_raw_values(group='cors.exposed-headers', - allowed_origin='http://headers.example.com', - expose_headers='X-Header-1,X-Header-2', - allow_headers='X-Header-1,X-Header-2') - - fixture.load_raw_values(group='cors.cached', - allowed_origin='http://cached.example.com', - max_age='3600') - - fixture.load_raw_values(group='cors.get-only', - allowed_origin='http://get.example.com', - allow_methods='GET') - fixture.load_raw_values(group='cors.all-methods', - allowed_origin='http://all.example.com', - allow_methods='GET,PUT,POST,DELETE,HEAD') - - # Now that the config is set up, create our application. - self.application = cors.CORS(test_application, self.config) - - def test_config_overrides(self): - """Assert that the configuration options are properly registered.""" - - # Confirm global configuration - gc = self.config.cors - self.assertEqual(gc.allowed_origin, ['http://valid.example.com']) - self.assertEqual(gc.allow_credentials, False) - self.assertEqual(gc.expose_headers, []) - self.assertEqual(gc.max_age, None) - self.assertEqual(gc.allow_methods, ['GET']) - self.assertEqual(gc.allow_headers, []) - - # Confirm credentials overrides. - cc = self.config['cors.credentials'] - self.assertEqual(cc.allowed_origin, ['http://creds.example.com']) - self.assertEqual(cc.allow_credentials, True) - self.assertEqual(cc.expose_headers, gc.expose_headers) - self.assertEqual(cc.max_age, gc.max_age) - self.assertEqual(cc.allow_methods, gc.allow_methods) - self.assertEqual(cc.allow_headers, gc.allow_headers) - - # Confirm exposed-headers overrides. - ec = self.config['cors.exposed-headers'] - self.assertEqual(ec.allowed_origin, ['http://headers.example.com']) - self.assertEqual(ec.allow_credentials, gc.allow_credentials) - self.assertEqual(ec.expose_headers, ['X-Header-1', 'X-Header-2']) - self.assertEqual(ec.max_age, gc.max_age) - self.assertEqual(ec.allow_methods, gc.allow_methods) - self.assertEqual(ec.allow_headers, ['X-Header-1', 'X-Header-2']) - - # Confirm cached overrides. - chc = self.config['cors.cached'] - self.assertEqual(chc.allowed_origin, ['http://cached.example.com']) - self.assertEqual(chc.allow_credentials, gc.allow_credentials) - self.assertEqual(chc.expose_headers, gc.expose_headers) - self.assertEqual(chc.max_age, 3600) - self.assertEqual(chc.allow_methods, gc.allow_methods) - self.assertEqual(chc.allow_headers, gc.allow_headers) - - # Confirm get-only overrides. - goc = self.config['cors.get-only'] - self.assertEqual(goc.allowed_origin, ['http://get.example.com']) - self.assertEqual(goc.allow_credentials, gc.allow_credentials) - self.assertEqual(goc.expose_headers, gc.expose_headers) - self.assertEqual(goc.max_age, gc.max_age) - self.assertEqual(goc.allow_methods, ['GET']) - self.assertEqual(goc.allow_headers, gc.allow_headers) - - # Confirm all-methods overrides. - ac = self.config['cors.all-methods'] - self.assertEqual(ac.allowed_origin, ['http://all.example.com']) - self.assertEqual(ac.allow_credentials, gc.allow_credentials) - self.assertEqual(ac.expose_headers, gc.expose_headers) - self.assertEqual(ac.max_age, gc.max_age) - self.assertEqual(ac.allow_methods, - ['GET', 'PUT', 'POST', 'DELETE', 'HEAD']) - self.assertEqual(ac.allow_headers, gc.allow_headers) - - def test_no_origin_header(self): - """CORS Specification Section 6.2.1 - - If the Origin header is not present terminate this set of steps. The - request is outside the scope of this specification. - """ - request = webob.Request.blank('/') - request.method = "OPTIONS" - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin=None, - max_age=None, - allow_methods=None, - allow_headers=None, - allow_credentials=None, - expose_headers=None) - - def test_case_sensitive_origin(self): - """CORS Specification Section 6.2.2 - - If the value of the Origin header is not a case-sensitive match for - any of the values in list of origins do not set any additional headers - and terminate this set of steps. - """ - - # Test valid domain - request = webob.Request.blank('/') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://valid.example.com' - request.headers['Access-Control-Request-Method'] = 'GET' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin='http://valid.example.com', - max_age=None, - allow_methods='GET', - allow_headers='', - allow_credentials=None, - expose_headers=None) - - # Test invalid domain - request = webob.Request.blank('/') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://invalid.example.com' - request.headers['Access-Control-Request-Method'] = 'GET' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin=None, - max_age=None, - allow_methods=None, - allow_headers=None, - allow_credentials=None, - expose_headers=None) - - # Test case-sensitive mismatch domain - request = webob.Request.blank('/') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://VALID.EXAMPLE.COM' - request.headers['Access-Control-Request-Method'] = 'GET' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin=None, - max_age=None, - allow_methods=None, - allow_headers=None, - allow_credentials=None, - expose_headers=None) - - def test_simple_header_response(self): - """CORS Specification Section 3 - - A header is said to be a simple header if the header field name is an - ASCII case-insensitive match for Accept, Accept-Language, or - Content-Language or if it is an ASCII case-insensitive match for - Content-Type and the header field value media type (excluding - parameters) is an ASCII case-insensitive match for - application/x-www-form-urlencoded, multipart/form-data, or text/plain. - - NOTE: We are not testing the media type cases. - """ - - simple_headers = ','.join([ - 'accept', - 'accept-language', - 'content-language', - 'content-type' - ]) - - request = webob.Request.blank('/') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://valid.example.com' - request.headers['Access-Control-Request-Method'] = 'GET' - request.headers['Access-Control-Request-Headers'] = simple_headers - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin='http://valid.example.com', - max_age=None, - allow_methods='GET', - allow_headers=simple_headers, - allow_credentials=None, - expose_headers=None) - - def test_no_request_method(self): - """CORS Specification Section 6.2.3 - - If there is no Access-Control-Request-Method header or if parsing - failed, do not set any additional headers and terminate this set of - steps. The request is outside the scope of this specification. - """ - - # Test valid domain, valid method. - request = webob.Request.blank('/') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://get.example.com' - request.headers['Access-Control-Request-Method'] = 'GET' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin='http://get.example.com', - max_age=None, - allow_methods='GET', - allow_headers=None, - allow_credentials=None, - expose_headers=None) - - # Test valid domain, invalid HTTP method. - request = webob.Request.blank('/') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://valid.example.com' - request.headers['Access-Control-Request-Method'] = 'TEAPOT' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin=None, - max_age=None, - allow_methods=None, - allow_headers=None, - allow_credentials=None, - expose_headers=None) - - # Test valid domain, no HTTP method. - request = webob.Request.blank('/') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://valid.example.com' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin=None, - max_age=None, - allow_methods=None, - allow_headers=None, - allow_credentials=None, - expose_headers=None) - - def test_invalid_method(self): - """CORS Specification Section 6.2.3 - - If method is not a case-sensitive match for any of the values in - list of methods do not set any additional headers and terminate this - set of steps. - """ - request = webob.Request.blank('/') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://get.example.com' - request.headers['Access-Control-Request-Method'] = 'get' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin=None, - max_age=None, - allow_methods=None, - allow_headers=None, - allow_credentials=None, - expose_headers=None) - - def test_no_parse_request_headers(self): - """CORS Specification Section 6.2.4 - - If there are no Access-Control-Request-Headers headers let header - field-names be the empty list. - - If parsing failed do not set any additional headers and terminate - this set of steps. The request is outside the scope of this - specification. - """ - request = webob.Request.blank('/') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://headers.example.com' - request.headers['Access-Control-Request-Method'] = 'GET' - request.headers['Access-Control-Request-Headers'] = 'value with spaces' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin=None, - max_age=None, - allow_methods=None, - allow_headers=None, - allow_credentials=None, - expose_headers=None) - - def test_no_request_headers(self): - """CORS Specification Section 6.2.4 - - If there are no Access-Control-Request-Headers headers let header - field-names be the empty list. - """ - request = webob.Request.blank('/') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://headers.example.com' - request.headers['Access-Control-Request-Method'] = 'GET' - request.headers['Access-Control-Request-Headers'] = '' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin='http://headers.example.com', - max_age=None, - allow_methods='GET', - allow_headers=None, - allow_credentials=None, - expose_headers=None) - - def test_request_headers(self): - """CORS Specification Section 6.2.4 - - Let header field-names be the values as result of parsing the - Access-Control-Request-Headers headers. - - If there are no Access-Control-Request-Headers headers let header - field-names be the empty list. - """ - request = webob.Request.blank('/') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://headers.example.com' - request.headers['Access-Control-Request-Method'] = 'GET' - request.headers['Access-Control-Request-Headers'] = 'X-Header-1,' \ - 'X-Header-2' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin='http://headers.example.com', - max_age=None, - allow_methods='GET', - allow_headers='X-Header-1,X-Header-2', - allow_credentials=None, - expose_headers=None) - - def test_request_headers_not_permitted(self): - """CORS Specification Section 6.2.4, 6.2.6 - - If there are no Access-Control-Request-Headers headers let header - field-names be the empty list. - - If any of the header field-names is not a ASCII case-insensitive - match for any of the values in list of headers do not set any - additional headers and terminate this set of steps. - """ - request = webob.Request.blank('/') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://headers.example.com' - request.headers['Access-Control-Request-Method'] = 'GET' - request.headers['Access-Control-Request-Headers'] = 'X-Not-Exposed,' \ - 'X-Never-Exposed' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin=None, - max_age=None, - allow_methods=None, - allow_headers=None, - allow_credentials=None, - expose_headers=None) - - def test_credentials(self): - """CORS Specification Section 6.2.7 - - If the resource supports credentials add a single - Access-Control-Allow-Origin header, with the value of the Origin header - as value, and add a single Access-Control-Allow-Credentials header with - the case-sensitive string "true" as value. - - Otherwise, add a single Access-Control-Allow-Origin header, with either - the value of the Origin header or the string "*" as value. - - NOTE: We never use the "*" as origin. - """ - request = webob.Request.blank('/') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://creds.example.com' - request.headers['Access-Control-Request-Method'] = 'GET' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin='http://creds.example.com', - max_age=None, - allow_methods='GET', - allow_headers=None, - allow_credentials="true", - expose_headers=None) - - def test_optional_max_age(self): - """CORS Specification Section 6.2.8 - - Optionally add a single Access-Control-Max-Age header with as value - the amount of seconds the user agent is allowed to cache the result of - the request. - """ - request = webob.Request.blank('/') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://cached.example.com' - request.headers['Access-Control-Request-Method'] = 'GET' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin='http://cached.example.com', - max_age=3600, - allow_methods='GET', - allow_headers=None, - allow_credentials=None, - expose_headers=None) - - def test_allow_methods(self): - """CORS Specification Section 6.2.9 - - Add one or more Access-Control-Allow-Methods headers consisting of - (a subset of) the list of methods. - - Since the list of methods can be unbounded, simply returning the method - indicated by Access-Control-Request-Method (if supported) can be - enough. - """ - for method in ['GET', 'PUT', 'POST', 'DELETE']: - request = webob.Request.blank('/') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://all.example.com' - request.headers['Access-Control-Request-Method'] = method - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin='http://all.example.com', - max_age=None, - allow_methods=method, - allow_headers=None, - allow_credentials=None, - expose_headers=None) - - for method in ['PUT', 'POST', 'DELETE']: - request = webob.Request.blank('/') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://get.example.com' - request.headers['Access-Control-Request-Method'] = method - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin=None, - max_age=None, - allow_methods=None, - allow_headers=None, - allow_credentials=None, - expose_headers=None) - - def test_allow_headers(self): - """CORS Specification Section 6.2.10 - - Add one or more Access-Control-Allow-Headers headers consisting of - (a subset of) the list of headers. - - If each of the header field-names is a simple header and none is - Content-Type, this step may be skipped. - - If a header field name is a simple header and is not Content-Type, it - is not required to be listed. Content-Type is to be listed as only a - subset of its values makes it qualify as simple header. - """ - - requested_headers = 'Content-Type,X-Header-1,Cache-Control,Expires,' \ - 'Last-Modified,Pragma' - - request = webob.Request.blank('/') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://headers.example.com' - request.headers['Access-Control-Request-Method'] = 'GET' - request.headers['Access-Control-Request-Headers'] = requested_headers - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin='http://headers.example.com', - max_age=None, - allow_methods='GET', - allow_headers=requested_headers, - allow_credentials=None, - expose_headers=None) - - def test_application_options_response(self): - """Assert that an application provided OPTIONS response is honored. - - If the underlying application, via middleware or other, provides a - CORS response, its response should be honored. - """ - test_origin = 'http://creds.example.com' - - request = webob.Request.blank('/server_cors') - request.method = "OPTIONS" - request.headers['Origin'] = test_origin - request.headers['Access-Control-Request-Method'] = 'GET' - - response = request.get_response(self.application) - - # If the regular CORS handling catches this request, it should set - # the allow credentials header. This makes sure that it doesn't. - self.assertNotIn('Access-Control-Allow-Credentials', response.headers) - self.assertEqual(response.headers['Access-Control-Allow-Origin'], - test_origin) - self.assertEqual(response.headers['X-Server-Generated-Response'], - '1') - - # If the application returns an OPTIONS response without CORS - # headers, assert that we apply headers. - request = webob.Request.blank('/server_no_cors') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://get.example.com' - request.headers['Access-Control-Request-Method'] = 'GET' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin='http://get.example.com', - max_age=None, - allow_methods='GET', - allow_headers=None, - allow_credentials=None, - expose_headers=None, - has_content_type=True) - - -class CORSTestWildcard(CORSTestBase): - """Test the CORS wildcard specification.""" - - def setUp(self): - super(CORSTestWildcard, self).setUp() - - fixture = self.config_fixture # Line length accommodation - fixture.load_raw_values(group='cors', - allowed_origin='http://default.example.com', - allow_credentials='True', - max_age='', - expose_headers='', - allow_methods='GET,PUT,POST,DELETE,HEAD', - allow_headers='') - - fixture.load_raw_values(group='cors.wildcard', - allowed_origin='*', - allow_methods='GET') - - # Now that the config is set up, create our application. - self.application = cors.CORS(test_application, self.config) - - def test_config_overrides(self): - """Assert that the configuration options are properly registered.""" - - # Confirm global configuration - gc = self.config.cors - self.assertEqual(gc.allowed_origin, ['http://default.example.com']) - self.assertEqual(gc.allow_credentials, True) - self.assertEqual(gc.expose_headers, []) - self.assertEqual(gc.max_age, None) - self.assertEqual(gc.allow_methods, ['GET', 'PUT', 'POST', 'DELETE', - 'HEAD']) - self.assertEqual(gc.allow_headers, []) - - # Confirm all-methods overrides. - ac = self.config['cors.wildcard'] - self.assertEqual(ac.allowed_origin, ['*']) - self.assertEqual(gc.allow_credentials, True) - self.assertEqual(ac.expose_headers, gc.expose_headers) - self.assertEqual(ac.max_age, gc.max_age) - self.assertEqual(ac.allow_methods, ['GET']) - self.assertEqual(ac.allow_headers, gc.allow_headers) - - def test_wildcard_domain(self): - """CORS Specification, Wildcards - - If the configuration file specifies CORS settings for the wildcard '*' - domain, it should return those for all origin domains except for the - overrides. - """ - - # Test valid domain - request = webob.Request.blank('/') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://default.example.com' - request.headers['Access-Control-Request-Method'] = 'GET' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin='http://default.example.com', - max_age=None, - allow_methods='GET', - allow_headers='', - allow_credentials='true', - expose_headers=None) - - # Test valid domain - request = webob.Request.blank('/') - request.method = "GET" - request.headers['Origin'] = 'http://default.example.com' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin='http://default.example.com', - max_age=None, - allow_headers='', - allow_credentials='true', - expose_headers=None, - has_content_type=True) - - # Test invalid domain - request = webob.Request.blank('/') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://invalid.example.com' - request.headers['Access-Control-Request-Method'] = 'GET' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin='*', - max_age=None, - allow_methods='GET', - allow_headers='', - allow_credentials='true', - expose_headers=None, - has_content_type=True) - - -class CORSTestLatentProperties(CORSTestBase): - """Test the CORS wildcard specification.""" - - def setUp(self): - super(CORSTestLatentProperties, self).setUp() - - fixture = self.config_fixture # Line length accommodation - fixture.load_raw_values(group='cors', - allowed_origin='http://default.example.com', - allow_credentials='True', - max_age='', - expose_headers='X-Configured', - allow_methods='GET', - allow_headers='X-Configured') - - # Now that the config is set up, create our application. - self.application = cors.CORS(test_application, self.config) - - def test_latent_methods(self): - """Assert that latent HTTP methods are permitted.""" - - self.application.set_latent(allow_headers=None, - expose_headers=None, - allow_methods=['POST']) - - request = webob.Request.blank('/') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://default.example.com' - request.headers['Access-Control-Request-Method'] = 'POST' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin='http://default.example.com', - max_age=None, - allow_methods='POST', - allow_headers='', - allow_credentials='true', - expose_headers=None) - - def test_invalid_latent_methods(self): - """Assert that passing a non-list is caught.""" - - self.assertRaises(TypeError, - self.application.set_latent, - allow_methods='POST') - - def test_latent_allow_headers(self): - """Assert that latent HTTP headers are permitted.""" - - self.application.set_latent(allow_headers=['X-Latent'], - expose_headers=None, - allow_methods=None) - - request = webob.Request.blank('/') - request.method = "OPTIONS" - request.headers['Origin'] = 'http://default.example.com' - request.headers['Access-Control-Request-Method'] = 'GET' - request.headers[ - 'Access-Control-Request-Headers'] = 'X-Latent,X-Configured' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin='http://default.example.com', - max_age=None, - allow_methods='GET', - allow_headers='X-Latent,X-Configured', - allow_credentials='true', - expose_headers=None) - - def test_invalid_latent_allow_headers(self): - """Assert that passing a non-list is caught in allow headers.""" - - self.assertRaises(TypeError, - self.application.set_latent, - allow_headers='X-Latent') - - def test_latent_expose_headers(self): - """Assert that latent HTTP headers are exposed.""" - - self.application.set_latent(allow_headers=None, - expose_headers=[ - 'X-Server-Generated-Response'], - allow_methods=None) - - request = webob.Request.blank('/') - request.method = "GET" - request.headers['Origin'] = 'http://default.example.com' - response = request.get_response(self.application) - self.assertCORSResponse(response, - status='200 OK', - allow_origin='http://default.example.com', - max_age=None, - allow_methods=None, - allow_headers=None, - allow_credentials='true', - expose_headers='X-Configured,' - 'X-Server-Generated-Response', - has_content_type=True) - - def test_invalid_latent_expose_headers(self): - """Assert that passing a non-list is caught in expose headers.""" - - # Add headers to the application. - - self.assertRaises(TypeError, - self.application.set_latent, - expose_headers='X-Latent') diff --git a/oslo_middleware/tests/test_entry_points.py b/oslo_middleware/tests/test_entry_points.py deleted file mode 100644 index d7368ac..0000000 --- a/oslo_middleware/tests/test_entry_points.py +++ /dev/null @@ -1,38 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslotest import base -import stevedore -from testtools import matchers - - -class TestPasteDeploymentEntryPoints(base.BaseTestCase): - - def test_entry_points(self): - factory_classes = { - 'catch_errors': 'CatchErrors', - 'correlation_id': 'CorrelationId', - 'cors': 'CORS', - 'debug': 'Debug', - 'healthcheck': 'Healthcheck', - 'http_proxy_to_wsgi': 'HTTPProxyToWSGI', - 'request_id': 'RequestId', - 'sizelimit': 'RequestBodySizeLimiter', - 'ssl': 'SSLMiddleware', - } - - em = stevedore.ExtensionManager('paste.filter_factory') - - # Ensure all the factories are defined by their names - factory_names = [extension.name for extension in em] - self.assertThat(factory_names, - matchers.ContainsAll(factory_classes)) diff --git a/oslo_middleware/tests/test_healthcheck.py b/oslo_middleware/tests/test_healthcheck.py deleted file mode 100644 index df73969..0000000 --- a/oslo_middleware/tests/test_healthcheck.py +++ /dev/null @@ -1,189 +0,0 @@ -# Copyright (c) 2013 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import threading -import time - -import mock -from oslotest import base as test_base -import requests -import webob.dec -import webob.exc - -from oslo_middleware import healthcheck -from oslo_middleware.healthcheck import __main__ - - -class HealthcheckMainTests(test_base.BaseTestCase): - - def test_startup_response(self): - server = __main__.create_server(0) - th = threading.Thread(target=server.serve_forever) - th.start() - self.addCleanup(server.shutdown) - while True: - try: - # Connecting on 0.0.0.0 is not allowed on windows - # The operating system will return WSAEADDRNOTAVAIL which - # in turn will throw a requests.ConnectionError - r = requests.get("http://127.0.0.1:%s" % ( - server.server_address[1])) - except requests.ConnectionError: - # Server hasn't started up yet, try again in a few. - time.sleep(1) - else: - self.assertEqual(200, r.status_code) - break - - -class HealthcheckTests(test_base.BaseTestCase): - - @staticmethod - @webob.dec.wsgify - def application(req): - return 'Hello, World!!!' - - def _do_test_request(self, conf={}, path='/healthcheck', - accept='text/plain', method='GET', - server_port=80): - self.app = healthcheck.Healthcheck(self.application, conf) - req = webob.Request.blank(path, accept=accept, method=method) - req.server_port = server_port - res = req.get_response(self.app) - return res - - def _do_test(self, conf={}, path='/healthcheck', - expected_code=webob.exc.HTTPOk.code, - expected_body=b'', accept='text/plain', - method='GET', server_port=80): - res = self._do_test_request(conf=conf, path=path, - accept=accept, method=method, - server_port=server_port) - self.assertEqual(expected_code, res.status_int) - self.assertEqual(expected_body, res.body) - - def test_default_path_match(self): - self._do_test() - - def test_default_path_not_match(self): - self._do_test(path='/toto', expected_body=b'Hello, World!!!') - - def test_configured_path_match(self): - conf = {'path': '/hidden_healthcheck'} - self._do_test(conf, path='/hidden_healthcheck') - - def test_configured_path_not_match(self): - conf = {'path': '/hidden_healthcheck'} - self._do_test(conf, path='/toto', expected_body=b'Hello, World!!!') - - @mock.patch('oslo_middleware.healthcheck.disable_by_file.LOG') - def test_disablefile_unconfigured(self, fake_log): - fake_warn = fake_log.warning - conf = {'backends': 'disable_by_file'} - self._do_test(conf, expected_body=b'OK') - self.assertIn('disable_by_file', self.app._backends.names()) - fake_warn.assert_called_once_with( - 'DisableByFile healthcheck middleware ' - 'enabled without disable_by_file_path ' - 'set' - ) - - def test_disablefile_enabled(self): - conf = {'backends': 'disable_by_file', - 'disable_by_file_path': '/foobar'} - self._do_test(conf, expected_body=b'OK') - self.assertIn('disable_by_file', self.app._backends.names()) - - def test_disablefile_enabled_head(self): - conf = {'backends': 'disable_by_file', - 'disable_by_file_path': '/foobar'} - self._do_test(conf, expected_body=b'', method='HEAD', - expected_code=webob.exc.HTTPNoContent.code) - - def test_disablefile_enabled_html_detailed(self): - conf = {'backends': 'disable_by_file', - 'disable_by_file_path': '/foobar', 'detailed': True} - res = self._do_test_request(conf, accept="text/html") - self.assertIn(b'Result of 1 checks:', res.body) - self.assertIn(b'OK', res.body) - self.assertEqual(webob.exc.HTTPOk.code, res.status_int) - - def test_disablefile_disabled(self): - filename = self.create_tempfiles([('test', 'foobar')])[0] - conf = {'backends': 'disable_by_file', - 'disable_by_file_path': filename} - self._do_test(conf, - expected_code=webob.exc.HTTPServiceUnavailable.code, - expected_body=b'DISABLED BY FILE') - self.assertIn('disable_by_file', self.app._backends.names()) - - def test_disablefile_disabled_head(self): - filename = self.create_tempfiles([('test', 'foobar')])[0] - conf = {'backends': 'disable_by_file', - 'disable_by_file_path': filename} - self._do_test(conf, - expected_code=webob.exc.HTTPServiceUnavailable.code, - expected_body=b'', method='HEAD') - self.assertIn('disable_by_file', self.app._backends.names()) - - def test_disablefile_disabled_html_detailed(self): - filename = self.create_tempfiles([('test', 'foobar')])[0] - conf = {'backends': 'disable_by_file', - 'disable_by_file_path': filename, 'detailed': True} - res = self._do_test_request(conf, accept="text/html") - self.assertIn(b'DISABLED BY FILE', res.body) - self.assertEqual(webob.exc.HTTPServiceUnavailable.code, - res.status_int) - - def test_two_backends(self): - filename = self.create_tempfiles([('test', 'foobar')])[0] - conf = {'backends': 'disable_by_file,disable_by_file', - 'disable_by_file_path': filename} - self._do_test(conf, - expected_code=webob.exc.HTTPServiceUnavailable.code, - expected_body=b'DISABLED BY FILE\nDISABLED BY FILE') - self.assertIn('disable_by_file', self.app._backends.names()) - - def test_disable_by_port_file(self): - filename = self.create_tempfiles([('test', 'foobar')])[0] - conf = {'backends': 'disable_by_files_ports', - 'disable_by_file_paths': "80:%s" % filename} - self._do_test(conf, - expected_code=webob.exc.HTTPServiceUnavailable.code, - expected_body=b'DISABLED BY FILE') - self.assertIn('disable_by_files_ports', self.app._backends.names()) - - def test_no_disable_by_port_file(self): - filename = self.create_tempfiles([('test', 'foobar')])[0] - conf = {'backends': 'disable_by_files_ports', - 'disable_by_file_paths': "8000:%s" % filename} - self._do_test(conf, - expected_code=webob.exc.HTTPOk.code, - expected_body=b'OK') - self.assertIn('disable_by_files_ports', self.app._backends.names()) - - def test_disable_by_port_many_files(self): - filename = self.create_tempfiles([('test', 'foobar')])[0] - filename2 = self.create_tempfiles([('test2', 'foobar2')])[0] - conf = {'backends': 'disable_by_files_ports', - 'disable_by_file_paths': "80:%s,81:%s" % (filename, filename2)} - self._do_test(conf, - expected_code=webob.exc.HTTPServiceUnavailable.code, - expected_body=b'DISABLED BY FILE') - self._do_test(conf, - expected_code=webob.exc.HTTPServiceUnavailable.code, - expected_body=b'DISABLED BY FILE', - server_port=81) - self.assertIn('disable_by_files_ports', self.app._backends.names()) diff --git a/oslo_middleware/tests/test_http_proxy_to_wsgi.py b/oslo_middleware/tests/test_http_proxy_to_wsgi.py deleted file mode 100644 index 26baa77..0000000 --- a/oslo_middleware/tests/test_http_proxy_to_wsgi.py +++ /dev/null @@ -1,131 +0,0 @@ -# Copyright (c) 2015 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -from wsgiref import util - -from oslotest import base as test_base -import webob - -from oslo_middleware import http_proxy_to_wsgi - - -class TestHTTPProxyToWSGI(test_base.BaseTestCase): - - def setUp(self): - super(TestHTTPProxyToWSGI, self).setUp() - - @webob.dec.wsgify() - def fake_app(req): - return util.application_uri(req.environ) - - self.middleware = http_proxy_to_wsgi.HTTPProxyToWSGI(fake_app) - self.middleware.oslo_conf.set_override('enable_proxy_headers_parsing', - True, - group='oslo_middleware', - enforce_type=True) - self.request = webob.Request.blank('/foo/bar', method='POST') - - def test_backward_compat(self): - @webob.dec.wsgify() - def fake_app(req): - return util.application_uri(req.environ) - - self.middleware = http_proxy_to_wsgi.HTTPProxyToWSGIMiddleware( - fake_app) - response = self.request.get_response(self.middleware) - self.assertEqual(b"http://localhost:80/", response.body) - - def test_no_headers(self): - response = self.request.get_response(self.middleware) - self.assertEqual(b"http://localhost:80/", response.body) - - def test_url_translate_ssl(self): - self.request.headers['X-Forwarded-Proto'] = "https" - response = self.request.get_response(self.middleware) - self.assertEqual(b"https://localhost:80/", response.body) - - def test_url_translate_ssl_port(self): - self.request.headers['X-Forwarded-Proto'] = "https" - self.request.headers['X-Forwarded-Host'] = "example.com:123" - response = self.request.get_response(self.middleware) - self.assertEqual(b"https://example.com:123/", response.body) - - def test_url_translate_host_ipv6(self): - self.request.headers['X-Forwarded-Proto'] = "https" - self.request.headers['X-Forwarded-Host'] = "[f00:b4d::1]:123" - response = self.request.get_response(self.middleware) - self.assertEqual(b"https://[f00:b4d::1]:123/", response.body) - - def test_url_translate_base(self): - self.request.headers['X-Forwarded-Prefix'] = "/bla" - response = self.request.get_response(self.middleware) - self.assertEqual(b"http://localhost:80/bla", response.body) - - def test_url_translate_port_and_base_and_proto_and_host(self): - self.request.headers['X-Forwarded-Proto'] = "https" - self.request.headers['X-Forwarded-Prefix'] = "/bla" - self.request.headers['X-Forwarded-Host'] = "example.com:8043" - response = self.request.get_response(self.middleware) - self.assertEqual(b"https://example.com:8043/bla", response.body) - - def test_rfc7239_invalid(self): - self.request.headers['Forwarded'] = ( - "iam=anattacker;metoo, I will crash you!!P;m,xx") - response = self.request.get_response(self.middleware) - self.assertEqual(b"http://localhost:80/", response.body) - - def test_rfc7239_proto(self): - self.request.headers['Forwarded'] = ( - "for=foobar;proto=https, for=foobaz;proto=http") - response = self.request.get_response(self.middleware) - self.assertEqual(b"https://localhost:80/", response.body) - - def test_rfc7239_proto_host(self): - self.request.headers['Forwarded'] = ( - "for=foobar;proto=https;host=example.com, for=foobaz;proto=http") - response = self.request.get_response(self.middleware) - self.assertEqual(b"https://example.com/", response.body) - - def test_rfc7239_proto_host_base(self): - self.request.headers['Forwarded'] = ( - "for=foobar;proto=https;host=example.com:8043, for=foobaz") - self.request.headers['X-Forwarded-Prefix'] = "/bla" - response = self.request.get_response(self.middleware) - self.assertEqual(b"https://example.com:8043/bla", response.body) - - -class TestHTTPProxyToWSGIDisabled(test_base.BaseTestCase): - - def setUp(self): - super(TestHTTPProxyToWSGIDisabled, self).setUp() - - @webob.dec.wsgify() - def fake_app(req): - return util.application_uri(req.environ) - - self.middleware = http_proxy_to_wsgi.HTTPProxyToWSGI(fake_app) - self.middleware.oslo_conf.set_override('enable_proxy_headers_parsing', - False, - group='oslo_middleware', - enforce_type=True) - self.request = webob.Request.blank('/foo/bar', method='POST') - - def test_no_headers(self): - response = self.request.get_response(self.middleware) - self.assertEqual(b"http://localhost:80/", response.body) - - def test_url_translate_ssl_has_no_effect(self): - self.request.headers['X-Forwarded-Proto'] = "https" - self.request.headers['X-Forwarded-Host'] = "example.com:123" - response = self.request.get_response(self.middleware) - self.assertEqual(b"http://localhost:80/", response.body) diff --git a/oslo_middleware/tests/test_opts.py b/oslo_middleware/tests/test_opts.py deleted file mode 100644 index 763d550..0000000 --- a/oslo_middleware/tests/test_opts.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_middleware import opts -from oslotest.base import BaseTestCase - - -class TestOptionDiscovery(BaseTestCase): - - def test_all(self): - opts.list_opts() - - def test_sizelimit(self): - opts.list_opts_sizelimit() - - def test_cors(self): - opts.list_opts_cors() - - def test_ssl(self): - opts.list_opts_ssl() diff --git a/oslo_middleware/tests/test_request_id.py b/oslo_middleware/tests/test_request_id.py deleted file mode 100644 index 76f3696..0000000 --- a/oslo_middleware/tests/test_request_id.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (c) 2013 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -from oslotest import base as test_base -from testtools import matchers -import webob -import webob.dec - -from oslo_middleware import request_id - - -class RequestIdTest(test_base.BaseTestCase): - def test_generate_request_id(self): - @webob.dec.wsgify - def application(req): - return req.environ[request_id.ENV_REQUEST_ID] - - app = request_id.RequestId(application) - req = webob.Request.blank('/test') - res = req.get_response(app) - res_req_id = res.headers.get(request_id.HTTP_RESP_HEADER_REQUEST_ID) - if isinstance(res_req_id, bytes): - res_req_id = res_req_id.decode('utf-8') - self.assertThat(res_req_id, matchers.StartsWith('req-')) - # request-id in request environ is returned as response body - self.assertEqual(res_req_id, res.body.decode('utf-8')) diff --git a/oslo_middleware/tests/test_sizelimit.py b/oslo_middleware/tests/test_sizelimit.py deleted file mode 100644 index dc29cd0..0000000 --- a/oslo_middleware/tests/test_sizelimit.py +++ /dev/null @@ -1,108 +0,0 @@ -# Copyright (c) 2012 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_config import fixture as config -from oslotest import base as test_base -import six -import webob - -from oslo_middleware import sizelimit - - -class TestLimitingReader(test_base.BaseTestCase): - - def test_limiting_reader(self): - BYTES = 1024 - bytes_read = 0 - data = six.StringIO("*" * BYTES) - for chunk in sizelimit.LimitingReader(data, BYTES): - bytes_read += len(chunk) - - self.assertEqual(bytes_read, BYTES) - - bytes_read = 0 - data = six.StringIO("*" * BYTES) - reader = sizelimit.LimitingReader(data, BYTES) - byte = reader.read(1) - while len(byte) != 0: - bytes_read += 1 - byte = reader.read(1) - - self.assertEqual(bytes_read, BYTES) - - def test_read_default_value(self): - BYTES = 1024 - data_str = "*" * BYTES - data = six.StringIO(data_str) - reader = sizelimit.LimitingReader(data, BYTES) - res = reader.read() - self.assertEqual(data_str, res) - - def test_limiting_reader_fails(self): - BYTES = 1024 - - def _consume_all_iter(): - bytes_read = 0 - data = six.StringIO("*" * BYTES) - for chunk in sizelimit.LimitingReader(data, BYTES - 1): - bytes_read += len(chunk) - - self.assertRaises(webob.exc.HTTPRequestEntityTooLarge, - _consume_all_iter) - - def _consume_all_read(): - bytes_read = 0 - data = six.StringIO("*" * BYTES) - reader = sizelimit.LimitingReader(data, BYTES - 1) - byte = reader.read(1) - while len(byte) != 0: - bytes_read += 1 - byte = reader.read(1) - - self.assertRaises(webob.exc.HTTPRequestEntityTooLarge, - _consume_all_read) - - -class TestRequestBodySizeLimiter(test_base.BaseTestCase): - - def setUp(self): - super(TestRequestBodySizeLimiter, self).setUp() - self.useFixture(config.Config()) - - @webob.dec.wsgify() - def fake_app(req): - return webob.Response(req.body) - - self.middleware = sizelimit.RequestBodySizeLimiter(fake_app) - self.MAX_REQUEST_BODY_SIZE = ( - self.middleware.oslo_conf.oslo_middleware.max_request_body_size) - self.request = webob.Request.blank('/', method='POST') - - def test_content_length_acceptable(self): - self.request.headers['Content-Length'] = self.MAX_REQUEST_BODY_SIZE - self.request.body = b"0" * self.MAX_REQUEST_BODY_SIZE - response = self.request.get_response(self.middleware) - self.assertEqual(response.status_int, 200) - - def test_content_length_too_large(self): - self.request.headers['Content-Length'] = self.MAX_REQUEST_BODY_SIZE + 1 - self.request.body = b"0" * (self.MAX_REQUEST_BODY_SIZE + 1) - response = self.request.get_response(self.middleware) - self.assertEqual(response.status_int, 413) - - def test_request_too_large_no_content_length(self): - self.request.body = b"0" * (self.MAX_REQUEST_BODY_SIZE + 1) - self.request.headers['Content-Length'] = None - response = self.request.get_response(self.middleware) - self.assertEqual(response.status_int, 413) diff --git a/oslo_middleware/tests/test_ssl.py b/oslo_middleware/tests/test_ssl.py deleted file mode 100644 index e493a3a..0000000 --- a/oslo_middleware/tests/test_ssl.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright (c) 2015 Thales Services SAS -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_config import fixture as config -from oslotest import base -import webob - -from oslo_middleware import ssl - - -class SSLMiddlewareTest(base.BaseTestCase): - - def setUp(self): - super(SSLMiddlewareTest, self).setUp() - self.useFixture(config.Config()) - - def _test_scheme(self, expected, headers, secure_proxy_ssl_header=None): - middleware = ssl.SSLMiddleware(None) - if secure_proxy_ssl_header: - middleware.oslo_conf.set_override( - 'secure_proxy_ssl_header', secure_proxy_ssl_header, - group='oslo_middleware', enforce_type=True) - request = webob.Request.blank('http://example.com/', headers=headers) - - # Ensure ssl middleware does not stop pipeline execution - self.assertIsNone(middleware.process_request(request)) - - self.assertEqual(expected, request.scheme) - - def test_without_forwarded_protocol(self): - self._test_scheme('http', {}) - - def test_with_forwarded_protocol(self): - headers = {'X-Forwarded-Proto': 'https'} - self._test_scheme('https', headers) - - def test_with_custom_header(self): - headers = {'X-Forwarded-Proto': 'https'} - self._test_scheme('http', headers, - secure_proxy_ssl_header='X-My-Header') - - def test_with_custom_header_and_forwarded_protocol(self): - headers = {'X-My-Header': 'https'} - self._test_scheme('https', headers, - secure_proxy_ssl_header='X-My-Header') diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 0c6af5d..0000000 --- a/requirements.txt +++ /dev/null @@ -1,14 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -pbr>=1.6 # Apache-2.0 -Jinja2>=2.8 # BSD License (3 clause) -oslo.config>=3.14.0 # Apache-2.0 -oslo.context>=2.4.0 # Apache-2.0 -oslo.i18n>=2.1.0 # Apache-2.0 -oslo.utils>=3.16.0 # Apache-2.0 -six>=1.9.0 # MIT -stevedore>=1.16.0 # Apache-2.0 -WebOb>=1.2.3 # MIT -debtcollector>=1.2.0 # Apache-2.0 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index d2a7686..0000000 --- a/setup.cfg +++ /dev/null @@ -1,74 +0,0 @@ -[metadata] -name = oslo.middleware -summary = Oslo Middleware library -description-file = - README.rst -author = OpenStack -author-email = openstack-dev@lists.openstack.org -home-page = http://wiki.openstack.org/wiki/Oslo#oslo.middleware -classifier = - Environment :: OpenStack - Intended Audience :: Information Technology - Intended Audience :: System Administrators - License :: OSI Approved :: Apache Software License - Operating System :: POSIX :: Linux - Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.4 - -[files] -packages = - oslo_middleware - -[entry_points] -oslo.config.opts = - oslo.middleware = oslo_middleware.opts:list_opts - oslo.middleware.cors = oslo_middleware.opts:list_opts_cors - oslo.middleware.sizelimit = oslo_middleware.opts:list_opts_sizelimit - oslo.middleware.ssl = oslo_middleware.opts:list_opts_ssl - oslo.middleware.http_proxy_to_wsgi = oslo_middleware.opts:list_opts_http_proxy_to_wsgi - -oslo.middleware.healthcheck = - disable_by_file = oslo_middleware.healthcheck.disable_by_file:DisableByFileHealthcheck - disable_by_files_ports = oslo_middleware.healthcheck.disable_by_file:DisableByFilesPortsHealthcheck - -paste.filter_factory = - catch_errors = oslo_middleware:CatchErrors.factory - correlation_id = oslo_middleware:CorrelationId.factory - cors = oslo_middleware:CORS.factory - debug = oslo_middleware:Debug.factory - healthcheck = oslo_middleware:Healthcheck.factory - http_proxy_to_wsgi = oslo_middleware:HTTPProxyToWSGI.factory - request_id = oslo_middleware:RequestId.factory - sizelimit = oslo_middleware:RequestBodySizeLimiter.factory - ssl = oslo_middleware:SSLMiddleware.factory - -[build_sphinx] -source-dir = doc/source -build-dir = doc/build -all_files = 1 - -[upload_sphinx] -upload-dir = doc/build/html - -[compile_catalog] -directory = oslo_middleware/locale -domain = oslo_middleware - -[update_catalog] -domain = oslo_middleware -output_dir = oslo_middleware/locale -input_file = oslo_middleware/locale/oslo_middleware.pot - -[extract_messages] -keywords = _ gettext ngettext l_ lazy_gettext -mapping_file = babel.cfg -output_file = oslo_middleware/locale/oslo_middleware.pot - -[pbr] -warnerrors = True - -[wheel] -universal = 1 diff --git a/setup.py b/setup.py deleted file mode 100644 index 782bb21..0000000 --- a/setup.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT -import setuptools - -# In python < 2.7.4, a lazy loading of package `pbr` will break -# setuptools if some other modules registered functions in `atexit`. -# solution from: http://bugs.python.org/issue15881#msg170215 -try: - import multiprocessing # noqa -except ImportError: - pass - -setuptools.setup( - setup_requires=['pbr>=1.8'], - pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index 5f53419..0000000 --- a/test-requirements.txt +++ /dev/null @@ -1,12 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -fixtures>=3.0.0 # Apache-2.0/BSD -hacking<0.11,>=0.10.0 -mock>=2.0 # BSD -oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0 -oslotest>=1.10.0 # Apache-2.0 -sphinx!=1.3b1,<1.3,>=1.2.1 # BSD -testtools>=1.4.0 # MIT -coverage>=3.6 # Apache-2.0 diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 9ff7d03..0000000 --- a/tox.ini +++ /dev/null @@ -1,37 +0,0 @@ -[tox] -minversion = 1.6 -envlist = py34,py27,pypy,pep8 - -[testenv] -deps = -r{toxinidir}/test-requirements.txt -commands = python setup.py testr --slowest --testr-args='{posargs}' - -[testenv:pep8] -commands = flake8 - -[testenv:venv] -commands = {posargs} - -[testenv:docs] -commands = python setup.py build_sphinx - -[testenv:cover] -commands = python setup.py test --coverage --coverage-package-name=oslo_middleware --testr-args='{posargs}' - -[flake8] -# E123, E125 skipped as they are invalid PEP-8. - -show-source = True -ignore = E123,E125 -exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,__init__.py - -[hacking] -import_exceptions = oslo_middleware._i18n - -[testenv:pip-missing-reqs] -# do not install test-requirements as that will pollute the virtualenv for -# determining missing packages -# this also means that pip-missing-reqs must be installed separately, outside -# of the requirements.txt files -deps = pip_missing_reqs -commands = pip-missing-reqs -d --ignore-module=oslo_middleware* --ignore-module=pkg_resources --ignore-file=oslo_middleware/tests/* oslo_middleware