VMware vSphere Integrated Containers provider (#206)
* Add Virtual Kubelet provider for VIC Initial virtual kubelet provider for VMware VIC. This provider currently handles creating and starting of a pod VM via the VIC portlayer and persona server. Image store handling via the VIC persona server. This provider currently requires the feature/wolfpack branch of VIC. * Added pod stop and delete. Also added node capacity. Added the ability to stop and delete pod VMs via VIC. Also retrieve node capacity information from the VCH. * Cleanup and readme file Some file clean up and added a Readme.md markdown file for the VIC provider. * Cleaned up errors, added function comments, moved operation code 1. Cleaned up error handling. Set standard for creating errors. 2. Added method prototype comments for all interface functions. 3. Moved PodCreator, PodStarter, PodStopper, and PodDeleter to a new folder. * Add mocking code and unit tests for podcache, podcreator, and podstarter Used the unit test framework used in VIC to handle assertions in the provider's unit test. Mocking code generated using OSS project mockery, which is compatible with the testify assertion framework. * Vendored packages for the VIC provider Requires feature/wolfpack branch of VIC and a few specific commit sha of projects used within VIC. * Implementation of POD Stopper and Deleter unit tests (#4) * Updated files for initial PR
This commit is contained in:
26
vendor/github.com/go-openapi/runtime/.editorconfig
generated
vendored
Normal file
26
vendor/github.com/go-openapi/runtime/.editorconfig
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# Set default charset
|
||||
[*.{js,py,go,scala,rb,java,html,css,less,sass,md}]
|
||||
charset = utf-8
|
||||
|
||||
# Tab indentation (no size specified)
|
||||
[*.go]
|
||||
indent_style = tab
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
# Matches the exact files either package.json or .travis.yml
|
||||
[{package.json,.travis.yml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
117
vendor/github.com/go-openapi/runtime/.github/CONTRIBUTING.md
generated
vendored
Normal file
117
vendor/github.com/go-openapi/runtime/.github/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
## Contribution Guidelines
|
||||
|
||||
### Pull requests are always welcome
|
||||
|
||||
We are always thrilled to receive pull requests, and do our best to
|
||||
process them as fast as possible. Not sure if that typo is worth a pull
|
||||
request? Do it! We will appreciate it.
|
||||
|
||||
If your pull request is not accepted on the first try, don't be
|
||||
discouraged! If there's a problem with the implementation, hopefully you
|
||||
received feedback on what to improve.
|
||||
|
||||
We're trying very hard to keep go-swagger lean and focused. We don't want it
|
||||
to do everything for everybody. This means that we might decide against
|
||||
incorporating a new feature. However, there might be a way to implement
|
||||
that feature *on top of* go-swagger.
|
||||
|
||||
|
||||
### Conventions
|
||||
|
||||
Fork the repo and make changes on your fork in a feature branch:
|
||||
|
||||
- If it's a bugfix branch, name it XXX-something where XXX is the number of the
|
||||
issue
|
||||
- If it's a feature branch, create an enhancement issue to announce your
|
||||
intentions, and name it XXX-something where XXX is the number of the issue.
|
||||
|
||||
Submit unit tests for your changes. Go has a great test framework built in; use
|
||||
it! Take a look at existing tests for inspiration. Run the full test suite on
|
||||
your branch before submitting a pull request.
|
||||
|
||||
Update the documentation when creating or modifying features. Test
|
||||
your documentation changes for clarity, concision, and correctness, as
|
||||
well as a clean documentation build. See ``docs/README.md`` for more
|
||||
information on building the docs and how docs get released.
|
||||
|
||||
Write clean code. Universally formatted code promotes ease of writing, reading,
|
||||
and maintenance. Always run `gofmt -s -w file.go` on each changed file before
|
||||
committing your changes. Most editors have plugins that do this automatically.
|
||||
|
||||
Pull requests descriptions should be as clear as possible and include a
|
||||
reference to all the issues that they address.
|
||||
|
||||
Pull requests must not contain commits from other users or branches.
|
||||
|
||||
Commit messages must start with a capitalized and short summary (max. 50
|
||||
chars) written in the imperative, followed by an optional, more detailed
|
||||
explanatory text which is separated from the summary by an empty line.
|
||||
|
||||
Code review comments may be added to your pull request. Discuss, then make the
|
||||
suggested modifications and push additional commits to your feature branch. Be
|
||||
sure to post a comment after pushing. The new commits will show up in the pull
|
||||
request automatically, but the reviewers will not be notified unless you
|
||||
comment.
|
||||
|
||||
Before the pull request is merged, make sure that you squash your commits into
|
||||
logical units of work using `git rebase -i` and `git push -f`. After every
|
||||
commit the test suite should be passing. Include documentation changes in the
|
||||
same commit so that a revert would remove all traces of the feature or fix.
|
||||
|
||||
Commits that fix or close an issue should include a reference like `Closes #XXX`
|
||||
or `Fixes #XXX`, which will automatically close the issue when merged.
|
||||
|
||||
### Sign your work
|
||||
|
||||
The sign-off is a simple line at the end of the explanation for the
|
||||
patch, which certifies that you wrote it or otherwise have the right to
|
||||
pass it on as an open-source patch. The rules are pretty simple: if you
|
||||
can certify the below (from
|
||||
[developercertificate.org](http://developercertificate.org/)):
|
||||
|
||||
```
|
||||
Developer Certificate of Origin
|
||||
Version 1.1
|
||||
|
||||
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
|
||||
660 York Street, Suite 102,
|
||||
San Francisco, CA 94110 USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this
|
||||
license document, but changing it is not allowed.
|
||||
|
||||
|
||||
Developer's Certificate of Origin 1.1
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part
|
||||
by me, under the same open source license (unless I am
|
||||
permitted to submit under a different license), as indicated
|
||||
in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified
|
||||
it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
||||
```
|
||||
|
||||
then you just add a line to every git commit message:
|
||||
|
||||
Signed-off-by: Joe Smith <joe@gmail.com>
|
||||
|
||||
using your real name (sorry, no pseudonyms or anonymous contributions.)
|
||||
|
||||
You can add the sign off when creating the git commit via `git commit -s`.
|
||||
5
vendor/github.com/go-openapi/runtime/.gitignore
generated
vendored
Normal file
5
vendor/github.com/go-openapi/runtime/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
secrets.yml
|
||||
coverage.out
|
||||
*.cov
|
||||
*.out
|
||||
playground
|
||||
24
vendor/github.com/go-openapi/runtime/.travis.yml
generated
vendored
Normal file
24
vendor/github.com/go-openapi/runtime/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.7.1
|
||||
install:
|
||||
- go get -u github.com/axw/gocov/gocov
|
||||
- go get -u gopkg.in/matm/v1/gocov-html
|
||||
- go get -u github.com/cee-dub/go-junit-report
|
||||
- go get -u github.com/stretchr/testify/assert
|
||||
- go get -u golang.org/x/net/context
|
||||
- go get -u gopkg.in/yaml.v2
|
||||
- go get -u github.com/gorilla/context
|
||||
- go get -u github.com/go-openapi/analysis
|
||||
- go get -u github.com/go-openapi/errors
|
||||
- go get -u github.com/go-openapi/loads
|
||||
- go get -u github.com/go-openapi/strfmt
|
||||
- go get -u github.com/go-openapi/validate
|
||||
- go get -u github.com/docker/go-units
|
||||
script:
|
||||
- ./hack/coverage
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
notifications:
|
||||
slack:
|
||||
secure: EmObnQuM9Mw8J9vpFaKKHqSMN4Wsr/A9+v7ewAD5cEhA0T1P4m7MbJMiJOhxUhj/X+BFh2DamW+P2lT8mybj5wg8wnkQ2BteKA8Tawi6f9PRw2NRheO8tAi8o/npLnlmet0kc93mn+oLuqHw36w4+j5mkOl2FghkfGiUVhwrhkCP7KXQN+3TU87e+/HzQumlJ3nsE+6terVxkH3PmaUTsS5ONaODZfuxFpfb7RsoEl3skHf6d+tr+1nViLxxly7558Nc33C+W1mr0qiEvMLZ+kJ/CpGWBJ6CUJM3jm6hNe2eMuIPwEK2hxZob8c7n22VPap4K6a0bBRoydoDXaba+2sD7Ym6ivDO/DVyL44VeBBLyIiIBylDGQdZH+6SoWm90Qe/i7tnY/T5Ao5igT8f3cfQY1c3EsTfqmlDfrhmACBmwSlgkdVBLTprHL63JMY24LWmh4jhxsmMRZhCL4dze8su1w6pLN/pD1pGHtKYCEVbdTmaM3PblNRFf12XB7qosmQsgUndH4Vq3bTbU0s1pKjeDhRyLvFzvR0TBbo0pDLEoF1A/i5GVFWa7yLZNUDudQERRh7qv/xBl2excIaQ1sV4DSVm7bAE9l6Kp+yeHQJW2uN6Y3X8wu9gB9nv9l5HBze7wh8KE6PyWAOLYYqZg9/sAtsv/2GcQqXcKFF1zcA=
|
||||
74
vendor/github.com/go-openapi/runtime/CODE_OF_CONDUCT.md
generated
vendored
Normal file
74
vendor/github.com/go-openapi/runtime/CODE_OF_CONDUCT.md
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||
nationality, personal appearance, race, religion, or sexual identity and
|
||||
orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at ivan+abuse@flanders.co.nz. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
202
vendor/github.com/go-openapi/runtime/LICENSE
generated
vendored
Normal file
202
vendor/github.com/go-openapi/runtime/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
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.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
5
vendor/github.com/go-openapi/runtime/README.md
generated
vendored
Normal file
5
vendor/github.com/go-openapi/runtime/README.md
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# runtime [](https://travis-ci.org/go-openapi/runtime) [](https://codecov.io/gh/go-openapi/runtime) [](https://slackin.goswagger.io)
|
||||
|
||||
[](https://raw.githubusercontent.com/go-openapi/runtime/master/LICENSE) [](http://godoc.org/github.com/go-openapi/runtime)
|
||||
|
||||
The runtime component for use in codegeneration or as untyped usage.
|
||||
33
vendor/github.com/go-openapi/runtime/authinfo_test.go
generated
vendored
Normal file
33
vendor/github.com/go-openapi/runtime/authinfo_test.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAuthInfoWriter(t *testing.T) {
|
||||
hand := ClientAuthInfoWriterFunc(func(r ClientRequest, _ strfmt.Registry) error {
|
||||
r.SetHeaderParam("authorization", "Bearer the-token-goes-here")
|
||||
return nil
|
||||
})
|
||||
|
||||
tr := new(trw)
|
||||
hand.AuthenticateRequest(tr, nil)
|
||||
assert.Equal(t, "Bearer the-token-goes-here", tr.Headers.Get("Authorization"))
|
||||
}
|
||||
99
vendor/github.com/go-openapi/runtime/bytestream.go
generated
vendored
Normal file
99
vendor/github.com/go-openapi/runtime/bytestream.go
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// ByteStreamConsumer creates a consmer for byte streams,
|
||||
// takes a Writer/BinaryUnmarshaler interface or binary slice by reference,
|
||||
// and reads from the provided reader
|
||||
func ByteStreamConsumer() Consumer {
|
||||
return ConsumerFunc(func(reader io.Reader, data interface{}) error {
|
||||
if reader == nil {
|
||||
return errors.New("ByteStreamConsumer requires a reader") // early exit
|
||||
}
|
||||
|
||||
if wrtr, ok := data.(io.Writer); ok {
|
||||
_, err := io.Copy(wrtr, reader)
|
||||
return err
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
_, err := buf.ReadFrom(reader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b := buf.Bytes()
|
||||
|
||||
if bu, ok := data.(encoding.BinaryUnmarshaler); ok {
|
||||
return bu.UnmarshalBinary(b)
|
||||
}
|
||||
|
||||
if t := reflect.TypeOf(data); data != nil && t.Kind() == reflect.Ptr {
|
||||
v := reflect.Indirect(reflect.ValueOf(data))
|
||||
if t = v.Type(); t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 {
|
||||
v.SetBytes(b)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("%v (%T) is not supported by the ByteStreamConsumer, %s",
|
||||
data, data, "can be resolved by supporting Writer/BinaryUnmarshaler interface")
|
||||
})
|
||||
}
|
||||
|
||||
// ByteStreamProducer creates a producer for byte streams,
|
||||
// takes a Reader/BinaryMarshaler interface or binary slice,
|
||||
// and writes to a writer (essentially a pipe)
|
||||
func ByteStreamProducer() Producer {
|
||||
return ProducerFunc(func(writer io.Writer, data interface{}) error {
|
||||
if writer == nil {
|
||||
return errors.New("ByteStreamProducer requires a writer") // early exit
|
||||
}
|
||||
|
||||
if rdr, ok := data.(io.Reader); ok {
|
||||
_, err := io.Copy(writer, rdr)
|
||||
return err
|
||||
}
|
||||
|
||||
if bm, ok := data.(encoding.BinaryMarshaler); ok {
|
||||
bytes, err := bm.MarshalBinary()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = writer.Write(bytes)
|
||||
return err
|
||||
}
|
||||
|
||||
if data != nil {
|
||||
v := reflect.Indirect(reflect.ValueOf(data))
|
||||
if t := v.Type(); t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 {
|
||||
_, err := writer.Write(v.Bytes())
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("%v (%T) is not supported by the ByteStreamProducer, %s",
|
||||
data, data, "can be resolved by supporting Reader/BinaryMarshaler interface")
|
||||
})
|
||||
}
|
||||
114
vendor/github.com/go-openapi/runtime/bytestream_test.go
generated
vendored
Normal file
114
vendor/github.com/go-openapi/runtime/bytestream_test.go
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestByteStreamConsumer(t *testing.T) {
|
||||
cons := ByteStreamConsumer()
|
||||
|
||||
expected := "the data for the stream to be sent over the wire"
|
||||
|
||||
// can consume as a Writer
|
||||
var b bytes.Buffer
|
||||
if assert.NoError(t, cons.Consume(bytes.NewBufferString(expected), &b)) {
|
||||
assert.Equal(t, expected, b.String())
|
||||
}
|
||||
|
||||
// can consume as an UnmarshalBinary
|
||||
var bu binaryUnmarshalDummy
|
||||
if assert.NoError(t, cons.Consume(bytes.NewBufferString(expected), &bu)) {
|
||||
assert.Equal(t, expected, bu.str)
|
||||
}
|
||||
|
||||
// can consume as a binary slice
|
||||
var bs []byte
|
||||
if assert.NoError(t, cons.Consume(bytes.NewBufferString(expected), &bs)) {
|
||||
assert.Equal(t, expected, string(bs))
|
||||
}
|
||||
type binarySlice []byte
|
||||
var bs2 binarySlice
|
||||
if assert.NoError(t, cons.Consume(bytes.NewBufferString(expected), &bs2)) {
|
||||
assert.Equal(t, expected, string(bs2))
|
||||
}
|
||||
|
||||
// passing in a nilslice wil result in an error
|
||||
var ns *[]byte
|
||||
assert.Error(t, cons.Consume(bytes.NewBufferString(expected), &ns))
|
||||
|
||||
// passing in nil wil result in an error as well
|
||||
assert.Error(t, cons.Consume(bytes.NewBufferString(expected), nil))
|
||||
|
||||
// a reader who results in an error, will make it fail
|
||||
assert.Error(t, cons.Consume(new(nopReader), &bu))
|
||||
assert.Error(t, cons.Consume(new(nopReader), &bs))
|
||||
|
||||
// the readers can also not be nil
|
||||
assert.Error(t, cons.Consume(nil, &bs))
|
||||
}
|
||||
|
||||
type binaryUnmarshalDummy struct {
|
||||
str string
|
||||
}
|
||||
|
||||
func (b *binaryUnmarshalDummy) UnmarshalBinary(bytes []byte) error {
|
||||
if len(bytes) == 0 {
|
||||
return errors.New("no text given")
|
||||
}
|
||||
|
||||
b.str = string(bytes)
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestByteStreamProducer(t *testing.T) {
|
||||
cons := ByteStreamProducer()
|
||||
expected := "the data for the stream to be sent over the wire"
|
||||
|
||||
var rdr bytes.Buffer
|
||||
|
||||
// can produce using a reader
|
||||
if assert.NoError(t, cons.Produce(&rdr, bytes.NewBufferString(expected))) {
|
||||
assert.Equal(t, expected, rdr.String())
|
||||
rdr.Reset()
|
||||
}
|
||||
|
||||
// can produce using a binary marshaller
|
||||
if assert.NoError(t, cons.Produce(&rdr, &binaryMarshalDummy{expected})) {
|
||||
assert.Equal(t, expected, rdr.String())
|
||||
rdr.Reset()
|
||||
}
|
||||
|
||||
// binary slices can also be used to produce
|
||||
if assert.NoError(t, cons.Produce(&rdr, []byte(expected))) {
|
||||
assert.Equal(t, expected, rdr.String())
|
||||
rdr.Reset()
|
||||
}
|
||||
type binarySlice []byte
|
||||
if assert.NoError(t, cons.Produce(&rdr, binarySlice(expected))) {
|
||||
assert.Equal(t, expected, rdr.String())
|
||||
rdr.Reset()
|
||||
}
|
||||
|
||||
// when binaryMarshal data is used, its potential error gets propagated
|
||||
assert.Error(t, cons.Produce(&rdr, new(binaryMarshalDummy)))
|
||||
// nil data should never be accepted either
|
||||
assert.Error(t, cons.Produce(&rdr, nil))
|
||||
// nil readers should also never be acccepted
|
||||
assert.Error(t, cons.Produce(nil, bytes.NewBufferString(expected)))
|
||||
}
|
||||
|
||||
type binaryMarshalDummy struct {
|
||||
str string
|
||||
}
|
||||
|
||||
func (b *binaryMarshalDummy) MarshalBinary() ([]byte, error) {
|
||||
if len(b.str) == 0 {
|
||||
return nil, errors.New("no text set")
|
||||
}
|
||||
|
||||
return []byte(b.str), nil
|
||||
}
|
||||
64
vendor/github.com/go-openapi/runtime/client/auth_info.go
generated
vendored
Normal file
64
vendor/github.com/go-openapi/runtime/client/auth_info.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// PassThroughAuth never manipulates the request
|
||||
var PassThroughAuth runtime.ClientAuthInfoWriter
|
||||
|
||||
func init() {
|
||||
PassThroughAuth = runtime.ClientAuthInfoWriterFunc(func(_ runtime.ClientRequest, _ strfmt.Registry) error { return nil })
|
||||
}
|
||||
|
||||
// BasicAuth provides a basic auth info writer
|
||||
func BasicAuth(username, password string) runtime.ClientAuthInfoWriter {
|
||||
return runtime.ClientAuthInfoWriterFunc(func(r runtime.ClientRequest, _ strfmt.Registry) error {
|
||||
encoded := base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
|
||||
r.SetHeaderParam("Authorization", "Basic "+encoded)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// APIKeyAuth provides an API key auth info writer
|
||||
func APIKeyAuth(name, in, value string) runtime.ClientAuthInfoWriter {
|
||||
if in == "query" {
|
||||
return runtime.ClientAuthInfoWriterFunc(func(r runtime.ClientRequest, _ strfmt.Registry) error {
|
||||
r.SetQueryParam(name, value)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
if in == "header" {
|
||||
return runtime.ClientAuthInfoWriterFunc(func(r runtime.ClientRequest, _ strfmt.Registry) error {
|
||||
r.SetHeaderParam(name, value)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BearerToken provides a header based oauth2 bearer access token auth info writer
|
||||
func BearerToken(token string) runtime.ClientAuthInfoWriter {
|
||||
return runtime.ClientAuthInfoWriterFunc(func(r runtime.ClientRequest, _ strfmt.Registry) error {
|
||||
r.SetHeaderParam("Authorization", "Bearer "+token)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
65
vendor/github.com/go-openapi/runtime/client/auth_info_test.go
generated
vendored
Normal file
65
vendor/github.com/go-openapi/runtime/client/auth_info_test.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBasicAuth(t *testing.T) {
|
||||
r, _ := newRequest("GET", "/", nil)
|
||||
|
||||
writer := BasicAuth("someone", "with a password")
|
||||
writer.AuthenticateRequest(r, nil)
|
||||
|
||||
req := new(http.Request)
|
||||
req.Header = make(http.Header)
|
||||
req.Header.Set("Authorization", r.header.Get("Authorization"))
|
||||
usr, pw, ok := req.BasicAuth()
|
||||
if assert.True(t, ok) {
|
||||
assert.Equal(t, "someone", usr)
|
||||
assert.Equal(t, "with a password", pw)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIKeyAuth_Query(t *testing.T) {
|
||||
r, _ := newRequest("GET", "/", nil)
|
||||
|
||||
writer := APIKeyAuth("api_key", "query", "the-shared-key")
|
||||
writer.AuthenticateRequest(r, nil)
|
||||
|
||||
assert.Equal(t, "the-shared-key", r.query.Get("api_key"))
|
||||
}
|
||||
|
||||
func TestAPIKeyAuth_Header(t *testing.T) {
|
||||
r, _ := newRequest("GET", "/", nil)
|
||||
|
||||
writer := APIKeyAuth("x-api-token", "header", "the-shared-key")
|
||||
writer.AuthenticateRequest(r, nil)
|
||||
|
||||
assert.Equal(t, "the-shared-key", r.header.Get("x-api-token"))
|
||||
}
|
||||
|
||||
func TestBearerTokenAuth(t *testing.T) {
|
||||
r, _ := newRequest("GET", "/", nil)
|
||||
|
||||
writer := BearerToken("the-shared-token")
|
||||
writer.AuthenticateRequest(r, nil)
|
||||
|
||||
assert.Equal(t, "Bearer the-shared-token", r.header.Get("Authorization"))
|
||||
}
|
||||
272
vendor/github.com/go-openapi/runtime/client/request.go
generated
vendored
Normal file
272
vendor/github.com/go-openapi/runtime/client/request.go
generated
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// NewRequest creates a new swagger http client request
|
||||
func newRequest(method, pathPattern string, writer runtime.ClientRequestWriter) (*request, error) {
|
||||
return &request{
|
||||
pathPattern: pathPattern,
|
||||
method: method,
|
||||
writer: writer,
|
||||
header: make(http.Header),
|
||||
query: make(url.Values),
|
||||
timeout: DefaultTimeout,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Request represents a swagger client request.
|
||||
//
|
||||
// This Request struct converts to a HTTP request.
|
||||
// There might be others that convert to other transports.
|
||||
// There is no error checking here, it is assumed to be used after a spec has been validated.
|
||||
// so impossible combinations should not arise (hopefully).
|
||||
//
|
||||
// The main purpose of this struct is to hide the machinery of adding params to a transport request.
|
||||
// The generated code only implements what is necessary to turn a param into a valid value for these methods.
|
||||
type request struct {
|
||||
pathPattern string
|
||||
method string
|
||||
writer runtime.ClientRequestWriter
|
||||
|
||||
pathParams map[string]string
|
||||
header http.Header
|
||||
query url.Values
|
||||
formFields url.Values
|
||||
fileFields map[string]runtime.NamedReadCloser
|
||||
payload interface{}
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
var (
|
||||
// ensure interface compliance
|
||||
_ runtime.ClientRequest = new(request)
|
||||
)
|
||||
|
||||
// BuildHTTP creates a new http request based on the data from the params
|
||||
func (r *request) BuildHTTP(mediaType string, producers map[string]runtime.Producer, registry strfmt.Registry) (*http.Request, error) {
|
||||
// build the data
|
||||
if err := r.writer.WriteToRequest(r, registry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// create http request
|
||||
path := r.pathPattern
|
||||
for k, v := range r.pathParams {
|
||||
path = strings.Replace(path, "{"+k+"}", v, -1)
|
||||
}
|
||||
|
||||
var body io.ReadCloser
|
||||
var pr *io.PipeReader
|
||||
var pw *io.PipeWriter
|
||||
buf := bytes.NewBuffer(nil)
|
||||
body = ioutil.NopCloser(buf)
|
||||
if r.fileFields != nil {
|
||||
pr, pw = io.Pipe()
|
||||
body = pr
|
||||
}
|
||||
req, err := http.NewRequest(r.method, path, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.URL.RawQuery = r.query.Encode()
|
||||
req.Header = r.header
|
||||
|
||||
// check if this is a form type request
|
||||
if len(r.formFields) > 0 || len(r.fileFields) > 0 {
|
||||
// check if this is multipart
|
||||
if len(r.fileFields) > 0 {
|
||||
mp := multipart.NewWriter(pw)
|
||||
req.Header.Set(runtime.HeaderContentType, mp.FormDataContentType())
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
mp.Close()
|
||||
pw.Close()
|
||||
}()
|
||||
|
||||
for fn, v := range r.formFields {
|
||||
if len(v) > 0 {
|
||||
if err := mp.WriteField(fn, v[0]); err != nil {
|
||||
pw.CloseWithError(err)
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for fn, f := range r.fileFields {
|
||||
wrtr, err := mp.CreateFormFile(fn, filepath.Base(f.Name()))
|
||||
if err != nil {
|
||||
pw.CloseWithError(err)
|
||||
log.Println(err)
|
||||
}
|
||||
defer func() {
|
||||
for _, ff := range r.fileFields {
|
||||
ff.Close()
|
||||
}
|
||||
|
||||
}()
|
||||
if _, err := io.Copy(wrtr, f); err != nil {
|
||||
pw.CloseWithError(err)
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
}()
|
||||
return req, nil
|
||||
}
|
||||
|
||||
req.Header.Set(runtime.HeaderContentType, mediaType)
|
||||
// write the form values as the body
|
||||
buf.WriteString(r.formFields.Encode())
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// if there is payload, use the producer to write the payload, and then
|
||||
// set the header to the content-type appropriate for the payload produced
|
||||
if r.payload != nil {
|
||||
// TODO: infer most appropriate content type based on the producer used,
|
||||
// and the `consumers` section of the spec/operation
|
||||
req.Header.Set(runtime.HeaderContentType, mediaType)
|
||||
if rdr, ok := r.payload.(io.ReadCloser); ok {
|
||||
req.Body = rdr
|
||||
return req, nil
|
||||
}
|
||||
|
||||
if rdr, ok := r.payload.(io.Reader); ok {
|
||||
req.Body = ioutil.NopCloser(rdr)
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// set the content length of the request or else a chunked transfer is
|
||||
// declared, and this corrupts outgoing JSON payloads. the content's
|
||||
// length must be set prior to the body being written per the spec at
|
||||
// https://golang.org/pkg/net/http
|
||||
//
|
||||
// If Body is present, Content-Length is <= 0 and TransferEncoding
|
||||
// hasn't been set to "identity", Write adds
|
||||
// "Transfer-Encoding: chunked" to the header. Body is closed
|
||||
// after it is sent.
|
||||
//
|
||||
// to that end a temporary buffer, b, is created to produce the payload
|
||||
// body, and then its size is used to set the request's content length
|
||||
var b bytes.Buffer
|
||||
producer := producers[mediaType]
|
||||
if err := producer.Produce(&b, r.payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.ContentLength = int64(b.Len())
|
||||
if _, err := buf.Write(b.Bytes()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// SetHeaderParam adds a header param to the request
|
||||
// when there is only 1 value provided for the varargs, it will set it.
|
||||
// when there are several values provided for the varargs it will add it (no overriding)
|
||||
func (r *request) SetHeaderParam(name string, values ...string) error {
|
||||
if r.header == nil {
|
||||
r.header = make(http.Header)
|
||||
}
|
||||
r.header[http.CanonicalHeaderKey(name)] = values
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetQueryParam adds a query param to the request
|
||||
// when there is only 1 value provided for the varargs, it will set it.
|
||||
// when there are several values provided for the varargs it will add it (no overriding)
|
||||
func (r *request) SetQueryParam(name string, values ...string) error {
|
||||
if r.query == nil {
|
||||
r.query = make(url.Values)
|
||||
}
|
||||
r.query[name] = values
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetFormParam adds a forn param to the request
|
||||
// when there is only 1 value provided for the varargs, it will set it.
|
||||
// when there are several values provided for the varargs it will add it (no overriding)
|
||||
func (r *request) SetFormParam(name string, values ...string) error {
|
||||
if r.formFields == nil {
|
||||
r.formFields = make(url.Values)
|
||||
}
|
||||
r.formFields[name] = values
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetPathParam adds a path param to the request
|
||||
func (r *request) SetPathParam(name string, value string) error {
|
||||
if r.pathParams == nil {
|
||||
r.pathParams = make(map[string]string)
|
||||
}
|
||||
|
||||
r.pathParams[name] = value
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetFileParam adds a file param to the request
|
||||
func (r *request) SetFileParam(name string, file runtime.NamedReadCloser) error {
|
||||
if actualFile, ok := file.(*os.File); ok {
|
||||
fi, err := os.Stat(actualFile.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if fi.IsDir() {
|
||||
return fmt.Errorf("%q is a directory, only files are supported", file.Name())
|
||||
}
|
||||
}
|
||||
|
||||
if r.fileFields == nil {
|
||||
r.fileFields = make(map[string]runtime.NamedReadCloser)
|
||||
}
|
||||
if r.formFields == nil {
|
||||
r.formFields = make(url.Values)
|
||||
}
|
||||
|
||||
r.fileFields[name] = file
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetBodyParam sets a body parameter on the request.
|
||||
// This does not yet serialze the object, this happens as late as possible.
|
||||
func (r *request) SetBodyParam(payload interface{}) error {
|
||||
r.payload = payload
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetTimeout sets the timeout for a request
|
||||
func (r *request) SetTimeout(timeout time.Duration) error {
|
||||
r.timeout = timeout
|
||||
return nil
|
||||
}
|
||||
244
vendor/github.com/go-openapi/runtime/client/request_test.go
generated
vendored
Normal file
244
vendor/github.com/go-openapi/runtime/client/request_test.go
generated
vendored
Normal file
@@ -0,0 +1,244 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"io/ioutil"
|
||||
"mime"
|
||||
"mime/multipart"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var testProducers = map[string]runtime.Producer{
|
||||
runtime.JSONMime: runtime.JSONProducer(),
|
||||
runtime.XMLMime: runtime.XMLProducer(),
|
||||
runtime.TextMime: runtime.TextProducer(),
|
||||
}
|
||||
|
||||
func TestBuildRequest_SetHeaders(t *testing.T) {
|
||||
r, _ := newRequest("GET", "/flats/{id}/", nil)
|
||||
// single value
|
||||
r.SetHeaderParam("X-Rate-Limit", "500")
|
||||
assert.Equal(t, "500", r.header.Get("X-Rate-Limit"))
|
||||
r.SetHeaderParam("X-Rate-Limit", "400")
|
||||
assert.Equal(t, "400", r.header.Get("X-Rate-Limit"))
|
||||
|
||||
// multi value
|
||||
r.SetHeaderParam("X-Accepts", "json", "xml", "yaml")
|
||||
assert.EqualValues(t, []string{"json", "xml", "yaml"}, r.header["X-Accepts"])
|
||||
}
|
||||
|
||||
func TestBuildRequest_SetPath(t *testing.T) {
|
||||
r, _ := newRequest("GET", "/flats/{id}/?hello=world", nil)
|
||||
|
||||
r.SetPathParam("id", "1345")
|
||||
assert.Equal(t, "1345", r.pathParams["id"])
|
||||
}
|
||||
|
||||
func TestBuildRequest_SetQuery(t *testing.T) {
|
||||
r, _ := newRequest("GET", "/flats/{id}/", nil)
|
||||
|
||||
// single value
|
||||
r.SetQueryParam("hello", "there")
|
||||
assert.Equal(t, "there", r.query.Get("hello"))
|
||||
|
||||
// multi value
|
||||
r.SetQueryParam("goodbye", "cruel", "world")
|
||||
assert.Equal(t, []string{"cruel", "world"}, r.query["goodbye"])
|
||||
}
|
||||
|
||||
func TestBuildRequest_SetForm(t *testing.T) {
|
||||
// non-multipart
|
||||
r, _ := newRequest("POST", "/flats", nil)
|
||||
r.SetFormParam("hello", "world")
|
||||
assert.Equal(t, "world", r.formFields.Get("hello"))
|
||||
r.SetFormParam("goodbye", "cruel", "world")
|
||||
assert.Equal(t, []string{"cruel", "world"}, r.formFields["goodbye"])
|
||||
}
|
||||
|
||||
func TestBuildRequest_SetFile(t *testing.T) {
|
||||
// needs to convert form to multipart
|
||||
r, _ := newRequest("POST", "/flats/{id}/image", nil)
|
||||
// error if it isn't there
|
||||
err := r.SetFileParam("not there", os.NewFile(0, "./i-dont-exist"))
|
||||
assert.Error(t, err)
|
||||
// error if it isn't a file
|
||||
err = r.SetFileParam("directory", os.NewFile(0, "../client"))
|
||||
assert.Error(t, err)
|
||||
// success adds it to the map
|
||||
err = r.SetFileParam("file", mustGetFile("./runtime.go"))
|
||||
if assert.NoError(t, err) {
|
||||
fl, ok := r.fileFields["file"]
|
||||
if assert.True(t, ok) {
|
||||
assert.Equal(t, "runtime.go", filepath.Base(fl.Name()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mustGetFile(path string) *os.File {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func TestBuildRequest_SetBody(t *testing.T) {
|
||||
r, _ := newRequest("GET", "/flats/{id}/?hello=world", nil)
|
||||
bd := []struct{ Name, Hobby string }{{"Tom", "Organ trail"}, {"John", "Bird watching"}}
|
||||
|
||||
r.SetBodyParam(bd)
|
||||
assert.Equal(t, bd, r.payload)
|
||||
}
|
||||
|
||||
func TestBuildRequest_BuildHTTP_Payload(t *testing.T) {
|
||||
bd := []struct{ Name, Hobby string }{{"Tom", "Organ trail"}, {"John", "Bird watching"}}
|
||||
reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, reg strfmt.Registry) error {
|
||||
req.SetBodyParam(bd)
|
||||
req.SetQueryParam("hello", "world")
|
||||
req.SetPathParam("id", "1234")
|
||||
req.SetHeaderParam("X-Rate-Limit", "200")
|
||||
return nil
|
||||
})
|
||||
r, _ := newRequest("GET", "/flats/{id}/", reqWrtr)
|
||||
r.SetHeaderParam(runtime.HeaderContentType, runtime.JSONMime)
|
||||
|
||||
req, err := r.BuildHTTP(runtime.JSONMime, testProducers, nil)
|
||||
if assert.NoError(t, err) && assert.NotNil(t, req) {
|
||||
assert.Equal(t, "200", req.Header.Get("x-rate-limit"))
|
||||
assert.Equal(t, "world", req.URL.Query().Get("hello"))
|
||||
assert.Equal(t, "/flats/1234/", req.URL.Path)
|
||||
expectedBody, _ := json.Marshal(bd)
|
||||
actualBody, _ := ioutil.ReadAll(req.Body)
|
||||
assert.Equal(t, append(expectedBody, '\n'), actualBody)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildRequest_BuildHTTP_XMLPayload(t *testing.T) {
|
||||
bd := []struct {
|
||||
XMLName xml.Name `xml:"person"`
|
||||
Name string `xml:"name"`
|
||||
Hobby string `xml:"hobby"`
|
||||
}{{xml.Name{}, "Tom", "Organ trail"}, {xml.Name{}, "John", "Bird watching"}}
|
||||
reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, reg strfmt.Registry) error {
|
||||
req.SetBodyParam(bd)
|
||||
req.SetQueryParam("hello", "world")
|
||||
req.SetPathParam("id", "1234")
|
||||
req.SetHeaderParam("X-Rate-Limit", "200")
|
||||
return nil
|
||||
})
|
||||
r, _ := newRequest("GET", "/flats/{id}/", reqWrtr)
|
||||
r.SetHeaderParam(runtime.HeaderContentType, runtime.XMLMime)
|
||||
|
||||
req, err := r.BuildHTTP(runtime.XMLMime, testProducers, nil)
|
||||
if assert.NoError(t, err) && assert.NotNil(t, req) {
|
||||
assert.Equal(t, "200", req.Header.Get("x-rate-limit"))
|
||||
assert.Equal(t, "world", req.URL.Query().Get("hello"))
|
||||
assert.Equal(t, "/flats/1234/", req.URL.Path)
|
||||
expectedBody, _ := xml.Marshal(bd)
|
||||
actualBody, _ := ioutil.ReadAll(req.Body)
|
||||
assert.Equal(t, expectedBody, actualBody)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildRequest_BuildHTTP_TextPayload(t *testing.T) {
|
||||
bd := "Tom: Organ trail; John: Bird watching"
|
||||
reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, reg strfmt.Registry) error {
|
||||
req.SetBodyParam(bd)
|
||||
req.SetQueryParam("hello", "world")
|
||||
req.SetPathParam("id", "1234")
|
||||
req.SetHeaderParam("X-Rate-Limit", "200")
|
||||
return nil
|
||||
})
|
||||
r, _ := newRequest("GET", "/flats/{id}/", reqWrtr)
|
||||
r.SetHeaderParam(runtime.HeaderContentType, runtime.TextMime)
|
||||
|
||||
req, err := r.BuildHTTP(runtime.TextMime, testProducers, nil)
|
||||
if assert.NoError(t, err) && assert.NotNil(t, req) {
|
||||
assert.Equal(t, "200", req.Header.Get("x-rate-limit"))
|
||||
assert.Equal(t, "world", req.URL.Query().Get("hello"))
|
||||
assert.Equal(t, "/flats/1234/", req.URL.Path)
|
||||
expectedBody := []byte(bd)
|
||||
actualBody, _ := ioutil.ReadAll(req.Body)
|
||||
assert.Equal(t, expectedBody, actualBody)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildRequest_BuildHTTP_Form(t *testing.T) {
|
||||
reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, reg strfmt.Registry) error {
|
||||
req.SetFormParam("something", "some value")
|
||||
req.SetQueryParam("hello", "world")
|
||||
req.SetPathParam("id", "1234")
|
||||
req.SetHeaderParam("X-Rate-Limit", "200")
|
||||
return nil
|
||||
})
|
||||
r, _ := newRequest("GET", "/flats/{id}/", reqWrtr)
|
||||
r.SetHeaderParam(runtime.HeaderContentType, runtime.JSONMime)
|
||||
|
||||
req, err := r.BuildHTTP(runtime.JSONMime, testProducers, nil)
|
||||
if assert.NoError(t, err) && assert.NotNil(t, req) {
|
||||
assert.Equal(t, "200", req.Header.Get("x-rate-limit"))
|
||||
assert.Equal(t, "world", req.URL.Query().Get("hello"))
|
||||
assert.Equal(t, "/flats/1234/", req.URL.Path)
|
||||
expected := []byte("something=some+value")
|
||||
actual, _ := ioutil.ReadAll(req.Body)
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildRequest_BuildHTTP_Files(t *testing.T) {
|
||||
cont, _ := ioutil.ReadFile("./runtime.go")
|
||||
reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, reg strfmt.Registry) error {
|
||||
req.SetFormParam("something", "some value")
|
||||
req.SetFileParam("file", mustGetFile("./runtime.go"))
|
||||
req.SetQueryParam("hello", "world")
|
||||
req.SetPathParam("id", "1234")
|
||||
req.SetHeaderParam("X-Rate-Limit", "200")
|
||||
return nil
|
||||
})
|
||||
r, _ := newRequest("GET", "/flats/{id}/", reqWrtr)
|
||||
r.SetHeaderParam(runtime.HeaderContentType, runtime.JSONMime)
|
||||
req, err := r.BuildHTTP(runtime.JSONMime, testProducers, nil)
|
||||
if assert.NoError(t, err) && assert.NotNil(t, req) {
|
||||
assert.Equal(t, "200", req.Header.Get("x-rate-limit"))
|
||||
assert.Equal(t, "world", req.URL.Query().Get("hello"))
|
||||
assert.Equal(t, "/flats/1234/", req.URL.Path)
|
||||
mediaType, params, err := mime.ParseMediaType(req.Header.Get(runtime.HeaderContentType))
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, runtime.MultipartFormMime, mediaType)
|
||||
boundary := params["boundary"]
|
||||
mr := multipart.NewReader(req.Body, boundary)
|
||||
defer req.Body.Close()
|
||||
frm, err := mr.ReadForm(1 << 20)
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, "some value", frm.Value["something"][0])
|
||||
mpff := frm.File["file"][0]
|
||||
mpf, _ := mpff.Open()
|
||||
defer mpf.Close()
|
||||
assert.Equal(t, "runtime.go", mpff.Filename)
|
||||
actual, _ := ioutil.ReadAll(mpf)
|
||||
assert.Equal(t, cont, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
vendor/github.com/go-openapi/runtime/client/response.go
generated
vendored
Normal file
44
vendor/github.com/go-openapi/runtime/client/response.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
)
|
||||
|
||||
var _ runtime.ClientResponse = response{}
|
||||
|
||||
type response struct {
|
||||
resp *http.Response
|
||||
}
|
||||
|
||||
func (r response) Code() int {
|
||||
return r.resp.StatusCode
|
||||
}
|
||||
|
||||
func (r response) Message() string {
|
||||
return r.resp.Status
|
||||
}
|
||||
|
||||
func (r response) GetHeader(name string) string {
|
||||
return r.resp.Header.Get(name)
|
||||
}
|
||||
|
||||
func (r response) Body() io.ReadCloser {
|
||||
return r.resp.Body
|
||||
}
|
||||
40
vendor/github.com/go-openapi/runtime/client/response_test.go
generated
vendored
Normal file
40
vendor/github.com/go-openapi/runtime/client/response_test.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestResponse(t *testing.T) {
|
||||
under := new(http.Response)
|
||||
under.Status = "the status message"
|
||||
under.StatusCode = 392
|
||||
under.Header = make(http.Header)
|
||||
under.Header.Set("Blah", "blah blah")
|
||||
under.Body = ioutil.NopCloser(bytes.NewBufferString("some content"))
|
||||
|
||||
var resp runtime.ClientResponse = response{under}
|
||||
assert.EqualValues(t, under.StatusCode, resp.Code())
|
||||
assert.Equal(t, under.Status, resp.Message())
|
||||
assert.Equal(t, "blah blah", resp.GetHeader("blah"))
|
||||
assert.Equal(t, under.Body, resp.Body())
|
||||
}
|
||||
323
vendor/github.com/go-openapi/runtime/client/runtime.go
generated
vendored
Normal file
323
vendor/github.com/go-openapi/runtime/client/runtime.go
generated
vendored
Normal file
@@ -0,0 +1,323 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/net/context/ctxhttp"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// TLSClientOptions to configure client authentication with mutual TLS
|
||||
type TLSClientOptions struct {
|
||||
Certificate string
|
||||
Key string
|
||||
CA string
|
||||
ServerName string
|
||||
InsecureSkipVerify bool
|
||||
_ struct{}
|
||||
}
|
||||
|
||||
// TLSClientAuth creates a tls.Config for mutual auth
|
||||
func TLSClientAuth(opts TLSClientOptions) (*tls.Config, error) {
|
||||
// load client cert
|
||||
cert, err := tls.LoadX509KeyPair(opts.Certificate, opts.Key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tls client cert: %v", err)
|
||||
}
|
||||
|
||||
// create client tls config
|
||||
cfg := &tls.Config{}
|
||||
cfg.Certificates = []tls.Certificate{cert}
|
||||
cfg.InsecureSkipVerify = opts.InsecureSkipVerify
|
||||
|
||||
// When no CA certificate is provided, default to the system cert pool
|
||||
// that way when a request is made to a server known by the system trust store,
|
||||
// the name is still verified
|
||||
if opts.CA != "" {
|
||||
// load ca cert
|
||||
caCert, err := ioutil.ReadFile(opts.CA)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tls client ca: %v", err)
|
||||
}
|
||||
caCertPool := x509.NewCertPool()
|
||||
caCertPool.AppendCertsFromPEM(caCert)
|
||||
cfg.RootCAs = caCertPool
|
||||
}
|
||||
|
||||
// apply servername overrride
|
||||
if opts.ServerName != "" {
|
||||
cfg.InsecureSkipVerify = false
|
||||
cfg.ServerName = opts.ServerName
|
||||
}
|
||||
|
||||
cfg.BuildNameToCertificate()
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// TLSTransport creates a http client transport suitable for mutual tls auth
|
||||
func TLSTransport(opts TLSClientOptions) (http.RoundTripper, error) {
|
||||
cfg, err := TLSClientAuth(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &http.Transport{TLSClientConfig: cfg}, nil
|
||||
}
|
||||
|
||||
// TLSClient creates a http.Client for mutual auth
|
||||
func TLSClient(opts TLSClientOptions) (*http.Client, error) {
|
||||
transport, err := TLSTransport(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &http.Client{Transport: transport}, nil
|
||||
}
|
||||
|
||||
// DefaultTimeout the default request timeout
|
||||
var DefaultTimeout = 30 * time.Second
|
||||
|
||||
// Runtime represents an API client that uses the transport
|
||||
// to make http requests based on a swagger specification.
|
||||
type Runtime struct {
|
||||
DefaultMediaType string
|
||||
DefaultAuthentication runtime.ClientAuthInfoWriter
|
||||
Consumers map[string]runtime.Consumer
|
||||
Producers map[string]runtime.Producer
|
||||
|
||||
Transport http.RoundTripper
|
||||
Jar http.CookieJar
|
||||
//Spec *spec.Document
|
||||
Host string
|
||||
BasePath string
|
||||
Formats strfmt.Registry
|
||||
Debug bool
|
||||
Context context.Context
|
||||
|
||||
clientOnce *sync.Once
|
||||
client *http.Client
|
||||
schemes []string
|
||||
do func(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
// New creates a new default runtime for a swagger api runtime.Client
|
||||
func New(host, basePath string, schemes []string) *Runtime {
|
||||
var rt Runtime
|
||||
rt.DefaultMediaType = runtime.JSONMime
|
||||
|
||||
// TODO: actually infer this stuff from the spec
|
||||
rt.Consumers = map[string]runtime.Consumer{
|
||||
runtime.JSONMime: runtime.JSONConsumer(),
|
||||
runtime.XMLMime: runtime.XMLConsumer(),
|
||||
runtime.TextMime: runtime.TextConsumer(),
|
||||
runtime.DefaultMime: runtime.ByteStreamConsumer(),
|
||||
}
|
||||
rt.Producers = map[string]runtime.Producer{
|
||||
runtime.JSONMime: runtime.JSONProducer(),
|
||||
runtime.XMLMime: runtime.XMLProducer(),
|
||||
runtime.TextMime: runtime.TextProducer(),
|
||||
runtime.DefaultMime: runtime.ByteStreamProducer(),
|
||||
}
|
||||
rt.Transport = http.DefaultTransport
|
||||
rt.Jar = nil
|
||||
rt.Host = host
|
||||
rt.BasePath = basePath
|
||||
rt.Context = context.Background()
|
||||
rt.clientOnce = new(sync.Once)
|
||||
if !strings.HasPrefix(rt.BasePath, "/") {
|
||||
rt.BasePath = "/" + rt.BasePath
|
||||
}
|
||||
rt.Debug = len(os.Getenv("DEBUG")) > 0
|
||||
if len(schemes) > 0 {
|
||||
rt.schemes = schemes
|
||||
}
|
||||
rt.do = ctxhttp.Do
|
||||
return &rt
|
||||
}
|
||||
|
||||
// NewWithClient allows you to create a new transport with a configured http.Client
|
||||
func NewWithClient(host, basePath string, schemes []string, client *http.Client) *Runtime {
|
||||
rt := New(host, basePath, schemes)
|
||||
if client != nil {
|
||||
rt.clientOnce.Do(func() {
|
||||
rt.client = client
|
||||
})
|
||||
}
|
||||
return rt
|
||||
}
|
||||
|
||||
func (r *Runtime) pickScheme(schemes []string) string {
|
||||
if v := r.selectScheme(r.schemes); v != "" {
|
||||
return v
|
||||
}
|
||||
if v := r.selectScheme(schemes); v != "" {
|
||||
return v
|
||||
}
|
||||
return "http"
|
||||
}
|
||||
|
||||
func (r *Runtime) selectScheme(schemes []string) string {
|
||||
schLen := len(schemes)
|
||||
if schLen == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
scheme := schemes[0]
|
||||
// prefer https, but skip when not possible
|
||||
if scheme != "https" && schLen > 1 {
|
||||
for _, sch := range schemes {
|
||||
if sch == "https" {
|
||||
scheme = sch
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return scheme
|
||||
}
|
||||
|
||||
// Submit a request and when there is a body on success it will turn that into the result
|
||||
// all other things are turned into an api error for swagger which retains the status code
|
||||
func (r *Runtime) Submit(operation *runtime.ClientOperation) (interface{}, error) {
|
||||
params, readResponse, auth := operation.Params, operation.Reader, operation.AuthInfo
|
||||
|
||||
request, err := newRequest(operation.Method, operation.PathPattern, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var accept []string
|
||||
for _, mimeType := range operation.ProducesMediaTypes {
|
||||
accept = append(accept, mimeType)
|
||||
}
|
||||
request.SetHeaderParam(runtime.HeaderAccept, accept...)
|
||||
|
||||
if auth == nil && r.DefaultAuthentication != nil {
|
||||
auth = r.DefaultAuthentication
|
||||
}
|
||||
if auth != nil {
|
||||
if err := auth.AuthenticateRequest(request, r.Formats); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: pick appropriate media type
|
||||
cmt := r.DefaultMediaType
|
||||
if len(operation.ConsumesMediaTypes) > 0 {
|
||||
cmt = operation.ConsumesMediaTypes[0]
|
||||
}
|
||||
|
||||
req, err := request.BuildHTTP(cmt, r.Producers, r.Formats)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.URL.Scheme = r.pickScheme(operation.Schemes)
|
||||
req.URL.Host = r.Host
|
||||
var reinstateSlash bool
|
||||
if req.URL.Path != "" && req.URL.Path != "/" && req.URL.Path[len(req.URL.Path)-1] == '/' {
|
||||
reinstateSlash = true
|
||||
}
|
||||
req.URL.Path = path.Join(r.BasePath, req.URL.Path)
|
||||
if reinstateSlash {
|
||||
req.URL.Path = req.URL.Path + "/"
|
||||
}
|
||||
|
||||
r.clientOnce.Do(func() {
|
||||
r.client = &http.Client{
|
||||
Transport: r.Transport,
|
||||
Jar: r.Jar,
|
||||
}
|
||||
})
|
||||
|
||||
if r.Debug {
|
||||
b, err2 := httputil.DumpRequestOut(req, true)
|
||||
if err2 != nil {
|
||||
return nil, err2
|
||||
}
|
||||
fmt.Fprintln(os.Stderr, string(b))
|
||||
}
|
||||
|
||||
var hasTimeout bool
|
||||
pctx := operation.Context
|
||||
if pctx == nil {
|
||||
pctx = r.Context
|
||||
} else {
|
||||
hasTimeout = true
|
||||
}
|
||||
if pctx == nil {
|
||||
pctx = context.Background()
|
||||
}
|
||||
var ctx context.Context
|
||||
var cancel context.CancelFunc
|
||||
if hasTimeout {
|
||||
ctx, cancel = context.WithCancel(pctx)
|
||||
} else {
|
||||
ctx, cancel = context.WithTimeout(pctx, request.timeout)
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
client := operation.Client
|
||||
if client == nil {
|
||||
client = r.client
|
||||
}
|
||||
if r.do == nil {
|
||||
r.do = ctxhttp.Do
|
||||
}
|
||||
res, err := r.do(ctx, client, req) // make requests, by default follows 10 redirects before failing
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if r.Debug {
|
||||
b, err2 := httputil.DumpResponse(res, true)
|
||||
if err2 != nil {
|
||||
return nil, err2
|
||||
}
|
||||
fmt.Fprintln(os.Stderr, string(b))
|
||||
}
|
||||
|
||||
ct := res.Header.Get(runtime.HeaderContentType)
|
||||
if ct == "" { // this should really really never occur
|
||||
ct = r.DefaultMediaType
|
||||
}
|
||||
|
||||
mt, _, err := mime.ParseMediaType(ct)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse content type: %s", err)
|
||||
}
|
||||
|
||||
cons, ok := r.Consumers[mt]
|
||||
if !ok {
|
||||
// scream about not knowing what to do
|
||||
return nil, fmt.Errorf("no consumer: %q", ct)
|
||||
}
|
||||
return readResponse.ReadResponse(response{res}, cons)
|
||||
}
|
||||
722
vendor/github.com/go-openapi/runtime/client/runtime_test.go
generated
vendored
Normal file
722
vendor/github.com/go-openapi/runtime/client/runtime_test.go
generated
vendored
Normal file
@@ -0,0 +1,722 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// task This describes a task. Tasks require a content property to be set.
|
||||
type task struct {
|
||||
|
||||
// Completed
|
||||
Completed bool `json:"completed" xml:"completed"`
|
||||
|
||||
// Content Task content can contain [GFM](https://help.github.com/articles/github-flavored-markdown/).
|
||||
Content string `json:"content" xml:"content"`
|
||||
|
||||
// ID This id property is autogenerated when a task is created.
|
||||
ID int64 `json:"id" xml:"id"`
|
||||
}
|
||||
|
||||
func TestRuntime_TLSAuthConfig(t *testing.T) {
|
||||
var opts TLSClientOptions
|
||||
opts.CA = "../fixtures/certs/myCA.crt"
|
||||
opts.Key = "../fixtures/certs/myclient.key"
|
||||
opts.Certificate = "../fixtures/certs/myclient.crt"
|
||||
opts.ServerName = "somewhere"
|
||||
|
||||
cfg, err := TLSClientAuth(opts)
|
||||
if assert.NoError(t, err) {
|
||||
if assert.NotNil(t, cfg) {
|
||||
assert.Len(t, cfg.Certificates, 1)
|
||||
assert.NotNil(t, cfg.RootCAs)
|
||||
assert.Equal(t, "somewhere", cfg.ServerName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRuntime_Concurrent(t *testing.T) {
|
||||
// test that it can make a simple request
|
||||
// and get the response for it.
|
||||
// defaults all the way down
|
||||
result := []task{
|
||||
{false, "task 1 content", 1},
|
||||
{false, "task 2 content", 2},
|
||||
}
|
||||
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.Header().Add(runtime.HeaderContentType, runtime.JSONMime)
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
jsongen := json.NewEncoder(rw)
|
||||
jsongen.Encode(result)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
rwrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
hu, _ := url.Parse(server.URL)
|
||||
rt := New(hu.Host, "/", []string{"http"})
|
||||
resCC := make(chan interface{})
|
||||
errCC := make(chan error)
|
||||
var res interface{}
|
||||
var err error
|
||||
|
||||
for j := 0; j < 6; j++ {
|
||||
go func() {
|
||||
resC := make(chan interface{})
|
||||
errC := make(chan error)
|
||||
|
||||
go func() {
|
||||
var resp interface{}
|
||||
var errp error
|
||||
for i := 0; i < 3; i++ {
|
||||
resp, errp = rt.Submit(&runtime.ClientOperation{
|
||||
ID: "getTasks",
|
||||
Method: "GET",
|
||||
PathPattern: "/",
|
||||
Params: rwrtr,
|
||||
Reader: runtime.ClientResponseReaderFunc(func(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
||||
if response.Code() == 200 {
|
||||
var result []task
|
||||
if err := consumer.Consume(response.Body(), &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
return nil, errors.New("Generic error")
|
||||
}),
|
||||
})
|
||||
<-time.After(100 * time.Millisecond)
|
||||
}
|
||||
resC <- resp
|
||||
errC <- errp
|
||||
}()
|
||||
resCC <- <-resC
|
||||
errCC <- <-errC
|
||||
}()
|
||||
}
|
||||
|
||||
c := 6
|
||||
for c > 0 {
|
||||
res = <-resCC
|
||||
err = <-errCC
|
||||
c--
|
||||
}
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
assert.IsType(t, []task{}, res)
|
||||
actual := res.([]task)
|
||||
assert.EqualValues(t, result, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRuntime_Canary(t *testing.T) {
|
||||
// test that it can make a simple request
|
||||
// and get the response for it.
|
||||
// defaults all the way down
|
||||
result := []task{
|
||||
{false, "task 1 content", 1},
|
||||
{false, "task 2 content", 2},
|
||||
}
|
||||
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.Header().Add(runtime.HeaderContentType, runtime.JSONMime)
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
jsongen := json.NewEncoder(rw)
|
||||
jsongen.Encode(result)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
rwrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
hu, _ := url.Parse(server.URL)
|
||||
rt := New(hu.Host, "/", []string{"http"})
|
||||
res, err := rt.Submit(&runtime.ClientOperation{
|
||||
ID: "getTasks",
|
||||
Method: "GET",
|
||||
PathPattern: "/",
|
||||
Params: rwrtr,
|
||||
Reader: runtime.ClientResponseReaderFunc(func(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
||||
if response.Code() == 200 {
|
||||
var result []task
|
||||
if err := consumer.Consume(response.Body(), &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
return nil, errors.New("Generic error")
|
||||
}),
|
||||
})
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
assert.IsType(t, []task{}, res)
|
||||
actual := res.([]task)
|
||||
assert.EqualValues(t, result, actual)
|
||||
}
|
||||
}
|
||||
|
||||
type tasks struct {
|
||||
Tasks []task `xml:"task"`
|
||||
}
|
||||
|
||||
func TestRuntime_XMLCanary(t *testing.T) {
|
||||
// test that it can make a simple XML request
|
||||
// and get the response for it.
|
||||
result := tasks{
|
||||
Tasks: []task{
|
||||
{false, "task 1 content", 1},
|
||||
{false, "task 2 content", 2},
|
||||
},
|
||||
}
|
||||
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.Header().Add(runtime.HeaderContentType, runtime.XMLMime)
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
xmlgen := xml.NewEncoder(rw)
|
||||
xmlgen.Encode(result)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
rwrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
hu, _ := url.Parse(server.URL)
|
||||
rt := New(hu.Host, "/", []string{"http"})
|
||||
res, err := rt.Submit(&runtime.ClientOperation{
|
||||
ID: "getTasks",
|
||||
Method: "GET",
|
||||
PathPattern: "/",
|
||||
Params: rwrtr,
|
||||
Reader: runtime.ClientResponseReaderFunc(func(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
||||
if response.Code() == 200 {
|
||||
var result tasks
|
||||
if err := consumer.Consume(response.Body(), &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
return nil, errors.New("Generic error")
|
||||
}),
|
||||
})
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
assert.IsType(t, tasks{}, res)
|
||||
actual := res.(tasks)
|
||||
assert.EqualValues(t, result, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRuntime_TextCanary(t *testing.T) {
|
||||
// test that it can make a simple text request
|
||||
// and get the response for it.
|
||||
result := "1: task 1 content; 2: task 2 content"
|
||||
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.Header().Add(runtime.HeaderContentType, runtime.TextMime)
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
rw.Write([]byte(result))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
rwrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
hu, _ := url.Parse(server.URL)
|
||||
rt := New(hu.Host, "/", []string{"http"})
|
||||
res, err := rt.Submit(&runtime.ClientOperation{
|
||||
ID: "getTasks",
|
||||
Method: "GET",
|
||||
PathPattern: "/",
|
||||
Params: rwrtr,
|
||||
Reader: runtime.ClientResponseReaderFunc(func(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
||||
if response.Code() == 200 {
|
||||
var result string
|
||||
if err := consumer.Consume(response.Body(), &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
return nil, errors.New("Generic error")
|
||||
}),
|
||||
})
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
assert.IsType(t, "", res)
|
||||
actual := res.(string)
|
||||
assert.EqualValues(t, result, actual)
|
||||
}
|
||||
}
|
||||
|
||||
type roundTripperFunc func(*http.Request) (*http.Response, error)
|
||||
|
||||
func (fn roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
return fn(req)
|
||||
}
|
||||
|
||||
func TestRuntime_CustomTransport(t *testing.T) {
|
||||
rwrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
|
||||
return nil
|
||||
})
|
||||
result := []task{
|
||||
{false, "task 1 content", 1},
|
||||
{false, "task 2 content", 2},
|
||||
}
|
||||
|
||||
rt := New("localhost:3245", "/", []string{"ws", "wss", "https"})
|
||||
rt.Transport = roundTripperFunc(func(req *http.Request) (*http.Response, error) {
|
||||
if req.URL.Scheme != "https" {
|
||||
return nil, errors.New("this was not a https request")
|
||||
}
|
||||
var resp http.Response
|
||||
resp.StatusCode = 200
|
||||
resp.Header = make(http.Header)
|
||||
resp.Header.Set("content-type", "application/json")
|
||||
buf := bytes.NewBuffer(nil)
|
||||
enc := json.NewEncoder(buf)
|
||||
enc.Encode(result)
|
||||
resp.Body = ioutil.NopCloser(buf)
|
||||
return &resp, nil
|
||||
})
|
||||
|
||||
res, err := rt.Submit(&runtime.ClientOperation{
|
||||
ID: "getTasks",
|
||||
Method: "GET",
|
||||
PathPattern: "/",
|
||||
Schemes: []string{"ws", "wss", "https"},
|
||||
Params: rwrtr,
|
||||
Reader: runtime.ClientResponseReaderFunc(func(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
||||
if response.Code() == 200 {
|
||||
var result []task
|
||||
if err := consumer.Consume(response.Body(), &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
return nil, errors.New("Generic error")
|
||||
}),
|
||||
})
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
assert.IsType(t, []task{}, res)
|
||||
actual := res.([]task)
|
||||
assert.EqualValues(t, result, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRuntime_CustomCookieJar(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
authenticated := false
|
||||
for _, cookie := range req.Cookies() {
|
||||
if cookie.Name == "sessionid" && cookie.Value == "abc" {
|
||||
authenticated = true
|
||||
}
|
||||
}
|
||||
if !authenticated {
|
||||
username, password, ok := req.BasicAuth()
|
||||
if ok && username == "username" && password == "password" {
|
||||
authenticated = true
|
||||
http.SetCookie(rw, &http.Cookie{Name: "sessionid", Value: "abc"})
|
||||
}
|
||||
}
|
||||
if authenticated {
|
||||
rw.Header().Add(runtime.HeaderContentType, runtime.JSONMime)
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
jsongen := json.NewEncoder(rw)
|
||||
jsongen.Encode([]task{})
|
||||
} else {
|
||||
rw.WriteHeader(http.StatusUnauthorized)
|
||||
}
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
rwrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
hu, _ := url.Parse(server.URL)
|
||||
rt := New(hu.Host, "/", []string{"http"})
|
||||
rt.Jar, _ = cookiejar.New(nil)
|
||||
|
||||
submit := func(authInfo runtime.ClientAuthInfoWriter) {
|
||||
_, err := rt.Submit(&runtime.ClientOperation{
|
||||
ID: "getTasks",
|
||||
Method: "GET",
|
||||
PathPattern: "/",
|
||||
Params: rwrtr,
|
||||
AuthInfo: authInfo,
|
||||
Reader: runtime.ClientResponseReaderFunc(func(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
||||
if response.Code() == 200 {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, errors.New("Generic error")
|
||||
}),
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
submit(BasicAuth("username", "password"))
|
||||
submit(nil)
|
||||
}
|
||||
|
||||
func TestRuntime_AuthCanary(t *testing.T) {
|
||||
// test that it can make a simple request
|
||||
// and get the response for it.
|
||||
// defaults all the way down
|
||||
result := []task{
|
||||
{false, "task 1 content", 1},
|
||||
{false, "task 2 content", 2},
|
||||
}
|
||||
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
if req.Header.Get("Authorization") != "Bearer the-super-secret-token" {
|
||||
rw.WriteHeader(400)
|
||||
return
|
||||
}
|
||||
rw.Header().Add(runtime.HeaderContentType, runtime.JSONMime)
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
jsongen := json.NewEncoder(rw)
|
||||
jsongen.Encode(result)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
rwrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
hu, _ := url.Parse(server.URL)
|
||||
|
||||
rt := New(hu.Host, "/", []string{"http"})
|
||||
res, err := rt.Submit(&runtime.ClientOperation{
|
||||
ID: "getTasks",
|
||||
Params: rwrtr,
|
||||
Reader: runtime.ClientResponseReaderFunc(func(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
||||
if response.Code() == 200 {
|
||||
var result []task
|
||||
if err := consumer.Consume(response.Body(), &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
return nil, errors.New("Generic error")
|
||||
}),
|
||||
AuthInfo: BearerToken("the-super-secret-token"),
|
||||
})
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
assert.IsType(t, []task{}, res)
|
||||
actual := res.([]task)
|
||||
assert.EqualValues(t, result, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRuntime_PickConsumer(t *testing.T) {
|
||||
result := []task{
|
||||
{false, "task 1 content", 1},
|
||||
{false, "task 2 content", 2},
|
||||
}
|
||||
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
if req.Header.Get("Content-Type") != "application/octet-stream" {
|
||||
rw.Header().Add(runtime.HeaderContentType, runtime.JSONMime+";charset=utf-8")
|
||||
rw.WriteHeader(400)
|
||||
return
|
||||
}
|
||||
rw.Header().Add(runtime.HeaderContentType, runtime.JSONMime+";charset=utf-8")
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
jsongen := json.NewEncoder(rw)
|
||||
jsongen.Encode(result)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
rwrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
|
||||
req.SetBodyParam(bytes.NewBufferString("hello"))
|
||||
return nil
|
||||
})
|
||||
|
||||
hu, _ := url.Parse(server.URL)
|
||||
rt := New(hu.Host, "/", []string{"http"})
|
||||
res, err := rt.Submit(&runtime.ClientOperation{
|
||||
ID: "getTasks",
|
||||
Method: "POST",
|
||||
PathPattern: "/",
|
||||
Schemes: []string{"http"},
|
||||
ConsumesMediaTypes: []string{"application/octet-stream"},
|
||||
Params: rwrtr,
|
||||
Reader: runtime.ClientResponseReaderFunc(func(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
||||
if response.Code() == 200 {
|
||||
var result []task
|
||||
if err := consumer.Consume(response.Body(), &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
return nil, errors.New("Generic error")
|
||||
}),
|
||||
AuthInfo: BearerToken("the-super-secret-token"),
|
||||
})
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
assert.IsType(t, []task{}, res)
|
||||
actual := res.([]task)
|
||||
assert.EqualValues(t, result, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRuntime_ContentTypeCanary(t *testing.T) {
|
||||
// test that it can make a simple request
|
||||
// and get the response for it.
|
||||
// defaults all the way down
|
||||
result := []task{
|
||||
{false, "task 1 content", 1},
|
||||
{false, "task 2 content", 2},
|
||||
}
|
||||
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
if req.Header.Get("Authorization") != "Bearer the-super-secret-token" {
|
||||
rw.WriteHeader(400)
|
||||
return
|
||||
}
|
||||
rw.Header().Add(runtime.HeaderContentType, runtime.JSONMime+";charset=utf-8")
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
jsongen := json.NewEncoder(rw)
|
||||
jsongen.Encode(result)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
rwrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
hu, _ := url.Parse(server.URL)
|
||||
rt := New(hu.Host, "/", []string{"http"})
|
||||
rt.do = nil
|
||||
res, err := rt.Submit(&runtime.ClientOperation{
|
||||
ID: "getTasks",
|
||||
Method: "GET",
|
||||
PathPattern: "/",
|
||||
Schemes: []string{"http"},
|
||||
Params: rwrtr,
|
||||
Reader: runtime.ClientResponseReaderFunc(func(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
||||
if response.Code() == 200 {
|
||||
var result []task
|
||||
if err := consumer.Consume(response.Body(), &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
return nil, errors.New("Generic error")
|
||||
}),
|
||||
AuthInfo: BearerToken("the-super-secret-token"),
|
||||
})
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
assert.IsType(t, []task{}, res)
|
||||
actual := res.([]task)
|
||||
assert.EqualValues(t, result, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRuntime_ChunkedResponse(t *testing.T) {
|
||||
// test that it can make a simple request
|
||||
// and get the response for it.
|
||||
// defaults all the way down
|
||||
result := []task{
|
||||
{false, "task 1 content", 1},
|
||||
{false, "task 2 content", 2},
|
||||
}
|
||||
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
if req.Header.Get("Authorization") != "Bearer the-super-secret-token" {
|
||||
rw.WriteHeader(400)
|
||||
return
|
||||
}
|
||||
rw.Header().Add(runtime.HeaderTransferEncoding, "chunked")
|
||||
rw.Header().Add(runtime.HeaderContentType, runtime.JSONMime+";charset=utf-8")
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
jsongen := json.NewEncoder(rw)
|
||||
jsongen.Encode(result)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
rwrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
//specDoc, err := spec.Load("../../fixtures/codegen/todolist.simple.yml")
|
||||
hu, _ := url.Parse(server.URL)
|
||||
|
||||
rt := New(hu.Host, "/", []string{"http"})
|
||||
res, err := rt.Submit(&runtime.ClientOperation{
|
||||
ID: "getTasks",
|
||||
Method: "GET",
|
||||
PathPattern: "/",
|
||||
Schemes: []string{"http"},
|
||||
Params: rwrtr,
|
||||
Reader: runtime.ClientResponseReaderFunc(func(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
||||
if response.Code() == 200 {
|
||||
var result []task
|
||||
if err := consumer.Consume(response.Body(), &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
return nil, errors.New("Generic error")
|
||||
}),
|
||||
AuthInfo: BearerToken("the-super-secret-token"),
|
||||
})
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
assert.IsType(t, []task{}, res)
|
||||
actual := res.([]task)
|
||||
assert.EqualValues(t, result, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRuntime_DebugValue(t *testing.T) {
|
||||
original := os.Getenv("DEBUG")
|
||||
|
||||
// Emtpy DEBUG means Debug is False
|
||||
os.Setenv("DEBUG", "")
|
||||
runtime := New("", "/", []string{"https"})
|
||||
assert.False(t, runtime.Debug)
|
||||
|
||||
// Non-Empty Debug means Debug is True
|
||||
|
||||
os.Setenv("DEBUG", "1")
|
||||
runtime = New("", "/", []string{"https"})
|
||||
assert.True(t, runtime.Debug)
|
||||
|
||||
os.Setenv("DEBUG", "true")
|
||||
runtime = New("", "/", []string{"https"})
|
||||
assert.True(t, runtime.Debug)
|
||||
|
||||
os.Setenv("DEBUG", "foo")
|
||||
runtime = New("", "/", []string{"https"})
|
||||
assert.True(t, runtime.Debug)
|
||||
|
||||
// Make sure DEBUG is initial value once again
|
||||
os.Setenv("DEBUG", original)
|
||||
}
|
||||
|
||||
func TestRuntime_OverrideScheme(t *testing.T) {
|
||||
runtime := New("", "/", []string{"https"})
|
||||
sch := runtime.pickScheme([]string{"http"})
|
||||
assert.Equal(t, "https", sch)
|
||||
}
|
||||
|
||||
func TestRuntime_OverrideClient(t *testing.T) {
|
||||
client := &http.Client{}
|
||||
runtime := NewWithClient("", "/", []string{"https"}, client)
|
||||
var i int
|
||||
runtime.clientOnce.Do(func() { i++ })
|
||||
assert.Equal(t, client, runtime.client)
|
||||
assert.Equal(t, 0, i)
|
||||
}
|
||||
|
||||
func TestRuntime_OverrideClientOperation(t *testing.T) {
|
||||
client := &http.Client{}
|
||||
rt := NewWithClient("", "/", []string{"https"}, client)
|
||||
var i int
|
||||
rt.clientOnce.Do(func() { i++ })
|
||||
assert.Equal(t, client, rt.client)
|
||||
assert.Equal(t, 0, i)
|
||||
|
||||
var seen *http.Client
|
||||
rt.do = func(_ context.Context, cl *http.Client, _ *http.Request) (*http.Response, error) {
|
||||
seen = cl
|
||||
res := new(http.Response)
|
||||
res.StatusCode = 200
|
||||
res.Body = ioutil.NopCloser(bytes.NewBufferString("OK"))
|
||||
return res, nil
|
||||
}
|
||||
|
||||
client2 := new(http.Client)
|
||||
client2.Timeout = 3 * time.Second
|
||||
if assert.NotEqual(t, client, client2) {
|
||||
_, err := rt.Submit(&runtime.ClientOperation{
|
||||
Client: client2,
|
||||
Params: runtime.ClientRequestWriterFunc(func(r runtime.ClientRequest, _ strfmt.Registry) error {
|
||||
return nil
|
||||
}),
|
||||
Reader: runtime.ClientResponseReaderFunc(func(_ runtime.ClientResponse, _ runtime.Consumer) (interface{}, error) {
|
||||
return nil, nil
|
||||
}),
|
||||
})
|
||||
if assert.NoError(t, err) {
|
||||
|
||||
assert.Equal(t, client2, seen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRuntime_PreserveTrailingSlash(t *testing.T) {
|
||||
var redirected bool
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.Header().Add(runtime.HeaderContentType, runtime.JSONMime+";charset=utf-8")
|
||||
|
||||
if req.URL.Path == "/api/tasks" {
|
||||
redirected = true
|
||||
return
|
||||
}
|
||||
if req.URL.Path == "/api/tasks/" {
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
}
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
hu, _ := url.Parse(server.URL)
|
||||
|
||||
rt := New(hu.Host, "/", []string{"http"})
|
||||
|
||||
rwrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
_, err := rt.Submit(&runtime.ClientOperation{
|
||||
ID: "getTasks",
|
||||
Method: "GET",
|
||||
PathPattern: "/api/tasks/",
|
||||
Params: rwrtr,
|
||||
Reader: runtime.ClientResponseReaderFunc(func(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
||||
if redirected {
|
||||
return nil, errors.New("expected Submit to preserve trailing slashes - this caused a redirect")
|
||||
}
|
||||
if response.Code() == http.StatusOK {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, errors.New("Generic error")
|
||||
}),
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
30
vendor/github.com/go-openapi/runtime/client_auth_info.go
generated
vendored
Normal file
30
vendor/github.com/go-openapi/runtime/client_auth_info.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package runtime
|
||||
|
||||
import "github.com/go-openapi/strfmt"
|
||||
|
||||
// A ClientAuthInfoWriterFunc converts a function to a request writer interface
|
||||
type ClientAuthInfoWriterFunc func(ClientRequest, strfmt.Registry) error
|
||||
|
||||
// AuthenticateRequest adds authentication data to the request
|
||||
func (fn ClientAuthInfoWriterFunc) AuthenticateRequest(req ClientRequest, reg strfmt.Registry) error {
|
||||
return fn(req, reg)
|
||||
}
|
||||
|
||||
// A ClientAuthInfoWriter implementor knows how to write authentication info to a request
|
||||
type ClientAuthInfoWriter interface {
|
||||
AuthenticateRequest(ClientRequest, strfmt.Registry) error
|
||||
}
|
||||
42
vendor/github.com/go-openapi/runtime/client_operation.go
generated
vendored
Normal file
42
vendor/github.com/go-openapi/runtime/client_operation.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// ClientOperation represents the context for a swagger operation to be submitted to the transport
|
||||
type ClientOperation struct {
|
||||
ID string
|
||||
Method string
|
||||
PathPattern string
|
||||
ProducesMediaTypes []string
|
||||
ConsumesMediaTypes []string
|
||||
Schemes []string
|
||||
AuthInfo ClientAuthInfoWriter
|
||||
Params ClientRequestWriter
|
||||
Reader ClientResponseReader
|
||||
Context context.Context
|
||||
Client *http.Client
|
||||
}
|
||||
|
||||
// A ClientTransport implementor knows how to submit Request objects to some destination
|
||||
type ClientTransport interface {
|
||||
//Submit(string, RequestWriter, ResponseReader, AuthInfoWriter) (interface{}, error)
|
||||
Submit(*ClientOperation) (interface{}, error)
|
||||
}
|
||||
59
vendor/github.com/go-openapi/runtime/client_request.go
generated
vendored
Normal file
59
vendor/github.com/go-openapi/runtime/client_request.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// ClientRequestWriterFunc converts a function to a request writer interface
|
||||
type ClientRequestWriterFunc func(ClientRequest, strfmt.Registry) error
|
||||
|
||||
// WriteToRequest adds data to the request
|
||||
func (fn ClientRequestWriterFunc) WriteToRequest(req ClientRequest, reg strfmt.Registry) error {
|
||||
return fn(req, reg)
|
||||
}
|
||||
|
||||
// ClientRequestWriter is an interface for things that know how to write to a request
|
||||
type ClientRequestWriter interface {
|
||||
WriteToRequest(ClientRequest, strfmt.Registry) error
|
||||
}
|
||||
|
||||
// ClientRequest is an interface for things that know how to
|
||||
// add information to a swagger client request
|
||||
type ClientRequest interface {
|
||||
SetHeaderParam(string, ...string) error
|
||||
|
||||
SetQueryParam(string, ...string) error
|
||||
|
||||
SetFormParam(string, ...string) error
|
||||
|
||||
SetPathParam(string, string) error
|
||||
|
||||
SetFileParam(string, NamedReadCloser) error
|
||||
|
||||
SetBodyParam(interface{}) error
|
||||
|
||||
SetTimeout(time.Duration) error
|
||||
}
|
||||
|
||||
// NamedReadCloser represents a named ReadCloser interface
|
||||
type NamedReadCloser interface {
|
||||
io.ReadCloser
|
||||
Name() string
|
||||
}
|
||||
68
vendor/github.com/go-openapi/runtime/client_request_test.go
generated
vendored
Normal file
68
vendor/github.com/go-openapi/runtime/client_request_test.go
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type trw struct {
|
||||
Headers http.Header
|
||||
Body interface{}
|
||||
}
|
||||
|
||||
func (t *trw) SetHeaderParam(name string, values ...string) error {
|
||||
if t.Headers == nil {
|
||||
t.Headers = make(http.Header)
|
||||
}
|
||||
t.Headers.Set(name, values[0])
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *trw) SetQueryParam(_ string, _ ...string) error { return nil }
|
||||
|
||||
func (t *trw) SetFormParam(_ string, _ ...string) error { return nil }
|
||||
|
||||
func (t *trw) SetPathParam(_ string, _ string) error { return nil }
|
||||
|
||||
func (t *trw) SetFileParam(_ string, _ NamedReadCloser) error { return nil }
|
||||
|
||||
func (t *trw) SetBodyParam(body interface{}) error {
|
||||
t.Body = body
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *trw) SetTimeout(timeout time.Duration) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestRequestWriterFunc(t *testing.T) {
|
||||
|
||||
hand := ClientRequestWriterFunc(func(r ClientRequest, reg strfmt.Registry) error {
|
||||
r.SetHeaderParam("blah", "blah blah")
|
||||
r.SetBodyParam(struct{ Name string }{"Adriana"})
|
||||
return nil
|
||||
})
|
||||
|
||||
tr := new(trw)
|
||||
hand.WriteToRequest(tr, nil)
|
||||
assert.Equal(t, "blah blah", tr.Headers.Get("blah"))
|
||||
assert.Equal(t, "Adriana", tr.Body.(struct{ Name string }).Name)
|
||||
}
|
||||
63
vendor/github.com/go-openapi/runtime/client_response.go
generated
vendored
Normal file
63
vendor/github.com/go-openapi/runtime/client_response.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// A ClientResponse represents a client response
|
||||
// This bridges between responses obtained from different transports
|
||||
type ClientResponse interface {
|
||||
Code() int
|
||||
Message() string
|
||||
GetHeader(string) string
|
||||
Body() io.ReadCloser
|
||||
}
|
||||
|
||||
// A ClientResponseReaderFunc turns a function into a ClientResponseReader interface implementation
|
||||
type ClientResponseReaderFunc func(ClientResponse, Consumer) (interface{}, error)
|
||||
|
||||
// ReadResponse reads the response
|
||||
func (read ClientResponseReaderFunc) ReadResponse(resp ClientResponse, consumer Consumer) (interface{}, error) {
|
||||
return read(resp, consumer)
|
||||
}
|
||||
|
||||
// A ClientResponseReader is an interface for things want to read a response.
|
||||
// An application of this is to create structs from response values
|
||||
type ClientResponseReader interface {
|
||||
ReadResponse(ClientResponse, Consumer) (interface{}, error)
|
||||
}
|
||||
|
||||
// NewAPIError creates a new API error
|
||||
func NewAPIError(opName string, payload interface{}, code int) *APIError {
|
||||
return &APIError{
|
||||
OperationName: opName,
|
||||
Response: payload,
|
||||
Code: code,
|
||||
}
|
||||
}
|
||||
|
||||
// APIError wraps an error model and captures the status code
|
||||
type APIError struct {
|
||||
OperationName string
|
||||
Response interface{}
|
||||
Code int
|
||||
}
|
||||
|
||||
func (a *APIError) Error() string {
|
||||
return fmt.Sprintf("%s (status %d): %+v ", a.OperationName, a.Code, a.Response)
|
||||
}
|
||||
60
vendor/github.com/go-openapi/runtime/client_response_test.go
generated
vendored
Normal file
60
vendor/github.com/go-openapi/runtime/client_response_test.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type response struct {
|
||||
}
|
||||
|
||||
func (r response) Code() int {
|
||||
return 490
|
||||
}
|
||||
func (r response) Message() string {
|
||||
return "the message"
|
||||
}
|
||||
func (r response) GetHeader(_ string) string {
|
||||
return "the header"
|
||||
}
|
||||
func (r response) Body() io.ReadCloser {
|
||||
return ioutil.NopCloser(bytes.NewBufferString("the content"))
|
||||
}
|
||||
|
||||
func TestResponseReaderFunc(t *testing.T) {
|
||||
var actual struct {
|
||||
Header, Message, Body string
|
||||
Code int
|
||||
}
|
||||
reader := ClientResponseReaderFunc(func(r ClientResponse, _ Consumer) (interface{}, error) {
|
||||
b, _ := ioutil.ReadAll(r.Body())
|
||||
actual.Body = string(b)
|
||||
actual.Code = r.Code()
|
||||
actual.Message = r.Message()
|
||||
actual.Header = r.GetHeader("blah")
|
||||
return actual, nil
|
||||
})
|
||||
reader.ReadResponse(response{}, nil)
|
||||
assert.Equal(t, "the content", actual.Body)
|
||||
assert.Equal(t, "the message", actual.Message)
|
||||
assert.Equal(t, "the header", actual.Header)
|
||||
assert.Equal(t, 490, actual.Code)
|
||||
}
|
||||
41
vendor/github.com/go-openapi/runtime/constants.go
generated
vendored
Normal file
41
vendor/github.com/go-openapi/runtime/constants.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package runtime
|
||||
|
||||
const (
|
||||
// HeaderContentType represents a http content-type header, it's value is supposed to be a mime type
|
||||
HeaderContentType = "Content-Type"
|
||||
|
||||
// HeaderTransferEncoding represents a http transfer-encoding header.
|
||||
HeaderTransferEncoding = "Transfer-Encoding"
|
||||
|
||||
// HeaderAccept the Accept header
|
||||
HeaderAccept = "Accept"
|
||||
|
||||
charsetKey = "charset"
|
||||
|
||||
// DefaultMime the default fallback mime type
|
||||
DefaultMime = "application/octet-stream"
|
||||
// JSONMime the json mime type
|
||||
JSONMime = "application/json"
|
||||
// YAMLMime the yaml mime type
|
||||
YAMLMime = "application/x-yaml"
|
||||
// XMLMime the xml mime type
|
||||
XMLMime = "application/xml"
|
||||
// TextMime the text mime type
|
||||
TextMime = "text/plain"
|
||||
// MultipartFormMime the multipart form mime type
|
||||
MultipartFormMime = "multipart/form-data"
|
||||
)
|
||||
9
vendor/github.com/go-openapi/runtime/discard.go
generated
vendored
Normal file
9
vendor/github.com/go-openapi/runtime/discard.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package runtime
|
||||
|
||||
import "io"
|
||||
|
||||
// DiscardConsumer does absolutely nothing, it's a black hole.
|
||||
var DiscardConsumer = ConsumerFunc(func(_ io.Reader, _ interface{}) error { return nil })
|
||||
|
||||
// DiscardProducer does absolutely nothing, it's a black hole.
|
||||
var DiscardProducer = ProducerFunc(func(_ io.Writer, _ interface{}) error { return nil })
|
||||
21
vendor/github.com/go-openapi/runtime/fixtures/bugs/264/swagger.yml
generated
vendored
Normal file
21
vendor/github.com/go-openapi/runtime/fixtures/bugs/264/swagger.yml
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
swagger: '2.0'
|
||||
info:
|
||||
version: 1.0.0
|
||||
title: 'Test'
|
||||
schemes:
|
||||
- http
|
||||
produces:
|
||||
- application/json
|
||||
consumes:
|
||||
- application/json
|
||||
paths:
|
||||
/key/{id}:
|
||||
delete:
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
type: integer
|
||||
required: true
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
29
vendor/github.com/go-openapi/runtime/fixtures/certs/myCA.crt
generated
vendored
Normal file
29
vendor/github.com/go-openapi/runtime/fixtures/certs/myCA.crt
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIE/TCCAuWgAwIBAgIJAJ0kpLFo4pEzMA0GCSqGSIb3DQEBCwUAMBUxEzARBgNV
|
||||
BAMMCkdvIFN3YWdnZXIwHhcNMTYxMjIxMDgzMzM4WhcNMTgxMjIxMDgzMzM4WjAV
|
||||
MRMwEQYDVQQDDApHbyBTd2FnZ2VyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
|
||||
CgKCAgEAzQ5NC1JBNNP79HPiUBAO59LoUMGbmSU9K9v+cQMuyyOuv0nwuiXc5anU
|
||||
J1BINqgLR1VJjwTnQsXSlsr2SPs/144KgTsgk/QpMXdlFQwfqLJBIFlsQQBbMx6L
|
||||
/2Ho6KE7z/qz6cqgKvYrGDu6ELUu016MbUsPWfhPBJE7Ftoajk5AIomDPmiTi0cZ
|
||||
wdhC8SB0aVVQ2IWrsusfgPeOQ+ZLa/WHmpJ2Syfq41i/VKllEeCrMwtMP2By2kA/
|
||||
ufBLCnhr7yZ0u22O1Bl1+0XedWli2GiXyt1h9nQ5blTTKZi5grOzAgCcshb/bw1H
|
||||
1hdJKMqkzbqt2Mxc/78PJbDgicJU1ap+fhfBmUviWIMML6eum2ObuKd4ihhXKfqp
|
||||
T/nSUA0P9565W71SLAHFLdZX/VSMZnoehkwIicVGgEzjlYj2j9qBc0CjYzbEtQXH
|
||||
TRGhbjMX5LSByeE6hwLM6hIbQL4nriRobar63rbOc74Tm1ed02R6BvQjgXgOGqAN
|
||||
BgCKKjfUIm0Qm2qV4WkwGIAOi+hdUpbNJ0X2dU/B00qLhar+h4NT9TW4PmKf4agk
|
||||
NZ6O3C1saGxjtuPnIdDxWTdRhPSUyjsllmWhrmkY2bsRB8Z47zqrdfyajXlPOmBM
|
||||
1f0am4Zeo3ditBTfFqtA2LLQbn1yZwYJQ8+sESu6bsm3S89DFT0CAwEAAaNQME4w
|
||||
HQYDVR0OBBYEFN4BShcjqDbbgaGvPiGMNrUEi/RZMB8GA1UdIwQYMBaAFN4BShcj
|
||||
qDbbgaGvPiGMNrUEi/RZMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIB
|
||||
AIqZYn+PFMcOwraYtXtAzJwU4gElWDjIA+xVMMzulHde8t7EWo+I5iDdtn+sHzhG
|
||||
B1oYFhKv/HIX9GR3XDYWluoUVA4Ed9eBamL0Qqzq4Era6ZN1VQd0egvyOT40UQ7m
|
||||
2aNw1nLgWadCmsxeVMKQRdzct9G3dOfJp7K5WybINWTibNMTuoSuU5RwtzriK000
|
||||
C9pnxCD8boSNY/flOX0M5Mt3kv2JaIH2UsMKNGBf5+rXcKfhTE6JgiXorUEEztHP
|
||||
PFpZ6VFKDlr8QC/4aLYhOJ9LIloaxZyk/rccCuHbdPPX5XGA3Z9i/lxSoqtShYlS
|
||||
mt5vmdRwQob/ul6hPch3YRqD4VgeM1O80FEsWBK2WmGGH3wKNKea7u6dZyfQv3t3
|
||||
fUVmByAVMllVRA1YiKmBZ/kOeAMku5hpR9kzErCXZd/xrKWVym000RsvRb6apltM
|
||||
sYnlCyKfIdKxUXavO0Bf4+YoaN4/p3mZchxpLBwrzhPyUpGQ9b3TuGjoEmtG57yn
|
||||
6I3U40/TouJR0aF7i1bAF5QJWYOS7OycJbHAIZiQx9ENDP3ZMfYNWQO6STFJAjvC
|
||||
C0u23DyiJWZqE4Uw51O7jWKh7bSEKWutwa0XKWrpxhUjHFX4qGigIvXpO9LMjR60
|
||||
YDhdCEmUiu/Hc0tt0QzyTA6w47TP0gXREeBLabzuEDPi
|
||||
-----END CERTIFICATE-----
|
||||
51
vendor/github.com/go-openapi/runtime/fixtures/certs/myCA.key
generated
vendored
Normal file
51
vendor/github.com/go-openapi/runtime/fixtures/certs/myCA.key
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIJKgIBAAKCAgEAzQ5NC1JBNNP79HPiUBAO59LoUMGbmSU9K9v+cQMuyyOuv0nw
|
||||
uiXc5anUJ1BINqgLR1VJjwTnQsXSlsr2SPs/144KgTsgk/QpMXdlFQwfqLJBIFls
|
||||
QQBbMx6L/2Ho6KE7z/qz6cqgKvYrGDu6ELUu016MbUsPWfhPBJE7Ftoajk5AIomD
|
||||
PmiTi0cZwdhC8SB0aVVQ2IWrsusfgPeOQ+ZLa/WHmpJ2Syfq41i/VKllEeCrMwtM
|
||||
P2By2kA/ufBLCnhr7yZ0u22O1Bl1+0XedWli2GiXyt1h9nQ5blTTKZi5grOzAgCc
|
||||
shb/bw1H1hdJKMqkzbqt2Mxc/78PJbDgicJU1ap+fhfBmUviWIMML6eum2ObuKd4
|
||||
ihhXKfqpT/nSUA0P9565W71SLAHFLdZX/VSMZnoehkwIicVGgEzjlYj2j9qBc0Cj
|
||||
YzbEtQXHTRGhbjMX5LSByeE6hwLM6hIbQL4nriRobar63rbOc74Tm1ed02R6BvQj
|
||||
gXgOGqANBgCKKjfUIm0Qm2qV4WkwGIAOi+hdUpbNJ0X2dU/B00qLhar+h4NT9TW4
|
||||
PmKf4agkNZ6O3C1saGxjtuPnIdDxWTdRhPSUyjsllmWhrmkY2bsRB8Z47zqrdfya
|
||||
jXlPOmBM1f0am4Zeo3ditBTfFqtA2LLQbn1yZwYJQ8+sESu6bsm3S89DFT0CAwEA
|
||||
AQKCAgAjBkBOoLwWg+bTOD/9oOCK5FFeCdPD8sJiDW+Gah7B/9RHRB/kC7eRWtKr
|
||||
7GCJRWa3xm+MCDBgDV4M95ndmVysOsy8ihbkbp3inxwa3jlCHUBWgC+nYqIxNxR+
|
||||
iIC5y2BmA9JbKor1C5sMxpbfZ7MZ01p1CI8UtP76LrxDCPnkOKVnwMk0DbS1420Y
|
||||
2RGGEh8QJsxqT1qmctastpwMKPfU9tk0o7Ok3qqWLoBvu4dR6GgVjeZ2JMk5UiQQ
|
||||
ZGTM4wi8jnr90JbGz5qBUsvOjjOd9y+GLQ4ghHWSzNZMkpONKZh3zRb2rErw8vnE
|
||||
LbIHT6Wapjovf6ia3k1+CJoxrYnDrsOHcWopm2kle7FXjgfHRXubcNU2aLdIAcRg
|
||||
ZGGyalex3/NXKjhGf8jhaXKkOYDL37ZFtEmaUJVjjhiIE5jGByBHU0pqKk9Tdtv0
|
||||
s5r5m0T8Gk8h70+fZ/C+wkYE4h8uzqAlq/yrxBSlGMHEVG9PI9tr9bM1FLM/H92q
|
||||
CqoVR6YWTC7o5Kasr33RKYJg5vPHfFoIGHX9etbfHPGQsbCLaWhTLIYus+0b4ZS1
|
||||
D1jHCoxHCjKzf2PFwogtRsmhyQSS3A3GyEWy7BZgFvgKFpq9hRC66k8Z7pnnkKrW
|
||||
i4YihK17ivI5uG67Aqlc+kdahRNVWOOaPbwjGosmlULyfCOdGQKCAQEA79dD3caa
|
||||
zXqFQkYDZwZcthXw9Hn+ChTCcfucJz9I0DUeL8FpUQYCkFZRUoEgF/eNrKSG+ctn
|
||||
VDgrj0IZAcumpfjc4ZMug8svFYkE+vsUVgSI03KPRJ5NZ+Egn+HExURzCSQY6fK8
|
||||
mCp05+gXndiUhoco2H851esmMtCSd/5IyR3d3C64ZfFGSk/Nx66A4Z643ffB6tOH
|
||||
KYWFgVoQtSb92pgyxuBzZ1JhxuBVihRzAQtuE+uZ14xPoVv52fUlYXUhGmdqtZ3l
|
||||
Cio3YGZTaUqtF0BP8HshzAWQ2k2vCJUxY99dbFfsE+v8vCojgMz8KmzO7C+j3Pa1
|
||||
hq77rT29WFvaHwKCAQEA2t8R3QCkcaCRDMAPomqPJjUHrX2gdPM2zFFCvSqiVkh6
|
||||
8ft9NF8sO1aXq600IxTiTf/L8ZvM0HlPlYQSjFzGWsOgNww9MKF7L4NnJ7e/8mwP
|
||||
jqfajNcqecHIXvNi0AqXOpN/hEhm5MWKce/BPV6GpnRnb5doy8wOG0ESsmUA/5TJ
|
||||
y/65LVxDKT9SdymDVayRwq2vNn9qW2BBcM9yan5GstkE3zzkrzKcCgz5X09/vO3R
|
||||
K3fYk0FReE9CY9XAQGtz36Ra19efETzvWPi18zsP96QMUYIS2+Y45sVPhGZbY2aG
|
||||
HQXTg8xIJN51E+jmWpJ1vv27izFh5TXeloRD4qldIwKCAQEAqkG6+KVy4OjXzlsb
|
||||
MTiP+eaLfVFYaFmiSv3dNPM0wjDi8+2t0Imeqk3MPvBRExJ17ReChbLB8ERLj8/R
|
||||
Jrgl3e5TBoLP41kKXJQ/B9fS8NkZNFk/oOtrcZGb8kN3xr23l8abNQBOpwqEoNfe
|
||||
Y/wKO5GZCk8OhHAAVtQ/FZVaoAJmq1YzKpLjXf9WyihzbzaYb2Hgs81jRrN1OYTx
|
||||
FVfPnyyp5woQgkk2BdLchj/L//LYOqXmOOBu6tH7BKGE3rEiRbciRjkHDXc4hmM9
|
||||
VSJgy3+o/8K5FDbjREUfOs2GGSrIDBBCE0ZTzFNxjo51d7x0C7Ap98Ley/RNzwZj
|
||||
8mSJ6wKCAQEA0NXvcXPfdBvEyumnAU2zcL1AqiUoKO635pPSnjRD2RgnVySi/omg
|
||||
5q1k4oXNLXwLwmjD67DA6FoXuY3fNNaA3LGz+VJQQEqUA23Zy2fkWicJYRB/08qp
|
||||
2KsxyIdqTR8N1PJPxaRfqQFja/tb4naC++gtmahacbot64tXj6gYH8WUFnThs4pI
|
||||
+t5UjSarDeAu5BZdDB7fGHjrd/w4K6x5QMUZhPfRK+maQWzHtE1ikJ5J6rPbjgXQ
|
||||
+n6F1kRpwA3G7ikgFLrEJ+qAZeBJm99LCPsaVdtKq08sE+VITghsQpfcd2zLuQH+
|
||||
BE/OXkTnJpyAhNANVm6z/cQ8sllZfLglCQKCAQEAkZTQ0xnUeJTV0CqljMNCIN4M
|
||||
i6Xyqf5uUDPfooY+fILbemT/acYUAkbjamgJlQMQ7yui9WV7Q/9HiCHaVh3o5zrV
|
||||
zaq3vocA9x9nK998/He7772/uJarINvLFj/p/vTQM4Lni+bJ93bk6XE+FQKPgY9B
|
||||
GfeFFaVtH7gimB4CjrxYprhAfqyxyE/m6JVMRg1olIFuav37GYP+TJ2K85klQRNa
|
||||
TEXbm6ZJpSHfNjKZzUczziaIbwnMN9OxJY6M3a1JuEy2h+og5oRdMOoB6RETzhle
|
||||
mxT5uEtA6mR6KyBZBjWhcl/V/Rw1DVMmtVbHCdc0+Xn/CMemRLCw1bxRUu/iww==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
27
vendor/github.com/go-openapi/runtime/fixtures/certs/mycert1.crt
generated
vendored
Normal file
27
vendor/github.com/go-openapi/runtime/fixtures/certs/mycert1.crt
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEqzCCApMCCQChJZEdSdrQkjANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDDApH
|
||||
byBTd2FnZ2VyMB4XDTE2MTIyMTA4MzMzOFoXDTE3MTIyMTA4MzMzOFowGjEYMBYG
|
||||
A1UEAwwPZ29zd2FnZ2VyLmxvY2FsMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
|
||||
CgKCAgEAs1MHhleossLBkYKYwOT+82RT651CfCOilpEUhm92KGRSMQXZEk+2TUgc
|
||||
dGPeQNDNmbpXGzdk1HZkqWR5XKfSjWWxfmBlbBoYnkL3neoiXBdBVsgHkEPdP5ly
|
||||
uJRkohy6az1vnq2vLaI+YujStutf8hSdcPu9VeALbrR027dMbY2XMC97FteeVaw1
|
||||
mXmW9UHDVSV9UPBPswUOQWhjIADBk5IYaYASCY3M4X5BPCWFu1oQhgVMEhodBoBj
|
||||
pHhHrfoDm1TwtT+dp53TmR10zpUiN+FcaVMsjqN4DWX4ma0uhu+zJew2XjCJkNfX
|
||||
wVqGFpe2Hx+lupOGs/kwBvQ4PYn5ydgcm5DTggBC45JxCAVi3tQCYGsg2xkX9yPj
|
||||
aXYc8E4/aeQI9UZxUeR2siBn8ECX4gJTmPJbQ4Xykqn6YOHyxIVoqd+9wo9Z1weH
|
||||
xCWtPGESg7l7Jn/6WQ5V8z6RzrquGi67asrpYpv2lxNXMQA0f3S8sWYe4f8QVazy
|
||||
ALtu8+0XE17UPjlbNBqEfCIrMsYmL5VyMVbL0dlXXBxHjzfpXraNGoSD4v6LxRxP
|
||||
dWQgrhEZ6DmfiWfX8uhLdMwlvUxNXj33UDtM8dtN6mHERA9wF2RQQzPddZ0MYmUF
|
||||
DI92i9mRC7Yzx6mcv/yUnFw213Jnzg297lW0Xp0ifawyPi2V8f8CAwEAATANBgkq
|
||||
hkiG9w0BAQsFAAOCAgEAme1gyNQry3E5bj4XfdL4aNvZamzLaQVRlNZSHUzDhhpH
|
||||
6N/DK/CAw4g4Msty7g3KBZPmldJhxH0bnSoRGMjFdKn9tVQeJOjaHQ2Z3cQWwdte
|
||||
iXtu2F38SVfP5HCh9ASQ9vQXahGOruUPUUNUnDLfOBea7vrT3DmVugXlMSmaYuSJ
|
||||
JdrbPzD48yy60AEDlCVpY2m1cEc5SmTkXbrAg2jhQd6ytaPQ28vGQnpZHSS/xWjC
|
||||
Hh68o5SUoGoFErZxPd0o2brHavi4YybYt7CXlWG2TJ89s3BCSPIHclNF2HjxRq/r
|
||||
2Q/Ttzo3cRBxi3RBnrLdn4qNgJjZnWaLobjaWcs1fbI32allogLsiurCwZb0ToC0
|
||||
fNMzyHVNWY8BqsuyWyF2H0F9rklmqGFJSmrqt8kDLx0xpkZchGPIDSRh+f+PPDmE
|
||||
jGPPH2qxz4un0foJx99dtw18TPaplFo2LxRK89koTiQNyzAHwSn6PHGlyXhNPsUt
|
||||
K5GzjAu6B4uyldcg2m+4O/dbNdeqSczYAFenfEO7PRAy3AP7Lxs2xqQaNiA10965
|
||||
vYmCNIOuV24CuFEIrjOQkZeFCw+odsgFs5Nv8JfDdA+BRr+Haq8FVX8afEc0BEnr
|
||||
xY6f2fvgYTMvx0Z3UVT/XJ3POWHRL0HFLj5avHE0eOOkrcPbX6UsANd1v0F2BH8=
|
||||
-----END CERTIFICATE-----
|
||||
51
vendor/github.com/go-openapi/runtime/fixtures/certs/mycert1.key
generated
vendored
Normal file
51
vendor/github.com/go-openapi/runtime/fixtures/certs/mycert1.key
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIJKQIBAAKCAgEAs1MHhleossLBkYKYwOT+82RT651CfCOilpEUhm92KGRSMQXZ
|
||||
Ek+2TUgcdGPeQNDNmbpXGzdk1HZkqWR5XKfSjWWxfmBlbBoYnkL3neoiXBdBVsgH
|
||||
kEPdP5lyuJRkohy6az1vnq2vLaI+YujStutf8hSdcPu9VeALbrR027dMbY2XMC97
|
||||
FteeVaw1mXmW9UHDVSV9UPBPswUOQWhjIADBk5IYaYASCY3M4X5BPCWFu1oQhgVM
|
||||
EhodBoBjpHhHrfoDm1TwtT+dp53TmR10zpUiN+FcaVMsjqN4DWX4ma0uhu+zJew2
|
||||
XjCJkNfXwVqGFpe2Hx+lupOGs/kwBvQ4PYn5ydgcm5DTggBC45JxCAVi3tQCYGsg
|
||||
2xkX9yPjaXYc8E4/aeQI9UZxUeR2siBn8ECX4gJTmPJbQ4Xykqn6YOHyxIVoqd+9
|
||||
wo9Z1weHxCWtPGESg7l7Jn/6WQ5V8z6RzrquGi67asrpYpv2lxNXMQA0f3S8sWYe
|
||||
4f8QVazyALtu8+0XE17UPjlbNBqEfCIrMsYmL5VyMVbL0dlXXBxHjzfpXraNGoSD
|
||||
4v6LxRxPdWQgrhEZ6DmfiWfX8uhLdMwlvUxNXj33UDtM8dtN6mHERA9wF2RQQzPd
|
||||
dZ0MYmUFDI92i9mRC7Yzx6mcv/yUnFw213Jnzg297lW0Xp0ifawyPi2V8f8CAwEA
|
||||
AQKCAgBZtF8/RPqO8f4C3GGtnOAswTN52eE4WFstFsY9ueRRsF2tSE+eaWG4pyoU
|
||||
zyCPK+St0hlg9ATsg403b5uGTi11rjlsDqyttyA5iyZzSHyHtNpqnwWplUlIV2qc
|
||||
Cx+MOPLIUqNTrW7EVTUAJZfDCVulrcpUipncK4eMiZkrkDYbV4kaAaaBdrsuAEeP
|
||||
ztNFPPCJ14coxg4Yb58B+UYc7EPpnlu36uka/mRPKOlZPSv43MUHRf8XzxhV+EPg
|
||||
Moso7LiBK6x9/qTPBJSlM6cK8G99pK6lwYW4lO2pRilmNsvflGj5v4Ay/fTTECZO
|
||||
AwqwopPoXdx5yPLJdQ4hbGn13t+k0pB4LYXl1xqLg2Z9QN+pgC2h41OrSx8Ozw9U
|
||||
KTocbsMV6pafnMRoQ5Fjb+eTy4VE8rZl/OlMDX2cR2XL+a3ypIAA5E4KrYDiIBiU
|
||||
MSA3EA3GsOOnyrV+fII+f2tVo/qDnvxQO/ZPUr/XG2xtJ+gqThWlrBft/O4/lCju
|
||||
+kfNg8cMHtahGOmLz1ALsl32ANj5jTZmVOEs9xTG7+TeQ2RzWeBYTB7oNTMNIbaL
|
||||
pTZTzxoeRyxx8sUvtaTb23IWSpRUiS4+F7Tn97g6ks8fYQPsVkl3WzXeECaL9uNN
|
||||
hFkAwd0omD4TwQlmOUVm3IH7A0InTAaooC9jJfNqmhhHcLUAgQKCAQEA3N+pR1ed
|
||||
aCXQit6bgw0rIF6RzjeGp6lLGaPdvCUM7sdAUwSGbFOgkcaw9TELFpCpfZGKFXI9
|
||||
IxPOwjFrURY4S2iuyAVv+Cw7trXW4BF1z+08M9RWYGLvyUsO7FIsGUmdYRtasb5L
|
||||
IfHfGoXttadKWcdFMSF+25CUcbleyCNrJzXOzeMn1/UoN6+qfsyfaAD03nw/ZmhA
|
||||
mK3UKjR7UOUPXt9gIXVivRaEQBakrLkJtK33fl1hztqxComE3/h6Qmj6iRmyxX3y
|
||||
v3mzXbyC6jobq1tLUWpxvlQgoAyk+zZ0LNEHlkVfertaz0XdN/L2ZgjoGjJxfn/y
|
||||
OK0a4jJyCpXXEwKCAQEAz9fJcpqaB25joZsqG+islNljyFjJRT9+E8IU97OglhJM
|
||||
8T9TFs4RNsAxIqHwYm4KuoSlI4GhYeuOxGk6yUGm8cO314J7Wv4CAgZeJBcmxJUs
|
||||
C8FbcXKbesK3VIuvATgzI9Vq/UF+GxJCkPctZJ9Oa0t578rVS4JH5ZJQdw2A77Lq
|
||||
kGunMDboVY7EYDOn/fNMKGfcnH8KIQn/2b6CKLarj39b1fG7MeCuxPRejijaKtZI
|
||||
ra5n0ofLluGo9HBXLgqgsjhjkSWU79lRypuKS8qOcjI08Xaw3Q8+qn0uLCARd8rN
|
||||
2+mQy5OAZJCWpYIKPL6E41GaxcaTdOYzlOCs9Oz65QKCAQEAgSqzXitYvC1RFcU1
|
||||
AKDU1as4bXZ/YtFYP/halcq9E26mqWX+Dp+hSV7+4YT6zQlwdSSFsiEKq9bLlTk9
|
||||
X0A1T7Q6cnLrliCYEzOoI4VSdnRwPocwtFFnlTo10fIEJA2u4bkTgtqcKY+/P02P
|
||||
RCo/Ct3EEwVZoKGejhsv2K8N3PJUrIbpKBwQlvA+LsUPe80DZpEWqpbRH/iYGM50
|
||||
R0yNfpf3KdnyEk52rNwRFYloqacLE3Uc29F8s4LUl/5B0VB/I2pJ58DOEzfiszCp
|
||||
Br1QrRdIpqYvOnUMV0zNtrOToRnk6/ZJ7gZfBtP+mNeXTPhsc9WIFchRKN/i1uFV
|
||||
W+dgzQKCAQEArcXTDdio85GeB1395PuyX3kqbjWdgiJFvStF8JvkpdSDNCknxSdh
|
||||
SQ+DhVsz6nfqzGtezsLxNTeHVDxPBDm55OUobi0QCdHZx+ufBjm9FhtKikGNvNp/
|
||||
mDH4qd1n4nMkfs9O9pOtZeDsetvOvhRbsmWWe6BwmQNCLXUZhZBqvv4uE7WOQUeH
|
||||
FRGaqnxF9pNWl2nPD6E/zMPZgCpCFNw1sHJhTA0h39/k/5L5A46waaRje6MX9vPG
|
||||
ik39vvG2Ui5ckOWIibCMR8TBF87X3+ppEp1bmo8L7Kd0U4L5+baOJEQRvc4YW7zl
|
||||
Wi9xZMvG12bLIGv4JWeTnediNRVsRhNk6QKCAQBXYkpxk6LTgP+b6FJ7fiImzDbH
|
||||
QJ+RbBYJdgYLEarKWdWhNqj3YiDOUJt+ve13reybL4cLmOYoNzeUO9IHyGeTp+WV
|
||||
gtPf1g2hm2TZannWsoTvnoXJ8yR52ZQQ5JusNosbmlrqWRAN8GhISdYTJDNcS2hD
|
||||
PnVX/kaJfRDennokD+FWuyygua66LBdZi3UNgGMay15/2CCoC3PoejfQORxDyPP9
|
||||
am+e3/U6QG1/VWMHen3Mb0AZKwEBAwX1jL4EpoDZ+Y6jP0tbQ5xL7RivsUNtAVlQ
|
||||
m7lumflcBy1WqkmviVJ9M2iFuo0HznuH1qlgOJpUiqZZjL/gEvkdDNMcQSmH
|
||||
-----END RSA PRIVATE KEY-----
|
||||
26
vendor/github.com/go-openapi/runtime/fixtures/certs/mycert1.req
generated
vendored
Normal file
26
vendor/github.com/go-openapi/runtime/fixtures/certs/mycert1.req
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIEXzCCAkcCAQAwGjEYMBYGA1UEAwwPZ29zd2FnZ2VyLmxvY2FsMIICIjANBgkq
|
||||
hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAs1MHhleossLBkYKYwOT+82RT651CfCOi
|
||||
lpEUhm92KGRSMQXZEk+2TUgcdGPeQNDNmbpXGzdk1HZkqWR5XKfSjWWxfmBlbBoY
|
||||
nkL3neoiXBdBVsgHkEPdP5lyuJRkohy6az1vnq2vLaI+YujStutf8hSdcPu9VeAL
|
||||
brR027dMbY2XMC97FteeVaw1mXmW9UHDVSV9UPBPswUOQWhjIADBk5IYaYASCY3M
|
||||
4X5BPCWFu1oQhgVMEhodBoBjpHhHrfoDm1TwtT+dp53TmR10zpUiN+FcaVMsjqN4
|
||||
DWX4ma0uhu+zJew2XjCJkNfXwVqGFpe2Hx+lupOGs/kwBvQ4PYn5ydgcm5DTggBC
|
||||
45JxCAVi3tQCYGsg2xkX9yPjaXYc8E4/aeQI9UZxUeR2siBn8ECX4gJTmPJbQ4Xy
|
||||
kqn6YOHyxIVoqd+9wo9Z1weHxCWtPGESg7l7Jn/6WQ5V8z6RzrquGi67asrpYpv2
|
||||
lxNXMQA0f3S8sWYe4f8QVazyALtu8+0XE17UPjlbNBqEfCIrMsYmL5VyMVbL0dlX
|
||||
XBxHjzfpXraNGoSD4v6LxRxPdWQgrhEZ6DmfiWfX8uhLdMwlvUxNXj33UDtM8dtN
|
||||
6mHERA9wF2RQQzPddZ0MYmUFDI92i9mRC7Yzx6mcv/yUnFw213Jnzg297lW0Xp0i
|
||||
fawyPi2V8f8CAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4ICAQB7U21HoBp5Qfrwd8aA
|
||||
KzBY2BfEp5ouyn32kpfkB3Ha6+XJ69Lt1WHMSKnmYamlwZCSOS2uQ6DzdTLDfZpC
|
||||
8PH5Gs32O9zJwUeSuYcUQGfcAenauu9gwC5ZnIbhOs5YTnEFquVsBqrNUKS+hLKJ
|
||||
sAPtucoqlLX5qSkv/BOK2X4os90LAmx+yB/yarAzZOO0ku8qXt+MHI+rOMPLTmm9
|
||||
kYhtyXejQaXLOVbvQ9b2gxHvMcyLhklc4KpJPRfPzOdNebHsf5o4Em6lxeglGw/A
|
||||
z05sBSAla69sEygcItZryQ4WjMRUpsLePXJrlSL5DYWGK6BX1gCkWtpXLqE1HgR3
|
||||
4L/xvaJQ5ZWpLoyJoJauU37Zhd5dLNGpNiSSEA0BKOjj9Kjm8nvsJE9DgziTaG57
|
||||
qFLRkMkDdBdb5wOfVYI/MY9zc+igrFPQJkQ0Xkdza8yXegBldv1JRe+49zifysea
|
||||
Y/B+qWx8IpeHke0iEMqR6iWrw6oGBG/obHJ/V09DwC6iU8vot+pLr/bSyoUCUP30
|
||||
OEATJf50ic9oZYXgdT9oNBcAlAriuzoQuGi9nAKZJss6YkhooWoqXlXNQgAEc2gl
|
||||
WF4fNumXwVaPVeW2q36Xk1btHz7k+IeVUg1jaPMPUJ+1dgIOZA7FcoYotvF6StyX
|
||||
xoHybhvC7lbeif8EK7tJ2p4hug==
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
29
vendor/github.com/go-openapi/runtime/fixtures/certs/myclient.crt
generated
vendored
Normal file
29
vendor/github.com/go-openapi/runtime/fixtures/certs/myclient.crt
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIE7jCCAtYCCQChJZEdSdrQkzANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDDApH
|
||||
byBTd2FnZ2VyMB4XDTE2MTIyMTA4MzM0N1oXDTE3MTIyMTA4MzM0N1owXTELMAkG
|
||||
A1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExETAPBgNVBAcMCE1pbGxicmFl
|
||||
MRIwEAYDVQQKDAlMb2NhbCBEZXYxEjAQBgNVBAMMCWxvY2FsaG9zdDCCAiIwDQYJ
|
||||
KoZIhvcNAQEBBQADggIPADCCAgoCggIBALGjhpJfej7btWCO4OCRJBliUAUyPMO8
|
||||
B649Qjn1Yiw9E1L5viByYJSihsfUQ7u2gHip7QdigKCA/s4+w8V2L0Dv8lCowCLk
|
||||
exf10b7XGQaOqhk2mlr/jOapAg0pKDoUlVErBBZK2s6UbD/gLXAbxudwxCFKJ1Y7
|
||||
d/Dw5aTl1vlWZpHzf2o9/ZCeHXf8Xu3aMIEPJ79wG0vzNZK7bL1r1lQVzACdHAr3
|
||||
4HAQAvgWB4ZjKqN8z0vGC0N0MpaAuHD8fH8wQ5YiWBbDhDPFVzRYU8PcQjeZSMFq
|
||||
Oulew9KVm+vXtcMvteEoXMXwWlqAGlvnv7sskc/VbrLJJQaoswyKgy1QCKxVO47E
|
||||
f2iU4kP75iDYx6NpApdnpN3zxHMHyZDxuwmtoKealenxl5cZeHc6uUU1wXk+nmy7
|
||||
TrgW509mcopHzHj+Q0zyGUg/dRws3qXPAGZehJPoaYF1F54eiindF1yLMMH5osvy
|
||||
1bNp2EQezOlY3P4gqW9VHq3CQvytmDbXqS0vPzVAsFu8YazM3Bs0mW2bBXrEsajW
|
||||
DSjrvbhdZjlL9j2jqwZ2nzyan88M5t5T0vZhcu+wKisATI1yLdV3oWvLmdFz/XA9
|
||||
L6UyosTiwC1MWPmkOY4mcHn/Px70f40+wO815pZ6FbjecxRSyMfAm6vDPWtLAMUr
|
||||
1UoD4vasyvQNAgMBAAEwDQYJKoZIhvcNAQELBQADggIBACI85R1LfDwKpmWFdCeN
|
||||
M8O6TwSftxh113QzMvobYDMmBI+yVn0ZvpcfP7E+LWRjzNcDxMFbntbbFWt99Rcd
|
||||
rJek6CVxLJug53mUEFmvktreHsJ1T7cMbk1ZVroAurE7hZOWYM2HwXlKzVyXX0qh
|
||||
wR26HSuzQcGBfo5/8e6dzMuy0fUVkgDMu4oKt0+mGgS4kXsOyexfRRBkY9GPusVk
|
||||
gSzu/WbSGNxNvp/ewWNi8waqrN3noM83iae+BXxI0Sq4eLTQ/vnV1ReM4gRR12Vw
|
||||
anwZqHZ/WzBV27z9gW36t7wRxJS/uTXQ8J08KtBRBPv+19NXSqqjys5Jg0P1f+l9
|
||||
k+sWwpVqIF2rAQ3FyMfboaFKPC0jRn7iJMjp9KyvMbSI+25/rP5xvMicoJwRlk9I
|
||||
GNGasxSfmRpVpV+WG04xMGp3cPrCXHBdAAjI3O68YIPOX3VqZ6MasN1iGuYWOmam
|
||||
yeKzLUApYdtkR7yJ+X1FOKVfbzX27CLYmzwrHnDLJzu8NVgqLGU+qTSK0zm3sYE3
|
||||
w3ex6WX86Oz2QBJ5h/s2TLbsWis7ZkKjMyXqVWlbg4P3reyNrfpAoc0y1R9EjZlf
|
||||
1c9HZBRBuRMgaPWmdSR4lxw1FhQBTstIfzC8lBYNbt8QRRtJIxVF9mxiL7H+6XH5
|
||||
FZXcQCHun6klGtCkypeAaviE
|
||||
-----END CERTIFICATE-----
|
||||
27
vendor/github.com/go-openapi/runtime/fixtures/certs/myclient.csr
generated
vendored
Normal file
27
vendor/github.com/go-openapi/runtime/fixtures/certs/myclient.csr
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIEojCCAooCAQAwXTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWEx
|
||||
ETAPBgNVBAcMCE1pbGxicmFlMRIwEAYDVQQKDAlMb2NhbCBEZXYxEjAQBgNVBAMM
|
||||
CWxvY2FsaG9zdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALGjhpJf
|
||||
ej7btWCO4OCRJBliUAUyPMO8B649Qjn1Yiw9E1L5viByYJSihsfUQ7u2gHip7Qdi
|
||||
gKCA/s4+w8V2L0Dv8lCowCLkexf10b7XGQaOqhk2mlr/jOapAg0pKDoUlVErBBZK
|
||||
2s6UbD/gLXAbxudwxCFKJ1Y7d/Dw5aTl1vlWZpHzf2o9/ZCeHXf8Xu3aMIEPJ79w
|
||||
G0vzNZK7bL1r1lQVzACdHAr34HAQAvgWB4ZjKqN8z0vGC0N0MpaAuHD8fH8wQ5Yi
|
||||
WBbDhDPFVzRYU8PcQjeZSMFqOulew9KVm+vXtcMvteEoXMXwWlqAGlvnv7sskc/V
|
||||
brLJJQaoswyKgy1QCKxVO47Ef2iU4kP75iDYx6NpApdnpN3zxHMHyZDxuwmtoKea
|
||||
lenxl5cZeHc6uUU1wXk+nmy7TrgW509mcopHzHj+Q0zyGUg/dRws3qXPAGZehJPo
|
||||
aYF1F54eiindF1yLMMH5osvy1bNp2EQezOlY3P4gqW9VHq3CQvytmDbXqS0vPzVA
|
||||
sFu8YazM3Bs0mW2bBXrEsajWDSjrvbhdZjlL9j2jqwZ2nzyan88M5t5T0vZhcu+w
|
||||
KisATI1yLdV3oWvLmdFz/XA9L6UyosTiwC1MWPmkOY4mcHn/Px70f40+wO815pZ6
|
||||
FbjecxRSyMfAm6vDPWtLAMUr1UoD4vasyvQNAgMBAAGgADANBgkqhkiG9w0BAQsF
|
||||
AAOCAgEAM9VLDurmvoYQyNEpRvFpOLPkgr8rgboo/HN+O/hN9jtmXranLxzTzd+u
|
||||
OJCujyzS3sbqiZwPeT3APHH4c/mLdrEKZHjfy2sEeXMsVW6dCOcIEYsADSCM6chi
|
||||
zU86aw4rAkd6YYB+lXFsEmBq78AIpw0vcdpoPoqGRG9ETQsjr4kD3ATGHTnaP551
|
||||
61JJed7Kn5FTbieTmzmMa46dn7GjTTmPEcoAnHNCx4CbJAHwWEzvQWF4lVlyb2di
|
||||
jFD0NQ0WeaFHK/f6UQMqMq+7TpurN8sLWDlyPHA2X/FT+OsUMAX2mLcwZEsYhTjP
|
||||
dC4ZCuZ/itDgEp3hyPeKiLo+mL/bhhy50nzah/qclI9PS8ufUXEjWoObqiJ5eyIZ
|
||||
jTZ73qpLupS+Yrami98IYfuOotwGzKkVLwUPtCWQrKsun6YNtotuKKmqEEQX3Fm3
|
||||
ZXIYv0BckkXIGd0aKPeMGgMUO26pyxPBSRWB29F07LXzS6eEmfOHvZcT+QLZmys9
|
||||
FkH3yePeTilojCnxNINPyKT4Dk0NiZviCdKavUIJ5QtOyDJ1Nc9j5ss+QaAaNtZZ
|
||||
VTTjupNp+cfCh/kdyGpGP+GgXQQcGgw4OaIbfXqmec7RsqTOppK5gDR4Ne3e5FVm
|
||||
SpPDyHbv2GJolPG8/HCOsLCJED+wAEfhK/wUg8ZpC+7Ymct2TU8=
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
51
vendor/github.com/go-openapi/runtime/fixtures/certs/myclient.key
generated
vendored
Normal file
51
vendor/github.com/go-openapi/runtime/fixtures/certs/myclient.key
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIJJwIBAAKCAgEAsaOGkl96Ptu1YI7g4JEkGWJQBTI8w7wHrj1COfViLD0TUvm+
|
||||
IHJglKKGx9RDu7aAeKntB2KAoID+zj7DxXYvQO/yUKjAIuR7F/XRvtcZBo6qGTaa
|
||||
Wv+M5qkCDSkoOhSVUSsEFkrazpRsP+AtcBvG53DEIUonVjt38PDlpOXW+VZmkfN/
|
||||
aj39kJ4dd/xe7dowgQ8nv3AbS/M1krtsvWvWVBXMAJ0cCvfgcBAC+BYHhmMqo3zP
|
||||
S8YLQ3QyloC4cPx8fzBDliJYFsOEM8VXNFhTw9xCN5lIwWo66V7D0pWb69e1wy+1
|
||||
4ShcxfBaWoAaW+e/uyyRz9VussklBqizDIqDLVAIrFU7jsR/aJTiQ/vmINjHo2kC
|
||||
l2ek3fPEcwfJkPG7Ca2gp5qV6fGXlxl4dzq5RTXBeT6ebLtOuBbnT2ZyikfMeP5D
|
||||
TPIZSD91HCzepc8AZl6Ek+hpgXUXnh6KKd0XXIswwfmiy/LVs2nYRB7M6Vjc/iCp
|
||||
b1UercJC/K2YNtepLS8/NUCwW7xhrMzcGzSZbZsFesSxqNYNKOu9uF1mOUv2PaOr
|
||||
BnafPJqfzwzm3lPS9mFy77AqKwBMjXIt1Xeha8uZ0XP9cD0vpTKixOLALUxY+aQ5
|
||||
jiZwef8/HvR/jT7A7zXmlnoVuN5zFFLIx8Cbq8M9a0sAxSvVSgPi9qzK9A0CAwEA
|
||||
AQKCAgAb4VyHsLCRGQ64nvQwitctnL6OcjoTRnm2ISs5yYelBdj4lvX+RbVe3rtk
|
||||
ta4D0jsLtS/cjts9VcGoQTWc0lXMTVysyC+Pymh/dDd9SmlFHDMaTfWf/qfws+n8
|
||||
gs8rfnuJB8VWcl0xOx5aUCcRh2qKfKprxyWxZRgIGucQIHrDG4pxsdP3qs8XWZmq
|
||||
cVO85RfjyaslYsUGAKAR7ZS9jiVPgTRJjF8QYaM6M2kj4uE/eGUCz94BOI4gAibG
|
||||
dGF+akJn+/0/nRhSSlF/hqOPNaXAAdvqugYvRSsF4be+X3jfZTXD8sMLGbil4Hlt
|
||||
5tk8P31aNT6Vbhw3t1Y2W1fuyfaYbPZfprpR/6ZPV3Uf1oWoh1ystIxWnfU7Qdxu
|
||||
vrkHkrtho6Qt/7d8nNg0mQ8y5glNcVh/iNu9gkyHIpQ2dZpM9tpHArBGweHVDMvZ
|
||||
vrb/oJ5fRxnKkyouMtWvqO1TY4STPBwCDNSwJa0yxTn3fLvkOdHk1nGEKra7E7Nc
|
||||
hgsIe4q1ZoEikg7cZe8pvcsHIFfju3Kv/zgDTvHjzHPTdNear7mpk/LihlWdbTiI
|
||||
UKkgv17JHRsIhfE5G4pZXLRv2qjCGh+uS8yn2k5qPJqGoyIQ2A7BYbaQ/y2gVh6u
|
||||
hnVdKeETT2uUqIS3xHrV0U9grAeldPJu7bHRwSoJ+HUbp+D8QQKCAQEA4/5K0+Qq
|
||||
p4rpB+4FpPkMcM4yE1j0ASwHsKGMDPU70/t8yfzZBlpf5WNHTOWa8frnxOyazo8E
|
||||
sjm2Xw1RlMb21bFF0wjb3uhN2ak++0zIKMf5vWnM0bb2z7yzbcOJVxLzO9DmRUh0
|
||||
OXvHvbeKbW9KXHT3YKA2zjaw0mO1zl7sd7r028wYpD6owGtfzooyXwWCnByIQ3nM
|
||||
JFB7wFJGIg6Kbu2eJULrN1EaT1Ye0FUVmc4x55FLmZvkYziQ88e4UsjYdZ4R5EFi
|
||||
2XULVI1RA+NPqDXkXmpIx3JnRRvaPc74QatGvDFwY8YeCAjfGFN5LiwFJ6Cz3/jf
|
||||
WjDLOhqoSiYQ2QKCAQEAx3W7uPE7WNQRsyu2QnsEDdlikgP0FJf3fFZOYurfsxp7
|
||||
iqTpNkR9pSWXftP4FBM/KRruoY5TucmPTfGPRS6sQWTfUkVOhrUpOLnuWjf2DJxH
|
||||
Qqb0wnT76WcAB4L5Gr//91a+w3dwAX5YhdTZLxEKgpm8ky290otCg3+AYOb/P3Ja
|
||||
V8RR8RQCNV1+y7peBgjj/mbYeVpxjTiZ5cq4cx2OU4rnup/k3HIg1Gw+qr0N9AUN
|
||||
2WYOL+X0qaKffDa2ekv88H6mVnfRSReFIpteuV0XITwvMc0DbHdj6zEj1TSZMExu
|
||||
rDVe7eh2BeL1QxbuazRUgwZ+kfy2NUzPkB1SSwi8VQKCAQBs8K4qj0S+Z8avjlFO
|
||||
Id6K7EvLKN72zGYkRRzZeDiNMwbOsS22NmrJ/eUs3i1qYJxsYS4bcwUocCEvS/rm
|
||||
XyfEtf8KNppw6YmBbrh0dZzSt7MiibJfptBKNP17fkpau+hTdZ8CDfvTF806XsAb
|
||||
SGk8wnsNxaBKaqGU9iYCJSNSlpe3is9fc71IrEXMOAaXltdw5sVJkKI12+s121o9
|
||||
nbsSBCJj5ZTlCrDKpfj1TSKUKo13+9om3PGFY5sHkTAHBoc/tDcSXRfxllbCoP/M
|
||||
HsqKMq4bWyfJfWXRBN0EWagQINocxHbShfEFn8+SHRizMj+ITuaEJ7P5sYT6D5DI
|
||||
VWYJAoIBAEqaxdFiIYGTKN+sbOqm2phXhB/7bJM7WC1glsc29N8n+6ebEUPkEF7y
|
||||
FZ0xqavQmyJD2ZgCBV0LgBd2T9FfqLx4/3LlS37lSfrWyMlj/xsuZRUQH6KQYR0n
|
||||
EoK8wXH4+MPJ5WZ1SSa13GSKfYW2SQkaecdPJ54VypYm3ZzhKf3QRuxnGQMkKcNO
|
||||
KjwHhF2be7PPQg75/lkFH8MstRsRpgengA90+QRfh9oMdtAkEJECRvDW1F2kFIRS
|
||||
uHacfFp4C67koFDdViGRs5GDLcYFhL5ApaJp/WrXqT7yTWXU26uOGyM8fzpbZbHD
|
||||
91rVu+3LUAUGK9ds/7Yl+cj8vqgkJ1UCggEAc0a5kmBREz/8rAWKnlCZrhBsxUUM
|
||||
tiIj32h6dVdFo5SsoyVTxdB394npw1DAsC8xdowrcm/zsYstB3IDMYlrBnCdRxTU
|
||||
Xu6RD3Jci0Qg1cfLQg5snlRnrNz12wygXcvTvW8cHsda8vO+FL1RgFdehDtYoyZr
|
||||
swcLLRAOOLTRXy1Xdbv+8vE6s5ryl3uAO+2Zwbmur3tRL+rhXE+Tb308jlt8g2NK
|
||||
WrRbc3c092aImdGcKmkMGqo6H+xnL9Jj7sR161uO5JJQjxcYbZ5PBmm3J5Z71cSY
|
||||
LR5snbYdxUy7WKE3yxAoWi+FMsoGf+O77+oHAcpXRaTDv0Enr/7rEku5Yw==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
BIN
vendor/github.com/go-openapi/runtime/fixtures/certs/myclient.p12
generated
vendored
Normal file
BIN
vendor/github.com/go-openapi/runtime/fixtures/certs/myclient.p12
generated
vendored
Normal file
Binary file not shown.
1
vendor/github.com/go-openapi/runtime/fixtures/certs/serial
generated
vendored
Normal file
1
vendor/github.com/go-openapi/runtime/fixtures/certs/serial
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
A125911D49DAD093
|
||||
38
vendor/github.com/go-openapi/runtime/flagext/byte_size.go
generated
vendored
Normal file
38
vendor/github.com/go-openapi/runtime/flagext/byte_size.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
package flagext
|
||||
|
||||
import (
|
||||
"github.com/docker/go-units"
|
||||
)
|
||||
|
||||
// ByteSize used to pass byte sizes to a go-flags CLI
|
||||
type ByteSize int
|
||||
|
||||
// MarshalFlag implements go-flags Marshaller interface
|
||||
func (b ByteSize) MarshalFlag() (string, error) {
|
||||
return units.HumanSize(float64(b)), nil
|
||||
}
|
||||
|
||||
// UnmarshalFlag implements go-flags Unmarshaller interface
|
||||
func (b *ByteSize) UnmarshalFlag(value string) error {
|
||||
sz, err := units.FromHumanSize(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*b = ByteSize(int(sz))
|
||||
return nil
|
||||
}
|
||||
|
||||
// String method for a bytesize (pflag value and stringer interface)
|
||||
func (b ByteSize) String() string {
|
||||
return units.HumanSize(float64(b))
|
||||
}
|
||||
|
||||
// Set the value of this bytesize (pflag value interfaces)
|
||||
func (b *ByteSize) Set(value string) error {
|
||||
return b.UnmarshalFlag(value)
|
||||
}
|
||||
|
||||
// Type returns the type of the pflag value (pflag value interface)
|
||||
func (b *ByteSize) Type() string {
|
||||
return "byte-size"
|
||||
}
|
||||
43
vendor/github.com/go-openapi/runtime/flagext/byte_size_test.go
generated
vendored
Normal file
43
vendor/github.com/go-openapi/runtime/flagext/byte_size_test.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
package flagext
|
||||
|
||||
import "testing"
|
||||
import "github.com/stretchr/testify/assert"
|
||||
|
||||
func TestMarshalBytesize(t *testing.T) {
|
||||
v, err := ByteSize(1024).MarshalFlag()
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, "1.024 kB", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringBytesize(t *testing.T) {
|
||||
v := ByteSize(2048).String()
|
||||
assert.Equal(t, "2.048 kB", v)
|
||||
}
|
||||
|
||||
func TestUnmarshalBytesize(t *testing.T) {
|
||||
var b ByteSize
|
||||
err := b.UnmarshalFlag("notASize")
|
||||
assert.Error(t, err)
|
||||
|
||||
err = b.UnmarshalFlag("1MB")
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, ByteSize(1000000), b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetBytesize(t *testing.T) {
|
||||
var b ByteSize
|
||||
err := b.Set("notASize")
|
||||
assert.Error(t, err)
|
||||
|
||||
err = b.Set("2MB")
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, ByteSize(2000000), b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeBytesize(t *testing.T) {
|
||||
var b ByteSize
|
||||
assert.Equal(t, "byte-size", b.Type())
|
||||
}
|
||||
20
vendor/github.com/go-openapi/runtime/hack/coverage
generated
vendored
Executable file
20
vendor/github.com/go-openapi/runtime/hack/coverage
generated
vendored
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
set -e -o pipefail
|
||||
|
||||
# Run test coverage on each subdirectories and merge the coverage profile.
|
||||
echo "mode: ${GOCOVMODE-atomic}" > coverage.txt
|
||||
|
||||
# Standard go tooling behavior is to ignore dirs with leading underscores
|
||||
# skip generator for race detection and coverage
|
||||
for dir in $(go list ./...)
|
||||
do
|
||||
pth="$GOPATH/src/$dir"
|
||||
go test -race -timeout 20m -covermode=${GOCOVMODE-atomic} -coverprofile=${pth}/profile.out $dir
|
||||
if [ -f $pth/profile.out ]
|
||||
then
|
||||
cat $pth/profile.out | tail -n +2 >> coverage.txt
|
||||
rm $pth/profile.out
|
||||
fi
|
||||
done
|
||||
|
||||
go tool cover -func coverage.txt
|
||||
16
vendor/github.com/go-openapi/runtime/hack/gen-self-signed-certs.sh
generated
vendored
Executable file
16
vendor/github.com/go-openapi/runtime/hack/gen-self-signed-certs.sh
generated
vendored
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
|
||||
# generate CA
|
||||
openssl genrsa -out myCA.key 4096
|
||||
openssl req -x509 -new -key myCA.key -out myCA.crt -days 730 -subj /CN="Go Swagger"
|
||||
|
||||
# generate server cert and key
|
||||
openssl genrsa -out mycert1.key 4096
|
||||
openssl req -new -out mycert1.req -key mycert1.key -subj /CN="goswagger.local"
|
||||
openssl x509 -req -in mycert1.req -out mycert1.crt -CAkey myCA.key -CA myCA.crt -days 365 -CAcreateserial -CAserial serial
|
||||
|
||||
# generate client cert, key and bundle
|
||||
openssl genrsa -out myclient.key 4096
|
||||
openssl req -new -key myclient.key -out myclient.csr
|
||||
openssl x509 -req -days 730 -in myclient.csr -out myclient.crt -CAkey myCA.key -CA myCA.crt -days 365 -CAcreateserial -CAserial serial
|
||||
openssl pkcs12 -export -clcerts -in myclient.crt -inkey myclient.key -out myclient.p12
|
||||
45
vendor/github.com/go-openapi/runtime/headers.go
generated
vendored
Normal file
45
vendor/github.com/go-openapi/runtime/headers.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"mime"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
)
|
||||
|
||||
// ContentType parses a content type header
|
||||
func ContentType(headers http.Header) (string, string, error) {
|
||||
ct := headers.Get(HeaderContentType)
|
||||
orig := ct
|
||||
if ct == "" {
|
||||
ct = DefaultMime
|
||||
}
|
||||
if ct == "" {
|
||||
return "", "", nil
|
||||
}
|
||||
|
||||
mt, opts, err := mime.ParseMediaType(ct)
|
||||
if err != nil {
|
||||
return "", "", errors.NewParseError(HeaderContentType, "header", orig, err)
|
||||
}
|
||||
|
||||
if cs, ok := opts[charsetKey]; ok {
|
||||
return mt, cs, nil
|
||||
}
|
||||
|
||||
return mt, "", nil
|
||||
}
|
||||
61
vendor/github.com/go-openapi/runtime/headers_test.go
generated
vendored
Normal file
61
vendor/github.com/go-openapi/runtime/headers_test.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"mime"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParseContentType(t *testing.T) {
|
||||
_, _, reason1 := mime.ParseMediaType("application(")
|
||||
_, _, reason2 := mime.ParseMediaType("application/json;char*")
|
||||
data := []struct {
|
||||
hdr, mt, cs string
|
||||
err *errors.ParseError
|
||||
}{
|
||||
{"application/json", "application/json", "", nil},
|
||||
{"text/html; charset=utf-8", "text/html", "utf-8", nil},
|
||||
{"text/html;charset=utf-8", "text/html", "utf-8", nil},
|
||||
{"", "application/octet-stream", "", nil},
|
||||
{"text/html; charset=utf-8", "text/html", "utf-8", nil},
|
||||
{"application(", "", "", errors.NewParseError("Content-Type", "header", "application(", reason1)},
|
||||
{"application/json;char*", "", "", errors.NewParseError("Content-Type", "header", "application/json;char*", reason2)},
|
||||
}
|
||||
|
||||
headers := http.Header(map[string][]string{})
|
||||
for _, v := range data {
|
||||
if v.hdr != "" {
|
||||
headers.Set("Content-Type", v.hdr)
|
||||
} else {
|
||||
headers.Del("Content-Type")
|
||||
}
|
||||
ct, cs, err := ContentType(headers)
|
||||
if v.err == nil {
|
||||
assert.NoError(t, err, "input: %q, err: %v", v.hdr, err)
|
||||
} else {
|
||||
assert.Error(t, err, "input: %q", v.hdr)
|
||||
assert.IsType(t, &errors.ParseError{}, err, "input: %q", v.hdr)
|
||||
assert.Equal(t, v.err.Error(), err.Error(), "input: %q", v.hdr)
|
||||
}
|
||||
assert.Equal(t, v.mt, ct, "input: %q", v.hdr)
|
||||
assert.Equal(t, v.cs, cs, "input: %q", v.hdr)
|
||||
}
|
||||
|
||||
}
|
||||
94
vendor/github.com/go-openapi/runtime/interfaces.go
generated
vendored
Normal file
94
vendor/github.com/go-openapi/runtime/interfaces.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"io"
|
||||
"mime/multipart"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// File represents an uploaded file.
|
||||
type File struct {
|
||||
Data multipart.File
|
||||
Header *multipart.FileHeader
|
||||
}
|
||||
|
||||
// OperationHandlerFunc an adapter for a function to the OperationHandler interface
|
||||
type OperationHandlerFunc func(interface{}) (interface{}, error)
|
||||
|
||||
// Handle implements the operation handler interface
|
||||
func (s OperationHandlerFunc) Handle(data interface{}) (interface{}, error) {
|
||||
return s(data)
|
||||
}
|
||||
|
||||
// OperationHandler a handler for a swagger operation
|
||||
type OperationHandler interface {
|
||||
Handle(interface{}) (interface{}, error)
|
||||
}
|
||||
|
||||
// ConsumerFunc represents a function that can be used as a consumer
|
||||
type ConsumerFunc func(io.Reader, interface{}) error
|
||||
|
||||
// Consume consumes the reader into the data parameter
|
||||
func (fn ConsumerFunc) Consume(reader io.Reader, data interface{}) error {
|
||||
return fn(reader, data)
|
||||
}
|
||||
|
||||
// Consumer implementations know how to bind the values on the provided interface to
|
||||
// data provided by the request body
|
||||
type Consumer interface {
|
||||
// Consume performs the binding of request values
|
||||
Consume(io.Reader, interface{}) error
|
||||
}
|
||||
|
||||
// ProducerFunc represents a function that can be used as a producer
|
||||
type ProducerFunc func(io.Writer, interface{}) error
|
||||
|
||||
// Produce produces the response for the provided data
|
||||
func (f ProducerFunc) Produce(writer io.Writer, data interface{}) error {
|
||||
return f(writer, data)
|
||||
}
|
||||
|
||||
// Producer implementations know how to turn the provided interface into a valid
|
||||
// HTTP response
|
||||
type Producer interface {
|
||||
// Produce writes to the http response
|
||||
Produce(io.Writer, interface{}) error
|
||||
}
|
||||
|
||||
// AuthenticatorFunc turns a function into an authenticator
|
||||
type AuthenticatorFunc func(interface{}) (bool, interface{}, error)
|
||||
|
||||
// Authenticate authenticates the request with the provided data
|
||||
func (f AuthenticatorFunc) Authenticate(params interface{}) (bool, interface{}, error) {
|
||||
return f(params)
|
||||
}
|
||||
|
||||
// Authenticator represents an authentication strategy
|
||||
// implementations of Authenticator know how to authenticate the
|
||||
// request data and translate that into a valid principal object or an error
|
||||
type Authenticator interface {
|
||||
Authenticate(interface{}) (bool, interface{}, error)
|
||||
}
|
||||
|
||||
// Validatable types implementing this interface allow customizing their validation
|
||||
// this will be used instead of the reflective valditation based on the spec document.
|
||||
// the implementations are assumed to have been generated by the swagger tool so they should
|
||||
// contain all the validations obtained from the spec
|
||||
type Validatable interface {
|
||||
Validate(strfmt.Registry) error
|
||||
}
|
||||
811
vendor/github.com/go-openapi/runtime/internal/testing/data.go
generated
vendored
Normal file
811
vendor/github.com/go-openapi/runtime/internal/testing/data.go
generated
vendored
Normal file
@@ -0,0 +1,811 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package testing
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// PetStore20YAML yaml doc for swagger 2.0 pet store
|
||||
const PetStore20YAML = `swagger: '2.0'
|
||||
info:
|
||||
version: '1.0.0'
|
||||
title: Swagger Petstore
|
||||
description: A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification
|
||||
termsOfService: http://helloreverb.com/terms/
|
||||
contact:
|
||||
name: Swagger API team
|
||||
email: foo@example.com
|
||||
url: http://swagger.io
|
||||
license:
|
||||
name: MIT
|
||||
url: http://opensource.org/licenses/MIT
|
||||
host: petstore.swagger.wordnik.com
|
||||
basePath: /api
|
||||
schemes:
|
||||
- http
|
||||
consumes:
|
||||
- application/json
|
||||
produces:
|
||||
- application/json
|
||||
paths:
|
||||
/pets:
|
||||
get:
|
||||
description: Returns all pets from the system that the user has access to
|
||||
operationId: findPets
|
||||
produces:
|
||||
- application/json
|
||||
- application/xml
|
||||
- text/xml
|
||||
- text/html
|
||||
parameters:
|
||||
- name: tags
|
||||
in: query
|
||||
description: tags to filter by
|
||||
required: false
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
collectionFormat: csv
|
||||
- name: limit
|
||||
in: query
|
||||
description: maximum number of results to return
|
||||
required: false
|
||||
type: integer
|
||||
format: int32
|
||||
responses:
|
||||
'200':
|
||||
description: pet response
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/pet'
|
||||
default:
|
||||
description: unexpected error
|
||||
schema:
|
||||
$ref: '#/definitions/errorModel'
|
||||
post:
|
||||
description: Creates a new pet in the store. Duplicates are allowed
|
||||
operationId: addPet
|
||||
produces:
|
||||
- application/json
|
||||
parameters:
|
||||
- name: pet
|
||||
in: body
|
||||
description: Pet to add to the store
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/newPet'
|
||||
responses:
|
||||
'200':
|
||||
description: pet response
|
||||
schema:
|
||||
$ref: '#/definitions/pet'
|
||||
default:
|
||||
description: unexpected error
|
||||
schema:
|
||||
$ref: '#/definitions/errorModel'
|
||||
/pets/{id}:
|
||||
get:
|
||||
description: Returns a user based on a single ID, if the user does not have access to the pet
|
||||
operationId: findPetById
|
||||
produces:
|
||||
- application/json
|
||||
- application/xml
|
||||
- text/xml
|
||||
- text/html
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
description: ID of pet to fetch
|
||||
required: true
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
'200':
|
||||
description: pet response
|
||||
schema:
|
||||
$ref: '#/definitions/pet'
|
||||
default:
|
||||
description: unexpected error
|
||||
schema:
|
||||
$ref: '#/definitions/errorModel'
|
||||
delete:
|
||||
description: deletes a single pet based on the ID supplied
|
||||
operationId: deletePet
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
description: ID of pet to delete
|
||||
required: true
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
'204':
|
||||
description: pet deleted
|
||||
default:
|
||||
description: unexpected error
|
||||
schema:
|
||||
$ref: '#/definitions/errorModel'
|
||||
definitions:
|
||||
pet:
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
name:
|
||||
type: string
|
||||
tag:
|
||||
type: string
|
||||
newPet:
|
||||
allOf:
|
||||
- $ref: '#/definitions/pet'
|
||||
- required:
|
||||
- name
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
name:
|
||||
type: string
|
||||
errorModel:
|
||||
required:
|
||||
- code
|
||||
- message
|
||||
properties:
|
||||
code:
|
||||
type: integer
|
||||
format: int32
|
||||
message:
|
||||
type: string
|
||||
`
|
||||
|
||||
// PetStore20 json doc for swagger 2.0 pet store
|
||||
const PetStore20 = `{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"version": "1.0.0",
|
||||
"title": "Swagger Petstore",
|
||||
"contact": {
|
||||
"name": "Wordnik API Team",
|
||||
"url": "http://developer.wordnik.com"
|
||||
},
|
||||
"license": {
|
||||
"name": "Creative Commons 4.0 International",
|
||||
"url": "http://creativecommons.org/licenses/by/4.0/"
|
||||
}
|
||||
},
|
||||
"host": "petstore.swagger.wordnik.com",
|
||||
"basePath": "/api",
|
||||
"schemes": [
|
||||
"http"
|
||||
],
|
||||
"paths": {
|
||||
"/pets": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"basic": []
|
||||
}
|
||||
],
|
||||
"tags": [ "Pet Operations" ],
|
||||
"operationId": "getAllPets",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "status",
|
||||
"in": "query",
|
||||
"description": "The status to filter by",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "limit",
|
||||
"in": "query",
|
||||
"description": "The maximum number of results to return",
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
],
|
||||
"summary": "Finds all pets in the system",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Pet response",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Pet"
|
||||
}
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "Unexpected error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"basic": []
|
||||
}
|
||||
],
|
||||
"tags": [ "Pet Operations" ],
|
||||
"operationId": "createPet",
|
||||
"summary": "Creates a new pet",
|
||||
"consumes": ["application/x-yaml"],
|
||||
"produces": ["application/x-yaml"],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "pet",
|
||||
"in": "body",
|
||||
"description": "The Pet to create",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/newPet"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Created Pet response",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Pet"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "Unexpected error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/pets/{id}": {
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"apiKey": []
|
||||
}
|
||||
],
|
||||
"description": "Deletes the Pet by id",
|
||||
"operationId": "deletePet",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"description": "ID of pet to delete",
|
||||
"required": true,
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "pet deleted"
|
||||
},
|
||||
"default": {
|
||||
"description": "unexpected error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"get": {
|
||||
"tags": [ "Pet Operations" ],
|
||||
"operationId": "getPetById",
|
||||
"summary": "Finds the pet by id",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Pet response",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Pet"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "Unexpected error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"description": "ID of pet",
|
||||
"required": true,
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"Category": {
|
||||
"id": "Category",
|
||||
"properties": {
|
||||
"id": {
|
||||
"format": "int64",
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Pet": {
|
||||
"id": "Pet",
|
||||
"properties": {
|
||||
"category": {
|
||||
"$ref": "#/definitions/Category"
|
||||
},
|
||||
"id": {
|
||||
"description": "unique identifier for the pet",
|
||||
"format": "int64",
|
||||
"maximum": 100.0,
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"photoUrls": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"status": {
|
||||
"description": "pet status in the store",
|
||||
"enum": [
|
||||
"available",
|
||||
"pending",
|
||||
"sold"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"tags": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/Tag"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"name"
|
||||
]
|
||||
},
|
||||
"newPet": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Pet"
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"name"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"Tag": {
|
||||
"id": "Tag",
|
||||
"properties": {
|
||||
"id": {
|
||||
"format": "int64",
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Error": {
|
||||
"required": [
|
||||
"code",
|
||||
"message"
|
||||
],
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"consumes": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml",
|
||||
"text/plain",
|
||||
"text/html"
|
||||
],
|
||||
"securityDefinitions": {
|
||||
"basic": {
|
||||
"type": "basic"
|
||||
},
|
||||
"apiKey": {
|
||||
"type": "apiKey",
|
||||
"in": "header",
|
||||
"name": "X-API-KEY"
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
// RootPetStore20 json doc for swagger 2.0 pet store at /
|
||||
const RootPetStore20 = `{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"version": "1.0.0",
|
||||
"title": "Swagger Petstore",
|
||||
"contact": {
|
||||
"name": "Wordnik API Team",
|
||||
"url": "http://developer.wordnik.com"
|
||||
},
|
||||
"license": {
|
||||
"name": "Creative Commons 4.0 International",
|
||||
"url": "http://creativecommons.org/licenses/by/4.0/"
|
||||
}
|
||||
},
|
||||
"host": "petstore.swagger.wordnik.com",
|
||||
"basePath": "/",
|
||||
"schemes": [
|
||||
"http"
|
||||
],
|
||||
"paths": {
|
||||
"/pets": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"basic": []
|
||||
}
|
||||
],
|
||||
"tags": [ "Pet Operations" ],
|
||||
"operationId": "getAllPets",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "status",
|
||||
"in": "query",
|
||||
"description": "The status to filter by",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"summary": "Finds all pets in the system",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Pet response",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Pet"
|
||||
}
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "Unexpected error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"basic": []
|
||||
}
|
||||
],
|
||||
"tags": [ "Pet Operations" ],
|
||||
"operationId": "createPet",
|
||||
"summary": "Creates a new pet",
|
||||
"consumes": ["application/x-yaml"],
|
||||
"produces": ["application/x-yaml"],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "pet",
|
||||
"in": "body",
|
||||
"description": "The Pet to create",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/newPet"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Created Pet response",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Pet"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "Unexpected error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/pets/{id}": {
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"apiKey": []
|
||||
}
|
||||
],
|
||||
"description": "Deletes the Pet by id",
|
||||
"operationId": "deletePet",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"description": "ID of pet to delete",
|
||||
"required": true,
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "pet deleted"
|
||||
},
|
||||
"default": {
|
||||
"description": "unexpected error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"get": {
|
||||
"tags": [ "Pet Operations" ],
|
||||
"operationId": "getPetById",
|
||||
"summary": "Finds the pet by id",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Pet response",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Pet"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "Unexpected error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"description": "ID of pet",
|
||||
"required": true,
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"Category": {
|
||||
"id": "Category",
|
||||
"properties": {
|
||||
"id": {
|
||||
"format": "int64",
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Pet": {
|
||||
"id": "Pet",
|
||||
"properties": {
|
||||
"category": {
|
||||
"$ref": "#/definitions/Category"
|
||||
},
|
||||
"id": {
|
||||
"description": "unique identifier for the pet",
|
||||
"format": "int64",
|
||||
"maximum": 100.0,
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"photoUrls": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"status": {
|
||||
"description": "pet status in the store",
|
||||
"enum": [
|
||||
"available",
|
||||
"pending",
|
||||
"sold"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"tags": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/Tag"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"name"
|
||||
]
|
||||
},
|
||||
"newPet": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Pet"
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"name"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"Tag": {
|
||||
"id": "Tag",
|
||||
"properties": {
|
||||
"id": {
|
||||
"format": "int64",
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Error": {
|
||||
"required": [
|
||||
"code",
|
||||
"message"
|
||||
],
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"consumes": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml",
|
||||
"text/plain",
|
||||
"text/html"
|
||||
],
|
||||
"securityDefinitions": {
|
||||
"basic": {
|
||||
"type": "basic"
|
||||
},
|
||||
"apiKey": {
|
||||
"type": "apiKey",
|
||||
"in": "header",
|
||||
"name": "X-API-KEY"
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
// PetStoreJSONMessage json raw message for Petstore20
|
||||
var PetStoreJSONMessage = json.RawMessage([]byte(PetStore20))
|
||||
|
||||
// RootPetStoreJSONMessage json raw message for Petstore20
|
||||
var RootPetStoreJSONMessage = json.RawMessage([]byte(RootPetStore20))
|
||||
|
||||
// InvalidJSON invalid swagger 2.0 spec in JSON
|
||||
const InvalidJSON = `{
|
||||
"apiVersion": "1.0.0",
|
||||
"apis": [
|
||||
{
|
||||
"description": "Operations about pets",
|
||||
"path": "/pet"
|
||||
},
|
||||
{
|
||||
"description": "Operations about user",
|
||||
"path": "/user"
|
||||
},
|
||||
{
|
||||
"description": "Operations about store",
|
||||
"path": "/store"
|
||||
}
|
||||
],
|
||||
"authorizations": {
|
||||
"oauth2": {
|
||||
"grantTypes": {
|
||||
"authorization_code": {
|
||||
"tokenEndpoint": {
|
||||
"tokenName": "auth_code",
|
||||
"url": "http://petstore.swagger.wordnik.com/oauth/token"
|
||||
},
|
||||
"tokenRequestEndpoint": {
|
||||
"clientIdName": "client_id",
|
||||
"clientSecretName": "client_secret",
|
||||
"url": "http://petstore.swagger.wordnik.com/oauth/requestToken"
|
||||
}
|
||||
},
|
||||
"implicit": {
|
||||
"loginEndpoint": {
|
||||
"url": "http://petstore.swagger.wordnik.com/oauth/dialog"
|
||||
},
|
||||
"tokenName": "access_token"
|
||||
}
|
||||
},
|
||||
"scopes": [
|
||||
{
|
||||
"description": "Modify pets in your account",
|
||||
"scope": "write:pets"
|
||||
},
|
||||
{
|
||||
"description": "Read your pets",
|
||||
"scope": "read:pets"
|
||||
},
|
||||
{
|
||||
"description": "Anything (testing)",
|
||||
"scope": "test:anything"
|
||||
}
|
||||
],
|
||||
"type": "oauth2"
|
||||
}
|
||||
},
|
||||
"info": {
|
||||
"contact": "apiteam@wordnik.com",
|
||||
"description": "This is a sample server Petstore server. You can find out more about Swagger \n at <a href=\"http://swagger.wordnik.com\">http://swagger.wordnik.com</a> or on irc.freenode.net, #swagger. For this sample,\n you can use the api key \"special-key\" to test the authorization filters",
|
||||
"license": "Apache 2.0",
|
||||
"licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.html",
|
||||
"termsOfServiceUrl": "http://helloreverb.com/terms/",
|
||||
"title": "Swagger Sample App"
|
||||
},
|
||||
"swaggerVersion": "1.2"
|
||||
}
|
||||
`
|
||||
|
||||
// InvalidJSONMessage json raw message for invalid json
|
||||
var InvalidJSONMessage = json.RawMessage([]byte(InvalidJSON))
|
||||
147
vendor/github.com/go-openapi/runtime/internal/testing/petstore/api.go
generated
vendored
Normal file
147
vendor/github.com/go-openapi/runtime/internal/testing/petstore/api.go
generated
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package petstore
|
||||
|
||||
import (
|
||||
"io"
|
||||
gotest "testing"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/go-openapi/runtime"
|
||||
testingutil "github.com/go-openapi/runtime/internal/testing"
|
||||
"github.com/go-openapi/runtime/middleware/untyped"
|
||||
"github.com/go-openapi/runtime/security"
|
||||
"github.com/go-openapi/runtime/yamlpc"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// NewAPI registers a stub api for the pet store
|
||||
func NewAPI(t gotest.TB) (*loads.Document, *untyped.API) {
|
||||
spec, err := loads.Analyzed(testingutil.PetStoreJSONMessage, "")
|
||||
assert.NoError(t, err)
|
||||
api := untyped.NewAPI(spec)
|
||||
|
||||
api.RegisterConsumer("application/json", runtime.JSONConsumer())
|
||||
api.RegisterProducer("application/json", runtime.JSONProducer())
|
||||
api.RegisterConsumer("application/xml", new(stubConsumer))
|
||||
api.RegisterProducer("application/xml", new(stubProducer))
|
||||
api.RegisterProducer("text/plain", new(stubProducer))
|
||||
api.RegisterProducer("text/html", new(stubProducer))
|
||||
api.RegisterConsumer("application/x-yaml", yamlpc.YAMLConsumer())
|
||||
api.RegisterProducer("application/x-yaml", yamlpc.YAMLProducer())
|
||||
|
||||
api.RegisterAuth("basic", security.BasicAuth(func(username, password string) (interface{}, error) {
|
||||
if username == "admin" && password == "admin" {
|
||||
return "admin", nil
|
||||
}
|
||||
return nil, errors.Unauthenticated("basic")
|
||||
}))
|
||||
api.RegisterAuth("apiKey", security.APIKeyAuth("X-API-KEY", "header", func(token string) (interface{}, error) {
|
||||
if token == "token123" {
|
||||
return "admin", nil
|
||||
}
|
||||
return nil, errors.Unauthenticated("token")
|
||||
}))
|
||||
api.RegisterOperation("get", "/pets", new(stubOperationHandler))
|
||||
api.RegisterOperation("post", "/pets", new(stubOperationHandler))
|
||||
api.RegisterOperation("delete", "/pets/{id}", new(stubOperationHandler))
|
||||
api.RegisterOperation("get", "/pets/{id}", new(stubOperationHandler))
|
||||
|
||||
api.Models["pet"] = func() interface{} { return new(Pet) }
|
||||
api.Models["newPet"] = func() interface{} { return new(Pet) }
|
||||
api.Models["tag"] = func() interface{} { return new(Tag) }
|
||||
|
||||
return spec, api
|
||||
}
|
||||
|
||||
// NewRootAPI registers a stub api for the pet store
|
||||
func NewRootAPI(t gotest.TB) (*loads.Document, *untyped.API) {
|
||||
spec, err := loads.Analyzed(testingutil.RootPetStoreJSONMessage, "")
|
||||
assert.NoError(t, err)
|
||||
api := untyped.NewAPI(spec)
|
||||
|
||||
api.RegisterConsumer("application/json", runtime.JSONConsumer())
|
||||
api.RegisterProducer("application/json", runtime.JSONProducer())
|
||||
api.RegisterConsumer("application/xml", new(stubConsumer))
|
||||
api.RegisterProducer("application/xml", new(stubProducer))
|
||||
api.RegisterProducer("text/plain", new(stubProducer))
|
||||
api.RegisterProducer("text/html", new(stubProducer))
|
||||
api.RegisterConsumer("application/x-yaml", yamlpc.YAMLConsumer())
|
||||
api.RegisterProducer("application/x-yaml", yamlpc.YAMLProducer())
|
||||
|
||||
api.RegisterAuth("basic", security.BasicAuth(func(username, password string) (interface{}, error) {
|
||||
if username == "admin" && password == "admin" {
|
||||
return "admin", nil
|
||||
}
|
||||
return nil, errors.Unauthenticated("basic")
|
||||
}))
|
||||
api.RegisterAuth("apiKey", security.APIKeyAuth("X-API-KEY", "header", func(token string) (interface{}, error) {
|
||||
if token == "token123" {
|
||||
return "admin", nil
|
||||
}
|
||||
return nil, errors.Unauthenticated("token")
|
||||
}))
|
||||
api.RegisterOperation("get", "/pets", new(stubOperationHandler))
|
||||
api.RegisterOperation("post", "/pets", new(stubOperationHandler))
|
||||
api.RegisterOperation("delete", "/pets/{id}", new(stubOperationHandler))
|
||||
api.RegisterOperation("get", "/pets/{id}", new(stubOperationHandler))
|
||||
|
||||
api.Models["pet"] = func() interface{} { return new(Pet) }
|
||||
api.Models["newPet"] = func() interface{} { return new(Pet) }
|
||||
api.Models["tag"] = func() interface{} { return new(Tag) }
|
||||
|
||||
return spec, api
|
||||
}
|
||||
|
||||
// Tag the tag model
|
||||
type Tag struct {
|
||||
ID int64
|
||||
Name string
|
||||
}
|
||||
|
||||
// Pet the pet model
|
||||
type Pet struct {
|
||||
ID int64
|
||||
Name string
|
||||
PhotoURLs []string
|
||||
Status string
|
||||
Tags []Tag
|
||||
}
|
||||
|
||||
type stubConsumer struct {
|
||||
}
|
||||
|
||||
func (s *stubConsumer) Consume(_ io.Reader, _ interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type stubProducer struct {
|
||||
}
|
||||
|
||||
func (s *stubProducer) Produce(_ io.Writer, _ interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type stubOperationHandler struct {
|
||||
}
|
||||
|
||||
func (s *stubOperationHandler) ParameterModel() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *stubOperationHandler) Handle(params interface{}) (interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
351
vendor/github.com/go-openapi/runtime/internal/testing/simplepetstore/api.go
generated
vendored
Normal file
351
vendor/github.com/go-openapi/runtime/internal/testing/simplepetstore/api.go
generated
vendored
Normal file
@@ -0,0 +1,351 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package simplepetstore
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/go-openapi/runtime/middleware/untyped"
|
||||
)
|
||||
|
||||
// NewPetstore creates a new petstore api handler
|
||||
func NewPetstore() (http.Handler, error) {
|
||||
spec, err := loads.Analyzed(json.RawMessage([]byte(swaggerJSON)), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
api := untyped.NewAPI(spec)
|
||||
|
||||
api.RegisterOperation("get", "/pets", getAllPets)
|
||||
api.RegisterOperation("post", "/pets", createPet)
|
||||
api.RegisterOperation("delete", "/pets/{id}", deletePet)
|
||||
api.RegisterOperation("get", "/pets/{id}", getPetByID)
|
||||
|
||||
return middleware.Serve(spec, api), nil
|
||||
}
|
||||
|
||||
var getAllPets = runtime.OperationHandlerFunc(func(data interface{}) (interface{}, error) {
|
||||
return pets, nil
|
||||
})
|
||||
|
||||
var createPet = runtime.OperationHandlerFunc(func(data interface{}) (interface{}, error) {
|
||||
body := data.(map[string]interface{})["pet"].(map[string]interface{})
|
||||
return addPet(Pet{
|
||||
Name: body["name"].(string),
|
||||
Status: body["status"].(string),
|
||||
}), nil
|
||||
})
|
||||
|
||||
var deletePet = runtime.OperationHandlerFunc(func(data interface{}) (interface{}, error) {
|
||||
id := data.(map[string]interface{})["id"].(int64)
|
||||
removePet(id)
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
var getPetByID = runtime.OperationHandlerFunc(func(data interface{}) (interface{}, error) {
|
||||
id := data.(map[string]interface{})["id"].(int64)
|
||||
return petByID(id)
|
||||
})
|
||||
|
||||
// Tag the tag model
|
||||
type Tag struct {
|
||||
ID int64
|
||||
Name string
|
||||
}
|
||||
|
||||
// Pet the pet model
|
||||
type Pet struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
PhotoURLs []string `json:"photoUrls,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Tags []Tag `json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
var pets = []Pet{
|
||||
{1, "Dog", []string{}, "available", nil},
|
||||
{2, "Cat", []string{}, "pending", nil},
|
||||
}
|
||||
|
||||
var petsLock = &sync.Mutex{}
|
||||
var lastPetID int64 = 2
|
||||
|
||||
func newPetID() int64 {
|
||||
return atomic.AddInt64(&lastPetID, 1)
|
||||
}
|
||||
|
||||
func addPet(pet Pet) Pet {
|
||||
petsLock.Lock()
|
||||
defer petsLock.Unlock()
|
||||
pet.ID = newPetID()
|
||||
pets = append(pets, pet)
|
||||
return pet
|
||||
}
|
||||
|
||||
func removePet(id int64) {
|
||||
petsLock.Lock()
|
||||
defer petsLock.Unlock()
|
||||
var newPets []Pet
|
||||
for _, pet := range pets {
|
||||
if pet.ID != id {
|
||||
newPets = append(newPets, pet)
|
||||
}
|
||||
}
|
||||
pets = newPets
|
||||
}
|
||||
|
||||
func petByID(id int64) (*Pet, error) {
|
||||
for _, pet := range pets {
|
||||
if pet.ID == id {
|
||||
return &pet, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.NotFound("not found: pet %d", id)
|
||||
}
|
||||
|
||||
var swaggerJSON = `{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"version": "1.0.0",
|
||||
"title": "Swagger Petstore",
|
||||
"description": "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification",
|
||||
"termsOfService": "http://helloreverb.com/terms/",
|
||||
"contact": {
|
||||
"name": "Wordnik API Team"
|
||||
},
|
||||
"license": {
|
||||
"name": "MIT"
|
||||
}
|
||||
},
|
||||
"host": "localhost:8344",
|
||||
"basePath": "/api",
|
||||
"schemes": [
|
||||
"http"
|
||||
],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"paths": {
|
||||
"/pets": {
|
||||
"get": {
|
||||
"description": "Returns all pets from the system that the user has access to",
|
||||
"operationId": "findPets",
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml",
|
||||
"text/xml",
|
||||
"text/html"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "tags",
|
||||
"in": "query",
|
||||
"description": "tags to filter by",
|
||||
"required": false,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"collectionFormat": "csv"
|
||||
},
|
||||
{
|
||||
"name": "limit",
|
||||
"in": "query",
|
||||
"description": "maximum number of results to return",
|
||||
"required": false,
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "pet response",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/pet"
|
||||
}
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "unexpected error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/errorModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"description": "Creates a new pet in the store. Duplicates are allowed",
|
||||
"operationId": "addPet",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "pet",
|
||||
"in": "body",
|
||||
"description": "Pet to add to the store",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/petInput"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "pet response",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/pet"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "unexpected error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/errorModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/pets/{id}": {
|
||||
"get": {
|
||||
"description": "Returns a user based on a single ID, if the user does not have access to the pet",
|
||||
"operationId": "findPetById",
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml",
|
||||
"text/xml",
|
||||
"text/html"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"description": "ID of pet to fetch",
|
||||
"required": true,
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "pet response",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/pet"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "unexpected error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/errorModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"description": "deletes a single pet based on the ID supplied",
|
||||
"operationId": "deletePet",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"description": "ID of pet to delete",
|
||||
"required": true,
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "pet deleted"
|
||||
},
|
||||
"default": {
|
||||
"description": "unexpected error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/errorModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"pet": {
|
||||
"required": [
|
||||
"name",
|
||||
"status"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"petInput": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/pet"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"errorModel": {
|
||||
"required": [
|
||||
"code",
|
||||
"message"
|
||||
],
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
81
vendor/github.com/go-openapi/runtime/internal/testing/simplepetstore/api_test.go
generated
vendored
Normal file
81
vendor/github.com/go-openapi/runtime/internal/testing/simplepetstore/api_test.go
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package simplepetstore
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSimplePetstoreSpec(t *testing.T) {
|
||||
handler, _ := NewPetstore()
|
||||
// Serves swagger spec document
|
||||
r, _ := runtime.JSONRequest("GET", "/swagger.json", nil)
|
||||
rw := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rw, r)
|
||||
assert.Equal(t, 200, rw.Code)
|
||||
assert.Equal(t, swaggerJSON, rw.Body.String())
|
||||
}
|
||||
|
||||
func TestSimplePetstoreAllPets(t *testing.T) {
|
||||
handler, _ := NewPetstore()
|
||||
// Serves swagger spec document
|
||||
r, _ := runtime.JSONRequest("GET", "/api/pets", nil)
|
||||
rw := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rw, r)
|
||||
assert.Equal(t, 200, rw.Code)
|
||||
assert.Equal(t, "[{\"id\":1,\"name\":\"Dog\",\"status\":\"available\"},{\"id\":2,\"name\":\"Cat\",\"status\":\"pending\"}]\n", rw.Body.String())
|
||||
}
|
||||
|
||||
func TestSimplePetstorePetByID(t *testing.T) {
|
||||
handler, _ := NewPetstore()
|
||||
|
||||
// Serves swagger spec document
|
||||
r, _ := runtime.JSONRequest("GET", "/api/pets/1", nil)
|
||||
rw := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rw, r)
|
||||
assert.Equal(t, 200, rw.Code)
|
||||
assert.Equal(t, "{\"id\":1,\"name\":\"Dog\",\"status\":\"available\"}\n", rw.Body.String())
|
||||
}
|
||||
|
||||
func TestSimplePetstoreAddPet(t *testing.T) {
|
||||
handler, _ := NewPetstore()
|
||||
// Serves swagger spec document
|
||||
r, _ := runtime.JSONRequest("POST", "/api/pets", bytes.NewBuffer([]byte(`{"name": "Fish","status": "available"}`)))
|
||||
rw := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rw, r)
|
||||
assert.Equal(t, 200, rw.Code)
|
||||
assert.Equal(t, "{\"id\":3,\"name\":\"Fish\",\"status\":\"available\"}\n", rw.Body.String())
|
||||
}
|
||||
|
||||
func TestSimplePetstoreDeletePet(t *testing.T) {
|
||||
handler, _ := NewPetstore()
|
||||
// Serves swagger spec document
|
||||
r, _ := runtime.JSONRequest("DELETE", "/api/pets/1", nil)
|
||||
rw := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rw, r)
|
||||
assert.Equal(t, 204, rw.Code)
|
||||
assert.Equal(t, "", rw.Body.String())
|
||||
|
||||
r, _ = runtime.JSONRequest("GET", "/api/pets/1", nil)
|
||||
rw = httptest.NewRecorder()
|
||||
handler.ServeHTTP(rw, r)
|
||||
assert.Equal(t, 404, rw.Code)
|
||||
assert.Equal(t, "{\"code\":404,\"message\":\"not found: pet 1\"}", rw.Body.String())
|
||||
}
|
||||
37
vendor/github.com/go-openapi/runtime/json.go
generated
vendored
Normal file
37
vendor/github.com/go-openapi/runtime/json.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
)
|
||||
|
||||
// JSONConsumer creates a new JSON consumer
|
||||
func JSONConsumer() Consumer {
|
||||
return ConsumerFunc(func(reader io.Reader, data interface{}) error {
|
||||
dec := json.NewDecoder(reader)
|
||||
dec.UseNumber() // preserve number formats
|
||||
return dec.Decode(data)
|
||||
})
|
||||
}
|
||||
|
||||
// JSONProducer creates a new JSON producer
|
||||
func JSONProducer() Producer {
|
||||
return ProducerFunc(func(writer io.Writer, data interface{}) error {
|
||||
enc := json.NewEncoder(writer)
|
||||
return enc.Encode(data)
|
||||
})
|
||||
}
|
||||
62
vendor/github.com/go-openapi/runtime/json_test.go
generated
vendored
Normal file
62
vendor/github.com/go-openapi/runtime/json_test.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var consProdJSON = `{"name":"Somebody","id":1}`
|
||||
|
||||
type eofRdr struct {
|
||||
}
|
||||
|
||||
func (r *eofRdr) Read(d []byte) (int, error) {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
func TestJSONConsumer(t *testing.T) {
|
||||
cons := JSONConsumer()
|
||||
var data struct {
|
||||
Name string
|
||||
ID int
|
||||
}
|
||||
err := cons.Consume(bytes.NewBuffer([]byte(consProdJSON)), &data)
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, "Somebody", data.Name)
|
||||
assert.Equal(t, 1, data.ID)
|
||||
|
||||
err = cons.Consume(new(eofRdr), &data)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONProducer(t *testing.T) {
|
||||
prod := JSONProducer()
|
||||
data := struct {
|
||||
Name string `json:"name"`
|
||||
ID int `json:"id"`
|
||||
}{Name: "Somebody", ID: 1}
|
||||
|
||||
rw := httptest.NewRecorder()
|
||||
err := prod.Produce(rw, data)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, consProdJSON+"\n", rw.Body.String())
|
||||
}
|
||||
101
vendor/github.com/go-openapi/runtime/middleware/body_test.go
generated
vendored
Normal file
101
vendor/github.com/go-openapi/runtime/middleware/body_test.go
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/internal/testing/petstore"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type eofReader struct {
|
||||
}
|
||||
|
||||
func (r *eofReader) Read(b []byte) (int, error) {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
func (r *eofReader) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type rbn func(*http.Request, *MatchedRoute) error
|
||||
|
||||
func (b rbn) BindRequest(r *http.Request, rr *MatchedRoute) error {
|
||||
return b(r, rr)
|
||||
}
|
||||
|
||||
func TestBindRequest_BodyValidation(t *testing.T) {
|
||||
spec, api := petstore.NewAPI(t)
|
||||
ctx := NewContext(spec, api, nil)
|
||||
api.DefaultConsumes = runtime.JSONMime
|
||||
ctx.router = DefaultRouter(spec, ctx.api)
|
||||
|
||||
req, err := http.NewRequest("GET", path.Join(spec.BasePath(), "/pets"), new(eofReader))
|
||||
if assert.NoError(t, err) {
|
||||
req.Header.Set("Content-Type", runtime.JSONMime)
|
||||
|
||||
ri, ok := ctx.RouteInfo(req)
|
||||
if assert.True(t, ok) {
|
||||
|
||||
err := ctx.BindValidRequest(req, ri, rbn(func(r *http.Request, rr *MatchedRoute) error {
|
||||
defer r.Body.Close()
|
||||
var data interface{}
|
||||
err := runtime.JSONConsumer().Consume(r.Body, &data)
|
||||
_ = data
|
||||
return err
|
||||
}))
|
||||
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, io.EOF, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBindRequest_DeleteNoBody(t *testing.T) {
|
||||
spec, api := petstore.NewAPI(t)
|
||||
ctx := NewContext(spec, api, nil)
|
||||
api.DefaultConsumes = runtime.JSONMime
|
||||
ctx.router = DefaultRouter(spec, ctx.api)
|
||||
|
||||
req, err := http.NewRequest("DELETE", path.Join(spec.BasePath(), "/pets/123"), new(eofReader))
|
||||
if assert.NoError(t, err) {
|
||||
req.Header.Set("Accept", "*/*")
|
||||
|
||||
ri, ok := ctx.RouteInfo(req)
|
||||
if assert.True(t, ok) {
|
||||
|
||||
err := ctx.BindValidRequest(req, ri, rbn(func(r *http.Request, rr *MatchedRoute) error {
|
||||
return nil
|
||||
}))
|
||||
|
||||
assert.NoError(t, err)
|
||||
//assert.Equal(t, io.EOF, err)
|
||||
}
|
||||
}
|
||||
|
||||
req, err = http.NewRequest("DELETE", path.Join(spec.BasePath(), "/pets/123"), new(eofReader))
|
||||
if assert.NoError(t, err) {
|
||||
req.Header.Set("Accept", "*/*")
|
||||
req.Header.Set("Content-Type", runtime.JSONMime)
|
||||
req.ContentLength = 1
|
||||
|
||||
ri, ok := ctx.RouteInfo(req)
|
||||
if assert.True(t, ok) {
|
||||
|
||||
err := ctx.BindValidRequest(req, ri, rbn(func(r *http.Request, rr *MatchedRoute) error {
|
||||
defer r.Body.Close()
|
||||
var data interface{}
|
||||
err := runtime.JSONConsumer().Consume(r.Body, &data)
|
||||
_ = data
|
||||
return err
|
||||
}))
|
||||
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, io.EOF, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
526
vendor/github.com/go-openapi/runtime/middleware/context.go
generated
vendored
Normal file
526
vendor/github.com/go-openapi/runtime/middleware/context.go
generated
vendored
Normal file
@@ -0,0 +1,526 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/go-openapi/analysis"
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/middleware/untyped"
|
||||
"github.com/go-openapi/runtime/security"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/gorilla/context"
|
||||
)
|
||||
|
||||
// Debug when true turns on verbose logging
|
||||
var Debug = os.Getenv("SWAGGER_DEBUG") != "" || os.Getenv("DEBUG") != ""
|
||||
|
||||
func debugLog(format string, args ...interface{}) {
|
||||
if Debug {
|
||||
log.Printf(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
// A Builder can create middlewares
|
||||
type Builder func(http.Handler) http.Handler
|
||||
|
||||
// PassthroughBuilder returns the handler, aka the builder identity function
|
||||
func PassthroughBuilder(handler http.Handler) http.Handler { return handler }
|
||||
|
||||
// RequestBinder is an interface for types to implement
|
||||
// when they want to be able to bind from a request
|
||||
type RequestBinder interface {
|
||||
BindRequest(*http.Request, *MatchedRoute) error
|
||||
}
|
||||
|
||||
// Responder is an interface for types to implement
|
||||
// when they want to be considered for writing HTTP responses
|
||||
type Responder interface {
|
||||
WriteResponse(http.ResponseWriter, runtime.Producer)
|
||||
}
|
||||
|
||||
// ResponderFunc wraps a func as a Responder interface
|
||||
type ResponderFunc func(http.ResponseWriter, runtime.Producer)
|
||||
|
||||
// WriteResponse writes to the response
|
||||
func (fn ResponderFunc) WriteResponse(rw http.ResponseWriter, pr runtime.Producer) {
|
||||
fn(rw, pr)
|
||||
}
|
||||
|
||||
// Context is a type safe wrapper around an untyped request context
|
||||
// used throughout to store request context with the gorilla context module
|
||||
type Context struct {
|
||||
spec *loads.Document
|
||||
analyzer *analysis.Spec
|
||||
api RoutableAPI
|
||||
router Router
|
||||
formats strfmt.Registry
|
||||
}
|
||||
|
||||
type routableUntypedAPI struct {
|
||||
api *untyped.API
|
||||
hlock *sync.Mutex
|
||||
handlers map[string]map[string]http.Handler
|
||||
defaultConsumes string
|
||||
defaultProduces string
|
||||
}
|
||||
|
||||
func newRoutableUntypedAPI(spec *loads.Document, api *untyped.API, context *Context) *routableUntypedAPI {
|
||||
var handlers map[string]map[string]http.Handler
|
||||
if spec == nil || api == nil {
|
||||
return nil
|
||||
}
|
||||
analyzer := analysis.New(spec.Spec())
|
||||
for method, hls := range analyzer.Operations() {
|
||||
um := strings.ToUpper(method)
|
||||
for path, op := range hls {
|
||||
schemes := analyzer.SecurityDefinitionsFor(op)
|
||||
|
||||
if oh, ok := api.OperationHandlerFor(method, path); ok {
|
||||
if handlers == nil {
|
||||
handlers = make(map[string]map[string]http.Handler)
|
||||
}
|
||||
if b, ok := handlers[um]; !ok || b == nil {
|
||||
handlers[um] = make(map[string]http.Handler)
|
||||
}
|
||||
|
||||
var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// lookup route info in the context
|
||||
route, _ := context.RouteInfo(r)
|
||||
|
||||
// bind and validate the request using reflection
|
||||
bound, validation := context.BindAndValidate(r, route)
|
||||
if validation != nil {
|
||||
context.Respond(w, r, route.Produces, route, validation)
|
||||
return
|
||||
}
|
||||
|
||||
// actually handle the request
|
||||
result, err := oh.Handle(bound)
|
||||
if err != nil {
|
||||
// respond with failure
|
||||
context.Respond(w, r, route.Produces, route, err)
|
||||
return
|
||||
}
|
||||
|
||||
// respond with success
|
||||
context.Respond(w, r, route.Produces, route, result)
|
||||
})
|
||||
|
||||
if len(schemes) > 0 {
|
||||
handler = newSecureAPI(context, handler)
|
||||
}
|
||||
handlers[um][path] = handler
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &routableUntypedAPI{
|
||||
api: api,
|
||||
hlock: new(sync.Mutex),
|
||||
handlers: handlers,
|
||||
defaultProduces: api.DefaultProduces,
|
||||
defaultConsumes: api.DefaultConsumes,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *routableUntypedAPI) HandlerFor(method, path string) (http.Handler, bool) {
|
||||
r.hlock.Lock()
|
||||
paths, ok := r.handlers[strings.ToUpper(method)]
|
||||
if !ok {
|
||||
r.hlock.Unlock()
|
||||
return nil, false
|
||||
}
|
||||
handler, ok := paths[path]
|
||||
r.hlock.Unlock()
|
||||
return handler, ok
|
||||
}
|
||||
func (r *routableUntypedAPI) ServeErrorFor(operationID string) func(http.ResponseWriter, *http.Request, error) {
|
||||
return r.api.ServeError
|
||||
}
|
||||
func (r *routableUntypedAPI) ConsumersFor(mediaTypes []string) map[string]runtime.Consumer {
|
||||
return r.api.ConsumersFor(mediaTypes)
|
||||
}
|
||||
func (r *routableUntypedAPI) ProducersFor(mediaTypes []string) map[string]runtime.Producer {
|
||||
return r.api.ProducersFor(mediaTypes)
|
||||
}
|
||||
func (r *routableUntypedAPI) AuthenticatorsFor(schemes map[string]spec.SecurityScheme) map[string]runtime.Authenticator {
|
||||
return r.api.AuthenticatorsFor(schemes)
|
||||
}
|
||||
func (r *routableUntypedAPI) Formats() strfmt.Registry {
|
||||
return r.api.Formats()
|
||||
}
|
||||
|
||||
func (r *routableUntypedAPI) DefaultProduces() string {
|
||||
return r.defaultProduces
|
||||
}
|
||||
|
||||
func (r *routableUntypedAPI) DefaultConsumes() string {
|
||||
return r.defaultConsumes
|
||||
}
|
||||
|
||||
// NewRoutableContext creates a new context for a routable API
|
||||
func NewRoutableContext(spec *loads.Document, routableAPI RoutableAPI, routes Router) *Context {
|
||||
var an *analysis.Spec
|
||||
if spec != nil {
|
||||
an = analysis.New(spec.Spec())
|
||||
}
|
||||
ctx := &Context{spec: spec, api: routableAPI, analyzer: an}
|
||||
return ctx
|
||||
}
|
||||
|
||||
// NewContext creates a new context wrapper
|
||||
func NewContext(spec *loads.Document, api *untyped.API, routes Router) *Context {
|
||||
var an *analysis.Spec
|
||||
if spec != nil {
|
||||
an = analysis.New(spec.Spec())
|
||||
}
|
||||
ctx := &Context{spec: spec, analyzer: an}
|
||||
ctx.api = newRoutableUntypedAPI(spec, api, ctx)
|
||||
return ctx
|
||||
}
|
||||
|
||||
// Serve serves the specified spec with the specified api registrations as a http.Handler
|
||||
func Serve(spec *loads.Document, api *untyped.API) http.Handler {
|
||||
return ServeWithBuilder(spec, api, PassthroughBuilder)
|
||||
}
|
||||
|
||||
// ServeWithBuilder serves the specified spec with the specified api registrations as a http.Handler that is decorated
|
||||
// by the Builder
|
||||
func ServeWithBuilder(spec *loads.Document, api *untyped.API, builder Builder) http.Handler {
|
||||
context := NewContext(spec, api, nil)
|
||||
return context.APIHandler(builder)
|
||||
}
|
||||
|
||||
type contextKey int8
|
||||
|
||||
const (
|
||||
_ contextKey = iota
|
||||
ctxContentType
|
||||
ctxResponseFormat
|
||||
ctxMatchedRoute
|
||||
ctxAllowedMethods
|
||||
ctxBoundParams
|
||||
ctxSecurityPrincipal
|
||||
ctxSecurityScopes
|
||||
|
||||
ctxConsumer
|
||||
)
|
||||
|
||||
type contentTypeValue struct {
|
||||
MediaType string
|
||||
Charset string
|
||||
}
|
||||
|
||||
// BasePath returns the base path for this API
|
||||
func (c *Context) BasePath() string {
|
||||
return c.spec.BasePath()
|
||||
}
|
||||
|
||||
// RequiredProduces returns the accepted content types for responses
|
||||
func (c *Context) RequiredProduces() []string {
|
||||
return c.analyzer.RequiredProduces()
|
||||
}
|
||||
|
||||
// BindValidRequest binds a params object to a request but only when the request is valid
|
||||
// if the request is not valid an error will be returned
|
||||
func (c *Context) BindValidRequest(request *http.Request, route *MatchedRoute, binder RequestBinder) error {
|
||||
var res []error
|
||||
|
||||
requestContentType := "*/*"
|
||||
// check and validate content type, select consumer
|
||||
if runtime.HasBody(request) {
|
||||
ct, _, err := runtime.ContentType(request.Header)
|
||||
if err != nil {
|
||||
res = append(res, err)
|
||||
} else {
|
||||
if err := validateContentType(route.Consumes, ct); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
if len(res) == 0 {
|
||||
cons, ok := route.Consumers[ct]
|
||||
if !ok {
|
||||
res = append(res, errors.New(500, "no consumer registered for %s", ct))
|
||||
} else {
|
||||
route.Consumer = cons
|
||||
requestContentType = ct
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check and validate the response format
|
||||
if len(res) == 0 && runtime.HasBody(request) {
|
||||
if str := NegotiateContentType(request, route.Produces, requestContentType); str == "" {
|
||||
res = append(res, errors.InvalidResponseFormat(request.Header.Get(runtime.HeaderAccept), route.Produces))
|
||||
}
|
||||
}
|
||||
|
||||
// now bind the request with the provided binder
|
||||
// it's assumed the binder will also validate the request and return an error if the
|
||||
// request is invalid
|
||||
if binder != nil && len(res) == 0 {
|
||||
if err := binder.BindRequest(request, route); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContentType gets the parsed value of a content type
|
||||
func (c *Context) ContentType(request *http.Request) (string, string, error) {
|
||||
if v, ok := context.GetOk(request, ctxContentType); ok {
|
||||
if val, ok := v.(*contentTypeValue); ok {
|
||||
return val.MediaType, val.Charset, nil
|
||||
}
|
||||
}
|
||||
|
||||
mt, cs, err := runtime.ContentType(request.Header)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
context.Set(request, ctxContentType, &contentTypeValue{mt, cs})
|
||||
return mt, cs, nil
|
||||
}
|
||||
|
||||
// LookupRoute looks a route up and returns true when it is found
|
||||
func (c *Context) LookupRoute(request *http.Request) (*MatchedRoute, bool) {
|
||||
if route, ok := c.router.Lookup(request.Method, request.URL.EscapedPath()); ok {
|
||||
return route, ok
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// RouteInfo tries to match a route for this request
|
||||
func (c *Context) RouteInfo(request *http.Request) (*MatchedRoute, bool) {
|
||||
if v, ok := context.GetOk(request, ctxMatchedRoute); ok {
|
||||
if val, ok := v.(*MatchedRoute); ok {
|
||||
return val, ok
|
||||
}
|
||||
}
|
||||
|
||||
if route, ok := c.LookupRoute(request); ok {
|
||||
context.Set(request, ctxMatchedRoute, route)
|
||||
return route, ok
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// ResponseFormat negotiates the response content type
|
||||
func (c *Context) ResponseFormat(r *http.Request, offers []string) string {
|
||||
if v, ok := context.GetOk(r, ctxResponseFormat); ok {
|
||||
if val, ok := v.(string); ok {
|
||||
return val
|
||||
}
|
||||
}
|
||||
|
||||
format := NegotiateContentType(r, offers, "")
|
||||
if format != "" {
|
||||
context.Set(r, ctxResponseFormat, format)
|
||||
}
|
||||
return format
|
||||
}
|
||||
|
||||
// AllowedMethods gets the allowed methods for the path of this request
|
||||
func (c *Context) AllowedMethods(request *http.Request) []string {
|
||||
return c.router.OtherMethods(request.Method, request.URL.EscapedPath())
|
||||
}
|
||||
|
||||
// Authorize authorizes the request
|
||||
func (c *Context) Authorize(request *http.Request, route *MatchedRoute) (interface{}, error) {
|
||||
if route == nil || len(route.Authenticators) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if v, ok := context.GetOk(request, ctxSecurityPrincipal); ok {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
var lastError error
|
||||
for scheme, authenticator := range route.Authenticators {
|
||||
applies, usr, err := authenticator.Authenticate(&security.ScopedAuthRequest{
|
||||
Request: request,
|
||||
RequiredScopes: route.Scopes[scheme],
|
||||
})
|
||||
if !applies || err != nil || usr == nil {
|
||||
if err != nil {
|
||||
lastError = err
|
||||
}
|
||||
continue
|
||||
}
|
||||
context.Set(request, ctxSecurityPrincipal, usr)
|
||||
context.Set(request, ctxSecurityScopes, route.Scopes[scheme])
|
||||
return usr, nil
|
||||
}
|
||||
|
||||
if lastError != nil {
|
||||
return nil, lastError
|
||||
}
|
||||
|
||||
return nil, errors.Unauthenticated("invalid credentials")
|
||||
}
|
||||
|
||||
// BindAndValidate binds and validates the request
|
||||
func (c *Context) BindAndValidate(request *http.Request, matched *MatchedRoute) (interface{}, error) {
|
||||
if v, ok := context.GetOk(request, ctxBoundParams); ok {
|
||||
if val, ok := v.(*validation); ok {
|
||||
debugLog("got cached validation (valid: %t)", len(val.result) == 0)
|
||||
if len(val.result) > 0 {
|
||||
return val.bound, errors.CompositeValidationError(val.result...)
|
||||
}
|
||||
return val.bound, nil
|
||||
}
|
||||
}
|
||||
result := validateRequest(c, request, matched)
|
||||
if result != nil {
|
||||
context.Set(request, ctxBoundParams, result)
|
||||
}
|
||||
if len(result.result) > 0 {
|
||||
return result.bound, errors.CompositeValidationError(result.result...)
|
||||
}
|
||||
debugLog("no validation errors found")
|
||||
return result.bound, nil
|
||||
}
|
||||
|
||||
// NotFound the default not found responder for when no route has been matched yet
|
||||
func (c *Context) NotFound(rw http.ResponseWriter, r *http.Request) {
|
||||
c.Respond(rw, r, []string{c.api.DefaultProduces()}, nil, errors.NotFound("not found"))
|
||||
}
|
||||
|
||||
// Respond renders the response after doing some content negotiation
|
||||
func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []string, route *MatchedRoute, data interface{}) {
|
||||
offers := []string{}
|
||||
for _, mt := range produces {
|
||||
if mt != c.api.DefaultProduces() {
|
||||
offers = append(offers, mt)
|
||||
}
|
||||
}
|
||||
// the default producer is last so more specific producers take precedence
|
||||
offers = append(offers, c.api.DefaultProduces())
|
||||
|
||||
format := c.ResponseFormat(r, offers)
|
||||
rw.Header().Set(runtime.HeaderContentType, format)
|
||||
|
||||
if resp, ok := data.(Responder); ok {
|
||||
producers := route.Producers
|
||||
prod, ok := producers[format]
|
||||
if !ok {
|
||||
prods := c.api.ProducersFor([]string{c.api.DefaultProduces()})
|
||||
pr, ok := prods[c.api.DefaultProduces()]
|
||||
if !ok {
|
||||
panic(errors.New(http.StatusInternalServerError, "can't find a producer for "+format))
|
||||
}
|
||||
prod = pr
|
||||
}
|
||||
resp.WriteResponse(rw, prod)
|
||||
return
|
||||
}
|
||||
|
||||
if err, ok := data.(error); ok {
|
||||
if format == "" {
|
||||
rw.Header().Set(runtime.HeaderContentType, runtime.JSONMime)
|
||||
}
|
||||
if route == nil || route.Operation == nil {
|
||||
c.api.ServeErrorFor("")(rw, r, err)
|
||||
return
|
||||
}
|
||||
c.api.ServeErrorFor(route.Operation.ID)(rw, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
if route == nil || route.Operation == nil {
|
||||
rw.WriteHeader(200)
|
||||
if r.Method == "HEAD" {
|
||||
return
|
||||
}
|
||||
producers := c.api.ProducersFor(offers)
|
||||
prod, ok := producers[format]
|
||||
if !ok {
|
||||
panic(errors.New(http.StatusInternalServerError, "can't find a producer for "+format))
|
||||
}
|
||||
if err := prod.Produce(rw, data); err != nil {
|
||||
panic(err) // let the recovery middleware deal with this
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if _, code, ok := route.Operation.SuccessResponse(); ok {
|
||||
rw.WriteHeader(code)
|
||||
if code == 204 || r.Method == "HEAD" {
|
||||
return
|
||||
}
|
||||
|
||||
producers := route.Producers
|
||||
prod, ok := producers[format]
|
||||
if !ok {
|
||||
if !ok {
|
||||
prods := c.api.ProducersFor([]string{c.api.DefaultProduces()})
|
||||
pr, ok := prods[c.api.DefaultProduces()]
|
||||
if !ok {
|
||||
panic(errors.New(http.StatusInternalServerError, "can't find a producer for "+format))
|
||||
}
|
||||
prod = pr
|
||||
}
|
||||
}
|
||||
if err := prod.Produce(rw, data); err != nil {
|
||||
panic(err) // let the recovery middleware deal with this
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
c.api.ServeErrorFor(route.Operation.ID)(rw, r, errors.New(http.StatusInternalServerError, "can't produce response"))
|
||||
}
|
||||
|
||||
// APIHandler returns a handler to serve the API, this includes a swagger spec, router and the contract defined in the swagger spec
|
||||
func (c *Context) APIHandler(builder Builder) http.Handler {
|
||||
b := builder
|
||||
if b == nil {
|
||||
b = PassthroughBuilder
|
||||
}
|
||||
|
||||
var title string
|
||||
sp := c.spec.Spec()
|
||||
if sp != nil && sp.Info != nil && sp.Info.Title != "" {
|
||||
title = sp.Info.Title
|
||||
}
|
||||
|
||||
redocOpts := RedocOpts{
|
||||
BasePath: c.BasePath(),
|
||||
Title: title,
|
||||
}
|
||||
|
||||
return Spec("", c.spec.Raw(), Redoc(redocOpts, c.RoutesHandler(builder)))
|
||||
}
|
||||
|
||||
// RoutesHandler returns a handler to serve the API, just the routes and the contract defined in the swagger spec
|
||||
func (c *Context) RoutesHandler(builder Builder) http.Handler {
|
||||
b := builder
|
||||
if b == nil {
|
||||
b = PassthroughBuilder
|
||||
}
|
||||
return NewRouter(c, b(NewOperationExecutor(c)))
|
||||
}
|
||||
395
vendor/github.com/go-openapi/runtime/middleware/context_test.go
generated
vendored
Normal file
395
vendor/github.com/go-openapi/runtime/middleware/context_test.go
generated
vendored
Normal file
@@ -0,0 +1,395 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/go-openapi/loads/fmts"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/internal/testing/petstore"
|
||||
"github.com/go-openapi/runtime/middleware/untyped"
|
||||
"github.com/gorilla/context"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type stubOperationHandler struct {
|
||||
}
|
||||
|
||||
func (s *stubOperationHandler) ParameterModel() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *stubOperationHandler) Handle(params interface{}) (interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type testBinder struct {
|
||||
}
|
||||
|
||||
func (t *testBinder) BindRequest(r *http.Request, m *MatchedRoute) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
loads.AddLoader(fmts.YAMLMatcher, fmts.YAMLDoc)
|
||||
}
|
||||
|
||||
func TestContentType_Issue264(t *testing.T) {
|
||||
swspec, err := loads.Spec("../fixtures/bugs/264/swagger.yml")
|
||||
if assert.NoError(t, err) {
|
||||
api := untyped.NewAPI(swspec)
|
||||
api.RegisterConsumer("application/json", runtime.JSONConsumer())
|
||||
api.RegisterProducer("application/json", runtime.JSONProducer())
|
||||
api.RegisterOperation("delete", "/key/{id}", new(stubOperationHandler))
|
||||
|
||||
handler := Serve(swspec, api)
|
||||
request, _ := http.NewRequest("DELETE", "/key/1", nil)
|
||||
recorder := httptest.NewRecorder()
|
||||
handler.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServe(t *testing.T) {
|
||||
spec, api := petstore.NewAPI(t)
|
||||
handler := Serve(spec, api)
|
||||
|
||||
// serve spec document
|
||||
request, _ := http.NewRequest("GET", "http://localhost:8080/swagger.json", nil)
|
||||
request.Header.Add("Content-Type", runtime.JSONMime)
|
||||
request.Header.Add("Accept", runtime.JSONMime)
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
handler.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
|
||||
request, _ = http.NewRequest("GET", "http://localhost:8080/swagger-ui", nil)
|
||||
recorder = httptest.NewRecorder()
|
||||
|
||||
handler.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, 404, recorder.Code)
|
||||
}
|
||||
|
||||
func TestContextAuthorize(t *testing.T) {
|
||||
spec, api := petstore.NewAPI(t)
|
||||
ctx := NewContext(spec, api, nil)
|
||||
ctx.router = DefaultRouter(spec, ctx.api)
|
||||
|
||||
request, _ := runtime.JSONRequest("GET", "/api/pets", nil)
|
||||
|
||||
v, ok := context.GetOk(request, ctxSecurityPrincipal)
|
||||
assert.False(t, ok)
|
||||
assert.Nil(t, v)
|
||||
|
||||
ri, ok := ctx.RouteInfo(request)
|
||||
assert.True(t, ok)
|
||||
p, err := ctx.Authorize(request, ri)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, p)
|
||||
|
||||
v, ok = context.GetOk(request, ctxSecurityPrincipal)
|
||||
assert.False(t, ok)
|
||||
assert.Nil(t, v)
|
||||
|
||||
request.SetBasicAuth("wrong", "wrong")
|
||||
p, err = ctx.Authorize(request, ri)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, p)
|
||||
|
||||
v, ok = context.GetOk(request, ctxSecurityPrincipal)
|
||||
assert.False(t, ok)
|
||||
assert.Nil(t, v)
|
||||
|
||||
request.SetBasicAuth("admin", "admin")
|
||||
p, err = ctx.Authorize(request, ri)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "admin", p)
|
||||
|
||||
v, ok = context.GetOk(request, ctxSecurityPrincipal)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "admin", v)
|
||||
|
||||
request.SetBasicAuth("doesn't matter", "doesn't")
|
||||
pp, rr := ctx.Authorize(request, ri)
|
||||
assert.Equal(t, p, pp)
|
||||
assert.Equal(t, err, rr)
|
||||
}
|
||||
|
||||
func TestContextNegotiateContentType(t *testing.T) {
|
||||
spec, api := petstore.NewAPI(t)
|
||||
ctx := NewContext(spec, api, nil)
|
||||
ctx.router = DefaultRouter(spec, ctx.api)
|
||||
|
||||
request, _ := http.NewRequest("POST", "/api/pets", nil)
|
||||
// request.Header.Add("Accept", "*/*")
|
||||
request.Header.Add("content-type", "text/html")
|
||||
|
||||
v, ok := context.GetOk(request, ctxBoundParams)
|
||||
assert.False(t, ok)
|
||||
assert.Nil(t, v)
|
||||
|
||||
ri, _ := ctx.RouteInfo(request)
|
||||
|
||||
res := NegotiateContentType(request, ri.Produces, "")
|
||||
assert.Equal(t, "", res)
|
||||
|
||||
res2 := NegotiateContentType(request, ri.Produces, "text/plain")
|
||||
assert.Equal(t, "text/plain", res2)
|
||||
}
|
||||
|
||||
func TestContextBindAndValidate(t *testing.T) {
|
||||
spec, api := petstore.NewAPI(t)
|
||||
ctx := NewContext(spec, api, nil)
|
||||
ctx.router = DefaultRouter(spec, ctx.api)
|
||||
|
||||
request, _ := http.NewRequest("POST", "/api/pets", nil)
|
||||
request.Header.Add("Accept", "*/*")
|
||||
request.Header.Add("content-type", "text/html")
|
||||
request.ContentLength = 1
|
||||
|
||||
v, ok := context.GetOk(request, ctxBoundParams)
|
||||
assert.False(t, ok)
|
||||
assert.Nil(t, v)
|
||||
|
||||
ri, _ := ctx.RouteInfo(request)
|
||||
data, result := ctx.BindAndValidate(request, ri) // this requires a much more thorough test
|
||||
assert.NotNil(t, data)
|
||||
assert.NotNil(t, result)
|
||||
|
||||
v, ok = context.GetOk(request, ctxBoundParams)
|
||||
assert.True(t, ok)
|
||||
assert.NotNil(t, v)
|
||||
|
||||
dd, rr := ctx.BindAndValidate(request, ri)
|
||||
assert.Equal(t, data, dd)
|
||||
assert.Equal(t, result, rr)
|
||||
}
|
||||
|
||||
func TestContextRender(t *testing.T) {
|
||||
ct := runtime.JSONMime
|
||||
spec, api := petstore.NewAPI(t)
|
||||
|
||||
assert.NotNil(t, spec)
|
||||
assert.NotNil(t, api)
|
||||
ctx := NewContext(spec, api, nil)
|
||||
ctx.router = DefaultRouter(spec, ctx.api)
|
||||
|
||||
request, _ := http.NewRequest("GET", "pets", nil)
|
||||
request.Header.Set(runtime.HeaderAccept, ct)
|
||||
ri, _ := ctx.RouteInfo(request)
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
ctx.Respond(recorder, request, []string{ct}, ri, map[string]interface{}{"name": "hello"})
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
assert.Equal(t, "{\"name\":\"hello\"}\n", recorder.Body.String())
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
ctx.Respond(recorder, request, []string{ct}, ri, errors.New("this went wrong"))
|
||||
assert.Equal(t, 500, recorder.Code)
|
||||
|
||||
// recorder = httptest.NewRecorder()
|
||||
// assert.Panics(t, func() { ctx.Respond(recorder, request, []string{ct}, ri, map[int]interface{}{1: "hello"}) })
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
request, _ = http.NewRequest("GET", "pets", nil)
|
||||
assert.Panics(t, func() { ctx.Respond(recorder, request, []string{}, ri, map[string]interface{}{"name": "hello"}) })
|
||||
|
||||
request, _ = http.NewRequest("GET", "/pets", nil)
|
||||
request.Header.Set(runtime.HeaderAccept, ct)
|
||||
ri, _ = ctx.RouteInfo(request)
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
ctx.Respond(recorder, request, []string{ct}, ri, map[string]interface{}{"name": "hello"})
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
assert.Equal(t, "{\"name\":\"hello\"}\n", recorder.Body.String())
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
ctx.Respond(recorder, request, []string{ct}, ri, errors.New("this went wrong"))
|
||||
assert.Equal(t, 500, recorder.Code)
|
||||
|
||||
// recorder = httptest.NewRecorder()
|
||||
// assert.Panics(t, func() { ctx.Respond(recorder, request, []string{ct}, ri, map[int]interface{}{1: "hello"}) })
|
||||
|
||||
// recorder = httptest.NewRecorder()
|
||||
// request, _ = http.NewRequest("GET", "/pets", nil)
|
||||
// assert.Panics(t, func() { ctx.Respond(recorder, request, []string{}, ri, map[string]interface{}{"name": "hello"}) })
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
request, _ = http.NewRequest("DELETE", "/api/pets/1", nil)
|
||||
ri, _ = ctx.RouteInfo(request)
|
||||
ctx.Respond(recorder, request, ri.Produces, ri, nil)
|
||||
assert.Equal(t, 204, recorder.Code)
|
||||
}
|
||||
|
||||
func TestContextValidResponseFormat(t *testing.T) {
|
||||
ct := "application/json"
|
||||
spec, api := petstore.NewAPI(t)
|
||||
ctx := NewContext(spec, api, nil)
|
||||
ctx.router = DefaultRouter(spec, ctx.api)
|
||||
|
||||
request, _ := http.NewRequest("GET", "http://localhost:8080", nil)
|
||||
request.Header.Set(runtime.HeaderAccept, ct)
|
||||
|
||||
// check there's nothing there
|
||||
cached, ok := context.GetOk(request, ctxResponseFormat)
|
||||
assert.False(t, ok)
|
||||
assert.Empty(t, cached)
|
||||
|
||||
// trigger the parse
|
||||
mt := ctx.ResponseFormat(request, []string{ct})
|
||||
assert.Equal(t, ct, mt)
|
||||
|
||||
// check it was cached
|
||||
cached, ok = context.GetOk(request, ctxResponseFormat)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, ct, cached)
|
||||
|
||||
// check if the cast works and fetch from cache too
|
||||
mt = ctx.ResponseFormat(request, []string{ct})
|
||||
assert.Equal(t, ct, mt)
|
||||
}
|
||||
|
||||
func TestContextInvalidResponseFormat(t *testing.T) {
|
||||
ct := "application/x-yaml"
|
||||
other := "application/sgml"
|
||||
spec, api := petstore.NewAPI(t)
|
||||
ctx := NewContext(spec, api, nil)
|
||||
ctx.router = DefaultRouter(spec, ctx.api)
|
||||
|
||||
request, _ := http.NewRequest("GET", "http://localhost:8080", nil)
|
||||
request.Header.Set(runtime.HeaderAccept, ct)
|
||||
|
||||
// check there's nothing there
|
||||
cached, ok := context.GetOk(request, ctxResponseFormat)
|
||||
assert.False(t, ok)
|
||||
assert.Empty(t, cached)
|
||||
|
||||
// trigger the parse
|
||||
mt := ctx.ResponseFormat(request, []string{other})
|
||||
assert.Empty(t, mt)
|
||||
|
||||
// check it was cached
|
||||
cached, ok = context.GetOk(request, ctxResponseFormat)
|
||||
assert.False(t, ok)
|
||||
assert.Empty(t, cached)
|
||||
|
||||
// check if the cast works and fetch from cache too
|
||||
mt = ctx.ResponseFormat(request, []string{other})
|
||||
assert.Empty(t, mt)
|
||||
}
|
||||
|
||||
func TestContextValidRoute(t *testing.T) {
|
||||
spec, api := petstore.NewAPI(t)
|
||||
ctx := NewContext(spec, api, nil)
|
||||
ctx.router = DefaultRouter(spec, ctx.api)
|
||||
|
||||
request, _ := http.NewRequest("GET", "/api/pets", nil)
|
||||
|
||||
// check there's nothing there
|
||||
_, ok := context.GetOk(request, ctxMatchedRoute)
|
||||
assert.False(t, ok)
|
||||
|
||||
matched, ok := ctx.RouteInfo(request)
|
||||
assert.True(t, ok)
|
||||
assert.NotNil(t, matched)
|
||||
|
||||
// check it was cached
|
||||
_, ok = context.GetOk(request, ctxMatchedRoute)
|
||||
assert.True(t, ok)
|
||||
|
||||
matched, ok = ctx.RouteInfo(request)
|
||||
assert.True(t, ok)
|
||||
assert.NotNil(t, matched)
|
||||
}
|
||||
|
||||
func TestContextInvalidRoute(t *testing.T) {
|
||||
spec, api := petstore.NewAPI(t)
|
||||
ctx := NewContext(spec, api, nil)
|
||||
ctx.router = DefaultRouter(spec, ctx.api)
|
||||
|
||||
request, _ := http.NewRequest("DELETE", "pets", nil)
|
||||
|
||||
// check there's nothing there
|
||||
_, ok := context.GetOk(request, ctxMatchedRoute)
|
||||
assert.False(t, ok)
|
||||
|
||||
matched, ok := ctx.RouteInfo(request)
|
||||
assert.False(t, ok)
|
||||
assert.Nil(t, matched)
|
||||
|
||||
// check it was cached
|
||||
_, ok = context.GetOk(request, ctxMatchedRoute)
|
||||
assert.False(t, ok)
|
||||
|
||||
matched, ok = ctx.RouteInfo(request)
|
||||
assert.False(t, ok)
|
||||
assert.Nil(t, matched)
|
||||
}
|
||||
|
||||
func TestContextValidContentType(t *testing.T) {
|
||||
ct := "application/json"
|
||||
ctx := NewContext(nil, nil, nil)
|
||||
|
||||
request, _ := http.NewRequest("GET", "http://localhost:8080", nil)
|
||||
request.Header.Set(runtime.HeaderContentType, ct)
|
||||
|
||||
// check there's nothing there
|
||||
_, ok := context.GetOk(request, ctxContentType)
|
||||
assert.False(t, ok)
|
||||
|
||||
// trigger the parse
|
||||
mt, _, err := ctx.ContentType(request)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, ct, mt)
|
||||
|
||||
// check it was cached
|
||||
_, ok = context.GetOk(request, ctxContentType)
|
||||
assert.True(t, ok)
|
||||
|
||||
// check if the cast works and fetch from cache too
|
||||
mt, _, err = ctx.ContentType(request)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, ct, mt)
|
||||
}
|
||||
|
||||
func TestContextInvalidContentType(t *testing.T) {
|
||||
ct := "application("
|
||||
ctx := NewContext(nil, nil, nil)
|
||||
|
||||
request, _ := http.NewRequest("GET", "http://localhost:8080", nil)
|
||||
request.Header.Set(runtime.HeaderContentType, ct)
|
||||
|
||||
// check there's nothing there
|
||||
_, ok := context.GetOk(request, ctxContentType)
|
||||
assert.False(t, ok)
|
||||
|
||||
// trigger the parse
|
||||
mt, _, err := ctx.ContentType(request)
|
||||
assert.Error(t, err)
|
||||
assert.Empty(t, mt)
|
||||
|
||||
// check it was not cached
|
||||
_, ok = context.GetOk(request, ctxContentType)
|
||||
assert.False(t, ok)
|
||||
|
||||
// check if the failure continues
|
||||
_, _, err = ctx.ContentType(request)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
19
vendor/github.com/go-openapi/runtime/middleware/denco/LICENSE
generated
vendored
Executable file
19
vendor/github.com/go-openapi/runtime/middleware/denco/LICENSE
generated
vendored
Executable file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2014 Naoya Inada <naoina@kuune.org>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
180
vendor/github.com/go-openapi/runtime/middleware/denco/README.md
generated
vendored
Executable file
180
vendor/github.com/go-openapi/runtime/middleware/denco/README.md
generated
vendored
Executable file
@@ -0,0 +1,180 @@
|
||||
# Denco [](https://travis-ci.org/naoina/denco)
|
||||
|
||||
The fast and flexible HTTP request router for [Go](http://golang.org).
|
||||
|
||||
Denco is based on Double-Array implementation of [Kocha-urlrouter](https://github.com/naoina/kocha-urlrouter).
|
||||
However, Denco is optimized and some features added.
|
||||
|
||||
## Features
|
||||
|
||||
* Fast (See [go-http-routing-benchmark](https://github.com/naoina/go-http-routing-benchmark))
|
||||
* [URL patterns](#url-patterns) (`/foo/:bar` and `/foo/*wildcard`)
|
||||
* Small (but enough) URL router API
|
||||
* HTTP request multiplexer like `http.ServeMux`
|
||||
|
||||
## Installation
|
||||
|
||||
go get -u github.com/go-openapi/runtime/middleware/denco
|
||||
|
||||
## Using as HTTP request multiplexer
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware/denco"
|
||||
)
|
||||
|
||||
func Index(w http.ResponseWriter, r *http.Request, params denco.Params) {
|
||||
fmt.Fprintf(w, "Welcome to Denco!\n")
|
||||
}
|
||||
|
||||
func User(w http.ResponseWriter, r *http.Request, params denco.Params) {
|
||||
fmt.Fprintf(w, "Hello %s!\n", params.Get("name"))
|
||||
}
|
||||
|
||||
func main() {
|
||||
mux := denco.NewMux()
|
||||
handler, err := mux.Build([]denco.Handler{
|
||||
mux.GET("/", Index),
|
||||
mux.GET("/user/:name", User),
|
||||
mux.POST("/user/:name", User),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
log.Fatal(http.ListenAndServe(":8080", handler))
|
||||
}
|
||||
```
|
||||
|
||||
## Using as URL router
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware/denco"
|
||||
)
|
||||
|
||||
type route struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func main() {
|
||||
router := denco.New()
|
||||
router.Build([]denco.Record{
|
||||
{"/", &route{"root"}},
|
||||
{"/user/:id", &route{"user"}},
|
||||
{"/user/:name/:id", &route{"username"}},
|
||||
{"/static/*filepath", &route{"static"}},
|
||||
})
|
||||
|
||||
data, params, found := router.Lookup("/")
|
||||
// print `&main.route{name:"root"}, denco.Params(nil), true`.
|
||||
fmt.Printf("%#v, %#v, %#v\n", data, params, found)
|
||||
|
||||
data, params, found = router.Lookup("/user/hoge")
|
||||
// print `&main.route{name:"user"}, denco.Params{denco.Param{Name:"id", Value:"hoge"}}, true`.
|
||||
fmt.Printf("%#v, %#v, %#v\n", data, params, found)
|
||||
|
||||
data, params, found = router.Lookup("/user/hoge/7")
|
||||
// print `&main.route{name:"username"}, denco.Params{denco.Param{Name:"name", Value:"hoge"}, denco.Param{Name:"id", Value:"7"}}, true`.
|
||||
fmt.Printf("%#v, %#v, %#v\n", data, params, found)
|
||||
|
||||
data, params, found = router.Lookup("/static/path/to/file")
|
||||
// print `&main.route{name:"static"}, denco.Params{denco.Param{Name:"filepath", Value:"path/to/file"}}, true`.
|
||||
fmt.Printf("%#v, %#v, %#v\n", data, params, found)
|
||||
}
|
||||
```
|
||||
|
||||
See [Godoc](http://godoc.org/github.com/go-openapi/runtime/middleware/denco) for more details.
|
||||
|
||||
## Getting the value of path parameter
|
||||
|
||||
You can get the value of path parameter by 2 ways.
|
||||
|
||||
1. Using [`denco.Params.Get`](http://godoc.org/github.com/go-openapi/runtime/middleware/denco#Params.Get) method
|
||||
2. Find by loop
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware/denco"
|
||||
)
|
||||
|
||||
func main() {
|
||||
router := denco.New()
|
||||
if err := router.Build([]denco.Record{
|
||||
{"/user/:name/:id", "route1"},
|
||||
}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// 1. Using denco.Params.Get method.
|
||||
_, params, _ := router.Lookup("/user/alice/1")
|
||||
name := params.Get("name")
|
||||
if name != "" {
|
||||
fmt.Printf("Hello %s.\n", name) // prints "Hello alice.".
|
||||
}
|
||||
|
||||
// 2. Find by loop.
|
||||
for _, param := range params {
|
||||
if param.Name == "name" {
|
||||
fmt.Printf("Hello %s.\n", name) // prints "Hello alice.".
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## URL patterns
|
||||
|
||||
Denco's route matching strategy is "most nearly matching".
|
||||
|
||||
When routes `/:name` and `/alice` have been built, URI `/alice` matches the route `/alice`, not `/:name`.
|
||||
Because URI `/alice` is more match with the route `/alice` than `/:name`.
|
||||
|
||||
For more example, when routes below have been built:
|
||||
|
||||
```
|
||||
/user/alice
|
||||
/user/:name
|
||||
/user/:name/:id
|
||||
/user/alice/:id
|
||||
/user/:id/bob
|
||||
```
|
||||
|
||||
Routes matching are:
|
||||
|
||||
```
|
||||
/user/alice => "/user/alice" (no match with "/user/:name")
|
||||
/user/bob => "/user/:name"
|
||||
/user/naoina/1 => "/user/:name/1"
|
||||
/user/alice/1 => "/user/alice/:id" (no match with "/user/:name/:id")
|
||||
/user/1/bob => "/user/:id/bob" (no match with "/user/:name/:id")
|
||||
/user/alice/bob => "/user/alice/:id" (no match with "/user/:name/:id" and "/user/:id/bob")
|
||||
```
|
||||
|
||||
## Limitation
|
||||
|
||||
Denco has some limitations below.
|
||||
|
||||
* Number of param records (such as `/:name`) must be less than 2^22
|
||||
* Number of elements of internal slice must be less than 2^22
|
||||
|
||||
## Benchmarks
|
||||
|
||||
cd $GOPATH/github.com/go-openapi/runtime/middleware/denco
|
||||
go test -bench . -benchmem
|
||||
|
||||
## License
|
||||
|
||||
Denco is licensed under the MIT License.
|
||||
452
vendor/github.com/go-openapi/runtime/middleware/denco/router.go
generated
vendored
Executable file
452
vendor/github.com/go-openapi/runtime/middleware/denco/router.go
generated
vendored
Executable file
@@ -0,0 +1,452 @@
|
||||
// Package denco provides fast URL router.
|
||||
package denco
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// ParamCharacter is a special character for path parameter.
|
||||
ParamCharacter = ':'
|
||||
|
||||
// WildcardCharacter is a special character for wildcard path parameter.
|
||||
WildcardCharacter = '*'
|
||||
|
||||
// TerminationCharacter is a special character for end of path.
|
||||
TerminationCharacter = '#'
|
||||
|
||||
// MaxSize is max size of records and internal slice.
|
||||
MaxSize = (1 << 22) - 1
|
||||
)
|
||||
|
||||
// Router represents a URL router.
|
||||
type Router struct {
|
||||
// SizeHint expects the maximum number of path parameters in records to Build.
|
||||
// SizeHint will be used to determine the capacity of the memory to allocate.
|
||||
// By default, SizeHint will be determined from given records to Build.
|
||||
SizeHint int
|
||||
|
||||
static map[string]interface{}
|
||||
param *doubleArray
|
||||
}
|
||||
|
||||
// New returns a new Router.
|
||||
func New() *Router {
|
||||
return &Router{
|
||||
SizeHint: -1,
|
||||
static: make(map[string]interface{}),
|
||||
param: newDoubleArray(),
|
||||
}
|
||||
}
|
||||
|
||||
// Lookup returns data and path parameters that associated with path.
|
||||
// params is a slice of the Param that arranged in the order in which parameters appeared.
|
||||
// e.g. when built routing path is "/path/to/:id/:name" and given path is "/path/to/1/alice". params order is [{"id": "1"}, {"name": "alice"}], not [{"name": "alice"}, {"id": "1"}].
|
||||
func (rt *Router) Lookup(path string) (data interface{}, params Params, found bool) {
|
||||
if data, found := rt.static[path]; found {
|
||||
return data, nil, true
|
||||
}
|
||||
if len(rt.param.node) == 1 {
|
||||
return nil, nil, false
|
||||
}
|
||||
nd, params, found := rt.param.lookup(path, make([]Param, 0, rt.SizeHint), 1)
|
||||
if !found {
|
||||
return nil, nil, false
|
||||
}
|
||||
for i := 0; i < len(params); i++ {
|
||||
params[i].Name = nd.paramNames[i]
|
||||
}
|
||||
return nd.data, params, true
|
||||
}
|
||||
|
||||
// Build builds URL router from records.
|
||||
func (rt *Router) Build(records []Record) error {
|
||||
statics, params := makeRecords(records)
|
||||
if len(params) > MaxSize {
|
||||
return fmt.Errorf("denco: too many records")
|
||||
}
|
||||
if rt.SizeHint < 0 {
|
||||
rt.SizeHint = 0
|
||||
for _, p := range params {
|
||||
size := 0
|
||||
for _, k := range p.Key {
|
||||
if k == ParamCharacter || k == WildcardCharacter {
|
||||
size++
|
||||
}
|
||||
}
|
||||
if size > rt.SizeHint {
|
||||
rt.SizeHint = size
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, r := range statics {
|
||||
rt.static[r.Key] = r.Value
|
||||
}
|
||||
if err := rt.param.build(params, 1, 0, make(map[int]struct{})); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Param represents name and value of path parameter.
|
||||
type Param struct {
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
|
||||
// Params represents the name and value of path parameters.
|
||||
type Params []Param
|
||||
|
||||
// Get gets the first value associated with the given name.
|
||||
// If there are no values associated with the key, Get returns "".
|
||||
func (ps Params) Get(name string) string {
|
||||
for _, p := range ps {
|
||||
if p.Name == name {
|
||||
return p.Value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type doubleArray struct {
|
||||
bc []baseCheck
|
||||
node []*node
|
||||
}
|
||||
|
||||
func newDoubleArray() *doubleArray {
|
||||
return &doubleArray{
|
||||
bc: []baseCheck{0},
|
||||
node: []*node{nil}, // A start index is adjusting to 1 because 0 will be used as a mark of non-existent node.
|
||||
}
|
||||
}
|
||||
|
||||
// baseCheck contains BASE, CHECK and Extra flags.
|
||||
// From the top, 22bits of BASE, 2bits of Extra flags and 8bits of CHECK.
|
||||
//
|
||||
// BASE (22bit) | Extra flags (2bit) | CHECK (8bit)
|
||||
// |----------------------|--|--------|
|
||||
// 32 10 8 0
|
||||
type baseCheck uint32
|
||||
|
||||
func (bc baseCheck) Base() int {
|
||||
return int(bc >> 10)
|
||||
}
|
||||
|
||||
func (bc *baseCheck) SetBase(base int) {
|
||||
*bc |= baseCheck(base) << 10
|
||||
}
|
||||
|
||||
func (bc baseCheck) Check() byte {
|
||||
return byte(bc)
|
||||
}
|
||||
|
||||
func (bc *baseCheck) SetCheck(check byte) {
|
||||
*bc |= baseCheck(check)
|
||||
}
|
||||
|
||||
func (bc baseCheck) IsEmpty() bool {
|
||||
return bc&0xfffffcff == 0
|
||||
}
|
||||
|
||||
func (bc baseCheck) IsSingleParam() bool {
|
||||
return bc¶mTypeSingle == paramTypeSingle
|
||||
}
|
||||
|
||||
func (bc baseCheck) IsWildcardParam() bool {
|
||||
return bc¶mTypeWildcard == paramTypeWildcard
|
||||
}
|
||||
|
||||
func (bc baseCheck) IsAnyParam() bool {
|
||||
return bc¶mTypeAny != 0
|
||||
}
|
||||
|
||||
func (bc *baseCheck) SetSingleParam() {
|
||||
*bc |= (1 << 8)
|
||||
}
|
||||
|
||||
func (bc *baseCheck) SetWildcardParam() {
|
||||
*bc |= (1 << 9)
|
||||
}
|
||||
|
||||
const (
|
||||
paramTypeSingle = 0x0100
|
||||
paramTypeWildcard = 0x0200
|
||||
paramTypeAny = 0x0300
|
||||
)
|
||||
|
||||
func (da *doubleArray) lookup(path string, params []Param, idx int) (*node, []Param, bool) {
|
||||
indices := make([]uint64, 0, 1)
|
||||
for i := 0; i < len(path); i++ {
|
||||
if da.bc[idx].IsAnyParam() {
|
||||
indices = append(indices, (uint64(i)<<32)|(uint64(idx)&0xffffffff))
|
||||
}
|
||||
c := path[i]
|
||||
if idx = nextIndex(da.bc[idx].Base(), c); idx >= len(da.bc) || da.bc[idx].Check() != c {
|
||||
goto BACKTRACKING
|
||||
}
|
||||
}
|
||||
if next := nextIndex(da.bc[idx].Base(), TerminationCharacter); next < len(da.bc) && da.bc[next].Check() == TerminationCharacter {
|
||||
return da.node[da.bc[next].Base()], params, true
|
||||
}
|
||||
BACKTRACKING:
|
||||
for j := len(indices) - 1; j >= 0; j-- {
|
||||
i, idx := int(indices[j]>>32), int(indices[j]&0xffffffff)
|
||||
if da.bc[idx].IsSingleParam() {
|
||||
idx := nextIndex(da.bc[idx].Base(), ParamCharacter)
|
||||
if idx >= len(da.bc) {
|
||||
break
|
||||
}
|
||||
next := NextSeparator(path, i)
|
||||
params := append(params, Param{Value: path[i:next]})
|
||||
if nd, params, found := da.lookup(path[next:], params, idx); found {
|
||||
return nd, params, true
|
||||
}
|
||||
}
|
||||
if da.bc[idx].IsWildcardParam() {
|
||||
idx := nextIndex(da.bc[idx].Base(), WildcardCharacter)
|
||||
params := append(params, Param{Value: path[i:]})
|
||||
return da.node[da.bc[idx].Base()], params, true
|
||||
}
|
||||
}
|
||||
return nil, nil, false
|
||||
}
|
||||
|
||||
// build builds double-array from records.
|
||||
func (da *doubleArray) build(srcs []*record, idx, depth int, usedBase map[int]struct{}) error {
|
||||
sort.Stable(recordSlice(srcs))
|
||||
base, siblings, leaf, err := da.arrange(srcs, idx, depth, usedBase)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if leaf != nil {
|
||||
nd, err := makeNode(leaf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
da.bc[idx].SetBase(len(da.node))
|
||||
da.node = append(da.node, nd)
|
||||
}
|
||||
for _, sib := range siblings {
|
||||
da.setCheck(nextIndex(base, sib.c), sib.c)
|
||||
}
|
||||
for _, sib := range siblings {
|
||||
records := srcs[sib.start:sib.end]
|
||||
switch sib.c {
|
||||
case ParamCharacter:
|
||||
for _, r := range records {
|
||||
next := NextSeparator(r.Key, depth+1)
|
||||
name := r.Key[depth+1 : next]
|
||||
r.paramNames = append(r.paramNames, name)
|
||||
r.Key = r.Key[next:]
|
||||
}
|
||||
da.bc[idx].SetSingleParam()
|
||||
if err := da.build(records, nextIndex(base, sib.c), 0, usedBase); err != nil {
|
||||
return err
|
||||
}
|
||||
case WildcardCharacter:
|
||||
r := records[0]
|
||||
name := r.Key[depth+1 : len(r.Key)-1]
|
||||
r.paramNames = append(r.paramNames, name)
|
||||
r.Key = ""
|
||||
da.bc[idx].SetWildcardParam()
|
||||
if err := da.build(records, nextIndex(base, sib.c), 0, usedBase); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if err := da.build(records, nextIndex(base, sib.c), depth+1, usedBase); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// setBase sets BASE.
|
||||
func (da *doubleArray) setBase(i, base int) {
|
||||
da.bc[i].SetBase(base)
|
||||
}
|
||||
|
||||
// setCheck sets CHECK.
|
||||
func (da *doubleArray) setCheck(i int, check byte) {
|
||||
da.bc[i].SetCheck(check)
|
||||
}
|
||||
|
||||
// findEmptyIndex returns an index of unused BASE/CHECK node.
|
||||
func (da *doubleArray) findEmptyIndex(start int) int {
|
||||
i := start
|
||||
for ; i < len(da.bc); i++ {
|
||||
if da.bc[i].IsEmpty() {
|
||||
break
|
||||
}
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// findBase returns good BASE.
|
||||
func (da *doubleArray) findBase(siblings []sibling, start int, usedBase map[int]struct{}) (base int) {
|
||||
for idx, firstChar := start+1, siblings[0].c; ; idx = da.findEmptyIndex(idx + 1) {
|
||||
base = nextIndex(idx, firstChar)
|
||||
if _, used := usedBase[base]; used {
|
||||
continue
|
||||
}
|
||||
i := 0
|
||||
for ; i < len(siblings); i++ {
|
||||
next := nextIndex(base, siblings[i].c)
|
||||
if len(da.bc) <= next {
|
||||
da.bc = append(da.bc, make([]baseCheck, next-len(da.bc)+1)...)
|
||||
}
|
||||
if !da.bc[next].IsEmpty() {
|
||||
break
|
||||
}
|
||||
}
|
||||
if i == len(siblings) {
|
||||
break
|
||||
}
|
||||
}
|
||||
usedBase[base] = struct{}{}
|
||||
return base
|
||||
}
|
||||
|
||||
func (da *doubleArray) arrange(records []*record, idx, depth int, usedBase map[int]struct{}) (base int, siblings []sibling, leaf *record, err error) {
|
||||
siblings, leaf, err = makeSiblings(records, depth)
|
||||
if err != nil {
|
||||
return -1, nil, nil, err
|
||||
}
|
||||
if len(siblings) < 1 {
|
||||
return -1, nil, leaf, nil
|
||||
}
|
||||
base = da.findBase(siblings, idx, usedBase)
|
||||
if base > MaxSize {
|
||||
return -1, nil, nil, fmt.Errorf("denco: too many elements of internal slice")
|
||||
}
|
||||
da.setBase(idx, base)
|
||||
return base, siblings, leaf, err
|
||||
}
|
||||
|
||||
// node represents a node of Double-Array.
|
||||
type node struct {
|
||||
data interface{}
|
||||
|
||||
// Names of path parameters.
|
||||
paramNames []string
|
||||
}
|
||||
|
||||
// makeNode returns a new node from record.
|
||||
func makeNode(r *record) (*node, error) {
|
||||
dups := make(map[string]bool)
|
||||
for _, name := range r.paramNames {
|
||||
if dups[name] {
|
||||
return nil, fmt.Errorf("denco: path parameter `%v' is duplicated in the key `%v'", name, r.Key)
|
||||
}
|
||||
dups[name] = true
|
||||
}
|
||||
return &node{data: r.Value, paramNames: r.paramNames}, nil
|
||||
}
|
||||
|
||||
// sibling represents an intermediate data of build for Double-Array.
|
||||
type sibling struct {
|
||||
// An index of start of duplicated characters.
|
||||
start int
|
||||
|
||||
// An index of end of duplicated characters.
|
||||
end int
|
||||
|
||||
// A character of sibling.
|
||||
c byte
|
||||
}
|
||||
|
||||
// nextIndex returns a next index of array of BASE/CHECK.
|
||||
func nextIndex(base int, c byte) int {
|
||||
return base ^ int(c)
|
||||
}
|
||||
|
||||
// makeSiblings returns slice of sibling.
|
||||
func makeSiblings(records []*record, depth int) (sib []sibling, leaf *record, err error) {
|
||||
var (
|
||||
pc byte
|
||||
n int
|
||||
)
|
||||
for i, r := range records {
|
||||
if len(r.Key) <= depth {
|
||||
leaf = r
|
||||
continue
|
||||
}
|
||||
c := r.Key[depth]
|
||||
switch {
|
||||
case pc < c:
|
||||
sib = append(sib, sibling{start: i, c: c})
|
||||
case pc == c:
|
||||
continue
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("denco: BUG: routing table hasn't been sorted")
|
||||
}
|
||||
if n > 0 {
|
||||
sib[n-1].end = i
|
||||
}
|
||||
pc = c
|
||||
n++
|
||||
}
|
||||
if n == 0 {
|
||||
return nil, leaf, nil
|
||||
}
|
||||
sib[n-1].end = len(records)
|
||||
return sib, leaf, nil
|
||||
}
|
||||
|
||||
// Record represents a record data for router construction.
|
||||
type Record struct {
|
||||
// Key for router construction.
|
||||
Key string
|
||||
|
||||
// Result value for Key.
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
// NewRecord returns a new Record.
|
||||
func NewRecord(key string, value interface{}) Record {
|
||||
return Record{
|
||||
Key: key,
|
||||
Value: value,
|
||||
}
|
||||
}
|
||||
|
||||
// record represents a record that use to build the Double-Array.
|
||||
type record struct {
|
||||
Record
|
||||
paramNames []string
|
||||
}
|
||||
|
||||
// makeRecords returns the records that use to build Double-Arrays.
|
||||
func makeRecords(srcs []Record) (statics, params []*record) {
|
||||
spChars := string([]byte{ParamCharacter, WildcardCharacter})
|
||||
termChar := string(TerminationCharacter)
|
||||
for _, r := range srcs {
|
||||
if strings.ContainsAny(r.Key, spChars) {
|
||||
r.Key += termChar
|
||||
params = append(params, &record{Record: r})
|
||||
} else {
|
||||
statics = append(statics, &record{Record: r})
|
||||
}
|
||||
}
|
||||
return statics, params
|
||||
}
|
||||
|
||||
// recordSlice represents a slice of Record for sort and implements the sort.Interface.
|
||||
type recordSlice []*record
|
||||
|
||||
// Len implements the sort.Interface.Len.
|
||||
func (rs recordSlice) Len() int {
|
||||
return len(rs)
|
||||
}
|
||||
|
||||
// Less implements the sort.Interface.Less.
|
||||
func (rs recordSlice) Less(i, j int) bool {
|
||||
return rs[i].Key < rs[j].Key
|
||||
}
|
||||
|
||||
// Swap implements the sort.Interface.Swap.
|
||||
func (rs recordSlice) Swap(i, j int) {
|
||||
rs[i], rs[j] = rs[j], rs[i]
|
||||
}
|
||||
178
vendor/github.com/go-openapi/runtime/middleware/denco/router_bench_test.go
generated
vendored
Executable file
178
vendor/github.com/go-openapi/runtime/middleware/denco/router_bench_test.go
generated
vendored
Executable file
@@ -0,0 +1,178 @@
|
||||
package denco_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware/denco"
|
||||
)
|
||||
|
||||
func BenchmarkRouterLookupStatic100(b *testing.B) {
|
||||
benchmarkRouterLookupStatic(b, 100)
|
||||
}
|
||||
|
||||
func BenchmarkRouterLookupStatic300(b *testing.B) {
|
||||
benchmarkRouterLookupStatic(b, 300)
|
||||
}
|
||||
|
||||
func BenchmarkRouterLookupStatic700(b *testing.B) {
|
||||
benchmarkRouterLookupStatic(b, 700)
|
||||
}
|
||||
|
||||
func BenchmarkRouterLookupSingleParam100(b *testing.B) {
|
||||
records := makeTestSingleParamRecords(100)
|
||||
benchmarkRouterLookupSingleParam(b, records)
|
||||
}
|
||||
|
||||
func BenchmarkRouterLookupSingleParam300(b *testing.B) {
|
||||
records := makeTestSingleParamRecords(300)
|
||||
benchmarkRouterLookupSingleParam(b, records)
|
||||
}
|
||||
|
||||
func BenchmarkRouterLookupSingleParam700(b *testing.B) {
|
||||
records := makeTestSingleParamRecords(700)
|
||||
benchmarkRouterLookupSingleParam(b, records)
|
||||
}
|
||||
|
||||
func BenchmarkRouterLookupSingle2Param100(b *testing.B) {
|
||||
records := makeTestSingle2ParamRecords(100)
|
||||
benchmarkRouterLookupSingleParam(b, records)
|
||||
}
|
||||
|
||||
func BenchmarkRouterLookupSingle2Param300(b *testing.B) {
|
||||
records := makeTestSingle2ParamRecords(300)
|
||||
benchmarkRouterLookupSingleParam(b, records)
|
||||
}
|
||||
|
||||
func BenchmarkRouterLookupSingle2Param700(b *testing.B) {
|
||||
records := makeTestSingle2ParamRecords(700)
|
||||
benchmarkRouterLookupSingleParam(b, records)
|
||||
}
|
||||
|
||||
func BenchmarkRouterBuildStatic100(b *testing.B) {
|
||||
records := makeTestStaticRecords(100)
|
||||
benchmarkRouterBuild(b, records)
|
||||
}
|
||||
|
||||
func BenchmarkRouterBuildStatic300(b *testing.B) {
|
||||
records := makeTestStaticRecords(300)
|
||||
benchmarkRouterBuild(b, records)
|
||||
}
|
||||
|
||||
func BenchmarkRouterBuildStatic700(b *testing.B) {
|
||||
records := makeTestStaticRecords(700)
|
||||
benchmarkRouterBuild(b, records)
|
||||
}
|
||||
|
||||
func BenchmarkRouterBuildSingleParam100(b *testing.B) {
|
||||
records := makeTestSingleParamRecords(100)
|
||||
benchmarkRouterBuild(b, records)
|
||||
}
|
||||
|
||||
func BenchmarkRouterBuildSingleParam300(b *testing.B) {
|
||||
records := makeTestSingleParamRecords(300)
|
||||
benchmarkRouterBuild(b, records)
|
||||
}
|
||||
|
||||
func BenchmarkRouterBuildSingleParam700(b *testing.B) {
|
||||
records := makeTestSingleParamRecords(700)
|
||||
benchmarkRouterBuild(b, records)
|
||||
}
|
||||
|
||||
func BenchmarkRouterBuildSingle2Param100(b *testing.B) {
|
||||
records := makeTestSingle2ParamRecords(100)
|
||||
benchmarkRouterBuild(b, records)
|
||||
}
|
||||
|
||||
func BenchmarkRouterBuildSingle2Param300(b *testing.B) {
|
||||
records := makeTestSingle2ParamRecords(300)
|
||||
benchmarkRouterBuild(b, records)
|
||||
}
|
||||
|
||||
func BenchmarkRouterBuildSingle2Param700(b *testing.B) {
|
||||
records := makeTestSingle2ParamRecords(700)
|
||||
benchmarkRouterBuild(b, records)
|
||||
}
|
||||
|
||||
func benchmarkRouterLookupStatic(b *testing.B, n int) {
|
||||
b.StopTimer()
|
||||
router := denco.New()
|
||||
records := makeTestStaticRecords(n)
|
||||
if err := router.Build(records); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
record := pickTestRecord(records)
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if r, _, _ := router.Lookup(record.Key); r != record.Value {
|
||||
b.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkRouterLookupSingleParam(b *testing.B, records []denco.Record) {
|
||||
router := denco.New()
|
||||
if err := router.Build(records); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
record := pickTestRecord(records)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, _, found := router.Lookup(record.Key); !found {
|
||||
b.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkRouterBuild(b *testing.B, records []denco.Record) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
router := denco.New()
|
||||
if err := router.Build(records); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makeTestStaticRecords(n int) []denco.Record {
|
||||
records := make([]denco.Record, n)
|
||||
for i := 0; i < n; i++ {
|
||||
records[i] = denco.NewRecord("/"+randomString(50), fmt.Sprintf("testroute%d", i))
|
||||
}
|
||||
return records
|
||||
}
|
||||
|
||||
func makeTestSingleParamRecords(n int) []denco.Record {
|
||||
records := make([]denco.Record, n)
|
||||
for i := 0; i < len(records); i++ {
|
||||
records[i] = denco.NewRecord(fmt.Sprintf("/user%d/:name", i), fmt.Sprintf("testroute%d", i))
|
||||
}
|
||||
return records
|
||||
}
|
||||
|
||||
func makeTestSingle2ParamRecords(n int) []denco.Record {
|
||||
records := make([]denco.Record, n)
|
||||
for i := 0; i < len(records); i++ {
|
||||
records[i] = denco.NewRecord(fmt.Sprintf("/user%d/:name/comment/:id", i), fmt.Sprintf("testroute%d", i))
|
||||
}
|
||||
return records
|
||||
}
|
||||
|
||||
func pickTestRecord(records []denco.Record) denco.Record {
|
||||
return records[len(records)/2]
|
||||
}
|
||||
|
||||
func randomString(n int) string {
|
||||
const srcStrings = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/"
|
||||
var buf bytes.Buffer
|
||||
for i := 0; i < n; i++ {
|
||||
num, err := rand.Int(rand.Reader, big.NewInt(int64(len(srcStrings)-1)))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf.WriteByte(srcStrings[num.Int64()])
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
524
vendor/github.com/go-openapi/runtime/middleware/denco/router_test.go
generated
vendored
Executable file
524
vendor/github.com/go-openapi/runtime/middleware/denco/router_test.go
generated
vendored
Executable file
@@ -0,0 +1,524 @@
|
||||
package denco_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware/denco"
|
||||
)
|
||||
|
||||
func routes() []denco.Record {
|
||||
return []denco.Record{
|
||||
{"/", "testroute0"},
|
||||
{"/path/to/route", "testroute1"},
|
||||
{"/path/to/other", "testroute2"},
|
||||
{"/path/to/route/a", "testroute3"},
|
||||
{"/path/to/:param", "testroute4"},
|
||||
{"/gists/:param1/foo/:param2", "testroute12"},
|
||||
{"/gists/:param1/foo/bar", "testroute11"},
|
||||
{"/:param1/:param2/foo/:param3", "testroute13"},
|
||||
{"/path/to/wildcard/*routepath", "testroute5"},
|
||||
{"/path/to/:param1/:param2", "testroute6"},
|
||||
{"/path/to/:param1/sep/:param2", "testroute7"},
|
||||
{"/:year/:month/:day", "testroute8"},
|
||||
{"/user/:id", "testroute9"},
|
||||
{"/a/to/b/:param/*routepath", "testroute10"},
|
||||
}
|
||||
}
|
||||
|
||||
var realURIs = []denco.Record{
|
||||
{"/authorizations", "/authorizations"},
|
||||
{"/authorizations/:id", "/authorizations/:id"},
|
||||
{"/applications/:client_id/tokens/:access_token", "/applications/:client_id/tokens/:access_token"},
|
||||
{"/events", "/events"},
|
||||
{"/repos/:owner/:repo/events", "/repos/:owner/:repo/events"},
|
||||
{"/networks/:owner/:repo/events", "/networks/:owner/:repo/events"},
|
||||
{"/orgs/:org/events", "/orgs/:org/events"},
|
||||
{"/users/:user/received_events", "/users/:user/received_events"},
|
||||
{"/users/:user/received_events/public", "/users/:user/received_events/public"},
|
||||
{"/users/:user/events", "/users/:user/events"},
|
||||
{"/users/:user/events/public", "/users/:user/events/public"},
|
||||
{"/users/:user/events/orgs/:org", "/users/:user/events/orgs/:org"},
|
||||
{"/feeds", "/feeds"},
|
||||
{"/notifications", "/notifications"},
|
||||
{"/repos/:owner/:repo/notifications", "/repos/:owner/:repo/notifications"},
|
||||
{"/notifications/threads/:id", "/notifications/threads/:id"},
|
||||
{"/notifications/threads/:id/subscription", "/notifications/threads/:id/subscription"},
|
||||
{"/repos/:owner/:repo/stargazers", "/repos/:owner/:repo/stargazers"},
|
||||
{"/users/:user/starred", "/users/:user/starred"},
|
||||
{"/user/starred", "/user/starred"},
|
||||
{"/user/starred/:owner/:repo", "/user/starred/:owner/:repo"},
|
||||
{"/repos/:owner/:repo/subscribers", "/repos/:owner/:repo/subscribers"},
|
||||
{"/users/:user/subscriptions", "/users/:user/subscriptions"},
|
||||
{"/user/subscriptions", "/user/subscriptions"},
|
||||
{"/repos/:owner/:repo/subscription", "/repos/:owner/:repo/subscription"},
|
||||
{"/user/subscriptions/:owner/:repo", "/user/subscriptions/:owner/:repo"},
|
||||
{"/users/:user/gists", "/users/:user/gists"},
|
||||
{"/gists", "/gists"},
|
||||
{"/gists/:id", "/gists/:id"},
|
||||
{"/gists/:id/star", "/gists/:id/star"},
|
||||
{"/repos/:owner/:repo/git/blobs/:sha", "/repos/:owner/:repo/git/blobs/:sha"},
|
||||
{"/repos/:owner/:repo/git/commits/:sha", "/repos/:owner/:repo/git/commits/:sha"},
|
||||
{"/repos/:owner/:repo/git/refs", "/repos/:owner/:repo/git/refs"},
|
||||
{"/repos/:owner/:repo/git/tags/:sha", "/repos/:owner/:repo/git/tags/:sha"},
|
||||
{"/repos/:owner/:repo/git/trees/:sha", "/repos/:owner/:repo/git/trees/:sha"},
|
||||
{"/issues", "/issues"},
|
||||
{"/user/issues", "/user/issues"},
|
||||
{"/orgs/:org/issues", "/orgs/:org/issues"},
|
||||
{"/repos/:owner/:repo/issues", "/repos/:owner/:repo/issues"},
|
||||
{"/repos/:owner/:repo/issues/:number", "/repos/:owner/:repo/issues/:number"},
|
||||
{"/repos/:owner/:repo/assignees", "/repos/:owner/:repo/assignees"},
|
||||
{"/repos/:owner/:repo/assignees/:assignee", "/repos/:owner/:repo/assignees/:assignee"},
|
||||
{"/repos/:owner/:repo/issues/:number/comments", "/repos/:owner/:repo/issues/:number/comments"},
|
||||
{"/repos/:owner/:repo/issues/:number/events", "/repos/:owner/:repo/issues/:number/events"},
|
||||
{"/repos/:owner/:repo/labels", "/repos/:owner/:repo/labels"},
|
||||
{"/repos/:owner/:repo/labels/:name", "/repos/:owner/:repo/labels/:name"},
|
||||
{"/repos/:owner/:repo/issues/:number/labels", "/repos/:owner/:repo/issues/:number/labels"},
|
||||
{"/repos/:owner/:repo/milestones/:number/labels", "/repos/:owner/:repo/milestones/:number/labels"},
|
||||
{"/repos/:owner/:repo/milestones", "/repos/:owner/:repo/milestones"},
|
||||
{"/repos/:owner/:repo/milestones/:number", "/repos/:owner/:repo/milestones/:number"},
|
||||
{"/emojis", "/emojis"},
|
||||
{"/gitignore/templates", "/gitignore/templates"},
|
||||
{"/gitignore/templates/:name", "/gitignore/templates/:name"},
|
||||
{"/meta", "/meta"},
|
||||
{"/rate_limit", "/rate_limit"},
|
||||
{"/users/:user/orgs", "/users/:user/orgs"},
|
||||
{"/user/orgs", "/user/orgs"},
|
||||
{"/orgs/:org", "/orgs/:org"},
|
||||
{"/orgs/:org/members", "/orgs/:org/members"},
|
||||
{"/orgs/:org/members/:user", "/orgs/:org/members/:user"},
|
||||
{"/orgs/:org/public_members", "/orgs/:org/public_members"},
|
||||
{"/orgs/:org/public_members/:user", "/orgs/:org/public_members/:user"},
|
||||
{"/orgs/:org/teams", "/orgs/:org/teams"},
|
||||
{"/teams/:id", "/teams/:id"},
|
||||
{"/teams/:id/members", "/teams/:id/members"},
|
||||
{"/teams/:id/members/:user", "/teams/:id/members/:user"},
|
||||
{"/teams/:id/repos", "/teams/:id/repos"},
|
||||
{"/teams/:id/repos/:owner/:repo", "/teams/:id/repos/:owner/:repo"},
|
||||
{"/user/teams", "/user/teams"},
|
||||
{"/repos/:owner/:repo/pulls", "/repos/:owner/:repo/pulls"},
|
||||
{"/repos/:owner/:repo/pulls/:number", "/repos/:owner/:repo/pulls/:number"},
|
||||
{"/repos/:owner/:repo/pulls/:number/commits", "/repos/:owner/:repo/pulls/:number/commits"},
|
||||
{"/repos/:owner/:repo/pulls/:number/files", "/repos/:owner/:repo/pulls/:number/files"},
|
||||
{"/repos/:owner/:repo/pulls/:number/merge", "/repos/:owner/:repo/pulls/:number/merge"},
|
||||
{"/repos/:owner/:repo/pulls/:number/comments", "/repos/:owner/:repo/pulls/:number/comments"},
|
||||
{"/user/repos", "/user/repos"},
|
||||
{"/users/:user/repos", "/users/:user/repos"},
|
||||
{"/orgs/:org/repos", "/orgs/:org/repos"},
|
||||
{"/repositories", "/repositories"},
|
||||
{"/repos/:owner/:repo", "/repos/:owner/:repo"},
|
||||
{"/repos/:owner/:repo/contributors", "/repos/:owner/:repo/contributors"},
|
||||
{"/repos/:owner/:repo/languages", "/repos/:owner/:repo/languages"},
|
||||
{"/repos/:owner/:repo/teams", "/repos/:owner/:repo/teams"},
|
||||
{"/repos/:owner/:repo/tags", "/repos/:owner/:repo/tags"},
|
||||
{"/repos/:owner/:repo/branches", "/repos/:owner/:repo/branches"},
|
||||
{"/repos/:owner/:repo/branches/:branch", "/repos/:owner/:repo/branches/:branch"},
|
||||
{"/repos/:owner/:repo/collaborators", "/repos/:owner/:repo/collaborators"},
|
||||
{"/repos/:owner/:repo/collaborators/:user", "/repos/:owner/:repo/collaborators/:user"},
|
||||
{"/repos/:owner/:repo/comments", "/repos/:owner/:repo/comments"},
|
||||
{"/repos/:owner/:repo/commits/:sha/comments", "/repos/:owner/:repo/commits/:sha/comments"},
|
||||
{"/repos/:owner/:repo/comments/:id", "/repos/:owner/:repo/comments/:id"},
|
||||
{"/repos/:owner/:repo/commits", "/repos/:owner/:repo/commits"},
|
||||
{"/repos/:owner/:repo/commits/:sha", "/repos/:owner/:repo/commits/:sha"},
|
||||
{"/repos/:owner/:repo/readme", "/repos/:owner/:repo/readme"},
|
||||
{"/repos/:owner/:repo/keys", "/repos/:owner/:repo/keys"},
|
||||
{"/repos/:owner/:repo/keys/:id", "/repos/:owner/:repo/keys/:id"},
|
||||
{"/repos/:owner/:repo/downloads", "/repos/:owner/:repo/downloads"},
|
||||
{"/repos/:owner/:repo/downloads/:id", "/repos/:owner/:repo/downloads/:id"},
|
||||
{"/repos/:owner/:repo/forks", "/repos/:owner/:repo/forks"},
|
||||
{"/repos/:owner/:repo/hooks", "/repos/:owner/:repo/hooks"},
|
||||
{"/repos/:owner/:repo/hooks/:id", "/repos/:owner/:repo/hooks/:id"},
|
||||
{"/repos/:owner/:repo/releases", "/repos/:owner/:repo/releases"},
|
||||
{"/repos/:owner/:repo/releases/:id", "/repos/:owner/:repo/releases/:id"},
|
||||
{"/repos/:owner/:repo/releases/:id/assets", "/repos/:owner/:repo/releases/:id/assets"},
|
||||
{"/repos/:owner/:repo/stats/contributors", "/repos/:owner/:repo/stats/contributors"},
|
||||
{"/repos/:owner/:repo/stats/commit_activity", "/repos/:owner/:repo/stats/commit_activity"},
|
||||
{"/repos/:owner/:repo/stats/code_frequency", "/repos/:owner/:repo/stats/code_frequency"},
|
||||
{"/repos/:owner/:repo/stats/participation", "/repos/:owner/:repo/stats/participation"},
|
||||
{"/repos/:owner/:repo/stats/punch_card", "/repos/:owner/:repo/stats/punch_card"},
|
||||
{"/repos/:owner/:repo/statuses/:ref", "/repos/:owner/:repo/statuses/:ref"},
|
||||
{"/search/repositories", "/search/repositories"},
|
||||
{"/search/code", "/search/code"},
|
||||
{"/search/issues", "/search/issues"},
|
||||
{"/search/users", "/search/users"},
|
||||
{"/legacy/issues/search/:owner/:repository/:state/:keyword", "/legacy/issues/search/:owner/:repository/:state/:keyword"},
|
||||
{"/legacy/repos/search/:keyword", "/legacy/repos/search/:keyword"},
|
||||
{"/legacy/user/search/:keyword", "/legacy/user/search/:keyword"},
|
||||
{"/legacy/user/email/:email", "/legacy/user/email/:email"},
|
||||
{"/users/:user", "/users/:user"},
|
||||
{"/user", "/user"},
|
||||
{"/users", "/users"},
|
||||
{"/user/emails", "/user/emails"},
|
||||
{"/users/:user/followers", "/users/:user/followers"},
|
||||
{"/user/followers", "/user/followers"},
|
||||
{"/users/:user/following", "/users/:user/following"},
|
||||
{"/user/following", "/user/following"},
|
||||
{"/user/following/:user", "/user/following/:user"},
|
||||
{"/users/:user/following/:target_user", "/users/:user/following/:target_user"},
|
||||
{"/users/:user/keys", "/users/:user/keys"},
|
||||
{"/user/keys", "/user/keys"},
|
||||
{"/user/keys/:id", "/user/keys/:id"},
|
||||
{"/people/:userId", "/people/:userId"},
|
||||
{"/people", "/people"},
|
||||
{"/activities/:activityId/people/:collection", "/activities/:activityId/people/:collection"},
|
||||
{"/people/:userId/people/:collection", "/people/:userId/people/:collection"},
|
||||
{"/people/:userId/openIdConnect", "/people/:userId/openIdConnect"},
|
||||
{"/people/:userId/activities/:collection", "/people/:userId/activities/:collection"},
|
||||
{"/activities/:activityId", "/activities/:activityId"},
|
||||
{"/activities", "/activities"},
|
||||
{"/activities/:activityId/comments", "/activities/:activityId/comments"},
|
||||
{"/comments/:commentId", "/comments/:commentId"},
|
||||
{"/people/:userId/moments/:collection", "/people/:userId/moments/:collection"},
|
||||
}
|
||||
|
||||
type testcase struct {
|
||||
path string
|
||||
value interface{}
|
||||
params []denco.Param
|
||||
found bool
|
||||
}
|
||||
|
||||
func runLookupTest(t *testing.T, records []denco.Record, testcases []testcase) {
|
||||
r := denco.New()
|
||||
if err := r.Build(records); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, testcase := range testcases {
|
||||
data, params, found := r.Lookup(testcase.path)
|
||||
if !reflect.DeepEqual(data, testcase.value) || !reflect.DeepEqual(params, denco.Params(testcase.params)) || !reflect.DeepEqual(found, testcase.found) {
|
||||
t.Errorf("Router.Lookup(%q) => (%#v, %#v, %#v), want (%#v, %#v, %#v)", testcase.path, data, params, found, testcase.value, denco.Params(testcase.params), testcase.found)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouter_Lookup(t *testing.T) {
|
||||
testcases := []testcase{
|
||||
{"/", "testroute0", nil, true},
|
||||
{"/gists/1323/foo/bar", "testroute11", []denco.Param{{"param1", "1323"}}, true},
|
||||
{"/gists/1323/foo/133", "testroute12", []denco.Param{{"param1", "1323"}, {"param2", "133"}}, true},
|
||||
{"/234/1323/foo/133", "testroute13", []denco.Param{{"param1", "234"}, {"param2", "1323"}, {"param3", "133"}}, true},
|
||||
{"/path/to/route", "testroute1", nil, true},
|
||||
{"/path/to/other", "testroute2", nil, true},
|
||||
{"/path/to/route/a", "testroute3", nil, true},
|
||||
{"/path/to/hoge", "testroute4", []denco.Param{{"param", "hoge"}}, true},
|
||||
{"/path/to/wildcard/some/params", "testroute5", []denco.Param{{"routepath", "some/params"}}, true},
|
||||
{"/path/to/o1/o2", "testroute6", []denco.Param{{"param1", "o1"}, {"param2", "o2"}}, true},
|
||||
{"/path/to/p1/sep/p2", "testroute7", []denco.Param{{"param1", "p1"}, {"param2", "p2"}}, true},
|
||||
{"/2014/01/06", "testroute8", []denco.Param{{"year", "2014"}, {"month", "01"}, {"day", "06"}}, true},
|
||||
{"/user/777", "testroute9", []denco.Param{{"id", "777"}}, true},
|
||||
{"/a/to/b/p1/some/wildcard/params", "testroute10", []denco.Param{{"param", "p1"}, {"routepath", "some/wildcard/params"}}, true},
|
||||
{"/missing", nil, nil, false},
|
||||
}
|
||||
runLookupTest(t, routes(), testcases)
|
||||
|
||||
records := []denco.Record{
|
||||
{"/", "testroute0"},
|
||||
{"/:b", "testroute1"},
|
||||
{"/*wildcard", "testroute2"},
|
||||
}
|
||||
testcases = []testcase{
|
||||
{"/", "testroute0", nil, true},
|
||||
{"/true", "testroute1", []denco.Param{{"b", "true"}}, true},
|
||||
{"/foo/bar", "testroute2", []denco.Param{{"wildcard", "foo/bar"}}, true},
|
||||
}
|
||||
runLookupTest(t, records, testcases)
|
||||
|
||||
records = []denco.Record{
|
||||
{"/networks/:owner/:repo/events", "testroute0"},
|
||||
{"/orgs/:org/events", "testroute1"},
|
||||
{"/notifications/threads/:id", "testroute2"},
|
||||
}
|
||||
testcases = []testcase{
|
||||
{"/networks/:owner/:repo/events", "testroute0", []denco.Param{{"owner", ":owner"}, {"repo", ":repo"}}, true},
|
||||
{"/orgs/:org/events", "testroute1", []denco.Param{{"org", ":org"}}, true},
|
||||
{"/notifications/threads/:id", "testroute2", []denco.Param{{"id", ":id"}}, true},
|
||||
}
|
||||
runLookupTest(t, records, testcases)
|
||||
|
||||
runLookupTest(t, []denco.Record{
|
||||
{"/", "route2"},
|
||||
}, []testcase{
|
||||
{"/user/alice", nil, nil, false},
|
||||
})
|
||||
|
||||
runLookupTest(t, []denco.Record{
|
||||
{"/user/:name", "route1"},
|
||||
}, []testcase{
|
||||
{"/", nil, nil, false},
|
||||
})
|
||||
|
||||
runLookupTest(t, []denco.Record{
|
||||
{"/*wildcard", "testroute0"},
|
||||
{"/a/:b", "testroute1"},
|
||||
}, []testcase{
|
||||
{"/a", "testroute0", []denco.Param{{"wildcard", "a"}}, true},
|
||||
})
|
||||
}
|
||||
|
||||
func TestRouter_Lookup_withManyRoutes(t *testing.T) {
|
||||
n := 1000
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
records := make([]denco.Record, n)
|
||||
for i := 0; i < n; i++ {
|
||||
records[i] = denco.Record{Key: "/" + randomString(rand.Intn(50)+10), Value: fmt.Sprintf("route%d", i)}
|
||||
}
|
||||
router := denco.New()
|
||||
if err := router.Build(records); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, r := range records {
|
||||
data, params, found := router.Lookup(r.Key)
|
||||
if !reflect.DeepEqual(data, r.Value) || len(params) != 0 || !reflect.DeepEqual(found, true) {
|
||||
t.Errorf("Router.Lookup(%q) => (%#v, %#v, %#v), want (%#v, %#v, %#v)", r.Key, data, len(params), found, r.Value, 0, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouter_Lookup_realURIs(t *testing.T) {
|
||||
testcases := []testcase{
|
||||
{"/authorizations", "/authorizations", nil, true},
|
||||
{"/authorizations/1", "/authorizations/:id", []denco.Param{{"id", "1"}}, true},
|
||||
{"/applications/1/tokens/zohRoo7e", "/applications/:client_id/tokens/:access_token", []denco.Param{{"client_id", "1"}, {"access_token", "zohRoo7e"}}, true},
|
||||
{"/events", "/events", nil, true},
|
||||
{"/repos/naoina/denco/events", "/repos/:owner/:repo/events", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/networks/naoina/denco/events", "/networks/:owner/:repo/events", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/orgs/something/events", "/orgs/:org/events", []denco.Param{{"org", "something"}}, true},
|
||||
{"/users/naoina/received_events", "/users/:user/received_events", []denco.Param{{"user", "naoina"}}, true},
|
||||
{"/users/naoina/received_events/public", "/users/:user/received_events/public", []denco.Param{{"user", "naoina"}}, true},
|
||||
{"/users/naoina/events", "/users/:user/events", []denco.Param{{"user", "naoina"}}, true},
|
||||
{"/users/naoina/events/public", "/users/:user/events/public", []denco.Param{{"user", "naoina"}}, true},
|
||||
{"/users/naoina/events/orgs/something", "/users/:user/events/orgs/:org", []denco.Param{{"user", "naoina"}, {"org", "something"}}, true},
|
||||
{"/feeds", "/feeds", nil, true},
|
||||
{"/notifications", "/notifications", nil, true},
|
||||
{"/repos/naoina/denco/notifications", "/repos/:owner/:repo/notifications", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/notifications/threads/1", "/notifications/threads/:id", []denco.Param{{"id", "1"}}, true},
|
||||
{"/notifications/threads/2/subscription", "/notifications/threads/:id/subscription", []denco.Param{{"id", "2"}}, true},
|
||||
{"/repos/naoina/denco/stargazers", "/repos/:owner/:repo/stargazers", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/users/naoina/starred", "/users/:user/starred", []denco.Param{{"user", "naoina"}}, true},
|
||||
{"/user/starred", "/user/starred", nil, true},
|
||||
{"/user/starred/naoina/denco", "/user/starred/:owner/:repo", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/subscribers", "/repos/:owner/:repo/subscribers", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/users/naoina/subscriptions", "/users/:user/subscriptions", []denco.Param{{"user", "naoina"}}, true},
|
||||
{"/user/subscriptions", "/user/subscriptions", nil, true},
|
||||
{"/repos/naoina/denco/subscription", "/repos/:owner/:repo/subscription", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/user/subscriptions/naoina/denco", "/user/subscriptions/:owner/:repo", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/users/naoina/gists", "/users/:user/gists", []denco.Param{{"user", "naoina"}}, true},
|
||||
{"/gists", "/gists", nil, true},
|
||||
{"/gists/1", "/gists/:id", []denco.Param{{"id", "1"}}, true},
|
||||
{"/gists/2/star", "/gists/:id/star", []denco.Param{{"id", "2"}}, true},
|
||||
{"/repos/naoina/denco/git/blobs/03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9", "/repos/:owner/:repo/git/blobs/:sha", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"sha", "03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9"}}, true},
|
||||
{"/repos/naoina/denco/git/commits/03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9", "/repos/:owner/:repo/git/commits/:sha", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"sha", "03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9"}}, true},
|
||||
{"/repos/naoina/denco/git/refs", "/repos/:owner/:repo/git/refs", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/git/tags/03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9", "/repos/:owner/:repo/git/tags/:sha", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"sha", "03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9"}}, true},
|
||||
{"/repos/naoina/denco/git/trees/03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9", "/repos/:owner/:repo/git/trees/:sha", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"sha", "03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9"}}, true},
|
||||
{"/issues", "/issues", nil, true},
|
||||
{"/user/issues", "/user/issues", nil, true},
|
||||
{"/orgs/something/issues", "/orgs/:org/issues", []denco.Param{{"org", "something"}}, true},
|
||||
{"/repos/naoina/denco/issues", "/repos/:owner/:repo/issues", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/issues/1", "/repos/:owner/:repo/issues/:number", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
|
||||
{"/repos/naoina/denco/assignees", "/repos/:owner/:repo/assignees", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/assignees/foo", "/repos/:owner/:repo/assignees/:assignee", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"assignee", "foo"}}, true},
|
||||
{"/repos/naoina/denco/issues/1/comments", "/repos/:owner/:repo/issues/:number/comments", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
|
||||
{"/repos/naoina/denco/issues/1/events", "/repos/:owner/:repo/issues/:number/events", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
|
||||
{"/repos/naoina/denco/labels", "/repos/:owner/:repo/labels", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/labels/bug", "/repos/:owner/:repo/labels/:name", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"name", "bug"}}, true},
|
||||
{"/repos/naoina/denco/issues/1/labels", "/repos/:owner/:repo/issues/:number/labels", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
|
||||
{"/repos/naoina/denco/milestones/1/labels", "/repos/:owner/:repo/milestones/:number/labels", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
|
||||
{"/repos/naoina/denco/milestones", "/repos/:owner/:repo/milestones", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/milestones/1", "/repos/:owner/:repo/milestones/:number", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
|
||||
{"/emojis", "/emojis", nil, true},
|
||||
{"/gitignore/templates", "/gitignore/templates", nil, true},
|
||||
{"/gitignore/templates/Go", "/gitignore/templates/:name", []denco.Param{{"name", "Go"}}, true},
|
||||
{"/meta", "/meta", nil, true},
|
||||
{"/rate_limit", "/rate_limit", nil, true},
|
||||
{"/users/naoina/orgs", "/users/:user/orgs", []denco.Param{{"user", "naoina"}}, true},
|
||||
{"/user/orgs", "/user/orgs", nil, true},
|
||||
{"/orgs/something", "/orgs/:org", []denco.Param{{"org", "something"}}, true},
|
||||
{"/orgs/something/members", "/orgs/:org/members", []denco.Param{{"org", "something"}}, true},
|
||||
{"/orgs/something/members/naoina", "/orgs/:org/members/:user", []denco.Param{{"org", "something"}, {"user", "naoina"}}, true},
|
||||
{"/orgs/something/public_members", "/orgs/:org/public_members", []denco.Param{{"org", "something"}}, true},
|
||||
{"/orgs/something/public_members/naoina", "/orgs/:org/public_members/:user", []denco.Param{{"org", "something"}, {"user", "naoina"}}, true},
|
||||
{"/orgs/something/teams", "/orgs/:org/teams", []denco.Param{{"org", "something"}}, true},
|
||||
{"/teams/1", "/teams/:id", []denco.Param{{"id", "1"}}, true},
|
||||
{"/teams/2/members", "/teams/:id/members", []denco.Param{{"id", "2"}}, true},
|
||||
{"/teams/3/members/naoina", "/teams/:id/members/:user", []denco.Param{{"id", "3"}, {"user", "naoina"}}, true},
|
||||
{"/teams/4/repos", "/teams/:id/repos", []denco.Param{{"id", "4"}}, true},
|
||||
{"/teams/5/repos/naoina/denco", "/teams/:id/repos/:owner/:repo", []denco.Param{{"id", "5"}, {"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/user/teams", "/user/teams", nil, true},
|
||||
{"/repos/naoina/denco/pulls", "/repos/:owner/:repo/pulls", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/pulls/1", "/repos/:owner/:repo/pulls/:number", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
|
||||
{"/repos/naoina/denco/pulls/1/commits", "/repos/:owner/:repo/pulls/:number/commits", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
|
||||
{"/repos/naoina/denco/pulls/1/files", "/repos/:owner/:repo/pulls/:number/files", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
|
||||
{"/repos/naoina/denco/pulls/1/merge", "/repos/:owner/:repo/pulls/:number/merge", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
|
||||
{"/repos/naoina/denco/pulls/1/comments", "/repos/:owner/:repo/pulls/:number/comments", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
|
||||
{"/user/repos", "/user/repos", nil, true},
|
||||
{"/users/naoina/repos", "/users/:user/repos", []denco.Param{{"user", "naoina"}}, true},
|
||||
{"/orgs/something/repos", "/orgs/:org/repos", []denco.Param{{"org", "something"}}, true},
|
||||
{"/repositories", "/repositories", nil, true},
|
||||
{"/repos/naoina/denco", "/repos/:owner/:repo", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/contributors", "/repos/:owner/:repo/contributors", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/languages", "/repos/:owner/:repo/languages", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/teams", "/repos/:owner/:repo/teams", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/tags", "/repos/:owner/:repo/tags", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/branches", "/repos/:owner/:repo/branches", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/branches/master", "/repos/:owner/:repo/branches/:branch", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"branch", "master"}}, true},
|
||||
{"/repos/naoina/denco/collaborators", "/repos/:owner/:repo/collaborators", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/collaborators/something", "/repos/:owner/:repo/collaborators/:user", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"user", "something"}}, true},
|
||||
{"/repos/naoina/denco/comments", "/repos/:owner/:repo/comments", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/commits/03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9/comments", "/repos/:owner/:repo/commits/:sha/comments", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"sha", "03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9"}}, true},
|
||||
{"/repos/naoina/denco/comments/1", "/repos/:owner/:repo/comments/:id", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"id", "1"}}, true},
|
||||
{"/repos/naoina/denco/commits", "/repos/:owner/:repo/commits", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/commits/03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9", "/repos/:owner/:repo/commits/:sha", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"sha", "03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9"}}, true},
|
||||
{"/repos/naoina/denco/readme", "/repos/:owner/:repo/readme", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/keys", "/repos/:owner/:repo/keys", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/keys/1", "/repos/:owner/:repo/keys/:id", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"id", "1"}}, true},
|
||||
{"/repos/naoina/denco/downloads", "/repos/:owner/:repo/downloads", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/downloads/2", "/repos/:owner/:repo/downloads/:id", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"id", "2"}}, true},
|
||||
{"/repos/naoina/denco/forks", "/repos/:owner/:repo/forks", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/hooks", "/repos/:owner/:repo/hooks", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/hooks/2", "/repos/:owner/:repo/hooks/:id", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"id", "2"}}, true},
|
||||
{"/repos/naoina/denco/releases", "/repos/:owner/:repo/releases", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/releases/1", "/repos/:owner/:repo/releases/:id", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"id", "1"}}, true},
|
||||
{"/repos/naoina/denco/releases/1/assets", "/repos/:owner/:repo/releases/:id/assets", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"id", "1"}}, true},
|
||||
{"/repos/naoina/denco/stats/contributors", "/repos/:owner/:repo/stats/contributors", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/stats/commit_activity", "/repos/:owner/:repo/stats/commit_activity", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/stats/code_frequency", "/repos/:owner/:repo/stats/code_frequency", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/stats/participation", "/repos/:owner/:repo/stats/participation", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/stats/punch_card", "/repos/:owner/:repo/stats/punch_card", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
|
||||
{"/repos/naoina/denco/statuses/master", "/repos/:owner/:repo/statuses/:ref", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"ref", "master"}}, true},
|
||||
{"/search/repositories", "/search/repositories", nil, true},
|
||||
{"/search/code", "/search/code", nil, true},
|
||||
{"/search/issues", "/search/issues", nil, true},
|
||||
{"/search/users", "/search/users", nil, true},
|
||||
{"/legacy/issues/search/naoina/denco/closed/test", "/legacy/issues/search/:owner/:repository/:state/:keyword", []denco.Param{{"owner", "naoina"}, {"repository", "denco"}, {"state", "closed"}, {"keyword", "test"}}, true},
|
||||
{"/legacy/repos/search/test", "/legacy/repos/search/:keyword", []denco.Param{{"keyword", "test"}}, true},
|
||||
{"/legacy/user/search/test", "/legacy/user/search/:keyword", []denco.Param{{"keyword", "test"}}, true},
|
||||
{"/legacy/user/email/naoina@kuune.org", "/legacy/user/email/:email", []denco.Param{{"email", "naoina@kuune.org"}}, true},
|
||||
{"/users/naoina", "/users/:user", []denco.Param{{"user", "naoina"}}, true},
|
||||
{"/user", "/user", nil, true},
|
||||
{"/users", "/users", nil, true},
|
||||
{"/user/emails", "/user/emails", nil, true},
|
||||
{"/users/naoina/followers", "/users/:user/followers", []denco.Param{{"user", "naoina"}}, true},
|
||||
{"/user/followers", "/user/followers", nil, true},
|
||||
{"/users/naoina/following", "/users/:user/following", []denco.Param{{"user", "naoina"}}, true},
|
||||
{"/user/following", "/user/following", nil, true},
|
||||
{"/user/following/naoina", "/user/following/:user", []denco.Param{{"user", "naoina"}}, true},
|
||||
{"/users/naoina/following/target", "/users/:user/following/:target_user", []denco.Param{{"user", "naoina"}, {"target_user", "target"}}, true},
|
||||
{"/users/naoina/keys", "/users/:user/keys", []denco.Param{{"user", "naoina"}}, true},
|
||||
{"/user/keys", "/user/keys", nil, true},
|
||||
{"/user/keys/1", "/user/keys/:id", []denco.Param{{"id", "1"}}, true},
|
||||
{"/people/me", "/people/:userId", []denco.Param{{"userId", "me"}}, true},
|
||||
{"/people", "/people", nil, true},
|
||||
{"/activities/foo/people/vault", "/activities/:activityId/people/:collection", []denco.Param{{"activityId", "foo"}, {"collection", "vault"}}, true},
|
||||
{"/people/me/people/vault", "/people/:userId/people/:collection", []denco.Param{{"userId", "me"}, {"collection", "vault"}}, true},
|
||||
{"/people/me/openIdConnect", "/people/:userId/openIdConnect", []denco.Param{{"userId", "me"}}, true},
|
||||
{"/people/me/activities/vault", "/people/:userId/activities/:collection", []denco.Param{{"userId", "me"}, {"collection", "vault"}}, true},
|
||||
{"/activities/foo", "/activities/:activityId", []denco.Param{{"activityId", "foo"}}, true},
|
||||
{"/activities", "/activities", nil, true},
|
||||
{"/activities/foo/comments", "/activities/:activityId/comments", []denco.Param{{"activityId", "foo"}}, true},
|
||||
{"/comments/hoge", "/comments/:commentId", []denco.Param{{"commentId", "hoge"}}, true},
|
||||
{"/people/me/moments/vault", "/people/:userId/moments/:collection", []denco.Param{{"userId", "me"}, {"collection", "vault"}}, true},
|
||||
}
|
||||
runLookupTest(t, realURIs, testcases)
|
||||
}
|
||||
|
||||
func TestRouter_Build(t *testing.T) {
|
||||
// test for duplicate name of path parameters.
|
||||
func() {
|
||||
r := denco.New()
|
||||
if err := r.Build([]denco.Record{
|
||||
{"/:user/:id/:id", "testroute0"},
|
||||
{"/:user/:user/:id", "testroute0"},
|
||||
}); err == nil {
|
||||
t.Errorf("no error returned by duplicate name of path parameters")
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func TestRouter_Build_withoutSizeHint(t *testing.T) {
|
||||
for _, v := range []struct {
|
||||
keys []string
|
||||
sizeHint int
|
||||
}{
|
||||
{[]string{"/user"}, 0},
|
||||
{[]string{"/user/:id"}, 1},
|
||||
{[]string{"/user/:id/post"}, 1},
|
||||
{[]string{"/user/:id/:group"}, 2},
|
||||
{[]string{"/user/:id/post/:cid"}, 2},
|
||||
{[]string{"/user/:id/post/:cid", "/admin/:id/post/:cid"}, 2},
|
||||
{[]string{"/user/:id", "/admin/:id/post/:cid"}, 2},
|
||||
{[]string{"/user/:id/post/:cid", "/admin/:id/post/:cid/:type"}, 3},
|
||||
} {
|
||||
r := denco.New()
|
||||
actual := r.SizeHint
|
||||
expect := -1
|
||||
if !reflect.DeepEqual(actual, expect) {
|
||||
t.Errorf(`before Build; Router.SizeHint => (%[1]T=%#[1]v); want (%[2]T=%#[2]v)`, actual, expect)
|
||||
}
|
||||
records := make([]denco.Record, len(v.keys))
|
||||
for i, k := range v.keys {
|
||||
records[i] = denco.Record{Key: k, Value: "value"}
|
||||
}
|
||||
if err := r.Build(records); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actual = r.SizeHint
|
||||
expect = v.sizeHint
|
||||
if !reflect.DeepEqual(actual, expect) {
|
||||
t.Errorf(`Router.Build(%#v); Router.SizeHint => (%[2]T=%#[2]v); want (%[3]T=%#[3]v)`, records, actual, expect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouter_Build_withSizeHint(t *testing.T) {
|
||||
for _, v := range []struct {
|
||||
key string
|
||||
sizeHint int
|
||||
expect int
|
||||
}{
|
||||
{"/user", 0, 0},
|
||||
{"/user", 1, 1},
|
||||
{"/user", 2, 2},
|
||||
{"/user/:id", 3, 3},
|
||||
{"/user/:id/:group", 0, 0},
|
||||
{"/user/:id/:group", 1, 1},
|
||||
} {
|
||||
r := denco.New()
|
||||
r.SizeHint = v.sizeHint
|
||||
records := []denco.Record{
|
||||
{v.key, "value"},
|
||||
}
|
||||
if err := r.Build(records); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actual := r.SizeHint
|
||||
expect := v.expect
|
||||
if !reflect.DeepEqual(actual, expect) {
|
||||
t.Errorf(`Router.Build(%#v); Router.SizeHint => (%[2]T=%#[2]v); want (%[3]T=%#[3]v)`, records, actual, expect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParams_Get(t *testing.T) {
|
||||
params := denco.Params([]denco.Param{
|
||||
{"name1", "value1"},
|
||||
{"name2", "value2"},
|
||||
{"name3", "value3"},
|
||||
{"name1", "value4"},
|
||||
})
|
||||
for _, v := range []struct{ value, expected string }{
|
||||
{"name1", "value1"},
|
||||
{"name2", "value2"},
|
||||
{"name3", "value3"},
|
||||
{"name4", ""},
|
||||
} {
|
||||
actual := params.Get(v.value)
|
||||
expected := v.expected
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Errorf("Params.Get(%q) => %#v, want %#v", v.value, actual, expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
106
vendor/github.com/go-openapi/runtime/middleware/denco/server.go
generated
vendored
Executable file
106
vendor/github.com/go-openapi/runtime/middleware/denco/server.go
generated
vendored
Executable file
@@ -0,0 +1,106 @@
|
||||
package denco
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Mux represents a multiplexer for HTTP request.
|
||||
type Mux struct{}
|
||||
|
||||
// NewMux returns a new Mux.
|
||||
func NewMux() *Mux {
|
||||
return &Mux{}
|
||||
}
|
||||
|
||||
// GET is shorthand of Mux.Handler("GET", path, handler).
|
||||
func (m *Mux) GET(path string, handler HandlerFunc) Handler {
|
||||
return m.Handler("GET", path, handler)
|
||||
}
|
||||
|
||||
// POST is shorthand of Mux.Handler("POST", path, handler).
|
||||
func (m *Mux) POST(path string, handler HandlerFunc) Handler {
|
||||
return m.Handler("POST", path, handler)
|
||||
}
|
||||
|
||||
// PUT is shorthand of Mux.Handler("PUT", path, handler).
|
||||
func (m *Mux) PUT(path string, handler HandlerFunc) Handler {
|
||||
return m.Handler("PUT", path, handler)
|
||||
}
|
||||
|
||||
// HEAD is shorthand of Mux.Handler("HEAD", path, handler).
|
||||
func (m *Mux) HEAD(path string, handler HandlerFunc) Handler {
|
||||
return m.Handler("HEAD", path, handler)
|
||||
}
|
||||
|
||||
// Handler returns a handler for HTTP method.
|
||||
func (m *Mux) Handler(method, path string, handler HandlerFunc) Handler {
|
||||
return Handler{
|
||||
Method: method,
|
||||
Path: path,
|
||||
Func: handler,
|
||||
}
|
||||
}
|
||||
|
||||
// Build builds a http.Handler.
|
||||
func (m *Mux) Build(handlers []Handler) (http.Handler, error) {
|
||||
recordMap := make(map[string][]Record)
|
||||
for _, h := range handlers {
|
||||
recordMap[h.Method] = append(recordMap[h.Method], NewRecord(h.Path, h.Func))
|
||||
}
|
||||
mux := newServeMux()
|
||||
for m, records := range recordMap {
|
||||
router := New()
|
||||
if err := router.Build(records); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mux.routers[m] = router
|
||||
}
|
||||
return mux, nil
|
||||
}
|
||||
|
||||
// Handler represents a handler of HTTP request.
|
||||
type Handler struct {
|
||||
// Method is an HTTP method.
|
||||
Method string
|
||||
|
||||
// Path is a routing path for handler.
|
||||
Path string
|
||||
|
||||
// Func is a function of handler of HTTP request.
|
||||
Func HandlerFunc
|
||||
}
|
||||
|
||||
// The HandlerFunc type is aliased to type of handler function.
|
||||
type HandlerFunc func(w http.ResponseWriter, r *http.Request, params Params)
|
||||
|
||||
type serveMux struct {
|
||||
routers map[string]*Router
|
||||
}
|
||||
|
||||
func newServeMux() *serveMux {
|
||||
return &serveMux{
|
||||
routers: make(map[string]*Router),
|
||||
}
|
||||
}
|
||||
|
||||
// ServeHTTP implements http.Handler interface.
|
||||
func (mux *serveMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
handler, params := mux.handler(r.Method, r.URL.Path)
|
||||
handler(w, r, params)
|
||||
}
|
||||
|
||||
func (mux *serveMux) handler(method, path string) (HandlerFunc, []Param) {
|
||||
if router, found := mux.routers[method]; found {
|
||||
if handler, params, found := router.Lookup(path); found {
|
||||
return handler.(HandlerFunc), params
|
||||
}
|
||||
}
|
||||
return NotFound, nil
|
||||
}
|
||||
|
||||
// NotFound replies to the request with an HTTP 404 not found error.
|
||||
// NotFound is called when unknown HTTP method or a handler not found.
|
||||
// If you want to use the your own NotFound handler, please overwrite this variable.
|
||||
var NotFound = func(w http.ResponseWriter, r *http.Request, _ Params) {
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
106
vendor/github.com/go-openapi/runtime/middleware/denco/server_test.go
generated
vendored
Executable file
106
vendor/github.com/go-openapi/runtime/middleware/denco/server_test.go
generated
vendored
Executable file
@@ -0,0 +1,106 @@
|
||||
package denco_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware/denco"
|
||||
)
|
||||
|
||||
func testHandlerFunc(w http.ResponseWriter, r *http.Request, params denco.Params) {
|
||||
fmt.Fprintf(w, "method: %s, path: %s, params: %v", r.Method, r.URL.Path, params)
|
||||
}
|
||||
|
||||
func TestMux(t *testing.T) {
|
||||
mux := denco.NewMux()
|
||||
handler, err := mux.Build([]denco.Handler{
|
||||
mux.GET("/", testHandlerFunc),
|
||||
mux.GET("/user/:name", testHandlerFunc),
|
||||
mux.POST("/user/:name", testHandlerFunc),
|
||||
mux.HEAD("/user/:name", testHandlerFunc),
|
||||
mux.PUT("/user/:name", testHandlerFunc),
|
||||
mux.Handler("GET", "/user/handler", testHandlerFunc),
|
||||
mux.Handler("POST", "/user/handler", testHandlerFunc),
|
||||
{"PUT", "/user/inference", testHandlerFunc},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
server := httptest.NewServer(handler)
|
||||
defer server.Close()
|
||||
|
||||
for _, v := range []struct {
|
||||
status int
|
||||
method, path, expected string
|
||||
}{
|
||||
{200, "GET", "/", "method: GET, path: /, params: []"},
|
||||
{200, "GET", "/user/alice", "method: GET, path: /user/alice, params: [{name alice}]"},
|
||||
{200, "POST", "/user/bob", "method: POST, path: /user/bob, params: [{name bob}]"},
|
||||
{200, "HEAD", "/user/alice", ""},
|
||||
{200, "PUT", "/user/bob", "method: PUT, path: /user/bob, params: [{name bob}]"},
|
||||
{404, "POST", "/", "404 page not found\n"},
|
||||
{404, "GET", "/unknown", "404 page not found\n"},
|
||||
{404, "POST", "/user/alice/1", "404 page not found\n"},
|
||||
{200, "GET", "/user/handler", "method: GET, path: /user/handler, params: []"},
|
||||
{200, "POST", "/user/handler", "method: POST, path: /user/handler, params: []"},
|
||||
{200, "PUT", "/user/inference", "method: PUT, path: /user/inference, params: []"},
|
||||
} {
|
||||
req, err := http.NewRequest(v.method, server.URL+v.path, nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
defer res.Body.Close()
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
actual := string(body)
|
||||
expected := v.expected
|
||||
if res.StatusCode != v.status || actual != expected {
|
||||
t.Errorf(`%s "%s" => %#v %#v, want %#v %#v`, v.method, v.path, res.StatusCode, actual, v.status, expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotFound(t *testing.T) {
|
||||
mux := denco.NewMux()
|
||||
handler, err := mux.Build([]denco.Handler{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
server := httptest.NewServer(handler)
|
||||
defer server.Close()
|
||||
|
||||
origNotFound := denco.NotFound
|
||||
defer func() {
|
||||
denco.NotFound = origNotFound
|
||||
}()
|
||||
denco.NotFound = func(w http.ResponseWriter, r *http.Request, params denco.Params) {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
fmt.Fprintf(w, "method: %s, path: %s, params: %v", r.Method, r.URL.Path, params)
|
||||
}
|
||||
res, err := http.Get(server.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actual := string(body)
|
||||
expected := "method: GET, path: /, params: []"
|
||||
if res.StatusCode != http.StatusServiceUnavailable || actual != expected {
|
||||
t.Errorf(`GET "/" => %#v %#v, want %#v %#v`, res.StatusCode, actual, http.StatusServiceUnavailable, expected)
|
||||
}
|
||||
}
|
||||
12
vendor/github.com/go-openapi/runtime/middleware/denco/util.go
generated
vendored
Executable file
12
vendor/github.com/go-openapi/runtime/middleware/denco/util.go
generated
vendored
Executable file
@@ -0,0 +1,12 @@
|
||||
package denco
|
||||
|
||||
// NextSeparator returns an index of next separator in path.
|
||||
func NextSeparator(path string, start int) int {
|
||||
for start < len(path) {
|
||||
if c := path[start]; c == '/' || c == TerminationCharacter {
|
||||
break
|
||||
}
|
||||
start++
|
||||
}
|
||||
return start
|
||||
}
|
||||
31
vendor/github.com/go-openapi/runtime/middleware/denco/util_test.go
generated
vendored
Executable file
31
vendor/github.com/go-openapi/runtime/middleware/denco/util_test.go
generated
vendored
Executable file
@@ -0,0 +1,31 @@
|
||||
package denco_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware/denco"
|
||||
)
|
||||
|
||||
func TestNextSeparator(t *testing.T) {
|
||||
for _, testcase := range []struct {
|
||||
path string
|
||||
start int
|
||||
expected interface{}
|
||||
}{
|
||||
{"/path/to/route", 0, 0},
|
||||
{"/path/to/route", 1, 5},
|
||||
{"/path/to/route", 9, 14},
|
||||
{"/path.html", 1, 10},
|
||||
{"/foo/bar.html", 1, 4},
|
||||
{"/foo/bar.html/baz.png", 5, 13},
|
||||
{"/foo/bar.html/baz.png", 14, 21},
|
||||
{"path#", 0, 4},
|
||||
} {
|
||||
actual := denco.NextSeparator(testcase.path, testcase.start)
|
||||
expected := testcase.expected
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Errorf("path = %q, start = %v expect %v, but %v", testcase.path, testcase.start, expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
65
vendor/github.com/go-openapi/runtime/middleware/doc.go
generated
vendored
Normal file
65
vendor/github.com/go-openapi/runtime/middleware/doc.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
/*Package middleware provides the library with helper functions for serving swagger APIs.
|
||||
|
||||
Pseudo middleware handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/gorilla/context"
|
||||
)
|
||||
|
||||
func newCompleteMiddleware(ctx *Context) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
defer context.Clear(r)
|
||||
|
||||
// use context to lookup routes
|
||||
if matched, ok := ctx.RouteInfo(r); ok {
|
||||
|
||||
if len(matched.Authenticators) > 0 {
|
||||
if _, err := ctx.Authorize(r, matched); err != nil {
|
||||
ctx.Respond(rw, r, matched.Produces, matched, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
bound, validation := ctx.BindAndValidate(r, matched)
|
||||
if validation != nil {
|
||||
ctx.Respond(rw, r, matched.Produces, matched, validation)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := matched.Handler.Handle(bound)
|
||||
if err != nil {
|
||||
ctx.Respond(rw, r, matched.Produces, matched, err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Respond(rw, r, matched.Produces, matched, result)
|
||||
return
|
||||
}
|
||||
|
||||
// Not found, check if it exists in the other methods first
|
||||
if others := ctx.AllowedMethods(r); len(others) > 0 {
|
||||
ctx.Respond(rw, r, ctx.spec.RequiredProduces(), nil, errors.MethodNotAllowed(r.Method, others))
|
||||
return
|
||||
}
|
||||
ctx.Respond(rw, r, ctx.spec.RequiredProduces(), nil, errors.NotFound("path %s was not found", r.URL.Path))
|
||||
})
|
||||
}
|
||||
*/
|
||||
package middleware
|
||||
299
vendor/github.com/go-openapi/runtime/middleware/header/header.go
generated
vendored
Normal file
299
vendor/github.com/go-openapi/runtime/middleware/header/header.go
generated
vendored
Normal file
@@ -0,0 +1,299 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd.
|
||||
|
||||
// this file was taken from the github.com/golang/gddo repository
|
||||
|
||||
// Package header provides functions for parsing HTTP headers.
|
||||
package header
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Octet types from RFC 2616.
|
||||
var octetTypes [256]octetType
|
||||
|
||||
type octetType byte
|
||||
|
||||
const (
|
||||
isToken octetType = 1 << iota
|
||||
isSpace
|
||||
)
|
||||
|
||||
func init() {
|
||||
// OCTET = <any 8-bit sequence of data>
|
||||
// CHAR = <any US-ASCII character (octets 0 - 127)>
|
||||
// CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
|
||||
// CR = <US-ASCII CR, carriage return (13)>
|
||||
// LF = <US-ASCII LF, linefeed (10)>
|
||||
// SP = <US-ASCII SP, space (32)>
|
||||
// HT = <US-ASCII HT, horizontal-tab (9)>
|
||||
// <"> = <US-ASCII double-quote mark (34)>
|
||||
// CRLF = CR LF
|
||||
// LWS = [CRLF] 1*( SP | HT )
|
||||
// TEXT = <any OCTET except CTLs, but including LWS>
|
||||
// separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <">
|
||||
// | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT
|
||||
// token = 1*<any CHAR except CTLs or separators>
|
||||
// qdtext = <any TEXT except <">>
|
||||
|
||||
for c := 0; c < 256; c++ {
|
||||
var t octetType
|
||||
isCtl := c <= 31 || c == 127
|
||||
isChar := 0 <= c && c <= 127
|
||||
isSeparator := strings.IndexRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) >= 0
|
||||
if strings.IndexRune(" \t\r\n", rune(c)) >= 0 {
|
||||
t |= isSpace
|
||||
}
|
||||
if isChar && !isCtl && !isSeparator {
|
||||
t |= isToken
|
||||
}
|
||||
octetTypes[c] = t
|
||||
}
|
||||
}
|
||||
|
||||
// Copy returns a shallow copy of the header.
|
||||
func Copy(header http.Header) http.Header {
|
||||
h := make(http.Header)
|
||||
for k, vs := range header {
|
||||
h[k] = vs
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
var timeLayouts = []string{"Mon, 02 Jan 2006 15:04:05 GMT", time.RFC850, time.ANSIC}
|
||||
|
||||
// ParseTime parses the header as time. The zero value is returned if the
|
||||
// header is not present or there is an error parsing the
|
||||
// header.
|
||||
func ParseTime(header http.Header, key string) time.Time {
|
||||
if s := header.Get(key); s != "" {
|
||||
for _, layout := range timeLayouts {
|
||||
if t, err := time.Parse(layout, s); err == nil {
|
||||
return t.UTC()
|
||||
}
|
||||
}
|
||||
}
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
// ParseList parses a comma separated list of values. Commas are ignored in
|
||||
// quoted strings. Quoted values are not unescaped or unquoted. Whitespace is
|
||||
// trimmed.
|
||||
func ParseList(header http.Header, key string) []string {
|
||||
var result []string
|
||||
for _, s := range header[http.CanonicalHeaderKey(key)] {
|
||||
begin := 0
|
||||
end := 0
|
||||
escape := false
|
||||
quote := false
|
||||
for i := 0; i < len(s); i++ {
|
||||
b := s[i]
|
||||
switch {
|
||||
case escape:
|
||||
escape = false
|
||||
end = i + 1
|
||||
case quote:
|
||||
switch b {
|
||||
case '\\':
|
||||
escape = true
|
||||
case '"':
|
||||
quote = false
|
||||
}
|
||||
end = i + 1
|
||||
case b == '"':
|
||||
quote = true
|
||||
end = i + 1
|
||||
case octetTypes[b]&isSpace != 0:
|
||||
if begin == end {
|
||||
begin = i + 1
|
||||
end = begin
|
||||
}
|
||||
case b == ',':
|
||||
if begin < end {
|
||||
result = append(result, s[begin:end])
|
||||
}
|
||||
begin = i + 1
|
||||
end = begin
|
||||
default:
|
||||
end = i + 1
|
||||
}
|
||||
}
|
||||
if begin < end {
|
||||
result = append(result, s[begin:end])
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// ParseValueAndParams parses a comma separated list of values with optional
|
||||
// semicolon separated name-value pairs. Content-Type and Content-Disposition
|
||||
// headers are in this format.
|
||||
func ParseValueAndParams(header http.Header, key string) (value string, params map[string]string) {
|
||||
params = make(map[string]string)
|
||||
s := header.Get(key)
|
||||
value, s = expectTokenSlash(s)
|
||||
if value == "" {
|
||||
return
|
||||
}
|
||||
value = strings.ToLower(value)
|
||||
s = skipSpace(s)
|
||||
for strings.HasPrefix(s, ";") {
|
||||
var pkey string
|
||||
pkey, s = expectToken(skipSpace(s[1:]))
|
||||
if pkey == "" {
|
||||
return
|
||||
}
|
||||
if !strings.HasPrefix(s, "=") {
|
||||
return
|
||||
}
|
||||
var pvalue string
|
||||
pvalue, s = expectTokenOrQuoted(s[1:])
|
||||
if pvalue == "" {
|
||||
return
|
||||
}
|
||||
pkey = strings.ToLower(pkey)
|
||||
params[pkey] = pvalue
|
||||
s = skipSpace(s)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type AcceptSpec struct {
|
||||
Value string
|
||||
Q float64
|
||||
}
|
||||
|
||||
// ParseAccept parses Accept* headers.
|
||||
func ParseAccept(header http.Header, key string) (specs []AcceptSpec) {
|
||||
loop:
|
||||
for _, s := range header[key] {
|
||||
for {
|
||||
var spec AcceptSpec
|
||||
spec.Value, s = expectTokenSlash(s)
|
||||
if spec.Value == "" {
|
||||
continue loop
|
||||
}
|
||||
spec.Q = 1.0
|
||||
s = skipSpace(s)
|
||||
if strings.HasPrefix(s, ";") {
|
||||
s = skipSpace(s[1:])
|
||||
if !strings.HasPrefix(s, "q=") {
|
||||
continue loop
|
||||
}
|
||||
spec.Q, s = expectQuality(s[2:])
|
||||
if spec.Q < 0.0 {
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
specs = append(specs, spec)
|
||||
s = skipSpace(s)
|
||||
if !strings.HasPrefix(s, ",") {
|
||||
continue loop
|
||||
}
|
||||
s = skipSpace(s[1:])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func skipSpace(s string) (rest string) {
|
||||
i := 0
|
||||
for ; i < len(s); i++ {
|
||||
if octetTypes[s[i]]&isSpace == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return s[i:]
|
||||
}
|
||||
|
||||
func expectToken(s string) (token, rest string) {
|
||||
i := 0
|
||||
for ; i < len(s); i++ {
|
||||
if octetTypes[s[i]]&isToken == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return s[:i], s[i:]
|
||||
}
|
||||
|
||||
func expectTokenSlash(s string) (token, rest string) {
|
||||
i := 0
|
||||
for ; i < len(s); i++ {
|
||||
b := s[i]
|
||||
if (octetTypes[b]&isToken == 0) && b != '/' {
|
||||
break
|
||||
}
|
||||
}
|
||||
return s[:i], s[i:]
|
||||
}
|
||||
|
||||
func expectQuality(s string) (q float64, rest string) {
|
||||
switch {
|
||||
case len(s) == 0:
|
||||
return -1, ""
|
||||
case s[0] == '0':
|
||||
q = 0
|
||||
case s[0] == '1':
|
||||
q = 1
|
||||
default:
|
||||
return -1, ""
|
||||
}
|
||||
s = s[1:]
|
||||
if !strings.HasPrefix(s, ".") {
|
||||
return q, s
|
||||
}
|
||||
s = s[1:]
|
||||
i := 0
|
||||
n := 0
|
||||
d := 1
|
||||
for ; i < len(s); i++ {
|
||||
b := s[i]
|
||||
if b < '0' || b > '9' {
|
||||
break
|
||||
}
|
||||
n = n*10 + int(b) - '0'
|
||||
d *= 10
|
||||
}
|
||||
return q + float64(n)/float64(d), s[i:]
|
||||
}
|
||||
|
||||
func expectTokenOrQuoted(s string) (value string, rest string) {
|
||||
if !strings.HasPrefix(s, "\"") {
|
||||
return expectToken(s)
|
||||
}
|
||||
s = s[1:]
|
||||
for i := 0; i < len(s); i++ {
|
||||
switch s[i] {
|
||||
case '"':
|
||||
return s[:i], s[i+1:]
|
||||
case '\\':
|
||||
p := make([]byte, len(s)-1)
|
||||
j := copy(p, s[:i])
|
||||
escape := true
|
||||
for i = i + 1; i < len(s); i++ {
|
||||
b := s[i]
|
||||
switch {
|
||||
case escape:
|
||||
escape = false
|
||||
p[j] = b
|
||||
j += 1
|
||||
case b == '\\':
|
||||
escape = true
|
||||
case b == '"':
|
||||
return string(p[:j]), s[i+1:]
|
||||
default:
|
||||
p[j] = b
|
||||
j += 1
|
||||
}
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
82
vendor/github.com/go-openapi/runtime/middleware/negotiate.go
generated
vendored
Normal file
82
vendor/github.com/go-openapi/runtime/middleware/negotiate.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd.
|
||||
|
||||
// this file was taken from the github.com/golang/gddo repository
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware/header"
|
||||
)
|
||||
|
||||
// NegotiateContentEncoding returns the best offered content encoding for the
|
||||
// request's Accept-Encoding header. If two offers match with equal weight and
|
||||
// then the offer earlier in the list is preferred. If no offers are
|
||||
// acceptable, then "" is returned.
|
||||
func NegotiateContentEncoding(r *http.Request, offers []string) string {
|
||||
bestOffer := "identity"
|
||||
bestQ := -1.0
|
||||
specs := header.ParseAccept(r.Header, "Accept-Encoding")
|
||||
for _, offer := range offers {
|
||||
for _, spec := range specs {
|
||||
if spec.Q > bestQ &&
|
||||
(spec.Value == "*" || spec.Value == offer) {
|
||||
bestQ = spec.Q
|
||||
bestOffer = offer
|
||||
}
|
||||
}
|
||||
}
|
||||
if bestQ == 0 {
|
||||
bestOffer = ""
|
||||
}
|
||||
return bestOffer
|
||||
}
|
||||
|
||||
// NegotiateContentType returns the best offered content type for the request's
|
||||
// Accept header. If two offers match with equal weight, then the more specific
|
||||
// offer is preferred. For example, text/* trumps */*. If two offers match
|
||||
// with equal weight and specificity, then the offer earlier in the list is
|
||||
// preferred. If no offers match, then defaultOffer is returned.
|
||||
func NegotiateContentType(r *http.Request, offers []string, defaultOffer string) string {
|
||||
bestOffer := defaultOffer
|
||||
bestQ := -1.0
|
||||
bestWild := 3
|
||||
specs := header.ParseAccept(r.Header, "Accept")
|
||||
for _, offer := range offers {
|
||||
for _, spec := range specs {
|
||||
switch {
|
||||
case spec.Q == 0.0:
|
||||
// ignore
|
||||
case spec.Q < bestQ:
|
||||
// better match found
|
||||
case spec.Value == "*/*":
|
||||
if spec.Q > bestQ || bestWild > 2 {
|
||||
bestQ = spec.Q
|
||||
bestWild = 2
|
||||
bestOffer = offer
|
||||
}
|
||||
case strings.HasSuffix(spec.Value, "/*"):
|
||||
if strings.HasPrefix(offer, spec.Value[:len(spec.Value)-1]) &&
|
||||
(spec.Q > bestQ || bestWild > 1) {
|
||||
bestQ = spec.Q
|
||||
bestWild = 1
|
||||
bestOffer = offer
|
||||
}
|
||||
default:
|
||||
if spec.Value == offer &&
|
||||
(spec.Q > bestQ || bestWild > 0) {
|
||||
bestQ = spec.Q
|
||||
bestWild = 0
|
||||
bestOffer = offer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bestOffer
|
||||
}
|
||||
70
vendor/github.com/go-openapi/runtime/middleware/negotiate_test.go
generated
vendored
Normal file
70
vendor/github.com/go-openapi/runtime/middleware/negotiate_test.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var negotiateContentEncodingTests = []struct {
|
||||
s string
|
||||
offers []string
|
||||
expect string
|
||||
}{
|
||||
{"", []string{"identity", "gzip"}, "identity"},
|
||||
{"*;q=0", []string{"identity", "gzip"}, ""},
|
||||
{"gzip", []string{"identity", "gzip"}, "gzip"},
|
||||
}
|
||||
|
||||
func TestNegotiateContentEnoding(t *testing.T) {
|
||||
for _, tt := range negotiateContentEncodingTests {
|
||||
r := &http.Request{Header: http.Header{"Accept-Encoding": {tt.s}}}
|
||||
actual := NegotiateContentEncoding(r, tt.offers)
|
||||
if actual != tt.expect {
|
||||
t.Errorf("NegotiateContentEncoding(%q, %#v)=%q, want %q", tt.s, tt.offers, actual, tt.expect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var negotiateContentTypeTests = []struct {
|
||||
s string
|
||||
offers []string
|
||||
defaultOffer string
|
||||
expect string
|
||||
}{
|
||||
{"text/html, */*;q=0", []string{"x/y"}, "", ""},
|
||||
{"text/html, */*", []string{"x/y"}, "", "x/y"},
|
||||
{"text/html, image/png", []string{"text/html", "image/png"}, "", "text/html"},
|
||||
{"text/html, image/png", []string{"image/png", "text/html"}, "", "image/png"},
|
||||
{"text/html, image/png; q=0.5", []string{"image/png"}, "", "image/png"},
|
||||
{"text/html, image/png; q=0.5", []string{"text/html"}, "", "text/html"},
|
||||
{"text/html, image/png; q=0.5", []string{"foo/bar"}, "", ""},
|
||||
{"text/html, image/png; q=0.5", []string{"image/png", "text/html"}, "", "text/html"},
|
||||
{"text/html, image/png; q=0.5", []string{"text/html", "image/png"}, "", "text/html"},
|
||||
{"text/html;q=0.5, image/png", []string{"image/png"}, "", "image/png"},
|
||||
{"text/html;q=0.5, image/png", []string{"text/html"}, "", "text/html"},
|
||||
{"text/html;q=0.5, image/png", []string{"image/png", "text/html"}, "", "image/png"},
|
||||
{"text/html;q=0.5, image/png", []string{"text/html", "image/png"}, "", "image/png"},
|
||||
{"image/png, image/*;q=0.5", []string{"image/jpg", "image/png"}, "", "image/png"},
|
||||
{"image/png, image/*;q=0.5", []string{"image/jpg"}, "", "image/jpg"},
|
||||
{"image/png, image/*;q=0.5", []string{"image/jpg", "image/gif"}, "", "image/jpg"},
|
||||
{"image/png, image/*", []string{"image/jpg", "image/gif"}, "", "image/jpg"},
|
||||
{"image/png, image/*", []string{"image/gif", "image/jpg"}, "", "image/gif"},
|
||||
{"image/png, image/*", []string{"image/gif", "image/png"}, "", "image/png"},
|
||||
{"image/png, image/*", []string{"image/png", "image/gif"}, "", "image/png"},
|
||||
}
|
||||
|
||||
func TestNegotiateContentType(t *testing.T) {
|
||||
for _, tt := range negotiateContentTypeTests {
|
||||
r := &http.Request{Header: http.Header{"Accept": {tt.s}}}
|
||||
actual := NegotiateContentType(r, tt.offers, tt.defaultOffer)
|
||||
if actual != tt.expect {
|
||||
t.Errorf("NegotiateContentType(%q, %#v, %q)=%q, want %q", tt.s, tt.offers, tt.defaultOffer, actual, tt.expect)
|
||||
}
|
||||
}
|
||||
}
|
||||
48
vendor/github.com/go-openapi/runtime/middleware/not_implemented.go
generated
vendored
Normal file
48
vendor/github.com/go-openapi/runtime/middleware/not_implemented.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
)
|
||||
|
||||
type errorResp struct {
|
||||
code int
|
||||
response interface{}
|
||||
headers http.Header
|
||||
}
|
||||
|
||||
func (e *errorResp) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
for k, v := range e.headers {
|
||||
for _, val := range v {
|
||||
rw.Header().Add(k, val)
|
||||
}
|
||||
}
|
||||
if e.code > 0 {
|
||||
rw.WriteHeader(e.code)
|
||||
} else {
|
||||
rw.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
if err := producer.Produce(rw, e.response); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// NotImplemented the error response when the response is not implemented
|
||||
func NotImplemented(message string) Responder {
|
||||
return &errorResp{http.StatusNotImplemented, message, make(http.Header)}
|
||||
}
|
||||
26
vendor/github.com/go-openapi/runtime/middleware/operation.go
generated
vendored
Normal file
26
vendor/github.com/go-openapi/runtime/middleware/operation.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package middleware
|
||||
|
||||
import "net/http"
|
||||
|
||||
// NewOperationExecutor creates a context aware middleware that handles the operations after routing
|
||||
func NewOperationExecutor(ctx *Context) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
// use context to lookup routes
|
||||
route, _ := ctx.RouteInfo(r)
|
||||
route.Handler.ServeHTTP(rw, r)
|
||||
})
|
||||
}
|
||||
64
vendor/github.com/go-openapi/runtime/middleware/operation_test.go
generated
vendored
Normal file
64
vendor/github.com/go-openapi/runtime/middleware/operation_test.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/internal/testing/petstore"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestOperationExecutor(t *testing.T) {
|
||||
spec, api := petstore.NewAPI(t)
|
||||
api.RegisterOperation("get", "/pets", runtime.OperationHandlerFunc(func(params interface{}) (interface{}, error) {
|
||||
return []interface{}{
|
||||
map[string]interface{}{"id": 1, "name": "a dog"},
|
||||
}, nil
|
||||
}))
|
||||
|
||||
context := NewContext(spec, api, nil)
|
||||
context.router = DefaultRouter(spec, context.api)
|
||||
mw := NewOperationExecutor(context)
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
request, _ := http.NewRequest("GET", "/api/pets", nil)
|
||||
request.Header.Add("Accept", "application/json")
|
||||
request.SetBasicAuth("admin", "admin")
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
assert.Equal(t, `[{"id":1,"name":"a dog"}]`+"\n", recorder.Body.String())
|
||||
|
||||
spec, api = petstore.NewAPI(t)
|
||||
api.RegisterOperation("get", "/pets", runtime.OperationHandlerFunc(func(params interface{}) (interface{}, error) {
|
||||
return nil, errors.New(422, "expected")
|
||||
}))
|
||||
|
||||
context = NewContext(spec, api, nil)
|
||||
context.router = DefaultRouter(spec, context.api)
|
||||
mw = NewOperationExecutor(context)
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
request, _ = http.NewRequest("GET", "/api/pets", nil)
|
||||
request.Header.Add("Accept", "application/json")
|
||||
request.SetBasicAuth("admin", "admin")
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, 422, recorder.Code)
|
||||
assert.Equal(t, `{"code":422,"message":"expected"}`, recorder.Body.String())
|
||||
}
|
||||
480
vendor/github.com/go-openapi/runtime/middleware/parameter.go
generated
vendored
Normal file
480
vendor/github.com/go-openapi/runtime/middleware/parameter.go
generated
vendored
Normal file
@@ -0,0 +1,480 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
const defaultMaxMemory = 32 << 20
|
||||
|
||||
var textUnmarshalType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem()
|
||||
|
||||
func newUntypedParamBinder(param spec.Parameter, spec *spec.Swagger, formats strfmt.Registry) *untypedParamBinder {
|
||||
binder := new(untypedParamBinder)
|
||||
binder.Name = param.Name
|
||||
binder.parameter = ¶m
|
||||
binder.formats = formats
|
||||
if param.In != "body" {
|
||||
binder.validator = validate.NewParamValidator(¶m, formats)
|
||||
} else {
|
||||
binder.validator = validate.NewSchemaValidator(param.Schema, spec, param.Name, formats)
|
||||
}
|
||||
|
||||
return binder
|
||||
}
|
||||
|
||||
type untypedParamBinder struct {
|
||||
parameter *spec.Parameter
|
||||
formats strfmt.Registry
|
||||
Name string
|
||||
validator validate.EntityValidator
|
||||
}
|
||||
|
||||
func (p *untypedParamBinder) Type() reflect.Type {
|
||||
return p.typeForSchema(p.parameter.Type, p.parameter.Format, p.parameter.Items)
|
||||
}
|
||||
|
||||
func (p *untypedParamBinder) typeForSchema(tpe, format string, items *spec.Items) reflect.Type {
|
||||
switch tpe {
|
||||
case "boolean":
|
||||
return reflect.TypeOf(true)
|
||||
|
||||
case "string":
|
||||
if tt, ok := p.formats.GetType(format); ok {
|
||||
return tt
|
||||
}
|
||||
return reflect.TypeOf("")
|
||||
|
||||
case "integer":
|
||||
switch format {
|
||||
case "int8":
|
||||
return reflect.TypeOf(int8(0))
|
||||
case "int16":
|
||||
return reflect.TypeOf(int16(0))
|
||||
case "int32":
|
||||
return reflect.TypeOf(int32(0))
|
||||
case "int64":
|
||||
return reflect.TypeOf(int64(0))
|
||||
default:
|
||||
return reflect.TypeOf(int64(0))
|
||||
}
|
||||
|
||||
case "number":
|
||||
switch format {
|
||||
case "float":
|
||||
return reflect.TypeOf(float32(0))
|
||||
case "double":
|
||||
return reflect.TypeOf(float64(0))
|
||||
}
|
||||
|
||||
case "array":
|
||||
if items == nil {
|
||||
return nil
|
||||
}
|
||||
itemsType := p.typeForSchema(items.Type, items.Format, items.Items)
|
||||
if itemsType == nil {
|
||||
return nil
|
||||
}
|
||||
return reflect.MakeSlice(reflect.SliceOf(itemsType), 0, 0).Type()
|
||||
|
||||
case "file":
|
||||
return reflect.TypeOf(&runtime.File{}).Elem()
|
||||
|
||||
case "object":
|
||||
return reflect.TypeOf(map[string]interface{}{})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *untypedParamBinder) allowsMulti() bool {
|
||||
return p.parameter.In == "query" || p.parameter.In == "formData"
|
||||
}
|
||||
|
||||
func (p *untypedParamBinder) readValue(values runtime.Gettable, target reflect.Value) ([]string, bool, bool, error) {
|
||||
name, in, cf, tpe := p.parameter.Name, p.parameter.In, p.parameter.CollectionFormat, p.parameter.Type
|
||||
if tpe == "array" {
|
||||
if cf == "multi" {
|
||||
if !p.allowsMulti() {
|
||||
return nil, false, false, errors.InvalidCollectionFormat(name, in, cf)
|
||||
}
|
||||
vv, hasKey, _ := values.GetOK(name)
|
||||
return vv, false, hasKey, nil
|
||||
}
|
||||
|
||||
v, hk, hv := values.GetOK(name)
|
||||
if !hv {
|
||||
return nil, false, hk, nil
|
||||
}
|
||||
d, c, e := p.readFormattedSliceFieldValue(v[len(v)-1], target)
|
||||
return d, c, hk, e
|
||||
}
|
||||
|
||||
vv, hk, _ := values.GetOK(name)
|
||||
return vv, false, hk, nil
|
||||
}
|
||||
|
||||
func (p *untypedParamBinder) Bind(request *http.Request, routeParams RouteParams, consumer runtime.Consumer, target reflect.Value) error {
|
||||
// fmt.Println("binding", p.name, "as", p.Type())
|
||||
switch p.parameter.In {
|
||||
case "query":
|
||||
data, custom, hasKey, err := p.readValue(runtime.Values(request.URL.Query()), target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if custom {
|
||||
return nil
|
||||
}
|
||||
|
||||
return p.bindValue(data, hasKey, target)
|
||||
|
||||
case "header":
|
||||
data, custom, hasKey, err := p.readValue(runtime.Values(request.Header), target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if custom {
|
||||
return nil
|
||||
}
|
||||
return p.bindValue(data, hasKey, target)
|
||||
|
||||
case "path":
|
||||
data, custom, hasKey, err := p.readValue(routeParams, target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if custom {
|
||||
return nil
|
||||
}
|
||||
return p.bindValue(data, hasKey, target)
|
||||
|
||||
case "formData":
|
||||
var err error
|
||||
var mt string
|
||||
|
||||
mt, _, e := runtime.ContentType(request.Header)
|
||||
if e != nil {
|
||||
// because of the interface conversion go thinks the error is not nil
|
||||
// so we first check for nil and then set the err var if it's not nil
|
||||
err = e
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return errors.InvalidContentType("", []string{"multipart/form-data", "application/x-www-form-urlencoded"})
|
||||
}
|
||||
|
||||
if mt != "multipart/form-data" && mt != "application/x-www-form-urlencoded" {
|
||||
return errors.InvalidContentType(mt, []string{"multipart/form-data", "application/x-www-form-urlencoded"})
|
||||
}
|
||||
|
||||
if mt == "multipart/form-data" {
|
||||
if err := request.ParseMultipartForm(defaultMaxMemory); err != nil {
|
||||
return errors.NewParseError(p.Name, p.parameter.In, "", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := request.ParseForm(); err != nil {
|
||||
return errors.NewParseError(p.Name, p.parameter.In, "", err)
|
||||
}
|
||||
|
||||
if p.parameter.Type == "file" {
|
||||
file, header, err := request.FormFile(p.parameter.Name)
|
||||
if err != nil {
|
||||
return errors.NewParseError(p.Name, p.parameter.In, "", err)
|
||||
}
|
||||
target.Set(reflect.ValueOf(runtime.File{Data: file, Header: header}))
|
||||
return nil
|
||||
}
|
||||
|
||||
if request.MultipartForm != nil {
|
||||
data, custom, hasKey, err := p.readValue(runtime.Values(request.MultipartForm.Value), target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if custom {
|
||||
return nil
|
||||
}
|
||||
return p.bindValue(data, hasKey, target)
|
||||
}
|
||||
data, custom, hasKey, err := p.readValue(runtime.Values(request.PostForm), target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if custom {
|
||||
return nil
|
||||
}
|
||||
return p.bindValue(data, hasKey, target)
|
||||
|
||||
case "body":
|
||||
newValue := reflect.New(target.Type())
|
||||
if !runtime.HasBody(request) {
|
||||
if p.parameter.Default != nil {
|
||||
target.Set(reflect.ValueOf(p.parameter.Default))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
if err := consumer.Consume(request.Body, newValue.Interface()); err != nil {
|
||||
if err == io.EOF && p.parameter.Default != nil {
|
||||
target.Set(reflect.ValueOf(p.parameter.Default))
|
||||
return nil
|
||||
}
|
||||
tpe := p.parameter.Type
|
||||
if p.parameter.Format != "" {
|
||||
tpe = p.parameter.Format
|
||||
}
|
||||
return errors.InvalidType(p.Name, p.parameter.In, tpe, nil)
|
||||
}
|
||||
target.Set(reflect.Indirect(newValue))
|
||||
return nil
|
||||
default:
|
||||
return errors.New(500, fmt.Sprintf("invalid parameter location %q", p.parameter.In))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *untypedParamBinder) bindValue(data []string, hasKey bool, target reflect.Value) error {
|
||||
if p.parameter.Type == "array" {
|
||||
return p.setSliceFieldValue(target, p.parameter.Default, data, hasKey)
|
||||
}
|
||||
var d string
|
||||
if len(data) > 0 {
|
||||
d = data[len(data)-1]
|
||||
}
|
||||
return p.setFieldValue(target, p.parameter.Default, d, hasKey)
|
||||
}
|
||||
|
||||
func (p *untypedParamBinder) setFieldValue(target reflect.Value, defaultValue interface{}, data string, hasKey bool) error {
|
||||
tpe := p.parameter.Type
|
||||
if p.parameter.Format != "" {
|
||||
tpe = p.parameter.Format
|
||||
}
|
||||
|
||||
if (!hasKey || (!p.parameter.AllowEmptyValue && data == "")) && p.parameter.Required && p.parameter.Default == nil {
|
||||
return errors.Required(p.Name, p.parameter.In)
|
||||
}
|
||||
|
||||
ok, err := p.tryUnmarshaler(target, defaultValue, data)
|
||||
if err != nil {
|
||||
return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
|
||||
}
|
||||
if ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
defVal := reflect.Zero(target.Type())
|
||||
if defaultValue != nil {
|
||||
defVal = reflect.ValueOf(defaultValue)
|
||||
}
|
||||
|
||||
if tpe == "byte" {
|
||||
if data == "" {
|
||||
if target.CanSet() {
|
||||
target.SetBytes(defVal.Bytes())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
b, err := base64.StdEncoding.DecodeString(data)
|
||||
if err != nil {
|
||||
b, err = base64.URLEncoding.DecodeString(data)
|
||||
if err != nil {
|
||||
return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
|
||||
}
|
||||
}
|
||||
if target.CanSet() {
|
||||
target.SetBytes(b)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
switch target.Kind() {
|
||||
case reflect.Bool:
|
||||
if data == "" {
|
||||
if target.CanSet() {
|
||||
target.SetBool(defVal.Bool())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
b, err := swag.ConvertBool(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if target.CanSet() {
|
||||
target.SetBool(b)
|
||||
}
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
if data == "" {
|
||||
if target.CanSet() {
|
||||
rd := defVal.Convert(reflect.TypeOf(int64(0)))
|
||||
target.SetInt(rd.Int())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
i, err := strconv.ParseInt(data, 10, 64)
|
||||
if err != nil {
|
||||
return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
|
||||
}
|
||||
if target.OverflowInt(i) {
|
||||
return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
|
||||
}
|
||||
if target.CanSet() {
|
||||
target.SetInt(i)
|
||||
}
|
||||
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
if data == "" {
|
||||
if target.CanSet() {
|
||||
rd := defVal.Convert(reflect.TypeOf(uint64(0)))
|
||||
target.SetUint(rd.Uint())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
u, err := strconv.ParseUint(data, 10, 64)
|
||||
if err != nil {
|
||||
return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
|
||||
}
|
||||
if target.OverflowUint(u) {
|
||||
return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
|
||||
}
|
||||
if target.CanSet() {
|
||||
target.SetUint(u)
|
||||
}
|
||||
|
||||
case reflect.Float32, reflect.Float64:
|
||||
if data == "" {
|
||||
if target.CanSet() {
|
||||
rd := defVal.Convert(reflect.TypeOf(float64(0)))
|
||||
target.SetFloat(rd.Float())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
f, err := strconv.ParseFloat(data, 64)
|
||||
if err != nil {
|
||||
return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
|
||||
}
|
||||
if target.OverflowFloat(f) {
|
||||
return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
|
||||
}
|
||||
if target.CanSet() {
|
||||
target.SetFloat(f)
|
||||
}
|
||||
|
||||
case reflect.String:
|
||||
value := data
|
||||
if value == "" {
|
||||
value = defVal.String()
|
||||
}
|
||||
// validate string
|
||||
if target.CanSet() {
|
||||
target.SetString(value)
|
||||
}
|
||||
|
||||
case reflect.Ptr:
|
||||
if data == "" && defVal.Kind() == reflect.Ptr {
|
||||
if target.CanSet() {
|
||||
target.Set(defVal)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
newVal := reflect.New(target.Type().Elem())
|
||||
if err := p.setFieldValue(reflect.Indirect(newVal), defVal, data, hasKey); err != nil {
|
||||
return err
|
||||
}
|
||||
if target.CanSet() {
|
||||
target.Set(newVal)
|
||||
}
|
||||
|
||||
default:
|
||||
return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *untypedParamBinder) tryUnmarshaler(target reflect.Value, defaultValue interface{}, data string) (bool, error) {
|
||||
if !target.CanSet() {
|
||||
return false, nil
|
||||
}
|
||||
// When a type implements encoding.TextUnmarshaler we'll use that instead of reflecting some more
|
||||
if reflect.PtrTo(target.Type()).Implements(textUnmarshalType) {
|
||||
if defaultValue != nil && len(data) == 0 {
|
||||
target.Set(reflect.ValueOf(defaultValue))
|
||||
return true, nil
|
||||
}
|
||||
value := reflect.New(target.Type())
|
||||
if err := value.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(data)); err != nil {
|
||||
return true, err
|
||||
}
|
||||
target.Set(reflect.Indirect(value))
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (p *untypedParamBinder) readFormattedSliceFieldValue(data string, target reflect.Value) ([]string, bool, error) {
|
||||
ok, err := p.tryUnmarshaler(target, p.parameter.Default, data)
|
||||
if err != nil {
|
||||
return nil, true, err
|
||||
}
|
||||
if ok {
|
||||
return nil, true, nil
|
||||
}
|
||||
|
||||
return swag.SplitByFormat(data, p.parameter.CollectionFormat), false, nil
|
||||
}
|
||||
|
||||
func (p *untypedParamBinder) setSliceFieldValue(target reflect.Value, defaultValue interface{}, data []string, hasKey bool) error {
|
||||
sz := len(data)
|
||||
if (!hasKey || (!p.parameter.AllowEmptyValue && (sz == 0 || (sz == 1 && data[0] == "")))) && p.parameter.Required && defaultValue == nil {
|
||||
return errors.Required(p.Name, p.parameter.In)
|
||||
}
|
||||
|
||||
defVal := reflect.Zero(target.Type())
|
||||
if defaultValue != nil {
|
||||
defVal = reflect.ValueOf(defaultValue)
|
||||
}
|
||||
|
||||
if !target.CanSet() {
|
||||
return nil
|
||||
}
|
||||
if sz == 0 {
|
||||
target.Set(defVal)
|
||||
return nil
|
||||
}
|
||||
|
||||
value := reflect.MakeSlice(reflect.SliceOf(target.Type().Elem()), sz, sz)
|
||||
|
||||
for i := 0; i < sz; i++ {
|
||||
if err := p.setFieldValue(value.Index(i), nil, data[i], hasKey); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
target.Set(value)
|
||||
|
||||
return nil
|
||||
}
|
||||
340
vendor/github.com/go-openapi/runtime/middleware/parameter_test.go
generated
vendored
Normal file
340
vendor/github.com/go-openapi/runtime/middleware/parameter_test.go
generated
vendored
Normal file
@@ -0,0 +1,340 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"math"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type email struct {
|
||||
Address string
|
||||
}
|
||||
|
||||
type paramFactory func(string) *spec.Parameter
|
||||
|
||||
var paramFactories = []paramFactory{
|
||||
spec.QueryParam,
|
||||
spec.HeaderParam,
|
||||
spec.PathParam,
|
||||
spec.FormDataParam,
|
||||
}
|
||||
|
||||
func np(param *spec.Parameter) *untypedParamBinder {
|
||||
return newUntypedParamBinder(*param, new(spec.Swagger), strfmt.Default)
|
||||
}
|
||||
|
||||
var stringItems = new(spec.Items)
|
||||
|
||||
func init() {
|
||||
stringItems.Type = "string"
|
||||
}
|
||||
|
||||
func testCollectionFormat(t *testing.T, param *spec.Parameter, valid bool) {
|
||||
binder := &untypedParamBinder{
|
||||
parameter: param,
|
||||
}
|
||||
_, _, _, err := binder.readValue(runtime.Values(nil), reflect.ValueOf(nil))
|
||||
if valid {
|
||||
assert.NoError(t, err)
|
||||
} else {
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, errors.InvalidCollectionFormat(param.Name, param.In, param.CollectionFormat), err)
|
||||
}
|
||||
}
|
||||
|
||||
func requiredError(param *spec.Parameter) *errors.Validation {
|
||||
return errors.Required(param.Name, param.In)
|
||||
}
|
||||
|
||||
func validateRequiredTest(t *testing.T, param *spec.Parameter, value reflect.Value) {
|
||||
|
||||
binder := np(param)
|
||||
err := binder.bindValue([]string{}, true, value)
|
||||
assert.Error(t, err)
|
||||
assert.NotNil(t, param)
|
||||
assert.EqualError(t, requiredError(param), err.Error())
|
||||
err = binder.bindValue([]string{""}, true, value)
|
||||
if assert.Error(t, err) {
|
||||
assert.EqualError(t, requiredError(param), err.Error())
|
||||
}
|
||||
|
||||
// should be impossible data, but let's go with it
|
||||
err = binder.bindValue([]string{"a"}, false, value)
|
||||
assert.Error(t, err)
|
||||
assert.EqualError(t, requiredError(param), err.Error())
|
||||
err = binder.bindValue([]string{""}, false, value)
|
||||
assert.Error(t, err)
|
||||
assert.EqualError(t, requiredError(param), err.Error())
|
||||
}
|
||||
|
||||
func validateRequiredAllowEmptyTest(t *testing.T, param *spec.Parameter, value reflect.Value) {
|
||||
param.AllowEmptyValue = true
|
||||
binder := np(param)
|
||||
err := binder.bindValue([]string{}, true, value)
|
||||
assert.NoError(t, err)
|
||||
if assert.NotNil(t, param) {
|
||||
err = binder.bindValue([]string{""}, true, value)
|
||||
assert.NoError(t, err)
|
||||
err = binder.bindValue([]string{"1"}, false, value)
|
||||
assert.Error(t, err)
|
||||
assert.EqualError(t, requiredError(param), err.Error())
|
||||
err = binder.bindValue([]string{""}, false, value)
|
||||
assert.Error(t, err)
|
||||
assert.EqualError(t, requiredError(param), err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequiredValidation(t *testing.T) {
|
||||
strParam := spec.QueryParam("name").Typed("string", "").AsRequired()
|
||||
validateRequiredTest(t, strParam, reflect.ValueOf(""))
|
||||
validateRequiredAllowEmptyTest(t, strParam, reflect.ValueOf(""))
|
||||
|
||||
intParam := spec.QueryParam("id").Typed("integer", "int32").AsRequired()
|
||||
validateRequiredTest(t, intParam, reflect.ValueOf(int32(0)))
|
||||
validateRequiredAllowEmptyTest(t, intParam, reflect.ValueOf(int32(0)))
|
||||
longParam := spec.QueryParam("id").Typed("integer", "int64").AsRequired()
|
||||
validateRequiredTest(t, longParam, reflect.ValueOf(int64(0)))
|
||||
validateRequiredAllowEmptyTest(t, longParam, reflect.ValueOf(int64(0)))
|
||||
|
||||
floatParam := spec.QueryParam("score").Typed("number", "float").AsRequired()
|
||||
validateRequiredTest(t, floatParam, reflect.ValueOf(float32(0)))
|
||||
validateRequiredAllowEmptyTest(t, floatParam, reflect.ValueOf(float32(0)))
|
||||
doubleParam := spec.QueryParam("score").Typed("number", "double").AsRequired()
|
||||
validateRequiredTest(t, doubleParam, reflect.ValueOf(float64(0)))
|
||||
validateRequiredAllowEmptyTest(t, doubleParam, reflect.ValueOf(float64(0)))
|
||||
|
||||
dateTimeParam := spec.QueryParam("registered").Typed("string", "date-time").AsRequired()
|
||||
validateRequiredTest(t, dateTimeParam, reflect.ValueOf(strfmt.DateTime{}))
|
||||
// validateRequiredAllowEmptyTest(t, dateTimeParam, reflect.ValueOf(strfmt.DateTime{}))
|
||||
|
||||
dateParam := spec.QueryParam("registered").Typed("string", "date").AsRequired()
|
||||
validateRequiredTest(t, dateParam, reflect.ValueOf(strfmt.Date{}))
|
||||
// validateRequiredAllowEmptyTest(t, dateParam, reflect.ValueOf(strfmt.DateTime{}))
|
||||
|
||||
sliceParam := spec.QueryParam("tags").CollectionOf(stringItems, "").AsRequired()
|
||||
validateRequiredTest(t, sliceParam, reflect.MakeSlice(reflect.TypeOf([]string{}), 0, 0))
|
||||
validateRequiredAllowEmptyTest(t, sliceParam, reflect.MakeSlice(reflect.TypeOf([]string{}), 0, 0))
|
||||
}
|
||||
|
||||
func TestInvalidCollectionFormat(t *testing.T) {
|
||||
validCf1 := spec.QueryParam("validFmt").CollectionOf(stringItems, "multi")
|
||||
validCf2 := spec.FormDataParam("validFmt2").CollectionOf(stringItems, "multi")
|
||||
invalidCf1 := spec.HeaderParam("invalidHdr").CollectionOf(stringItems, "multi")
|
||||
invalidCf2 := spec.PathParam("invalidPath").CollectionOf(stringItems, "multi")
|
||||
|
||||
testCollectionFormat(t, validCf1, true)
|
||||
testCollectionFormat(t, validCf2, true)
|
||||
testCollectionFormat(t, invalidCf1, false)
|
||||
testCollectionFormat(t, invalidCf2, false)
|
||||
}
|
||||
|
||||
func invalidTypeError(param *spec.Parameter, data interface{}) *errors.Validation {
|
||||
tpe := param.Type
|
||||
if param.Format != "" {
|
||||
tpe = param.Format
|
||||
}
|
||||
return errors.InvalidType(param.Name, param.In, tpe, data)
|
||||
}
|
||||
|
||||
func TestTypeValidation(t *testing.T) {
|
||||
for _, newParam := range paramFactories {
|
||||
intParam := newParam("badInt").Typed("integer", "int32")
|
||||
value := reflect.ValueOf(int32(0))
|
||||
binder := np(intParam)
|
||||
err := binder.bindValue([]string{"yada"}, true, value)
|
||||
// fails for invalid string
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, invalidTypeError(intParam, "yada"), err)
|
||||
// fails for overflow
|
||||
val := int64(math.MaxInt32)
|
||||
str := strconv.FormatInt(val, 10) + "0"
|
||||
v := int32(0)
|
||||
value = reflect.ValueOf(&v).Elem()
|
||||
binder = np(intParam)
|
||||
err = binder.bindValue([]string{str}, true, value)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, invalidTypeError(intParam, str), err)
|
||||
|
||||
longParam := newParam("badLong").Typed("integer", "int64")
|
||||
value = reflect.ValueOf(int64(0))
|
||||
binder = np(longParam)
|
||||
err = binder.bindValue([]string{"yada"}, true, value)
|
||||
// fails for invalid string
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, invalidTypeError(longParam, "yada"), err)
|
||||
// fails for overflow
|
||||
str2 := strconv.FormatInt(math.MaxInt64, 10) + "0"
|
||||
v2 := int64(0)
|
||||
vv2 := reflect.ValueOf(&v2).Elem()
|
||||
binder = np(longParam)
|
||||
err = binder.bindValue([]string{str2}, true, vv2)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, invalidTypeError(longParam, str2), err)
|
||||
|
||||
floatParam := newParam("badFloat").Typed("number", "float")
|
||||
value = reflect.ValueOf(float64(0))
|
||||
binder = np(floatParam)
|
||||
err = binder.bindValue([]string{"yada"}, true, value)
|
||||
// fails for invalid string
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, invalidTypeError(floatParam, "yada"), err)
|
||||
// fails for overflow
|
||||
str3 := strconv.FormatFloat(math.MaxFloat64, 'f', 5, 64)
|
||||
v3 := reflect.TypeOf(float32(0))
|
||||
value = reflect.New(v3).Elem()
|
||||
binder = np(floatParam)
|
||||
err = binder.bindValue([]string{str3}, true, value)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, invalidTypeError(floatParam, str3), err)
|
||||
|
||||
doubleParam := newParam("badDouble").Typed("number", "double")
|
||||
value = reflect.ValueOf(float64(0))
|
||||
binder = np(doubleParam)
|
||||
err = binder.bindValue([]string{"yada"}, true, value)
|
||||
// fails for invalid string
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, invalidTypeError(doubleParam, "yada"), err)
|
||||
// fails for overflow
|
||||
str4 := "9" + strconv.FormatFloat(math.MaxFloat64, 'f', 5, 64)
|
||||
v4 := reflect.TypeOf(float64(0))
|
||||
value = reflect.New(v4).Elem()
|
||||
binder = np(doubleParam)
|
||||
err = binder.bindValue([]string{str4}, true, value)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, invalidTypeError(doubleParam, str4), err)
|
||||
|
||||
dateParam := newParam("badDate").Typed("string", "date")
|
||||
value = reflect.ValueOf(strfmt.Date{})
|
||||
binder = np(dateParam)
|
||||
err = binder.bindValue([]string{"yada"}, true, value)
|
||||
// fails for invalid string
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, invalidTypeError(dateParam, "yada"), err)
|
||||
|
||||
dateTimeParam := newParam("badDateTime").Typed("string", "date-time")
|
||||
value = reflect.ValueOf(strfmt.DateTime{})
|
||||
binder = np(dateTimeParam)
|
||||
err = binder.bindValue([]string{"yada"}, true, value)
|
||||
// fails for invalid string
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, invalidTypeError(dateTimeParam, "yada"), err)
|
||||
|
||||
byteParam := newParam("badByte").Typed("string", "byte")
|
||||
values := url.Values(map[string][]string{})
|
||||
values.Add("badByte", "yaüda")
|
||||
v5 := []byte{}
|
||||
value = reflect.ValueOf(&v5).Elem()
|
||||
binder = np(byteParam)
|
||||
err = binder.bindValue([]string{"yaüda"}, true, value)
|
||||
// fails for invalid string
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, invalidTypeError(byteParam, "yaüda"), err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeDetectionInvalidItems(t *testing.T) {
|
||||
withoutItems := spec.QueryParam("without").CollectionOf(nil, "")
|
||||
binder := &untypedParamBinder{
|
||||
Name: "without",
|
||||
parameter: withoutItems,
|
||||
}
|
||||
assert.Nil(t, binder.Type())
|
||||
|
||||
items := new(spec.Items)
|
||||
items.Type = "array"
|
||||
withInvalidItems := spec.QueryParam("invalidItems").CollectionOf(items, "")
|
||||
binder = &untypedParamBinder{
|
||||
Name: "invalidItems",
|
||||
parameter: withInvalidItems,
|
||||
}
|
||||
assert.Nil(t, binder.Type())
|
||||
|
||||
noType := spec.QueryParam("invalidType")
|
||||
noType.Type = "invalid"
|
||||
binder = &untypedParamBinder{
|
||||
Name: "invalidType",
|
||||
parameter: noType,
|
||||
}
|
||||
assert.Nil(t, binder.Type())
|
||||
}
|
||||
|
||||
// type emailStrFmt struct {
|
||||
// name string
|
||||
// tpe reflect.Type
|
||||
// validator FormatValidator
|
||||
// }
|
||||
//
|
||||
// func (e *emailStrFmt) Name() string {
|
||||
// return e.name
|
||||
// }
|
||||
//
|
||||
// func (e *emailStrFmt) Type() reflect.Type {
|
||||
// return e.tpe
|
||||
// }
|
||||
//
|
||||
// func (e *emailStrFmt) Matches(str string) bool {
|
||||
// return e.validator(str)
|
||||
// }
|
||||
//
|
||||
// func TestTypeDetectionValid(t *testing.T) {
|
||||
// // emlFmt := &emailStrFmt{
|
||||
// // name: "email",
|
||||
// // tpe: reflect.TypeOf(email{}),
|
||||
// // }
|
||||
// // formats := []StringFormat{emlFmt}
|
||||
//
|
||||
// expected := map[string]reflect.Type{
|
||||
// "name": reflect.TypeOf(""),
|
||||
// "id": reflect.TypeOf(int64(0)),
|
||||
// "age": reflect.TypeOf(int32(0)),
|
||||
// "score": reflect.TypeOf(float32(0)),
|
||||
// "factor": reflect.TypeOf(float64(0)),
|
||||
// "friend": reflect.TypeOf(map[string]interface{}{}),
|
||||
// "X-Request-Id": reflect.TypeOf(int64(0)),
|
||||
// "tags": reflect.TypeOf([]string{}),
|
||||
// "confirmed": reflect.TypeOf(true),
|
||||
// "planned": reflect.TypeOf(swagger.Date{}),
|
||||
// "delivered": reflect.TypeOf(swagger.DateTime{}),
|
||||
// "email": reflect.TypeOf(email{}),
|
||||
// "picture": reflect.TypeOf([]byte{}),
|
||||
// "file": reflect.TypeOf(&swagger.File{}).Elem(),
|
||||
// }
|
||||
//
|
||||
// params := parametersForAllTypes("")
|
||||
// emailParam := spec.QueryParam("email").Typed("string", "email")
|
||||
// params["email"] = *emailParam
|
||||
//
|
||||
// fileParam := spec.FileParam("file")
|
||||
// params["file"] = *fileParam
|
||||
//
|
||||
// for _, v := range params {
|
||||
// binder := ¶mBinder{
|
||||
// formats: formats,
|
||||
// name: v.Name,
|
||||
// parameter: &v,
|
||||
// }
|
||||
// assert.Equal(t, expected[v.Name], binder.Type(), "name: %s", v.Name)
|
||||
// }
|
||||
// }
|
||||
101
vendor/github.com/go-openapi/runtime/middleware/redoc.go
generated
vendored
Normal file
101
vendor/github.com/go-openapi/runtime/middleware/redoc.go
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"path"
|
||||
)
|
||||
|
||||
// RedocOpts configures the Redoc middlewares
|
||||
type RedocOpts struct {
|
||||
// BasePath for the UI path, defaults to: /
|
||||
BasePath string
|
||||
// Path combines with BasePath for the full UI path, defaults to: docs
|
||||
Path string
|
||||
// SpecURL the url to find the spec for
|
||||
SpecURL string
|
||||
// RedocURL for the js that generates the redoc site, defaults to: https://rebilly.github.io/ReDoc/releases/latest/redoc.min.js
|
||||
RedocURL string
|
||||
// Title for the documentation site, default to: API documentation
|
||||
Title string
|
||||
}
|
||||
|
||||
// EnsureDefaults in case some options are missing
|
||||
func (r *RedocOpts) EnsureDefaults() {
|
||||
if r.BasePath == "" {
|
||||
r.BasePath = "/"
|
||||
}
|
||||
if r.Path == "" {
|
||||
r.Path = "docs"
|
||||
}
|
||||
if r.SpecURL == "" {
|
||||
r.SpecURL = "/swagger.json"
|
||||
}
|
||||
if r.RedocURL == "" {
|
||||
r.RedocURL = redocLatest
|
||||
}
|
||||
if r.Title == "" {
|
||||
r.Title = "API documentation"
|
||||
}
|
||||
}
|
||||
|
||||
// Redoc creates a middleware to serve a documentation site for a swagger spec.
|
||||
// This allows for altering the spec before starting the http listener.
|
||||
//
|
||||
func Redoc(opts RedocOpts, next http.Handler) http.Handler {
|
||||
opts.EnsureDefaults()
|
||||
|
||||
pth := path.Join(opts.BasePath, opts.Path)
|
||||
tmpl := template.Must(template.New("redoc").Parse(redocTemplate))
|
||||
|
||||
buf := bytes.NewBuffer(nil)
|
||||
tmpl.Execute(buf, opts)
|
||||
b := buf.Bytes()
|
||||
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == pth {
|
||||
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
|
||||
rw.Write(b)
|
||||
return
|
||||
}
|
||||
|
||||
if next == nil {
|
||||
rw.Header().Set("Content-Type", "text/plain")
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
rw.Write([]byte(fmt.Sprintf("%q not found", pth)))
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(rw, r)
|
||||
})
|
||||
}
|
||||
|
||||
const (
|
||||
redocLatest = "https://rebilly.github.io/ReDoc/releases/latest/redoc.min.js"
|
||||
redocTemplate = `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{ .Title }}</title>
|
||||
<!-- needed for adaptive design -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!--
|
||||
ReDoc doesn't change outer page styles
|
||||
-->
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<redoc spec-url='{{ .SpecURL }}'></redoc>
|
||||
<script src="{{ .RedocURL }}"> </script>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
)
|
||||
22
vendor/github.com/go-openapi/runtime/middleware/redoc_test.go
generated
vendored
Normal file
22
vendor/github.com/go-openapi/runtime/middleware/redoc_test.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRedocMiddleware(t *testing.T) {
|
||||
redoc := Redoc(RedocOpts{}, nil)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/docs", nil)
|
||||
recorder := httptest.NewRecorder()
|
||||
redoc.ServeHTTP(recorder, req)
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
assert.Equal(t, "text/html; charset=utf-8", recorder.Header().Get("Content-Type"))
|
||||
assert.Contains(t, recorder.Body.String(), "<title>API documentation</title>")
|
||||
assert.Contains(t, recorder.Body.String(), "<redoc spec-url='/swagger.json'></redoc>")
|
||||
assert.Contains(t, recorder.Body.String(), redocLatest)
|
||||
}
|
||||
104
vendor/github.com/go-openapi/runtime/middleware/request.go
generated
vendored
Normal file
104
vendor/github.com/go-openapi/runtime/middleware/request.go
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// RequestBinder binds and validates the data from a http request
|
||||
type untypedRequestBinder struct {
|
||||
Spec *spec.Swagger
|
||||
Parameters map[string]spec.Parameter
|
||||
Formats strfmt.Registry
|
||||
paramBinders map[string]*untypedParamBinder
|
||||
}
|
||||
|
||||
// NewRequestBinder creates a new binder for reading a request.
|
||||
func newUntypedRequestBinder(parameters map[string]spec.Parameter, spec *spec.Swagger, formats strfmt.Registry) *untypedRequestBinder {
|
||||
binders := make(map[string]*untypedParamBinder)
|
||||
for fieldName, param := range parameters {
|
||||
binders[fieldName] = newUntypedParamBinder(param, spec, formats)
|
||||
}
|
||||
return &untypedRequestBinder{
|
||||
Parameters: parameters,
|
||||
paramBinders: binders,
|
||||
Spec: spec,
|
||||
Formats: formats,
|
||||
}
|
||||
}
|
||||
|
||||
// Bind perform the databinding and validation
|
||||
func (o *untypedRequestBinder) Bind(request *http.Request, routeParams RouteParams, consumer runtime.Consumer, data interface{}) error {
|
||||
val := reflect.Indirect(reflect.ValueOf(data))
|
||||
isMap := val.Kind() == reflect.Map
|
||||
var result []error
|
||||
debugLog("binding %d parameters for %s %s", len(o.Parameters), request.Method, request.URL.EscapedPath())
|
||||
for fieldName, param := range o.Parameters {
|
||||
binder := o.paramBinders[fieldName]
|
||||
debugLog("binding paramter %s for %s %s", fieldName, request.Method, request.URL.EscapedPath())
|
||||
var target reflect.Value
|
||||
if !isMap {
|
||||
binder.Name = fieldName
|
||||
target = val.FieldByName(fieldName)
|
||||
}
|
||||
|
||||
if isMap {
|
||||
tpe := binder.Type()
|
||||
if tpe == nil {
|
||||
if param.Schema.Type.Contains("array") {
|
||||
tpe = reflect.TypeOf([]interface{}{})
|
||||
} else {
|
||||
tpe = reflect.TypeOf(map[string]interface{}{})
|
||||
}
|
||||
}
|
||||
target = reflect.Indirect(reflect.New(tpe))
|
||||
|
||||
}
|
||||
|
||||
if !target.IsValid() {
|
||||
result = append(result, errors.New(500, "parameter name %q is an unknown field", binder.Name))
|
||||
continue
|
||||
}
|
||||
|
||||
if err := binder.Bind(request, routeParams, consumer, target); err != nil {
|
||||
result = append(result, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if binder.validator != nil {
|
||||
rr := binder.validator.Validate(target.Interface())
|
||||
if rr != nil && rr.HasErrors() {
|
||||
result = append(result, rr.AsError())
|
||||
}
|
||||
}
|
||||
|
||||
if isMap {
|
||||
val.SetMapIndex(reflect.ValueOf(param.Name), target)
|
||||
}
|
||||
}
|
||||
|
||||
if len(result) > 0 {
|
||||
return errors.CompositeValidationError(result...)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
481
vendor/github.com/go-openapi/runtime/middleware/request_test.go
generated
vendored
Normal file
481
vendor/github.com/go-openapi/runtime/middleware/request_test.go
generated
vendored
Normal file
@@ -0,0 +1,481 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type stubConsumer struct {
|
||||
}
|
||||
|
||||
func (s *stubConsumer) Consume(_ io.Reader, _ interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type friend struct {
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
}
|
||||
|
||||
type jsonRequestParams struct {
|
||||
ID int64 // path
|
||||
Name string // query
|
||||
Friend friend // body
|
||||
RequestID int64 // header
|
||||
Tags []string // csv
|
||||
}
|
||||
|
||||
type jsonRequestPtr struct {
|
||||
ID int64 // path
|
||||
Name string // query
|
||||
RequestID int64 // header
|
||||
Tags []string // csv
|
||||
Friend *friend
|
||||
}
|
||||
|
||||
type jsonRequestSlice struct {
|
||||
ID int64 // path
|
||||
Name string // query
|
||||
RequestID int64 // header
|
||||
Tags []string // csv
|
||||
Friend []friend
|
||||
}
|
||||
|
||||
type jsonRequestAllTypes struct {
|
||||
Confirmed bool
|
||||
Planned strfmt.Date
|
||||
Delivered strfmt.DateTime
|
||||
Age int32
|
||||
ID int64
|
||||
Score float32
|
||||
Factor float64
|
||||
Friend friend
|
||||
Name string
|
||||
Tags []string
|
||||
Picture []byte
|
||||
RequestID int64
|
||||
}
|
||||
|
||||
func parametersForAllTypes(fmt string) map[string]spec.Parameter {
|
||||
if fmt == "" {
|
||||
fmt = "csv"
|
||||
}
|
||||
nameParam := spec.QueryParam("name").Typed("string", "")
|
||||
idParam := spec.PathParam("id").Typed("integer", "int64")
|
||||
ageParam := spec.QueryParam("age").Typed("integer", "int32")
|
||||
scoreParam := spec.QueryParam("score").Typed("number", "float")
|
||||
factorParam := spec.QueryParam("factor").Typed("number", "double")
|
||||
|
||||
friendSchema := new(spec.Schema).Typed("object", "")
|
||||
friendParam := spec.BodyParam("friend", friendSchema)
|
||||
|
||||
requestIDParam := spec.HeaderParam("X-Request-Id").Typed("integer", "int64")
|
||||
requestIDParam.Extensions = spec.Extensions(map[string]interface{}{})
|
||||
requestIDParam.Extensions.Add("go-name", "RequestID")
|
||||
|
||||
items := new(spec.Items)
|
||||
items.Type = "string"
|
||||
tagsParam := spec.QueryParam("tags").CollectionOf(items, fmt)
|
||||
|
||||
confirmedParam := spec.QueryParam("confirmed").Typed("boolean", "")
|
||||
plannedParam := spec.QueryParam("planned").Typed("string", "date")
|
||||
deliveredParam := spec.QueryParam("delivered").Typed("string", "date-time")
|
||||
pictureParam := spec.QueryParam("picture").Typed("string", "byte") // base64 encoded during transport
|
||||
|
||||
return map[string]spec.Parameter{
|
||||
"ID": *idParam,
|
||||
"Name": *nameParam,
|
||||
"RequestID": *requestIDParam,
|
||||
"Friend": *friendParam,
|
||||
"Tags": *tagsParam,
|
||||
"Age": *ageParam,
|
||||
"Score": *scoreParam,
|
||||
"Factor": *factorParam,
|
||||
"Confirmed": *confirmedParam,
|
||||
"Planned": *plannedParam,
|
||||
"Delivered": *deliveredParam,
|
||||
"Picture": *pictureParam,
|
||||
}
|
||||
}
|
||||
|
||||
func parametersForJSONRequestParams(fmt string) map[string]spec.Parameter {
|
||||
if fmt == "" {
|
||||
fmt = "csv"
|
||||
}
|
||||
nameParam := spec.QueryParam("name").Typed("string", "")
|
||||
idParam := spec.PathParam("id").Typed("integer", "int64")
|
||||
|
||||
friendSchema := new(spec.Schema).Typed("object", "")
|
||||
friendParam := spec.BodyParam("friend", friendSchema)
|
||||
|
||||
requestIDParam := spec.HeaderParam("X-Request-Id").Typed("integer", "int64")
|
||||
requestIDParam.Extensions = spec.Extensions(map[string]interface{}{})
|
||||
requestIDParam.Extensions.Add("go-name", "RequestID")
|
||||
|
||||
items := new(spec.Items)
|
||||
items.Type = "string"
|
||||
tagsParam := spec.QueryParam("tags").CollectionOf(items, fmt)
|
||||
|
||||
return map[string]spec.Parameter{
|
||||
"ID": *idParam,
|
||||
"Name": *nameParam,
|
||||
"RequestID": *requestIDParam,
|
||||
"Friend": *friendParam,
|
||||
"Tags": *tagsParam,
|
||||
}
|
||||
}
|
||||
func parametersForJSONRequestSliceParams(fmt string) map[string]spec.Parameter {
|
||||
if fmt == "" {
|
||||
fmt = "csv"
|
||||
}
|
||||
nameParam := spec.QueryParam("name").Typed("string", "")
|
||||
idParam := spec.PathParam("id").Typed("integer", "int64")
|
||||
|
||||
friendSchema := new(spec.Schema).Typed("object", "")
|
||||
friendParam := spec.BodyParam("friend", spec.ArrayProperty(friendSchema))
|
||||
|
||||
requestIDParam := spec.HeaderParam("X-Request-Id").Typed("integer", "int64")
|
||||
requestIDParam.Extensions = spec.Extensions(map[string]interface{}{})
|
||||
requestIDParam.Extensions.Add("go-name", "RequestID")
|
||||
|
||||
items := new(spec.Items)
|
||||
items.Type = "string"
|
||||
tagsParam := spec.QueryParam("tags").CollectionOf(items, fmt)
|
||||
|
||||
return map[string]spec.Parameter{
|
||||
"ID": *idParam,
|
||||
"Name": *nameParam,
|
||||
"RequestID": *requestIDParam,
|
||||
"Friend": *friendParam,
|
||||
"Tags": *tagsParam,
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequestBindingDefaultValue(t *testing.T) {
|
||||
confirmed := true
|
||||
name := "thomas"
|
||||
friend := map[string]interface{}{"name": "toby", "age": float64(32)}
|
||||
id, age, score, factor := int64(7575), int32(348), float32(5.309), float64(37.403)
|
||||
requestID := 19394858
|
||||
tags := []string{"one", "two", "three"}
|
||||
dt1 := time.Date(2014, 8, 9, 0, 0, 0, 0, time.UTC)
|
||||
planned := strfmt.Date(dt1)
|
||||
dt2 := time.Date(2014, 10, 12, 8, 5, 5, 0, time.UTC)
|
||||
delivered := strfmt.DateTime(dt2)
|
||||
uri, _ := url.Parse("http://localhost:8002/hello")
|
||||
defaults := map[string]interface{}{
|
||||
"id": id,
|
||||
"age": age,
|
||||
"score": score,
|
||||
"factor": factor,
|
||||
"name": name,
|
||||
"friend": friend,
|
||||
"X-Request-Id": requestID,
|
||||
"tags": tags,
|
||||
"confirmed": confirmed,
|
||||
"planned": planned,
|
||||
"delivered": delivered,
|
||||
"picture": []byte("hello"),
|
||||
}
|
||||
op2 := parametersForAllTypes("")
|
||||
op3 := make(map[string]spec.Parameter)
|
||||
for k, p := range op2 {
|
||||
p.Default = defaults[p.Name]
|
||||
op3[k] = p
|
||||
}
|
||||
|
||||
req, _ := http.NewRequest("POST", uri.String(), bytes.NewBuffer(nil))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
binder := newUntypedRequestBinder(op3, new(spec.Swagger), strfmt.Default)
|
||||
|
||||
data := make(map[string]interface{})
|
||||
err := binder.Bind(req, RouteParams(nil), runtime.JSONConsumer(), &data)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, defaults["id"], data["id"])
|
||||
assert.Equal(t, name, data["name"])
|
||||
assert.Equal(t, friend, data["friend"])
|
||||
assert.EqualValues(t, requestID, data["X-Request-Id"])
|
||||
assert.Equal(t, tags, data["tags"])
|
||||
assert.Equal(t, planned, data["planned"])
|
||||
assert.Equal(t, delivered, data["delivered"])
|
||||
assert.Equal(t, confirmed, data["confirmed"])
|
||||
assert.Equal(t, age, data["age"])
|
||||
assert.Equal(t, factor, data["factor"])
|
||||
assert.Equal(t, score, data["score"])
|
||||
assert.Equal(t, "hello", string(data["picture"].(strfmt.Base64)))
|
||||
}
|
||||
|
||||
func TestRequestBindingForInvalid(t *testing.T) {
|
||||
|
||||
invalidParam := spec.QueryParam("some")
|
||||
|
||||
op1 := map[string]spec.Parameter{"Some": *invalidParam}
|
||||
|
||||
binder := newUntypedRequestBinder(op1, new(spec.Swagger), strfmt.Default)
|
||||
req, _ := http.NewRequest("GET", "http://localhost:8002/hello?name=the-name", nil)
|
||||
|
||||
err := binder.Bind(req, nil, new(stubConsumer), new(jsonRequestParams))
|
||||
assert.Error(t, err)
|
||||
|
||||
op2 := parametersForJSONRequestParams("")
|
||||
binder = newUntypedRequestBinder(op2, new(spec.Swagger), strfmt.Default)
|
||||
|
||||
req, _ = http.NewRequest("POST", "http://localhost:8002/hello/1?name=the-name", bytes.NewBuffer([]byte(`{"name":"toby","age":32}`)))
|
||||
req.Header.Set("Content-Type", "application(")
|
||||
data := jsonRequestParams{}
|
||||
err = binder.Bind(req, RouteParams([]RouteParam{{"id", "1"}}), runtime.JSONConsumer(), &data)
|
||||
assert.Error(t, err)
|
||||
|
||||
req, _ = http.NewRequest("POST", "http://localhost:8002/hello/1?name=the-name", bytes.NewBuffer([]byte(`{]`)))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
data = jsonRequestParams{}
|
||||
err = binder.Bind(req, RouteParams([]RouteParam{{"id", "1"}}), runtime.JSONConsumer(), &data)
|
||||
assert.Error(t, err)
|
||||
|
||||
invalidMultiParam := spec.HeaderParam("tags").CollectionOf(new(spec.Items), "multi")
|
||||
op3 := map[string]spec.Parameter{"Tags": *invalidMultiParam}
|
||||
binder = newUntypedRequestBinder(op3, new(spec.Swagger), strfmt.Default)
|
||||
|
||||
req, _ = http.NewRequest("POST", "http://localhost:8002/hello/1?name=the-name", bytes.NewBuffer([]byte(`{}`)))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
data = jsonRequestParams{}
|
||||
err = binder.Bind(req, RouteParams([]RouteParam{{"id", "1"}}), runtime.JSONConsumer(), &data)
|
||||
assert.Error(t, err)
|
||||
|
||||
invalidMultiParam = spec.PathParam("").CollectionOf(new(spec.Items), "multi")
|
||||
|
||||
op4 := map[string]spec.Parameter{"Tags": *invalidMultiParam}
|
||||
binder = newUntypedRequestBinder(op4, new(spec.Swagger), strfmt.Default)
|
||||
|
||||
req, _ = http.NewRequest("POST", "http://localhost:8002/hello/1?name=the-name", bytes.NewBuffer([]byte(`{}`)))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
data = jsonRequestParams{}
|
||||
err = binder.Bind(req, RouteParams([]RouteParam{{"id", "1"}}), runtime.JSONConsumer(), &data)
|
||||
assert.Error(t, err)
|
||||
|
||||
invalidInParam := spec.HeaderParam("tags").Typed("string", "")
|
||||
invalidInParam.In = "invalid"
|
||||
op5 := map[string]spec.Parameter{"Tags": *invalidInParam}
|
||||
binder = newUntypedRequestBinder(op5, new(spec.Swagger), strfmt.Default)
|
||||
|
||||
req, _ = http.NewRequest("POST", "http://localhost:8002/hello/1?name=the-name", bytes.NewBuffer([]byte(`{}`)))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
data = jsonRequestParams{}
|
||||
err = binder.Bind(req, RouteParams([]RouteParam{{"id", "1"}}), runtime.JSONConsumer(), &data)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestRequestBindingForValid(t *testing.T) {
|
||||
|
||||
for _, fmt := range []string{"csv", "pipes", "tsv", "ssv", "multi"} {
|
||||
op1 := parametersForJSONRequestParams(fmt)
|
||||
|
||||
binder := newUntypedRequestBinder(op1, new(spec.Swagger), strfmt.Default)
|
||||
|
||||
lval := []string{"one", "two", "three"}
|
||||
queryString := ""
|
||||
switch fmt {
|
||||
case "multi":
|
||||
queryString = strings.Join(lval, "&tags=")
|
||||
case "ssv":
|
||||
queryString = strings.Join(lval, " ")
|
||||
case "pipes":
|
||||
queryString = strings.Join(lval, "|")
|
||||
case "tsv":
|
||||
queryString = strings.Join(lval, "\t")
|
||||
default:
|
||||
queryString = strings.Join(lval, ",")
|
||||
}
|
||||
|
||||
urlStr := "http://localhost:8002/hello/1?name=the-name&tags=" + queryString
|
||||
|
||||
req, _ := http.NewRequest("POST", urlStr, bytes.NewBuffer([]byte(`{"name":"toby","age":32}`)))
|
||||
req.Header.Set("Content-Type", "application/json;charset=utf-8")
|
||||
req.Header.Set("X-Request-Id", "1325959595")
|
||||
|
||||
data := jsonRequestParams{}
|
||||
err := binder.Bind(req, RouteParams([]RouteParam{{"id", "1"}}), runtime.JSONConsumer(), &data)
|
||||
|
||||
expected := jsonRequestParams{
|
||||
ID: 1,
|
||||
Name: "the-name",
|
||||
Friend: friend{"toby", 32},
|
||||
RequestID: 1325959595,
|
||||
Tags: []string{"one", "two", "three"},
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, data)
|
||||
}
|
||||
|
||||
op1 := parametersForJSONRequestParams("")
|
||||
|
||||
binder := newUntypedRequestBinder(op1, new(spec.Swagger), strfmt.Default)
|
||||
urlStr := "http://localhost:8002/hello/1?name=the-name&tags=one,two,three"
|
||||
req, _ := http.NewRequest("POST", urlStr, bytes.NewBuffer([]byte(`{"name":"toby","age":32}`)))
|
||||
req.Header.Set("Content-Type", "application/json;charset=utf-8")
|
||||
req.Header.Set("X-Request-Id", "1325959595")
|
||||
|
||||
data2 := jsonRequestPtr{}
|
||||
err := binder.Bind(req, []RouteParam{{"id", "1"}}, runtime.JSONConsumer(), &data2)
|
||||
|
||||
expected2 := jsonRequestPtr{
|
||||
Friend: &friend{"toby", 32},
|
||||
Tags: []string{"one", "two", "three"},
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
if data2.Friend == nil {
|
||||
t.Fatal("friend is nil")
|
||||
}
|
||||
assert.Equal(t, *expected2.Friend, *data2.Friend)
|
||||
assert.Equal(t, expected2.Tags, data2.Tags)
|
||||
|
||||
req, _ = http.NewRequest("POST", urlStr, bytes.NewBuffer([]byte(`[{"name":"toby","age":32}]`)))
|
||||
req.Header.Set("Content-Type", "application/json;charset=utf-8")
|
||||
req.Header.Set("X-Request-Id", "1325959595")
|
||||
op2 := parametersForJSONRequestSliceParams("")
|
||||
binder = newUntypedRequestBinder(op2, new(spec.Swagger), strfmt.Default)
|
||||
data3 := jsonRequestSlice{}
|
||||
err = binder.Bind(req, []RouteParam{{"id", "1"}}, runtime.JSONConsumer(), &data3)
|
||||
|
||||
expected3 := jsonRequestSlice{
|
||||
Friend: []friend{{"toby", 32}},
|
||||
Tags: []string{"one", "two", "three"},
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected3.Friend, data3.Friend)
|
||||
assert.Equal(t, expected3.Tags, data3.Tags)
|
||||
}
|
||||
|
||||
type formRequest struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
func parametersForFormUpload() map[string]spec.Parameter {
|
||||
nameParam := spec.FormDataParam("name").Typed("string", "")
|
||||
|
||||
ageParam := spec.FormDataParam("age").Typed("integer", "int32")
|
||||
|
||||
return map[string]spec.Parameter{"Name": *nameParam, "Age": *ageParam}
|
||||
}
|
||||
|
||||
func TestFormUpload(t *testing.T) {
|
||||
params := parametersForFormUpload()
|
||||
binder := newUntypedRequestBinder(params, new(spec.Swagger), strfmt.Default)
|
||||
|
||||
urlStr := "http://localhost:8002/hello"
|
||||
req, _ := http.NewRequest("POST", urlStr, bytes.NewBufferString(`name=the-name&age=32`))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
data := formRequest{}
|
||||
res := binder.Bind(req, nil, runtime.JSONConsumer(), &data)
|
||||
assert.NoError(t, res)
|
||||
assert.Equal(t, "the-name", data.Name)
|
||||
assert.Equal(t, 32, data.Age)
|
||||
|
||||
req, _ = http.NewRequest("POST", urlStr, bytes.NewBufferString(`name=%3&age=32`))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
data = formRequest{}
|
||||
assert.Error(t, binder.Bind(req, nil, runtime.JSONConsumer(), &data))
|
||||
}
|
||||
|
||||
type fileRequest struct {
|
||||
Name string // body
|
||||
File runtime.File // upload
|
||||
}
|
||||
|
||||
func paramsForFileUpload() *untypedRequestBinder {
|
||||
nameParam := spec.FormDataParam("name").Typed("string", "")
|
||||
|
||||
fileParam := spec.FileParam("file")
|
||||
|
||||
params := map[string]spec.Parameter{"Name": *nameParam, "File": *fileParam}
|
||||
return newUntypedRequestBinder(params, new(spec.Swagger), strfmt.Default)
|
||||
}
|
||||
|
||||
func TestBindingFileUpload(t *testing.T) {
|
||||
binder := paramsForFileUpload()
|
||||
|
||||
body := bytes.NewBuffer(nil)
|
||||
writer := multipart.NewWriter(body)
|
||||
part, err := writer.CreateFormFile("file", "plain-jane.txt")
|
||||
assert.NoError(t, err)
|
||||
|
||||
part.Write([]byte("the file contents"))
|
||||
writer.WriteField("name", "the-name")
|
||||
assert.NoError(t, writer.Close())
|
||||
|
||||
urlStr := "http://localhost:8002/hello"
|
||||
req, _ := http.NewRequest("POST", urlStr, body)
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
|
||||
data := fileRequest{}
|
||||
assert.NoError(t, binder.Bind(req, nil, runtime.JSONConsumer(), &data))
|
||||
assert.Equal(t, "the-name", data.Name)
|
||||
assert.NotNil(t, data.File)
|
||||
assert.NotNil(t, data.File.Header)
|
||||
assert.Equal(t, "plain-jane.txt", data.File.Header.Filename)
|
||||
|
||||
bb, err := ioutil.ReadAll(data.File.Data)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []byte("the file contents"), bb)
|
||||
|
||||
req, _ = http.NewRequest("POST", urlStr, body)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
data = fileRequest{}
|
||||
assert.Error(t, binder.Bind(req, nil, runtime.JSONConsumer(), &data))
|
||||
|
||||
req, _ = http.NewRequest("POST", urlStr, body)
|
||||
req.Header.Set("Content-Type", "application(")
|
||||
data = fileRequest{}
|
||||
assert.Error(t, binder.Bind(req, nil, runtime.JSONConsumer(), &data))
|
||||
|
||||
body = bytes.NewBuffer(nil)
|
||||
writer = multipart.NewWriter(body)
|
||||
part, err = writer.CreateFormFile("bad-name", "plain-jane.txt")
|
||||
assert.NoError(t, err)
|
||||
|
||||
part.Write([]byte("the file contents"))
|
||||
writer.WriteField("name", "the-name")
|
||||
assert.NoError(t, writer.Close())
|
||||
req, _ = http.NewRequest("POST", urlStr, body)
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
|
||||
data = fileRequest{}
|
||||
assert.Error(t, binder.Bind(req, nil, runtime.JSONConsumer(), &data))
|
||||
|
||||
req, _ = http.NewRequest("POST", urlStr, body)
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
req.MultipartReader()
|
||||
|
||||
data = fileRequest{}
|
||||
assert.Error(t, binder.Bind(req, nil, runtime.JSONConsumer(), &data))
|
||||
|
||||
}
|
||||
38
vendor/github.com/go-openapi/runtime/middleware/route_param_test.go
generated
vendored
Normal file
38
vendor/github.com/go-openapi/runtime/middleware/route_param_test.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRouteParams(t *testing.T) {
|
||||
coll1 := RouteParams([]RouteParam{
|
||||
{"blah", "foo"},
|
||||
{"abc", "bar"},
|
||||
{"ccc", "efg"},
|
||||
})
|
||||
|
||||
v := coll1.Get("blah")
|
||||
assert.Equal(t, v, "foo")
|
||||
v2 := coll1.Get("abc")
|
||||
assert.Equal(t, v2, "bar")
|
||||
v3 := coll1.Get("ccc")
|
||||
assert.Equal(t, v3, "efg")
|
||||
v4 := coll1.Get("ydkdk")
|
||||
assert.Empty(t, v4)
|
||||
}
|
||||
262
vendor/github.com/go-openapi/runtime/middleware/router.go
generated
vendored
Normal file
262
vendor/github.com/go-openapi/runtime/middleware/router.go
generated
vendored
Normal file
@@ -0,0 +1,262 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
fpath "path"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/analysis"
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/middleware/denco"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/gorilla/context"
|
||||
)
|
||||
|
||||
// RouteParam is a object to capture route params in a framework agnostic way.
|
||||
// implementations of the muxer should use these route params to communicate with the
|
||||
// swagger framework
|
||||
type RouteParam struct {
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
|
||||
// RouteParams the collection of route params
|
||||
type RouteParams []RouteParam
|
||||
|
||||
// Get gets the value for the route param for the specified key
|
||||
func (r RouteParams) Get(name string) string {
|
||||
vv, _, _ := r.GetOK(name)
|
||||
if len(vv) > 0 {
|
||||
return vv[len(vv)-1]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetOK gets the value but also returns booleans to indicate if a key or value
|
||||
// is present. This aids in validation and satisfies an interface in use there
|
||||
//
|
||||
// The returned values are: data, has key, has value
|
||||
func (r RouteParams) GetOK(name string) ([]string, bool, bool) {
|
||||
for _, p := range r {
|
||||
if p.Name == name {
|
||||
return []string{p.Value}, true, p.Value != ""
|
||||
}
|
||||
}
|
||||
return nil, false, false
|
||||
}
|
||||
|
||||
// NewRouter creates a new context aware router middleware
|
||||
func NewRouter(ctx *Context, next http.Handler) http.Handler {
|
||||
if ctx.router == nil {
|
||||
ctx.router = DefaultRouter(ctx.spec, ctx.api)
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
defer context.Clear(r)
|
||||
if _, ok := ctx.RouteInfo(r); ok {
|
||||
next.ServeHTTP(rw, r)
|
||||
return
|
||||
}
|
||||
|
||||
// Not found, check if it exists in the other methods first
|
||||
if others := ctx.AllowedMethods(r); len(others) > 0 {
|
||||
ctx.Respond(rw, r, ctx.analyzer.RequiredProduces(), nil, errors.MethodNotAllowed(r.Method, others))
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Respond(rw, r, ctx.analyzer.RequiredProduces(), nil, errors.NotFound("path %s was not found", r.URL.EscapedPath()))
|
||||
})
|
||||
}
|
||||
|
||||
// RoutableAPI represents an interface for things that can serve
|
||||
// as a provider of implementations for the swagger router
|
||||
type RoutableAPI interface {
|
||||
HandlerFor(string, string) (http.Handler, bool)
|
||||
ServeErrorFor(string) func(http.ResponseWriter, *http.Request, error)
|
||||
ConsumersFor([]string) map[string]runtime.Consumer
|
||||
ProducersFor([]string) map[string]runtime.Producer
|
||||
AuthenticatorsFor(map[string]spec.SecurityScheme) map[string]runtime.Authenticator
|
||||
Formats() strfmt.Registry
|
||||
DefaultProduces() string
|
||||
DefaultConsumes() string
|
||||
}
|
||||
|
||||
// Router represents a swagger aware router
|
||||
type Router interface {
|
||||
Lookup(method, path string) (*MatchedRoute, bool)
|
||||
OtherMethods(method, path string) []string
|
||||
}
|
||||
|
||||
type defaultRouteBuilder struct {
|
||||
spec *loads.Document
|
||||
analyzer *analysis.Spec
|
||||
api RoutableAPI
|
||||
records map[string][]denco.Record
|
||||
}
|
||||
|
||||
type defaultRouter struct {
|
||||
spec *loads.Document
|
||||
api RoutableAPI
|
||||
routers map[string]*denco.Router
|
||||
}
|
||||
|
||||
func newDefaultRouteBuilder(spec *loads.Document, api RoutableAPI) *defaultRouteBuilder {
|
||||
return &defaultRouteBuilder{
|
||||
spec: spec,
|
||||
analyzer: analysis.New(spec.Spec()),
|
||||
api: api,
|
||||
records: make(map[string][]denco.Record),
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultRouter creates a default implemenation of the router
|
||||
func DefaultRouter(spec *loads.Document, api RoutableAPI) Router {
|
||||
builder := newDefaultRouteBuilder(spec, api)
|
||||
if spec != nil {
|
||||
for method, paths := range builder.analyzer.Operations() {
|
||||
for path, operation := range paths {
|
||||
fp := fpath.Join(spec.BasePath(), path)
|
||||
debugLog("adding route %s %s %q", method, fp, operation.ID)
|
||||
builder.AddRoute(method, fp, operation)
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder.Build()
|
||||
}
|
||||
|
||||
type routeEntry struct {
|
||||
PathPattern string
|
||||
BasePath string
|
||||
Operation *spec.Operation
|
||||
Consumes []string
|
||||
Consumers map[string]runtime.Consumer
|
||||
Produces []string
|
||||
Producers map[string]runtime.Producer
|
||||
Parameters map[string]spec.Parameter
|
||||
Handler http.Handler
|
||||
Formats strfmt.Registry
|
||||
Binder *untypedRequestBinder
|
||||
Authenticators map[string]runtime.Authenticator
|
||||
Scopes map[string][]string
|
||||
}
|
||||
|
||||
// MatchedRoute represents the route that was matched in this request
|
||||
type MatchedRoute struct {
|
||||
routeEntry
|
||||
Params RouteParams
|
||||
Consumer runtime.Consumer
|
||||
Producer runtime.Producer
|
||||
}
|
||||
|
||||
func (d *defaultRouter) Lookup(method, path string) (*MatchedRoute, bool) {
|
||||
mth := strings.ToUpper(method)
|
||||
debugLog("looking up route for %s %s", method, path)
|
||||
if Debug {
|
||||
if len(d.routers) == 0 {
|
||||
debugLog("there are no known routers")
|
||||
}
|
||||
for meth := range d.routers {
|
||||
debugLog("got a router for %s", meth)
|
||||
}
|
||||
}
|
||||
if router, ok := d.routers[mth]; ok {
|
||||
if m, rp, ok := router.Lookup(path); ok && m != nil {
|
||||
if entry, ok := m.(*routeEntry); ok {
|
||||
debugLog("found a route for %s %s with %d parameters", method, path, len(entry.Parameters))
|
||||
var params RouteParams
|
||||
for _, p := range rp {
|
||||
params = append(params, RouteParam{Name: p.Name, Value: p.Value})
|
||||
}
|
||||
return &MatchedRoute{routeEntry: *entry, Params: params}, true
|
||||
}
|
||||
} else {
|
||||
debugLog("couldn't find a route by path for %s %s", method, path)
|
||||
}
|
||||
} else {
|
||||
debugLog("couldn't find a route by method for %s %s", method, path)
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (d *defaultRouter) OtherMethods(method, path string) []string {
|
||||
mn := strings.ToUpper(method)
|
||||
var methods []string
|
||||
for k, v := range d.routers {
|
||||
if k != mn {
|
||||
if _, _, ok := v.Lookup(path); ok {
|
||||
methods = append(methods, k)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
return methods
|
||||
}
|
||||
|
||||
var pathConverter = regexp.MustCompile(`{(\w+)}`)
|
||||
|
||||
func (d *defaultRouteBuilder) AddRoute(method, path string, operation *spec.Operation) {
|
||||
mn := strings.ToUpper(method)
|
||||
|
||||
bp := fpath.Clean(d.spec.BasePath())
|
||||
if len(bp) > 0 && bp[len(bp)-1] == '/' {
|
||||
bp = bp[:len(bp)-1]
|
||||
}
|
||||
|
||||
if handler, ok := d.api.HandlerFor(method, strings.TrimPrefix(path, bp)); ok {
|
||||
consumes := d.analyzer.ConsumesFor(operation)
|
||||
produces := d.analyzer.ProducesFor(operation)
|
||||
parameters := d.analyzer.ParamsFor(method, strings.TrimPrefix(path, bp))
|
||||
definitions := d.analyzer.SecurityDefinitionsFor(operation)
|
||||
requirements := d.analyzer.SecurityRequirementsFor(operation)
|
||||
scopes := make(map[string][]string, len(requirements))
|
||||
for _, v := range requirements {
|
||||
scopes[v.Name] = v.Scopes
|
||||
}
|
||||
|
||||
record := denco.NewRecord(pathConverter.ReplaceAllString(path, ":$1"), &routeEntry{
|
||||
Operation: operation,
|
||||
Handler: handler,
|
||||
Consumes: consumes,
|
||||
Produces: produces,
|
||||
Consumers: d.api.ConsumersFor(consumes),
|
||||
Producers: d.api.ProducersFor(produces),
|
||||
Parameters: parameters,
|
||||
Formats: d.api.Formats(),
|
||||
Binder: newUntypedRequestBinder(parameters, d.spec.Spec(), d.api.Formats()),
|
||||
Authenticators: d.api.AuthenticatorsFor(definitions),
|
||||
Scopes: scopes,
|
||||
})
|
||||
d.records[mn] = append(d.records[mn], record)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *defaultRouteBuilder) Build() *defaultRouter {
|
||||
routers := make(map[string]*denco.Router)
|
||||
for method, records := range d.records {
|
||||
router := denco.New()
|
||||
router.Build(records)
|
||||
routers[method] = router
|
||||
}
|
||||
return &defaultRouter{
|
||||
spec: d.spec,
|
||||
routers: routers,
|
||||
}
|
||||
}
|
||||
206
vendor/github.com/go-openapi/runtime/middleware/router_test.go
generated
vendored
Normal file
206
vendor/github.com/go-openapi/runtime/middleware/router_test.go
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/analysis"
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/go-openapi/runtime/internal/testing/petstore"
|
||||
"github.com/go-openapi/runtime/middleware/untyped"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func terminator(rw http.ResponseWriter, r *http.Request) {
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func TestRouterMiddleware(t *testing.T) {
|
||||
spec, api := petstore.NewAPI(t)
|
||||
context := NewContext(spec, api, nil)
|
||||
mw := NewRouter(context, http.HandlerFunc(terminator))
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
request, _ := http.NewRequest("GET", "/api/pets", nil)
|
||||
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
request, _ = http.NewRequest("DELETE", "/api/pets", nil)
|
||||
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, http.StatusMethodNotAllowed, recorder.Code)
|
||||
|
||||
methods := strings.Split(recorder.Header().Get("Allow"), ",")
|
||||
sort.Sort(sort.StringSlice(methods))
|
||||
assert.Equal(t, "GET,POST", strings.Join(methods, ","))
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
request, _ = http.NewRequest("GET", "/nopets", nil)
|
||||
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, http.StatusNotFound, recorder.Code)
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
request, _ = http.NewRequest("GET", "/pets", nil)
|
||||
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, http.StatusNotFound, recorder.Code)
|
||||
|
||||
spec, api = petstore.NewRootAPI(t)
|
||||
context = NewContext(spec, api, nil)
|
||||
mw = NewRouter(context, http.HandlerFunc(terminator))
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
request, _ = http.NewRequest("GET", "/pets", nil)
|
||||
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
request, _ = http.NewRequest("DELETE", "/pets", nil)
|
||||
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, http.StatusMethodNotAllowed, recorder.Code)
|
||||
|
||||
methods = strings.Split(recorder.Header().Get("Allow"), ",")
|
||||
sort.Sort(sort.StringSlice(methods))
|
||||
assert.Equal(t, "GET,POST", strings.Join(methods, ","))
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
request, _ = http.NewRequest("GET", "/nopets", nil)
|
||||
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, http.StatusNotFound, recorder.Code)
|
||||
|
||||
}
|
||||
|
||||
func TestRouterBuilder(t *testing.T) {
|
||||
spec, api := petstore.NewAPI(t)
|
||||
analyzed := analysis.New(spec.Spec())
|
||||
|
||||
assert.Len(t, analyzed.RequiredConsumes(), 3)
|
||||
assert.Len(t, analyzed.RequiredProduces(), 5)
|
||||
assert.Len(t, analyzed.OperationIDs(), 4)
|
||||
|
||||
// context := NewContext(spec, api)
|
||||
builder := petAPIRouterBuilder(spec, api, analyzed)
|
||||
getRecords := builder.records["GET"]
|
||||
postRecords := builder.records["POST"]
|
||||
deleteRecords := builder.records["DELETE"]
|
||||
|
||||
assert.Len(t, getRecords, 2)
|
||||
assert.Len(t, postRecords, 1)
|
||||
assert.Len(t, deleteRecords, 1)
|
||||
|
||||
assert.Empty(t, builder.records["PATCH"])
|
||||
assert.Empty(t, builder.records["OPTIONS"])
|
||||
assert.Empty(t, builder.records["HEAD"])
|
||||
assert.Empty(t, builder.records["PUT"])
|
||||
|
||||
rec := postRecords[0]
|
||||
assert.Equal(t, rec.Key, "/pets")
|
||||
val := rec.Value.(*routeEntry)
|
||||
assert.Len(t, val.Consumers, 1)
|
||||
assert.Len(t, val.Producers, 1)
|
||||
assert.Len(t, val.Consumes, 1)
|
||||
assert.Len(t, val.Produces, 1)
|
||||
|
||||
assert.Len(t, val.Parameters, 1)
|
||||
|
||||
recG := getRecords[0]
|
||||
assert.Equal(t, recG.Key, "/pets")
|
||||
valG := recG.Value.(*routeEntry)
|
||||
assert.Len(t, valG.Consumers, 2)
|
||||
assert.Len(t, valG.Producers, 4)
|
||||
assert.Len(t, valG.Consumes, 2)
|
||||
assert.Len(t, valG.Produces, 4)
|
||||
|
||||
assert.Len(t, valG.Parameters, 2)
|
||||
}
|
||||
|
||||
func TestRouterCanonicalBasePath(t *testing.T) {
|
||||
spec, api := petstore.NewAPI(t)
|
||||
spec.Spec().BasePath = "/api///"
|
||||
context := NewContext(spec, api, nil)
|
||||
mw := NewRouter(context, http.HandlerFunc(terminator))
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
request, _ := http.NewRequest("GET", "/api/pets", nil)
|
||||
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
}
|
||||
|
||||
func TestRouter_EscapedPath(t *testing.T) {
|
||||
spec, api := petstore.NewAPI(t)
|
||||
spec.Spec().BasePath = "/api/"
|
||||
context := NewContext(spec, api, nil)
|
||||
mw := NewRouter(context, http.HandlerFunc(terminator))
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
request, _ := http.NewRequest("GET", "/api/pets/123", nil)
|
||||
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
request, _ = http.NewRequest("GET", "/api/pets/abc%2Fdef", nil)
|
||||
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
ri, _ := context.RouteInfo(request)
|
||||
if assert.NotNil(t, ri) {
|
||||
if assert.NotNil(t, ri.Params) {
|
||||
assert.Equal(t, "abc%2Fdef", ri.Params.Get("id"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouterStruct(t *testing.T) {
|
||||
spec, api := petstore.NewAPI(t)
|
||||
router := DefaultRouter(spec, newRoutableUntypedAPI(spec, api, new(Context)))
|
||||
|
||||
methods := router.OtherMethods("post", "/api/pets/{id}")
|
||||
assert.Len(t, methods, 2)
|
||||
|
||||
entry, ok := router.Lookup("delete", "/api/pets/{id}")
|
||||
assert.True(t, ok)
|
||||
assert.NotNil(t, entry)
|
||||
assert.Len(t, entry.Params, 1)
|
||||
assert.Equal(t, "id", entry.Params[0].Name)
|
||||
|
||||
_, ok = router.Lookup("delete", "/pets")
|
||||
assert.False(t, ok)
|
||||
|
||||
_, ok = router.Lookup("post", "/no-pets")
|
||||
assert.False(t, ok)
|
||||
}
|
||||
|
||||
func petAPIRouterBuilder(spec *loads.Document, api *untyped.API, analyzed *analysis.Spec) *defaultRouteBuilder {
|
||||
builder := newDefaultRouteBuilder(spec, newRoutableUntypedAPI(spec, api, new(Context)))
|
||||
builder.AddRoute("GET", "/pets", analyzed.AllPaths()["/pets"].Get)
|
||||
builder.AddRoute("POST", "/pets", analyzed.AllPaths()["/pets"].Post)
|
||||
builder.AddRoute("DELETE", "/pets/{id}", analyzed.AllPaths()["/pets/{id}"].Delete)
|
||||
builder.AddRoute("GET", "/pets/{id}", analyzed.AllPaths()["/pets/{id}"].Get)
|
||||
|
||||
return builder
|
||||
}
|
||||
34
vendor/github.com/go-openapi/runtime/middleware/security.go
generated
vendored
Normal file
34
vendor/github.com/go-openapi/runtime/middleware/security.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package middleware
|
||||
|
||||
import "net/http"
|
||||
|
||||
func newSecureAPI(ctx *Context, next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
route, _ := ctx.RouteInfo(r)
|
||||
if route != nil && len(route.Authenticators) == 0 {
|
||||
next.ServeHTTP(rw, r)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := ctx.Authorize(r, route); err != nil {
|
||||
ctx.Respond(rw, r, route.Produces, route, err)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(rw, r)
|
||||
})
|
||||
}
|
||||
58
vendor/github.com/go-openapi/runtime/middleware/security_test.go
generated
vendored
Normal file
58
vendor/github.com/go-openapi/runtime/middleware/security_test.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/runtime/internal/testing/petstore"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSecurityMiddleware(t *testing.T) {
|
||||
spec, api := petstore.NewAPI(t)
|
||||
context := NewContext(spec, api, nil)
|
||||
context.router = DefaultRouter(spec, context.api)
|
||||
mw := newSecureAPI(context, http.HandlerFunc(terminator))
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
request, _ := http.NewRequest("GET", "/api/pets", nil)
|
||||
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, 401, recorder.Code)
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
request, _ = http.NewRequest("GET", "/api/pets", nil)
|
||||
request.SetBasicAuth("admin", "wrong")
|
||||
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, 401, recorder.Code)
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
request, _ = http.NewRequest("GET", "/api/pets", nil)
|
||||
request.SetBasicAuth("admin", "admin")
|
||||
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
request, _ = http.NewRequest("GET", "//apipets/1", nil)
|
||||
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
|
||||
}
|
||||
47
vendor/github.com/go-openapi/runtime/middleware/spec.go
generated
vendored
Normal file
47
vendor/github.com/go-openapi/runtime/middleware/spec.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"path"
|
||||
)
|
||||
|
||||
// Spec creates a middleware to serve a swagger spec.
|
||||
// This allows for altering the spec before starting the http listener.
|
||||
// This can be useful if you want to serve the swagger spec from another path than /swagger.json
|
||||
//
|
||||
func Spec(basePath string, b []byte, next http.Handler) http.Handler {
|
||||
if basePath == "" {
|
||||
basePath = "/"
|
||||
}
|
||||
pth := path.Join(basePath, "swagger.json")
|
||||
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == pth {
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
rw.Write(b)
|
||||
return
|
||||
}
|
||||
|
||||
if next == nil {
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(rw, r)
|
||||
})
|
||||
}
|
||||
56
vendor/github.com/go-openapi/runtime/middleware/spec_test.go
generated
vendored
Normal file
56
vendor/github.com/go-openapi/runtime/middleware/spec_test.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/internal/testing/petstore"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestServeSpecMiddleware(t *testing.T) {
|
||||
spec, api := petstore.NewAPI(t)
|
||||
ctx := NewContext(spec, api, nil)
|
||||
|
||||
handler := Spec("", ctx.spec.Raw(), nil)
|
||||
// serves spec
|
||||
request, _ := http.NewRequest("GET", "/swagger.json", nil)
|
||||
request.Header.Add(runtime.HeaderContentType, runtime.JSONMime)
|
||||
recorder := httptest.NewRecorder()
|
||||
handler.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
|
||||
// returns 404 when no next handler
|
||||
request, _ = http.NewRequest("GET", "/api/pets", nil)
|
||||
request.Header.Add(runtime.HeaderContentType, runtime.JSONMime)
|
||||
recorder = httptest.NewRecorder()
|
||||
handler.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, 404, recorder.Code)
|
||||
|
||||
// forwards to next handler for other url
|
||||
handler = Spec("", ctx.spec.Raw(), http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
request, _ = http.NewRequest("GET", "/api/pets", nil)
|
||||
request.Header.Add(runtime.HeaderContentType, runtime.JSONMime)
|
||||
recorder = httptest.NewRecorder()
|
||||
handler.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
|
||||
}
|
||||
301
vendor/github.com/go-openapi/runtime/middleware/string_conversion_test.go
generated
vendored
Normal file
301
vendor/github.com/go-openapi/runtime/middleware/string_conversion_test.go
generated
vendored
Normal file
@@ -0,0 +1,301 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var evaluatesAsTrue = []string{"true", "1", "yes", "ok", "y", "on", "selected", "checked", "t", "enabled"}
|
||||
|
||||
type unmarshallerSlice []string
|
||||
|
||||
func (u *unmarshallerSlice) UnmarshalText(data []byte) error {
|
||||
if len(data) == 0 {
|
||||
return errors.New("an error")
|
||||
}
|
||||
*u = strings.Split(string(data), ",")
|
||||
return nil
|
||||
}
|
||||
|
||||
type SomeOperationParams struct {
|
||||
Name string
|
||||
ID int64
|
||||
Confirmed bool
|
||||
Age int
|
||||
Visits int32
|
||||
Count int16
|
||||
Seq int8
|
||||
UID uint64
|
||||
UAge uint
|
||||
UVisits uint32
|
||||
UCount uint16
|
||||
USeq uint8
|
||||
Score float32
|
||||
Rate float64
|
||||
Timestamp strfmt.DateTime
|
||||
Birthdate strfmt.Date
|
||||
LastFailure *strfmt.DateTime
|
||||
Unsupported struct{}
|
||||
Tags []string
|
||||
Prefs []int32
|
||||
Categories unmarshallerSlice
|
||||
}
|
||||
|
||||
func FloatParamTest(t *testing.T, fName, pName, format string, val reflect.Value, defVal, expectedDef interface{}, actual func() interface{}) {
|
||||
fld := val.FieldByName(pName)
|
||||
binder := &untypedParamBinder{
|
||||
parameter: spec.QueryParam(pName).Typed("number", "double").WithDefault(defVal),
|
||||
Name: pName,
|
||||
}
|
||||
|
||||
err := binder.setFieldValue(fld, defVal, "5", true)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 5, actual())
|
||||
|
||||
err = binder.setFieldValue(fld, defVal, "", true)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, expectedDef, actual())
|
||||
|
||||
err = binder.setFieldValue(fld, defVal, "yada", true)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func IntParamTest(t *testing.T, pName string, val reflect.Value, defVal, expectedDef interface{}, actual func() interface{}) {
|
||||
fld := val.FieldByName(pName)
|
||||
|
||||
binder := &untypedParamBinder{
|
||||
parameter: spec.QueryParam(pName).Typed("integer", "int64").WithDefault(defVal),
|
||||
Name: pName,
|
||||
}
|
||||
err := binder.setFieldValue(fld, defVal, "5", true)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 5, actual())
|
||||
|
||||
err = binder.setFieldValue(fld, defVal, "", true)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, expectedDef, actual())
|
||||
|
||||
err = binder.setFieldValue(fld, defVal, "yada", true)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestParamBinding(t *testing.T) {
|
||||
|
||||
actual := new(SomeOperationParams)
|
||||
val := reflect.ValueOf(actual).Elem()
|
||||
pName := "Name"
|
||||
fld := val.FieldByName(pName)
|
||||
|
||||
binder := &untypedParamBinder{
|
||||
parameter: spec.QueryParam(pName).Typed("string", "").WithDefault("some-name"),
|
||||
Name: pName,
|
||||
}
|
||||
|
||||
err := binder.setFieldValue(fld, "some-name", "the name value", true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "the name value", actual.Name)
|
||||
|
||||
err = binder.setFieldValue(fld, "some-name", "", true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "some-name", actual.Name)
|
||||
|
||||
IntParamTest(t, "ID", val, 1, 1, func() interface{} { return actual.ID })
|
||||
IntParamTest(t, "ID", val, nil, 0, func() interface{} { return actual.ID })
|
||||
IntParamTest(t, "Age", val, 1, 1, func() interface{} { return actual.Age })
|
||||
IntParamTest(t, "Age", val, nil, 0, func() interface{} { return actual.Age })
|
||||
IntParamTest(t, "Visits", val, 1, 1, func() interface{} { return actual.Visits })
|
||||
IntParamTest(t, "Visits", val, nil, 0, func() interface{} { return actual.Visits })
|
||||
IntParamTest(t, "Count", val, 1, 1, func() interface{} { return actual.Count })
|
||||
IntParamTest(t, "Count", val, nil, 0, func() interface{} { return actual.Count })
|
||||
IntParamTest(t, "Seq", val, 1, 1, func() interface{} { return actual.Seq })
|
||||
IntParamTest(t, "Seq", val, nil, 0, func() interface{} { return actual.Seq })
|
||||
IntParamTest(t, "UID", val, uint64(1), 1, func() interface{} { return actual.UID })
|
||||
IntParamTest(t, "UID", val, uint64(0), 0, func() interface{} { return actual.UID })
|
||||
IntParamTest(t, "UAge", val, uint(1), 1, func() interface{} { return actual.UAge })
|
||||
IntParamTest(t, "UAge", val, nil, 0, func() interface{} { return actual.UAge })
|
||||
IntParamTest(t, "UVisits", val, uint32(1), 1, func() interface{} { return actual.UVisits })
|
||||
IntParamTest(t, "UVisits", val, nil, 0, func() interface{} { return actual.UVisits })
|
||||
IntParamTest(t, "UCount", val, uint16(1), 1, func() interface{} { return actual.UCount })
|
||||
IntParamTest(t, "UCount", val, nil, 0, func() interface{} { return actual.UCount })
|
||||
IntParamTest(t, "USeq", val, uint8(1), 1, func() interface{} { return actual.USeq })
|
||||
IntParamTest(t, "USeq", val, nil, 0, func() interface{} { return actual.USeq })
|
||||
|
||||
FloatParamTest(t, "score", "Score", "float", val, 1.0, 1, func() interface{} { return actual.Score })
|
||||
FloatParamTest(t, "score", "Score", "float", val, nil, 0, func() interface{} { return actual.Score })
|
||||
FloatParamTest(t, "rate", "Rate", "double", val, 1.0, 1, func() interface{} { return actual.Rate })
|
||||
FloatParamTest(t, "rate", "Rate", "double", val, nil, 0, func() interface{} { return actual.Rate })
|
||||
|
||||
pName = "Confirmed"
|
||||
confirmedField := val.FieldByName(pName)
|
||||
binder = &untypedParamBinder{
|
||||
parameter: spec.QueryParam(pName).Typed("boolean", "").WithDefault(true),
|
||||
Name: pName,
|
||||
}
|
||||
|
||||
for _, tv := range evaluatesAsTrue {
|
||||
err = binder.setFieldValue(confirmedField, true, tv, true)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, actual.Confirmed)
|
||||
}
|
||||
|
||||
err = binder.setFieldValue(confirmedField, true, "", true)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, actual.Confirmed)
|
||||
|
||||
err = binder.setFieldValue(confirmedField, true, "0", true)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, actual.Confirmed)
|
||||
|
||||
pName = "Timestamp"
|
||||
timeField := val.FieldByName(pName)
|
||||
dt := strfmt.DateTime(time.Date(2014, 3, 19, 2, 9, 0, 0, time.UTC))
|
||||
binder = &untypedParamBinder{
|
||||
parameter: spec.QueryParam(pName).Typed("string", "date-time").WithDefault(dt),
|
||||
Name: pName,
|
||||
}
|
||||
exp := strfmt.DateTime(time.Date(2014, 5, 14, 2, 9, 0, 0, time.UTC))
|
||||
|
||||
err = binder.setFieldValue(timeField, dt, exp.String(), true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, exp, actual.Timestamp)
|
||||
|
||||
err = binder.setFieldValue(timeField, dt, "", true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, dt, actual.Timestamp)
|
||||
|
||||
err = binder.setFieldValue(timeField, dt, "yada", true)
|
||||
assert.Error(t, err)
|
||||
|
||||
ddt := strfmt.Date(time.Date(2014, 3, 19, 0, 0, 0, 0, time.UTC))
|
||||
pName = "Birthdate"
|
||||
dateField := val.FieldByName(pName)
|
||||
binder = &untypedParamBinder{
|
||||
parameter: spec.QueryParam(pName).Typed("string", "date").WithDefault(ddt),
|
||||
Name: pName,
|
||||
}
|
||||
expd := strfmt.Date(time.Date(2014, 5, 14, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
err = binder.setFieldValue(dateField, ddt, expd.String(), true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expd, actual.Birthdate)
|
||||
|
||||
err = binder.setFieldValue(dateField, ddt, "", true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, ddt, actual.Birthdate)
|
||||
|
||||
err = binder.setFieldValue(dateField, ddt, "yada", true)
|
||||
assert.Error(t, err)
|
||||
|
||||
dt = strfmt.DateTime(time.Date(2014, 3, 19, 2, 9, 0, 0, time.UTC))
|
||||
fdt := &dt
|
||||
pName = "LastFailure"
|
||||
ftimeField := val.FieldByName(pName)
|
||||
binder = &untypedParamBinder{
|
||||
parameter: spec.QueryParam(pName).Typed("string", "date").WithDefault(fdt),
|
||||
Name: pName,
|
||||
}
|
||||
exp = strfmt.DateTime(time.Date(2014, 5, 14, 2, 9, 0, 0, time.UTC))
|
||||
fexp := &exp
|
||||
|
||||
err = binder.setFieldValue(ftimeField, fdt, fexp.String(), true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, fexp, actual.LastFailure)
|
||||
|
||||
err = binder.setFieldValue(ftimeField, fdt, "", true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, fdt, actual.LastFailure)
|
||||
|
||||
err = binder.setFieldValue(ftimeField, fdt, "", true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, fdt, actual.LastFailure)
|
||||
|
||||
actual.LastFailure = nil
|
||||
err = binder.setFieldValue(ftimeField, fdt, "yada", true)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, actual.LastFailure)
|
||||
|
||||
pName = "Unsupported"
|
||||
unsupportedField := val.FieldByName(pName)
|
||||
binder = &untypedParamBinder{
|
||||
parameter: spec.QueryParam(pName).Typed("string", ""),
|
||||
Name: pName,
|
||||
}
|
||||
err = binder.setFieldValue(unsupportedField, nil, "", true)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestSliceConversion(t *testing.T) {
|
||||
|
||||
actual := new(SomeOperationParams)
|
||||
val := reflect.ValueOf(actual).Elem()
|
||||
|
||||
// prefsField := val.FieldByName("Prefs")
|
||||
// cData := "yada,2,3"
|
||||
// _, _, err := readFormattedSliceFieldValue("Prefs", prefsField, cData, "csv", nil)
|
||||
// assert.Error(t, err)
|
||||
|
||||
sliced := []string{"some", "string", "values"}
|
||||
seps := map[string]string{"ssv": " ", "tsv": "\t", "pipes": "|", "csv": ",", "": ","}
|
||||
|
||||
tagsField := val.FieldByName("Tags")
|
||||
for k, sep := range seps {
|
||||
binder := &untypedParamBinder{
|
||||
Name: "Tags",
|
||||
parameter: spec.QueryParam("tags").CollectionOf(stringItems, k),
|
||||
}
|
||||
|
||||
actual.Tags = nil
|
||||
cData := strings.Join(sliced, sep)
|
||||
tags, _, err := binder.readFormattedSliceFieldValue(cData, tagsField)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, sliced, tags)
|
||||
cData = strings.Join(sliced, " "+sep+" ")
|
||||
tags, _, err = binder.readFormattedSliceFieldValue(cData, tagsField)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, sliced, tags)
|
||||
tags, _, err = binder.readFormattedSliceFieldValue("", tagsField)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, tags)
|
||||
}
|
||||
|
||||
assert.Nil(t, swag.SplitByFormat("yada", "multi"))
|
||||
assert.Nil(t, swag.SplitByFormat("", ""))
|
||||
|
||||
categoriesField := val.FieldByName("Categories")
|
||||
binder := &untypedParamBinder{
|
||||
Name: "Categories",
|
||||
parameter: spec.QueryParam("categories").CollectionOf(stringItems, "csv"),
|
||||
}
|
||||
cData := strings.Join(sliced, ",")
|
||||
categories, custom, err := binder.readFormattedSliceFieldValue(cData, categoriesField)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, sliced, actual.Categories)
|
||||
assert.True(t, custom)
|
||||
assert.Empty(t, categories)
|
||||
categories, custom, err = binder.readFormattedSliceFieldValue("", categoriesField)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, custom)
|
||||
assert.Empty(t, categories)
|
||||
}
|
||||
275
vendor/github.com/go-openapi/runtime/middleware/untyped/api.go
generated
vendored
Normal file
275
vendor/github.com/go-openapi/runtime/middleware/untyped/api.go
generated
vendored
Normal file
@@ -0,0 +1,275 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package untyped
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/analysis"
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// NewAPI creates the default untyped API
|
||||
func NewAPI(spec *loads.Document) *API {
|
||||
var an *analysis.Spec
|
||||
if spec != nil && spec.Spec() != nil {
|
||||
an = analysis.New(spec.Spec())
|
||||
}
|
||||
api := &API{
|
||||
spec: spec,
|
||||
analyzer: an,
|
||||
consumers: make(map[string]runtime.Consumer, 10),
|
||||
producers: make(map[string]runtime.Producer, 10),
|
||||
authenticators: make(map[string]runtime.Authenticator),
|
||||
operations: make(map[string]map[string]runtime.OperationHandler),
|
||||
ServeError: errors.ServeError,
|
||||
Models: make(map[string]func() interface{}),
|
||||
formats: strfmt.NewFormats(),
|
||||
}
|
||||
return api.WithJSONDefaults()
|
||||
}
|
||||
|
||||
// API represents an untyped mux for a swagger spec
|
||||
type API struct {
|
||||
spec *loads.Document
|
||||
analyzer *analysis.Spec
|
||||
DefaultProduces string
|
||||
DefaultConsumes string
|
||||
consumers map[string]runtime.Consumer
|
||||
producers map[string]runtime.Producer
|
||||
authenticators map[string]runtime.Authenticator
|
||||
operations map[string]map[string]runtime.OperationHandler
|
||||
ServeError func(http.ResponseWriter, *http.Request, error)
|
||||
Models map[string]func() interface{}
|
||||
formats strfmt.Registry
|
||||
}
|
||||
|
||||
// WithJSONDefaults loads the json defaults for this api
|
||||
func (d *API) WithJSONDefaults() *API {
|
||||
d.DefaultConsumes = runtime.JSONMime
|
||||
d.DefaultProduces = runtime.JSONMime
|
||||
d.consumers[runtime.JSONMime] = runtime.JSONConsumer()
|
||||
d.producers[runtime.JSONMime] = runtime.JSONProducer()
|
||||
return d
|
||||
}
|
||||
|
||||
// WithoutJSONDefaults clears the json defaults for this api
|
||||
func (d *API) WithoutJSONDefaults() *API {
|
||||
d.DefaultConsumes = ""
|
||||
d.DefaultProduces = ""
|
||||
delete(d.consumers, runtime.JSONMime)
|
||||
delete(d.producers, runtime.JSONMime)
|
||||
return d
|
||||
}
|
||||
|
||||
// Formats returns the registered string formats
|
||||
func (d *API) Formats() strfmt.Registry {
|
||||
if d.formats == nil {
|
||||
d.formats = strfmt.NewFormats()
|
||||
}
|
||||
return d.formats
|
||||
}
|
||||
|
||||
// RegisterFormat registers a custom format validator
|
||||
func (d *API) RegisterFormat(name string, format strfmt.Format, validator strfmt.Validator) {
|
||||
if d.formats == nil {
|
||||
d.formats = strfmt.NewFormats()
|
||||
}
|
||||
d.formats.Add(name, format, validator)
|
||||
}
|
||||
|
||||
// RegisterAuth registers an auth handler in this api
|
||||
func (d *API) RegisterAuth(scheme string, handler runtime.Authenticator) {
|
||||
if d.authenticators == nil {
|
||||
d.authenticators = make(map[string]runtime.Authenticator)
|
||||
}
|
||||
d.authenticators[scheme] = handler
|
||||
}
|
||||
|
||||
// RegisterConsumer registers a consumer for a media type.
|
||||
func (d *API) RegisterConsumer(mediaType string, handler runtime.Consumer) {
|
||||
if d.consumers == nil {
|
||||
d.consumers = make(map[string]runtime.Consumer, 10)
|
||||
}
|
||||
d.consumers[strings.ToLower(mediaType)] = handler
|
||||
}
|
||||
|
||||
// RegisterProducer registers a producer for a media type
|
||||
func (d *API) RegisterProducer(mediaType string, handler runtime.Producer) {
|
||||
if d.producers == nil {
|
||||
d.producers = make(map[string]runtime.Producer, 10)
|
||||
}
|
||||
d.producers[strings.ToLower(mediaType)] = handler
|
||||
}
|
||||
|
||||
// RegisterOperation registers an operation handler for an operation name
|
||||
func (d *API) RegisterOperation(method, path string, handler runtime.OperationHandler) {
|
||||
if d.operations == nil {
|
||||
d.operations = make(map[string]map[string]runtime.OperationHandler, 30)
|
||||
}
|
||||
um := strings.ToUpper(method)
|
||||
if b, ok := d.operations[um]; !ok || b == nil {
|
||||
d.operations[um] = make(map[string]runtime.OperationHandler)
|
||||
}
|
||||
d.operations[um][path] = handler
|
||||
}
|
||||
|
||||
// OperationHandlerFor returns the operation handler for the specified id if it can be found
|
||||
func (d *API) OperationHandlerFor(method, path string) (runtime.OperationHandler, bool) {
|
||||
if d.operations == nil {
|
||||
return nil, false
|
||||
}
|
||||
if pi, ok := d.operations[strings.ToUpper(method)]; ok {
|
||||
h, ok := pi[path]
|
||||
return h, ok
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// ConsumersFor gets the consumers for the specified media types
|
||||
func (d *API) ConsumersFor(mediaTypes []string) map[string]runtime.Consumer {
|
||||
result := make(map[string]runtime.Consumer)
|
||||
for _, mt := range mediaTypes {
|
||||
if consumer, ok := d.consumers[mt]; ok {
|
||||
result[mt] = consumer
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// ProducersFor gets the producers for the specified media types
|
||||
func (d *API) ProducersFor(mediaTypes []string) map[string]runtime.Producer {
|
||||
result := make(map[string]runtime.Producer)
|
||||
for _, mt := range mediaTypes {
|
||||
if producer, ok := d.producers[mt]; ok {
|
||||
result[mt] = producer
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// AuthenticatorsFor gets the authenticators for the specified security schemes
|
||||
func (d *API) AuthenticatorsFor(schemes map[string]spec.SecurityScheme) map[string]runtime.Authenticator {
|
||||
result := make(map[string]runtime.Authenticator)
|
||||
for k := range schemes {
|
||||
if a, ok := d.authenticators[k]; ok {
|
||||
result[k] = a
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Validate validates this API for any missing items
|
||||
func (d *API) Validate() error {
|
||||
return d.validate()
|
||||
}
|
||||
|
||||
// validateWith validates the registrations in this API against the provided spec analyzer
|
||||
func (d *API) validate() error {
|
||||
var consumes []string
|
||||
for k := range d.consumers {
|
||||
consumes = append(consumes, k)
|
||||
}
|
||||
|
||||
var produces []string
|
||||
for k := range d.producers {
|
||||
produces = append(produces, k)
|
||||
}
|
||||
|
||||
var authenticators []string
|
||||
for k := range d.authenticators {
|
||||
authenticators = append(authenticators, k)
|
||||
}
|
||||
|
||||
var operations []string
|
||||
for m, v := range d.operations {
|
||||
for p := range v {
|
||||
operations = append(operations, fmt.Sprintf("%s %s", strings.ToUpper(m), p))
|
||||
}
|
||||
}
|
||||
|
||||
var definedAuths []string
|
||||
for k := range d.spec.Spec().SecurityDefinitions {
|
||||
definedAuths = append(definedAuths, k)
|
||||
}
|
||||
|
||||
if err := d.verify("consumes", consumes, d.analyzer.RequiredConsumes()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.verify("produces", produces, d.analyzer.RequiredProduces()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.verify("operation", operations, d.analyzer.OperationMethodPaths()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
requiredAuths := d.analyzer.RequiredSecuritySchemes()
|
||||
if err := d.verify("auth scheme", authenticators, requiredAuths); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.verify("security definitions", definedAuths, requiredAuths); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *API) verify(name string, registrations []string, expectations []string) error {
|
||||
|
||||
sort.Sort(sort.StringSlice(registrations))
|
||||
sort.Sort(sort.StringSlice(expectations))
|
||||
|
||||
expected := map[string]struct{}{}
|
||||
seen := map[string]struct{}{}
|
||||
|
||||
for _, v := range expectations {
|
||||
expected[v] = struct{}{}
|
||||
}
|
||||
|
||||
var unspecified []string
|
||||
for _, v := range registrations {
|
||||
seen[v] = struct{}{}
|
||||
if _, ok := expected[v]; !ok {
|
||||
unspecified = append(unspecified, v)
|
||||
}
|
||||
}
|
||||
|
||||
for k := range seen {
|
||||
delete(expected, k)
|
||||
}
|
||||
|
||||
var unregistered []string
|
||||
for k := range expected {
|
||||
unregistered = append(unregistered, k)
|
||||
}
|
||||
sort.Sort(sort.StringSlice(unspecified))
|
||||
sort.Sort(sort.StringSlice(unregistered))
|
||||
|
||||
if len(unregistered) > 0 || len(unspecified) > 0 {
|
||||
return &errors.APIVerificationFailed{
|
||||
Section: name,
|
||||
MissingSpecification: unspecified,
|
||||
MissingRegistration: unregistered,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
276
vendor/github.com/go-openapi/runtime/middleware/untyped/api_test.go
generated
vendored
Normal file
276
vendor/github.com/go-openapi/runtime/middleware/untyped/api_test.go
generated
vendored
Normal file
@@ -0,0 +1,276 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package untyped
|
||||
|
||||
import (
|
||||
"io"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/analysis"
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/go-openapi/runtime"
|
||||
swaggerspec "github.com/go-openapi/spec"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func stubAutenticator() runtime.Authenticator {
|
||||
return runtime.AuthenticatorFunc(func(_ interface{}) (bool, interface{}, error) { return false, nil, nil })
|
||||
}
|
||||
|
||||
type stubConsumer struct {
|
||||
}
|
||||
|
||||
func (s *stubConsumer) Consume(_ io.Reader, _ interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type stubProducer struct {
|
||||
}
|
||||
|
||||
func (s *stubProducer) Produce(_ io.Writer, _ interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type stubOperationHandler struct {
|
||||
}
|
||||
|
||||
func (s *stubOperationHandler) ParameterModel() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *stubOperationHandler) Handle(params interface{}) (interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func TestUntypedAPIRegistrations(t *testing.T) {
|
||||
api := NewAPI(new(loads.Document)).WithJSONDefaults()
|
||||
|
||||
api.RegisterConsumer("application/yada", new(stubConsumer))
|
||||
api.RegisterProducer("application/yada-2", new(stubProducer))
|
||||
api.RegisterOperation("get", "/{someId}", new(stubOperationHandler))
|
||||
api.RegisterAuth("basic", stubAutenticator())
|
||||
|
||||
assert.NotEmpty(t, api.authenticators)
|
||||
|
||||
_, ok := api.authenticators["basic"]
|
||||
assert.True(t, ok)
|
||||
_, ok = api.consumers["application/yada"]
|
||||
assert.True(t, ok)
|
||||
_, ok = api.producers["application/yada-2"]
|
||||
assert.True(t, ok)
|
||||
_, ok = api.consumers["application/json"]
|
||||
assert.True(t, ok)
|
||||
_, ok = api.producers["application/json"]
|
||||
assert.True(t, ok)
|
||||
_, ok = api.operations["GET"]["/{someId}"]
|
||||
assert.True(t, ok)
|
||||
|
||||
h, ok := api.OperationHandlerFor("get", "/{someId}")
|
||||
assert.True(t, ok)
|
||||
assert.NotNil(t, h)
|
||||
|
||||
_, ok = api.OperationHandlerFor("doesntExist", "/{someId}")
|
||||
assert.False(t, ok)
|
||||
}
|
||||
|
||||
func TestUntypedAppValidation(t *testing.T) {
|
||||
invalidSpecStr := `{
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"security": [
|
||||
{"apiKey":[]}
|
||||
],
|
||||
"parameters": {
|
||||
"format": {
|
||||
"in": "query",
|
||||
"name": "format",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"paths": {
|
||||
"/": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "limit",
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"x-go-name": "Limit"
|
||||
}
|
||||
],
|
||||
"get": {
|
||||
"consumes": ["application/x-yaml"],
|
||||
"produces": ["application/x-yaml"],
|
||||
"security": [
|
||||
{"basic":[]}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "skip",
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
specStr := `{
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"security": [
|
||||
{"apiKey":[]}
|
||||
],
|
||||
"securityDefinitions": {
|
||||
"basic": { "type": "basic" },
|
||||
"apiKey": { "type": "apiKey", "in":"header", "name":"X-API-KEY" }
|
||||
},
|
||||
"parameters": {
|
||||
"format": {
|
||||
"in": "query",
|
||||
"name": "format",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"paths": {
|
||||
"/": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "limit",
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"x-go-name": "Limit"
|
||||
}
|
||||
],
|
||||
"get": {
|
||||
"consumes": ["application/x-yaml"],
|
||||
"produces": ["application/x-yaml"],
|
||||
"security": [
|
||||
{"basic":[]}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "skip",
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
validSpec, err := loads.Analyzed([]byte(specStr), "")
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, validSpec)
|
||||
|
||||
spec, err := loads.Analyzed([]byte(invalidSpecStr), "")
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, spec)
|
||||
|
||||
analyzed := analysis.New(spec.Spec())
|
||||
analyzedValid := analysis.New(validSpec.Spec())
|
||||
cons := analyzed.ConsumesFor(analyzed.AllPaths()["/"].Get)
|
||||
assert.Len(t, cons, 1)
|
||||
prods := analyzed.RequiredProduces()
|
||||
assert.Len(t, prods, 2)
|
||||
|
||||
api1 := NewAPI(spec)
|
||||
err = api1.Validate()
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "missing [application/x-yaml] consumes registrations", err.Error())
|
||||
api1.RegisterConsumer("application/x-yaml", new(stubConsumer))
|
||||
err = api1.validate()
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "missing [application/x-yaml] produces registrations", err.Error())
|
||||
api1.RegisterProducer("application/x-yaml", new(stubProducer))
|
||||
err = api1.validate()
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "missing [GET /] operation registrations", err.Error())
|
||||
api1.RegisterOperation("get", "/", new(stubOperationHandler))
|
||||
err = api1.validate()
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "missing [apiKey, basic] auth scheme registrations", err.Error())
|
||||
api1.RegisterAuth("basic", stubAutenticator())
|
||||
api1.RegisterAuth("apiKey", stubAutenticator())
|
||||
err = api1.validate()
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "missing [apiKey, basic] security definitions registrations", err.Error())
|
||||
|
||||
api3 := NewAPI(validSpec)
|
||||
api3.RegisterConsumer("application/x-yaml", new(stubConsumer))
|
||||
api3.RegisterProducer("application/x-yaml", new(stubProducer))
|
||||
api3.RegisterOperation("get", "/", new(stubOperationHandler))
|
||||
api3.RegisterAuth("basic", stubAutenticator())
|
||||
api3.RegisterAuth("apiKey", stubAutenticator())
|
||||
err = api3.validate()
|
||||
assert.NoError(t, err)
|
||||
api3.RegisterConsumer("application/something", new(stubConsumer))
|
||||
err = api3.validate()
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "missing from spec file [application/something] consumes", err.Error())
|
||||
|
||||
api2 := NewAPI(spec)
|
||||
api2.RegisterConsumer("application/something", new(stubConsumer))
|
||||
err = api2.validate()
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "missing [application/x-yaml] consumes registrations\nmissing from spec file [application/something] consumes", err.Error())
|
||||
api2.RegisterConsumer("application/x-yaml", new(stubConsumer))
|
||||
delete(api2.consumers, "application/something")
|
||||
api2.RegisterProducer("application/something", new(stubProducer))
|
||||
err = api2.validate()
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "missing [application/x-yaml] produces registrations\nmissing from spec file [application/something] produces", err.Error())
|
||||
delete(api2.producers, "application/something")
|
||||
api2.RegisterProducer("application/x-yaml", new(stubProducer))
|
||||
|
||||
expected := []string{"application/x-yaml"}
|
||||
sort.Sort(sort.StringSlice(expected))
|
||||
consumes := analyzed.ConsumesFor(analyzed.AllPaths()["/"].Get)
|
||||
sort.Sort(sort.StringSlice(consumes))
|
||||
assert.Equal(t, expected, consumes)
|
||||
consumers := api1.ConsumersFor(consumes)
|
||||
assert.Len(t, consumers, 1)
|
||||
|
||||
produces := analyzed.ProducesFor(analyzed.AllPaths()["/"].Get)
|
||||
sort.Sort(sort.StringSlice(produces))
|
||||
assert.Equal(t, expected, produces)
|
||||
producers := api1.ProducersFor(produces)
|
||||
assert.Len(t, producers, 1)
|
||||
|
||||
definitions := analyzedValid.SecurityDefinitionsFor(analyzedValid.AllPaths()["/"].Get)
|
||||
expectedSchemes := map[string]swaggerspec.SecurityScheme{"basic": *swaggerspec.BasicAuth()}
|
||||
assert.Equal(t, expectedSchemes, definitions)
|
||||
authenticators := api3.AuthenticatorsFor(definitions)
|
||||
assert.Len(t, authenticators, 1)
|
||||
|
||||
opHandler := runtime.OperationHandlerFunc(func(data interface{}) (interface{}, error) {
|
||||
return data, nil
|
||||
})
|
||||
d, err := opHandler.Handle(1)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, d)
|
||||
|
||||
authenticator := runtime.AuthenticatorFunc(func(params interface{}) (bool, interface{}, error) {
|
||||
if str, ok := params.(string); ok {
|
||||
return ok, str, nil
|
||||
}
|
||||
return true, nil, errors.Unauthenticated("authenticator")
|
||||
})
|
||||
ok, p, err := authenticator.Authenticate("hello")
|
||||
assert.True(t, ok)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "hello", p)
|
||||
}
|
||||
164
vendor/github.com/go-openapi/runtime/middleware/untyped_request_test.go
generated
vendored
Normal file
164
vendor/github.com/go-openapi/runtime/middleware/untyped_request_test.go
generated
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUntypedFormPost(t *testing.T) {
|
||||
params := parametersForFormUpload()
|
||||
binder := newUntypedRequestBinder(params, nil, strfmt.Default)
|
||||
|
||||
urlStr := "http://localhost:8002/hello"
|
||||
req, _ := http.NewRequest("POST", urlStr, bytes.NewBufferString(`name=the-name&age=32`))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
data := make(map[string]interface{})
|
||||
assert.NoError(t, binder.Bind(req, nil, runtime.JSONConsumer(), &data))
|
||||
assert.Equal(t, "the-name", data["name"])
|
||||
assert.EqualValues(t, 32, data["age"])
|
||||
|
||||
req, _ = http.NewRequest("POST", urlStr, bytes.NewBufferString(`name=%3&age=32`))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
data = make(map[string]interface{})
|
||||
assert.Error(t, binder.Bind(req, nil, runtime.JSONConsumer(), &data))
|
||||
}
|
||||
|
||||
func TestUntypedFileUpload(t *testing.T) {
|
||||
binder := paramsForFileUpload()
|
||||
|
||||
body := bytes.NewBuffer(nil)
|
||||
writer := multipart.NewWriter(body)
|
||||
part, err := writer.CreateFormFile("file", "plain-jane.txt")
|
||||
assert.NoError(t, err)
|
||||
|
||||
part.Write([]byte("the file contents"))
|
||||
writer.WriteField("name", "the-name")
|
||||
assert.NoError(t, writer.Close())
|
||||
|
||||
urlStr := "http://localhost:8002/hello"
|
||||
req, _ := http.NewRequest("POST", urlStr, body)
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
|
||||
data := make(map[string]interface{})
|
||||
assert.NoError(t, binder.Bind(req, nil, runtime.JSONConsumer(), &data))
|
||||
assert.Equal(t, "the-name", data["name"])
|
||||
assert.NotNil(t, data["file"])
|
||||
assert.IsType(t, runtime.File{}, data["file"])
|
||||
file := data["file"].(runtime.File)
|
||||
assert.NotNil(t, file.Header)
|
||||
assert.Equal(t, "plain-jane.txt", file.Header.Filename)
|
||||
|
||||
bb, err := ioutil.ReadAll(file.Data)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []byte("the file contents"), bb)
|
||||
|
||||
req, _ = http.NewRequest("POST", urlStr, body)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
data = make(map[string]interface{})
|
||||
assert.Error(t, binder.Bind(req, nil, runtime.JSONConsumer(), &data))
|
||||
|
||||
req, _ = http.NewRequest("POST", urlStr, body)
|
||||
req.Header.Set("Content-Type", "application(")
|
||||
data = make(map[string]interface{})
|
||||
assert.Error(t, binder.Bind(req, nil, runtime.JSONConsumer(), &data))
|
||||
|
||||
body = bytes.NewBuffer(nil)
|
||||
writer = multipart.NewWriter(body)
|
||||
part, err = writer.CreateFormFile("bad-name", "plain-jane.txt")
|
||||
assert.NoError(t, err)
|
||||
|
||||
part.Write([]byte("the file contents"))
|
||||
writer.WriteField("name", "the-name")
|
||||
assert.NoError(t, writer.Close())
|
||||
req, _ = http.NewRequest("POST", urlStr, body)
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
|
||||
data = make(map[string]interface{})
|
||||
assert.Error(t, binder.Bind(req, nil, runtime.JSONConsumer(), &data))
|
||||
|
||||
req, _ = http.NewRequest("POST", urlStr, body)
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
req.MultipartReader()
|
||||
|
||||
data = make(map[string]interface{})
|
||||
assert.Error(t, binder.Bind(req, nil, runtime.JSONConsumer(), &data))
|
||||
}
|
||||
|
||||
func TestUntypedBindingTypesForValid(t *testing.T) {
|
||||
|
||||
op2 := parametersForAllTypes("")
|
||||
binder := newUntypedRequestBinder(op2, nil, strfmt.Default)
|
||||
|
||||
confirmed := true
|
||||
name := "thomas"
|
||||
friend := map[string]interface{}{"name": "toby", "age": json.Number("32")}
|
||||
id, age, score, factor := int64(7575), int32(348), float32(5.309), float64(37.403)
|
||||
requestID := 19394858
|
||||
tags := []string{"one", "two", "three"}
|
||||
dt1 := time.Date(2014, 8, 9, 0, 0, 0, 0, time.UTC)
|
||||
planned := strfmt.Date(dt1)
|
||||
dt2 := time.Date(2014, 10, 12, 8, 5, 5, 0, time.UTC)
|
||||
delivered := strfmt.DateTime(dt2)
|
||||
picture := base64.URLEncoding.EncodeToString([]byte("hello"))
|
||||
uri, _ := url.Parse("http://localhost:8002/hello/7575")
|
||||
qs := uri.Query()
|
||||
qs.Add("name", name)
|
||||
qs.Add("confirmed", "true")
|
||||
qs.Add("age", "348")
|
||||
qs.Add("score", "5.309")
|
||||
qs.Add("factor", "37.403")
|
||||
qs.Add("tags", strings.Join(tags, ","))
|
||||
qs.Add("planned", planned.String())
|
||||
qs.Add("delivered", delivered.String())
|
||||
qs.Add("picture", picture)
|
||||
|
||||
req, _ := http.NewRequest("POST", uri.String()+"?"+qs.Encode(), bytes.NewBuffer([]byte(`{"name":"toby","age":32}`)))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("X-Request-Id", "19394858")
|
||||
|
||||
data := make(map[string]interface{})
|
||||
err := binder.Bind(req, RouteParams([]RouteParam{{"id", "7575"}}), runtime.JSONConsumer(), &data)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, id, data["id"])
|
||||
assert.Equal(t, name, data["name"])
|
||||
assert.Equal(t, friend, data["friend"])
|
||||
assert.EqualValues(t, requestID, data["X-Request-Id"])
|
||||
assert.Equal(t, tags, data["tags"])
|
||||
assert.Equal(t, planned, data["planned"])
|
||||
assert.Equal(t, delivered, data["delivered"])
|
||||
assert.Equal(t, confirmed, data["confirmed"])
|
||||
assert.Equal(t, age, data["age"])
|
||||
assert.Equal(t, factor, data["factor"])
|
||||
assert.Equal(t, score, data["score"])
|
||||
pb, _ := base64.URLEncoding.DecodeString(picture)
|
||||
assert.EqualValues(t, pb, data["picture"].(strfmt.Base64))
|
||||
|
||||
}
|
||||
141
vendor/github.com/go-openapi/runtime/middleware/validation.go
generated
vendored
Normal file
141
vendor/github.com/go-openapi/runtime/middleware/validation.go
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"mime"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// NewValidation starts a new validation middleware
|
||||
func newValidation(ctx *Context, next http.Handler) http.Handler {
|
||||
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
matched, _ := ctx.RouteInfo(r)
|
||||
if matched == nil {
|
||||
ctx.NotFound(rw, r)
|
||||
return
|
||||
}
|
||||
_, result := ctx.BindAndValidate(r, matched)
|
||||
|
||||
if result != nil {
|
||||
ctx.Respond(rw, r, matched.Produces, matched, result)
|
||||
return
|
||||
}
|
||||
|
||||
debugLog("no result for %s %s", r.Method, r.URL.EscapedPath())
|
||||
next.ServeHTTP(rw, r)
|
||||
})
|
||||
}
|
||||
|
||||
type validation struct {
|
||||
context *Context
|
||||
result []error
|
||||
request *http.Request
|
||||
route *MatchedRoute
|
||||
bound map[string]interface{}
|
||||
}
|
||||
|
||||
type untypedBinder map[string]interface{}
|
||||
|
||||
func (ub untypedBinder) BindRequest(r *http.Request, route *MatchedRoute, consumer runtime.Consumer) error {
|
||||
if err := route.Binder.Bind(r, route.Params, consumer, ub); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContentType validates the content type of a request
|
||||
func validateContentType(allowed []string, actual string) error {
|
||||
debugLog("validating content type for %q against [%s]", actual, strings.Join(allowed, ", "))
|
||||
if len(allowed) == 0 {
|
||||
return nil
|
||||
}
|
||||
mt, _, err := mime.ParseMediaType(actual)
|
||||
if err != nil {
|
||||
return errors.InvalidContentType(actual, allowed)
|
||||
}
|
||||
if swag.ContainsStringsCI(allowed, mt) {
|
||||
return nil
|
||||
}
|
||||
return errors.InvalidContentType(actual, allowed)
|
||||
}
|
||||
|
||||
func validateRequest(ctx *Context, request *http.Request, route *MatchedRoute) *validation {
|
||||
debugLog("validating request %s %s", request.Method, request.URL.EscapedPath())
|
||||
validate := &validation{
|
||||
context: ctx,
|
||||
request: request,
|
||||
route: route,
|
||||
bound: make(map[string]interface{}),
|
||||
}
|
||||
|
||||
validate.contentType()
|
||||
if len(validate.result) == 0 {
|
||||
validate.responseFormat()
|
||||
}
|
||||
if len(validate.result) == 0 {
|
||||
validate.parameters()
|
||||
}
|
||||
|
||||
return validate
|
||||
}
|
||||
|
||||
func (v *validation) parameters() {
|
||||
debugLog("validating request parameters for %s %s", v.request.Method, v.request.URL.EscapedPath())
|
||||
if result := v.route.Binder.Bind(v.request, v.route.Params, v.route.Consumer, v.bound); result != nil {
|
||||
if result.Error() == "validation failure list" {
|
||||
for _, e := range result.(*errors.Validation).Value.([]interface{}) {
|
||||
v.result = append(v.result, e.(error))
|
||||
}
|
||||
return
|
||||
}
|
||||
v.result = append(v.result, result)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *validation) contentType() {
|
||||
if len(v.result) == 0 && runtime.HasBody(v.request) {
|
||||
debugLog("validating body content type for %s %s", v.request.Method, v.request.URL.EscapedPath())
|
||||
ct, _, err := v.context.ContentType(v.request)
|
||||
if err != nil {
|
||||
v.result = append(v.result, err)
|
||||
}
|
||||
if len(v.result) == 0 {
|
||||
if err := validateContentType(v.route.Consumes, ct); err != nil {
|
||||
v.result = append(v.result, err)
|
||||
}
|
||||
}
|
||||
if ct != "" && v.route.Consumer == nil {
|
||||
cons, ok := v.route.Consumers[ct]
|
||||
if !ok {
|
||||
v.result = append(v.result, errors.New(500, "no consumer registered for %s", ct))
|
||||
} else {
|
||||
v.route.Consumer = cons
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (v *validation) responseFormat() {
|
||||
if str := v.context.ResponseFormat(v.request, v.route.Produces); str == "" && runtime.HasBody(v.request) {
|
||||
v.result = append(v.result, errors.InvalidResponseFormat(v.request.Header.Get(runtime.HeaderAccept), v.route.Produces))
|
||||
}
|
||||
}
|
||||
130
vendor/github.com/go-openapi/runtime/middleware/validation_test.go
generated
vendored
Normal file
130
vendor/github.com/go-openapi/runtime/middleware/validation_test.go
generated
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/internal/testing/petstore"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestContentTypeValidation(t *testing.T) {
|
||||
spec, api := petstore.NewAPI(t)
|
||||
context := NewContext(spec, api, nil)
|
||||
context.router = DefaultRouter(spec, context.api)
|
||||
mw := newValidation(context, http.HandlerFunc(terminator))
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
request, _ := http.NewRequest("GET", "/api/pets", nil)
|
||||
request.Header.Add("Accept", "*/*")
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, http.StatusOK, recorder.Code)
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
request, _ = http.NewRequest("POST", "/api/pets", nil)
|
||||
request.Header.Add("content-type", "application(")
|
||||
request.ContentLength = 1
|
||||
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, http.StatusBadRequest, recorder.Code)
|
||||
assert.Equal(t, "application/json", recorder.Header().Get("content-type"))
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
request, _ = http.NewRequest("POST", "/api/pets", nil)
|
||||
request.Header.Add("Accept", "application/json")
|
||||
request.Header.Add("content-type", "text/html")
|
||||
request.ContentLength = 1
|
||||
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, http.StatusUnsupportedMediaType, recorder.Code)
|
||||
assert.Equal(t, "application/json", recorder.Header().Get("content-type"))
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
request, _ = http.NewRequest("POST", "/api/pets", nil)
|
||||
request.Header.Add("Accept", "application/json")
|
||||
request.Header.Add("content-type", "text/html")
|
||||
request.TransferEncoding = []string{"chunked"}
|
||||
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, http.StatusUnsupportedMediaType, recorder.Code)
|
||||
assert.Equal(t, "application/json", recorder.Header().Get("content-type"))
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
request, _ = http.NewRequest("POST", "/api/pets", nil)
|
||||
request.Header.Add("Accept", "application/json")
|
||||
request.Header.Add("content-type", "text/html")
|
||||
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, 422, recorder.Code)
|
||||
assert.Equal(t, "application/json", recorder.Header().Get("content-type"))
|
||||
}
|
||||
|
||||
func TestResponseFormatValidation(t *testing.T) {
|
||||
spec, api := petstore.NewAPI(t)
|
||||
context := NewContext(spec, api, nil)
|
||||
context.router = DefaultRouter(spec, context.api)
|
||||
mw := newValidation(context, http.HandlerFunc(terminator))
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
request, _ := http.NewRequest("POST", "/api/pets", bytes.NewBuffer([]byte(`name: Dog`)))
|
||||
request.Header.Set(runtime.HeaderContentType, "application/x-yaml")
|
||||
request.Header.Set(runtime.HeaderAccept, "application/x-yaml")
|
||||
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, 200, recorder.Code, recorder.Body.String())
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
request, _ = http.NewRequest("POST", "/api/pets", bytes.NewBuffer([]byte(`name: Dog`)))
|
||||
request.Header.Set(runtime.HeaderContentType, "application/x-yaml")
|
||||
request.Header.Set(runtime.HeaderAccept, "application/sml")
|
||||
|
||||
mw.ServeHTTP(recorder, request)
|
||||
assert.Equal(t, http.StatusNotAcceptable, recorder.Code)
|
||||
}
|
||||
|
||||
func TestValidateContentType(t *testing.T) {
|
||||
data := []struct {
|
||||
hdr string
|
||||
allowed []string
|
||||
err *errors.Validation
|
||||
}{
|
||||
{"application/json", []string{"application/json"}, nil},
|
||||
{"application/json", []string{"application/x-yaml", "text/html"}, errors.InvalidContentType("application/json", []string{"application/x-yaml", "text/html"})},
|
||||
{"text/html; charset=utf-8", []string{"text/html"}, nil},
|
||||
{"text/html;charset=utf-8", []string{"text/html"}, nil},
|
||||
{"", []string{"application/json"}, errors.InvalidContentType("", []string{"application/json"})},
|
||||
{"text/html; charset=utf-8", []string{"application/json"}, errors.InvalidContentType("text/html; charset=utf-8", []string{"application/json"})},
|
||||
{"application(", []string{"application/json"}, errors.InvalidContentType("application(", []string{"application/json"})},
|
||||
{"application/json;char*", []string{"application/json"}, errors.InvalidContentType("application/json;char*", []string{"application/json"})},
|
||||
}
|
||||
|
||||
for _, v := range data {
|
||||
err := validateContentType(v.allowed, v.hdr)
|
||||
if v.err == nil {
|
||||
assert.NoError(t, err, "input: %q", v.hdr)
|
||||
} else {
|
||||
assert.Error(t, err, "input: %q", v.hdr)
|
||||
assert.IsType(t, &errors.Validation{}, err, "input: %q", v.hdr)
|
||||
assert.Equal(t, v.err.Error(), err.Error(), "input: %q", v.hdr)
|
||||
assert.EqualValues(t, http.StatusUnsupportedMediaType, err.(*errors.Validation).Code())
|
||||
}
|
||||
}
|
||||
}
|
||||
77
vendor/github.com/go-openapi/runtime/request.go
generated
vendored
Normal file
77
vendor/github.com/go-openapi/runtime/request.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// CanHaveBody returns true if this method can have a body
|
||||
func CanHaveBody(method string) bool {
|
||||
mn := strings.ToUpper(method)
|
||||
return mn == "POST" || mn == "PUT" || mn == "PATCH" || mn == "DELETE"
|
||||
}
|
||||
|
||||
// IsSafe returns true if this is a request with a safe method
|
||||
func IsSafe(r *http.Request) bool {
|
||||
mn := strings.ToUpper(r.Method)
|
||||
return mn == "GET" || mn == "HEAD"
|
||||
}
|
||||
|
||||
// AllowsBody returns true if the request allows for a body
|
||||
func AllowsBody(r *http.Request) bool {
|
||||
mn := strings.ToUpper(r.Method)
|
||||
return mn != "HEAD"
|
||||
}
|
||||
|
||||
// HasBody returns true if this method needs a content-type
|
||||
func HasBody(r *http.Request) bool {
|
||||
return len(r.TransferEncoding) > 0 || r.ContentLength > 0
|
||||
}
|
||||
|
||||
// JSONRequest creates a new http request with json headers set
|
||||
func JSONRequest(method, urlStr string, body io.Reader) (*http.Request, error) {
|
||||
req, err := http.NewRequest(method, urlStr, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Add(HeaderContentType, JSONMime)
|
||||
req.Header.Add(HeaderAccept, JSONMime)
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// Gettable for things with a method GetOK(string) (data string, hasKey bool, hasValue bool)
|
||||
type Gettable interface {
|
||||
GetOK(string) ([]string, bool, bool)
|
||||
}
|
||||
|
||||
// ReadSingleValue reads a single value from the source
|
||||
func ReadSingleValue(values Gettable, name string) string {
|
||||
vv, _, hv := values.GetOK(name)
|
||||
if hv {
|
||||
return vv[len(vv)-1]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ReadCollectionValue reads a collection value from a string data source
|
||||
func ReadCollectionValue(values Gettable, name, collectionFormat string) []string {
|
||||
v := ReadSingleValue(values, name)
|
||||
return swag.SplitByFormat(v, collectionFormat)
|
||||
}
|
||||
122
vendor/github.com/go-openapi/runtime/request_test.go
generated
vendored
Normal file
122
vendor/github.com/go-openapi/runtime/request_test.go
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
/*
|
||||
type tstreadcloser struct {
|
||||
closed bool
|
||||
}
|
||||
|
||||
func (t *tstreadcloser) Read(p []byte) (int, error) { return 0, nil }
|
||||
func (t *tstreadcloser) Close() error {
|
||||
t.closed = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestPeekingReader(t *testing.T) {
|
||||
// just passes to original reader when nothing called
|
||||
exp1 := []byte("original")
|
||||
pr1 := &peekingReader{rdr: ioutil.NopCloser(bytes.NewReader(exp1))}
|
||||
b1, err := ioutil.ReadAll(pr1)
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, exp1, b1)
|
||||
}
|
||||
|
||||
// uses actual when there was some buffering
|
||||
exp2 := []byte("actual")
|
||||
pt1, pt2 := []byte("a"), []byte("ctual")
|
||||
pr2 := &peekingReader{
|
||||
rdr: ioutil.NopCloser(bytes.NewReader(exp1)),
|
||||
actual: io.MultiReader(bytes.NewReader(pt1), bytes.NewReader(pt2)),
|
||||
peeked: pt1,
|
||||
}
|
||||
b2, err := ioutil.ReadAll(pr2)
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, exp2, b2)
|
||||
}
|
||||
|
||||
// closes original reader
|
||||
tr := new(tstreadcloser)
|
||||
pr3 := &peekingReader{
|
||||
rdr: tr,
|
||||
actual: ioutil.NopCloser(bytes.NewBuffer(nil)),
|
||||
peeked: pt1,
|
||||
}
|
||||
|
||||
|
||||
// returns true when peeked previously with data
|
||||
// returns true when peeked with data
|
||||
}
|
||||
*/
|
||||
|
||||
func TestJSONRequest(t *testing.T) {
|
||||
req, err := JSONRequest("GET", "/swagger.json", nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "GET", req.Method)
|
||||
assert.Equal(t, JSONMime, req.Header.Get(HeaderContentType))
|
||||
assert.Equal(t, JSONMime, req.Header.Get(HeaderAccept))
|
||||
|
||||
req, err = JSONRequest("GET", "%2", nil)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, req)
|
||||
}
|
||||
|
||||
//func TestCanHaveBody(t *testing.T) {
|
||||
//assert.True(t, CanHaveBody("put"))
|
||||
//assert.True(t, CanHaveBody("post"))
|
||||
//assert.True(t, CanHaveBody("patch"))
|
||||
//assert.True(t, CanHaveBody("delete"))
|
||||
//assert.False(t, CanHaveBody(""))
|
||||
//assert.False(t, CanHaveBody("get"))
|
||||
//assert.False(t, CanHaveBody("options"))
|
||||
//assert.False(t, CanHaveBody("head"))
|
||||
//assert.False(t, CanHaveBody("invalid"))
|
||||
//}
|
||||
|
||||
func TestReadSingle(t *testing.T) {
|
||||
values := url.Values(make(map[string][]string))
|
||||
values.Add("something", "the thing")
|
||||
assert.Equal(t, "the thing", ReadSingleValue(tv(values), "something"))
|
||||
assert.Empty(t, ReadSingleValue(tv(values), "notthere"))
|
||||
}
|
||||
|
||||
func TestReadCollection(t *testing.T) {
|
||||
values := url.Values(make(map[string][]string))
|
||||
values.Add("something", "value1,value2")
|
||||
assert.Equal(t, []string{"value1", "value2"}, ReadCollectionValue(tv(values), "something", "csv"))
|
||||
assert.Empty(t, ReadCollectionValue(tv(values), "notthere", ""))
|
||||
}
|
||||
|
||||
type tv map[string][]string
|
||||
|
||||
func (v tv) GetOK(key string) (value []string, hasKey bool, hasValue bool) {
|
||||
value, hasKey = v[key]
|
||||
if !hasKey {
|
||||
return
|
||||
}
|
||||
if len(value) == 0 {
|
||||
return
|
||||
}
|
||||
hasValue = true
|
||||
return
|
||||
|
||||
}
|
||||
94
vendor/github.com/go-openapi/runtime/security/apikey_auth_test.go
generated
vendored
Normal file
94
vendor/github.com/go-openapi/runtime/security/apikey_auth_test.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package security
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var tokenAuth = TokenAuthentication(func(token string) (interface{}, error) {
|
||||
if token == "token123" {
|
||||
return "admin", nil
|
||||
}
|
||||
return nil, errors.Unauthenticated("token")
|
||||
})
|
||||
|
||||
func TestInvalidApiKeyAuthInitialization(t *testing.T) {
|
||||
assert.Panics(t, func() { APIKeyAuth("api_key", "qery", tokenAuth) })
|
||||
}
|
||||
|
||||
func TestValidApiKeyAuth(t *testing.T) {
|
||||
ta := APIKeyAuth("api_key", "query", tokenAuth)
|
||||
ta2 := APIKeyAuth("X-API-KEY", "header", tokenAuth)
|
||||
|
||||
req1, _ := http.NewRequest("GET", "/blah?api_key=token123", nil)
|
||||
|
||||
ok, usr, err := ta.Authenticate(req1)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "admin", usr)
|
||||
assert.NoError(t, err)
|
||||
|
||||
req2, _ := http.NewRequest("GET", "/blah", nil)
|
||||
req2.Header.Set("X-API-KEY", "token123")
|
||||
|
||||
ok, usr, err = ta2.Authenticate(req2)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "admin", usr)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestInvalidApiKeyAuth(t *testing.T) {
|
||||
ta := APIKeyAuth("api_key", "query", tokenAuth)
|
||||
ta2 := APIKeyAuth("X-API-KEY", "header", tokenAuth)
|
||||
|
||||
req1, _ := http.NewRequest("GET", "/blah?api_key=token124", nil)
|
||||
|
||||
ok, usr, err := ta.Authenticate(req1)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, nil, usr)
|
||||
assert.Error(t, err)
|
||||
|
||||
req2, _ := http.NewRequest("GET", "/blah", nil)
|
||||
req2.Header.Set("X-API-KEY", "token124")
|
||||
|
||||
ok, usr, err = ta2.Authenticate(req2)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, nil, usr)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestMissingApiKeyAuth(t *testing.T) {
|
||||
ta := APIKeyAuth("api_key", "query", tokenAuth)
|
||||
ta2 := APIKeyAuth("X-API-KEY", "header", tokenAuth)
|
||||
|
||||
req1, _ := http.NewRequest("GET", "/blah", nil)
|
||||
req1.Header.Set("X-API-KEY", "token123")
|
||||
|
||||
ok, usr, err := ta.Authenticate(req1)
|
||||
assert.False(t, ok)
|
||||
assert.Equal(t, nil, usr)
|
||||
assert.NoError(t, err)
|
||||
|
||||
req2, _ := http.NewRequest("GET", "/blah?api_key=token123", nil)
|
||||
|
||||
ok, usr, err = ta2.Authenticate(req2)
|
||||
assert.False(t, ok)
|
||||
assert.Equal(t, nil, usr)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
128
vendor/github.com/go-openapi/runtime/security/authenticator.go
generated
vendored
Normal file
128
vendor/github.com/go-openapi/runtime/security/authenticator.go
generated
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package security
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
)
|
||||
|
||||
// HttpAuthenticator is a function that authenticates a HTTP request
|
||||
func HttpAuthenticator(handler func(*http.Request) (bool, interface{}, error)) runtime.Authenticator {
|
||||
return runtime.AuthenticatorFunc(func(params interface{}) (bool, interface{}, error) {
|
||||
if request, ok := params.(*http.Request); ok {
|
||||
return handler(request)
|
||||
}
|
||||
if scoped, ok := params.(*ScopedAuthRequest); ok {
|
||||
return handler(scoped.Request)
|
||||
}
|
||||
return false, nil, nil
|
||||
})
|
||||
}
|
||||
|
||||
// ScopedAuthenticator is a function that authenticates a HTTP request against a list of valid scopes
|
||||
func ScopedAuthenticator(handler func(*ScopedAuthRequest) (bool, interface{}, error)) runtime.Authenticator {
|
||||
return runtime.AuthenticatorFunc(func(params interface{}) (bool, interface{}, error) {
|
||||
if request, ok := params.(*ScopedAuthRequest); ok {
|
||||
return handler(request)
|
||||
}
|
||||
return false, nil, nil
|
||||
})
|
||||
}
|
||||
|
||||
// UserPassAuthentication authentication function
|
||||
type UserPassAuthentication func(string, string) (interface{}, error)
|
||||
|
||||
// TokenAuthentication authentication function
|
||||
type TokenAuthentication func(string) (interface{}, error)
|
||||
|
||||
// ScopedTokenAuthentication authentication function
|
||||
type ScopedTokenAuthentication func(string, []string) (interface{}, error)
|
||||
|
||||
// BasicAuth creates a basic auth authenticator with the provided authentication function
|
||||
func BasicAuth(authenticate UserPassAuthentication) runtime.Authenticator {
|
||||
return HttpAuthenticator(func(r *http.Request) (bool, interface{}, error) {
|
||||
if usr, pass, ok := r.BasicAuth(); ok {
|
||||
p, err := authenticate(usr, pass)
|
||||
return true, p, err
|
||||
}
|
||||
|
||||
return false, nil, nil
|
||||
})
|
||||
}
|
||||
|
||||
// APIKeyAuth creates an authenticator that uses a token for authorization.
|
||||
// This token can be obtained from either a header or a query string
|
||||
func APIKeyAuth(name, in string, authenticate TokenAuthentication) runtime.Authenticator {
|
||||
inl := strings.ToLower(in)
|
||||
if inl != "query" && inl != "header" {
|
||||
// panic because this is most likely a typo
|
||||
panic(errors.New(500, "api key auth: in value needs to be either \"query\" or \"header\"."))
|
||||
}
|
||||
|
||||
var getToken func(*http.Request) string
|
||||
switch inl {
|
||||
case "header":
|
||||
getToken = func(r *http.Request) string { return r.Header.Get(name) }
|
||||
case "query":
|
||||
getToken = func(r *http.Request) string { return r.URL.Query().Get(name) }
|
||||
}
|
||||
|
||||
return HttpAuthenticator(func(r *http.Request) (bool, interface{}, error) {
|
||||
token := getToken(r)
|
||||
if token == "" {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
p, err := authenticate(token)
|
||||
return true, p, err
|
||||
})
|
||||
}
|
||||
|
||||
// ScopedAuthRequest contains both a http request and the required scopes for a particular operation
|
||||
type ScopedAuthRequest struct {
|
||||
Request *http.Request
|
||||
RequiredScopes []string
|
||||
}
|
||||
|
||||
// BearerAuth for use with oauth2 flows
|
||||
func BearerAuth(name string, authenticate ScopedTokenAuthentication) runtime.Authenticator {
|
||||
const prefix = "Bearer "
|
||||
return ScopedAuthenticator(func(r *ScopedAuthRequest) (bool, interface{}, error) {
|
||||
var token string
|
||||
hdr := r.Request.Header.Get("Authorization")
|
||||
if strings.HasPrefix(hdr, prefix) {
|
||||
token = strings.TrimPrefix(hdr, prefix)
|
||||
}
|
||||
if token == "" {
|
||||
qs := r.Request.URL.Query()
|
||||
token = qs.Get("access_token")
|
||||
}
|
||||
ct, _, _ := runtime.ContentType(r.Request.Header)
|
||||
if token == "" && (ct == "application/x-www-form-urlencoded" || ct == "multipart/form-data") {
|
||||
token = r.Request.FormValue("access_token")
|
||||
}
|
||||
|
||||
if token == "" {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
p, err := authenticate(token, r.RequiredScopes)
|
||||
return true, p, err
|
||||
})
|
||||
}
|
||||
75
vendor/github.com/go-openapi/runtime/security/basic_auth_test.go
generated
vendored
Normal file
75
vendor/github.com/go-openapi/runtime/security/basic_auth_test.go
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package security
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var basicAuthHandler = UserPassAuthentication(func(user, pass string) (interface{}, error) {
|
||||
if user == "admin" && pass == "123456" {
|
||||
return "admin", nil
|
||||
}
|
||||
return "", errors.Unauthenticated("basic")
|
||||
})
|
||||
|
||||
func TestValidBasicAuth(t *testing.T) {
|
||||
ba := BasicAuth(basicAuthHandler)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/blah", nil)
|
||||
req.SetBasicAuth("admin", "123456")
|
||||
ok, usr, err := ba.Authenticate(req)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "admin", usr)
|
||||
}
|
||||
|
||||
func TestInvalidBasicAuth(t *testing.T) {
|
||||
ba := BasicAuth(basicAuthHandler)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/blah", nil)
|
||||
req.SetBasicAuth("admin", "admin")
|
||||
ok, usr, err := ba.Authenticate(req)
|
||||
|
||||
assert.Error(t, err)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "", usr)
|
||||
}
|
||||
|
||||
func TestMissingbasicAuth(t *testing.T) {
|
||||
ba := BasicAuth(basicAuthHandler)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/blah", nil)
|
||||
|
||||
ok, usr, err := ba.Authenticate(req)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, ok)
|
||||
assert.Equal(t, nil, usr)
|
||||
}
|
||||
|
||||
func TestNoRequestBasicAuth(t *testing.T) {
|
||||
ba := BasicAuth(basicAuthHandler)
|
||||
|
||||
ok, usr, err := ba.Authenticate("token")
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, ok)
|
||||
assert.Nil(t, usr)
|
||||
}
|
||||
143
vendor/github.com/go-openapi/runtime/security/bearer_auth_test.go
generated
vendored
Normal file
143
vendor/github.com/go-openapi/runtime/security/bearer_auth_test.go
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
package security
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var bearerAuth = ScopedTokenAuthentication(func(token string, requiredScopes []string) (interface{}, error) {
|
||||
if token == "token123" {
|
||||
return "admin", nil
|
||||
}
|
||||
return nil, errors.Unauthenticated("bearer")
|
||||
})
|
||||
|
||||
func TestValidBearerAuth(t *testing.T) {
|
||||
ba := BearerAuth("owners_auth", bearerAuth)
|
||||
|
||||
req1, _ := http.NewRequest("GET", "/blah?access_token=token123", nil)
|
||||
|
||||
ok, usr, err := ba.Authenticate(&ScopedAuthRequest{Request: req1})
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "admin", usr)
|
||||
assert.NoError(t, err)
|
||||
|
||||
req2, _ := http.NewRequest("GET", "/blah", nil)
|
||||
req2.Header.Set("Authorization", "Bearer token123")
|
||||
|
||||
ok, usr, err = ba.Authenticate(&ScopedAuthRequest{Request: req2})
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "admin", usr)
|
||||
assert.NoError(t, err)
|
||||
|
||||
body := url.Values(map[string][]string{})
|
||||
body.Set("access_token", "token123")
|
||||
req3, _ := http.NewRequest("POST", "/blah", strings.NewReader(body.Encode()))
|
||||
req3.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
ok, usr, err = ba.Authenticate(&ScopedAuthRequest{Request: req3})
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "admin", usr)
|
||||
assert.NoError(t, err)
|
||||
|
||||
mpbody := bytes.NewBuffer(nil)
|
||||
writer := multipart.NewWriter(mpbody)
|
||||
writer.WriteField("access_token", "token123")
|
||||
writer.Close()
|
||||
req4, _ := http.NewRequest("POST", "/blah", mpbody)
|
||||
req4.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
|
||||
ok, usr, err = ba.Authenticate(&ScopedAuthRequest{Request: req4})
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "admin", usr)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestInvalidBearerAuth(t *testing.T) {
|
||||
ba := BearerAuth("owners_auth", bearerAuth)
|
||||
|
||||
req1, _ := http.NewRequest("GET", "/blah?access_token=token124", nil)
|
||||
|
||||
ok, usr, err := ba.Authenticate(&ScopedAuthRequest{Request: req1})
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, nil, usr)
|
||||
assert.Error(t, err)
|
||||
|
||||
req2, _ := http.NewRequest("GET", "/blah", nil)
|
||||
req2.Header.Set("Authorization", "Bearer token124")
|
||||
|
||||
ok, usr, err = ba.Authenticate(&ScopedAuthRequest{Request: req2})
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, nil, usr)
|
||||
assert.Error(t, err)
|
||||
|
||||
body := url.Values(map[string][]string{})
|
||||
body.Set("access_token", "token124")
|
||||
req3, _ := http.NewRequest("POST", "/blah", strings.NewReader(body.Encode()))
|
||||
req3.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
ok, usr, err = ba.Authenticate(&ScopedAuthRequest{Request: req3})
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, nil, usr)
|
||||
assert.Error(t, err)
|
||||
|
||||
mpbody := bytes.NewBuffer(nil)
|
||||
writer := multipart.NewWriter(mpbody)
|
||||
writer.WriteField("access_token", "token124")
|
||||
writer.Close()
|
||||
req4, _ := http.NewRequest("POST", "/blah", mpbody)
|
||||
req4.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
|
||||
ok, usr, err = ba.Authenticate(&ScopedAuthRequest{Request: req4})
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, nil, usr)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestMissingBearerAuth(t *testing.T) {
|
||||
ba := BearerAuth("owners_auth", bearerAuth)
|
||||
|
||||
req1, _ := http.NewRequest("GET", "/blah?access_toke=token123", nil)
|
||||
|
||||
ok, usr, err := ba.Authenticate(&ScopedAuthRequest{Request: req1})
|
||||
assert.False(t, ok)
|
||||
assert.Equal(t, nil, usr)
|
||||
assert.NoError(t, err)
|
||||
|
||||
req2, _ := http.NewRequest("GET", "/blah", nil)
|
||||
req2.Header.Set("Authorization", "Beare token123")
|
||||
|
||||
ok, usr, err = ba.Authenticate(&ScopedAuthRequest{Request: req2})
|
||||
assert.False(t, ok)
|
||||
assert.Equal(t, nil, usr)
|
||||
assert.NoError(t, err)
|
||||
|
||||
body := url.Values(map[string][]string{})
|
||||
body.Set("access_toke", "token123")
|
||||
req3, _ := http.NewRequest("POST", "/blah", strings.NewReader(body.Encode()))
|
||||
req3.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
ok, usr, err = ba.Authenticate(&ScopedAuthRequest{Request: req3})
|
||||
assert.False(t, ok)
|
||||
assert.Equal(t, nil, usr)
|
||||
assert.NoError(t, err)
|
||||
|
||||
mpbody := bytes.NewBuffer(nil)
|
||||
writer := multipart.NewWriter(mpbody)
|
||||
writer.WriteField("access_toke", "token123")
|
||||
writer.Close()
|
||||
req4, _ := http.NewRequest("POST", "/blah", mpbody)
|
||||
req4.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
|
||||
ok, usr, err = ba.Authenticate(&ScopedAuthRequest{Request: req4})
|
||||
assert.False(t, ok)
|
||||
assert.Equal(t, nil, usr)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
90
vendor/github.com/go-openapi/runtime/statuses.go
generated
vendored
Normal file
90
vendor/github.com/go-openapi/runtime/statuses.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package runtime
|
||||
|
||||
// Statuses lists the most common HTTP status codes to default message
|
||||
// taken from https://httpstatuses.com/
|
||||
var Statuses = map[int]string{
|
||||
100: "Continue",
|
||||
101: "Switching Protocols",
|
||||
102: "Processing",
|
||||
103: "Checkpoint",
|
||||
122: "URI too long",
|
||||
200: "OK",
|
||||
201: "Created",
|
||||
202: "Accepted",
|
||||
203: "Request Processed",
|
||||
204: "No Content",
|
||||
205: "Reset Content",
|
||||
206: "Partial Content",
|
||||
207: "Multi-Status",
|
||||
208: "Already Reported",
|
||||
226: "IM Used",
|
||||
300: "Multiple Choices",
|
||||
301: "Moved Permanently",
|
||||
302: "Found",
|
||||
303: "See Other",
|
||||
304: "Not Modified",
|
||||
305: "Use Proxy",
|
||||
306: "Switch Proxy",
|
||||
307: "Temporary Redirect",
|
||||
308: "Permanent Redirect",
|
||||
400: "Bad Request",
|
||||
401: "Unauthorized",
|
||||
402: "Payment Required",
|
||||
403: "Forbidden",
|
||||
404: "Not Found",
|
||||
405: "Method Not Allowed",
|
||||
406: "Not Acceptable",
|
||||
407: "Proxy Authentication Required",
|
||||
408: "Request Timeout",
|
||||
409: "Conflict",
|
||||
410: "Gone",
|
||||
411: "Length Required",
|
||||
412: "Precondition Failed",
|
||||
413: "Request Entity Too Large",
|
||||
414: "Request-URI Too Long",
|
||||
415: "Unsupported Media Type",
|
||||
416: "Request Range Not Satisfiable",
|
||||
417: "Expectation Failed",
|
||||
418: "I'm a teapot",
|
||||
420: "Enhance Your Calm",
|
||||
422: "Unprocessable Entity",
|
||||
423: "Locked",
|
||||
424: "Failed Dependency",
|
||||
426: "Upgrade Required",
|
||||
428: "Precondition Required",
|
||||
429: "Too Many Requests",
|
||||
431: "Request Header Fields Too Large",
|
||||
444: "No Response",
|
||||
449: "Retry With",
|
||||
450: "Blocked by Windows Parental Controls",
|
||||
451: "Wrong Exchange Server",
|
||||
499: "Client Closed Request",
|
||||
500: "Internal Server Error",
|
||||
501: "Not Implemented",
|
||||
502: "Bad Gateway",
|
||||
503: "Service Unavailable",
|
||||
504: "Gateway Timeout",
|
||||
505: "HTTP Version Not Supported",
|
||||
506: "Variant Also Negotiates",
|
||||
507: "Insufficient Storage",
|
||||
508: "Loop Detected",
|
||||
509: "Bandwidth Limit Exceeded",
|
||||
510: "Not Extended",
|
||||
511: "Network Authentication Required",
|
||||
598: "Network read timeout error",
|
||||
599: "Network connect timeout error",
|
||||
}
|
||||
96
vendor/github.com/go-openapi/runtime/text.go
generated
vendored
Normal file
96
vendor/github.com/go-openapi/runtime/text.go
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// TextConsumer creates a new text consumer
|
||||
func TextConsumer() Consumer {
|
||||
return ConsumerFunc(func(reader io.Reader, data interface{}) error {
|
||||
if reader == nil {
|
||||
return errors.New("TextConsumer requires a reader") // early exit
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
_, err := buf.ReadFrom(reader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b := buf.Bytes()
|
||||
|
||||
if tu, ok := data.(encoding.TextUnmarshaler); ok {
|
||||
err := tu.UnmarshalText(b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("text consumer: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
t := reflect.TypeOf(data)
|
||||
if data != nil && t.Kind() == reflect.Ptr {
|
||||
v := reflect.Indirect(reflect.ValueOf(data))
|
||||
if t.Elem().Kind() == reflect.String {
|
||||
v.SetString(string(b))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("%v (%T) is not supported by the TextConsumer, %s",
|
||||
data, data, "can be resolved by supporting TextUnmarshaler interface")
|
||||
})
|
||||
}
|
||||
|
||||
// TextProducer creates a new text producer
|
||||
func TextProducer() Producer {
|
||||
return ProducerFunc(func(writer io.Writer, data interface{}) error {
|
||||
if writer == nil {
|
||||
return errors.New("TextProducer requires a writer") // early exit
|
||||
}
|
||||
|
||||
if data == nil {
|
||||
return errors.New("no data given to produce text from")
|
||||
}
|
||||
|
||||
if tm, ok := data.(encoding.TextMarshaler); ok {
|
||||
txt, err := tm.MarshalText()
|
||||
if err != nil {
|
||||
return fmt.Errorf("text producer: %v", err)
|
||||
}
|
||||
_, err = writer.Write(txt)
|
||||
return err
|
||||
}
|
||||
|
||||
if str, ok := data.(fmt.Stringer); ok {
|
||||
_, err := writer.Write([]byte(str.String()))
|
||||
return err
|
||||
}
|
||||
|
||||
v := reflect.Indirect(reflect.ValueOf(data))
|
||||
if v.Kind() != reflect.String {
|
||||
return fmt.Errorf("%T is not a supported type by the TextProducer", data)
|
||||
}
|
||||
|
||||
_, err := writer.Write([]byte(v.String()))
|
||||
return err
|
||||
})
|
||||
}
|
||||
151
vendor/github.com/go-openapi/runtime/text_test.go
generated
vendored
Normal file
151
vendor/github.com/go-openapi/runtime/text_test.go
generated
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var consProdText = `The quick brown fox jumped over the lazy dog.`
|
||||
|
||||
func TestTextConsumer(t *testing.T) {
|
||||
cons := TextConsumer()
|
||||
|
||||
// can consume as a string
|
||||
var str string
|
||||
err1 := cons.Consume(bytes.NewBuffer([]byte(consProdText)), &str)
|
||||
assert.NoError(t, err1)
|
||||
assert.Equal(t, consProdText, str)
|
||||
|
||||
var tu textUnmarshalDummy
|
||||
|
||||
// can consume as a TextUnmarshaler
|
||||
err3 := cons.Consume(bytes.NewBuffer([]byte(consProdText)), &tu)
|
||||
assert.NoError(t, err3)
|
||||
assert.Equal(t, consProdText, tu.str)
|
||||
|
||||
// text unmarshal objects can return an error as well, this will be propagated
|
||||
assert.Error(t, cons.Consume(bytes.NewBuffer(nil), &tu))
|
||||
|
||||
// when readers can't be read, those errors will be propogated as well
|
||||
assert.Error(t, cons.Consume(new(nopReader), &tu))
|
||||
|
||||
// readers can also not be nil
|
||||
assert.Error(t, cons.Consume(nil, &tu))
|
||||
|
||||
// can't consume nil ptr's or unsupported types
|
||||
assert.Error(t, cons.Consume(bytes.NewBuffer([]byte(consProdText)), nil))
|
||||
assert.Error(t, cons.Consume(bytes.NewBuffer([]byte(consProdText)), 42))
|
||||
assert.Error(t, cons.Consume(bytes.NewBuffer([]byte(consProdText)), &struct{}{}))
|
||||
}
|
||||
|
||||
type textUnmarshalDummy struct {
|
||||
str string
|
||||
}
|
||||
|
||||
func (t *textUnmarshalDummy) UnmarshalText(b []byte) error {
|
||||
if len(b) == 0 {
|
||||
return errors.New("no text given")
|
||||
}
|
||||
|
||||
t.str = string(b)
|
||||
return nil
|
||||
}
|
||||
|
||||
type nopReader struct{}
|
||||
|
||||
func (n *nopReader) Read(p []byte) (int, error) {
|
||||
return 0, errors.New("nop")
|
||||
}
|
||||
|
||||
func TestTextProducer(t *testing.T) {
|
||||
prod := TextProducer()
|
||||
rw := httptest.NewRecorder()
|
||||
err := prod.Produce(rw, consProdText)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, consProdText, rw.Body.String())
|
||||
rw2 := httptest.NewRecorder()
|
||||
err2 := prod.Produce(rw2, &consProdText)
|
||||
assert.NoError(t, err2)
|
||||
assert.Equal(t, consProdText, rw2.Body.String())
|
||||
|
||||
// should always work with type aliases
|
||||
// as an alias is sometimes given by generated go-swagger code
|
||||
type alias string
|
||||
aliasProdText := alias(consProdText)
|
||||
rw3 := httptest.NewRecorder()
|
||||
err3 := prod.Produce(rw3, aliasProdText)
|
||||
assert.NoError(t, err3)
|
||||
assert.Equal(t, consProdText, rw3.Body.String())
|
||||
rw4 := httptest.NewRecorder()
|
||||
err4 := prod.Produce(rw4, &aliasProdText)
|
||||
assert.NoError(t, err4)
|
||||
assert.Equal(t, consProdText, rw4.Body.String())
|
||||
|
||||
const answer = "42"
|
||||
|
||||
// Should always work with objects implementing Stringer interface
|
||||
rw5 := httptest.NewRecorder()
|
||||
err5 := prod.Produce(rw5, &stringerDummy{answer})
|
||||
assert.NoError(t, err5)
|
||||
assert.Equal(t, answer, rw5.Body.String())
|
||||
|
||||
// Should always work with objects implementing TextMarshaler interface
|
||||
rw6 := httptest.NewRecorder()
|
||||
err6 := prod.Produce(rw6, &textMarshalDummy{answer})
|
||||
assert.NoError(t, err6)
|
||||
assert.Equal(t, answer, rw6.Body.String())
|
||||
|
||||
// should not work with anything that's not (indirectly) a string
|
||||
rw7 := httptest.NewRecorder()
|
||||
err7 := prod.Produce(rw7, 42)
|
||||
assert.Error(t, err7)
|
||||
// nil values should also be safely caught with an error
|
||||
rw8 := httptest.NewRecorder()
|
||||
err8 := prod.Produce(rw8, nil)
|
||||
assert.Error(t, err8)
|
||||
|
||||
// writer can not be nil
|
||||
assert.Error(t, prod.Produce(nil, &textMarshalDummy{answer}))
|
||||
|
||||
// should not work for a textMarshaler that returns an error during marshalling
|
||||
rw9 := httptest.NewRecorder()
|
||||
err9 := prod.Produce(rw9, new(textMarshalDummy))
|
||||
assert.Error(t, err9)
|
||||
}
|
||||
|
||||
type stringerDummy struct {
|
||||
str string
|
||||
}
|
||||
|
||||
func (t *stringerDummy) String() string {
|
||||
return t.str
|
||||
}
|
||||
|
||||
type textMarshalDummy struct {
|
||||
str string
|
||||
}
|
||||
|
||||
func (t *textMarshalDummy) MarshalText() ([]byte, error) {
|
||||
if t.str == "" {
|
||||
return nil, errors.New("no text set")
|
||||
}
|
||||
return []byte(t.str), nil
|
||||
}
|
||||
19
vendor/github.com/go-openapi/runtime/values.go
generated
vendored
Normal file
19
vendor/github.com/go-openapi/runtime/values.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package runtime
|
||||
|
||||
// Values typically represent parameters on a http request.
|
||||
type Values map[string][]string
|
||||
|
||||
// GetOK returns the values collection for the given key.
|
||||
// When the key is present in the map it will return true for hasKey.
|
||||
// When the value is not empty it will return true for hasValue.
|
||||
func (v Values) GetOK(key string) (value []string, hasKey bool, hasValue bool) {
|
||||
value, hasKey = v[key]
|
||||
if !hasKey {
|
||||
return
|
||||
}
|
||||
if len(value) == 0 {
|
||||
return
|
||||
}
|
||||
hasValue = true
|
||||
return
|
||||
}
|
||||
36
vendor/github.com/go-openapi/runtime/xml.go
generated
vendored
Normal file
36
vendor/github.com/go-openapi/runtime/xml.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"io"
|
||||
)
|
||||
|
||||
// XMLConsumer creates a new XML consumer
|
||||
func XMLConsumer() Consumer {
|
||||
return ConsumerFunc(func(reader io.Reader, data interface{}) error {
|
||||
dec := xml.NewDecoder(reader)
|
||||
return dec.Decode(data)
|
||||
})
|
||||
}
|
||||
|
||||
// XMLProducer creates a new XML producer
|
||||
func XMLProducer() Producer {
|
||||
return ProducerFunc(func(writer io.Writer, data interface{}) error {
|
||||
enc := xml.NewEncoder(writer)
|
||||
return enc.Encode(data)
|
||||
})
|
||||
}
|
||||
53
vendor/github.com/go-openapi/runtime/xml_test.go
generated
vendored
Normal file
53
vendor/github.com/go-openapi/runtime/xml_test.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var consProdXML = `<person><name>Somebody</name><id>1</id></person>`
|
||||
|
||||
func TestXMLConsumer(t *testing.T) {
|
||||
cons := XMLConsumer()
|
||||
var data struct {
|
||||
XMLName xml.Name `xml:"person"`
|
||||
Name string `xml:"name"`
|
||||
ID int `xml:"id"`
|
||||
}
|
||||
err := cons.Consume(bytes.NewBuffer([]byte(consProdXML)), &data)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "Somebody", data.Name)
|
||||
assert.Equal(t, 1, data.ID)
|
||||
}
|
||||
|
||||
func TestXMLProducer(t *testing.T) {
|
||||
prod := XMLProducer()
|
||||
data := struct {
|
||||
XMLName xml.Name `xml:"person"`
|
||||
Name string `xml:"name"`
|
||||
ID int `xml:"id"`
|
||||
}{Name: "Somebody", ID: 1}
|
||||
|
||||
rw := httptest.NewRecorder()
|
||||
err := prod.Produce(rw, data)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, consProdXML, rw.Body.String())
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user