mirror of
https://github.com/kataras/iris.git
synced 2025-12-17 09:57: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
|
# 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
|
## 4.2.9 -> 4.3.0
|
||||||
|
|
||||||
|
|||||||
704
LICENSE
704
LICENSE
@@ -1,25 +1,7 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2016 Gerasimos Maropoulos
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
in the Software without restriction, including without limitation the rights
|
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,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
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="#"><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>
|
<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/>
|
<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>
|
<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].
|
* [Chat][Chat].
|
||||||
|
|
||||||
|
|
||||||
New website-docs & logo have been designed by the community[*](https://github.com/kataras/iris/issues/153)
|
New logo have been designed by the community member, [@OneebMalik](https://github.com/OneebMalik).
|
||||||
|
|
||||||
- Website created by [@kujtimiihoxha](https://github.com/kujtimiihoxha)
|
|
||||||
- Logo designed by [@OneebMalik](https://github.com/OneebMalik)
|
|
||||||
|
|
||||||
|
|
||||||
Features
|
Features
|
||||||
------------
|
------------
|
||||||
- Focus on high performance
|
- Focus on high performance
|
||||||
- Robust routing, static, wildcard subdomains and routes.
|
- 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
|
- [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)
|
- 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)
|
- 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) |
|
| [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) |
|
| [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) |
|
| [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) |
|
| [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) |
|
| [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) |
|
| [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
|
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). 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).
|
||||||
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).
|
|
||||||
|
|
||||||
Versioning
|
Versioning
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Current: **v4.3.0**
|
Current: **v4.4.0**
|
||||||
|
|
||||||
> Iris is an active project
|
> 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] 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, 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] 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)!
|
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
|
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
|
[Chat]: https://kataras.rocket.chat/channel/iris
|
||||||
[ChatMain]: https://kataras.rocket.chat/channel/iris
|
[ChatMain]: https://kataras.rocket.chat/channel/iris
|
||||||
[ChatAlternative]: https://gitter.im/kataras/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"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"time"
|
"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
|
// Configuration is also implements the OptionSet so it's a valid option itself, this is briliant enough
|
||||||
type Configuration struct {
|
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
|
// 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 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
|
// if 'y' is pressed then the updater will try to install the latest version
|
||||||
@@ -102,35 +173,6 @@ type Configuration struct {
|
|||||||
// Default is [IRIS]
|
// Default is [IRIS]
|
||||||
LoggerPreffix string
|
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
|
// DisableTemplateEngines set to true to disable loading the default template engine (html/template) and disallow the use of iris.UseEngine
|
||||||
// default is false
|
// default is false
|
||||||
DisableTemplateEngines bool
|
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
|
// All options starts with "Option" preffix in order to be easier to find what dev searching for
|
||||||
var (
|
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
|
// 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 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
|
// if 'y' is pressed then the updater will try to install the latest version
|
||||||
@@ -194,7 +346,6 @@ var (
|
|||||||
return func(c *Configuration) {
|
return func(c *Configuration) {
|
||||||
c.CheckForUpdates = val
|
c.CheckForUpdates = val
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// CheckForUpdatesSync checks for updates before server starts, it will have a little delay depends on the machine's download's speed
|
// 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
|
// 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
|
// OptionDisableTemplateEngines set to true to disable loading the default template engine (html/template) and disallow the use of iris.UseEngine
|
||||||
// Default is false
|
// Default is false
|
||||||
OptionDisableTemplateEngines = func(val bool) OptionSet {
|
OptionDisableTemplateEngines = func(val bool) OptionSet {
|
||||||
@@ -340,6 +483,25 @@ const (
|
|||||||
DefaultDisablePathEscape = false
|
DefaultDisablePathEscape = false
|
||||||
DefaultCharset = "UTF-8"
|
DefaultCharset = "UTF-8"
|
||||||
DefaultLoggerPreffix = "[IRIS] "
|
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 (
|
var (
|
||||||
@@ -350,6 +512,13 @@ var (
|
|||||||
// DefaultConfiguration returns the default configuration for an Iris station, fills the main Configuration
|
// DefaultConfiguration returns the default configuration for an Iris station, fills the main Configuration
|
||||||
func DefaultConfiguration() Configuration {
|
func DefaultConfiguration() Configuration {
|
||||||
return Configuration{
|
return Configuration{
|
||||||
|
VHost: "",
|
||||||
|
VScheme: "",
|
||||||
|
MaxRequestBodySize: DefaultMaxRequestBodySize,
|
||||||
|
ReadBufferSize: DefaultReadBufferSize,
|
||||||
|
WriteBufferSize: DefaultWriteBufferSize,
|
||||||
|
MaxConnsPerIP: 0,
|
||||||
|
MaxRequestsPerConn: 0,
|
||||||
CheckForUpdates: false,
|
CheckForUpdates: false,
|
||||||
CheckForUpdatesSync: false,
|
CheckForUpdatesSync: false,
|
||||||
DisablePathCorrection: DefaultDisablePathCorrection,
|
DisablePathCorrection: DefaultDisablePathCorrection,
|
||||||
@@ -362,7 +531,6 @@ func DefaultConfiguration() Configuration {
|
|||||||
TimeFormat: DefaultTimeFormat,
|
TimeFormat: DefaultTimeFormat,
|
||||||
Charset: DefaultCharset,
|
Charset: DefaultCharset,
|
||||||
Gzip: false,
|
Gzip: false,
|
||||||
ProfilePath: "",
|
|
||||||
Sessions: DefaultSessionsConfiguration(),
|
Sessions: DefaultSessionsConfiguration(),
|
||||||
Websocket: DefaultWebsocketConfiguration(),
|
Websocket: DefaultWebsocketConfiguration(),
|
||||||
Tester: DefaultTesterConfiguration(),
|
Tester: DefaultTesterConfiguration(),
|
||||||
@@ -579,9 +747,6 @@ func DefaultWebsocketConfiguration() WebsocketConfiguration {
|
|||||||
|
|
||||||
// TesterConfiguration configuration used inside main config field 'Tester'
|
// TesterConfiguration configuration used inside main config field 'Tester'
|
||||||
type TesterConfiguration struct {
|
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
|
// ExplicitURL If true then the url (should) be prepended manually, useful when want to test subdomains
|
||||||
// Default is false
|
// Default is false
|
||||||
ExplicitURL bool
|
ExplicitURL bool
|
||||||
@@ -591,13 +756,6 @@ type TesterConfiguration struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
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
|
// OptionTesterExplicitURL If true then the url (should) be prepended manually, useful when want to test subdomains
|
||||||
// Default is false
|
// Default is false
|
||||||
OptionTesterExplicitURL = func(val bool) OptionSet {
|
OptionTesterExplicitURL = func(val bool) OptionSet {
|
||||||
@@ -615,367 +773,19 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// DefaultTesterConfiguration returns the default configuration for a tester
|
// DefaultTesterConfiguration returns the default configuration for a tester
|
||||||
// the ListeningAddr is used as virtual only when no running server is founded
|
|
||||||
func DefaultTesterConfiguration() TesterConfiguration {
|
func DefaultTesterConfiguration() TesterConfiguration {
|
||||||
return TesterConfiguration{ListeningAddr: "iris-go.com:1993", ExplicitURL: false, Debug: false}
|
return TesterConfiguration{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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default values for base Server conf
|
// Default values for base Server conf
|
||||||
const (
|
const (
|
||||||
// DefaultServerHostname returns the default hostname which is 0.0.0.0
|
// DefaultServerHostname returns the default hostname which is 0.0.0.0
|
||||||
DefaultServerHostname = "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
|
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 (
|
var (
|
||||||
// DefaultServerAddr the default server addr which is: 0.0.0.0:8080
|
// DefaultServerAddr the default server addr which is: 0.0.0.0:8080
|
||||||
DefaultServerAddr = DefaultServerHostname + ":" + strconv.Itoa(DefaultServerPort)
|
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"
|
cookiename := "MYSESSIONID"
|
||||||
charset := "MYCHARSET"
|
charset := "MYCHARSET"
|
||||||
dev := true
|
dev := true
|
||||||
profilePath := "/mypprof"
|
vhost := "mydomain.com"
|
||||||
// first session, after charset,dev and profilepath, no canonical order.
|
// 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 := DefaultConfiguration()
|
||||||
expected.Sessions.Cookie = cookiename
|
expected.Sessions.Cookie = cookiename
|
||||||
expected.Charset = charset
|
expected.Charset = charset
|
||||||
expected.IsDevelopment = dev
|
expected.IsDevelopment = dev
|
||||||
expected.ProfilePath = profilePath
|
expected.VHost = vhost
|
||||||
|
|
||||||
has := *api.Config
|
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)
|
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 {
|
func (ctx *Context) VirtualHostname() string {
|
||||||
realhost := ctx.HostString()
|
realhost := ctx.HostString()
|
||||||
hostname := realhost
|
hostname := realhost
|
||||||
virtualhost := ctx.framework.Servers.Main().Hostname()
|
virtualhost := ctx.framework.mux.hostname
|
||||||
|
|
||||||
if portIdx := strings.IndexByte(hostname, ':'); portIdx > 0 {
|
if portIdx := strings.IndexByte(hostname, ':'); portIdx > 0 {
|
||||||
hostname = hostname[0:portIdx]
|
hostname = hostname[0:portIdx]
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ func TestContextURLParams(t *testing.T) {
|
|||||||
// hoststring returns the full host, will return the HOST:IP
|
// hoststring returns the full host, will return the HOST:IP
|
||||||
func TestContextHostString(t *testing.T) {
|
func TestContextHostString(t *testing.T) {
|
||||||
initDefault()
|
initDefault()
|
||||||
Config.Tester.ListeningAddr = "localhost:8080"
|
Default.Config.VHost = "0.0.0.0:8080"
|
||||||
Get("/", func(ctx *Context) {
|
Get("/", func(ctx *Context) {
|
||||||
ctx.Write(ctx.HostString())
|
ctx.Write(ctx.HostString())
|
||||||
})
|
})
|
||||||
@@ -138,8 +138,8 @@ func TestContextHostString(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
e := Tester(t)
|
e := Tester(t)
|
||||||
e.GET("/").Expect().Status(StatusOK).Body().Equal(Config.Tester.ListeningAddr)
|
e.GET("/").Expect().Status(StatusOK).Body().Equal(Default.Config.VHost)
|
||||||
e.GET("/wrong").Expect().Body().NotEqual(Config.Tester.ListeningAddr)
|
e.GET("/wrong").Expect().Body().NotEqual(Default.Config.VHost)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VirtualHostname returns the hostname only,
|
// VirtualHostname returns the hostname only,
|
||||||
@@ -147,7 +147,7 @@ func TestContextHostString(t *testing.T) {
|
|||||||
func TestContextVirtualHostName(t *testing.T) {
|
func TestContextVirtualHostName(t *testing.T) {
|
||||||
initDefault()
|
initDefault()
|
||||||
vhost := "mycustomvirtualname.com"
|
vhost := "mycustomvirtualname.com"
|
||||||
Config.Tester.ListeningAddr = vhost + ":8080"
|
Default.Config.VHost = vhost + ":8080"
|
||||||
Get("/", func(ctx *Context) {
|
Get("/", func(ctx *Context) {
|
||||||
ctx.Write(ctx.VirtualHostname())
|
ctx.Write(ctx.VirtualHostname())
|
||||||
})
|
})
|
||||||
@@ -176,13 +176,15 @@ func TestContextFormValueString(t *testing.T) {
|
|||||||
|
|
||||||
func TestContextSubdomain(t *testing.T) {
|
func TestContextSubdomain(t *testing.T) {
|
||||||
initDefault()
|
initDefault()
|
||||||
Config.Tester.ListeningAddr = "mydomain.com:9999"
|
Default.Config.VHost = "mydomain.com:9999"
|
||||||
//Config.Tester.ExplicitURL = true
|
//Default.Config.Tester.ListeningAddr = "mydomain.com:9999"
|
||||||
|
// Default.Config.Tester.ExplicitURL = true
|
||||||
Party("mysubdomain.").Get("/mypath", func(ctx *Context) {
|
Party("mysubdomain.").Get("/mypath", func(ctx *Context) {
|
||||||
ctx.Write(ctx.Subdomain())
|
ctx.Write(ctx.Subdomain())
|
||||||
})
|
})
|
||||||
|
|
||||||
e := Tester(t)
|
e := Tester(t)
|
||||||
|
|
||||||
e.GET("/").WithURL("http://mysubdomain.mydomain.com:9999").Expect().Status(StatusNotFound)
|
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")
|
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
|
// request cookie should be empty
|
||||||
Get("/after_destroy", func(ctx *Context) {
|
Get("/after_destroy", func(ctx *Context) {
|
||||||
})
|
})
|
||||||
|
Default.Config.VHost = "mydomain.com"
|
||||||
e := Tester(t)
|
e := Tester(t)
|
||||||
|
|
||||||
e.POST("/set").WithJSON(values).Expect().Status(StatusOK).Cookies().NotEmpty()
|
e.POST("/set").WithJSON(values).Expect().Status(StatusOK).Cookies().NotEmpty()
|
||||||
|
|||||||
659
http.go
659
http.go
@@ -3,23 +3,20 @@ package iris
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/tls"
|
"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"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/pprof"
|
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"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 (
|
const (
|
||||||
@@ -229,370 +226,6 @@ func StatusText(code int) string {
|
|||||||
return statusText[code]
|
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)
|
// 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.'
|
// 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.")
|
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)
|
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 {
|
func ToHandler(handler interface{}) Handler {
|
||||||
//this is not the best way to do it, but I dont have any options right now.
|
//this is not the best way to do it, but I dont have any options right now.
|
||||||
switch handler.(type) {
|
switch handler.(type) {
|
||||||
@@ -677,44 +310,6 @@ func joinMiddleware(middleware1 Middleware, middleware2 Middleware) Middleware {
|
|||||||
return newMiddleware
|
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 (
|
const (
|
||||||
// parameterStartByte is very used on the node, it's just contains the byte for the ':' rune/char
|
// parameterStartByte is very used on the node, it's just contains the byte for the ':' rune/char
|
||||||
parameterStartByte = byte(':')
|
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
|
// 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()
|
requestHost := context.VirtualHostname()
|
||||||
if requestHost != mux.hostname {
|
if requestHost != mux.hostname {
|
||||||
|
//println(requestHost + " != " + mux.hostname)
|
||||||
// we have a subdomain
|
// we have a subdomain
|
||||||
if strings.Index(tree.subdomain, dynamicSubdomainIndicator) != -1 {
|
if strings.Index(tree.subdomain, dynamicSubdomainIndicator) != -1 {
|
||||||
} else {
|
} else {
|
||||||
|
//println(requestHost + " = " + mux.hostname)
|
||||||
// mux.host = iris-go.com:8080, the subdomain for example is api.,
|
// mux.host = iris-go.com:8080, the subdomain for example is api.,
|
||||||
// so the host must be api.iris-go.com:8080
|
// so the host must be api.iris-go.com:8080
|
||||||
if tree.subdomain+mux.hostname != requestHost {
|
if tree.subdomain+mux.hostname != requestHost {
|
||||||
@@ -1599,3 +1196,241 @@ func (mux *serveMux) BuildHandler() HandlerFunc {
|
|||||||
mux.fireError(StatusNotFound, context)
|
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 (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/valyala/fasthttp"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -18,129 +19,140 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
testTLSCert = `-----BEGIN CERTIFICATE-----
|
testTLSCert = `-----BEGIN CERTIFICATE-----
|
||||||
MIIDAzCCAeugAwIBAgIJAPDsxtKV4v3uMA0GCSqGSIb3DQEBBQUAMBgxFjAUBgNV
|
MIIDATCCAemgAwIBAgIJAPdE0ZyCKwVtMA0GCSqGSIb3DQEBBQUAMBcxFTATBgNV
|
||||||
BAMMDTEyNy4wLjAuMTo0NDMwHhcNMTYwNjI5MTMxMjU4WhcNMjYwNjI3MTMxMjU4
|
BAMMDG15ZG9tYWluLmNvbTAeFw0xNjA5MjQwNjU3MDVaFw0yNjA5MjIwNjU3MDVa
|
||||||
WjAYMRYwFAYDVQQDDA0xMjcuMC4wLjE6NDQzMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
MBcxFTATBgNVBAMMDG15ZG9tYWluLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||||
AQ8AMIIBCgKCAQEA0KtAOHKrcbLwWJXgRX7XSFyu4HHHpSty4bliv8ET4sLJpbZH
|
ADCCAQoCggEBAM9YJOV1Bl+NwEq8ZAcVU2YONBw5zGkUFJUZkL77XT0i1V473JTf
|
||||||
XeVX05Foex7PnrurDP6e+0H5TgqqcpQM17/ZlFcyKrJcHSCgV0ZDB3Sb8RLQSLns
|
GEpNZisDman+6n+pXarC2mR4T9PkCfmk072HaZ2LXwYe9XSgxnLJZJA1fJMzdMMC
|
||||||
8a+MOSbn1WZ7TkC7d/cWlKmasQRHQ2V/cWlGooyKNEPoGaEz8MbY0wn2spyIJwsB
|
2XveINF+/eeoyW9+8ZjQPbZdHWcxi7RomXg1AOMAG2UWMjalK5xkTHcqDuOI2LEe
|
||||||
dciERC6317VTXbiZdoD8QbAsT+tBvEHM2m2A7B7PQmHNehtyFNbSV5uZNodvv1uv
|
mezWHnFdBJNMTi3pNdbVr7BjexZTSGhx4LAIP2ufTUoVzk+Cvyr4IhS00zOiyyWv
|
||||||
ZTnDa6IqpjFLb1b2HNFgwmaVPmmkLuy1l9PN+o6/DUnXKKBrfPAx4JOlqTKEQpWs
|
tuJaO20Q0Q5n34o9vDAACKAfNRLBE8qzdRwsjMumXTX3hJzvgFp/4Lr5Hr2I2fBd
|
||||||
pnfacTE3sWkkmOSSFltAXfkXIJFKdS/hy5J/KQIDAQABo1AwTjAdBgNVHQ4EFgQU
|
tbIWN9xIsu6IibBGFItiAfQSrKAR7IFVqDUCAwEAAaNQME4wHQYDVR0OBBYEFNvN
|
||||||
zr1df/c9+NyTpmyiQO8g3a8NswYwHwYDVR0jBBgwFoAUzr1df/c9+NyTpmyiQO8g
|
Yik2eBRDmDaqoMaLfvr75kGfMB8GA1UdIwQYMBaAFNvNYik2eBRDmDaqoMaLfvr7
|
||||||
3a8NswYwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEACG5shtMSDgCd
|
5kGfMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAEAv3pKkmDTXIChB
|
||||||
MNjOF+YmD+PX3Wy9J9zehgaDJ1K1oDvBbQFl7EOJl8lRMWITSws22Wxwh8UXVibL
|
nVrbYwNibin9HYOPf3JCjU48V672YPgbfJM0WfTvLXNVBOdTz3aIUrhfwv/go2Jz
|
||||||
sscKBp14dR3e7DdbwCVIX/JyrJyOaCfy2nNBdf1B06jYFsIHvP3vtBAb9bPNOTBQ
|
yDcIFdLUdwllovhj1RwI96lbgCJ4AKoO/fvJ5Rxq+/vvLYB38PNl/fVEnOOeWzCQ
|
||||||
QE0Ztu9kCqgsmu0//sHuBEeA3d3E7wvDhlqRSxTLcLtgC1NSgkFvBw0JvwgpkX6s
|
qHfjckShNV5GzJPhfpYn9Gj6+Zj3O0cJXhF9L/FlbVxFhwPjPRbFDNTHYzgiHy82
|
||||||
M5WpSBZwZv8qpplxhFfqNy8Uf+xrpSW0pGfkHumehkQGC6/Ry7raganS0aHhDPK9
|
zhhDhTQJVnNJXfokdlg9OjfFkySqpv9fvPi/dfk5j1KmKUiYP5SYUhZiKX1JScvx
|
||||||
Z1bEJ2com1bFFAQsm9yIXrRVMGGCtihB2Au0Q4jpEjUbzWYM+ItZyvRAGRM6Qex6
|
JgesCwz1nUfVQ1TYE0dphU8mTCN4Y42i7bctx7iLcDRIFhtYstt0hhCKSxFmJSBG
|
||||||
s/jogMeRsw==
|
y9RITRA=
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
`
|
`
|
||||||
|
|
||||||
testTLSKey = `-----BEGIN RSA PRIVATE KEY-----
|
testTLSKey = `-----BEGIN RSA PRIVATE KEY-----
|
||||||
MIIEpQIBAAKCAQEA0KtAOHKrcbLwWJXgRX7XSFyu4HHHpSty4bliv8ET4sLJpbZH
|
MIIEpQIBAAKCAQEAz1gk5XUGX43ASrxkBxVTZg40HDnMaRQUlRmQvvtdPSLVXjvc
|
||||||
XeVX05Foex7PnrurDP6e+0H5TgqqcpQM17/ZlFcyKrJcHSCgV0ZDB3Sb8RLQSLns
|
lN8YSk1mKwOZqf7qf6ldqsLaZHhP0+QJ+aTTvYdpnYtfBh71dKDGcslkkDV8kzN0
|
||||||
8a+MOSbn1WZ7TkC7d/cWlKmasQRHQ2V/cWlGooyKNEPoGaEz8MbY0wn2spyIJwsB
|
wwLZe94g0X7956jJb37xmNA9tl0dZzGLtGiZeDUA4wAbZRYyNqUrnGRMdyoO44jY
|
||||||
dciERC6317VTXbiZdoD8QbAsT+tBvEHM2m2A7B7PQmHNehtyFNbSV5uZNodvv1uv
|
sR6Z7NYecV0Ek0xOLek11tWvsGN7FlNIaHHgsAg/a59NShXOT4K/KvgiFLTTM6LL
|
||||||
ZTnDa6IqpjFLb1b2HNFgwmaVPmmkLuy1l9PN+o6/DUnXKKBrfPAx4JOlqTKEQpWs
|
Ja+24lo7bRDRDmffij28MAAIoB81EsETyrN1HCyMy6ZdNfeEnO+AWn/guvkevYjZ
|
||||||
pnfacTE3sWkkmOSSFltAXfkXIJFKdS/hy5J/KQIDAQABAoIBAQDCd+bo9I0s8Fun
|
8F21shY33Eiy7oiJsEYUi2IB9BKsoBHsgVWoNQIDAQABAoIBABRhi67qY+f8nQw7
|
||||||
4z3Y5oYSDTZ5O/CY0O5GyXPrSzCSM4Cj7EWEj1mTdb9Ohv9tam7WNHHLrcd+4NfK
|
nHF9zSbY+pJTtB4YFTXav3mmZ7HcvLB4neQcUdzr4sETp4UoQ5Cs60IfySvbD626
|
||||||
4ok5hLVs1vqM6h6IksB7taKATz+Jo0PzkzrsXvMqzERhEBo4aoGMIv2rXIkrEdas
|
WqipZQ7aQq1zx7FoVaRTMW6TEUmDmG03v6BzpUEhwoQVQYwF8Vb+WW01+vr0CDHe
|
||||||
S+pCsp8+nAWtAeBMCn0Slu65d16vQxwgfod6YZfvMKbvfhOIOShl9ejQ+JxVZcMw
|
kub26S8BtsaZehfjqKfqcHD9Au8ri+Nwbu91iT4POVzBBBwYbtwXZwaYDR5PCNOI
|
||||||
Ti8sgvYmFUrdrEH3nCgptARwbx4QwlHGaw/cLGHdepfFsVaNQsEzc7m61fSO70m4
|
ld+6qLapVIVKpvLHL+tA4A/n0n4l7p8TJo/qYesFRZ7J+USt4YGFDuf15nnDge/7
|
||||||
NYJv48ZgjOooF5AccbEcQW9IxxikwNc+wpFYy5vDGzrBwS5zLZQFpoyMWFhtWdjx
|
9Qjyqa9WmvRGytPdgtEzc8XwJu7xhcRthSmCppdY0ExHBwVceCEz8u3QbRYFqq3U
|
||||||
hbmNn1jlAoGBAPs0ZjqsfDrH5ja4dQIdu5ErOccsmoHfMMBftMRqNG5neQXEmoLc
|
iLXUpfkCgYEA6JMlRtLIEAPkJZGBxJBSaeWVOeaAaMnLAdcu4OFjSuxr65HXsdhM
|
||||||
Uz8WeQ/QDf302aTua6E9iSjd7gglbFukVwMndQ1Q8Rwxz10jkXfiE32lFnqK0csx
|
aWHopCE44NjBROAg67qgc5vNBZvhnCwyTI8nb6k/CO5QZ4AG1d2Xe/9rPV5pdaBL
|
||||||
ltruU6hOeSGSJhtGWBuNrT93G2lmy23fSG6BqOzdU4rn/2GPXy5zaxM/AoGBANSm
|
gRgOJjlG0apZpPVM4I/0JU5prwS2Z71lFmEMikwmbmngYmOysqUBfbMCgYEA5Dpw
|
||||||
/E96RcBUiI6rDVqKhY+7M1yjLB41JrErL9a0Qfa6kYnaXMr84pOqVN11IjhNNTgl
|
qzn1Oq+fasSUjzUa/wvBTVMpVjnNrda7Hnlx6lssnQaPFqifFYL9Zr/+5rWdsE2O
|
||||||
g1lwxlpXZcZh7rYu9b7EEMdiWrJDQV7OxLDHopqUWkQ+3MHwqs6CxchyCq7kv9Df
|
NNCsy68tacspAUa0LQinzpeSP4dyTVCvZG/xWPaYDKE6FDmzsi8xHBTTxMneeU6p
|
||||||
IKqat7Me6Cyeo0MqcW+UMxlCRBxKQ9jqC7hDfZuXAoGBAJmyS8ImerP0TtS4M08i
|
HUKJMUD3LcvBiCLunhT2xd1/+LKzVce6ms9R3ncCgYEAv9wjdDmOMSgEnblbg/xL
|
||||||
JfsCOY21qqs/hbKOXCm42W+be56d1fOvHngBJf0YzRbO0sNo5Q14ew04DEWLsCq5
|
AHEUmZ89bzSI9Au/8GP+tWAz5zF47o2w+355nGyLr3EgfuEmR1C97KEqkOX3SA5t
|
||||||
+EsDv0hwd7VKfJd+BakV99ruQTyk5wutwaEeJK1bph12MD6L4aiqHJAyLeFldZ45
|
sBqoPcUw6v0t9zP2b5dN0Ez0+rtX5GFH6Ecf5Qh7E5ukOCDkOpyGnAADzw3kK9Bi
|
||||||
+TUzu8mA+XaJz+U/NXtUPvU9AoGBALtl9M+tdy6I0Fa50ujJTe5eEGNAwK5WNKTI
|
BAQrhCstyQguwvvb/uOAR2ECgYEA3nYcZrqaz7ZqVL8C88hW5S4HIKEkFNlJI97A
|
||||||
5D2XWNIvk/Yh4shXlux+nI8UnHV1RMMX++qkAYi3oE71GsKeG55jdk3fFQInVsJQ
|
DAdiw4ZVqUXAady5HFXPPL1+8FEtQLGIIPEazXuWb53I/WZ2r8LVFunlcylKgBRa
|
||||||
APGw3FDRD8M4ip62ki+u+tEr/tIlcAyHtWfjNKO7RuubWVDlZFXqCiXmSdOMdsH/
|
sjLvdMEBGqZ5H0fTYabgXrfqZ9JBmcrTyyKU6b6icTBAF7u9DbfvhpTObZN6fO2v
|
||||||
bxiREW49AoGACWev/eOzBoQJCRN6EvU2OV0s3b6f1QsPvcaH0zc6bgbBFOGmJU8v
|
dcEJ0ycCgYEAxM8nGR+pa16kZmW1QV62EN0ifrU7SOJHCOGApU0jvTz8D4GO2j+H
|
||||||
pXhD88tsu9exptLkGVoYZjR0n0QT/2Kkyu93jVDW/80P7VCz8DKYyAJDa4CVwZxO
|
MsoPSBrZ++UYgtGO/dK4aBV1JDdy8ZdyfE6UN+a6dQgdNdbOMT4XwWdS0zlZ/+F4
|
||||||
MlobQSunSDKx/CCJhWkbytCyh1bngAtwSAYLXavYIlJbAzx6FvtAIw4=
|
PKvbgZnLEKHvjODJ65aQmcTVUoaa11J29iAAtA3a3TcMn6C2fYpRy1s=
|
||||||
-----END RSA PRIVATE KEY-----
|
-----END RSA PRIVATE KEY-----
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestServerHost(t *testing.T) {
|
func TestParseAddr(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"
|
|
||||||
|
|
||||||
server1.Config.ListeningAddr = ServerParseAddr(server1.Config.ListeningAddr)
|
// test hosts
|
||||||
server2.Config.ListeningAddr = ServerParseAddr(server2.Config.ListeningAddr)
|
expectedHost1 := "mydomain.com:1993"
|
||||||
server3.Config.ListeningAddr = ServerParseAddr(server3.Config.ListeningAddr)
|
expectedHost2 := "mydomain.com"
|
||||||
|
expectedHost3 := DefaultServerHostname + ":9090"
|
||||||
|
expectedHost4 := "mydomain.com:443"
|
||||||
|
|
||||||
if server1.Host() != expectedHost1 {
|
host1 := ParseHost(expectedHost1)
|
||||||
t.Fatalf("Expecting server 1's host to be %s but we got %s", expectedHost1, server1.Host())
|
host2 := ParseHost(expectedHost2)
|
||||||
}
|
host3 := ParseHost(":9090")
|
||||||
if server2.Host() != expectedHost2 {
|
host4 := ParseHost(expectedHost4)
|
||||||
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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestServerHostname(t *testing.T) {
|
if host1 != expectedHost1 {
|
||||||
var server Server
|
t.Fatalf("Expecting server 1's host to be %s but we got %s", expectedHost1, host1)
|
||||||
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 host2 != expectedHost2 {
|
||||||
|
t.Fatalf("Expecting server 2's host to be %s but we got %s", expectedHost2, host2)
|
||||||
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 server2.FullHost() != server2ExpectingFullhost {
|
if host3 != expectedHost3 {
|
||||||
t.Fatalf("Expecting server 2's fullhost to be %s but got %s", server2ExpectingFullhost, server2.FullHost())
|
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) {
|
hostname1 := ParseHostname(host1)
|
||||||
var server1, server2 Server
|
hostname2 := ParseHostname(host2)
|
||||||
expectedPort1 := 8080
|
hostname3 := ParseHostname(host3)
|
||||||
expectedPort2 := 80
|
hostname4 := ParseHostname(host4)
|
||||||
server1.Config.ListeningAddr = "mydomain.com:8080"
|
if hostname1 != expectedHostname1 {
|
||||||
server2.Config.ListeningAddr = "mydomain.com"
|
t.Fatalf("Expecting server 1's hostname to be %s but we got %s", expectedHostname1, hostname1)
|
||||||
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())
|
|
||||||
}
|
}
|
||||||
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
|
// Contains the server test for multi running servers
|
||||||
func TestMultiRunningServers_v1(t *testing.T) {
|
func TestMultiRunningServers_v1_PROXY(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)
|
defer Close()
|
||||||
|
host := "mydomain.com" // you have to add it to your hosts file( for windows, as 127.0.0.1 mydomain.com)
|
||||||
initDefault()
|
initDefault()
|
||||||
Config.DisableBanner = true
|
Default.Config.DisableBanner = true
|
||||||
// create the key and cert files on the fly, and delete them when this test finished
|
// create the key and cert files on the fly, and delete them when this test finished
|
||||||
certFile, ferr := ioutil.TempFile("", "cert")
|
certFile, ferr := ioutil.TempFile("", "cert")
|
||||||
|
|
||||||
@@ -153,9 +165,6 @@ func TestMultiRunningServers_v1(t *testing.T) {
|
|||||||
t.Fatal(ferr.Error())
|
t.Fatal(ferr.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
certFile.WriteString(testTLSCert)
|
|
||||||
keyFile.WriteString(testTLSKey)
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
certFile.Close()
|
certFile.Close()
|
||||||
time.Sleep(350 * time.Millisecond)
|
time.Sleep(350 * time.Millisecond)
|
||||||
@@ -166,33 +175,37 @@ func TestMultiRunningServers_v1(t *testing.T) {
|
|||||||
os.Remove(keyFile.Name())
|
os.Remove(keyFile.Name())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
certFile.WriteString(testTLSCert)
|
||||||
|
keyFile.WriteString(testTLSKey)
|
||||||
|
|
||||||
Get("/", func(ctx *Context) {
|
Get("/", func(ctx *Context) {
|
||||||
ctx.Write("Hello from %s", ctx.HostString())
|
ctx.Write("Hello from %s", ctx.HostString())
|
||||||
})
|
})
|
||||||
|
|
||||||
// start the secondary server
|
go ListenTLS(host+":443", certFile.Name(), keyFile.Name())
|
||||||
AddServer(ServerConfiguration{ListeningAddr: "mydomain.com:80", RedirectTo: "https://" + host, Virtual: true})
|
if ok := <-Default.Available; !ok {
|
||||||
// start the main server
|
|
||||||
go ListenTo(ServerConfiguration{ListeningAddr: host, CertFile: certFile.Name(), KeyFile: keyFile.Name(), Virtual: true})
|
|
||||||
// prepare test framework
|
|
||||||
if ok := <-Available; !ok {
|
|
||||||
t.Fatal("Unexpected error: server cannot start, please report this as bug!!")
|
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 := 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)
|
e.Request("GET", "https://"+host).Expect().Status(StatusOK).Body().Equal("Hello from " + host)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Contains the server test for multi running servers
|
// Contains the server test for multi running servers
|
||||||
func TestMultiRunningServers_v2(t *testing.T) {
|
func TestMultiRunningServers_v2(t *testing.T) {
|
||||||
|
defer Close()
|
||||||
domain := "mydomain.com"
|
domain := "mydomain.com"
|
||||||
host := domain + ":443"
|
|
||||||
initDefault()
|
initDefault()
|
||||||
Config.DisableBanner = true
|
Default.Config.DisableBanner = true
|
||||||
Config.Tester.ListeningAddr = host
|
|
||||||
// create the key and cert files on the fly, and delete them when this test finished
|
// create the key and cert files on the fly, and delete them when this test finished
|
||||||
certFile, ferr := ioutil.TempFile("", "cert")
|
certFile, ferr := ioutil.TempFile("", "cert")
|
||||||
|
|
||||||
@@ -219,25 +232,35 @@ func TestMultiRunningServers_v2(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
Get("/", func(ctx *Context) {
|
Get("/", func(ctx *Context) {
|
||||||
ctx.Write("Hello from %s", ctx.HostString())
|
ctx.Write("Hello from %s", string(ctx.HostString()))
|
||||||
})
|
})
|
||||||
|
|
||||||
// add a secondary server
|
// 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
|
// 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 {
|
if ok := <-Available; !ok {
|
||||||
t.Fatal("Unexpected error: server cannot start, please report this as bug!!")
|
t.Fatal("Unexpected error: server cannot start, please report this as bug!!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Default.Config.Tester.ExplicitURL = true
|
||||||
e := Tester(t)
|
e := Tester(t)
|
||||||
|
|
||||||
e.Request("GET", "http://"+domain+":80").Expect().Status(StatusOK).Body().Equal("Hello from " + host)
|
e.Request("GET", "http://"+domain).Expect().Status(StatusOK).Body().Equal("Hello from " + domain)
|
||||||
e.Request("GET", "https://"+host).Expect().Status(StatusOK).Body().Equal("Hello from " + host)
|
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 {
|
func testSubdomainHost() string {
|
||||||
s := testSubdomain + "." + Servers.Main().Host()
|
s := testSubdomain + "." + Default.Config.VHost
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSubdomainURL() (subdomainURL string) {
|
func testSubdomainURL() string {
|
||||||
subdomainHost := testSubdomainHost()
|
subdomainHost := testSubdomainHost()
|
||||||
if Servers.Main().IsSecure() {
|
return Default.Config.VScheme + subdomainHost
|
||||||
subdomainURL = "https://" + subdomainHost
|
|
||||||
} else {
|
|
||||||
subdomainURL = "http://" + subdomainHost
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func subdomainTester(e *httpexpect.Expect) *httpexpect.Expect {
|
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/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"}}},
|
{"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()
|
initDefault()
|
||||||
|
|
||||||
for idx := range testRoutes {
|
for idx := range testRoutes {
|
||||||
@@ -360,7 +378,6 @@ func TestMuxSimple(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMuxSimpleParty(t *testing.T) {
|
func TestMuxSimpleParty(t *testing.T) {
|
||||||
|
|
||||||
initDefault()
|
initDefault()
|
||||||
|
|
||||||
h := func(c *Context) { c.WriteString(c.HostString() + c.PathString()) }
|
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)
|
p.Get("/namedpath/:param1/something/:param2/else", h)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Default.Config.VHost = "0.0.0.0:8080"
|
||||||
e := Tester(t)
|
e := Tester(t)
|
||||||
|
|
||||||
request := func(reqPath string) {
|
request := func(reqPath string) {
|
||||||
e.Request("GET", reqPath).
|
e.Request("GET", reqPath).
|
||||||
Expect().
|
Expect().
|
||||||
Status(StatusOK).Body().Equal(Servers.Main().Host() + reqPath)
|
Status(StatusOK).Body().Equal(Default.Config.VHost + reqPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// run the tests
|
// run the tests
|
||||||
|
|||||||
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() {
|
func ExamplePlugins_Add() {
|
||||||
initDefault()
|
initDefault()
|
||||||
|
Default.Set(OptionDisableBanner(true))
|
||||||
Plugins.Add(PreListenFunc(func(*Framework) {
|
Plugins.Add(PreListenFunc(func(*Framework) {
|
||||||
fmt.Println("PreListen Func")
|
fmt.Println("PreListen Func")
|
||||||
}))
|
}))
|
||||||
@@ -72,9 +73,11 @@ func ExamplePlugins_Add() {
|
|||||||
Plugins.Add(myplugin)
|
Plugins.Add(myplugin)
|
||||||
desc := Plugins.GetDescription(myplugin)
|
desc := Plugins.GetDescription(myplugin)
|
||||||
fmt.Println(desc)
|
fmt.Println(desc)
|
||||||
|
go Listen(":8080")
|
||||||
|
|
||||||
ListenVirtual()
|
if ok := <-Available; ok {
|
||||||
Close()
|
Close()
|
||||||
|
}
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// GetName Struct
|
// GetName Struct
|
||||||
|
|||||||
47
ssh.go
47
ssh.go
@@ -102,7 +102,7 @@ func (s *SSHServer) bindTo(station *Framework) {
|
|||||||
|
|
||||||
sshCommands := Commands{
|
sshCommands := Commands{
|
||||||
Command{Name: "status", Description: "Prompts the status of the HTTP Server, is listening(started) or not(stopped).", Action: func(conn ssh.Channel) {
|
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)
|
statusRunningMsg(conn)
|
||||||
} else {
|
} else {
|
||||||
statusNotRunningMsg(conn)
|
statusNotRunningMsg(conn)
|
||||||
@@ -115,29 +115,26 @@ func (s *SSHServer) bindTo(station *Framework) {
|
|||||||
// Note for stop If you have opened a tab with Q route:
|
// 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)
|
// 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) {
|
Command{Name: "stop", Description: "Stops the HTTP Server.", Action: func(conn ssh.Channel) {
|
||||||
srv := station.Servers.Main()
|
if station.IsRunning() {
|
||||||
if srv != nil && srv.IsListening() {
|
station.Close()
|
||||||
srv.Close()
|
//srv.listener = nil used to reopen so let it setted
|
||||||
srv.listener = nil
|
|
||||||
serverStoppedMsg(conn)
|
serverStoppedMsg(conn)
|
||||||
} else {
|
} else {
|
||||||
errServerNotReadyMsg(conn)
|
errServerNotReadyMsg(conn)
|
||||||
}
|
}
|
||||||
}},
|
}},
|
||||||
Command{Name: "start", Description: "Starts the HTTP Server.", Action: func(conn ssh.Channel) {
|
Command{Name: "start", Description: "Starts the HTTP Server.", Action: func(conn ssh.Channel) {
|
||||||
srv := station.Servers.Main()
|
if !station.IsRunning() {
|
||||||
if !srv.IsListening() {
|
go station.Reserve()
|
||||||
go srv.Open(srv.Handler)
|
|
||||||
}
|
}
|
||||||
serverStartedMsg(conn)
|
serverStartedMsg(conn)
|
||||||
}},
|
}},
|
||||||
Command{Name: "restart", Description: "Restarts the HTTP Server.", Action: func(conn ssh.Channel) {
|
Command{Name: "restart", Description: "Restarts the HTTP Server.", Action: func(conn ssh.Channel) {
|
||||||
srv := station.Servers.Main()
|
if station.IsRunning() {
|
||||||
if srv != nil && srv.IsListening() {
|
station.Close()
|
||||||
srv.Close()
|
//srv.listener = nil used to reopen so let it setted
|
||||||
srv.listener = nil
|
|
||||||
}
|
}
|
||||||
go srv.Open(srv.Handler)
|
go station.Reserve()
|
||||||
serverRestartedMsg(conn)
|
serverRestartedMsg(conn)
|
||||||
}},
|
}},
|
||||||
/* not ready yet
|
/* 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
|
// parsePortSSH receives an addr of form host[:port] and returns the port part of it
|
||||||
// ex: localhost:8080 will return the `localhost`, mydomain.com:22 will return the 'mydomain'
|
// ex: localhost:22 will return the `22`, mydomain.com will return the '22'
|
||||||
func parseHostname(addr string) string {
|
func parsePortSSH(addr string) int {
|
||||||
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 {
|
|
||||||
if portIdx := strings.IndexByte(addr, ':'); portIdx != -1 {
|
if portIdx := strings.IndexByte(addr, ':'); portIdx != -1 {
|
||||||
afP := addr[portIdx+1:]
|
afP := addr[portIdx+1:]
|
||||||
p, err := strconv.Atoi(afP)
|
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)"}}
|
Command{Name: "exit", Description: "Exits from the terminal (if interactive shell)"}}
|
||||||
|
|
||||||
func (s *SSHServer) writeHelp(wr io.Writer) {
|
func (s *SSHServer) writeHelp(wr io.Writer) {
|
||||||
port := parsePort(s.Host)
|
port := parsePortSSH(s.Host)
|
||||||
hostname := parseHostname(s.Host)
|
hostname := ParseHostname(s.Host)
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
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
|
// 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