mirror of
https://github.com/kataras/iris.git
synced 2025-12-17 18:07:01 +00:00
Update to v4.4.0 Implementation of https://github.com/kataras/iris/issues/438
Read HISTORY.md
This commit is contained in:
53
HISTORY.md
53
HISTORY.md
@@ -1,6 +1,57 @@
|
||||
# History
|
||||
|
||||
**How to upgrade**: remove your `$GOPATH/src/github.com/kataras/iris` folder, open your command-line and execute this command: `go get -u github.com/kataras/iris`.
|
||||
**How to upgrade**: remove your `$GOPATH/src/github.com/kataras` folder, open your command-line and execute this command: `go get -u github.com/kataras/iris/iris`.
|
||||
|
||||
## 4.3.0 -> 4.4.0
|
||||
|
||||
**NOTE**: For normal users this update offers nothing, read that only if you run Iris behind a proxy or balancer like `nginx` or you need to serve using a custom `net.Listener`.
|
||||
|
||||
This update implements the [support of using native servers and net.Listener instead of Iris' defined](https://github.com/kataras/iris/issues/438).
|
||||
|
||||
### Breaking changes
|
||||
- `iris.Config.Profile` field removed and the whole pprof transfered to the [iris-contrib/middleware/pprof](https://github.com/iris-contrib/middleware/tree/master/pprof).
|
||||
- `iris.ListenTLSAuto` renamed to `iris.ListenLETSENCRYPT`
|
||||
- `iris.Default.Handler` is `iris.Router` which is the Handler you can use to setup a custom router or bind Iris' router, after `iris.Build` call, to an external custom server.
|
||||
- `iris.ServerConfiguration`, `iris.ListenVirtual`, `iris.AddServer`, `iris.Go` & `iris.TesterConfiguration.ListeningAddr` removed, read below the reason and their alternatives
|
||||
|
||||
### New features
|
||||
|
||||
- Boost Performance on server's startup
|
||||
- **NEW**: `iris.Reserve()` re-starts the server if `iris.Close()` called previously.
|
||||
- **NEW**: `iris.Config.VHost` and `iris.Config.VScheme` replaces the previous `ListenVirtual`, `iris.TesterConfiguration.ListeningAddr`, `iris.ServerConfiguration.VListeningAddr`, `iris.ServerConfiguration.VScheme`.
|
||||
- **NEW**: `iris.Build` it's called automatically on Listen functions or Serve function. **CALL IT, MANUALLY, ONLY** WHEN YOU WANT TO BE ABLE TO GET THE IRIS ROUTER(`iris.Router`) AND PASS THAT, HANDLER, TO ANOTHER EXTERNAL FASTHTTP SERVER.
|
||||
- **NEW**: `iris.Serve(net.Listener)`. Starts the server using a custom net.Listener, look below for example link
|
||||
- **NEW**: now that iris supports custom net.Listener bind, I had to provide to you some net.Listeners too, such as `iris.TCP4`, `iris.UNIX`, `iris.TLS` , `iris.LETSENCRPYPT` & `iris.CERT` , all of these are optionals because you can just use the `iris.Listen`, `iris.ListenUNIX`, `iris.ListenTLS` & `iris.ListenLETSENCRYPT`, but if you want, for example, to pass your own `tls.Config` then you will have to create a custom net.Listener and pass that to the `iris.Serve(net.Listener)`.
|
||||
|
||||
With these in mind, developers are now able to fill their advanced needs without use the `iris.AddServer, ServerConfiguration and V fields`, so it's easier to:
|
||||
|
||||
- use any external (fasthttp compatible) server or router. Examples: [server](https://github.com/iris-contrib/tree/master/custom_fasthtthttp_server) and [router]((https://github.com/iris-contrib/tree/master/custom_fasthtthttp_router)
|
||||
- bind any `net.Listener` which will be used to run the Iris' HTTP server, as requested [here](https://github.com/kataras/iris/issues/395). Example [here](https://github.com/iris-contrib/tree/master/custom_net_listener)
|
||||
- setup virtual host and scheme, useful when you run Iris behind `nginx` (etc) and want template function `{{url }}` and subdomains to work as you expected. Usage:
|
||||
|
||||
```go
|
||||
iris.Config.VHost = "mydomain.com"
|
||||
iris.Config.VScheme = "https://"
|
||||
|
||||
iris.Listen(":8080")
|
||||
|
||||
// this will run on localhost:8080 but templates, subdomains and all that will act like https://mydomain.com,
|
||||
// before this update you used the iris.AddServer and iris.Go and pass some strange fields into
|
||||
|
||||
```
|
||||
|
||||
Last, for testers:
|
||||
|
||||
|
||||
Who used the `iris.ListenVirtual(...).Handler`:
|
||||
If closed server, then `iris.Build()` and `iris.Router`, otherwise just `iris.Router`.
|
||||
|
||||
|
||||
To test subdomains or a custom domain just set the `iris.Config.VHost` and `iris.Config.VScheme` fields, instead of the old `subdomain_test_handler := iris.AddServer(iris.ServerConfiguration{VListeningAddr:"...", Virtual: true, VScheme:false}).Handler`. Usage [here](https://github.com/kataras/blob/master/http_test.go).
|
||||
|
||||
|
||||
|
||||
**Finally**, I have to notify you that [examples](https://github.com/iris-contrib/examples), [plugins](https://github.com/iris-contrib/plugin), [middleware](https://github.com/iris-contrib/middleware) and [book](https://github.com/iris-contrib/gitbook) have been updated.
|
||||
|
||||
## 4.2.9 -> 4.3.0
|
||||
|
||||
|
||||
704
LICENSE
704
LICENSE
@@ -1,25 +1,7 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Gerasimos Maropoulos
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Third-party packages licenses,
|
||||
|
||||
fasthttp -
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2016 Aliaksandr Valialkin, VertaMedia
|
||||
|
||||
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
|
||||
@@ -37,685 +19,3 @@ 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.
|
||||
|
||||
|
||||
django -
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2014 Florian Schlachter
|
||||
|
||||
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.
|
||||
|
||||
handlebars -
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Aymerick JEHANNE
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Jade -
|
||||
Copyright (c) 2015, Joker.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of jade nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Blackfriday -
|
||||
is distributed under the Simplified BSD License:
|
||||
|
||||
Copyright © 2011 Russ Ross
|
||||
All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided with
|
||||
the distribution.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
klaouspost/compress -
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
sourcecode: http.go->type->methods->muxEntry.add/.get/.giveProcedureTo -
|
||||
Copyright (c) 2013 Julien Schmidt
|
||||
Copyright (c) 2016 Gerasimos Maropoulos - performance improvements
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* The names of the contributors may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL JULIEN SCHMIDT BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
color
|
||||
Copyright (c) 2016 Gerasimos Maropoulos
|
||||
Copyright (c) 2013 Fatih Arslan
|
||||
|
||||
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.
|
||||
|
||||
go-colorable - The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Yasuhiro Matsumoto
|
||||
|
||||
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.
|
||||
|
||||
mergo - Copyright (c) 2013 Dario Castañé. All rights reserved.
|
||||
mergo - Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
formam - 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.
|
||||
|
||||
|
||||
|
||||
|
||||
i18n - 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:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of
|
||||
this License; and
|
||||
You must cause any modified files to carry prominent notices stating that You
|
||||
changed the files; and
|
||||
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
|
||||
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.
|
||||
|
||||
|
||||
httpexpect - test framework,
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Victor Gaydov
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Go packages license,
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
37
README.md
37
README.md
@@ -11,7 +11,7 @@
|
||||
|
||||
<a href="#"><img src="https://img.shields.io/badge/platform-Any-ec2eb4.svg?style=flat-square" alt="Platforms"></a>
|
||||
|
||||
<a href="https://github.com/kataras/iris/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0%20%20-E91E63.svg?style=flat-square" alt="License"></a>
|
||||
<a href="https://github.com/kataras/iris/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT%20%20-E91E63.svg?style=flat-square" alt="License"></a>
|
||||
|
||||
|
||||
<a href="https://golang.org"><img src="https://img.shields.io/badge/powered_by-Go-3362c2.svg?style=flat-square" alt="Built with GoLang"></a>
|
||||
@@ -19,7 +19,7 @@
|
||||
<br/>
|
||||
|
||||
|
||||
<a href="https://github.com/kataras/iris/releases"><img src="https://img.shields.io/badge/%20version%20-%204.3.0%20-blue.svg?style=flat-square" alt="Releases"></a>
|
||||
<a href="https://github.com/kataras/iris/releases"><img src="https://img.shields.io/badge/%20version%20-%204.4.0%20-blue.svg?style=flat-square" alt="Releases"></a>
|
||||
|
||||
<a href="https://github.com/iris-contrib/examples"><img src="https://img.shields.io/badge/%20examples-repository-3362c2.svg?style=flat-square" alt="Examples"></a>
|
||||
|
||||
@@ -117,16 +117,14 @@ If you'd like to discuss this package, or ask questions about it, feel free to
|
||||
* [Chat][Chat].
|
||||
|
||||
|
||||
New website-docs & logo have been designed by the community[*](https://github.com/kataras/iris/issues/153)
|
||||
|
||||
- Website created by [@kujtimiihoxha](https://github.com/kujtimiihoxha)
|
||||
- Logo designed by [@OneebMalik](https://github.com/OneebMalik)
|
||||
New logo have been designed by the community member, [@OneebMalik](https://github.com/OneebMalik).
|
||||
|
||||
|
||||
Features
|
||||
------------
|
||||
- Focus on high performance
|
||||
- Robust routing, static, wildcard subdomains and routes.
|
||||
- Internal version checker & updater[.*](https://github.com/kataras/iris/issues/401).
|
||||
- [Websocket API](https://github.com/kataras/go-websocket), [Sessions](https://github.com/kataras/go-sessions) support out of the box
|
||||
- Remote control through [SSH](https://github.com/iris-contrib/examples/blob/master/ssh/main.go)
|
||||
- View system supporting [6+](https://github.com/kataras/go-template) template engines.[*](https://kataras.gitbooks.io/iris/content/template-engines.html)
|
||||
@@ -160,6 +158,7 @@ Features
|
||||
| [I18n Middleware ](https://github.com/iris-contrib/middleware/tree/master/i18n) | Simple internationalization | [example](https://github.com/iris-contrib/examples/tree/master/middleware_internationalization_i18n), [book section](https://kataras.gitbooks.io/iris/content/middleware-internationalization-and-localization.html) |
|
||||
| [Recovery Middleware ](https://github.com/iris-contrib/middleware/tree/master/recovery) | Safety recover the station from panic | [example](https://github.com/iris-contrib/examples/blob/master/middleware_recovery/main.go) |
|
||||
| [Logger Middleware ](https://github.com/iris-contrib/middleware/tree/master/logger) | Logs every request | [example](https://github.com/iris-contrib/examples/blob/master/middleware_logger/main.go), [book section](https://kataras.gitbooks.io/iris/content/logger.html) |
|
||||
| [Profile Middleware ](https://github.com/iris-contrib/middleware/tree/master/pprof) | Http profiling for debugging | [example](https://github.com/iris-contrib/examples/blob/master/middleware_pprof/main.go) |
|
||||
| [Editor Plugin](https://github.com/iris-contrib/plugin/tree/master/editor) | Alm-tools, a typescript online IDE/Editor | [book section](https://kataras.gitbooks.io/iris/content/plugin-editor.html) |
|
||||
| [Typescript Plugin](https://github.com/iris-contrib/plugin/tree/master/typescript) | Auto-compile client-side typescript files | [book section](https://kataras.gitbooks.io/iris/content/plugin-typescript.html) |
|
||||
| [OAuth,OAuth2 Plugin](https://github.com/iris-contrib/plugin/tree/master/oauth) | User Authentication was never be easier, supports >27 providers | [example](https://github.com/iris-contrib/examples/tree/master/plugin_oauth_oauth2), [book section](https://kataras.gitbooks.io/iris/content/plugin-oauth.html) |
|
||||
@@ -193,13 +192,12 @@ This Benchmark test aims to compare the whole HTTP request processing between Go
|
||||
Testing
|
||||
------------
|
||||
|
||||
Community should write third-party or iris base tests to the [iris-contrib/tests repository](https://github.com/iris-contrib/tests).
|
||||
I recommend writing your API tests using this new library, [httpexpect](https://github.com/gavv/httpexpect) which supports Iris and fasthttp now, after my request [here](https://github.com/gavv/httpexpect/issues/2).
|
||||
I recommend writing your API tests using this new library, [httpexpect](https://github.com/gavv/httpexpect) which supports Iris and fasthttp now, after my request [here](https://github.com/gavv/httpexpect/issues/2). You can find Iris examples [here](https://github.com/gavv/httpexpect/blob/master/example/iris_test.go), [here](https://github.com/kataras/iris/blob/master/http_test.go) and [here](https://github.com/kataras/iris/blob/master/context_test.go).
|
||||
|
||||
Versioning
|
||||
------------
|
||||
|
||||
Current: **v4.3.0**
|
||||
Current: **v4.4.0**
|
||||
|
||||
> Iris is an active project
|
||||
|
||||
@@ -214,6 +212,7 @@ Todo
|
||||
- [x] Use of the standard `log.Logger` instead of the `iris-contrib/logger`(colorful logger), make these changes to all middleware, examples and plugins.
|
||||
- [x] Implement, even, a better way to manage configuration/options, devs will be able to set their own custom options inside there. ` I'm thinking of something the last days, but it will have breaking changes. `
|
||||
- [x] Implement an internal updater, as requested [here](https://github.com/kataras/iris/issues/401).
|
||||
- [x] Support of using native servers and net.Listener instead of Iris' defined.[*](https://github.com/kataras/iris/issues/438)
|
||||
|
||||
Iris is a **Community-Driven** Project, waiting for your suggestions and [feature requests](https://github.com/kataras/iris/issues?utf8=%E2%9C%93&q=label%3A%22feature%20request%22)!
|
||||
|
||||
@@ -231,26 +230,8 @@ If you are interested in contributing to the Iris project, please see the docume
|
||||
License
|
||||
------------
|
||||
|
||||
This project is licensed under the Apache License, Version 2.0.
|
||||
This project is licensed under the MIT License, Copyright (c) 2016 Gerasimos Maropoulos.
|
||||
|
||||
License can be found [here](LICENSE).
|
||||
|
||||
[Travis Widget]: https://img.shields.io/travis/kataras/iris.svg?style=flat-square
|
||||
[Travis]: http://travis-ci.org/kataras/iris
|
||||
[License Widget]: https://img.shields.io/badge/license-Apache%202.0%20%20-E91E63.svg?style=flat-square
|
||||
[License]: https://github.com/kataras/iris/blob/master/LICENSE
|
||||
[Release Widget]: https://img.shields.io/badge/release-v4.3.0-blue.svg?style=flat-square
|
||||
[Release]: https://github.com/kataras/iris/releases
|
||||
[Chat Widget]: https://img.shields.io/badge/community-chat-00BCD4.svg?style=flat-square
|
||||
[Chat]: https://kataras.rocket.chat/channel/iris
|
||||
[ChatMain]: https://kataras.rocket.chat/channel/iris
|
||||
[ChatAlternative]: https://gitter.im/kataras/iris
|
||||
[Report Widget]: https://img.shields.io/badge/report%20card-A%2B-F44336.svg?style=flat-square
|
||||
[Report]: http://goreportcard.com/report/kataras/iris
|
||||
[Documentation Widget]: https://img.shields.io/badge/documentation-reference-5272B4.svg?style=flat-square
|
||||
[Documentation]: https://www.gitbook.com/book/kataras/iris/details
|
||||
[Examples Widget]: https://img.shields.io/badge/examples-repository-3362c2.svg?style=flat-square
|
||||
[Examples]: https://github.com/iris-contrib/examples
|
||||
[Language Widget]: https://img.shields.io/badge/powered_by-Go-3362c2.svg?style=flat-square
|
||||
[Language]: http://golang.org
|
||||
[Platform Widget]: https://img.shields.io/badge/platform-Any--OS-gray.svg?style=flat-square
|
||||
|
||||
610
configuration.go
610
configuration.go
@@ -8,7 +8,6 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -41,6 +40,78 @@ func (o OptionSet) Set(c *Configuration) {
|
||||
//
|
||||
// Configuration is also implements the OptionSet so it's a valid option itself, this is briliant enough
|
||||
type Configuration struct {
|
||||
// VHost is the addr or the domain that server listens to, which it's optional
|
||||
// When to set VHost manually:
|
||||
// 1. it's automatically setted when you're calling
|
||||
// $instance.Listen/ListenUNIX/ListenTLS/ListenLETSENCRYPT functions or
|
||||
// ln,_ := iris.TCP4/UNIX/TLS/LETSENCRYPT; $instance.Serve(ln)
|
||||
// 2. If you using a balancer, or something like nginx
|
||||
// then set it in order to have the correct url
|
||||
// when calling the template helper '{{url }}'
|
||||
// *keep note that you can use {{urlpath }}) instead*
|
||||
//
|
||||
// Note: this is the main's server Host, you can setup unlimited number of fasthttp servers
|
||||
// listening to the $instance.Handler after the manually-called $instance.Build
|
||||
//
|
||||
// Default comes from iris.Listen/.Serve with iris' listeners (iris.TCP4/UNIX/TLS/LETSENCRYPT)
|
||||
VHost string
|
||||
|
||||
// VScheme is the scheme (http:// or https://) putted at the template function '{{url }}'
|
||||
// It's an optional field,
|
||||
// When to set VScheme manually:
|
||||
// 1. You didn't start the main server using $instance.Listen/ListenTLS/ListenLETSENCRYPT or $instance.Serve($instance.TCP4()/.TLS...)
|
||||
// 2. if you're using something like nginx and have iris listening with addr only(http://) but the nginx mapper is listening to https://
|
||||
//
|
||||
// Default comes from iris.Listen/.Serve with iris' listeners (TCP4,UNIX,TLS,LETSENCRYPT)
|
||||
VScheme string
|
||||
|
||||
// MaxRequestBodySize Maximum request body size.
|
||||
//
|
||||
// The server rejects requests with bodies exceeding this limit.
|
||||
//
|
||||
// By default request body size is 8MB.
|
||||
MaxRequestBodySize int
|
||||
|
||||
// Per-connection buffer size for requests' reading.
|
||||
// This also limits the maximum header size.
|
||||
//
|
||||
// Increase this buffer if your clients send multi-KB RequestURIs
|
||||
// and/or multi-KB headers (for example, BIG cookies).
|
||||
//
|
||||
// Default buffer size is used if not set.
|
||||
ReadBufferSize int
|
||||
|
||||
// Per-connection buffer size for responses' writing.
|
||||
//
|
||||
// Default buffer size is used if not set.
|
||||
WriteBufferSize int
|
||||
|
||||
// Maximum duration for reading the full request (including body).
|
||||
//
|
||||
// This also limits the maximum duration for idle keep-alive
|
||||
// connections.
|
||||
//
|
||||
// By default request read timeout is unlimited.
|
||||
ReadTimeout time.Duration
|
||||
|
||||
// Maximum duration for writing the full response (including body).
|
||||
//
|
||||
// By default response write timeout is unlimited.
|
||||
WriteTimeout time.Duration
|
||||
|
||||
// Maximum number of concurrent client connections allowed per IP.
|
||||
//
|
||||
// By default unlimited number of concurrent connections
|
||||
MaxConnsPerIP int
|
||||
|
||||
// Maximum number of requests served per connection.
|
||||
//
|
||||
// The server closes connection after the last request.
|
||||
// 'Connection: close' header is added to the last response.
|
||||
//
|
||||
// By default unlimited number of requests may be served per connection.
|
||||
MaxRequestsPerConn int
|
||||
|
||||
// CheckForUpdates will try to search for newer version of Iris based on the https://github.com/kataras/iris/releases
|
||||
// If a newer version found then the app will ask the he dev/user if want to update the 'x' version
|
||||
// if 'y' is pressed then the updater will try to install the latest version
|
||||
@@ -102,35 +173,6 @@ type Configuration struct {
|
||||
// Default is [IRIS]
|
||||
LoggerPreffix string
|
||||
|
||||
// ProfilePath a the route path, set it to enable http pprof tool
|
||||
// Default is empty, if you set it to a $path, these routes will handled:
|
||||
// $path/cmdline
|
||||
// $path/profile
|
||||
// $path/symbol
|
||||
// $path/goroutine
|
||||
// $path/heap
|
||||
// $path/threadcreate
|
||||
// $path/pprof/block
|
||||
// for example if '/debug/pprof'
|
||||
// http://yourdomain:PORT/debug/pprof/
|
||||
// http://yourdomain:PORT/debug/pprof/cmdline
|
||||
// http://yourdomain:PORT/debug/pprof/profile
|
||||
// http://yourdomain:PORT/debug/pprof/symbol
|
||||
// http://yourdomain:PORT/debug/pprof/goroutine
|
||||
// http://yourdomain:PORT/debug/pprof/heap
|
||||
// http://yourdomain:PORT/debug/pprof/threadcreate
|
||||
// http://yourdomain:PORT/debug/pprof/pprof/block
|
||||
// it can be a subdomain also, for example, if 'debug.'
|
||||
// http://debug.yourdomain:PORT/
|
||||
// http://debug.yourdomain:PORT/cmdline
|
||||
// http://debug.yourdomain:PORT/profile
|
||||
// http://debug.yourdomain:PORT/symbol
|
||||
// http://debug.yourdomain:PORT/goroutine
|
||||
// http://debug.yourdomain:PORT/heap
|
||||
// http://debug.yourdomain:PORT/threadcreate
|
||||
// http://debug.yourdomain:PORT/pprof/block
|
||||
ProfilePath string
|
||||
|
||||
// DisableTemplateEngines set to true to disable loading the default template engine (html/template) and disallow the use of iris.UseEngine
|
||||
// default is false
|
||||
DisableTemplateEngines bool
|
||||
@@ -176,6 +218,116 @@ func (c Configuration) Set(main *Configuration) {
|
||||
|
||||
// All options starts with "Option" preffix in order to be easier to find what dev searching for
|
||||
var (
|
||||
|
||||
// OptionVHost is the addr or the domain that server listens to, which it's optional
|
||||
// When to set VHost manually:
|
||||
// 1. it's automatically setted when you're calling
|
||||
// $instance.Listen/ListenUNIX/ListenTLS/ListenLETSENCRYPT functions or
|
||||
// ln,_ := iris.TCP4/UNIX/TLS/LETSENCRYPT; $instance.Serve(ln)
|
||||
// 2. If you using a balancer, or something like nginx
|
||||
// then set it in order to have the correct url
|
||||
// when calling the template helper '{{url }}'
|
||||
// *keep note that you can use {{urlpath }}) instead*
|
||||
//
|
||||
// Note: this is the main's server Host, you can setup unlimited number of fasthttp servers
|
||||
// listening to the $instance.Handler after the manually-called $instance.Build
|
||||
//
|
||||
// Default comes from iris.Listen/.Serve with iris' listeners (iris.TCP4/UNIX/TLS/LETSENCRYPT)
|
||||
OptionVHost = func(val string) OptionSet {
|
||||
return func(c *Configuration) {
|
||||
c.VHost = val
|
||||
}
|
||||
}
|
||||
|
||||
// OptionVScheme is the scheme (http:// or https://) putted at the template function '{{url }}'
|
||||
// It's an optional field,
|
||||
// When to set Scheme manually:
|
||||
// 1. You didn't start the main server using $instance.Listen/ListenTLS/ListenLETSENCRYPT or $instance.Serve($instance.TCP4()/.TLS...)
|
||||
// 2. if you're using something like nginx and have iris listening with addr only(http://) but the nginx mapper is listening to https://
|
||||
//
|
||||
// Default comes from iris.Listen/.Serve with iris' listeners (TCP4,UNIX,TLS,LETSENCRYPT)
|
||||
OptionVScheme = func(val string) OptionSet {
|
||||
return func(c *Configuration) {
|
||||
c.VScheme = val
|
||||
}
|
||||
}
|
||||
|
||||
// OptionMaxRequestBodySize Maximum request body size.
|
||||
//
|
||||
// The server rejects requests with bodies exceeding this limit.
|
||||
//
|
||||
// By default request body size is 8MB.
|
||||
OptionMaxRequestBodySize = func(val int) OptionSet {
|
||||
return func(c *Configuration) {
|
||||
c.MaxRequestBodySize = val
|
||||
}
|
||||
}
|
||||
|
||||
// Per-connection buffer size for requests' reading.``
|
||||
// This also limits the maximum header size.
|
||||
//
|
||||
// Increase this buffer if your clients send multi-KB RequestURIs
|
||||
// and/or multi-KB headers (for example, BIG cookies).
|
||||
//
|
||||
// Default buffer size is used if not set.
|
||||
OptionReadBufferSize = func(val int) OptionSet {
|
||||
return func(c *Configuration) {
|
||||
c.ReadBufferSize = val
|
||||
}
|
||||
}
|
||||
|
||||
// Per-connection buffer size for responses' writing.
|
||||
//
|
||||
// Default buffer size is used if not set.
|
||||
OptionWriteBufferSize = func(val int) OptionSet {
|
||||
return func(c *Configuration) {
|
||||
c.WriteBufferSize = val
|
||||
}
|
||||
}
|
||||
|
||||
// Maximum duration for reading the full request (including body).
|
||||
//
|
||||
// This also limits the maximum duration for idle keep-alive
|
||||
// connections.
|
||||
//
|
||||
// By default request read timeout is unlimited.
|
||||
OptionReadTimeout = func(val time.Duration) OptionSet {
|
||||
return func(c *Configuration) {
|
||||
c.ReadTimeout = val
|
||||
}
|
||||
}
|
||||
|
||||
// Maximum duration for writing the full response (including body).
|
||||
//
|
||||
// By default response write timeout is unlimited.
|
||||
OptionWriteTimeout = func(val time.Duration) OptionSet {
|
||||
return func(c *Configuration) {
|
||||
c.WriteTimeout = val
|
||||
}
|
||||
}
|
||||
|
||||
// OptionMaxConnsPerIP Maximum number of concurrent client connections allowed per IP.
|
||||
//
|
||||
// By default unlimited number of concurrent connections
|
||||
// may be established to the server from a single IP address.
|
||||
OptionMaxConnsPerIP = func(val int) OptionSet {
|
||||
return func(c *Configuration) {
|
||||
c.MaxConnsPerIP = val
|
||||
}
|
||||
}
|
||||
|
||||
// OptionMaxRequestsPerConn Maximum number of requests served per connection.
|
||||
//
|
||||
// The server closes connection after the last request.
|
||||
// 'Connection: close' header is added to the last response.
|
||||
//
|
||||
// By default unlimited number of requests may be served per connection.
|
||||
OptionMaxRequestsPerConn = func(val int) OptionSet {
|
||||
return func(c *Configuration) {
|
||||
c.MaxRequestsPerConn = val
|
||||
}
|
||||
}
|
||||
|
||||
// OptionCheckForUpdates will try to search for newer version of Iris based on the https://github.com/kataras/iris/releases
|
||||
// If a newer version found then the app will ask the he dev/user if want to update the 'x' version
|
||||
// if 'y' is pressed then the updater will try to install the latest version
|
||||
@@ -194,7 +346,6 @@ var (
|
||||
return func(c *Configuration) {
|
||||
c.CheckForUpdates = val
|
||||
}
|
||||
|
||||
}
|
||||
// CheckForUpdatesSync checks for updates before server starts, it will have a little delay depends on the machine's download's speed
|
||||
// See CheckForUpdates for more
|
||||
@@ -256,14 +407,6 @@ var (
|
||||
}
|
||||
}
|
||||
|
||||
// OptionProfilePath a the route path, set it to enable http pprof tool
|
||||
// Default is empty, if you set it to a $path, these routes will handled:
|
||||
OptionProfilePath = func(val string) OptionSet {
|
||||
return func(c *Configuration) {
|
||||
c.ProfilePath = val
|
||||
}
|
||||
}
|
||||
|
||||
// OptionDisableTemplateEngines set to true to disable loading the default template engine (html/template) and disallow the use of iris.UseEngine
|
||||
// Default is false
|
||||
OptionDisableTemplateEngines = func(val bool) OptionSet {
|
||||
@@ -340,6 +483,25 @@ const (
|
||||
DefaultDisablePathEscape = false
|
||||
DefaultCharset = "UTF-8"
|
||||
DefaultLoggerPreffix = "[IRIS] "
|
||||
// DefaultMaxRequestBodySize is 8MB
|
||||
DefaultMaxRequestBodySize = 2 * fasthttp.DefaultMaxRequestBodySize
|
||||
|
||||
// Per-connection buffer size for requests' reading.
|
||||
// This also limits the maximum header size.
|
||||
//
|
||||
// Increase this buffer if your clients send multi-KB RequestURIs
|
||||
// and/or multi-KB headers (for example, BIG cookies).
|
||||
//
|
||||
// Default buffer size is 8MB
|
||||
DefaultReadBufferSize = 8096
|
||||
|
||||
// Per-connection buffer size for responses' writing.
|
||||
//
|
||||
// Default buffer size is 8MB
|
||||
DefaultWriteBufferSize = 8096
|
||||
|
||||
// DefaultServerName the response header of the 'Server' value when writes to the client
|
||||
DefaultServerName = "iris"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -350,6 +512,13 @@ var (
|
||||
// DefaultConfiguration returns the default configuration for an Iris station, fills the main Configuration
|
||||
func DefaultConfiguration() Configuration {
|
||||
return Configuration{
|
||||
VHost: "",
|
||||
VScheme: "",
|
||||
MaxRequestBodySize: DefaultMaxRequestBodySize,
|
||||
ReadBufferSize: DefaultReadBufferSize,
|
||||
WriteBufferSize: DefaultWriteBufferSize,
|
||||
MaxConnsPerIP: 0,
|
||||
MaxRequestsPerConn: 0,
|
||||
CheckForUpdates: false,
|
||||
CheckForUpdatesSync: false,
|
||||
DisablePathCorrection: DefaultDisablePathCorrection,
|
||||
@@ -362,7 +531,6 @@ func DefaultConfiguration() Configuration {
|
||||
TimeFormat: DefaultTimeFormat,
|
||||
Charset: DefaultCharset,
|
||||
Gzip: false,
|
||||
ProfilePath: "",
|
||||
Sessions: DefaultSessionsConfiguration(),
|
||||
Websocket: DefaultWebsocketConfiguration(),
|
||||
Tester: DefaultTesterConfiguration(),
|
||||
@@ -579,9 +747,6 @@ func DefaultWebsocketConfiguration() WebsocketConfiguration {
|
||||
|
||||
// TesterConfiguration configuration used inside main config field 'Tester'
|
||||
type TesterConfiguration struct {
|
||||
// ListeningAddr is the virtual server's listening addr (host)
|
||||
// Default is "iris-go.com:1993"
|
||||
ListeningAddr string
|
||||
// ExplicitURL If true then the url (should) be prepended manually, useful when want to test subdomains
|
||||
// Default is false
|
||||
ExplicitURL bool
|
||||
@@ -591,13 +756,6 @@ type TesterConfiguration struct {
|
||||
}
|
||||
|
||||
var (
|
||||
// OptionTesterListeningAddr is the virtual server's listening addr (host)
|
||||
// Default is "iris-go.com:1993"
|
||||
OptionTesterListeningAddr = func(val string) OptionSet {
|
||||
return func(c *Configuration) {
|
||||
c.Tester.ListeningAddr = val
|
||||
}
|
||||
}
|
||||
// OptionTesterExplicitURL If true then the url (should) be prepended manually, useful when want to test subdomains
|
||||
// Default is false
|
||||
OptionTesterExplicitURL = func(val bool) OptionSet {
|
||||
@@ -615,367 +773,19 @@ var (
|
||||
)
|
||||
|
||||
// DefaultTesterConfiguration returns the default configuration for a tester
|
||||
// the ListeningAddr is used as virtual only when no running server is founded
|
||||
func DefaultTesterConfiguration() TesterConfiguration {
|
||||
return TesterConfiguration{ListeningAddr: "iris-go.com:1993", ExplicitURL: false, Debug: false}
|
||||
}
|
||||
|
||||
// ServerConfiguration is the configuration which is used inside iris' server(s) for listening to
|
||||
type ServerConfiguration struct {
|
||||
// ListenningAddr the addr that server listens to
|
||||
ListeningAddr string
|
||||
CertFile string
|
||||
KeyFile string
|
||||
// AutoTLS enable to get certifications from the Letsencrypt
|
||||
// when this configuration field is true, the CertFile & KeyFile are empty, no need to provide a key.
|
||||
//
|
||||
// example: https://github.com/iris-contrib/examples/blob/master/letsencyrpt/main.go
|
||||
AutoTLS bool
|
||||
// Mode this is for unix only
|
||||
Mode os.FileMode
|
||||
// MaxRequestBodySize Maximum request body size.
|
||||
//
|
||||
// The server rejects requests with bodies exceeding this limit.
|
||||
//
|
||||
// By default request body size is 8MB.
|
||||
MaxRequestBodySize int
|
||||
|
||||
// Per-connection buffer size for requests' reading.
|
||||
// This also limits the maximum header size.
|
||||
//
|
||||
// Increase this buffer if your clients send multi-KB RequestURIs
|
||||
// and/or multi-KB headers (for example, BIG cookies).
|
||||
//
|
||||
// Default buffer size is used if not set.
|
||||
ReadBufferSize int
|
||||
|
||||
// Per-connection buffer size for responses' writing.
|
||||
//
|
||||
// Default buffer size is used if not set.
|
||||
WriteBufferSize int
|
||||
|
||||
// Maximum duration for reading the full request (including body).
|
||||
//
|
||||
// This also limits the maximum duration for idle keep-alive
|
||||
// connections.
|
||||
//
|
||||
// By default request read timeout is unlimited.
|
||||
ReadTimeout time.Duration
|
||||
|
||||
// Maximum duration for writing the full response (including body).
|
||||
//
|
||||
// By default response write timeout is unlimited.
|
||||
WriteTimeout time.Duration
|
||||
|
||||
// Maximum number of concurrent client connections allowed per IP.
|
||||
//
|
||||
// By default unlimited number of concurrent connections
|
||||
// may be established to the server from a single IP address.
|
||||
// Usage: iris.ListenTo{iris.OptionServerListeningAddr(":8080"), iris.OptionServerMaxConnsPerIP(300)}
|
||||
// or: iris.ListenTo(iris.ServerConfiguration{ListeningAddr: ":8080", MaxConnsPerIP: 300})
|
||||
// for an optional second server with a different port you can always use:
|
||||
// iris.AddServer(iris.ServerConfiguration{ListeningAddr: ":9090", MaxConnsPerIP: 300})
|
||||
MaxConnsPerIP int
|
||||
|
||||
// Maximum number of requests served per connection.
|
||||
//
|
||||
// The server closes connection after the last request.
|
||||
// 'Connection: close' header is added to the last response.
|
||||
//
|
||||
// By default unlimited number of requests may be served per connection.
|
||||
// Usage: iris.ListenTo{iris.OptionServerListeningAddr(":8080"), iris.OptionServerMaxConnsPerIP(300)}
|
||||
// or: iris.ListenTo(iris.ServerConfiguration{ListeningAddr: ":8080", MaxRequestsPerConn:100})
|
||||
// for an optional second server with a different port you can always use:
|
||||
// iris.AddServer(iris.ServerConfiguration{ListeningAddr: ":9090", MaxRequestsPerConn:100})
|
||||
MaxRequestsPerConn int
|
||||
|
||||
// RedirectTo, defaults to empty, set it in order to override the station's handler and redirect all requests to this address which is of form(HOST:PORT or :PORT)
|
||||
//
|
||||
// NOTE: the http status is 'StatusMovedPermanently', means one-time-redirect(the browser remembers the new addr and goes to the new address without need to request something from this server
|
||||
// which means that if you want to change this address you have to clear your browser's cache in order this to be able to change to the new addr.
|
||||
//
|
||||
// example: https://github.com/iris-contrib/examples/tree/master/multiserver_listening2
|
||||
RedirectTo string
|
||||
// Virtual If this server is not really listens to a real host, it mostly used in order to achieve testing without system modifications
|
||||
Virtual bool
|
||||
// VListeningAddr, can be used for both virtual = true or false,
|
||||
// if it's setted to not empty, then the server's Host() will return this addr instead of the ListeningAddr.
|
||||
// server's Host() is used inside global template helper funcs
|
||||
// set it when you are sure you know what it does.
|
||||
//
|
||||
// Default is empty ""
|
||||
VListeningAddr string
|
||||
// VScheme if setted to not empty value then all template's helper funcs prepends that as the url scheme instead of the real scheme
|
||||
// server's .Scheme returns VScheme if not empty && differs from real scheme
|
||||
//
|
||||
// Default is empty ""
|
||||
VScheme string
|
||||
// Name the server's name, defaults to "iris".
|
||||
// You're free to change it, but I will trust you to don't, this is the only setting whose somebody, like me, can see if iris web framework is used
|
||||
Name string
|
||||
}
|
||||
|
||||
// note: ServerConfiguration is the only one config which has its own option setter because
|
||||
// it's independent from a specific iris instance:
|
||||
// same server can run on multi iris instance
|
||||
// one iris instance/station can have and listening to more than one server.
|
||||
|
||||
// OptionServerSettter server configuration option setter
|
||||
type OptionServerSettter interface {
|
||||
Set(c *ServerConfiguration)
|
||||
}
|
||||
|
||||
// OptionServerSet is the func which implements the OptionServerSettter, this is used widely
|
||||
type OptionServerSet func(c *ServerConfiguration)
|
||||
|
||||
// Set is the func which makes OptionServerSet implements the OptionServerSettter
|
||||
func (o OptionServerSet) Set(c *ServerConfiguration) {
|
||||
o(c)
|
||||
}
|
||||
|
||||
// Set implements the OptionServerSettter to the ServerConfiguration
|
||||
func (c ServerConfiguration) Set(main *ServerConfiguration) {
|
||||
mergo.MergeWithOverwrite(main, c)
|
||||
}
|
||||
|
||||
// Options for ServerConfiguration
|
||||
var (
|
||||
OptionServerListeningAddr = func(val string) OptionServerSet {
|
||||
return func(c *ServerConfiguration) {
|
||||
c.ListeningAddr = val
|
||||
}
|
||||
}
|
||||
|
||||
OptionServerCertFile = func(val string) OptionServerSet {
|
||||
return func(c *ServerConfiguration) {
|
||||
c.CertFile = val
|
||||
}
|
||||
}
|
||||
|
||||
OptionServerKeyFile = func(val string) OptionServerSet {
|
||||
return func(c *ServerConfiguration) {
|
||||
c.KeyFile = val
|
||||
}
|
||||
}
|
||||
|
||||
// AutoTLS enable to get certifications from the Letsencrypt
|
||||
// when this configuration field is true, the CertFile & KeyFile are empty, no need to provide a key.
|
||||
//
|
||||
// example: https://github.com/iris-contrib/examples/blob/master/letsencyrpt/main.go
|
||||
OptionServerAutoTLS = func(val bool) OptionServerSet {
|
||||
return func(c *ServerConfiguration) {
|
||||
c.AutoTLS = val
|
||||
}
|
||||
}
|
||||
|
||||
// Mode this is for unix only
|
||||
OptionServerMode = func(val os.FileMode) OptionServerSet {
|
||||
return func(c *ServerConfiguration) {
|
||||
c.Mode = val
|
||||
}
|
||||
}
|
||||
|
||||
// OptionServerMaxRequestBodySize Maximum request body size.
|
||||
//
|
||||
// The server rejects requests with bodies exceeding this limit.
|
||||
//
|
||||
// By default request body size is 8MB.
|
||||
OptionServerMaxRequestBodySize = func(val int) OptionServerSet {
|
||||
return func(c *ServerConfiguration) {
|
||||
c.MaxRequestBodySize = val
|
||||
}
|
||||
}
|
||||
|
||||
// Per-connection buffer size for requests' reading.
|
||||
// This also limits the maximum header size.
|
||||
//
|
||||
// Increase this buffer if your clients send multi-KB RequestURIs
|
||||
// and/or multi-KB headers (for example, BIG cookies).
|
||||
//
|
||||
// Default buffer size is used if not set.
|
||||
OptionServerReadBufferSize = func(val int) OptionServerSet {
|
||||
return func(c *ServerConfiguration) {
|
||||
c.ReadBufferSize = val
|
||||
}
|
||||
}
|
||||
|
||||
// Per-connection buffer size for responses' writing.
|
||||
//
|
||||
// Default buffer size is used if not set.
|
||||
OptionServerWriteBufferSize = func(val int) OptionServerSet {
|
||||
return func(c *ServerConfiguration) {
|
||||
c.WriteBufferSize = val
|
||||
}
|
||||
}
|
||||
|
||||
// Maximum duration for reading the full request (including body).
|
||||
//
|
||||
// This also limits the maximum duration for idle keep-alive
|
||||
// connections.
|
||||
//
|
||||
// By default request read timeout is unlimited.
|
||||
OptionServerReadTimeout = func(val time.Duration) OptionServerSet {
|
||||
return func(c *ServerConfiguration) {
|
||||
c.ReadTimeout = val
|
||||
}
|
||||
}
|
||||
|
||||
// Maximum duration for writing the full response (including body).
|
||||
//
|
||||
// By default response write timeout is unlimited.
|
||||
OptionServerWriteTimeout = func(val time.Duration) OptionServerSet {
|
||||
return func(c *ServerConfiguration) {
|
||||
c.WriteTimeout = val
|
||||
}
|
||||
}
|
||||
|
||||
// OptionServerMaxConnsPerIP Maximum number of concurrent client connections allowed per IP.
|
||||
//
|
||||
// By default unlimited number of concurrent connections
|
||||
// may be established to the server from a single IP address.
|
||||
OptionServerMaxConnsPerIP = func(val int) OptionServerSet {
|
||||
return func(c *ServerConfiguration) {
|
||||
c.MaxConnsPerIP = val
|
||||
}
|
||||
}
|
||||
|
||||
// OptionServerMaxRequestsPerConn Maximum number of requests served per connection.
|
||||
//
|
||||
// The server closes connection after the last request.
|
||||
// 'Connection: close' header is added to the last response.
|
||||
//
|
||||
// By default unlimited number of requests may be served per connection.
|
||||
OptionServerMaxRequestsPerConn = func(val int) OptionServerSet {
|
||||
return func(c *ServerConfiguration) {
|
||||
c.MaxRequestsPerConn = val
|
||||
}
|
||||
}
|
||||
|
||||
// RedirectTo, defaults to empty, set it in order to override the station's handler and redirect all requests to this address which is of form(HOST:PORT or :PORT)
|
||||
//
|
||||
// NOTE: the http status is 'StatusMovedPermanently', means one-time-redirect(the browser remembers the new addr and goes to the new address without need to request something from this server
|
||||
// which means that if you want to change this address you have to clear your browser's cache in order this to be able to change to the new addr.
|
||||
//
|
||||
// example: https://github.com/iris-contrib/examples/tree/master/multiserver_listening2
|
||||
OptionServerRedirectTo = func(val string) OptionServerSet {
|
||||
return func(c *ServerConfiguration) {
|
||||
c.RedirectTo = val
|
||||
}
|
||||
}
|
||||
|
||||
// OptionServerVirtual If this server is not really listens to a real host, it mostly used in order to achieve testing without system modifications
|
||||
OptionServerVirtual = func(val bool) OptionServerSet {
|
||||
return func(c *ServerConfiguration) {
|
||||
c.Virtual = val
|
||||
}
|
||||
}
|
||||
// OptionServerVListeningAddr, can be used for both virtual = true or false,
|
||||
// if it's setted to not empty, then the server's Host() will return this addr instead of the ListeningAddr.
|
||||
// server's Host() is used inside global template helper funcs
|
||||
// set it when you are sure you know what it does.
|
||||
//
|
||||
// Default is empty ""
|
||||
OptionServerVListeningAddr = func(val string) OptionServerSet {
|
||||
return func(c *ServerConfiguration) {
|
||||
c.VListeningAddr = val
|
||||
}
|
||||
}
|
||||
|
||||
// OptionServerVScheme if setted to not empty value then all template's helper funcs prepends that as the url scheme instead of the real scheme
|
||||
// server's .Scheme returns VScheme if not empty && differs from real scheme
|
||||
//
|
||||
// Default is empty ""
|
||||
OptionServerVScheme = func(val string) OptionServerSet {
|
||||
return func(c *ServerConfiguration) {
|
||||
c.VScheme = val
|
||||
}
|
||||
}
|
||||
|
||||
// OptionServerName the server's name, defaults to "iris".
|
||||
// You're free to change it, but I will trust you to don't, this is the only setting whose somebody, like me, can see if iris web framework is used
|
||||
OptionServerName = func(val string) OptionServerSet {
|
||||
return func(c *ServerConfiguration) {
|
||||
c.ListeningAddr = val
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// ServerParseAddr parses the listening addr and returns this
|
||||
func ServerParseAddr(listeningAddr string) string {
|
||||
// check if addr has :port, if not do it +:80 ,we need the hostname for many cases
|
||||
a := listeningAddr
|
||||
if a == "" {
|
||||
// check for os environments
|
||||
if oshost := os.Getenv("HOST"); oshost != "" {
|
||||
a = oshost
|
||||
} else if oshost := os.Getenv("ADDR"); oshost != "" {
|
||||
a = oshost
|
||||
} else if osport := os.Getenv("PORT"); osport != "" {
|
||||
a = ":" + osport
|
||||
}
|
||||
|
||||
if a == "" {
|
||||
a = DefaultServerAddr
|
||||
}
|
||||
|
||||
}
|
||||
if portIdx := strings.IndexByte(a, ':'); portIdx == 0 {
|
||||
// if contains only :port ,then the : is the first letter, so we dont have setted a hostname, lets set it
|
||||
a = DefaultServerHostname + a
|
||||
}
|
||||
if portIdx := strings.IndexByte(a, ':'); portIdx < 0 {
|
||||
// missing port part, add it
|
||||
a = a + ":80"
|
||||
}
|
||||
|
||||
return a
|
||||
return TesterConfiguration{ExplicitURL: false, Debug: false}
|
||||
}
|
||||
|
||||
// Default values for base Server conf
|
||||
const (
|
||||
// DefaultServerHostname returns the default hostname which is 0.0.0.0
|
||||
DefaultServerHostname = "0.0.0.0"
|
||||
// DefaultServerPort returns the default port which is 8080
|
||||
// DefaultServerPort returns the default port which is 8080, not used
|
||||
DefaultServerPort = 8080
|
||||
// DefaultMaxRequestBodySize is 8MB
|
||||
DefaultMaxRequestBodySize = 2 * fasthttp.DefaultMaxRequestBodySize
|
||||
|
||||
// Per-connection buffer size for requests' reading.
|
||||
// This also limits the maximum header size.
|
||||
//
|
||||
// Increase this buffer if your clients send multi-KB RequestURIs
|
||||
// and/or multi-KB headers (for example, BIG cookies).
|
||||
//
|
||||
// Default buffer size is 8MB
|
||||
DefaultReadBufferSize = 8096
|
||||
|
||||
// Per-connection buffer size for responses' writing.
|
||||
//
|
||||
// Default buffer size is 8MB
|
||||
DefaultWriteBufferSize = 8096
|
||||
|
||||
// DefaultServerName the response header of the 'Server' value when writes to the client
|
||||
DefaultServerName = "iris"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultServerAddr the default server addr which is: 0.0.0.0:8080
|
||||
DefaultServerAddr = DefaultServerHostname + ":" + strconv.Itoa(DefaultServerPort)
|
||||
)
|
||||
|
||||
// DefaultServerConfiguration returns the default configs for the server
|
||||
func DefaultServerConfiguration() ServerConfiguration {
|
||||
return ServerConfiguration{
|
||||
ListeningAddr: DefaultServerAddr,
|
||||
Name: DefaultServerName,
|
||||
MaxRequestBodySize: DefaultMaxRequestBodySize,
|
||||
ReadBufferSize: DefaultReadBufferSize,
|
||||
WriteBufferSize: DefaultWriteBufferSize,
|
||||
MaxConnsPerIP: 0,
|
||||
MaxRequestsPerConn: 0,
|
||||
RedirectTo: "",
|
||||
Virtual: false,
|
||||
VListeningAddr: "",
|
||||
VScheme: "",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,15 +67,15 @@ func TestConfigOptionsDeep(t *testing.T) {
|
||||
cookiename := "MYSESSIONID"
|
||||
charset := "MYCHARSET"
|
||||
dev := true
|
||||
profilePath := "/mypprof"
|
||||
vhost := "mydomain.com"
|
||||
// first session, after charset,dev and profilepath, no canonical order.
|
||||
api := New(OptionSessionsCookie(cookiename), OptionCharset(charset), OptionIsDevelopment(dev), OptionProfilePath(profilePath))
|
||||
api := New(OptionSessionsCookie(cookiename), OptionCharset(charset), OptionIsDevelopment(dev), OptionVHost(vhost))
|
||||
|
||||
expected := DefaultConfiguration()
|
||||
expected.Sessions.Cookie = cookiename
|
||||
expected.Charset = charset
|
||||
expected.IsDevelopment = dev
|
||||
expected.ProfilePath = profilePath
|
||||
expected.VHost = vhost
|
||||
|
||||
has := *api.Config
|
||||
|
||||
@@ -83,20 +83,3 @@ func TestConfigOptionsDeep(t *testing.T) {
|
||||
t.Fatalf("DEEP configuration is not the same after New expected:\n %#v \ngot:\n %#v", expected, has)
|
||||
}
|
||||
}
|
||||
|
||||
// ServerConfiguration is independent so make a small test for that
|
||||
func TestConfigServerOptions(t *testing.T) {
|
||||
expected := DefaultServerConfiguration()
|
||||
expected.ListeningAddr = "mydomain.com:80"
|
||||
expected.RedirectTo = "https://mydomain.com:443"
|
||||
expected.Virtual = true
|
||||
|
||||
c := ServerConfiguration{ListeningAddr: expected.ListeningAddr, RedirectTo: expected.RedirectTo, Virtual: expected.Virtual}
|
||||
// static config test
|
||||
s := newServer(c)
|
||||
|
||||
if !reflect.DeepEqual(s.Config, expected) {
|
||||
t.Fatalf("Static Server Configuration not equal after newServer, expected:\n%#v \nwhile got:\n%#v", expected, s.Config)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ func (ctx *Context) HostString() string {
|
||||
func (ctx *Context) VirtualHostname() string {
|
||||
realhost := ctx.HostString()
|
||||
hostname := realhost
|
||||
virtualhost := ctx.framework.Servers.Main().Hostname()
|
||||
virtualhost := ctx.framework.mux.hostname
|
||||
|
||||
if portIdx := strings.IndexByte(hostname, ':'); portIdx > 0 {
|
||||
hostname = hostname[0:portIdx]
|
||||
|
||||
@@ -128,7 +128,7 @@ func TestContextURLParams(t *testing.T) {
|
||||
// hoststring returns the full host, will return the HOST:IP
|
||||
func TestContextHostString(t *testing.T) {
|
||||
initDefault()
|
||||
Config.Tester.ListeningAddr = "localhost:8080"
|
||||
Default.Config.VHost = "0.0.0.0:8080"
|
||||
Get("/", func(ctx *Context) {
|
||||
ctx.Write(ctx.HostString())
|
||||
})
|
||||
@@ -138,8 +138,8 @@ func TestContextHostString(t *testing.T) {
|
||||
})
|
||||
|
||||
e := Tester(t)
|
||||
e.GET("/").Expect().Status(StatusOK).Body().Equal(Config.Tester.ListeningAddr)
|
||||
e.GET("/wrong").Expect().Body().NotEqual(Config.Tester.ListeningAddr)
|
||||
e.GET("/").Expect().Status(StatusOK).Body().Equal(Default.Config.VHost)
|
||||
e.GET("/wrong").Expect().Body().NotEqual(Default.Config.VHost)
|
||||
}
|
||||
|
||||
// VirtualHostname returns the hostname only,
|
||||
@@ -147,7 +147,7 @@ func TestContextHostString(t *testing.T) {
|
||||
func TestContextVirtualHostName(t *testing.T) {
|
||||
initDefault()
|
||||
vhost := "mycustomvirtualname.com"
|
||||
Config.Tester.ListeningAddr = vhost + ":8080"
|
||||
Default.Config.VHost = vhost + ":8080"
|
||||
Get("/", func(ctx *Context) {
|
||||
ctx.Write(ctx.VirtualHostname())
|
||||
})
|
||||
@@ -176,13 +176,15 @@ func TestContextFormValueString(t *testing.T) {
|
||||
|
||||
func TestContextSubdomain(t *testing.T) {
|
||||
initDefault()
|
||||
Config.Tester.ListeningAddr = "mydomain.com:9999"
|
||||
//Config.Tester.ExplicitURL = true
|
||||
Default.Config.VHost = "mydomain.com:9999"
|
||||
//Default.Config.Tester.ListeningAddr = "mydomain.com:9999"
|
||||
// Default.Config.Tester.ExplicitURL = true
|
||||
Party("mysubdomain.").Get("/mypath", func(ctx *Context) {
|
||||
ctx.Write(ctx.Subdomain())
|
||||
})
|
||||
|
||||
e := Tester(t)
|
||||
|
||||
e.GET("/").WithURL("http://mysubdomain.mydomain.com:9999").Expect().Status(StatusNotFound)
|
||||
e.GET("/mypath").WithURL("http://mysubdomain.mydomain.com:9999").Expect().Status(StatusOK).Body().Equal("mysubdomain")
|
||||
|
||||
@@ -560,7 +562,7 @@ func TestContextSessions(t *testing.T) {
|
||||
// request cookie should be empty
|
||||
Get("/after_destroy", func(ctx *Context) {
|
||||
})
|
||||
|
||||
Default.Config.VHost = "mydomain.com"
|
||||
e := Tester(t)
|
||||
|
||||
e.POST("/set").WithJSON(values).Expect().Status(StatusOK).Cookies().NotEmpty()
|
||||
|
||||
659
http.go
659
http.go
@@ -3,23 +3,20 @@ package iris
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"github.com/iris-contrib/letsencrypt"
|
||||
"github.com/kataras/go-errors"
|
||||
"github.com/kataras/iris/utils"
|
||||
"github.com/valyala/fasthttp"
|
||||
"github.com/valyala/fasthttp/fasthttpadaptor"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"log"
|
||||
|
||||
"github.com/iris-contrib/letsencrypt"
|
||||
"github.com/kataras/go-errors"
|
||||
"github.com/kataras/iris/utils"
|
||||
"github.com/valyala/fasthttp"
|
||||
"github.com/valyala/fasthttp/fasthttpadaptor"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -229,370 +226,6 @@ func StatusText(code int) string {
|
||||
return statusText[code]
|
||||
}
|
||||
|
||||
// Errors introduced by server.
|
||||
var (
|
||||
errServerPortAlreadyUsed = errors.New("Server can't run, port is already used")
|
||||
errServerAlreadyStarted = errors.New("Server is already started and listening")
|
||||
errServerHandlerMissing = errors.New("Handler is missing from server, can't start without handler")
|
||||
errServerIsClosed = errors.New("Can't close the server, propably is already closed or never started")
|
||||
errServerRemoveUnix = errors.New("Unexpected error when trying to remove unix socket file. Addr: %s | Trace: %s")
|
||||
errServerChmod = errors.New("Cannot chmod %#o for %q: %s")
|
||||
)
|
||||
|
||||
type (
|
||||
// Server the http server
|
||||
Server struct {
|
||||
*fasthttp.Server
|
||||
listener net.Listener
|
||||
Config ServerConfiguration
|
||||
tls bool
|
||||
mu sync.Mutex
|
||||
}
|
||||
// ServerList contains the servers connected to the Iris station
|
||||
ServerList struct {
|
||||
mux *serveMux
|
||||
servers []*Server
|
||||
}
|
||||
)
|
||||
|
||||
// newServer returns a pointer to a Server object, and set it's options if any, nothing more
|
||||
func newServer(setters ...OptionServerSettter) *Server {
|
||||
c := DefaultServerConfiguration()
|
||||
for _, setter := range setters {
|
||||
setter.Set(&c)
|
||||
}
|
||||
|
||||
s := &Server{Server: &fasthttp.Server{Name: c.Name}, Config: c}
|
||||
return s
|
||||
}
|
||||
|
||||
// IsListening returns true if server is listening/started, otherwise false
|
||||
func (s *Server) IsListening() bool {
|
||||
if s == nil {
|
||||
return false
|
||||
}
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.listener != nil && s.listener.Addr().String() != ""
|
||||
}
|
||||
|
||||
// IsOpened checks if handler is not nil and returns true if not, otherwise false
|
||||
// this is used to see if a server has opened, use IsListening if you want to see if the server is actually ready to serve connections
|
||||
func (s *Server) IsOpened() bool {
|
||||
if s == nil {
|
||||
return false
|
||||
}
|
||||
return s.Server != nil && s.Server.Handler != nil
|
||||
}
|
||||
|
||||
// IsSecure returns true if server uses TLS, otherwise false
|
||||
func (s *Server) IsSecure() bool {
|
||||
return s.tls || s.Config.AutoTLS // for any case
|
||||
}
|
||||
|
||||
// Listener returns the net.Listener which this server (is) listening to
|
||||
func (s *Server) Listener() net.Listener {
|
||||
return s.listener
|
||||
}
|
||||
|
||||
// Host returns the registered host for the server
|
||||
func (s *Server) Host() string {
|
||||
if s.Config.VListeningAddr != "" {
|
||||
return s.Config.VListeningAddr
|
||||
}
|
||||
return s.Config.ListeningAddr
|
||||
}
|
||||
|
||||
// Port returns the port which server listening for
|
||||
// if no port given with the ListeningAddr, it returns 80
|
||||
func (s *Server) Port() int {
|
||||
a := s.Host()
|
||||
if portIdx := strings.IndexByte(a, ':'); portIdx != -1 {
|
||||
p, err := strconv.Atoi(a[portIdx+1:])
|
||||
if err != nil {
|
||||
if s.Config.AutoTLS {
|
||||
return 443
|
||||
}
|
||||
return 80
|
||||
}
|
||||
return p
|
||||
}
|
||||
if s.Config.AutoTLS {
|
||||
return 443
|
||||
}
|
||||
return 80
|
||||
|
||||
}
|
||||
|
||||
// Scheme returns http:// or https:// if SSL is enabled
|
||||
func (s *Server) Scheme() string {
|
||||
scheme := "http://"
|
||||
// we need to be able to take that before(for testing &debugging) and after server's listen
|
||||
if s.IsSecure() || (s.Config.CertFile != "" && s.Config.KeyFile != "") || s.Config.AutoTLS {
|
||||
scheme = "https://"
|
||||
}
|
||||
// but if virtual scheme is setted and it differs from the real scheme, return the vscheme
|
||||
// the developer should set it correctly, http:// or https:// or anything at the future:P
|
||||
vscheme := s.Config.VScheme
|
||||
if len(vscheme) > 0 && vscheme != scheme {
|
||||
return vscheme
|
||||
}
|
||||
|
||||
return scheme
|
||||
}
|
||||
|
||||
// FullHost returns the scheme+host
|
||||
func (s *Server) FullHost() string {
|
||||
return s.Scheme() + s.Host()
|
||||
}
|
||||
|
||||
// Hostname returns the hostname part of the host (host expect port)
|
||||
func (s *Server) Hostname() string {
|
||||
a := s.Host()
|
||||
idxPort := strings.IndexByte(a, ':')
|
||||
if idxPort > 0 {
|
||||
// port exists, (it always exists for Config.ListeningAddr
|
||||
return a[0:idxPort] // except the port
|
||||
} // but for Config.VListeningAddr the developer maybe doesn't uses the host:port format
|
||||
|
||||
// so, if no port found, then return the Host as it is, it should be something 'mydomain.com'
|
||||
return a
|
||||
}
|
||||
|
||||
func (s *Server) listen() error {
|
||||
if s.IsListening() {
|
||||
return errServerAlreadyStarted
|
||||
}
|
||||
listener, err := net.Listen("tcp4", s.Config.ListeningAddr)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go s.serve(listener) // we don't catch underline errors, we catched all already
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (s *Server) listenUNIX() error {
|
||||
|
||||
mode := s.Config.Mode
|
||||
addr := s.Config.ListeningAddr
|
||||
|
||||
if errOs := os.Remove(addr); errOs != nil && !os.IsNotExist(errOs) {
|
||||
return errServerRemoveUnix.Format(s.Config.ListeningAddr, errOs.Error())
|
||||
}
|
||||
|
||||
listener, err := net.Listen("unix", addr)
|
||||
|
||||
if err != nil {
|
||||
return errServerPortAlreadyUsed
|
||||
}
|
||||
|
||||
if err = os.Chmod(addr, mode); err != nil {
|
||||
return errServerChmod.Format(mode, addr, err.Error())
|
||||
}
|
||||
|
||||
go s.serve(listener) // we don't catch underline errors, we catched all already
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
//Serve just serves a listener, it is a blocking action, plugin.PostListen is not fired here.
|
||||
func (s *Server) serve(l net.Listener) error {
|
||||
s.mu.Lock()
|
||||
s.listener = l
|
||||
s.mu.Unlock()
|
||||
if s.Config.CertFile != "" && s.Config.KeyFile != "" {
|
||||
s.tls = true
|
||||
return s.Server.ServeTLS(s.listener, s.Config.CertFile, s.Config.KeyFile)
|
||||
} else if s.Config.AutoTLS {
|
||||
var m letsencrypt.Manager
|
||||
if err := m.CacheFile("letsencrypt.cache"); err != nil {
|
||||
return err
|
||||
}
|
||||
tlsConfig := &tls.Config{GetCertificate: m.GetCertificate}
|
||||
|
||||
ln := tls.NewListener(l, tlsConfig)
|
||||
s.tls = true
|
||||
s.mu.Lock()
|
||||
s.listener = ln
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
return s.Server.Serve(s.listener)
|
||||
}
|
||||
|
||||
// Open opens/starts/runs/listens (to) the server, listen tls if Cert && Key is registed, listenUNIX if Mode is registed, otherwise listen
|
||||
func (s *Server) Open(h fasthttp.RequestHandler) error {
|
||||
if h == nil {
|
||||
return errServerHandlerMissing
|
||||
}
|
||||
|
||||
if s.IsListening() {
|
||||
return errServerAlreadyStarted
|
||||
}
|
||||
|
||||
s.Server.MaxRequestBodySize = s.Config.MaxRequestBodySize
|
||||
s.Server.ReadBufferSize = s.Config.ReadBufferSize
|
||||
s.Server.WriteBufferSize = s.Config.WriteBufferSize
|
||||
s.Server.ReadTimeout = s.Config.ReadTimeout
|
||||
s.Server.WriteTimeout = s.Config.WriteTimeout
|
||||
s.Server.MaxConnsPerIP = s.Config.MaxConnsPerIP
|
||||
s.Server.MaxRequestsPerConn = s.Config.MaxRequestsPerConn
|
||||
|
||||
if s.Config.RedirectTo != "" {
|
||||
// override the handler and redirect all requests to this addr
|
||||
s.Server.Handler = func(reqCtx *fasthttp.RequestCtx) {
|
||||
path := string(reqCtx.Path())
|
||||
redirectTo := s.Config.RedirectTo
|
||||
if path != "/" {
|
||||
redirectTo += "/" + path
|
||||
}
|
||||
reqCtx.Redirect(redirectTo, StatusMovedPermanently)
|
||||
}
|
||||
} else {
|
||||
s.Server.Handler = h
|
||||
}
|
||||
|
||||
if s.Config.Mode > 0 {
|
||||
return s.listenUNIX()
|
||||
}
|
||||
|
||||
s.Config.ListeningAddr = ServerParseAddr(s.Config.ListeningAddr)
|
||||
|
||||
if s.Config.Virtual {
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.listen()
|
||||
|
||||
}
|
||||
|
||||
// Close terminates the server
|
||||
func (s *Server) Close() (err error) {
|
||||
if !s.IsListening() {
|
||||
return errServerIsClosed
|
||||
}
|
||||
err = s.listener.Close()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------------------
|
||||
// --------------------------------ServerList implementation-----------------------------
|
||||
// -------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------------------
|
||||
|
||||
// Add adds a server to the list by its config
|
||||
// returns the new server
|
||||
func (s *ServerList) Add(setters ...OptionServerSettter) *Server {
|
||||
srv := newServer(setters...)
|
||||
s.servers = append(s.servers, srv)
|
||||
return srv
|
||||
}
|
||||
|
||||
// Len returns the size of the server list
|
||||
func (s *ServerList) Len() int {
|
||||
return len(s.servers)
|
||||
}
|
||||
|
||||
// Main returns the main server,
|
||||
// the last added server is the main server, even if's Virtual
|
||||
func (s *ServerList) Main() (srv *Server) {
|
||||
l := len(s.servers) - 1
|
||||
for i := range s.servers {
|
||||
if i == l {
|
||||
return s.servers[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns the server by it's registered Address
|
||||
func (s *ServerList) Get(addr string) (srv *Server) {
|
||||
for i := range s.servers {
|
||||
srv = s.servers[i]
|
||||
if srv.Config.ListeningAddr == addr {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetAll returns all registered servers
|
||||
func (s *ServerList) GetAll() []*Server {
|
||||
return s.servers
|
||||
}
|
||||
|
||||
// GetByIndex returns a server from the list by it's index
|
||||
func (s *ServerList) GetByIndex(i int) *Server {
|
||||
if len(s.servers) >= i+1 {
|
||||
return s.servers[i]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove deletes a server by it's registered Address
|
||||
// returns true if something was removed, otherwise returns false
|
||||
func (s *ServerList) Remove(addr string) bool {
|
||||
servers := s.servers
|
||||
for i := range servers {
|
||||
srv := servers[i]
|
||||
if srv.Config.ListeningAddr == addr {
|
||||
copy(servers[i:], servers[i+1:])
|
||||
servers[len(servers)-1] = nil
|
||||
s.servers = servers[:len(servers)-1]
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// CloseAll terminates all listening servers
|
||||
// returns the first error, if erro happens it continues to closes the rest of the servers
|
||||
func (s *ServerList) CloseAll() (err error) {
|
||||
for i := range s.servers {
|
||||
if err == nil {
|
||||
err = s.servers[i].Close()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// OpenAll starts all servers
|
||||
// returns the first error happens to one of these servers
|
||||
// if one server gets error it closes the previous servers and exits from this process
|
||||
func (s *ServerList) OpenAll(reqHandler fasthttp.RequestHandler) error {
|
||||
l := len(s.servers) - 1
|
||||
for i := range s.servers {
|
||||
if err := s.servers[i].Open(reqHandler); err != nil {
|
||||
time.Sleep(2 * time.Second)
|
||||
// for any case,
|
||||
// we don't care about performance on initialization,
|
||||
// we must make sure that the previous servers are running before closing them
|
||||
s.CloseAll()
|
||||
return err
|
||||
}
|
||||
if i == l {
|
||||
s.mux.setHostname(s.servers[i].Hostname())
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAllOpened returns all opened/started servers
|
||||
func (s *ServerList) GetAllOpened() (servers []*Server) {
|
||||
for i := range s.servers {
|
||||
if s.servers[i].IsOpened() {
|
||||
servers = append(servers, s.servers[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// errHandler returns na error with message: 'Passed argument is not func(*Context) neither an object which implements the iris.Handler with Serve(ctx *Context)
|
||||
// It seems to be a +type Points to: +pointer.'
|
||||
var errHandler = errors.New("Passed argument is not func(*Context) neither an object which implements the iris.Handler with Serve(ctx *Context)\n It seems to be a %T Points to: %v.")
|
||||
@@ -620,7 +253,7 @@ func (h HandlerFunc) Serve(ctx *Context) {
|
||||
h(ctx)
|
||||
}
|
||||
|
||||
// ToHandler converts an httapi.Handler or http.HandlerFunc to an iris.Handler
|
||||
// ToHandler converts an http.Handler or http.HandlerFunc to an iris.Handler
|
||||
func ToHandler(handler interface{}) Handler {
|
||||
//this is not the best way to do it, but I dont have any options right now.
|
||||
switch handler.(type) {
|
||||
@@ -677,44 +310,6 @@ func joinMiddleware(middleware1 Middleware, middleware2 Middleware) Middleware {
|
||||
return newMiddleware
|
||||
}
|
||||
|
||||
func profileMiddleware(debugPath string) Middleware {
|
||||
htmlMiddleware := HandlerFunc(func(ctx *Context) {
|
||||
ctx.SetContentType(contentHTML + "; charset=" + ctx.framework.Config.Charset)
|
||||
ctx.Next()
|
||||
})
|
||||
indexHandler := ToHandlerFunc(pprof.Index)
|
||||
cmdlineHandler := ToHandlerFunc(pprof.Cmdline)
|
||||
profileHandler := ToHandlerFunc(pprof.Profile)
|
||||
symbolHandler := ToHandlerFunc(pprof.Symbol)
|
||||
goroutineHandler := ToHandlerFunc(pprof.Handler("goroutine"))
|
||||
heapHandler := ToHandlerFunc(pprof.Handler("heap"))
|
||||
threadcreateHandler := ToHandlerFunc(pprof.Handler("threadcreate"))
|
||||
debugBlockHandler := ToHandlerFunc(pprof.Handler("block"))
|
||||
|
||||
return Middleware{htmlMiddleware, HandlerFunc(func(ctx *Context) {
|
||||
action := ctx.Param("action")
|
||||
if len(action) > 1 {
|
||||
if strings.Contains(action, "cmdline") {
|
||||
cmdlineHandler.Serve((ctx))
|
||||
} else if strings.Contains(action, "profile") {
|
||||
profileHandler.Serve(ctx)
|
||||
} else if strings.Contains(action, "symbol") {
|
||||
symbolHandler.Serve(ctx)
|
||||
} else if strings.Contains(action, "goroutine") {
|
||||
goroutineHandler.Serve(ctx)
|
||||
} else if strings.Contains(action, "heap") {
|
||||
heapHandler.Serve(ctx)
|
||||
} else if strings.Contains(action, "threadcreate") {
|
||||
threadcreateHandler.Serve(ctx)
|
||||
} else if strings.Contains(action, "debug/block") {
|
||||
debugBlockHandler.Serve(ctx)
|
||||
}
|
||||
} else {
|
||||
indexHandler.Serve(ctx)
|
||||
}
|
||||
})}
|
||||
}
|
||||
|
||||
const (
|
||||
// parameterStartByte is very used on the node, it's just contains the byte for the ':' rune/char
|
||||
parameterStartByte = byte(':')
|
||||
@@ -1539,9 +1134,11 @@ func (mux *serveMux) BuildHandler() HandlerFunc {
|
||||
// context.VirtualHost() is a slow method because it makes string.Replaces but user can understand that if subdomain then server will have some nano/or/milleseconds performance cost
|
||||
requestHost := context.VirtualHostname()
|
||||
if requestHost != mux.hostname {
|
||||
//println(requestHost + " != " + mux.hostname)
|
||||
// we have a subdomain
|
||||
if strings.Index(tree.subdomain, dynamicSubdomainIndicator) != -1 {
|
||||
} else {
|
||||
//println(requestHost + " = " + mux.hostname)
|
||||
// mux.host = iris-go.com:8080, the subdomain for example is api.,
|
||||
// so the host must be api.iris-go.com:8080
|
||||
if tree.subdomain+mux.hostname != requestHost {
|
||||
@@ -1599,3 +1196,241 @@ func (mux *serveMux) BuildHandler() HandlerFunc {
|
||||
mux.fireError(StatusNotFound, context)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
errPortAlreadyUsed = errors.New("Port is already used")
|
||||
errRemoveUnix = errors.New("Unexpected error when trying to remove unix socket file. Addr: %s | Trace: %s")
|
||||
errChmod = errors.New("Cannot chmod %#o for %q: %s")
|
||||
errCertKeyMissing = errors.New("You should provide certFile and keyFile for TLS/SSL")
|
||||
errParseTLS = errors.New("Couldn't load TLS, certFile=%q, keyFile=%q. Trace: %s")
|
||||
)
|
||||
|
||||
// TCP4 returns a new tcp4 Listener
|
||||
// *tcp6 has some bugs in some operating systems, as reported by Go Community*
|
||||
func TCP4(addr string) (net.Listener, error) {
|
||||
return net.Listen("tcp4", ParseHost(addr))
|
||||
}
|
||||
|
||||
// UNIX returns a new unix(file) Listener
|
||||
func UNIX(addr string, mode os.FileMode) (net.Listener, error) {
|
||||
if errOs := os.Remove(addr); errOs != nil && !os.IsNotExist(errOs) {
|
||||
return nil, errRemoveUnix.Format(addr, errOs.Error())
|
||||
}
|
||||
|
||||
listener, err := net.Listen("unix", addr)
|
||||
if err != nil {
|
||||
return nil, errPortAlreadyUsed.AppendErr(err)
|
||||
}
|
||||
|
||||
if err = os.Chmod(addr, mode); err != nil {
|
||||
return nil, errChmod.Format(mode, addr, err.Error())
|
||||
}
|
||||
|
||||
return listener, nil
|
||||
}
|
||||
|
||||
// TLS returns a new TLS Listener
|
||||
func TLS(addr, certFile, keyFile string) (net.Listener, error) {
|
||||
|
||||
if certFile == "" || keyFile == "" {
|
||||
return nil, errCertKeyMissing
|
||||
}
|
||||
|
||||
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err != nil {
|
||||
return nil, errParseTLS.Format(certFile, keyFile, err)
|
||||
}
|
||||
|
||||
return CERT(addr, cert)
|
||||
}
|
||||
|
||||
// CERT returns a listener which contans tls.Config with the provided certificate, use for ssl
|
||||
func CERT(addr string, cert tls.Certificate) (net.Listener, error) {
|
||||
ln, err := TCP4(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tlsConfig := &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
PreferServerCipherSuites: true,
|
||||
}
|
||||
return tls.NewListener(ln, tlsConfig), nil
|
||||
}
|
||||
|
||||
// LETSENCRYPT returns a new Automatic TLS Listener using letsencrypt.org service
|
||||
func LETSENCRYPT(addr string) (net.Listener, error) {
|
||||
if portIdx := strings.IndexByte(addr, ':'); portIdx == -1 {
|
||||
addr += ":443"
|
||||
}
|
||||
|
||||
ln, err := TCP4(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var m letsencrypt.Manager
|
||||
if err = m.CacheFile("letsencrypt.cache"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tlsConfig := &tls.Config{GetCertificate: m.GetCertificate}
|
||||
tlsLn := tls.NewListener(ln, tlsConfig)
|
||||
|
||||
return tlsLn, nil
|
||||
}
|
||||
|
||||
// TCPKeepAliveListener sets TCP keep-alive timeouts on accepted
|
||||
// connections.
|
||||
// Dead TCP connections (e.g. closing laptop mid-download) eventually
|
||||
// go away
|
||||
// It is not used by default if you want to pass a keep alive listener
|
||||
// then just pass the child listener, example:
|
||||
// listener := iris.TCPKeepAliveListener{iris.TCP4(":8080").(*net.TCPListener)}
|
||||
type TCPKeepAliveListener struct {
|
||||
*net.TCPListener
|
||||
}
|
||||
|
||||
// Accept implements the listener and sets the keep alive period which is 2minutes
|
||||
func (ln TCPKeepAliveListener) Accept() (c net.Conn, err error) {
|
||||
tc, err := ln.AcceptTCP()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tc.SetKeepAlive(true)
|
||||
tc.SetKeepAlivePeriod(2 * time.Minute)
|
||||
return tc, nil
|
||||
}
|
||||
|
||||
// ParseHost tries to convert a given string to an address which is compatible with net.Listener and server
|
||||
func ParseHost(addr string) string {
|
||||
// check if addr has :port, if not do it +:80 ,we need the hostname for many cases
|
||||
a := addr
|
||||
if a == "" {
|
||||
// check for os environments
|
||||
if oshost := os.Getenv("ADDR"); oshost != "" {
|
||||
a = oshost
|
||||
} else if oshost := os.Getenv("HOST"); oshost != "" {
|
||||
a = oshost
|
||||
} else if oshost := os.Getenv("HOSTNAME"); oshost != "" {
|
||||
a = oshost
|
||||
// check for port also here
|
||||
if osport := os.Getenv("PORT"); osport != "" {
|
||||
a += ":" + osport
|
||||
}
|
||||
} else if osport := os.Getenv("PORT"); osport != "" {
|
||||
a = ":" + osport
|
||||
} else {
|
||||
a = DefaultServerAddr
|
||||
}
|
||||
}
|
||||
if portIdx := strings.IndexByte(a, ':'); portIdx == 0 {
|
||||
if a[portIdx:] == ":https" {
|
||||
a = DefaultServerHostname + ":443"
|
||||
} else {
|
||||
// if contains only :port ,then the : is the first letter, so we dont have setted a hostname, lets set it
|
||||
a = DefaultServerHostname + a
|
||||
}
|
||||
}
|
||||
|
||||
/* changed my mind, don't add 80, this will cause problems on unix listeners, and it's not really necessary because we take the port using parsePort
|
||||
if portIdx := strings.IndexByte(a, ':'); portIdx < 0 {
|
||||
// missing port part, add it
|
||||
a = a + ":80"
|
||||
}*/
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// ParseHostname receives an addr of form host[:port] and returns the hostname part of it
|
||||
// ex: localhost:8080 will return the `localhost`, mydomain.com:8080 will return the 'mydomain'
|
||||
func ParseHostname(addr string) string {
|
||||
idx := strings.IndexByte(addr, ':')
|
||||
if idx == 0 {
|
||||
// only port, then return 0.0.0.0
|
||||
return "0.0.0.0"
|
||||
} else if idx > 0 {
|
||||
return addr[0:idx]
|
||||
}
|
||||
// it's already hostname
|
||||
return addr
|
||||
}
|
||||
|
||||
// ParsePort receives an addr of form host[:port] and returns the port part of it
|
||||
// ex: localhost:8080 will return the `8080`, mydomain.com will return the '80'
|
||||
func ParsePort(addr string) int {
|
||||
if portIdx := strings.IndexByte(addr, ':'); portIdx != -1 {
|
||||
afP := addr[portIdx+1:]
|
||||
p, err := strconv.Atoi(afP)
|
||||
if err == nil {
|
||||
return p
|
||||
} else if afP == "https" { // it's not number, check if it's :https
|
||||
return 443
|
||||
}
|
||||
}
|
||||
return 80
|
||||
}
|
||||
|
||||
const (
|
||||
// SchemeHTTPS returns "https://" (full)
|
||||
SchemeHTTPS = "https://"
|
||||
// SchemeHTTP returns "http://" (full)
|
||||
SchemeHTTP = "http://"
|
||||
)
|
||||
|
||||
// ParseScheme returns the scheme based on the host,addr,domain
|
||||
// Note: the full scheme not just http*,https* *http:// *https://
|
||||
func ParseScheme(domain string) string {
|
||||
// pure check
|
||||
if strings.HasPrefix(domain, SchemeHTTPS) || ParsePort(domain) == 443 {
|
||||
return SchemeHTTPS
|
||||
}
|
||||
return SchemeHTTP
|
||||
}
|
||||
|
||||
var proxyHandler = func(proxyAddr string, redirectSchemeAndHost string) fasthttp.RequestHandler {
|
||||
return func(reqCtx *fasthttp.RequestCtx) {
|
||||
// override the handler and redirect all requests to this addr
|
||||
redirectTo := redirectSchemeAndHost
|
||||
fakehost := string(reqCtx.Request.Host())
|
||||
path := string(reqCtx.Path())
|
||||
if strings.Count(fakehost, ".") >= 3 { // propably a subdomain, pure check but doesn't matters don't worry
|
||||
if sufIdx := strings.LastIndexByte(fakehost, '.'); sufIdx > 0 {
|
||||
// check if the last part is a number instead of .com/.gr...
|
||||
// if it's number then it's propably is 0.0.0.0 or 127.0.0.1... so it shouldn' use subdomain
|
||||
if _, err := strconv.Atoi(fakehost[sufIdx+1:]); err != nil {
|
||||
// it's not number then process the try to parse the subdomain
|
||||
redirectScheme := ParseScheme(redirectSchemeAndHost)
|
||||
realHost := strings.Replace(redirectSchemeAndHost, redirectScheme, "", 1)
|
||||
redirectHost := strings.Replace(fakehost, fakehost, realHost, 1)
|
||||
redirectTo = redirectScheme + redirectHost + path
|
||||
reqCtx.Redirect(redirectTo, StatusMovedPermanently)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if path != "/" {
|
||||
redirectTo += path
|
||||
}
|
||||
|
||||
reqCtx.Redirect(redirectTo, StatusMovedPermanently)
|
||||
}
|
||||
}
|
||||
|
||||
// Proxy not really a proxy, it's just
|
||||
// starts a server listening on proxyAddr but redirects all requests to the redirectToSchemeAndHost+$path
|
||||
// nothing special, use it only when you want to start a secondary server which its only work is to redirect from one requested path to another
|
||||
//
|
||||
// returns a close function
|
||||
func Proxy(proxyAddr string, redirectSchemeAndHost string) func() error {
|
||||
proxyAddr = ParseHost(proxyAddr)
|
||||
|
||||
// override the handler and redirect all requests to this addr
|
||||
h := proxyHandler(proxyAddr, redirectSchemeAndHost)
|
||||
prx := New(OptionDisableBanner(true))
|
||||
prx.Router = h
|
||||
|
||||
go prx.Listen(proxyAddr)
|
||||
|
||||
return prx.Close
|
||||
}
|
||||
|
||||
290
http_test.go
290
http_test.go
@@ -8,6 +8,7 @@ CONTRIBUTE & DISCUSSION ABOUT TESTS TO: https://github.com/iris-contrib/tests
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/valyala/fasthttp"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
@@ -18,129 +19,140 @@ import (
|
||||
|
||||
const (
|
||||
testTLSCert = `-----BEGIN CERTIFICATE-----
|
||||
MIIDAzCCAeugAwIBAgIJAPDsxtKV4v3uMA0GCSqGSIb3DQEBBQUAMBgxFjAUBgNV
|
||||
BAMMDTEyNy4wLjAuMTo0NDMwHhcNMTYwNjI5MTMxMjU4WhcNMjYwNjI3MTMxMjU4
|
||||
WjAYMRYwFAYDVQQDDA0xMjcuMC4wLjE6NDQzMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||
AQ8AMIIBCgKCAQEA0KtAOHKrcbLwWJXgRX7XSFyu4HHHpSty4bliv8ET4sLJpbZH
|
||||
XeVX05Foex7PnrurDP6e+0H5TgqqcpQM17/ZlFcyKrJcHSCgV0ZDB3Sb8RLQSLns
|
||||
8a+MOSbn1WZ7TkC7d/cWlKmasQRHQ2V/cWlGooyKNEPoGaEz8MbY0wn2spyIJwsB
|
||||
dciERC6317VTXbiZdoD8QbAsT+tBvEHM2m2A7B7PQmHNehtyFNbSV5uZNodvv1uv
|
||||
ZTnDa6IqpjFLb1b2HNFgwmaVPmmkLuy1l9PN+o6/DUnXKKBrfPAx4JOlqTKEQpWs
|
||||
pnfacTE3sWkkmOSSFltAXfkXIJFKdS/hy5J/KQIDAQABo1AwTjAdBgNVHQ4EFgQU
|
||||
zr1df/c9+NyTpmyiQO8g3a8NswYwHwYDVR0jBBgwFoAUzr1df/c9+NyTpmyiQO8g
|
||||
3a8NswYwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEACG5shtMSDgCd
|
||||
MNjOF+YmD+PX3Wy9J9zehgaDJ1K1oDvBbQFl7EOJl8lRMWITSws22Wxwh8UXVibL
|
||||
sscKBp14dR3e7DdbwCVIX/JyrJyOaCfy2nNBdf1B06jYFsIHvP3vtBAb9bPNOTBQ
|
||||
QE0Ztu9kCqgsmu0//sHuBEeA3d3E7wvDhlqRSxTLcLtgC1NSgkFvBw0JvwgpkX6s
|
||||
M5WpSBZwZv8qpplxhFfqNy8Uf+xrpSW0pGfkHumehkQGC6/Ry7raganS0aHhDPK9
|
||||
Z1bEJ2com1bFFAQsm9yIXrRVMGGCtihB2Au0Q4jpEjUbzWYM+ItZyvRAGRM6Qex6
|
||||
s/jogMeRsw==
|
||||
-----END CERTIFICATE-----
|
||||
MIIDATCCAemgAwIBAgIJAPdE0ZyCKwVtMA0GCSqGSIb3DQEBBQUAMBcxFTATBgNV
|
||||
BAMMDG15ZG9tYWluLmNvbTAeFw0xNjA5MjQwNjU3MDVaFw0yNjA5MjIwNjU3MDVa
|
||||
MBcxFTATBgNVBAMMDG15ZG9tYWluLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
ADCCAQoCggEBAM9YJOV1Bl+NwEq8ZAcVU2YONBw5zGkUFJUZkL77XT0i1V473JTf
|
||||
GEpNZisDman+6n+pXarC2mR4T9PkCfmk072HaZ2LXwYe9XSgxnLJZJA1fJMzdMMC
|
||||
2XveINF+/eeoyW9+8ZjQPbZdHWcxi7RomXg1AOMAG2UWMjalK5xkTHcqDuOI2LEe
|
||||
mezWHnFdBJNMTi3pNdbVr7BjexZTSGhx4LAIP2ufTUoVzk+Cvyr4IhS00zOiyyWv
|
||||
tuJaO20Q0Q5n34o9vDAACKAfNRLBE8qzdRwsjMumXTX3hJzvgFp/4Lr5Hr2I2fBd
|
||||
tbIWN9xIsu6IibBGFItiAfQSrKAR7IFVqDUCAwEAAaNQME4wHQYDVR0OBBYEFNvN
|
||||
Yik2eBRDmDaqoMaLfvr75kGfMB8GA1UdIwQYMBaAFNvNYik2eBRDmDaqoMaLfvr7
|
||||
5kGfMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAEAv3pKkmDTXIChB
|
||||
nVrbYwNibin9HYOPf3JCjU48V672YPgbfJM0WfTvLXNVBOdTz3aIUrhfwv/go2Jz
|
||||
yDcIFdLUdwllovhj1RwI96lbgCJ4AKoO/fvJ5Rxq+/vvLYB38PNl/fVEnOOeWzCQ
|
||||
qHfjckShNV5GzJPhfpYn9Gj6+Zj3O0cJXhF9L/FlbVxFhwPjPRbFDNTHYzgiHy82
|
||||
zhhDhTQJVnNJXfokdlg9OjfFkySqpv9fvPi/dfk5j1KmKUiYP5SYUhZiKX1JScvx
|
||||
JgesCwz1nUfVQ1TYE0dphU8mTCN4Y42i7bctx7iLcDRIFhtYstt0hhCKSxFmJSBG
|
||||
y9RITRA=
|
||||
-----END CERTIFICATE-----
|
||||
`
|
||||
|
||||
testTLSKey = `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEA0KtAOHKrcbLwWJXgRX7XSFyu4HHHpSty4bliv8ET4sLJpbZH
|
||||
XeVX05Foex7PnrurDP6e+0H5TgqqcpQM17/ZlFcyKrJcHSCgV0ZDB3Sb8RLQSLns
|
||||
8a+MOSbn1WZ7TkC7d/cWlKmasQRHQ2V/cWlGooyKNEPoGaEz8MbY0wn2spyIJwsB
|
||||
dciERC6317VTXbiZdoD8QbAsT+tBvEHM2m2A7B7PQmHNehtyFNbSV5uZNodvv1uv
|
||||
ZTnDa6IqpjFLb1b2HNFgwmaVPmmkLuy1l9PN+o6/DUnXKKBrfPAx4JOlqTKEQpWs
|
||||
pnfacTE3sWkkmOSSFltAXfkXIJFKdS/hy5J/KQIDAQABAoIBAQDCd+bo9I0s8Fun
|
||||
4z3Y5oYSDTZ5O/CY0O5GyXPrSzCSM4Cj7EWEj1mTdb9Ohv9tam7WNHHLrcd+4NfK
|
||||
4ok5hLVs1vqM6h6IksB7taKATz+Jo0PzkzrsXvMqzERhEBo4aoGMIv2rXIkrEdas
|
||||
S+pCsp8+nAWtAeBMCn0Slu65d16vQxwgfod6YZfvMKbvfhOIOShl9ejQ+JxVZcMw
|
||||
Ti8sgvYmFUrdrEH3nCgptARwbx4QwlHGaw/cLGHdepfFsVaNQsEzc7m61fSO70m4
|
||||
NYJv48ZgjOooF5AccbEcQW9IxxikwNc+wpFYy5vDGzrBwS5zLZQFpoyMWFhtWdjx
|
||||
hbmNn1jlAoGBAPs0ZjqsfDrH5ja4dQIdu5ErOccsmoHfMMBftMRqNG5neQXEmoLc
|
||||
Uz8WeQ/QDf302aTua6E9iSjd7gglbFukVwMndQ1Q8Rwxz10jkXfiE32lFnqK0csx
|
||||
ltruU6hOeSGSJhtGWBuNrT93G2lmy23fSG6BqOzdU4rn/2GPXy5zaxM/AoGBANSm
|
||||
/E96RcBUiI6rDVqKhY+7M1yjLB41JrErL9a0Qfa6kYnaXMr84pOqVN11IjhNNTgl
|
||||
g1lwxlpXZcZh7rYu9b7EEMdiWrJDQV7OxLDHopqUWkQ+3MHwqs6CxchyCq7kv9Df
|
||||
IKqat7Me6Cyeo0MqcW+UMxlCRBxKQ9jqC7hDfZuXAoGBAJmyS8ImerP0TtS4M08i
|
||||
JfsCOY21qqs/hbKOXCm42W+be56d1fOvHngBJf0YzRbO0sNo5Q14ew04DEWLsCq5
|
||||
+EsDv0hwd7VKfJd+BakV99ruQTyk5wutwaEeJK1bph12MD6L4aiqHJAyLeFldZ45
|
||||
+TUzu8mA+XaJz+U/NXtUPvU9AoGBALtl9M+tdy6I0Fa50ujJTe5eEGNAwK5WNKTI
|
||||
5D2XWNIvk/Yh4shXlux+nI8UnHV1RMMX++qkAYi3oE71GsKeG55jdk3fFQInVsJQ
|
||||
APGw3FDRD8M4ip62ki+u+tEr/tIlcAyHtWfjNKO7RuubWVDlZFXqCiXmSdOMdsH/
|
||||
bxiREW49AoGACWev/eOzBoQJCRN6EvU2OV0s3b6f1QsPvcaH0zc6bgbBFOGmJU8v
|
||||
pXhD88tsu9exptLkGVoYZjR0n0QT/2Kkyu93jVDW/80P7VCz8DKYyAJDa4CVwZxO
|
||||
MlobQSunSDKx/CCJhWkbytCyh1bngAtwSAYLXavYIlJbAzx6FvtAIw4=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`
|
||||
MIIEpQIBAAKCAQEAz1gk5XUGX43ASrxkBxVTZg40HDnMaRQUlRmQvvtdPSLVXjvc
|
||||
lN8YSk1mKwOZqf7qf6ldqsLaZHhP0+QJ+aTTvYdpnYtfBh71dKDGcslkkDV8kzN0
|
||||
wwLZe94g0X7956jJb37xmNA9tl0dZzGLtGiZeDUA4wAbZRYyNqUrnGRMdyoO44jY
|
||||
sR6Z7NYecV0Ek0xOLek11tWvsGN7FlNIaHHgsAg/a59NShXOT4K/KvgiFLTTM6LL
|
||||
Ja+24lo7bRDRDmffij28MAAIoB81EsETyrN1HCyMy6ZdNfeEnO+AWn/guvkevYjZ
|
||||
8F21shY33Eiy7oiJsEYUi2IB9BKsoBHsgVWoNQIDAQABAoIBABRhi67qY+f8nQw7
|
||||
nHF9zSbY+pJTtB4YFTXav3mmZ7HcvLB4neQcUdzr4sETp4UoQ5Cs60IfySvbD626
|
||||
WqipZQ7aQq1zx7FoVaRTMW6TEUmDmG03v6BzpUEhwoQVQYwF8Vb+WW01+vr0CDHe
|
||||
kub26S8BtsaZehfjqKfqcHD9Au8ri+Nwbu91iT4POVzBBBwYbtwXZwaYDR5PCNOI
|
||||
ld+6qLapVIVKpvLHL+tA4A/n0n4l7p8TJo/qYesFRZ7J+USt4YGFDuf15nnDge/7
|
||||
9Qjyqa9WmvRGytPdgtEzc8XwJu7xhcRthSmCppdY0ExHBwVceCEz8u3QbRYFqq3U
|
||||
iLXUpfkCgYEA6JMlRtLIEAPkJZGBxJBSaeWVOeaAaMnLAdcu4OFjSuxr65HXsdhM
|
||||
aWHopCE44NjBROAg67qgc5vNBZvhnCwyTI8nb6k/CO5QZ4AG1d2Xe/9rPV5pdaBL
|
||||
gRgOJjlG0apZpPVM4I/0JU5prwS2Z71lFmEMikwmbmngYmOysqUBfbMCgYEA5Dpw
|
||||
qzn1Oq+fasSUjzUa/wvBTVMpVjnNrda7Hnlx6lssnQaPFqifFYL9Zr/+5rWdsE2O
|
||||
NNCsy68tacspAUa0LQinzpeSP4dyTVCvZG/xWPaYDKE6FDmzsi8xHBTTxMneeU6p
|
||||
HUKJMUD3LcvBiCLunhT2xd1/+LKzVce6ms9R3ncCgYEAv9wjdDmOMSgEnblbg/xL
|
||||
AHEUmZ89bzSI9Au/8GP+tWAz5zF47o2w+355nGyLr3EgfuEmR1C97KEqkOX3SA5t
|
||||
sBqoPcUw6v0t9zP2b5dN0Ez0+rtX5GFH6Ecf5Qh7E5ukOCDkOpyGnAADzw3kK9Bi
|
||||
BAQrhCstyQguwvvb/uOAR2ECgYEA3nYcZrqaz7ZqVL8C88hW5S4HIKEkFNlJI97A
|
||||
DAdiw4ZVqUXAady5HFXPPL1+8FEtQLGIIPEazXuWb53I/WZ2r8LVFunlcylKgBRa
|
||||
sjLvdMEBGqZ5H0fTYabgXrfqZ9JBmcrTyyKU6b6icTBAF7u9DbfvhpTObZN6fO2v
|
||||
dcEJ0ycCgYEAxM8nGR+pa16kZmW1QV62EN0ifrU7SOJHCOGApU0jvTz8D4GO2j+H
|
||||
MsoPSBrZ++UYgtGO/dK4aBV1JDdy8ZdyfE6UN+a6dQgdNdbOMT4XwWdS0zlZ/+F4
|
||||
PKvbgZnLEKHvjODJ65aQmcTVUoaa11J29iAAtA3a3TcMn6C2fYpRy1s=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`
|
||||
)
|
||||
|
||||
func TestServerHost(t *testing.T) {
|
||||
var server1, server2, server3 Server
|
||||
var expectedHost1 = "mydomain.com:1993"
|
||||
var expectedHost2 = "mydomain.com:80"
|
||||
var expectedHost3 = DefaultServerHostname + ":9090"
|
||||
server1.Config.ListeningAddr = expectedHost1
|
||||
server2.Config.ListeningAddr = "mydomain.com"
|
||||
server3.Config.ListeningAddr = ":9090"
|
||||
func TestParseAddr(t *testing.T) {
|
||||
|
||||
server1.Config.ListeningAddr = ServerParseAddr(server1.Config.ListeningAddr)
|
||||
server2.Config.ListeningAddr = ServerParseAddr(server2.Config.ListeningAddr)
|
||||
server3.Config.ListeningAddr = ServerParseAddr(server3.Config.ListeningAddr)
|
||||
// test hosts
|
||||
expectedHost1 := "mydomain.com:1993"
|
||||
expectedHost2 := "mydomain.com"
|
||||
expectedHost3 := DefaultServerHostname + ":9090"
|
||||
expectedHost4 := "mydomain.com:443"
|
||||
|
||||
if server1.Host() != expectedHost1 {
|
||||
t.Fatalf("Expecting server 1's host to be %s but we got %s", expectedHost1, server1.Host())
|
||||
}
|
||||
if server2.Host() != expectedHost2 {
|
||||
t.Fatalf("Expecting server 2's host to be %s but we got %s", expectedHost2, server2.Host())
|
||||
}
|
||||
if server3.Host() != expectedHost3 {
|
||||
t.Fatalf("Expecting server 3's host to be %s but we got %s", expectedHost3, server3.Host())
|
||||
}
|
||||
}
|
||||
host1 := ParseHost(expectedHost1)
|
||||
host2 := ParseHost(expectedHost2)
|
||||
host3 := ParseHost(":9090")
|
||||
host4 := ParseHost(expectedHost4)
|
||||
|
||||
func TestServerHostname(t *testing.T) {
|
||||
var server Server
|
||||
var expectedHostname = "mydomain.com"
|
||||
server.Config.ListeningAddr = expectedHostname + ":1993"
|
||||
server.Config.ListeningAddr = ServerParseAddr(server.Config.ListeningAddr)
|
||||
if server.Hostname() != expectedHostname {
|
||||
t.Fatalf("Expecting server's hostname to be %s but we got %s", expectedHostname, server.Hostname())
|
||||
if host1 != expectedHost1 {
|
||||
t.Fatalf("Expecting server 1's host to be %s but we got %s", expectedHost1, host1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerFullHost(t *testing.T) {
|
||||
var server1 Server
|
||||
var server2 Server
|
||||
server1.Config.ListeningAddr = "127.0.0.1:8080"
|
||||
server1.Config.CertFile = "notempty"
|
||||
server1.Config.KeyFile = "notempty"
|
||||
server2.Config.ListeningAddr = "127.0.0.1:8080"
|
||||
server1ExpectingFullhost := "https://" + server1.Config.ListeningAddr
|
||||
server2ExpectingFullhost := "http://" + server2.Config.ListeningAddr
|
||||
if server1.FullHost() != server1ExpectingFullhost {
|
||||
t.Fatalf("Expecting server 1's fullhost to be %s but got %s", server1ExpectingFullhost, server1.FullHost())
|
||||
if host2 != expectedHost2 {
|
||||
t.Fatalf("Expecting server 2's host to be %s but we got %s", expectedHost2, host2)
|
||||
}
|
||||
if server2.FullHost() != server2ExpectingFullhost {
|
||||
t.Fatalf("Expecting server 2's fullhost to be %s but got %s", server2ExpectingFullhost, server2.FullHost())
|
||||
if host3 != expectedHost3 {
|
||||
t.Fatalf("Expecting server 3's host to be %s but we got %s", expectedHost3, host3)
|
||||
}
|
||||
if host4 != expectedHost4 {
|
||||
t.Fatalf("Expecting server 4's host to be %s but we got %s", expectedHost4, host4)
|
||||
}
|
||||
|
||||
}
|
||||
// test hostname
|
||||
expectedHostname1 := "mydomain.com"
|
||||
expectedHostname2 := "mydomain.com"
|
||||
expectedHostname3 := DefaultServerHostname
|
||||
expectedHostname4 := "mydomain.com"
|
||||
|
||||
func TestServerPort(t *testing.T) {
|
||||
var server1, server2 Server
|
||||
expectedPort1 := 8080
|
||||
expectedPort2 := 80
|
||||
server1.Config.ListeningAddr = "mydomain.com:8080"
|
||||
server2.Config.ListeningAddr = "mydomain.com"
|
||||
server1.Config.ListeningAddr = ServerParseAddr(server1.Config.ListeningAddr)
|
||||
server2.Config.ListeningAddr = ServerParseAddr(server2.Config.ListeningAddr)
|
||||
|
||||
if server1.Port() != expectedPort1 {
|
||||
t.Fatalf("Expecting server 1's port to be %d but we got %d", expectedPort1, server1.Port())
|
||||
hostname1 := ParseHostname(host1)
|
||||
hostname2 := ParseHostname(host2)
|
||||
hostname3 := ParseHostname(host3)
|
||||
hostname4 := ParseHostname(host4)
|
||||
if hostname1 != expectedHostname1 {
|
||||
t.Fatalf("Expecting server 1's hostname to be %s but we got %s", expectedHostname1, hostname1)
|
||||
}
|
||||
if server2.Port() != expectedPort2 {
|
||||
t.Fatalf("Expecting server 2's port to be %d but we got %d", expectedPort2, server2.Port())
|
||||
|
||||
if hostname2 != expectedHostname2 {
|
||||
t.Fatalf("Expecting server 2's hostname to be %s but we got %s", expectedHostname2, hostname2)
|
||||
}
|
||||
|
||||
if hostname3 != expectedHostname3 {
|
||||
t.Fatalf("Expecting server 3's hostname to be %s but we got %s", expectedHostname3, hostname3)
|
||||
}
|
||||
|
||||
if hostname4 != expectedHostname4 {
|
||||
t.Fatalf("Expecting server 4's hostname to be %s but we got %s", expectedHostname4, hostname4)
|
||||
}
|
||||
|
||||
// test scheme, no need to test fullhost(scheme+host)
|
||||
expectedScheme1 := SchemeHTTP
|
||||
expectedScheme2 := SchemeHTTP
|
||||
expectedScheme3 := SchemeHTTP
|
||||
expectedScheme4 := SchemeHTTPS
|
||||
scheme1 := ParseScheme(host1)
|
||||
scheme2 := ParseScheme(host2)
|
||||
scheme3 := ParseScheme(host3)
|
||||
scheme4 := ParseScheme(host4)
|
||||
if scheme1 != expectedScheme1 {
|
||||
t.Fatalf("Expecting server 1's hostname to be %s but we got %s", expectedScheme1, scheme1)
|
||||
}
|
||||
|
||||
if scheme2 != expectedScheme2 {
|
||||
t.Fatalf("Expecting server 2's hostname to be %s but we got %s", expectedScheme2, scheme2)
|
||||
}
|
||||
|
||||
if scheme3 != expectedScheme3 {
|
||||
t.Fatalf("Expecting server 3's hostname to be %s but we got %s", expectedScheme3, scheme3)
|
||||
}
|
||||
|
||||
if scheme4 != expectedScheme4 {
|
||||
t.Fatalf("Expecting server 4's hostname to be %s but we got %s", expectedScheme4, scheme4)
|
||||
}
|
||||
}
|
||||
|
||||
// Contains the server test for multi running servers
|
||||
func TestMultiRunningServers_v1(t *testing.T) {
|
||||
host := "mydomain.com:443" // you have to add it to your hosts file( for windows, as 127.0.0.1 mydomain.com)
|
||||
func TestMultiRunningServers_v1_PROXY(t *testing.T) {
|
||||
defer Close()
|
||||
host := "mydomain.com" // you have to add it to your hosts file( for windows, as 127.0.0.1 mydomain.com)
|
||||
initDefault()
|
||||
Config.DisableBanner = true
|
||||
Default.Config.DisableBanner = true
|
||||
// create the key and cert files on the fly, and delete them when this test finished
|
||||
certFile, ferr := ioutil.TempFile("", "cert")
|
||||
|
||||
@@ -153,9 +165,6 @@ func TestMultiRunningServers_v1(t *testing.T) {
|
||||
t.Fatal(ferr.Error())
|
||||
}
|
||||
|
||||
certFile.WriteString(testTLSCert)
|
||||
keyFile.WriteString(testTLSKey)
|
||||
|
||||
defer func() {
|
||||
certFile.Close()
|
||||
time.Sleep(350 * time.Millisecond)
|
||||
@@ -166,33 +175,37 @@ func TestMultiRunningServers_v1(t *testing.T) {
|
||||
os.Remove(keyFile.Name())
|
||||
}()
|
||||
|
||||
certFile.WriteString(testTLSCert)
|
||||
keyFile.WriteString(testTLSKey)
|
||||
|
||||
Get("/", func(ctx *Context) {
|
||||
ctx.Write("Hello from %s", ctx.HostString())
|
||||
})
|
||||
|
||||
// start the secondary server
|
||||
AddServer(ServerConfiguration{ListeningAddr: "mydomain.com:80", RedirectTo: "https://" + host, Virtual: true})
|
||||
// start the main server
|
||||
go ListenTo(ServerConfiguration{ListeningAddr: host, CertFile: certFile.Name(), KeyFile: keyFile.Name(), Virtual: true})
|
||||
// prepare test framework
|
||||
if ok := <-Available; !ok {
|
||||
go ListenTLS(host+":443", certFile.Name(), keyFile.Name())
|
||||
if ok := <-Default.Available; !ok {
|
||||
t.Fatal("Unexpected error: server cannot start, please report this as bug!!")
|
||||
}
|
||||
|
||||
closeProxy := Proxy("mydomain.com:80", "https://"+host)
|
||||
defer closeProxy()
|
||||
|
||||
Default.Config.Tester.ExplicitURL = true
|
||||
e := Tester(t)
|
||||
|
||||
e.Request("GET", "http://mydomain.com:80").Expect().Status(StatusOK).Body().Equal("Hello from " + host)
|
||||
e.Request("GET", "http://"+host).Expect().Status(StatusOK).Body().Equal("Hello from " + host)
|
||||
e.Request("GET", "https://"+host).Expect().Status(StatusOK).Body().Equal("Hello from " + host)
|
||||
|
||||
}
|
||||
|
||||
// Contains the server test for multi running servers
|
||||
func TestMultiRunningServers_v2(t *testing.T) {
|
||||
defer Close()
|
||||
domain := "mydomain.com"
|
||||
host := domain + ":443"
|
||||
|
||||
initDefault()
|
||||
Config.DisableBanner = true
|
||||
Config.Tester.ListeningAddr = host
|
||||
Default.Config.DisableBanner = true
|
||||
|
||||
// create the key and cert files on the fly, and delete them when this test finished
|
||||
certFile, ferr := ioutil.TempFile("", "cert")
|
||||
|
||||
@@ -219,25 +232,35 @@ func TestMultiRunningServers_v2(t *testing.T) {
|
||||
}()
|
||||
|
||||
Get("/", func(ctx *Context) {
|
||||
ctx.Write("Hello from %s", ctx.HostString())
|
||||
ctx.Write("Hello from %s", string(ctx.HostString()))
|
||||
})
|
||||
|
||||
// add a secondary server
|
||||
Servers.Add(ServerConfiguration{ListeningAddr: domain + ":80", RedirectTo: "https://" + host, Virtual: true})
|
||||
//Servers.Add(ServerConfiguration{ListeningAddr: domain + ":80", RedirectTo: "https://" + host, Virtual: true})
|
||||
// add our primary/main server
|
||||
Servers.Add(ServerConfiguration{ListeningAddr: host, CertFile: certFile.Name(), KeyFile: keyFile.Name(), Virtual: true})
|
||||
//Servers.Add(ServerConfiguration{ListeningAddr: host, CertFile: certFile.Name(), KeyFile: keyFile.Name(), Virtual: true})
|
||||
|
||||
go Go()
|
||||
//go Go()
|
||||
|
||||
// using the proxy handler
|
||||
fsrv1 := &fasthttp.Server{Handler: proxyHandler(domain+":80", "https://"+domain)}
|
||||
go fsrv1.ListenAndServe(domain + ":80")
|
||||
// using the same iris' handler but not as proxy, just the same handler
|
||||
fsrv2 := &fasthttp.Server{Handler: Default.Router}
|
||||
go fsrv2.ListenAndServe("myotherdomain.com" + ":8080")
|
||||
|
||||
go ListenTLS(domain+":443", certFile.Name(), keyFile.Name())
|
||||
|
||||
// prepare test framework
|
||||
if ok := <-Available; !ok {
|
||||
t.Fatal("Unexpected error: server cannot start, please report this as bug!!")
|
||||
}
|
||||
|
||||
Default.Config.Tester.ExplicitURL = true
|
||||
e := Tester(t)
|
||||
|
||||
e.Request("GET", "http://"+domain+":80").Expect().Status(StatusOK).Body().Equal("Hello from " + host)
|
||||
e.Request("GET", "https://"+host).Expect().Status(StatusOK).Body().Equal("Hello from " + host)
|
||||
e.Request("GET", "http://"+domain).Expect().Status(StatusOK).Body().Equal("Hello from " + domain)
|
||||
e.Request("GET", "http://myotherdomain.com:8080").Expect().Status(StatusOK).Body().Equal("Hello from myotherdomain.com:8080")
|
||||
e.Request("GET", "https://"+domain).Expect().Status(StatusOK).Body().Equal("Hello from " + domain)
|
||||
|
||||
}
|
||||
|
||||
@@ -247,18 +270,13 @@ const (
|
||||
)
|
||||
|
||||
func testSubdomainHost() string {
|
||||
s := testSubdomain + "." + Servers.Main().Host()
|
||||
s := testSubdomain + "." + Default.Config.VHost
|
||||
return s
|
||||
}
|
||||
|
||||
func testSubdomainURL() (subdomainURL string) {
|
||||
func testSubdomainURL() string {
|
||||
subdomainHost := testSubdomainHost()
|
||||
if Servers.Main().IsSecure() {
|
||||
subdomainURL = "https://" + subdomainHost
|
||||
} else {
|
||||
subdomainURL = "http://" + subdomainHost
|
||||
}
|
||||
return
|
||||
return Default.Config.VScheme + subdomainHost
|
||||
}
|
||||
|
||||
func subdomainTester(e *httpexpect.Expect) *httpexpect.Expect {
|
||||
@@ -316,7 +334,7 @@ func TestMuxSimple(t *testing.T) {
|
||||
{"GET", "/test_get_urlparameter2/second", "/test_get_urlparameter2/second", "name=irisurl&something=anything", "name=irisurl,something=anything", 200, true, nil, []param{{"name", "irisurl"}, {"something", "anything"}}},
|
||||
{"GET", "/test_get_urlparameter2/first/second/third", "/test_get_urlparameter2/first/second/third", "name=irisurl&something=anything&else=elsehere", "name=irisurl,something=anything,else=elsehere", 200, true, nil, []param{{"name", "irisurl"}, {"something", "anything"}, {"else", "elsehere"}}},
|
||||
}
|
||||
|
||||
defer Close()
|
||||
initDefault()
|
||||
|
||||
for idx := range testRoutes {
|
||||
@@ -360,7 +378,6 @@ func TestMuxSimple(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMuxSimpleParty(t *testing.T) {
|
||||
|
||||
initDefault()
|
||||
|
||||
h := func(c *Context) { c.WriteString(c.HostString() + c.PathString()) }
|
||||
@@ -386,12 +403,13 @@ func TestMuxSimpleParty(t *testing.T) {
|
||||
p.Get("/namedpath/:param1/something/:param2/else", h)
|
||||
}
|
||||
|
||||
Default.Config.VHost = "0.0.0.0:8080"
|
||||
e := Tester(t)
|
||||
|
||||
request := func(reqPath string) {
|
||||
e.Request("GET", reqPath).
|
||||
Expect().
|
||||
Status(StatusOK).Body().Equal(Servers.Main().Host() + reqPath)
|
||||
Status(StatusOK).Body().Equal(Default.Config.VHost + reqPath)
|
||||
}
|
||||
|
||||
// run the tests
|
||||
|
||||
757
iris.go
757
iris.go
@@ -13,7 +13,7 @@
|
||||
// iris.Get("/hi_json", func(c *iris.Context) {
|
||||
// c.JSON(200, iris.Map{
|
||||
// "Name": "Iris",
|
||||
// "Age": 2,
|
||||
// "Released": "13 March 2016",
|
||||
// })
|
||||
// })
|
||||
// iris.Listen(":8080")
|
||||
@@ -30,7 +30,7 @@
|
||||
// s1.Get("/hi_json", func(c *iris.Context) {
|
||||
// c.JSON(200, iris.Map{
|
||||
// "Name": "Iris",
|
||||
// "Age": 2,
|
||||
// "Released": "13 March 2016",
|
||||
// })
|
||||
// })
|
||||
//
|
||||
@@ -46,24 +46,12 @@
|
||||
// -----------------------------DOCUMENTATION----------------------------
|
||||
// ----------------------------_______________---------------------------
|
||||
// For middleware, template engines, response engines, sessions, websockets, mails, subdomains,
|
||||
// dynamic subdomains, routes, party of subdomains & routes and much more
|
||||
// dynamic subdomains, routes, party of subdomains & routes, ssh and much more
|
||||
// visit https://www.gitbook.com/book/kataras/iris/details
|
||||
package iris // import "github.com/kataras/iris"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gavv/httpexpect"
|
||||
"github.com/kataras/go-errors"
|
||||
"github.com/kataras/go-fs"
|
||||
@@ -71,14 +59,27 @@ import (
|
||||
"github.com/kataras/go-sessions"
|
||||
"github.com/kataras/go-template"
|
||||
"github.com/kataras/go-template/html"
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/utils"
|
||||
"github.com/valyala/fasthttp"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// Version is the current version of the Iris web framework
|
||||
Version = "4.3.0"
|
||||
Version = "4.4.0"
|
||||
|
||||
banner = ` _____ _
|
||||
|_ _| (_)
|
||||
@@ -88,26 +89,22 @@ const (
|
||||
|_____|_| |_||___/ ` + Version + ` `
|
||||
)
|
||||
|
||||
// Default entry, use it with iris.$anyPublicFunc
|
||||
// Default iris instance entry and its public fields, use it with iris.$anyPublicFuncOrField
|
||||
var (
|
||||
Default *Framework
|
||||
Config *Configuration
|
||||
Logger *log.Logger // if you want colors in your console then you should use this https://github.com/iris-contrib/logger instead.
|
||||
Plugins PluginContainer
|
||||
Router fasthttp.RequestHandler
|
||||
Websocket *WebsocketServer
|
||||
// Look ssh.go for this field's configuration
|
||||
// example: https://github.com/iris-contrib/examples/blob/master/ssh/main.go
|
||||
SSH *SSHServer
|
||||
Servers *ServerList
|
||||
// Available is a channel type of bool, fired to true when the server is opened and all plugins ran
|
||||
// never fires false, if the .Close called then the channel is re-allocating.
|
||||
// the channel is closed only when .ListenVirtual is used, otherwise it remains open until you close it.
|
||||
// the channel remains open until you close it.
|
||||
//
|
||||
// Note: it is a simple channel and decided to put it here and no inside HTTPServer, doesn't have statuses just true and false, simple as possible
|
||||
// Where to use that?
|
||||
// this is used on extreme cases when you don't know which .Listen/.ListenVirtual will be called
|
||||
// and you want to run/declare something external-not-Iris (all Iris functionality declared before .Listen/.ListenVirtual) AFTER the server is started and plugins finished.
|
||||
// see the server_test.go for an example
|
||||
// look at the http_test.go file for a usage example
|
||||
Available chan bool
|
||||
)
|
||||
|
||||
@@ -116,9 +113,9 @@ func initDefault() {
|
||||
Config = Default.Config
|
||||
Logger = Default.Logger
|
||||
Plugins = Default.Plugins
|
||||
Router = Default.Router
|
||||
Websocket = Default.Websocket
|
||||
SSH = Default.SSH
|
||||
Servers = Default.Servers
|
||||
Available = Default.Available
|
||||
}
|
||||
|
||||
@@ -137,18 +134,18 @@ type (
|
||||
FrameworkAPI interface {
|
||||
MuxAPI
|
||||
Set(...OptionSetter)
|
||||
CheckForUpdates(bool)
|
||||
Must(error)
|
||||
AddServer(...OptionServerSettter) *Server
|
||||
ListenTo(...OptionServerSettter) error
|
||||
Build()
|
||||
Serve(net.Listener) error
|
||||
Listen(string)
|
||||
ListenTLS(string, string, string)
|
||||
ListenLETSENCRYPT(string)
|
||||
ListenUNIX(string, os.FileMode)
|
||||
ListenVirtual(...string) *Server
|
||||
Close() error
|
||||
Reserve() error
|
||||
AcquireCtx(*fasthttp.RequestCtx) *Context
|
||||
ReleaseCtx(*Context)
|
||||
Go() error
|
||||
Close() error
|
||||
CheckForUpdates(bool)
|
||||
UseSessionDB(sessions.Database)
|
||||
UseSerializer(string, serializer.Serializer)
|
||||
UseTemplate(template.Engine) *template.Loader
|
||||
@@ -169,25 +166,30 @@ type (
|
||||
// Implements the FrameworkAPI
|
||||
Framework struct {
|
||||
*muxAPI
|
||||
// Handler field which can change the default iris' mux behavior
|
||||
// HTTP Server runtime fields is the iris' defined main server, developer can use unlimited number of servers
|
||||
// note: they're available after .Build, and .Serve/Listen/ListenTLS/ListenLETSENCRYPT/ListenUNIX
|
||||
ln net.Listener
|
||||
fsrv *fasthttp.Server
|
||||
Available chan bool
|
||||
//
|
||||
// Router field which can change the default iris' mux behavior
|
||||
// if you want to get benefit with iris' context make use of:
|
||||
// ctx:= iris.AcquireCtx(*fasthttp.RequestCtx) to get the context at the beginning of your handler
|
||||
// iris.ReleaseCtx(ctx) to release/put the context to the pool, at the very end of your custom handler.
|
||||
Handler fasthttp.RequestHandler
|
||||
Router fasthttp.RequestHandler
|
||||
|
||||
contextPool sync.Pool
|
||||
once sync.Once
|
||||
Config *Configuration
|
||||
sessions sessions.Sessions
|
||||
serializers serializer.Serializers
|
||||
templates *templateEngines
|
||||
// fields which are useful to the user/dev
|
||||
// the last added server is the main server
|
||||
Servers *ServerList
|
||||
// configuration by instance.Logger.Config
|
||||
Logger *log.Logger
|
||||
Plugins PluginContainer
|
||||
Websocket *WebsocketServer
|
||||
SSH *SSHServer
|
||||
Available chan bool
|
||||
|
||||
// this is setted once when .Tester(t) is called
|
||||
testFramework *httpexpect.Expect
|
||||
}
|
||||
@@ -233,7 +235,7 @@ func New(setters ...OptionSetter) *Framework {
|
||||
s.sessions = sessions.New(sessions.DisableAutoGC(true))
|
||||
}
|
||||
|
||||
// routing & http server
|
||||
// routing
|
||||
{
|
||||
// set the servemux, which will provide us the public API also, with its context pool
|
||||
mux := newServeMux(s.Logger)
|
||||
@@ -243,14 +245,53 @@ func New(setters ...OptionSetter) *Framework {
|
||||
}
|
||||
// set the public router API (and party)
|
||||
s.muxAPI = &muxAPI{mux: mux, relativePath: "/"}
|
||||
s.Servers = &ServerList{mux: mux, servers: make([]*Server, 0)}
|
||||
s.Available = make(chan bool)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Framework) initialize() {
|
||||
// Set sets an option aka configuration field to the default iris instance
|
||||
func Set(setters ...OptionSetter) {
|
||||
Default.Set(setters...)
|
||||
}
|
||||
|
||||
// Set sets an option aka configuration field to this iris instance
|
||||
func (s *Framework) Set(setters ...OptionSetter) {
|
||||
if s.Config == nil {
|
||||
defaultConfiguration := DefaultConfiguration()
|
||||
s.Config = &defaultConfiguration
|
||||
}
|
||||
|
||||
for _, setter := range setters {
|
||||
setter.Set(s.Config)
|
||||
}
|
||||
}
|
||||
|
||||
// Must panics on error, it panics on registed iris' logger
|
||||
func Must(err error) {
|
||||
Default.Must(err)
|
||||
}
|
||||
|
||||
// Must panics on error, it panics on registed iris' logger
|
||||
func (s *Framework) Must(err error) {
|
||||
if err != nil {
|
||||
s.Logger.Panic(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Build builds the whole framework's parts together
|
||||
// DO NOT CALL IT MANUALLY IF YOU ARE NOT:
|
||||
// SERVE IRIS BEHIND AN EXTERNAL CUSTOM fasthttp.Server, CAN BE CALLED ONCE PER IRIS INSTANCE FOR YOUR SAFETY
|
||||
func Build() {
|
||||
Default.Build()
|
||||
}
|
||||
|
||||
// Build builds the whole framework's parts together
|
||||
// DO NOT CALL IT MANUALLY IF YOU ARE NOT:
|
||||
// SERVE IRIS BEHIND AN EXTERNAL CUSTOM fasthttp.Server, CAN BE CALLED ONCE PER IRIS INSTANCE FOR YOUR SAFETY
|
||||
func (s *Framework) Build() {
|
||||
s.once.Do(func() {
|
||||
// prepare the serializers, if not any other serializers setted for the default serializer types(json,jsonp,xml,markdown,text,data) then the defaults are setted:
|
||||
serializer.RegisterDefaults(s.serializers)
|
||||
|
||||
@@ -279,14 +320,60 @@ func (s *Framework) initialize() {
|
||||
s.Websocket.RegisterTo(s, s.Config.Websocket)
|
||||
}
|
||||
|
||||
// prepare the mux & the server
|
||||
// prepare the server's handler, we do that check because iris supports
|
||||
// custom routers (you can take the routes registed by iris using iris.Lookups function)
|
||||
if s.Router == nil {
|
||||
// build and get the default mux' handler(*Context)
|
||||
serve := s.mux.BuildHandler()
|
||||
// build the fasthttp handler to bind it to the servers
|
||||
defaultHandler := func(reqCtx *fasthttp.RequestCtx) {
|
||||
ctx := s.AcquireCtx(reqCtx)
|
||||
serve(ctx)
|
||||
s.ReleaseCtx(ctx)
|
||||
}
|
||||
|
||||
s.Router = defaultHandler
|
||||
}
|
||||
|
||||
// .Build, normally*, auto-called after station's listener setted but before the real Serve, so here set the host, scheme
|
||||
// and the mux hostname(*this is here because user may not call .Serve/.Listen functions if listen by a custom server)
|
||||
|
||||
if s.Config.VHost == "" { // if not setted by Listen functions
|
||||
if s.ln != nil { // but user called .Serve
|
||||
// then take the listener's addr
|
||||
s.Config.VHost = s.ln.Addr().String()
|
||||
} else {
|
||||
// if no .Serve or .Listen called, then the user should set the VHost manually,
|
||||
// however set it to a default value here for any case
|
||||
s.Config.VHost = DefaultServerAddr
|
||||
}
|
||||
}
|
||||
// if user didn't specified a scheme then get it from the VHost, which is already setted at before statements
|
||||
if s.Config.VScheme == "" {
|
||||
s.Config.VScheme = ParseScheme(s.Config.VHost)
|
||||
}
|
||||
|
||||
// prepare the mux runtime fields
|
||||
s.mux.setCorrectPath(!s.Config.DisablePathCorrection)
|
||||
s.mux.setEscapePath(!s.Config.DisablePathEscape)
|
||||
// set the mux' hostname (for multi subdomain routing)
|
||||
s.mux.hostname = ParseHostname(s.Config.VHost)
|
||||
|
||||
// set the debug profiling handlers if ProfilePath is setted
|
||||
if debugPath := s.Config.ProfilePath; debugPath != "" {
|
||||
s.Handle(MethodGet, debugPath+"/*action", profileMiddleware(debugPath)...)
|
||||
if s.ln != nil { // user called Listen functions or Serve,
|
||||
// create the main server
|
||||
s.fsrv = &fasthttp.Server{Name: DefaultServerName,
|
||||
MaxRequestBodySize: s.Config.MaxRequestBodySize,
|
||||
ReadBufferSize: s.Config.ReadBufferSize,
|
||||
WriteBufferSize: s.Config.WriteBufferSize,
|
||||
ReadTimeout: s.Config.ReadTimeout,
|
||||
WriteTimeout: s.Config.WriteTimeout,
|
||||
MaxConnsPerIP: s.Config.MaxConnsPerIP,
|
||||
MaxRequestsPerConn: s.Config.MaxRequestsPerConn,
|
||||
Handler: s.Router,
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
// ssh
|
||||
if s.SSH != nil && s.SSH.Enabled() {
|
||||
@@ -301,75 +388,48 @@ func (s *Framework) initialize() {
|
||||
} else if s.Config.CheckForUpdates {
|
||||
go s.CheckForUpdates(false)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
// AcquireCtx gets an Iris' Context from pool
|
||||
// see iris.Handler & ReleaseCtx, Go()
|
||||
func AcquireCtx(reqCtx *fasthttp.RequestCtx) *Context {
|
||||
return Default.AcquireCtx(reqCtx)
|
||||
var (
|
||||
errServerAlreadyStarted = errors.New("Server is already started and listening")
|
||||
)
|
||||
|
||||
// Serve serves incoming connections from the given listener.
|
||||
//
|
||||
// Serve blocks until the given listener returns permanent error.
|
||||
func Serve(ln net.Listener) error {
|
||||
return Default.Serve(ln)
|
||||
}
|
||||
|
||||
// ReleaseCtx puts the Iris' Context back to the pool in order to be re-used
|
||||
// see iris.Handler & AcquireCtx, Go()
|
||||
func ReleaseCtx(ctx *Context) {
|
||||
Default.ReleaseCtx(ctx)
|
||||
}
|
||||
// Serve serves incoming connections from the given listener.
|
||||
//
|
||||
// Serve blocks until the given listener returns permanent error.
|
||||
func (s *Framework) Serve(ln net.Listener) error {
|
||||
if s.IsRunning() {
|
||||
return errServerAlreadyStarted
|
||||
}
|
||||
// maybe a 'race' here but user should not call .Serve more than one time especially in more than one go routines...
|
||||
s.ln = ln
|
||||
|
||||
// AcquireCtx gets an Iris' Context from pool
|
||||
// see iris.Handler & ReleaseCtx, Go()
|
||||
func (s *Framework) AcquireCtx(reqCtx *fasthttp.RequestCtx) *Context {
|
||||
ctx := s.contextPool.Get().(*Context) // Changed to use the pool's New 09/07/2016, ~ -4k nanoseconds(9 bench tests) per requests (better performance)
|
||||
ctx.RequestCtx = reqCtx
|
||||
return ctx
|
||||
}
|
||||
|
||||
// ReleaseCtx puts the Iris' Context back to the pool in order to be re-used
|
||||
// see iris.Handler & AcquireCtx, Go()
|
||||
func (s *Framework) ReleaseCtx(ctx *Context) {
|
||||
ctx.Params = ctx.Params[0:0]
|
||||
ctx.middleware = nil
|
||||
ctx.session = nil
|
||||
s.contextPool.Put(ctx)
|
||||
}
|
||||
|
||||
// Go starts the iris station, listens to all registered servers, and prepare only if Virtual
|
||||
func Go() error {
|
||||
return Default.Go()
|
||||
}
|
||||
|
||||
// Go starts the iris station, listens to all registered servers, and prepare only if Virtual
|
||||
func (s *Framework) Go() error {
|
||||
s.initialize()
|
||||
s.Build()
|
||||
s.Plugins.DoPreListen(s)
|
||||
|
||||
if s.Handler == nil { // use the 'h' which is the default mux' handler
|
||||
// build and get the default mux' handler(*Context)
|
||||
serve := s.mux.BuildHandler()
|
||||
// build the fasthttp handler to bind it to the servers
|
||||
defaultHandler := func(reqCtx *fasthttp.RequestCtx) {
|
||||
ctx := s.AcquireCtx(reqCtx)
|
||||
serve(ctx)
|
||||
s.ReleaseCtx(ctx)
|
||||
}
|
||||
// This didn't helped me ,here, but maybe can help you:
|
||||
// https://www.oreilly.com/learning/run-strikingly-fast-parallel-file-searches-in-go-with-sync-errgroup?utm_source=golangweekly&utm_medium=email
|
||||
// new experimental package: errgroup
|
||||
|
||||
s.Handler = defaultHandler
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
s.Logger.Panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
if firstErr := s.Servers.OpenAll(s.Handler); firstErr != nil {
|
||||
return firstErr
|
||||
}
|
||||
// start the server in goroutine, .Available will block instead
|
||||
go func() { s.Must(s.fsrv.Serve(ln)) }()
|
||||
|
||||
// print the banner
|
||||
if !s.Config.DisableBanner {
|
||||
openedServers := s.Servers.GetAllOpened()
|
||||
l := len(openedServers)
|
||||
hosts := make([]string, l, l)
|
||||
for i, srv := range openedServers {
|
||||
hosts[i] = srv.Host()
|
||||
}
|
||||
|
||||
bannerMessage := fmt.Sprintf("%s: Running at %s", time.Now().Format(s.Config.TimeFormat), strings.Join(hosts, ", "))
|
||||
bannerMessage := fmt.Sprintf("%s: Running at %s", time.Now().Format(s.Config.TimeFormat), s.Config.VHost)
|
||||
// we don't print it via Logger because:
|
||||
// 1. The banner is only 'useful' when the developer logs to terminal and no file
|
||||
// 2. Prefix & LstdFlags options of the default s.Logger
|
||||
@@ -380,28 +440,228 @@ func (s *Framework) Go() error {
|
||||
s.Plugins.DoPostListen(s)
|
||||
|
||||
go func() { s.Available <- true }()
|
||||
ch := make(chan os.Signal)
|
||||
|
||||
ch := make(chan os.Signal, 2)
|
||||
signal.Notify(ch, os.Interrupt, syscall.SIGTERM)
|
||||
<-ch
|
||||
s.Close() // btw, don't panic here
|
||||
if err := s.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
os.Exit(1)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Listen starts the standalone http server
|
||||
// which listens to the addr parameter which as the form of
|
||||
// host:port
|
||||
//
|
||||
// It panics on error if you need a func to return an error, use the Serve
|
||||
func Listen(addr string) {
|
||||
Default.Listen(addr)
|
||||
}
|
||||
|
||||
// Listen starts the standalone http server
|
||||
// which listens to the addr parameter which as the form of
|
||||
// host:port
|
||||
//
|
||||
// It panics on error if you need a func to return an error, use the Serve
|
||||
func (s *Framework) Listen(addr string) {
|
||||
addr = ParseHost(addr)
|
||||
if s.Config.VHost == "" {
|
||||
s.Config.VHost = addr
|
||||
// this will be set as the front-end listening addr
|
||||
}
|
||||
|
||||
ln, err := TCP4(addr)
|
||||
if err != nil {
|
||||
s.Logger.Panic(err)
|
||||
}
|
||||
|
||||
s.Must(s.Serve(ln))
|
||||
}
|
||||
|
||||
// ListenTLS Starts a https server with certificates,
|
||||
// if you use this method the requests of the form of 'http://' will fail
|
||||
// only https:// connections are allowed
|
||||
// which listens to the addr parameter which as the form of
|
||||
// host:port
|
||||
//
|
||||
// It panics on error if you need a func to return an error, use the Serve
|
||||
// ex: iris.ListenTLS(":8080","yourfile.cert","yourfile.key")
|
||||
func ListenTLS(addr string, certFile string, keyFile string) {
|
||||
Default.ListenTLS(addr, certFile, keyFile)
|
||||
}
|
||||
|
||||
// ListenTLS Starts a https server with certificates,
|
||||
// if you use this method the requests of the form of 'http://' will fail
|
||||
// only https:// connections are allowed
|
||||
// which listens to the addr parameter which as the form of
|
||||
// host:port
|
||||
//
|
||||
// It panics on error if you need a func to return an error, use the Serve
|
||||
// ex: iris.ListenTLS(":8080","yourfile.cert","yourfile.key")
|
||||
func (s *Framework) ListenTLS(addr string, certFile, keyFile string) {
|
||||
addr = ParseHost(addr)
|
||||
if s.Config.VHost == "" {
|
||||
s.Config.VHost = addr
|
||||
// this will be set as the front-end listening addr
|
||||
}
|
||||
|
||||
ln, err := TLS(addr, certFile, keyFile)
|
||||
if err != nil {
|
||||
s.Logger.Panic(err)
|
||||
}
|
||||
|
||||
s.Must(s.Serve(ln))
|
||||
}
|
||||
|
||||
// ListenLETSENCRYPT starts a server listening at the specific nat address
|
||||
// using key & certification taken from the letsencrypt.org 's servers
|
||||
// it's also starts a second 'http' server to redirect all 'http://$ADDR_HOSTNAME:80' to the' https://$ADDR'
|
||||
// example: https://github.com/iris-contrib/examples/blob/master/letsencyrpt/main.go
|
||||
func ListenLETSENCRYPT(addr string) {
|
||||
Default.ListenLETSENCRYPT(addr)
|
||||
}
|
||||
|
||||
// ListenLETSENCRYPT starts a server listening at the specific nat address
|
||||
// using key & certification taken from the letsencrypt.org 's servers
|
||||
// it's also starts a second 'http' server to redirect all 'http://$ADDR_HOSTNAME:80' to the' https://$ADDR'
|
||||
// example: https://github.com/iris-contrib/examples/blob/master/letsencyrpt/main.go
|
||||
func (s *Framework) ListenLETSENCRYPT(addr string) {
|
||||
addr = ParseHost(addr)
|
||||
if s.Config.VHost == "" {
|
||||
s.Config.VHost = addr
|
||||
// this will be set as the front-end listening addr
|
||||
}
|
||||
ln, err := LETSENCRYPT(addr)
|
||||
if err != nil {
|
||||
s.Logger.Panic(err)
|
||||
}
|
||||
|
||||
// starts a second server which listening on :80 to redirect all requests to the :443 (https://)
|
||||
Proxy(":80", "https://"+addr)
|
||||
s.Must(s.Serve(ln))
|
||||
}
|
||||
|
||||
// ListenUNIX starts the process of listening to the new requests using a 'socket file', this works only on unix
|
||||
//
|
||||
// It panics on error if you need a func to return an error, use the Serve
|
||||
// ex: iris.ListenUNIX(":8080", Mode: os.FileMode)
|
||||
func ListenUNIX(addr string, mode os.FileMode) {
|
||||
Default.ListenUNIX(addr, mode)
|
||||
}
|
||||
|
||||
// ListenUNIX starts the process of listening to the new requests using a 'socket file', this works only on unix
|
||||
//
|
||||
// It panics on error if you need a func to return an error, use the Serve
|
||||
// ex: iris.ListenUNIX(":8080", Mode: os.FileMode)
|
||||
func (s *Framework) ListenUNIX(addr string, mode os.FileMode) {
|
||||
// *on unix listen we don't parse the host, because sometimes it causes problems to the user
|
||||
if s.Config.VHost == "" {
|
||||
s.Config.VHost = addr
|
||||
// this will be set as the front-end listening addr
|
||||
}
|
||||
ln, err := UNIX(addr, mode)
|
||||
if err != nil {
|
||||
s.Logger.Panic(err)
|
||||
}
|
||||
|
||||
s.Must(s.Serve(ln))
|
||||
}
|
||||
|
||||
// IsRunning returns true if server is running
|
||||
func IsRunning() bool {
|
||||
return Default.IsRunning()
|
||||
}
|
||||
|
||||
// IsRunning returns true if server is running
|
||||
func (s *Framework) IsRunning() bool {
|
||||
return s != nil && s.ln != nil && s.ln.Addr() != nil && s.ln.Addr().String() != ""
|
||||
}
|
||||
|
||||
// DisableKeepalive whether to disable keep-alive connections.
|
||||
//
|
||||
// The server will close all the incoming connections after sending
|
||||
// the first response to client if this option is set to true.
|
||||
//
|
||||
// By default keep-alive connections are enabled
|
||||
//
|
||||
// Note: Used on packages like graceful, after the server runs.
|
||||
func DisableKeepalive(val bool) {
|
||||
Default.DisableKeepalive(val)
|
||||
}
|
||||
|
||||
// DisableKeepalive whether to disable keep-alive connections.
|
||||
//
|
||||
// The server will close all the incoming connections after sending
|
||||
// the first response to client if this option is set to true.
|
||||
//
|
||||
// By default keep-alive connections are enabled
|
||||
//
|
||||
// Note: Used on packages like graceful, after the server runs.
|
||||
func (s *Framework) DisableKeepalive(val bool) {
|
||||
if s.fsrv != nil {
|
||||
s.fsrv.DisableKeepalive = val
|
||||
}
|
||||
}
|
||||
|
||||
// Close terminates all the registered servers and returns an error if any
|
||||
// if you want to panic on this error use the iris.Must(iris.Close())
|
||||
func Close() error {
|
||||
return Default.Close()
|
||||
}
|
||||
|
||||
// Close terminates all the registered servers and returns an error if any
|
||||
// if you want to panic on this error use the iris.Must(iris.Close())
|
||||
func (s *Framework) Close() error {
|
||||
if s.IsRunning() {
|
||||
s.Plugins.DoPreClose(s)
|
||||
s.Available = make(chan bool)
|
||||
|
||||
return s.ln.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set sets an option aka configuration field to the default iris instance
|
||||
func Set(setters ...OptionSetter) {
|
||||
Default.Set(setters...)
|
||||
// Reserve re-starts the server using the last .Serve's listener
|
||||
func Reserve() error {
|
||||
return Default.Reserve()
|
||||
}
|
||||
|
||||
// Set sets an option aka configuration field to this iris instance
|
||||
func (s *Framework) Set(setters ...OptionSetter) {
|
||||
if s.Config == nil {
|
||||
defaultConfiguration := DefaultConfiguration()
|
||||
s.Config = &defaultConfiguration
|
||||
}
|
||||
// Reserve re-starts the server using the last .Serve's listener
|
||||
func (s *Framework) Reserve() error {
|
||||
return s.Serve(s.ln)
|
||||
}
|
||||
|
||||
for _, setter := range setters {
|
||||
setter.Set(s.Config)
|
||||
}
|
||||
// AcquireCtx gets an Iris' Context from pool
|
||||
// see .ReleaseCtx & .Serve
|
||||
func AcquireCtx(reqCtx *fasthttp.RequestCtx) *Context {
|
||||
return Default.AcquireCtx(reqCtx)
|
||||
}
|
||||
|
||||
// AcquireCtx gets an Iris' Context from pool
|
||||
// see .ReleaseCtx & .Serve
|
||||
func (s *Framework) AcquireCtx(reqCtx *fasthttp.RequestCtx) *Context {
|
||||
ctx := s.contextPool.Get().(*Context) // Changed to use the pool's New 09/07/2016, ~ -4k nanoseconds(9 bench tests) per requests (better performance)
|
||||
ctx.RequestCtx = reqCtx
|
||||
return ctx
|
||||
}
|
||||
|
||||
// ReleaseCtx puts the Iris' Context back to the pool in order to be re-used
|
||||
// see .AcquireCtx & .Serve
|
||||
func ReleaseCtx(ctx *Context) {
|
||||
Default.ReleaseCtx(ctx)
|
||||
}
|
||||
|
||||
// ReleaseCtx puts the Iris' Context back to the pool in order to be re-used
|
||||
// see .AcquireCtx & .Serve
|
||||
func (s *Framework) ReleaseCtx(ctx *Context) {
|
||||
ctx.Params = ctx.Params[0:0]
|
||||
ctx.middleware = nil
|
||||
ctx.session = nil
|
||||
s.contextPool.Put(ctx)
|
||||
}
|
||||
|
||||
// global once because is not necessary to check for updates on more than one iris station*
|
||||
@@ -454,224 +714,11 @@ func (s *Framework) CheckForUpdates(force bool) {
|
||||
if s.Logger != nil {
|
||||
s.Logger.Println("exiting now...")
|
||||
}
|
||||
os.Exit(0)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Must panics on error, it panics on registed iris' logger
|
||||
func Must(err error) {
|
||||
Default.Must(err)
|
||||
}
|
||||
|
||||
// Must panics on error, it panics on registed iris' logger
|
||||
func (s *Framework) Must(err error) {
|
||||
if err != nil {
|
||||
s.Logger.Panic(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// AddServer same as .Servers.Add(ServerConfiguration)
|
||||
//
|
||||
// AddServer starts a server which listens to this station
|
||||
// Note that the view engine's functions {{ url }} and {{ urlpath }} will return the first's registered server's scheme (http/https)
|
||||
//
|
||||
// this is useful mostly when you want to have two or more listening ports ( two or more servers ) for the same station
|
||||
//
|
||||
// receives one parameter which is the ServerConfiguration for the new server
|
||||
// returns the new standalone server( you can close this server by the returning reference)
|
||||
//
|
||||
// If you need only one server you can use the blocking-funcs: .Listen/ListenTLS/ListenUNIX/ListenTo
|
||||
//
|
||||
// this is a NOT A BLOCKING version, the main .Listen/ListenTLS/ListenUNIX/ListenTo should be always executed LAST, so this function goes before the main .Listen/ListenTLS/ListenUNIX/ListenTo
|
||||
func AddServer(setters ...OptionServerSettter) *Server {
|
||||
return Default.AddServer(setters...)
|
||||
}
|
||||
|
||||
// AddServer same as .Servers.Add(ServerConfiguration)
|
||||
//
|
||||
// AddServer starts a server which listens to this station
|
||||
// Note that the view engine's functions {{ url }} and {{ urlpath }} will return the last registered server's scheme (http/https)
|
||||
//
|
||||
// this is useful mostly when you want to have two or more listening ports ( two or more servers ) for the same station
|
||||
//
|
||||
// receives one parameter which is the ServerConfiguration for the new server
|
||||
// returns the new standalone server( you can close this server by the returning reference)
|
||||
//
|
||||
// If you need only one server you can use the blocking-funcs: .Listen/ListenTLS/ListenUNIX/ListenTo
|
||||
//
|
||||
// this is a NOT A BLOCKING version, the main .Listen/ListenTLS/ListenUNIX/ListenTo should be always executed LAST, so this function goes before the main .Listen/ListenTLS/ListenUNIX/ListenTo
|
||||
func (s *Framework) AddServer(setters ...OptionServerSettter) *Server {
|
||||
return s.Servers.Add(setters...)
|
||||
}
|
||||
|
||||
// ListenTo listens to a server but accepts the full server's configuration
|
||||
// returns an error, you're responsible to handle that
|
||||
// ex: ris.ListenTo(iris.ServerConfiguration{ListeningAddr:":8080"})
|
||||
// ex2: err := iris.ListenTo(iris.OptionServerListeningAddr(":8080"))
|
||||
// or use the iris.Must(iris.ListenTo(iris.ServerConfiguration{ListeningAddr:":8080"}))
|
||||
//
|
||||
// it's a blocking func
|
||||
func ListenTo(setters ...OptionServerSettter) error {
|
||||
return Default.ListenTo(setters...)
|
||||
}
|
||||
|
||||
// ListenTo listens to a server but acceots the full server's configuration
|
||||
// returns an error, you're responsible to handle that
|
||||
// ex: ris.ListenTo(iris.ServerConfiguration{ListeningAddr:":8080"})
|
||||
// ex2: err := iris.ListenTo(iris.OptionServerListeningAddr(":8080"))
|
||||
// or use the iris.Must(iris.ListenTo(iris.ServerConfiguration{ListeningAddr:":8080"}))
|
||||
//
|
||||
// it's a blocking func
|
||||
func (s *Framework) ListenTo(setters ...OptionServerSettter) (err error) {
|
||||
s.Servers.Add(setters...)
|
||||
return s.Go()
|
||||
}
|
||||
|
||||
// Listen starts the standalone http server
|
||||
// which listens to the addr parameter which as the form of
|
||||
// host:port
|
||||
//
|
||||
// It panics on error if you need a func to return an error, use the ListenTo
|
||||
func Listen(addr string) {
|
||||
Default.Listen(addr)
|
||||
}
|
||||
|
||||
// Listen starts the standalone http server
|
||||
// which listens to the addr parameter which as the form of
|
||||
// host:port
|
||||
//
|
||||
// It panics on error if you need a func to return an error, use the ListenTo
|
||||
func (s *Framework) Listen(addr string) {
|
||||
s.Must(s.ListenTo(ServerConfiguration{ListeningAddr: addr}))
|
||||
}
|
||||
|
||||
// ListenTLS Starts a https server with certificates,
|
||||
// if you use this method the requests of the form of 'http://' will fail
|
||||
// only https:// connections are allowed
|
||||
// which listens to the addr parameter which as the form of
|
||||
// host:port
|
||||
//
|
||||
// It panics on error if you need a func to return an error, use the ListenTo
|
||||
// ex: iris.ListenTLS(":8080","yourfile.cert","yourfile.key")
|
||||
func ListenTLS(addr string, certFile string, keyFile string) {
|
||||
Default.ListenTLS(addr, certFile, keyFile)
|
||||
}
|
||||
|
||||
// ListenTLSAuto starts a server listening at the specific nat address
|
||||
// using key & certification taken from the letsencrypt.org 's servers
|
||||
// it also starts a second 'http' server to redirect all 'http://$ADDR_HOSTNAME:80' to the' https://$ADDR'
|
||||
//
|
||||
// Notes:
|
||||
// if you don't want the last feature you should use this method:
|
||||
// iris.ListenTo(iris.ServerConfiguration{ListeningAddr: "mydomain.com:443", AutoTLS: true})
|
||||
// it's a blocking function
|
||||
// Limit : https://github.com/iris-contrib/letsencrypt/blob/master/lets.go#L142
|
||||
//
|
||||
// example: https://github.com/iris-contrib/examples/blob/master/letsencyrpt/main.go
|
||||
func ListenTLSAuto(addr string) {
|
||||
Default.ListenTLSAuto(addr)
|
||||
}
|
||||
|
||||
// ListenTLS Starts a https server with certificates,
|
||||
// if you use this method the requests of the form of 'http://' will fail
|
||||
// only https:// connections are allowed
|
||||
// which listens to the addr parameter which as the form of
|
||||
// host:port
|
||||
//
|
||||
// It panics on error if you need a func to return an error, use the ListenTo
|
||||
// ex: iris.ListenTLS(":8080","yourfile.cert","yourfile.key")
|
||||
func (s *Framework) ListenTLS(addr string, certFile, keyFile string) {
|
||||
if certFile == "" || keyFile == "" {
|
||||
s.Logger.Panic("You should provide certFile and keyFile for TLS/SSL")
|
||||
}
|
||||
s.Must(s.ListenTo(ServerConfiguration{ListeningAddr: addr, CertFile: certFile, KeyFile: keyFile}))
|
||||
}
|
||||
|
||||
// ListenTLSAuto starts a server listening at the specific nat address
|
||||
// using key & certification taken from the letsencrypt.org 's servers
|
||||
// it also starts a second 'http' server to redirect all 'http://$ADDR_HOSTNAME:80' to the' https://$ADDR'
|
||||
//
|
||||
// Notes:
|
||||
// if you don't want the last feature you should use this method:
|
||||
// iris.ListenTo(iris.ServerConfiguration{ListeningAddr: "mydomain.com:443", AutoTLS: true})
|
||||
// it's a blocking function
|
||||
// Limit : https://github.com/iris-contrib/letsencrypt/blob/master/lets.go#L142
|
||||
//
|
||||
// example: https://github.com/iris-contrib/examples/blob/master/letsencyrpt/main.go
|
||||
func (s *Framework) ListenTLSAuto(addr string) {
|
||||
if portIdx := strings.IndexByte(addr, ':'); portIdx == -1 {
|
||||
addr += ":443"
|
||||
}
|
||||
addr = ServerParseAddr(addr)
|
||||
|
||||
// start a secondary server (HTTP) on port 80, this is a non-blocking func
|
||||
// redirects all http to the main server which is tls/ssl on port :443
|
||||
s.AddServer(ServerConfiguration{ListeningAddr: ":80", RedirectTo: "https://" + addr})
|
||||
s.Must(s.ListenTo(ServerConfiguration{ListeningAddr: addr, AutoTLS: true}))
|
||||
}
|
||||
|
||||
// ListenUNIX starts the process of listening to the new requests using a 'socket file', this works only on unix
|
||||
//
|
||||
// It panics on error if you need a func to return an error, use the ListenTo
|
||||
// ex: iris.ListenUNIX(":8080", Mode: os.FileMode)
|
||||
func ListenUNIX(addr string, mode os.FileMode) {
|
||||
Default.ListenUNIX(addr, mode)
|
||||
}
|
||||
|
||||
// ListenUNIX starts the process of listening to the new requests using a 'socket file', this works only on unix
|
||||
//
|
||||
// It panics on error if you need a func to return an error, use the ListenTo
|
||||
// ex: ris.ListenUNIX(":8080", Mode: os.FileMode)
|
||||
func (s *Framework) ListenUNIX(addr string, mode os.FileMode) {
|
||||
s.Must(ListenTo(ServerConfiguration{ListeningAddr: addr, Mode: mode}))
|
||||
}
|
||||
|
||||
// ListenVirtual is useful only when you want to test Iris, it doesn't starts the server but it configures and returns it
|
||||
// initializes the whole framework but server doesn't listens to a specific net.Listener
|
||||
// it is not blocking the app
|
||||
func ListenVirtual(optionalAddr ...string) *Server {
|
||||
return Default.ListenVirtual(optionalAddr...)
|
||||
}
|
||||
|
||||
// ListenVirtual is useful only when you want to test Iris, it doesn't starts the server but it configures and returns it
|
||||
// initializes the whole framework but server doesn't listens to a specific net.Listener
|
||||
// it is not blocking the app
|
||||
func (s *Framework) ListenVirtual(optionalAddr ...string) *Server {
|
||||
s.Config.DisableBanner = true
|
||||
cfg := DefaultServerConfiguration()
|
||||
|
||||
if len(optionalAddr) > 0 && optionalAddr[0] != "" {
|
||||
cfg.ListeningAddr = optionalAddr[0]
|
||||
}
|
||||
cfg.Virtual = true
|
||||
|
||||
go func() {
|
||||
s.Must(s.ListenTo(cfg))
|
||||
}()
|
||||
|
||||
if ok := <-s.Available; !ok {
|
||||
s.Logger.Panic("Unexpected error:Virtual server cannot start, please report this as bug!!")
|
||||
}
|
||||
|
||||
close(s.Available)
|
||||
return s.Servers.Main()
|
||||
}
|
||||
|
||||
// Close terminates all the registered servers and returns an error if any
|
||||
// if you want to panic on this error use the iris.Must(iris.Close())
|
||||
func Close() error {
|
||||
return Default.Close()
|
||||
}
|
||||
|
||||
// Close terminates all the registered servers and returns an error if any
|
||||
// if you want to panic on this error use the iris.Must(iris.Close())
|
||||
func (s *Framework) Close() error {
|
||||
s.Plugins.DoPreClose(s)
|
||||
s.Available = make(chan bool)
|
||||
return s.Servers.CloseAll()
|
||||
}
|
||||
|
||||
// UseSessionDB registers a session database, you can register more than one
|
||||
// accepts a session database which implements a Load(sid string) map[string]interface{} and an Update(sid string, newValues map[string]interface{})
|
||||
// the only reason that a session database will be useful for you is when you want to keep the session's values/data after the app restart
|
||||
@@ -922,10 +969,9 @@ func (s *Framework) URL(routeName string, args ...interface{}) (url string) {
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
srv := s.Servers.Main()
|
||||
scheme := srv.Scheme()
|
||||
|
||||
host := srv.Host()
|
||||
scheme := s.Config.VScheme // if s.Config.VScheme was setted, that will be used instead of the real, in order to make easy to run behind nginx
|
||||
host := s.Config.VHost // if s.Config.VHost was setted, that will be used instead of the real, in order to make easy to run behind nginx
|
||||
arguments := args[0:]
|
||||
|
||||
// join arrays as arguments
|
||||
@@ -1028,35 +1074,25 @@ func (s *Framework) SerializeToString(keyOrContentType string, obj interface{},
|
||||
// NewTester Prepares and returns a new test framework based on the api
|
||||
// is useful when you need to have more than one test framework for the same iris insttance, otherwise you can use the iris.Tester(t *testing.T)/variable.Tester(t *testing.T)
|
||||
func NewTester(api *Framework, t *testing.T) *httpexpect.Expect {
|
||||
srv := api.Servers.Main()
|
||||
if srv == nil { // maybe the user called this after .Listen/ListenTLS/ListenUNIX, the tester can be used as standalone (with no running iris instance) or inside a running instance/app
|
||||
srv = api.ListenVirtual(api.Config.Tester.ListeningAddr)
|
||||
api.Set(OptionDisableBanner(true))
|
||||
|
||||
baseURL := ""
|
||||
if api.fsrv == nil {
|
||||
api.Build()
|
||||
}
|
||||
if !api.Config.Tester.ExplicitURL {
|
||||
baseURL = api.Config.VScheme + api.Config.VHost
|
||||
// if it's still empty then set it to the default server addr
|
||||
if baseURL == "" {
|
||||
baseURL = SchemeHTTP + DefaultServerAddr
|
||||
}
|
||||
|
||||
opened := api.Servers.GetAllOpened()
|
||||
h := srv.Handler
|
||||
baseURL := srv.FullHost()
|
||||
if len(opened) > 1 {
|
||||
baseURL = ""
|
||||
//we have more than one server, so we will create a handler here and redirect by registered listening addresses
|
||||
h = func(reqCtx *fasthttp.RequestCtx) {
|
||||
for _, s := range opened {
|
||||
if strings.HasPrefix(reqCtx.URI().String(), s.FullHost()) { // yes on :80 should be passed :80 also, this is inneed for multiserver testing
|
||||
s.Handler(reqCtx)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if api.Config.Tester.ExplicitURL {
|
||||
baseURL = ""
|
||||
}
|
||||
|
||||
testConfiguration := httpexpect.Config{
|
||||
BaseURL: baseURL,
|
||||
Client: &http.Client{
|
||||
Transport: httpexpect.NewFastBinder(h),
|
||||
Transport: httpexpect.NewFastBinder(api.Router),
|
||||
Jar: httpexpect.NewJar(),
|
||||
},
|
||||
Reporter: httpexpect.NewAssertReporter(t),
|
||||
@@ -1106,8 +1142,6 @@ type (
|
||||
// main handlers
|
||||
Handle(string, string, ...Handler) RouteNameFunc
|
||||
HandleFunc(string, string, ...HandlerFunc) RouteNameFunc
|
||||
// H_ is used to convert a context.IContext handler func to iris.HandlerFunc, is used only inside iris internal package to avoid import cycles
|
||||
H_(string, string, func(context.IContext)) func(string)
|
||||
API(string, HandlerAPI, ...HandlerFunc)
|
||||
|
||||
// http methods
|
||||
@@ -1295,13 +1329,6 @@ func (api *muxAPI) HandleFunc(method string, registedPath string, handlersFn ...
|
||||
return api.Handle(method, registedPath, convertToHandlers(handlersFn)...)
|
||||
}
|
||||
|
||||
// H_ is used to convert a context.IContext handler func to iris.HandlerFunc, is used only inside iris internal package to avoid import cycles
|
||||
func (api *muxAPI) H_(method string, registedPath string, fn func(context.IContext)) func(string) {
|
||||
return api.HandleFunc(method, registedPath, func(ctx *Context) {
|
||||
fn(ctx)
|
||||
})
|
||||
}
|
||||
|
||||
// API converts & registers a custom struct to the router
|
||||
// receives two parameters
|
||||
// first is the request path (string)
|
||||
@@ -1756,7 +1783,7 @@ func (api *muxAPI) StaticWeb(reqPath string, systemPath string, stripSlashes int
|
||||
if reqPath[len(reqPath)-1] != slashByte { // if / then /*filepath, if /something then /something/*filepath
|
||||
reqPath += slash
|
||||
}
|
||||
|
||||
//todo: fs.go
|
||||
hasIndex := utils.Exists(systemPath + utils.PathSeparator + "index.html")
|
||||
var indexNames []string
|
||||
if hasIndex {
|
||||
|
||||
14
iris_test.go
14
iris_test.go
@@ -1,14 +0,0 @@
|
||||
package iris
|
||||
|
||||
/*
|
||||
The most iris.go file implementation tested at other files like context_test, http_test, the untested are the Static methods, the favicon and some interfaces, which I already
|
||||
tested them on production and I don't expect unexpected behavior but if you think we need more:
|
||||
|
||||
CONTRIBUTE & DISCUSSION ABOUT TESTS TO: https://github.com/iris-contrib/tests
|
||||
*/
|
||||
|
||||
// Notes:
|
||||
//
|
||||
// We use Default := New() via initDefault() and not api := New() neither just Default. because we want to cover as much code as possible
|
||||
// The tests are mostly end-to-end, except some features like plugins.
|
||||
//
|
||||
@@ -56,6 +56,7 @@ func (t *testPluginEx) PreClose(*Framework) {
|
||||
|
||||
func ExamplePlugins_Add() {
|
||||
initDefault()
|
||||
Default.Set(OptionDisableBanner(true))
|
||||
Plugins.Add(PreListenFunc(func(*Framework) {
|
||||
fmt.Println("PreListen Func")
|
||||
}))
|
||||
@@ -72,9 +73,11 @@ func ExamplePlugins_Add() {
|
||||
Plugins.Add(myplugin)
|
||||
desc := Plugins.GetDescription(myplugin)
|
||||
fmt.Println(desc)
|
||||
go Listen(":8080")
|
||||
|
||||
ListenVirtual()
|
||||
if ok := <-Available; ok {
|
||||
Close()
|
||||
}
|
||||
|
||||
// Output:
|
||||
// GetName Struct
|
||||
|
||||
47
ssh.go
47
ssh.go
@@ -102,7 +102,7 @@ func (s *SSHServer) bindTo(station *Framework) {
|
||||
|
||||
sshCommands := Commands{
|
||||
Command{Name: "status", Description: "Prompts the status of the HTTP Server, is listening(started) or not(stopped).", Action: func(conn ssh.Channel) {
|
||||
if station.Servers.Main() != nil && station.Servers.Main().IsListening() {
|
||||
if station.IsRunning() {
|
||||
statusRunningMsg(conn)
|
||||
} else {
|
||||
statusNotRunningMsg(conn)
|
||||
@@ -115,29 +115,26 @@ func (s *SSHServer) bindTo(station *Framework) {
|
||||
// Note for stop If you have opened a tab with Q route:
|
||||
// in order to see that the http listener has closed you have to close your browser and re-navigate(browsers caches the tcp connection)
|
||||
Command{Name: "stop", Description: "Stops the HTTP Server.", Action: func(conn ssh.Channel) {
|
||||
srv := station.Servers.Main()
|
||||
if srv != nil && srv.IsListening() {
|
||||
srv.Close()
|
||||
srv.listener = nil
|
||||
if station.IsRunning() {
|
||||
station.Close()
|
||||
//srv.listener = nil used to reopen so let it setted
|
||||
serverStoppedMsg(conn)
|
||||
} else {
|
||||
errServerNotReadyMsg(conn)
|
||||
}
|
||||
}},
|
||||
Command{Name: "start", Description: "Starts the HTTP Server.", Action: func(conn ssh.Channel) {
|
||||
srv := station.Servers.Main()
|
||||
if !srv.IsListening() {
|
||||
go srv.Open(srv.Handler)
|
||||
if !station.IsRunning() {
|
||||
go station.Reserve()
|
||||
}
|
||||
serverStartedMsg(conn)
|
||||
}},
|
||||
Command{Name: "restart", Description: "Restarts the HTTP Server.", Action: func(conn ssh.Channel) {
|
||||
srv := station.Servers.Main()
|
||||
if srv != nil && srv.IsListening() {
|
||||
srv.Close()
|
||||
srv.listener = nil
|
||||
if station.IsRunning() {
|
||||
station.Close()
|
||||
//srv.listener = nil used to reopen so let it setted
|
||||
}
|
||||
go srv.Open(srv.Handler)
|
||||
go station.Reserve()
|
||||
serverRestartedMsg(conn)
|
||||
}},
|
||||
/* not ready yet
|
||||
@@ -452,23 +449,9 @@ func (s *SSHServer) logf(format string, a ...interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// parseHostname receives an addr of form host[:port] and returns the hostname part of it
|
||||
// ex: localhost:8080 will return the `localhost`, mydomain.com:22 will return the 'mydomain'
|
||||
func parseHostname(addr string) string {
|
||||
idx := strings.IndexByte(addr, ':')
|
||||
if idx == 0 {
|
||||
// only port, then return 0.0.0.0
|
||||
return "0.0.0.0"
|
||||
} else if idx > 0 {
|
||||
return addr[0:idx]
|
||||
}
|
||||
// it's already hostname
|
||||
return addr
|
||||
}
|
||||
|
||||
// parsePort receives an addr of form host[:port] and returns the port part of it
|
||||
// ex: localhost:8080 will return the `8080`, mydomain.com will return the '22'
|
||||
func parsePort(addr string) int {
|
||||
// parsePortSSH receives an addr of form host[:port] and returns the port part of it
|
||||
// ex: localhost:22 will return the `22`, mydomain.com will return the '22'
|
||||
func parsePortSSH(addr string) int {
|
||||
if portIdx := strings.IndexByte(addr, ':'); portIdx != -1 {
|
||||
afP := addr[portIdx+1:]
|
||||
p, err := strconv.Atoi(afP)
|
||||
@@ -484,8 +467,8 @@ var standardCommands = Commands{Command{Name: "help", Description: "Opens up the
|
||||
Command{Name: "exit", Description: "Exits from the terminal (if interactive shell)"}}
|
||||
|
||||
func (s *SSHServer) writeHelp(wr io.Writer) {
|
||||
port := parsePort(s.Host)
|
||||
hostname := parseHostname(s.Host)
|
||||
port := parsePortSSH(s.Host)
|
||||
hostname := ParseHostname(s.Host)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
// means that user-dev has old version of Go Programming Language in her/his machine, so print a message to the server terminal
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
## Package information
|
||||
|
||||
This package contains helpful functions that iris, internally, uses
|
||||
|
||||
|
||||
**That's it.**
|
||||
@@ -1,22 +0,0 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/kataras/go-errors"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNoZip returns an error with message: 'While creating file '+filename'. It's not a zip'
|
||||
ErrNoZip = errors.New("While installing file '%s'. It's not a zip")
|
||||
// ErrFileOpen returns an error with message: 'While opening a file. Trace: +specific error'
|
||||
ErrFileOpen = errors.New("While opening a file. Trace: %s")
|
||||
// ErrFileCreate returns an error with message: 'While creating a file. Trace: +specific error'
|
||||
ErrFileCreate = errors.New("While creating a file. Trace: %s")
|
||||
// ErrFileRemove returns an error with message: 'While removing a file. Trace: +specific error'
|
||||
ErrFileRemove = errors.New("While removing a file. Trace: %s")
|
||||
// ErrFileCopy returns an error with message: 'While copying files. Trace: +specific error'
|
||||
ErrFileCopy = errors.New("While copying files. Trace: %s")
|
||||
// ErrFileDownload returns an error with message: 'While downloading from +specific url. Trace: +specific error'
|
||||
ErrFileDownload = errors.New("While downloading from %s. Trace: %s")
|
||||
// ErrDirCreate returns an error with message: 'Unable to create directory on '+root dir'. Trace: +specific error
|
||||
ErrDirCreate = errors.New("Unable to create directory on '%s'. Trace: %s")
|
||||
)
|
||||
@@ -1,64 +0,0 @@
|
||||
/* ticker.go: after version 1, we don't need this atm, but we keep it. */
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Ticker is the timer which is used in cache
|
||||
type Ticker struct {
|
||||
ticker *time.Ticker
|
||||
started bool
|
||||
tickHandlers []func()
|
||||
}
|
||||
|
||||
// NewTicker returns a new Ticker
|
||||
func NewTicker() *Ticker {
|
||||
return &Ticker{tickHandlers: make([]func(), 0), started: false}
|
||||
}
|
||||
|
||||
// OnTick add event handlers/ callbacks which are called on each timer's tick
|
||||
func (c *Ticker) OnTick(h func()) {
|
||||
c.tickHandlers = append(c.tickHandlers, h)
|
||||
}
|
||||
|
||||
// Start starts the timer and execute all listener's when tick
|
||||
func (c *Ticker) Start(duration time.Duration) {
|
||||
if c.started {
|
||||
return
|
||||
}
|
||||
|
||||
if c.ticker != nil {
|
||||
panic("Iris Ticker: Cannot re-start a cache timer, if you stop it, it is not recommented to resume it,\n Just create a new CacheTimer.")
|
||||
}
|
||||
|
||||
c.ticker = time.NewTicker(duration)
|
||||
|
||||
go func() {
|
||||
for t := range c.ticker.C {
|
||||
_ = t
|
||||
// c.mu.Lock()
|
||||
// c.mu.Unlock()
|
||||
//I can make it a clojure to handle only handlers that are registed before .start() but we are ok with this, it is not map no need to Lock, for now.
|
||||
for i := range c.tickHandlers {
|
||||
c.tickHandlers[i]()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
c.started = true
|
||||
}
|
||||
|
||||
// Stop stops the ticker
|
||||
func (c *Ticker) Stop() {
|
||||
if c.started {
|
||||
c.ticker.Stop()
|
||||
c.started = false
|
||||
}
|
||||
}
|
||||
|
||||
// ITick is the interface which all ticker's listeners must implement
|
||||
type ITick interface {
|
||||
OnTick()
|
||||
}
|
||||
Reference in New Issue
Block a user