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