pax_global_header00006660000000000000000000000064136547167670014540gustar00rootroot0000000000000052 comment=3fca063f620fcab968367d7bef38655eff50bbf3 tntnet-3.0/000077500000000000000000000000001365471676700127165ustar00rootroot00000000000000tntnet-3.0/.gitignore000066400000000000000000000013451365471676700147110ustar00rootroot00000000000000# Files generated by autoconf, automake and libtool /INSTALL /aclocal.m4 /autom4te.cache /compile /config.guess /config.sub /configure /depcomp /install-sh /ltmain.sh /missing /m4/*.m4 !/m4/acx_pthread.m4 !/m4/ax_check_compile_flag.m4 !/m4/ax_compiler_vendor.m4 !/m4/pkg.m4 !/m4/ax_cxx_compile_stdcxx_11.m4 /framework/common/config.h.in .deps .libs Makefile.in Makefile config.log config.status libtool stamp-h1 # Files generated or compiled in the build process **/framework/common/config.h **/framework/runtime/tntnet **/misc/tntnet-config **/misc/tntnet-project **/sdk/tools/ecppc/ecppc **/sdk/tools/ecppl/ecppl **/sdk/tools/ecppll/ecppll **/etc/tntnet/tntnet.xml **/test/tntnet-test *.l[ao] *.o *.pc *.swp # Other .dirstamp *~ tntnet-3.0/AUTHORS000066400000000000000000000001061365471676700137630ustar00rootroot00000000000000Tommi Mäkitalo Jonas Platte tntnet-3.0/COPYING000066400000000000000000000576351365471676700137710ustar00rootroot00000000000000Copyright and license ===================== Copyright (C) 2003-2006 Tommi Maekitalo GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS tntnet-3.0/ChangeLog000066400000000000000000001706531365471676700145040ustar00rootroot000000000000002015-07-26 Tommi Mäkitalo - do not use libtool in project templates for standalone applications 2015-07-20 Tommi Mäkitalo - fix syntax error in configure.ac some version of autoconf generated a invalid configure script. Indeed it was wrong in configure.ac. 2015-07-15 Tommi Mäkitalo - add a generated file to .gitignore - fix handling scope when default value was set - fix wrong unit tests 2015-05-25 Tommi Mäkitalo - add js file per page to mvc template - new standard component empty@tntnet, which sends an empty result 2015-05-19 Tommi Mäkitalo - change mvc template: call controller also for dynamic pages, which are not routed through webmain - fix wrong comment in index page of mvc standalone template 2015-05-18 Tommi Mäkitalo - add a default http return code to components. The default http return code is by default 200 HTTP_OK but may be configured per mapping. The special value DECLINED instructs tntnet to continue with the next mapping. The ecpp compiler generates now a return code DEFAULT, which instructs tntnet to fall back to that dfeault http return code. The mvc templates use that feature so that it is not more necessary to return DECLINED in controllers but just fall throug the end of the component. 2015-04-12 Tommi Mäkitalo - remove some private headers from installation - impl tnt::Tntnet 2015-04-11 Tommi Mäkitalo - fix setting access log file using the method tnt::Tntnet::setAccessLog 2015-04-05 Tommi Mäkitalo - add some more documentation to project templates - use cxxtools::LogConfiguration to initialize logging 2015-03-16 Tommi Mäkitalo - check for sed in configure - it is used in tntnet-project 2015-03-21 Tommi Mäkitalo - remove irritating comment from tntnet.xml - remove <%application> scope from project templates since it should really be avoided, so we do not suggest it to use 2015-03-16 Tommi Mäkitalo - minor changes after running cppcheck 2015-03-15 Tommi Mäkitalo - fix generation of dependencies in ecppc: do not just use basename but full file path of target - change project templates to use new default file scope in models - add new file scope as default scope to ecpp - fix ecpp parser: <<$ is now parsed correctly - do not install internal header files from defcomp and add new defcomp "setheader" 2015-03-01 Tommi Mäkitalo - remove some internal classes from api documentation 2015-02-27 Tommi Mäkitalo - add examples for tntdb dburl in project template 2015-02-09 Tommi Mäkitalo - Update quick-start-guide.markdown 2015-02-06 Tommi Mäkitalo - remove unused include from project templates 2015-02-05 Joan - Update applicationunlocker.h 2015-02-02 Tommi Mäkitalo - generalize mapping in mvc template projects - fix g++ linker errors with tntnet-project 2015-02-01 Tommi Mäkitalo - improve project template: add some layout and instructions, how to proceed - improve project templates: add compile flags for C++11 when available and use xml configuration in mvc-standalone 2015-01-31 Tommi Mäkitalo - fix Makefile.am (README in mvc-standalone template is README.md) 2015-01-30 Tommi Mäkitalo - make definition of port in listener mandatory instead of taking 80 (or 443 for ssl) as default allow definition of one listener at top level of configuration file - Update Makefile.am - Update Makefile.am - Update Makefile.am - Update Makefile.am - Update Makefile.am - fix linker command 2015-01-26 Tommi Mäkitalo - improve mvc-standalone project template 2015-01-25 Tommi Mäkitalo - improve mvc templates of tntnet-project - remove useless flag DEFER_ACCEPT passed to accept method of ssl socket 2015-01-24 Tommi Mäkitalo - remove old remaining fragments of stressjob - the stressjob was removed already long ago 2015-01-23 Tommi Mäkitalo - new howto for chunked encoding 2015-01-22 Tommi Mäkitalo - make socketoption SO_REUSEADDR configurable; default is to set the option - minor change: get http error text automatically 2015-01-10 Tommi Mäkitalo - add --config flag to tntnet-project to generate a tntnet.xml template and replace tntnet-config with tntnet-project for that in the demo applications 2015-01-09 Tommi Mäkitalo - minor cleanup in unit test for component 2015-01-04 Tommi Mäkitalo - add some unit tests for component processing and fix cmd interface after finding bugs with those tests 2014-12-29 Tommi Mäkitalo - Update ecppc.1.markdown - Update quick-start-guide.markdown Add: - terminal promt for terminal instruction - tab size from 1 to 4, for better reading ecpp (html) code - Update ecppc.1.markdown Typo fixes 2014-12-28 Tommi Mäkitalo - Update ecppl.1.markdown - Update ecppl.1.markdown Add: - help and version usage - Update ecppc.1.markdown Add: - help and version option usage - Update quick-start-guide.markdown 2014-11-22 Jonas Platte - Fixed an include path issue introduced when adding -h / --help to ecppc and ecppl - Added -h / --help to tntnet-project, improved error handling 2014-11-13 Jonas Platte - Updated wrong argument and help option handling in ecppc, removed Usage exception class (from ecppc.h), added myself to the AUTHORS file 2014-12-28 Tommi Mäkitalo - merged changes from jplatte 2014-11-11 Jonas Platte - Added version and help flags to ecppc, minor readabilty changes 2014-11-09 Jonas Platte - Added -V, -h and --help options to ecppl 2014-12-28 Tommi Mäkitalo - Update quick-start-guide.markdown - install instruction before install from tarball, this are similar with the FAQ 1.9. 2014-12-27 Ralf Schülke - Update quick-start-guide.markdown Small typo fix and add a autotools mini howto link. 2014-12-26 Tommi Mäkitalo - remove old documents, logos and tntnet-config 2014-12-25 Tommi Mäkitalo - change generation of component name and output file name in ecpp compiler ecppc: remove just .ecpp extension and keep others, so that e.g. tntnet.jpg results in a component name "tntnet.jpg" and output file name "tntnet.jpg.cpp". - add tntnet logo 2014-12-22 Tommi Mäkitalo - update copyright header - update gitignore - update README file - fix project templates: add static sources in dist package - cleanup demos - minor improvement in project templates (use srcdir instead of top_srcdir to find sources) - fix out of tree build of new chat demo 2014-12-21 Tommi Mäkitalo - replace chat and rajax-jquery demos with a better chat demo with long poll 2014-12-14 Tommi Mäkitalo - fix bug in chunked encoding; output to reply.sout() must be routed through chunked encoder 2014-12-10 Tommi Mäkitalo - fixes for compression 2014-12-05 Tommi Mäkitalo - install demos again into pkg dir since disabling that prevents automake to create .so-files - very strange - some fixes for chunked output stream in http reply - compression might work now but not yet tested 2014-12-04 Tommi Mäkitalo - use opitimized ostream to collect output data instead of std::ostringstream - update autoconf macro to check for C++-11 (makes C++-11 flag optional) - remove generated file 2014-11-17 Tommi Mäkitalo - undeprecate "global" scope and improve some error messages in ecpp parser 2014-11-15 Tommi Mäkitalo - do not install demo applications on make install - read values optionally from xml attributes in tntnet.xml when cxxtools supports it (cxxtools version >=2.3) 2014-11-09 Tommi Mäkitalo - move definition of TcpJob and SslTcpJob from job.cpp into separate source file - remove useless condition which leads to a compiler warning about uninitialized variable in openssl.cpp 2014-11-04 Tommi Mäkitalo - use autoconf variables instead of directly call mkdir -p and sed in Makeile.am 2014-11-02 Jonas Platte - Added pkg-config support - Updated .gitignore - Added $(AM_V_GEN) for tntnet.xml generation in /etc 2014-11-04 Tommi Mäkitalo - remove optional extension in url from default mapping 2014-11-03 Tommi Mäkitalo - update gitignore - move mapping of resources to top in project templates 2014-11-01 Tommi Mäkitalo - update ChangeLog - remove generated file tntnet-project - update gitignore - fix project templates: add mapping to resources, allow - in project name 2014-10-31 Tommi Mäkitalo - add static resources to all tntnet-project templates and other small fixes in those 2014-10-28 Tommi Mäkitalo - discard previous http reply on execute if not fully read in http client 2014-10-19 Tommi Mäkitalo - fix handling of ranges in static@tntnet when using sendfile 2014-10-17 Tommi Mäkitalo - update http redirect code, use 307 instead of 302 for temporary redirects 2014-10-08 Tommi Mäkitalo - use c++ 11 mode of compiler if supported for better optimization 2014-10-08 Tommi Mäkitalo - do not log content size when chunked encoding is used since it is not really known 2014-09-12 Tommi Mäkitalo - forward flush of chunked output stream buffer to underlying stream buffer after writing chunk 2014-08-26 Tommi Mäkitalo - fix configuring tntnet using a own TntConfig object - fix compiler warning in openssl.cpp 2014-04-15 Jonas Platte - Last big style update: fixed all warnings from gcc with -Wall -Wextra (without building demos, with ssl=openssl) 2014-04-14 Jonas Platte - Some style updates: Added explicitly "private:" to classes where it was missing, Corrected indentation and line breaks, Updated private member variable names (more to come) - Unified blank lines in source files - Added missing TNT_ prefix for include guard macros - Small style and doc update for Component - Removed duplicate libtool entry in .gitignore 2014-04-08 Jonas Platte - Added some documentation to HttpRequest 2014-08-01 Tommi Mäkitalo - change in ecppc: use typedefs for scoped variables only when really needed (when typename contains a comma) 2014-07-23 Tommi Mäkitalo - small optimization when setting date header 2014-06-29 Tommi Mäkitalo - add content size of previous components to content length header in static@tntnet 2014-06-09 Tommi Mäkitalo - create projects using templates in tntnet-project 2014-06-03 Tommi Mäkitalo - add emulation for old pushArg method for positional parameters in mappings - revert component variable definition due to problems with types with commas (like std::map) 2014-05-30 Tommi Mäkitalo - fix syntax error in tnt/sessionunlocker.h (looks like nobody use it) 2014-05-29 Tommi Mäkitalo - build fix: according to the standard std::ostream do not have a default constructor (but in gcc) 2014-05-02 Tommi Mäkitalo - do not report a warning when a empty file is send on systems without sendfile 2014-04-07 Tommi Mäkitalo - fix generating projects with special characters in tntnet-project 2014-04-06 Jonas Platte - Added $(AM_V_GEN) to alldemos, tntnet-project 2014-04-06 Tommi Mäkitalo - fix unittest for scopes and add scope tests 2014-04-05 Jonas Platte - Fixed build + some small improvements for the demos 2014-04-04 Ralf Schülke - Update quick-start-guide.markdown 2014-04-04 Tommi Mäkitalo - fix build on systems without epoll (build was broken since style revision) - tntnet-wizzard was renamed to tntnet-project - do so also in Makefile.am 2014-04-03 Jonas Platte - Little fix for non-working references - Added missing "@endcond internal" doxygen label 2014-04-02 Tommi Mäkitalo - rename tntnet-wizzard to tntnet-project - make out of tree build working in tntnet-wizzard generated projects 2014-03-31 Jonas Platte - Various small doc and style updates - Another documentation revision for TntConfig - Small fixes in Tntnet documentation 2014-03-30 Jonas Platte - Cleaned up the source tree a bit 2014-03-30 Tommi Mäkitalo - set cache-control header only when not already set by user - fix licence header from GPL to LGPL 2014-03-30 Tommi Mäkitalo - set cache control header just once 2014-03-20 Jonas Platte - A little last style update in cookie.h - Style revisions 2014-03-18 Tommi Mäkitalo - integrate newsdb demo into build of demos 2014-03-18 Tommi Mäkitalo - do not use C++ style comments in C source - improve mvc demo including adding documentation - improve mvc demo including adding documentation - add gd demo application to demonstrate how to create dynamic graphics using the famous gd library 2014-03-18 Jonas Platte - Further style revision 2014-03-17 Tommi Mäkitalo - update unzip stuff - fix memory leak when reading configuration files - fix invalid use of return code in SSL_shutdown 2014-03-17 Jonas Platte - Style revision for everything from applicationunlocker to dispatcher {.h|.cpp} 2014-03-16 Tommi Mäkitalo - move and rename directory sdk/demos to demo - use configure flag --enable/--disable for server, sdk and demos and disable building demos by default 2014-03-15 Tommi Mäkitalo - add unused switch-cases back to reduce compiler warnings 2014-03-15 Jonas Platte - Fixed Mime class not overwriting virtual function configure from its base class Component, removed .dirstamp files 2014-03-14 Jonas Platte - Added null initialization for member pointers that previously were not initialized on object construction 2014-03-11 Jonas Platte - Some minor bugfixes - Removed dead and unused code - Little documentation update 2014-03-10 Jonas Platte - Reverted style changes 2014-03-09 Jonas Platte - Style revision on HttpMessage and HttpReply, partial style revision on HttpRequest, partial documentation revision on all three - Completed style and documentation revision of Compident, Maptarget and Tntnet, added a new mapUrl overload and deprecated old ones including vMapUrl 2014-03-01 Jonas Platte - Revised code style and documentation for Compident 2014-02-21 Tommi Mäkitalo - fix handling scoped variables - scope was forgot when variables were initialized 2014-02-19 Tommi Mäkitalo - make type conversion explicit to reduce compiler warnings 2014-02-19 Jonas Platte - Started documentation revision on httpmessage.h, httpreply.h and httprequest.h; some minor changes in the documentation of tntnet.h 2014-02-18 Tommi Mäkitalo - check in generated man page of ecpp with documentaion of <%attr> included - add documentation about <%attr> tag - Fixed building in a subdirectory 2014-02-10 Tommi Mäkitalo - fix some doxygen comments 2014-02-08 Tommi Mäkitalo - better error message in ecpp parser on unexpected end of file - fix doxygen comment of listen method in tnt::Tntnet - allow one line c++ section (% at start of line) to be closed with eof 2014-02-05 Tommi Mäkitalo - add missing include in gnutls.cpp 2014-02-04 Tommi Mäkitalo - fix formatting in tntnet-wizzard 2014-02-03 Tommi Mäkitalo - make <%config> working again - was broken for quite some time 2014-02-01 Tommi Mäkitalo - remove one directory level in generated projects of tntnet-wizzard to simplify project structure 2014-01-29 Tommi Mäkitalo - implement chunked encoding transfer mode 2014-01-22 Tommi Mäkitalo - add new jquery with tntnet howto 2014-01-21 Tommi Mäkitalo - update doxygen documentation in tnt::TntConfig - remove background worker feature - it was never used I guess 2014-01-20 Tommi Mäkitalo - update version number and abi version (must be higher than version 2.2 and 2.2.1) 2014-01-05 Tommi Mäkitalo - change default user of tntnet to tntnet - remove init script from tntnet - the packager has to write it depending on the distribution 2014-01-04 Jonas Platte - Started documenting TntConfig, flagged some classes internal 2013-12-26 Tommi Mäkitalo - fix changing root dir of tntnet 2013-12-25 Tommi Mäkitalo - add missing linkflag -lz to ecppc 2013-12-22 Jonas Platte - Reformatted multiline doc comments in tntnet.h 2013-12-21 Jonas Platte - Revised documentation in tnt/tntnet.h (still some bits missing) 2013-12-19 Tommi Mäkitalo - add some sanity checks for urls in static component 2013-12-11 Tommi Mäkitalo - fix possible information leak 2013-11-29 Tommi Mäkitalo - update installation hints 2013-11-10 Tommi Mäkitalo - update tntnet-wizzard (move source to src subdirectory and other changes) - replace configure.in with configure.ac in tntnet-config generated autoproject - fix some minor stuff in quick start guide 2013-11-06 Tommi Mäkitalo - fix typo in quick start guide 2013-11-05 Tommi Mäkitalo - fix forward declaration of struct TntConfig (produced a compiler warning) 2013-10-31 Tommi Mäkitalo - use memmove instead of memcpy when removing message header since the areas may overlap 2013-10-11 Tommi Mäkitalo - add --version switch to all tntnet tools 2013-10-03 Tommi Mäkitalo - autoscan.sh is obsolete - use "autoreconf -i" instead 2013-09-22 Tommi Mäkitalo - the tnt::Job do not need to be atomic ref counted; making it simple ref counted speeds up tntnet for about 1% - add doctype to tntnet-config template - fix escape sequence and add doctype to template in tntnet wizzard - fix racing condition: releasing request may result in a pthread unlock error 2013-09-20 Tommi Mäkitalo - fix syntax error in wizzard 2013-09-07 Tommi Mäkitalo - do not try to write access log when it is disabled - do not call SSL_shutdown twice when the first call completed the shutdown already 2013-08-25 Tommi Mäkitalo - empty setting for server will omit server header 2013-08-23 Tommi Mäkitalo - make server response header configurable - fix setting http header without trailing colon 2013-08-21 Tommi Mäkitalo - do not accept %00 in url since it is not processed correctly anyway 2013-08-16 Tommi Mäkitalo - fix url encoding (%xx accepted every alphanumeric character instead of just hex digits) 2013-08-05 Tommi Mäkitalo - tntnet has a new logo 2013-08-04 Tommi Mäkitalo - make dburl configuration parameter optional in mvc project of tntnet-wizzard - tntnet-wizzard can now create a simple project in addition to a mvc project - add check for autoconf and automake to tntnet-wizzard - add upload howto from homepage to documentation 2013-08-03 Tommi Mäkitalo - fix setting include directory in tntnet-wizzard 2013-07-29 Tommi Mäkitalo - add tntnet-wizzard to dist package and fix dist target in the generated project - create tntnet-wizzard, which creates web applications with the mvc pattern 2013-07-28 Tommi Mäkitalo - fix another bug in ecpp parser where scope could be set only once per page 2013-07-26 Tommi Mäkitalo - fix ecpp parser: scope could be set only once per page 2013-07-22 Tommi Mäkitalo - repalce deprecated GLOBAL with SHARED in calcmvc demo application 2013-07-20 Tommi Mäkitalo - rename scope="global" to scope="shared" 2013-07-10 Tommi Mäkitalo - disable static build by default and other small cleanups in the build system 2013-07-09 Tommi Mäkitalo - update build; autoconf wants configure.ac instead of configure.in - simplify reading listeners from configuration 2013-07-06 Tommi Mäkitalo - remove StressJob class - it was for load testing but not used any more - fix vim syntax highlighting for ecpp: allow scope definition to spread multiple lines 2013-06-21 Tommi Mäkitalo - set max age of files in multi binary components to 4 hours and allow it to be modified using maxAge arg 2013-06-20 Tommi Mäkitalo - no need to check url in static@tntnet since it is already done before - fix handling of documentRoot and change MaxAge setting to maxAge for consistency 2013-06-19 Tommi Mäkitalo - add cache control header to static files and make setting cache control header more intuitive in ecpp components - reduce warning level in tnt::Savepoint - initialize variables in calcmvc demo 2013-06-16 Tommi Mäkitalo - bugfix: scope was set only for first defined variable; the bug is quite new - version 2.2 is not affected 2013-06-02 Tommi Mäkitalo - fix section in tntnet.xml man page - use jquery in calcajax demo - function in cpp must not be inline to be usable - add support for permanent redirects as well as temporary in API and redirect@tntnet - make controls demo working again 2013-06-01 Tommi Mäkitalo - remove request.clearSession(), which do not work anyway - use reply.clearSession() instead 2013-05-30 Tommi Mäkitalo - remove obsolete demo cgi-getenv 2013-05-29 Tommi Mäkitalo - add configuration for calcmvc demo 2013-05-28 Tommi Mäkitalo - multiple changes: * simplify definition components from cpp * simplify configuration of components * session and application unlocker lock scope on destruction only if scope was locked before * move macros to define scoped variables to header tnt/component.h from tnt/ecpp.h to make them available in components defined in cpp and construct the key parameter from type and varname instead of expecting it as a parameter * document default components of tntnet from tntnet.so in man page tntnet-defcomp(1) * use the simplified way to define components in demos * add include attribute to scope tags 2013-05-20 Tommi Mäkitalo - fix case of pidfile and compPath in documentation and example file - fix fetching vector of query parameters - implemented easier api for accessing and converting query arguments 2013-05-17 Tommi Mäkitalo - implement virtualhosts configuration, so that all mappings for a virtual host can be combined into one section 2013-05-15 Tommi Mäkitalo - fix references to other man pages in man pages - do not set http headers when static@tntnet is not called as top level component 2013-05-04 Tommi Mäkitalo - helper method tnt::Mapping::setArg to add arguments to mapping in application mode easier 2013-04-15 Tommi Mäkitalo - implement controller feature in ecpp - scoped variables get a chance to handle the request 2013-04-07 tommi@tntnet.org - use json in chat demo 2013-03-31 tommi@tntnet.org - fix compiler warnings - set pthread flags and select threaded compiler globally in configure script - remove some obsolete documentation files (converted to markdown now) 2013-03-20 tommi@tntnet.org - fix for out of tree build 2013-03-17 tommi@tntnet.org - replace call to awk with $(AWK), which is set by configure to a suitable awk implementation - set preprocesor flags in CPPFLAGS instead of CXXFLAGS - fix some compiler warnings 2013-03-16 tommi@tntnet.org - release candidate 2.2rc2 - add chapters about business logic, application class and logging to quick start guide 2013-03-11 tommi@tntnet.org - add configure switch --disable-locale - remove obsolete configure check for cxxtools::net::TcpServer::getFd - don't crash if standard locale could not be created 2013-03-10 tommi@tntnet.org - add converter script from tntnet.conf to tntnet.xml to dist package and install it - bugfix: request.getArgDef(number, default) did not use the default value - update man page for tntnet.xml (tag is optional, request.getArgs with number) - make url in mapping optional - fix converting mapping from tntnet.conf to xml: tag in should be - make static component loader publicly available 2013-03-09 tommi@tntnet.org - reduce warnings with clang compiler - do not use implicit conversion of cxxtools::SmartPtr to raw pointer - using std::set in poller is somewhat stupid - std::vector is simpler here - add documentation about mimeDb to tntnet.xml man page 2013-03-03 tommi@tntnet.org - release candidate 2.2rc1 2013-03-01 tommi@tntnet.org - regenerate man pages - remove special characters from markdown man pages - add new <%get> and <%post> tags to vim syntax highlighting 2013-02-28 tommi@tntnet.org - convert static-howto document to markdown and update the content - add <%get> and <%post> sections to receive GET or POST parameters 2013-02-27 tommi@tntnet.org - do not use parent values feature of cxxtools::QueryParams since it was never really used and will be removed in cxxtools - fix leak of scopes 2013-02-24 tommi@tntnet.org - ignore exception message "lost connection to peer" when killing the monitor process before the worker process in daemon mode - remove all references to tntnet.conf - update documentation 2013-02-24 tommi@tntnet.org - revert invalid change: make %config variables optional again - make ip address in listener section of tntnet.xml optional - remove ip address from generated tntnet.xml since it is normally not needed and now optional - add a convenience method tnt::Tntnet::listen with just a port number to listen on all local interfaces; previously a empty string must be specified, which remains possible of course 2013-02-21 tommi@tntnet.org - replace references to tntnet.conf with tntnet.xml in man pages 2013-02-19 tommi@tntnet.org - add example to url mapping and listeners section in man page tntnet.xml(7) 2013-02-18 tommi@tntnet.org - update documentation (man page for tntnet.xml is finished) - implement named args in tntnet.xml - continue man page for tntnet.xml (not finished yet) 2013-02-17 tommi@tntnet.org - make node mandatory in tntnet.xml as it should be - add man page for tntnet.xml and remove obsolete man page for tntnet.conf 2013-02-16 tommi@tntnet.org - document option -i in the man page of ecppc - read filenames for multibinary component optionally from file using option -i in ecppc 2013-02-13 tommi@tntnet.org - fix crash in direct mode (which is used when static files are sent) 2013-02-12 tommi@tntnet.org - fix memory leak: scopes were never deleted since a change in cxxtools some times ago 2013-02-06 tommi@tntnet.org - cleaner termination of tntnet using method cxxtools::net::TcpServer::terminateAccept() 2013-01-18 tommi@tntnet.org - do not set -pedantic on xlC compiler 2013-01-08 tommi@tntnet.org - port man pages to markdown and use md2man to generate man pages (markdown is so much easier to write) 2012-12-28 tommi@tntnet.org - change global tntnet.conf to tntnet.xml - remove duplicate entry from tntconfig 2012-12-24 tommi@tntnet.org - add pkg.m4 to dist package also - remove the unused flushdelay from man page tntnet.properties (although tntnet.properties is obsolet nowadays) - fix builing dist package 2012-12-01 tommi@tntnet.org - process HEAD requests for static files 2012-11-10 tommi@tntnet.org - replace ssllisteners section from tntnet.xml with a listener entry with certificate tag - compile with -pedantic and -Wall by default when compiler supports it 2012-10-13 tommi@tntnet.org - do not initialize string iterator with 0 - it is not standard conformant - replace include of tnt/encoding.h with forward declaration in tnt/httpreply.h 2012-10-02 tommi@tntnet.org - implement method tnt::HttpReply::clearSession to clear the current session after the current request 2012-10-01 tommi@tntnet.org - call _exit instead of exit when tntnet tries to restart itself to make restarting more robust 2012-08-04 tommi@tntnet.org - fix forward declaration for tnt::Compident struct 2012-07-25 tommi@tntnet.org - update gnutls support and other patches from debian package 2012-07-08 tommi@tntnet.org - fix locking when url map cache is cleared 2012-06-30 tommi@tntnet.org - use original query string from request instead of qparam, which is a combination of GET and POST parameters in proxy component (Artem) 2012-06-25 tommi@tntnet.org - add some unittests for ecpp parser - fix proxy (pass additional headers, handle '/' correctly) - add vhost and url to not found exception - simplify management of pooled http reply impl objects - improvements in ecpp compiler: - report right line number (numbering started from 0, but it should start with 1) - don't stop on first error but try to recover - allow '/' in component names when calling without quotes (<& foo/bar >) 2012-06-17 tommi@tntnet.org - fix http status code ordering invalid ordering results in invalid binary search. The bug here had no effect until now just with good luck. 2012-06-11 tommi@tntnet.org - make stopping tntnet more robust (I don't exactly know, if this fixes possible crashes, but looks better now) 2012-06-10 tommi@tntnet.org - improve converter script from tntnet.conf to tntnet.xml (initialize logging using xml) - replace tntnet.conf and tntnet.properties with new tntnet.xml in newsdb demo - fix 2 memory leaks (static structures, which were not cleaned up correctly when tntnet stops) - optimize writing accesslog by buffering actual writes when there are multiple requests running in parallel 2012-06-08 tommi@tntnet.org - tntnet.properties is obsolete - do not try to generate it any more - optimize writing access log slightly 2012-05-31 tommi@tntnet.org - fix writing access log and pid file - default configuration file when started as root is also xml - fix specifiaction of compPath in generated example tntnet.xml 2012-05-28 tommi@tntnet.org - fix typo in generated sample tntnet xml configuration - do not truncate error log on start - move logging configuration into tntnet.xml; cxxtools got support for configuration of logging using the serialization framework 2012-05-13 tommi@tntnet.org - performance improvement: impl http reply class and create a pool, so that the reply do not need to be reconstructed for each request 2012-05-07 tommi@tntnet.org - fix potential template problem in call to destroy in tnt::PointerObject 2012-05-05 tommi@tntnet.org - implement "include" in configuration file, which was lost after converting to xml and json 2012-05-03 tommi@tntnet.org - fix setting path info 2012-04-30 tommi@tntnet.org - fix tntnet-conf2xml.pl to parse quoted strings correctly - fix order of link parameters in link command 2012-04-29 tommi@tntnet.org - session handling was broken after implementation of secure session scope 2012-04-27 tommi@tntnet.org - fix typo in ecpp compiler occured in last checkin 2012-04-26 tommi@tntnet.org - use serialization framework to read %config variables from tntnet configuration 2012-04-25 tommi@tntnet.org - move reading configuration from libtntnet to process and add support for json configuration files (as an experiment for now) - implement API for new mapping features 2012-04-24 tommi@tntnet.org - add mapping by method or ssl status - update copyright header 2012-04-16 tommi@tntnet.org - update demos to use new xml configuration - fix converting ssl listeners from tntnet.conf to tntnet.xml - converter script from tntnet.conf to tntnet.xml 2012-04-15 tommi@tntnet.org - configure tntnet using xml - remove cgi lib 2012-04-10 tommi@tntnet.org - send secure session cookie only when ssl is enabled 2012-04-08 tommi@tntnet.org - implement secure session scope for variables only kept in ssl sessions (tag <%securesession>) 2012-04-06 tommi@tntnet.org - add proxy module to tntnet standard components 2012-04-02 tommi@tntnet.org - update version number to 2.1 - fix another set of possible conflicts, sun studio compiler complains about 2012-03-31 tommi@tntnet.org - add configure check for header sys/sendfile.h 2012-03-26 tommi@tntnet.org - fix generation of tntnet-config (shared lib flag was missing) - add documentation about --autoproject option of tntnet-config 2012-02-29 tommi@tntnet.org - fix debug output - use name of type also as key into scope variables to prevent binding variables to instances of different type 2012-02-25 tommi@tntnet.org - set compile flags for ibm xlc 2012-02-14 bendri - replace cxxtools::int64_t with standard int64_t 2012-02-09 tommi@tntnet.org - remove code for blocking mode from openssl and gnutls since it is not used anyway and was not working for a long time 2012-02-09 tommi@tntnet.org - fix declaration template class (clang complained about it) 2012-02-09 tommi@tntnet.org - add missing headers (yofuh) 2012-02-08 tommi@tntnet.org - update ChangeLog 2012-01-09 tommi@tntnet.org - Use atomic operations instead of mutex in zdata. This fixes occational crashes on shutdown on AIX. 2011-12-15 tommi@tntnet.org - flag -qmkshrobj is still needed on AIX 2012-01-09 tommi@tntnet.org - Use atomic operations instead of mutex in zdata. This fixes occational crashes on shutdown on AIX. 2011-12-07 tommi@tntnet.org - output warning, when there is white space other than line feed after closing %-Tag 2011-12-04 tommi@tntnet.org - increase default listen backlog from 16 to 64 2011-09-29 tommi@tntnet.org - fix reuse of session id (may leak on parallel requests) 2011-09-25 tommi@tntnet.org - fix for autoconf 2.68 2011-09-20 tommi@tntnet.org - fix help page in ecppc - fix type in demo (std::set::erase takes a non const iterator) 2011-09-12 tommi@tntnet.org - the names of autotools projects created with tntnet-config may have special characters 2011-09-05 tommi@tntnet.org - DefaultDestroyPolicy was renamed to DeletePolicy in cxxtools 2011-08-25 tommi@tntnet.org - define constant for content-disposition header 2011-08-10 tommi@tntnet.org - fix license headers of files from minizip by updating them to the most recent version 2011-06-24 tommi@tntnet.org - reuse session id if already set instead of replacing it 2011-06-05 tommi@tntnet.org - ignore SIGPIPE always 2011-05-30 tommi@tntnet.org - add setting ErrorLog for redirecting stderr to a file 2011-05-29 tommi@tntnet.org - return error code if client tries to use http header Expect 2011-05-29 tommi@tntnet.org - add documentation for AcessLog into man page tntnet.conf(7) 2011-05-08 tommi@tntnet.org - do not translate '+' to space when parsing urls 2011-04-03 tommi@tntnet.org - add xptemplates (vim template plugin) 2011-04-03 tommi@tntnet.org - fail to start tntnet if ssl is configured but not compiled in 2011-04-03 tommi@tntnet.org - remove ipv4 addresses from configuration files 2011-03-26 tommi@tntnet.org - add "" to ecpp for printing conditionally something without escaping html similar to "<$$ ... $>" 2011-03-26 tommi@tntnet.org - set log category of components settable in ecppc using flag -l 2011-02-20 tommi@tntnet.org - fix a small documentation bug and update version number in quick start guide 2011-02-17 tommi@tntnet.org - add makefile rule to compile a .ico file 2011-01-23 tommi@tntnet.org - add background worker threads 2011-01-20 tommi@tntnet.org - set lib deps using LIBADD instead of LDFLAGS (thanks idl0r) 2011-01-16 tommi@tntnet.org - remove feature for preloading applications (it did not work anyway and it has limited use) 2011-01-09 tommi@tntnet.org - remove "Load" setting (and feature) from tntnet.conf since it did not work and is useless 2011-01-03 tommi@tntnet.org - add a generator for a autotools project to tntnet-config script 2010-11-13 tommi@tntnet.org - cleanup code to reduce compiler warnings 2010-11-07 tommi@tntnet.org - accept full uri in http request line as rfc demands 2010-10-25 tommi@tntnet.org - implement support for ranges in static@tntnet (or more precise: one range) 2010-09-04 tommi@tntnet.org - fix compile bug in gnutls support 2010-08-07 tommi@tntnet.org - fix handling of application name in session cookies 2010-08-01 tommi@tntnet.org - release 2.0 2010-07-30 tommi@tntnet.org - documentation updates 2010-07-18 tommi@tntnet.org - prefer application name over library name for session cookie 2010-07-10 tommi@tntnet.org - better error message, when number cannot be converted in %args-section - handle non empty strings as true in boolean arguments, so that submit buttons can be easily queried 2010-07-09 tommi@tntnet.org - fix race condition when stopping tntnet 2010-07-05 tommi@tntnet.org - keep session when component returns with DECLINED and no new session is found 2010-06-24 tommi@tntnet.org - do graceful shutdown on SIGINT 2010-06-15 tommi@tntnet.org - add support for access.log with common log format - fix bug, where always the first file of multibinary components was sent 2010-06-14 tommi@tntnet.org - files compiled with ecppc -b compressed when requested 2010-06-03 tommi@tntnet.org - set proper text in http reply header instead of defaulting to OK 2010-05-31 tommi@tntnet.org - do not log_warn if static file is not found in static@tntnet 2010-05-22 tommi@tntnet.org - use compression in multibinary components and cache the compressed data - fix for a very old bug, which may cause a crash when a component was called in parallel the first time 2010-04-06 tommi@tntnet.org - ecppc -I do not need a space before the parameter any more 2010-03-21 tommi@tntnet.org - do not generate current time into generated source to help tools like ccache detecting identity 2010-03-10 tommi@tntnet.org - use application/x-data as mime type in multibinary components when mimetype is otherwise unknown. - sort file names correctly in multibinary components 2010-02-26 tommi@tntnet.org - send cookies also in redirect and not authorized replies 2010-02-21 tommi@tntnet.org - new feature: make components callable from the command line using "tntnet -C compid" 2010-02-19 tommi@tntnet.org - make application name in tntnet application class settable - add a demo for using tntnet application class (calcapp) 2010-02-03 tommi@tntnet.org - (url-)decode cookie value as is should be 2010-01-27 tommi@tntnet.org - do not add a dot at the end of session cookie name if no library is set 2010-01-27 tommi@tntnet.org 2010-01-18 tommi@tntnet.org - improve logging output 2009-12-30 tommi@tntnet.org - make RTLD_LOCAL the default loading mechanism 2009-12-22 tommi@tntnet.org - do not use deprecated cxxtools::Dynbuffer but std::vector instead - remove unused class inflatestream - cxxtools::Pipe is moved to cxxtools::posix::Pipe - fix bug, where tntnet did not use keep alive when in HTTP 1.1 the connection header was ommitted 2009-12-21 tommi@tntnet.org - make unit test optional 2009-12-17 tommi@tntnet.org - handle utf8 correctly 2009-12-16 tommi@tntnet.org - fix bug, where a component, which followed a not matched MapUrl declined a request was called twice when the request was repeated - add proper locking to the url map cache 2009-12-15 tommi@tntnet.org - new classes tnt::SessionUnlocker and tnt::ApplicationUnlocker 2009-12-04 tommi@tntnet.org - load component libraries with RTLD_GLOBAL if library name is prefixed with ! in tntnet.conf 2009-12-04 tommi@tntnet.org - Do not use the file name of ecpp files as class names of generated components any more but let component names contain aribtrary characters (except \0). Ecppc gets the -p switch to include the full path of the source file into the component name. 2009-11-24 tommi@tntnet.org - optimization: use fixed size buffer of 4k for message header to reduce allocations - add some unit tests 2009-11-17 tommi@tntnet.org - send http error detected in parse state - use a fixed buffer of 8 bytes (7 + '\0'-terminator) for http method instead of std::string 2009-11-15 tommi@tntnet.org - add current file name to error messages and format messages like gcc 2009-11-15 tommi@tntnet.org - set FD_CLOEXEC properly for listeners - let cxxtools set FD_CLOEXEC for accepted sockets (needs up to date cxxtools) - do not derive Messageheader from std:multimap but delegate calls instead to a member multimap - remove tnt::Tntnet::forkProcess and tnt::Tntnet::runProcess methods (they are obsolete with FD_CLOEXEC set) 2009-11-15 tommi@tntnet.org - read of http body slightly optimized: do not use stringstream to convert content length to number 2009-11-11 tommi@tntnet.org - don't use cxxtools-config script any more 2009-11-07 tommi@tntnet.org - bugfix: wrong buffer for notification of poller was used, which may lead to a buffer overflow in very rare cases 2009-10-30 tommi@tntnet.org - make refcounting of tnt::Scope and tnt::Job thread safe 2009-10-30 tommi@tntnet.org - Send one set-cookie header per cookie instead of comma separated list. - The comma separated list as specified in rfc 2109 just don't work. This is actually a bug in the rfc. 2009-10-27 tommi@tntnet.org - new demo for reverse ajax, jquery and json 2009-10-17 tommi@tntnet.org - default to openssl instead of gnutls - add optional stressjob for stresstesting tntnet - process all requests read into input buffer (bugfix) - use cxxtools::RefCounted for reference counting Scope class - optimize sending reply: do not add missing headers to request before sending but send directly 2009-10-10 tommi@tntnet.org - change default charset from iso-8859-1 to UTF-8 2009-05-30 tommi@tntnet.org - allow comma in typenames of scoped variables (needed for templates with multiple type arguments) 2009-05-21 tommi@tntnet.org - add some missing includes and other fixes for solaris 2009-05-21 tommi@tntnet.org - set mime type explicitely when compiling other than ecpp-files 2009-04-13 tommi@tntnet.org - allow objects in scopes without transfering ownership and use that in <%param>-scope 2009-03-11 tommi@tntnet.org - bugfix: content-type field was not checked correctly for POST-requests 2009-02-18 tommi@tntnet.org - new method request.touch() to rearm the watchdog in daemon mode 2009-02-18 tommi@tntnet.org - increase default buffer size for ssl connections 2009-02-13 tommi@tntnet.org - remove regex-class since we have it in cxxtools already 2009-02-10 tommi@tntnet.org - decouple httprequest from network definitions by using a interface to determine server- and peer-addresses 2008-12-07 tommi@tntnet.org - be more robust on epoll failures 2008-12-07 tommi@tntnet.org - use read write mutex instead of mutex in component loader for better scalability 2008-12-06 tommi@tntnet.org - use more lightweight smart pointer for library handle 2008-11-26 tommi@tntnet.org - use RTLD_LOCAL-flag when loading components to improve separation between applications 2008-10-15 tommi@tntnet.org - make shutdown of tntnet cleaner and faster by using conditions 2008-07-04 tommi@tntnet.org - move shortcut methods into a separate class tnt::Configurator. This also ensures binary compatibility with previous releases 2008-06-16 tommi@tntnet.org - add shortcut methods for configuring tntnet to tnt::Tntnet-class to ease configuration when tntnet is used as a library 2008-06-03 tommi@tntnet.org - release version 1.6.3 2008-05-31 tommi@tntnet.org - allow multiline initialization in scope variables - handle ' and " in c++-comments correctly in ecpp parser 2008-05-25 tommi@tntnet.org - fix clearCookie (set cookie path as in setCookie; was broken since 2007-06-17) 2008-04-05 tommi@tntnet.org - define %args-variables before scoped variables, so it is possible to use %args variables to initialize scoped variables. - fix shutdown 2008-04-04 tommi@tntnet.org - default output for ecppc -M is stdout, not the basename of the source - don't set content-type- and keep-alive-headers when switching to direct mode 2008-03-29 tommi@tntnet.org - fix error and timeout handling in gnutls - improve gnutls performance by letting handshake happen in parallel between sockets 2008-03-23 tommi@tntnet.org - fix error handling in accept; accept in gnutls may throw exceptions, which tntnet did not catch. This resulted in a break of the accept- loop. 2008-03-19 tommi@tntnet.org - support certificate chains in openssl 2008-03-17 tommi@tntnet.org - clear username and password between keep-alive requests 2008-02-07 tommi@tntnet.org - simplify handling of scoped variables 2008-01-03 tommi@tntnet.org - openssl fixes - remove warnings when shutting down - make timersleep configurable 2007-12-28 tommi@tntnet.org - set FD_CLOEXEC on listener socket and accepted connections 2007-12-09 tommi@tntnet.org - tnt::Tntnet::forkProcess and runProcess to start processes. with a simple fork the child process inherits the listener ports and prevents restarting tntnet while the child process runs. - pass application object to request 2007-12-02 tommi@tntnet.org - named arguments from urlmapping to components, e.g. request.getArgs("DocumentRoot") 2007-11-18 tommi@tntnet.org - fixed cookie handling (did not work in some cases on IE) - reply.uout() for printing url encoded data 2007-11-04 tommi@tntnet.org - allow initialization of scope variables in ecpp with "type = value;" 2007-10-25 tommi@tntnet.org - move class tnt::Dispatcher::CompidentType to tnt::MapTarget - fix some warnings and errors produced by gcc when using -pedantic 2007-10-21 tommi@tntnet.org - search components in pkglibdir 2007-10-17 tommi@tntnet.org - set content-type also in other than POST requests 2007-10-15 tommi@tntnet.org - move most of tntnet into libtntnet to ease embedding tntnet in applications 2007-08-22 tommi@tntnet.org - allow underscore in name of scoped variables 2007-08-19 tommi@tntnet.org - rebuild epoll-fd after detecting inconsistency instead of failing 2007-08-11 tommi@tntnet.org - new feature: pass named parameters of any class to subcomponents 2007-07-14 tommi@tntnet.org - prefix classname in generated components with "_component_" to reduce possible naming-conflicts and allow components to have reserved c++-words as names (like "template") 2007-07-10 tommi@tntnet.org - generate macro SET_LANG to set language inside components 2007-07-08 tommi@tntnet.org - new methods request.setLocale(std::locale) and reply.setLocale(std::locale) 2007-07-07 tommi@tntnet.org - restructure HttpMessage/HttpRequest/HttpReply and pass additional http-headers with HttpError-exceptions - make HttpReply::notAuthorized and HttpReply::redirect throw an exception, so that it can be called in subcomponents easily 2007-07-03 tommi@tntnet.org - allow "char *var;" in scoped-variables - don't listen on 0.0.0.0:80 if only ssl-listeners are configured 2007-06-30 tommi@tntnet.org - support for http-basic-authentification - new tag <%doc>... (long form of comment-tag) 2007-06-20 tommi@tntnet.org - use C-locale if standard-locale ($LANG) is unknown 2007-06-17 tommi@tntnet.org - add debug-statements in dispatcher for easier debugging of MapUrl-statements - set cookie-path in session-scope to extend sessions to all pages 2007-05-29 tommi@tntnet.org - fix typo in redirect-component (name is redirect, not redired) 2007-05-27 tommi@tntnet.org - don't warn about unknown mime-type for ecpp-files - fix internationalization in subcomponents 2007-05-23 tommi@tntnet.org - use requestname as base filename in multibinary-generation by default - document option --mimetypes in ecppc 2007-05-20 tommi@tntnet.org - make content-type-detection in ecppc working again (broken since AddType-fix on 2007-05-16) 2007-05-17 tommi@tntnet.org - fix minor protocol-error when sendfile is used (connection was closed after request although the header specified to use keep-alive) 2007-05-16 tommi@tntnet.org - AddType-configuration-variable fixed 2007-05-13 tommi@tntnet.org - removed method isTop() from components, since it is not reliable in all circumstances. The feature is replaced with a additional virtual operator()-variant in tnt::Component. 2007-05-11 tommi@tntnet.org - change newsdb-demo to use built in connectionpool of tntdb - build-improvements (port to solaris/SunStudio) 2007-05-08 tommi@tntnet.org - allow cookie-values to have commas 2007-05-07 tommi@tntnet.org - fix gnutls - fix componentloader (crashed sometimes under load) 2007-05-04 tommi@tntnet.org - fix tntnet-config-script for Mac-OS-X 2007-05-03 tommi@tntnet.org - make tnt::MimeDb non-case-sensitive - building tntnet-server and cgi-lib is now optional and on by default for sdk-only-builds (useful for cross-builds) - make setting user and group working again 2007-04-29 tommi@tntnet.org - send gz-file in static@tntnet when gzip-encoding is accepted and a gz-file is available - use sendfile(2) in static@tntnet when possible 2007-04-25 tommi@tntnet.org - remove support for non-singleton components (it is useless now) 2007-04-16 tommi@tntnet.org - 2 other serious bugs fixed: epoll was not always waked up on new jobs. After this, idle-jobs where queued until system-resources were exhausted. Another problem was a race-condition when the http-date-header was generated. After these fixes tntnet runs stable under high load. 2007-04-15 tommi@tntnet.org - fixed serious bug: don't delete thread-scope in request - worker-thread does this 2007-04-11 tommi@tntnet.org - new option -L for ecppc to disable generation of #line-directives - add missing includes and rename some variables to suppress warnings from Sun Studo 11 (thank you Mark) 2007-03-27 tommi@tntnet.org - fix race-condition in scope-handling, which caused a crash on MP-boxes under high load - check for enough worker-threads to handle all sockets (tntnet now needs at least one per listen-socket after removing listener threads) - make thread-sleep-time configurable (default: 10s) 2007-03-25 tommi@tntnet.org - use TCP_DEFER_ACCEPT if available - remove listener-threads - worker threads now accept connections, which removes on context-switch on each accepted connection 2007-03-24 tommi@tntnet.org - new demo calci18n 2007-03-21 tommi@tntnet.org - change license from GPL to LGPL - new configure-option --with-epoll=yes|no|probe 2007-03-20 tommi@tntnet.org - look for LANG-settings also in sub-query-parameters 2007-03-18 tommi@tntnet.org - be more tolerant about whitespace in http-header 2007-03-13 tommi@tntnet.org - fix bug, which caused tntnet sometimes to fail loading components - new feature: tnt::HttpReply::resetContent 2007-03-11 tommi@tntnet.org - url-decode non-ascii-characters in path-info 2007-03-10 tommi@tntnet.org - revert signalhandlers for SIGPIPE and SIGABRT, which were lost when modularized - standard-components static and unzip set mime-type now 2007-01-24 tommi@tntnet.org - move process-handling from class Tntnet to a separate class Process 2006-12-03 tommi@tntnet.org - print full path of dependencies in ecppc -M - debug-log when fetching scoped variables 2006-11-23 tommi@tntnet.org - Option "-I dir" for ecppc, ecppl, ecppll 2006-11-20 tommi@tntnet.org - use epoll-interface when available 2006-11-18 tommi@tntnet.org - make sdk and demos optional in build-system - fix bug, which made keep-alive-timeout unnecessary short 2006-11-17 tommi@tntnet.org - Remove global factory-symbol from shared libraries. This makes it possible to have components with identical names in different libraries. 2006-11-16 tommi@tntnet.org - VMapUrl (virtual host specific mapping) 2006-11-05 tommi@tntnet.org - changed some less informative log-entries from info to debug - added logging of file-size in static pages - reading tntnet.conf from current directory in non-root accounts - using port 8000 as default-port in non-root accounts 2006-09-22 tommi@tntnet.org - major bugfix: MaxRequestSize was not checked for 0 in POST-requests. the result was, that POST-requests did not work in the default configuration at all. - Version 1.5.3 2006-09-09 tommi@tntnet.org - fix crash in cgi-library when using thread-scope in cgi-programs 2006-08-22 tommi@tntnet.org - tntnet has now a complete set of man-pages 2006-08-19 tommi@tntnet.org - increase maximum limits for better default scalability 2006-07-09 tommi@tntnet.org - thread-scope variables - new demo "alldemos", which links to all other demos 2006-07-03 tommi@tntnet.org - cookies are case-insensitive (see rfc 2109) 2006-06-25 tommi@tntnet.org - make http-headers case-insensitive as per spec - don't delete components any more - they don't eat so much memory and it is impossible to know, when components aren't needed any more 2006-06-20 tommi@tntnet.org - graceful shutdown of ssl-connections (gnutls and openssl) 2006-06-16 tommi@tntnet.org - new demo-applications calcmvc, which shows a simple mvc-pattern, and calcajax, which demonstrates, how to use ajax with tntnet 2006-06-10 tommi@tntnet.org - port to gnutls 2006-06-08 tommi@tntnet.org - take first commandline-argument as configurationfile - remove unnecessery virtual destructors (although this triggers some compiler-warnings) 2006-05-24 tommi@tntnet.org - fix linking with openssl for Open-BSD (and possibly others) - try harder to shut down listener 2006-05-08 tommi@tntnet.org - send charset in content-type-header with HTTP/1.1 2006-04-29 tommi@tntnet.org - improved namespace-support for components 2006-04-26 tommi@tntnet.org - support for IPv6 2006-04-12 tommi@tntnet.org - new demo newsdb, which reads news from a database using tntdb - add openssl-license and allow tntnet to be linked with openssl - fix names of standard-components (components in tntnet.so) 2006-04-04 tommi@tntnet.org - ANSI-C++-fixes - make SIGTERM a graceful shutdown 2006-03-24 tommi@tntnet.org - include #line-directives into generated code to help finding syntax errors in components 2006-03-23 tommi@tntnet.org - fix ssl - delay closing standard-handles for better error-reporting at startup - fix internationalization 2006-03-02 tommi@tntnet.org - locale-cache - poll before read, which reduces system calls even more 2006-02-16 tommi@tntnet.org - dramatic performance-improvement by optimization of locale-handling 2006-01-25 tommi@tntnet.org - add support for locales 2006-01-15 tommi@tntnet.org - Simplified constant data-handling for i18n - i18n is now controled with <%i18n>-tags 2005-12-31 tommi@tntnet.org - components can be compiled into cgi-programs 2005-12-09 tommi@tntnet.org - new demo "controls" to demonstrate usage of end-tags - new configuration-variables ListenBacklog, ListenRetry, EnableCompression 2005-12-08 tommi@tntnet.org - tntnet now supports gzip-encoding 2005-12-02 tommi@tntnet.org - end-tags for component-calls - documentation-updates and converted to open-document-format 2005-12-01 tommi@tntnet.org - fixed SSL-problems - need to mutex-lock SSL-read and -write-calls 2005-11-08 tommi@tntnet.org - store comploader in objectpool for later reuse. - derive workerthread from DetachedThread and delete itself on exit 2005-11-04 tommi@tntnet.org - new health-check - if a thread takes too long for processing (default: 10 minutes), the thread is considered hanging and tntnet is restarted automatically. 2005-10-22 tommi@tntnet.org - delay initialization of logging after changing user and group. This ensures that logfiles are created with the right permissions. - increase defaults for MinThreads from 5 to 10 and MaxThreads from 10 to 100. Threads are not that expensive and it should not hurt to create much more. 2005-10-18 tommi@tntnet.org - components with compressed data did not work any more - fixed 2005-09-26 tommi@tntnet.org - one level of indirection of factory-pointer removed. - detection of cxxtools- and zlib-headers fixed. Missing headers trigger a error at configure-time. 2005-09-15 tommi@tntnet.org - components are created with a factory instead of a create-method. This way there is no need to convert a void* to a function-pointer, what is not defined in c++. 2005-08-23 tommi@tntnet.org - documentation update (see doc/tntnet.sxw) - initscript update - tntnet reload 2005-08-22 tommi@tntnet.org - new namingconventions: classfiles start with uppercase, methods with lowercase - use cxxtools-1.4.0 2005-06-27 tommi@tntnet.org - fixed ssl-threading problem 2005-06-22 tommi@tntnet.org - dependencygeneration fixed (no *.h-dependency any more unless requested) - no escape of '&' in sout() - fixed upload.ecpp-demo - fixed ecppl/ecppll 2005-06-13 tommi@tntnet.org - components are generated in .cpp-files only by default (no .h-files) - bugfix: component-type was not filled - unsave html-character-output in <$...$> and is escaped 2005-06-02 tommi@tntnet.org - scope-variables - automatic session-handling - removed boost dependency 2005-05-17 tommi@tntnet.org - version 1.3.1 released 2005-05-17 tommi@tntnet.org - monitor-process calls listen before fork of worker instead of worker. 2005-05-03 tommi@tntnet.org - better startup-handling: parent-process wait for child to start successfully and listen to ports 2005-05-09 tommi@tntnet.org - Bug: peeraddress was cleared at keep-alive - init-scripts starts tntnet on restart even when not running 2005-03-03 tommi@tntnet.org - logs remote ip-address in category debug 2005-02-10 tommi@tntnet.org - new syntax for calling subcomponents 2005-01-23 tommi@tntnet.org - better scalability by creating a poller-thread, which monitors multiple idle connections instead of having a worker-thread for each connection. - worker-threads are dynamically stopped and started - Version 1.3.0 released 2005-01-12 tommi@tntnet.org - version 1.2.3 released - some protection against DoS-attacks (MaxRequestSize, MaxBodySize, MaxHeaderSize) - support for Cookies - tnt::savepoint 2004-12-14 tommi@tntnet.org - version 1.2.2 released - Bug in Keep-Alive fixed 2004-12-05 tommi@tntnet.org - version 1.2.1 released - Content-MD5-header - moved logging-wrapper to cxxtools (1.2.1) - typed arguments 2004-11-25 tommi@tntnet.org - version 1.2.0 released - use cxxtools-1.2.0 2004-11-24 tommi@tntnet.org - add missing CR in HTTP-Header 2004-11-22 tommi@tntnet.org - init-script checks, if tntnet is really running when pid-file is found 2004-11-12 tommi@tntnet.org - version 1.1.3 released - generate tntnet.conf with autoconf to get autoconf-parameters in 2004-11-11 tommi@tntnet.org - added missing tntnet.so.* 2004-11-03 tommi@tntnet.org - version 1.1.2 released - improved autoconf/automake-buildsystem - minor feature-improvements and bugfixes 2004-10-25 tommi@tntnet.org - version 1.1.1 released - buldsystem changed to autoconf/automake 2004-09-20 tommi@tntnet.org - resolved: server might crash under high load, because I linked it with the non-multithreaded regex-library 2004-09-16 tommi@tntnet.org - new build for compatibility with cxxtools 1.1 2004-09-07 tommi@tntnet.org - fixed HTTP-header 2004-08-31 tommi@tntnet.org - version 1.1 released - ecpp-components read LANG from request first. 2004-03-25 tommi@tntnet.org - initial release 1.0 tntnet-3.0/Makefile.am000066400000000000000000000021011365471676700147440ustar00rootroot00000000000000ACLOCAL_AMFLAGS = -I m4 if MAKE_SERVER SERVERDIRS = \ framework/runtime \ framework/defcomp \ etc endif if MAKE_SDK SDKDIRS = \ sdk/tools/common \ sdk/tools/ecppc \ misc endif if MAKE_DEMOS DEMODIRS = \ demo endif if MAKE_UNITTEST TESTDIRS = \ test endif SUBDIRS = \ framework/common \ doc/man \ $(SERVERDIRS) \ $(SDKDIRS) \ $(DEMODIRS) \ $(TESTDIRS) EXTRA_DIST = \ COPYING \ demo/newsdb/Makefile \ demo/newsdb/README \ demo/newsdb/global.ecpp \ demo/newsdb/index.ecpp \ demo/newsdb/news.ecpp \ demo/newsdb/newscss.css \ demo/newsdb/newsdata.sh \ demo/newsdb/newsdb.sql \ doc/jquery-howto.markdown \ doc/quick-start-guide.markdown \ doc/static-howto.markdown \ doc/upload-howto.markdown \ m4/acx_pthread.m4 \ m4/ax_check_compile_flag.m4 \ m4/ax_compiler_vendor.m4 \ m4/pkg.m4 \ misc/ecpp.vim \ misc/tntnet-logo.svg \ $(pkgdata_SCRIPTS) pkgconfigdir = $(libdir)/pkgconfig/ pkgconfig_DATA = \ pkgconfig/tntnet.pc \ pkgconfig/tntnet_sdk.pc tntnet-3.0/NEWS000066400000000000000000000000001365471676700134030ustar00rootroot00000000000000tntnet-3.0/README000066400000000000000000000043601365471676700136010ustar00rootroot00000000000000Tntnet ====== Tntnet is a web application server for web applications written in C++. You can write a Web-page with HTML and with special tags you embed C++-code into the page for active contents. These pages, called components are compiled into C++-classes with the ecpp-compilier "ecppc", then compiled into objectcode and linked into a process or shared library. This shared library is loaded by the webserver "tntnet" on request and executed. The ecpp-compiler can create also C++-classes from static files of any type, e.g. you can compile a jpeg-image into the library. So the whole webapplication is a single library. The application runs native, so they are very fast and compact. Features supported include: cookies, HTTP-upload, automatic request-parameter parsing and conversion, automatic sessionmanagement, scoped variables (application, request and session), internationalisation, keep-alive. Logging is done through cxxtools. Tntnet is fully multithreaded, so it scales well on multiprocessor machines. It uses a dynamic pool of workerthreads, which answers requests from http-clients. Installation ============ To install tntnet, you need cxxtools (http://www.tntnet.org/). You can find generic installation instructions in the file INSTALL. Quick start =========== To create a simple application run "tntnet-project hello". This creates a directory "hello" with a simple project and prints a short message, how to run the application. There are some demo-applications you can try in _demos_. To run the demos without installing tntnet, change to the directory of the demo and run tntnet from the directory framework/runtime: cd hello ../../framework/runtime/tntnet Tntnet listens on port 8000. Start your browser and navigate to: http://localhost:8000/ Documentation is provided in man pages and some documents found in the doc directory. Ssl === Tntnet supports ssl. It must be configured in tntnet.xml or using the api. For ssl a certificate is needed. To create a self signed certificate run: openssl req -x509 -nodes -days 1095 -utf8 -subj "/C=DE/L=Your Town/CN=$(hostname -f)/O=Your Organization/OU=Your unit" -newkey rsa:2048 -keyout tntnet.pem -out tntnet.pem Client side certificates can be used to restrict access to tntnet. tntnet-3.0/README.git000066400000000000000000000004101365471676700143530ustar00rootroot00000000000000Installation from git ===================== In the git repository there is no configure-script, but configure.ac, which is the source for configure. You need autoconf, automake and libtool to create configure. Run `autoreconf -i` to generate a configure script. tntnet-3.0/configure.ac000066400000000000000000000111431365471676700152040ustar00rootroot00000000000000AC_INIT(tntnet, 3.0, [Tommi Maekitalo ]) AC_CANONICAL_TARGET LT_INIT([disable-static]) AM_INIT_AUTOMAKE abi_current=13 abi_revision=0 abi_age=0 sonumber=${abi_current}:${abi_revision}:${abi_age} AC_SUBST(sonumber) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_HEADERS([framework/common/config.h]) AC_CONFIG_SRCDIR([framework/common/tntnet.cpp]) AC_SEARCH_LIBS(gethostbyname, nsl socket resolv) AC_SEARCH_LIBS(dlopen, dl, , AC_MSG_ERROR([dlopen not found])) AC_PROG_CXX AC_PROG_LIBTOOL AC_PROG_SED PKG_PROG_PKG_CONFIG AC_LANG(C++) AX_CXX_COMPILE_STDCXX_11(noext, mandatory) ACX_PTHREAD LIBS="$PTHREAD_LIBS $LIBS" CC="$PTHREAD_CC" CXX="$PTHREAD_CXX" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" CXXFLAGS="$CXXFLAGS $PTHREAD_CXXFLAGS" AX_COMPILER_VENDOR AS_IF([test "$ax_cv_cxx_compiler_vendor" = "ibm"], [CPPFLAGS="$CPPFLAGS -qrtti -qlanglvl=newexcp -D__NOLOCK_ON_INPUT -D__NOLOCK_ON_OUTPUT"], AX_CHECK_COMPILE_FLAG([-Wno-long-long], [CPPFLAGS="$CPPFLAGS -Wno-long-long"]) AX_CHECK_COMPILE_FLAG([-Wall], [CPPFLAGS="$CPPFLAGS -Wall"]) AX_CHECK_COMPILE_FLAG([-pedantic], [CPPFLAGS="$CPPFLAGS -pedantic"])) AC_CHECK_HEADER([zlib.h], , AC_MSG_ERROR([zlib not found])) AC_CHECK_HEADER([cxxtools/net/tcpsocket.h], , AC_MSG_ERROR([cxxtools headers not found])) AC_CHECK_FUNCS([fopen64], ,[AM_CFLAGS=-DUSE_FILE32API]) AC_SUBST(AM_CFLAGS) AC_COMPILE_IFELSE( [AC_LANG_SOURCE([ #include void f() { cxxtools::xml::XmlDeserializer d; d.readAttributes(true); }])], AC_DEFINE(CXXTOOLS_XMLDESERIALISER_ATTR, [], [Defined if cxxtools xmldeserializer can read attributes])) AC_COMPILE_IFELSE( [AC_LANG_SOURCE([ #include int flag = cxxtools::net::TcpServer::REUSEADDR; ])], AC_DEFINE(HAVE_CXXTOOLS_REUSEADDR, [], [Defined if cxxtools supports SO_REUSEADDR flag])) PKG_CHECK_MODULES([MINIZIP], [minizip], [HAVE_MINIZIP=true], [HAVE_MINIZIP=false]) AC_SUBST([MINIZIP_CFLAGS]) AC_SUBST([MINIZIP_LIBS]) AM_CONDITIONAL([HAVE_MINIZIP], [test $HAVE_MINIZIP = true]) AC_CHECK_FUNCS([epoll_create]) AC_CHECK_FUNCS([epoll_create1]) AC_CHECK_FUNCS([sendfile]) AC_CHECK_HEADERS([sys/sendfile.h]) # # optional components # AC_ARG_ENABLE([server], AS_HELP_STRING([--disable-server], [disable building tntnet server]), [enable_server=$enableval], [enable_server=yes]) AM_CONDITIONAL(MAKE_SERVER, test x$enable_server = xyes) AC_ARG_ENABLE([sdk], AS_HELP_STRING([--disable-sdk], [disable building sdk]), [enable_sdk=$enableval], [enable_sdk=yes]) AM_CONDITIONAL(MAKE_SDK, test x$enable_sdk = xyes) AC_ARG_ENABLE([demos], AS_HELP_STRING([--enable-demos], [enable building demos]), [enable_demos=$enableval], [enable_demos=no]) AM_CONDITIONAL(MAKE_DEMOS, test "$enable_demos" = "yes" -o "$enable_demos" = "install") AM_CONDITIONAL(INSTALL_DEMOS, test "$enable_demos" = "install") AS_IF([test "$enable_demos" = "yes"], [ AS_IF([test "$enable_sdk" != "yes"], [AC_MSG_ERROR([demos cannot be built without building sdk])]) AC_CHECK_HEADER([tntdb.h], , AC_MSG_ERROR([tntdb headers not found])) ] ) AC_ARG_WITH([md2man], AS_HELP_STRING([--with-md2man], [use go-md2man tool to generate man pages from markdown]) [with_md2man=$withval]) AS_IF( [test "$with_md2man"], AC_CHECK_PROG(MD2MAN, [go-md2man], [go-md2man]) AS_IF( [test -z "$MD2MAN"], AC_MSG_ERROR([go-md2man not found]) ) ) AM_CONDITIONAL(GENERATE_MAN, test ! -z "$with_md2man") # # others # AC_CHECK_FUNCS([setenv]) case "${host_cpu}-${host_os}" in *-aix*) SHARED_LIB_FLAG=-qmkshrobj ;; *-darwin*) SHARED_LIB_FLAG=-dynamiclib ;; *) SHARED_LIB_FLAG=-shared ;; esac AC_SUBST(SHARED_LIB_FLAG) AC_ARG_ENABLE([unittest], AS_HELP_STRING([--disable-unittest], [disable unittest]), [enable_unittest=$enableval], [enable_unittest=enable_unittest]) AM_CONDITIONAL(MAKE_UNITTEST, test "$enable_unittest" = "enable_unittest") AC_CONFIG_FILES([misc/tntnet-project], [chmod +x misc/tntnet-project]) AC_CONFIG_FILES([ Makefile demo/Makefile demo/accumulator/Makefile demo/calc/Makefile demo/calcajax/Makefile demo/calcapp/Makefile demo/calcmvc/Makefile demo/comp/Makefile demo/cookie/Makefile demo/gd/Makefile demo/hello/Makefile demo/newsdb/Makefile demo/rest/Makefile demo/savepoint/Makefile demo/session/Makefile demo/upload/Makefile doc/man/Makefile etc/Makefile framework/common/Makefile framework/runtime/Makefile framework/defcomp/Makefile misc/Makefile pkgconfig/tntnet.pc pkgconfig/tntnet_sdk.pc sdk/tools/common/Makefile sdk/tools/ecppc/Makefile test/Makefile ]) AC_OUTPUT tntnet-3.0/demo/000077500000000000000000000000001365471676700136425ustar00rootroot00000000000000tntnet-3.0/demo/.gitignore000066400000000000000000000016101365471676700156300ustar00rootroot00000000000000/accumulator/accumulator.cpp /accumulator/accumulator /calcajax/calcajax.cpp /calcajax/calcajax /calcajax/calcajax_js.cpp /calcajax/docalc.cpp /calcapp/calc /calcapp/calc.cpp /calcapp/tntnet.properties /calc/calc.cpp /calc/calc /calcmvc/calcmvc /calcmvc/calcController.cpp /calcmvc/calcModel.cpp /calcmvc/calcmvc.cpp /calcmvc/calcView.cpp /calcmvc/view/accumulator.cpp /calcmvc/view/calc.cpp /comp/comp.cpp /comp/extcomp.cpp /comp/subcomp.cpp /comp/tntnet.xml /cookie/cookie /cookie/cookie.cpp /gd/gd /gd/gd.cpp /gd/imgstr.cpp /hello/hello /hello/hello.cpp /hello/tntnet.cpp /newsdb/index.cpp /newsdb/news.cpp /newsdb/newscss.cpp /savepoint/savepoint.cpp /savepoint/tntnet.xml /session/appsession.cpp /session/session.cpp /session/tntnet.xml /upload/upload /upload/upload.cpp /rest/deldata /rest/delvalue.cpp /rest/getdata /rest/getkeys.cpp /rest/getvalue.cpp /rest/putdata /rest/putvalue.cpp /rest/rest tntnet-3.0/demo/Makefile.am000066400000000000000000000003021365471676700156710ustar00rootroot00000000000000SUBDIRS = \ accumulator \ calc \ calcajax \ calcapp \ calcmvc \ comp \ cookie \ gd \ hello \ newsdb \ rest \ savepoint \ session \ upload tntnet-3.0/demo/accumulator/000077500000000000000000000000001365471676700161615ustar00rootroot00000000000000tntnet-3.0/demo/accumulator/Makefile.am000066400000000000000000000005731365471676700202220ustar00rootroot00000000000000bin_PROGRAMS = accumulator accumulator_SOURCES = \ accumulator.ecpp \ main.cpp AM_CPPFLAGS = -I$(top_srcdir)/framework/common accumulator_LDADD = $(top_builddir)/framework/common/libtntnet.la -lcxxtools noinst_DATA = tntnet.xml CLEANFILES = accumulator.cpp ECPPC=$(top_builddir)/sdk/tools/ecppc/ecppc SUFFIXES=.ecpp .cpp .ecpp.cpp: $(ECPPC) $(AM_V_GEN)$(ECPPC) -o $@ $< tntnet-3.0/demo/accumulator/accumulator.ecpp000066400000000000000000000014541365471676700213550ustar00rootroot00000000000000<%args> // define variables which are filled from the form double value = 0; // default value is 0 bool add; bool sub; <%session> // define a session variable of type double with a initial value of 0 double currentValue = 0; <%cpp> if (add) currentValue += value; if (sub) currentValue -= value; Tntnet accumulator

Accumulator

<# this prints the session variable into the screen (and btw: this is a comment) #> The current value is <$ currentValue $>.


tntnet-3.0/demo/accumulator/main.cpp000066400000000000000000000036031365471676700176130ustar00rootroot00000000000000/* * Copyright (C) 2018 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include int main(int argc, char* argv[]) { try { std::ifstream in("tntnet.xml"); tnt::TntConfig config; in >> cxxtools::xml::Xml(config); log_init(config.logConfiguration); tnt::Tntnet app(config); app.mapUrl("^/$", "accumulator"); app.mapUrl("^/(.*)$", "$1"); app.run(); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } tntnet-3.0/demo/accumulator/tntnet.xml000066400000000000000000000045071365471676700202250ustar00rootroot00000000000000 8000 INFO tntnet INFO component.accumulator INFO tntnet-3.0/demo/calc/000077500000000000000000000000001365471676700145445ustar00rootroot00000000000000tntnet-3.0/demo/calc/Makefile.am000066400000000000000000000005621365471676700166030ustar00rootroot00000000000000bin_PROGRAMS = calc calc_SOURCES = \ calc.ecpp \ main.cpp AM_CPPFLAGS = -I$(top_srcdir)/framework/common calc_LDADD = $(top_builddir)/framework/common/libtntnet.la -lcxxtools noinst_DATA = tntnet.xml dist_noinst_DATA = README CLEANFILES = calc.cpp ECPPC=$(top_builddir)/sdk/tools/ecppc/ecppc SUFFIXES=.ecpp .cpp .ecpp.cpp: $(ECPPC) $(AM_V_GEN)$(ECPPC) -o $@ $< tntnet-3.0/demo/calc/README000066400000000000000000000007101365471676700154220ustar00rootroot00000000000000Demo-application "calc" ======================== This application shows, how arguments are converted to streameable types. It demonstrates a simple calculator-application. To run the application enter "tntnet" in this directory. If you have not yet installed but only built tntnet, you need to enter the path to the generated tntnet-program: "../../../framework/runtime/tntnet" You can see the result in your browser at http://localhost:8000/calc tntnet-3.0/demo/calc/calc.ecpp000066400000000000000000000024771365471676700163310ustar00rootroot00000000000000<%args> double arg1 = 0; // typed parameter with default value double arg2 = 0; // typed parameter with default value bool plus; // bool arguments for buttons bool minus; bool mul; bool div; <%cpp> // <= this starts a c++-processing-block double result = 0.0; char op = '\0'; if (plus) { result = arg1 + arg2; op = '+'; } else if (minus) { result = arg1 - arg2; op = '-'; } else if (mul) { result = arg1 * arg2; op = '*'; } else if (div) { result = arg1 / arg2; op = '/'; } <# <= this terminates a c++-processing-block (and this is a ecpp-comment) #> Calculator

Tommi's Tnt-Calculator

<# you can output other types as well - arg1 and arg2 are of type double. They just need a outputstream-operator #>

% if (op) { // '%' in the first column makes a c++-one-liner
<$arg1$> <$op$> <$arg2$> = <$result$> % } tntnet-3.0/demo/calc/main.cpp000066400000000000000000000035201365471676700161740ustar00rootroot00000000000000/* * Copyright (C) 2018 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include int main(int argc, char* argv[]) { try { std::ifstream in("tntnet.xml"); tnt::TntConfig config; in >> cxxtools::xml::Xml(config); tnt::Tntnet app(config); app.mapUrl("^/$", "calc"); app.mapUrl("^/(.*)$", "$1"); app.run(); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } tntnet-3.0/demo/calc/tntnet.xml000066400000000000000000000015011365471676700165770ustar00rootroot00000000000000 8000 INFO tntnet INFO component.calc INFO tntnet-3.0/demo/calcajax/000077500000000000000000000000001365471676700154105ustar00rootroot00000000000000tntnet-3.0/demo/calcajax/.gitignore000066400000000000000000000000131365471676700173720ustar00rootroot00000000000000jquery.cpp tntnet-3.0/demo/calcajax/Makefile.am000066400000000000000000000010261365471676700174430ustar00rootroot00000000000000bin_PROGRAMS = calcajax calcajax_SOURCES = \ calcajax.ecpp \ calcajax_js.js \ docalc.ecpp \ jquery.js \ main.cpp AM_CPPFLAGS = -I$(top_srcdir)/framework/common calcajax_LDFLAGS = calcajax_LDADD = $(top_builddir)/framework/common/libtntnet.la -lcxxtools noinst_DATA = tntnet.xml CLEANFILES = calcajax.cpp calcajax_js.cpp docalc.cpp SUFFIXES=.ecpp .js .cpp .ecpp.cpp: $(AM_V_GEN)$(top_builddir)/sdk/tools/ecppc/ecppc -o $@ $< .js.cpp: $(AM_V_GEN)$(top_builddir)/sdk/tools/ecppc/ecppc -m application/x-javascript -b -o $@ $< tntnet-3.0/demo/calcajax/calcajax.ecpp000066400000000000000000000013561365471676700200340ustar00rootroot00000000000000 Calculator

Tommi's Tnt-Calculator



tntnet-3.0/demo/calcajax/calcajax_js.js000066400000000000000000000014231365471676700202100ustar00rootroot00000000000000$(function() { function calc(op) { $.getJSON('/docalc', { arg1 : $('#arg1').val(), arg2 : $('#arg2').val(), op : op }, function(result) { if (result.resultOk) { $('#outarg1').html(result.arg1); $('#outarg2').html(result.arg2); $('#outop').html(result.op); $('#outresult').html(result.result); $('#result').show(); } else { $('#result').hide(); } }); } $('#plus').click(function() { calc('+') }); $('#minus').click(function() { calc('-') }); $('#mul').click(function() { calc('*') }); $('#div').click(function() { calc('/') }); }); tntnet-3.0/demo/calcajax/docalc.ecpp000066400000000000000000000022431365471676700175070ustar00rootroot00000000000000<%pre> #include namespace { struct Result { double arg1; double arg2; char op; double result; bool resultOk; }; // serialization operator needed in JsonSerializer void operator<<= (cxxtools::SerializationInfo& si, const Result& result) { si.addMember("arg1") <<= result.arg1; si.addMember("arg2") <<= result.arg2; si.addMember("op") <<= result.op; si.addMember("result") <<= result.result; si.addMember("resultOk") <<= result.resultOk; } } <%args> double arg1; double arg2; char op; <%cpp> Result result; result.arg1 = arg1; result.arg2 = arg2; result.result = 0.0; result.resultOk = true; result.op = op; switch (result.op) { case '+': result.result = arg1 + arg2; break; case '-': result.result = arg1 - arg2; break; case '*': result.result = arg1 * arg2; break; case '/': if (arg2 == 0) result.resultOk = false; else result.result = arg1 / arg2; break; default: result.resultOk = false; } cxxtools::JsonSerializer serializer(reply.out()); serializer.serialize(result) .finish(); tntnet-3.0/demo/calcajax/jquery.js000066400000000000000000001576461365471676700173100ustar00rootroot00000000000000/* * jQuery JavaScript Library v1.3.2 * http://jquery.com/ * * Copyright (c) 2009 John Resig * Dual licensed under the MIT and GPL licenses. * http://docs.jquery.com/License * * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009) * Revision: 6246 */ (function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("",""]||!O.indexOf("",""]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"","
"]||!O.indexOf("",""]||(!O.indexOf("",""]||!O.indexOf("",""]||!o.support.htmlSerialize&&[1,"div
","
"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}}); /* * Sizzle CSS Selector Engine - v0.9.3 * Copyright 2009, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * More information: http://sizzlejs.com/ */ (function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return UT[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="

";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="
";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("
").append(M.responseText.replace(//g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='
';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})();tntnet-3.0/demo/calcajax/main.cpp000066400000000000000000000035241365471676700170440ustar00rootroot00000000000000/* * Copyright (C) 2018 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include int main(int argc, char* argv[]) { try { std::ifstream in("tntnet.xml"); tnt::TntConfig config; in >> cxxtools::xml::Xml(config); tnt::Tntnet app(config); app.mapUrl("^/$", "calcajax"); app.mapUrl("^/(.*)$", "$1"); app.run(); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } tntnet-3.0/demo/calcajax/tntnet.xml000066400000000000000000000045711365471676700174550ustar00rootroot00000000000000 8000 INFO tntnet INFO component.calcajax INFO .libs tntnet-3.0/demo/calcapp/000077500000000000000000000000001365471676700152455ustar00rootroot00000000000000tntnet-3.0/demo/calcapp/Makefile.am000066400000000000000000000006611365471676700173040ustar00rootroot00000000000000noinst_PROGRAMS = calc noinst_DATA = tntnet.properties calc_SOURCES = \ calc.ecpp \ main.cpp EXTRA_DIST = \ calc.ecpp AM_CPPFLAGS = -I$(top_srcdir)/framework/common calc_LDADD = $(top_builddir)/framework/common/libtntnet.la -lcxxtools CLEANFILES = calc.cpp tntnet.properties SUFFIXES=.ecpp .cpp .ecpp.cpp: $(AM_V_GEN)$(top_builddir)/sdk/tools/ecppc/ecppc -o $@ $< tntnet.properties: $(AM_V_GEN)echo "rootlogger=INFO" > $@ tntnet-3.0/demo/calcapp/calc.ecpp000066400000000000000000000024221365471676700170200ustar00rootroot00000000000000<%args> double arg1 = 0; // typed parameter with default value double arg2 = 0; // typed parameter with default value char op = ' '; // typed parameter with default value <%cpp> // <= this starts a c++-processing-block double result = 0.0; bool result_ok = true; switch (op) { case '+': result = arg1 + arg2; break; case '-': result = arg1 - arg2; break; case '*': result = arg1 * arg2; break; case '/': result = arg1 / arg2; break; default: result_ok = false; } <# <= this terminates a c++-processing-block (and this is a ecpp-comment) #> Calculator

Tommi's Tnt-Calculator

<# you can output other types as well - arg1 and arg2 are of type double. They just need a outputstream-operator #>

% if (result_ok) { // '%' in the first column makes a c++-one-liner
<$arg1$> <$op$> <$arg2$> = <$result$> % } tntnet-3.0/demo/calcapp/main.cpp000066400000000000000000000065431365471676700167050ustar00rootroot00000000000000/* * Copyright (C) 2010 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** This demo shows how to create a standalone application server just with libtntnet. Normally applications are compiled into shared libraries and loaded at runtime. Configuration, especially the mapping from url to component, is done with tntnet.xml. As an alternative you may write your own small main function and compile the components into a program. There is no configuration file tntnet.xml read any more but you have to code your mappings into the program. The advantage is, that there is no configuration file needed. Since the mappings are often a fundamental part of your application, it is better to hard code it into the application. */ #include #include #include #include #include int main(int argc, char* argv[]) { try { // read listen ip from command line switch -l with default to empty, which means: all interfaces cxxtools::Arg ip(argc, argv, 'l'); // read listen port from command line switch -p with default to 8000 cxxtools::Arg port(argc, argv, 'p', 8000); // initialize logging - this is optional. If log_init is not called, // logging is disabled log_init("tntnet.properties"); // instantiate the tnt::Tntnet application class tnt::Tntnet app; app.setAppName("calc"); // set up your mappings app.mapUrl("^/$", "calc"); // the next mapping is only valid, when the method is "GET" (or more precisely // matches the regular expression "GET" - it may be GETTY or something) app.mapUrl("^/foo$", "calc") .setMethod("GET"); app.mapUrl("^/([^.]+)(..+)?", "$1"); // set more settings tnt::TntConfig::it().minThreads = 3; tnt::TntConfig::it().sessionTimeout = 600; // configure listener app.listen(ip, port); // note that a empty ip address tells tntnet to listen on all local interfaces // run the application app.run(); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } tntnet-3.0/demo/calcmvc/000077500000000000000000000000001365471676700152525ustar00rootroot00000000000000tntnet-3.0/demo/calcmvc/Makefile.am000066400000000000000000000012001365471676700172770ustar00rootroot00000000000000bin_PROGRAMS = calcmvc AUTOMAKE_OPTIONS = subdir-objects calcmvc_SOURCES = \ calcmvc.ecpp \ controller/accumulator.cpp \ controller/calc.cpp \ main.cpp \ view/accumulator.ecpp \ view/calc.ecpp noinst_HEADERS = \ model/accumulator.h \ model/calc.h AM_CPPFLAGS = -I$(top_srcdir)/framework/common -I. calcmvc_LDFLAGS = -module @SHARED_LIB_FLAG@ calcmvc_LDADD = $(top_builddir)/framework/common/libtntnet.la -lcxxtools dist_noinst_DATA = tntnet.xml CLEANFILES = calcmvc.cpp view/accumulator.cpp view/calc.cpp ECPPC=$(top_builddir)/sdk/tools/ecppc/ecppc SUFFIXES=.ecpp .cpp .ecpp.cpp: $(AM_V_GEN)$(ECPPC) -o $@ -p -I $(srcdir) $< tntnet-3.0/demo/calcmvc/calcmvc.ecpp000066400000000000000000000003471365471676700175370ustar00rootroot00000000000000 Calculator <& (request.getPathInfo()) qparam > tntnet-3.0/demo/calcmvc/controller/000077500000000000000000000000001365471676700174355ustar00rootroot00000000000000tntnet-3.0/demo/calcmvc/controller/accumulator.cpp000066400000000000000000000014721365471676700224640ustar00rootroot00000000000000/* * Copyright (C) 2012 Tommi Maekitalo * */ #include #include #include #include #include namespace controller { class Accumulator : public tnt::Component { public: unsigned operator() (tnt::HttpRequest& request, tnt::HttpReply& reply, tnt::QueryParams& qparam); }; static tnt::ComponentFactoryImpl factory("controller/accumulator"); unsigned Accumulator::operator() (tnt::HttpRequest& request, tnt::HttpReply& reply, tnt::QueryParams& qparam) { TNT_SESSION_SHARED_VAR(model::Accumulator, accumulator, ()); if (qparam.get("increment")) accumulator.increment(); if (qparam.get("decrement")) accumulator.decrement(); return DECLINED; } } tntnet-3.0/demo/calcmvc/controller/calc.cpp000066400000000000000000000023561365471676700210510ustar00rootroot00000000000000/* * Copyright (C) 2012 Tommi Maekitalo * */ #include #include #include #include #include namespace controller { class Calc : public tnt::Component { public: unsigned operator() (tnt::HttpRequest& request, tnt::HttpReply& reply, tnt::QueryParams& qparam); }; static tnt::ComponentFactoryImpl factory("controller/calc"); unsigned Calc::operator() (tnt::HttpRequest& request, tnt::HttpReply& reply, tnt::QueryParams& qparam) { TNT_REQUEST_SHARED_VAR(model::Calc, calc, ()); calc.arg1(qparam.get("arg1")); calc.arg2(qparam.get("arg2")); calc.op(qparam.get("op")); calc.resultOk(true); switch (calc.op()) { case '+': calc.result(calc.arg1() + calc.arg2()); break; case '-': calc.result(calc.arg1() - calc.arg2()); break; case '*': calc.result(calc.arg1() * calc.arg2()); break; case '/': if (calc.arg2() == 0) calc.resultOk(false); else calc.result(calc.arg1() / calc.arg2()); break; default: calc.resultOk(false); } return DECLINED; } } tntnet-3.0/demo/calcmvc/main.cpp000066400000000000000000000037661365471676700167160ustar00rootroot00000000000000/* * Copyright (C) 2018 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include int main(int argc, char* argv[]) { try { std::ifstream in("tntnet.xml"); tnt::TntConfig config; in >> cxxtools::xml::Xml(config); tnt::Tntnet app(config); app.mapUrl("^/$", "redirect@tntnet") .setPathInfo("/calc"); app.mapUrl("^/(.*)$", "controller/$1") .setMethod("^POST$"); app.mapUrl("^/(.*)$", "calcmvc") .setPathInfo("view/$1"); app.run(); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } tntnet-3.0/demo/calcmvc/model/000077500000000000000000000000001365471676700163525ustar00rootroot00000000000000tntnet-3.0/demo/calcmvc/model/accumulator.h000066400000000000000000000006101365471676700210370ustar00rootroot00000000000000/* * Copyright (C) 2012 Tommi Maekitalo * */ #ifndef MODEL_ACCUMULATOR_H #define MODEL_ACCUMULATOR_H namespace model { class Accumulator { int _value; public: Accumulator() : _value(0) { } int value() const { return _value; } void increment() { ++_value; } void decrement() { --_value; } }; } #endif // MODEL_ACCUMULATOR_H tntnet-3.0/demo/calcmvc/model/calc.h000066400000000000000000000015251365471676700174300ustar00rootroot00000000000000/* * Copyright (C) 2012 Tommi Maekitalo * */ #ifndef MODEL_CALC_H #define MODEL_CALC_H namespace model { class Calc { double _arg1; double _arg2; char _op; double _result; bool _resultOk; public: Calc() : _arg1(0), _arg2(0), _resultOk(false) { } void arg1(double v) { _arg1 = v; } void arg2(double v) { _arg2 = v; } void op(char v) { _op = v; } void result(double v) { _result = v; } void resultOk(bool v) { _resultOk = v; } double arg1() const { return _arg1; } double arg2() const { return _arg2; } char op() const { return _op; } double result() const { return _result; } bool resultOk() const { return _resultOk; } }; } #endif // MODEL_CALC_H tntnet-3.0/demo/calcmvc/tntnet.xml000066400000000000000000000010531365471676700173070ustar00rootroot00000000000000 8000 INFO tntnet INFO component.calcmvc INFO tntnet-3.0/demo/calcmvc/view/000077500000000000000000000000001365471676700162245ustar00rootroot00000000000000tntnet-3.0/demo/calcmvc/view/accumulator.ecpp000066400000000000000000000004601365471676700214140ustar00rootroot00000000000000<%session scope="shared" include="model/accumulator.h"> model::Accumulator accumulator;

Accumulator

value=<$ accumulator.value() $>
tntnet-3.0/demo/calcmvc/view/calc.ecpp000066400000000000000000000012741365471676700200030ustar00rootroot00000000000000<%request scope="shared" include="model/calc.h"> model::Calc calc;

Tommi's Tnt-Calculator

<# you can output other types as well - arg1 and arg2 are of type double. They just need a outputstream-operator #>

% if (calc.resultOk()) {
<$ calc.arg1() $> <$ calc.op() $> <$ calc.arg2() $> = <$ calc.result() $> % } tntnet-3.0/demo/comp/000077500000000000000000000000001365471676700146005ustar00rootroot00000000000000tntnet-3.0/demo/comp/Makefile.am000066400000000000000000000013721365471676700166370ustar00rootroot00000000000000pkglib_LTLIBRARIES = comp.la extlib.la comp_la_SOURCES = \ comp.ecpp \ subcomp.ecpp extlib_la_SOURCES = \ extcomp.ecpp AM_CPPFLAGS = -I$(top_srcdir)/framework/common comp_la_LDFLAGS = -module @SHARED_LIB_FLAG@ comp_la_LIBADD = $(top_builddir)/framework/common/libtntnet.la extlib_la_LDFLAGS = -module extlib_la_LIBADD = $(top_builddir)/framework/common/libtntnet.la noinst_DATA = tntnet.xml dist_noinst_DATA = README CLEANFILES = comp.cpp subcomp.cpp extcomp.cpp \ tntnet.xml SUFFIXES=.ecpp .cpp .ecpp.cpp: $(AM_V_GEN)$(top_builddir)/sdk/tools/ecppc/ecppc -o $@ $< tntnet.xml: $(AM_V_GEN)$(SHELL) $(top_builddir)/misc/tntnet-project --config=comp|$(AWK) '/<\/tntnet>/{print " \n .libs\n "} {print}' >$@ tntnet-3.0/demo/comp/README000066400000000000000000000010011365471676700154500ustar00rootroot00000000000000Demo-application "subcomp" ========================== This application shows various ways to embed subcomponents into a page and how to pass parameters to them. To run the application enter "tntnet" in this directory. If you have not yet installed but only built tntnet, you need to enter the path to the generated tntnet-program: "../../../framework/runtime/tntnet" You can see the result (various examples, how to ebed components including an explanation) in your browser at http://localhost:8000/comp tntnet-3.0/demo/comp/comp.ecpp000066400000000000000000000114301365471676700164060ustar00rootroot00000000000000

Calling subcomponents

Ecpp-pages can embed other pages. These embedded pages are called subcomponents. They come in 2 variants: local and external. Local subcomponents are defined inside another component with <%def componentname> and closed with </def>. External subcomponents are normal components.

A subcomponentcall starts with <& and ends with &>. Insert the componentname between these tags. If you omit the library-part of the component, the current library is used. If the componentname is a single word, ecpp looks for a local component, which is called if found. Otherwise it is a external componentcall.

You can dynamically build componentnames, by putting a c++-expression inside brackets. This expression is evaluated on runtime and the resulting component is called. The expression can be of type (or convertable to) std::string, tnt::Compident or tnt::Subcompident.

After the componentname you can add named parameters. Put a name followed by '=' and a value. The value is either a constant string or a expression. A expression must be bracketed. If you want to pass just the same parameters your current component received, put the single word qparam into the list (actually you can pass any cxxtools::query_params-variable).

A special case are local components, which have c++-parameters. You can put a normal parameterlist just like in c++-functions after the defition (<%def>-block) after the componentname. The can only be called locally.

Just a local componentcall

<& localcomp param1="value1" &>

<& localcomp param1="value1" &>

Another local componentcall. We pass a c++-parameter.

<& localcomp_p(5) &>

<& localcomp_p(5) >

A external componentcall (localcomp "extcomp" does not exist)

<& subcomp param1="value1" &>

<& subcomp param1="value1" &>

a external componentcall

<& extcomp@extlib param1="value1" &>

<& extcomp@extlib param1="value1" &>

a external subcomponentcall

<& extcomp.subcomp@extlib param1="value1" &>

<& extcomp.subcomp@extlib param1="value1" &>

compose componentname by expression

<{ // define some variables here std::string compname = "extcomp"; std::string libname = "extlib"; }>

<& (compname + '@' + libname) param1="value1" &>

<& (compname + '@' + libname) param1="value1" &>

call component by componentidentifier

<& (tnt::Compident(compname, libname)) param1="value1" &>

<& (tnt::Compident(libname, compname)) param1="value1" &>

pass a expression as parameter

<& localcomp param1=(1+5) qparam param2="uhu"&>

<& localcomp param1=(1+5) qparam param2="uhu"&>

pass multiple values with the same name as parameter

<& localcomp param3[]="value1" param3[]="value2" param4[]="17" param4[]=(28) &>

<& localcomp param3[]="value1" param3[]="value2" param4[]="17" param4[]=(28) &>

call subcomponents in c++-blocks

callComp("extcomp@extlib", request, reply, qparam);

<{ callComp("extcomp@extlib", request, reply, qparam); }>

<%def localcomp> <%args> param1; param2; param3[]; int param4[]; This is a local subcomponent. We got a parameter param1 with the value <$param1$>. % if (!param2.empty()) { We got param2 also. Its value is <$param2$>. % } We got <$ param3.size() $> times "param3" and <$ param4.size() $> times "param4". The values of param3 are: <{ std::copy(param3.begin(), param3.end(), std::ostream_iterator(reply.out(), ", ")); }>. The values of param4 are: <{ std::copy(param4.begin(), param4.end(), std::ostream_iterator(reply.out(), ", ")); }>. <%def localcomp_p(int i)> This is a local subcomponent with parameter. We got a c++-integer-parameter with the value <$i$>. This component can only be called locally because of c++-parameters. tntnet-3.0/demo/comp/extcomp.ecpp000066400000000000000000000001631365471676700171300ustar00rootroot00000000000000Here is a component extcomp <%def subcomp> Here is a subcomponent subcomp of extcomp tntnet-3.0/demo/comp/subcomp.ecpp000066400000000000000000000000201365471676700171110ustar00rootroot00000000000000Here is subcomp tntnet-3.0/demo/cookie/000077500000000000000000000000001365471676700151135ustar00rootroot00000000000000tntnet-3.0/demo/cookie/Makefile.am000066400000000000000000000005471365471676700171550ustar00rootroot00000000000000bin_PROGRAMS = cookie cookie_SOURCES = \ cookie.ecpp \ main.cpp AM_CPPFLAGS = -I$(top_srcdir)/framework/common cookie_LDADD = $(top_builddir)/framework/common/libtntnet.la -lcxxtools noinst_DATA = tntnet.xml dist_noinst_DATA = README CLEANFILES = cookie.cpp ECPPC=$(top_builddir)/sdk/tools/ecppc/ecppc .ecpp.cpp: $(ECPPC) $(AM_V_GEN)$(ECPPC) -o $@ $< tntnet-3.0/demo/cookie/README000066400000000000000000000007171365471676700160000ustar00rootroot00000000000000Demo-application "cookie" ======================== This application extends the "hello"-demo-application with cookie-support. The entered name is stored in a cookie for 1 hour. To run the application enter "tntnet" in this directory. If you have not yet installed but only built tntnet, you need to enter the path to the generated tntnet-program: "../../../framework/runtime/tntnet" You can see the result in your browser at http://localhost:8000/cookie tntnet-3.0/demo/cookie/cookie.ecpp000066400000000000000000000017261365471676700172430ustar00rootroot00000000000000<# This is a simple hello-world-application with cookie-support It stores the name in a cookie #> <%args> name; // define query-parameter // this defines a variable of type std::string with // the name "name" bool clearcookie; <%cpp> if (name.empty()) name = request.getCookie("name"); if (clearcookie) { reply.clearCookie("name"); // delete cookie from client } else if (!name.empty() && request.getCookie("name").getValue() != name) { reply.setCookie("name", name, 3600); // set cookie when new or modified } Hello World-application for tntnet

Hello <$ name.empty() ? "World" : name $>

What's your name?
reload tntnet-3.0/demo/cookie/main.cpp000066400000000000000000000035761365471676700165560ustar00rootroot00000000000000/* * Copyright (C) 2018 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include int main(int argc, char* argv[]) { try { std::ifstream in("tntnet.xml"); tnt::TntConfig config; in >> cxxtools::xml::Xml(config); log_init(config.logConfiguration); tnt::Tntnet app(config); app.mapUrl("^/$", "cookie"); app.mapUrl("^/(.*)$", "$1"); app.run(); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } tntnet-3.0/demo/gd/000077500000000000000000000000001365471676700142345ustar00rootroot00000000000000tntnet-3.0/demo/gd/Makefile.am000066400000000000000000000007101365471676700162660ustar00rootroot00000000000000bin_PROGRAMS = gd gd_SOURCES = \ gd++.cpp \ gd.ecpp \ imgstr.ecpp \ main.cpp include_HEADERS = \ gd++.h AM_CPPFLAGS = -I$(top_srcdir)/framework/common gd_LDFLAGS = -lgd gd_LDADD = $(top_builddir)/framework/common/libtntnet.la -lcxxtools noinst_DATA = tntnet.xml dist_noinst_DATA = README CLEANFILES = gd.cpp imgstr.cpp tntnet.cpp ECPPC=$(top_builddir)/sdk/tools/ecppc/ecppc SUFFIXES=.ecpp .cpp .ecpp.cpp: $(ECPPC) $(AM_V_GEN)$(ECPPC) -o $@ $< tntnet-3.0/demo/gd/README000066400000000000000000000021401365471676700151110ustar00rootroot00000000000000gd demo Tntnet application ========================== This application demonstrates the use of dynamically generated images in tntnet. The dynamically generated images uses the famous GD Graphics Library from Boutell.Com. To make it more C++ style, we created a small C++ wrapper around that. The application has 2 parts: the html screen `gd.ecpp`, which displays a form and the generated image and the actual image creation component `imgstr.ecpp`. The image creation component expects a query parameter `str` and generates a image with that text drawn into a small image. For output the png format is used. Building and running -------------------- To build the application you need to install tntnet and gd. For common linux distributions you need the development package of gd, which contains the headers and link libraries. The package is named gd-devel in fedora at least. Running `make` build the application and running `gd` starts the server. You can access the application using a browser using the url http://localhost:8000/ or the hostname of the server if you want to access the application remotely. tntnet-3.0/demo/gd/gd++.cpp000066400000000000000000000076431365471676700154720ustar00rootroot00000000000000/* * Copyright (C) 2012 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include namespace gd { Gd::Gd(int x, int y, bool trueColor) : _imagePtr(0) { if (trueColor) _imagePtr = gdImageCreateTrueColor(x, y); else _imagePtr = gdImageCreate(x, y); } Gd::~Gd() { if (_imagePtr) gdImageDestroy(_imagePtr); } int Gd::colorAllocate(int r, int g, int b) { int ret = gdImageColorAllocate(_imagePtr, r, g, b); if (ret == -1) { std::ostringstream msg; msg << "failed to allocate new color (" << r << ", " << g << ", " << b << ')'; throw std::runtime_error(msg.str()); } return ret; } void Gd::setThickness(int thickness) { gdImageSetThickness(_imagePtr, thickness); } void Gd::setAntiAliased(int color) { gdImageSetAntiAliased(_imagePtr, color); } void Gd::line(int x1, int y1, int x2, int y2, int color) { gdImageLine(_imagePtr, x1, y1, x2, y2, color); } void Gd::filledRectangle(int x1, int y1, int x2, int y2, int color) { gdImageFilledRectangle(_imagePtr, x1, y1, x2, y2, color); } void Gd::arc(int cx, int cy, int w, int h, int s, int e, int color) { gdImageArc(_imagePtr, cx, cy, w, h, s, e, color); } void Gd::drawChar(int x, int y, char ch, int color, FontStyle style) { gdFontPtr font = style == FontTiny ? gdFontGetTiny() : style == FontSmall ? gdFontGetSmall() : style == FontMedium ? gdFontGetMediumBold() : style == FontLarge ? gdFontGetLarge() : style == FontGiant ? gdFontGetGiant() : gdFontGetMediumBold(); gdImageChar(_imagePtr, font, x, y, ch, color); } void Gd::drawString(int x, int y, const char* str, int color, FontStyle style) { gdFontPtr font = style == FontTiny ? gdFontGetTiny() : style == FontSmall ? gdFontGetSmall() : style == FontMedium ? gdFontGetMediumBold() : style == FontLarge ? gdFontGetLarge() : style == FontGiant ? gdFontGetGiant() : gdFontGetMediumBold(); gdImageString(_imagePtr, font, x, y, const_cast(reinterpret_cast(str)), color); } namespace { int ostreamOut(void* context, const char* buffer, int len) { std::ostream* outPtr = reinterpret_cast(context); outPtr->write(buffer, len); return *outPtr ? len : -1; } } void Gd::printPng(std::ostream& out) const { gdSink sink; sink.sink = ostreamOut; sink.context = &out; gdImagePngToSink(_imagePtr, &sink); } } tntnet-3.0/demo/gd/gd++.h000066400000000000000000000022071365471676700151260ustar00rootroot00000000000000/* * Copyright (C) 2012 Tommi Maekitalo * */ #ifndef GDPP_H #define GDPP_H #include #include namespace gd { class Gd { gdImagePtr _imagePtr; // disable copy and assignment Gd(const Gd&); const Gd& operator=(const Gd&); public: Gd(int x, int y, bool trueColor = false); ~Gd(); int colorAllocate(int r, int g, int b); void setThickness(int thickness); void setAntiAliased(int color); void line(int x1, int y1, int x2, int y2, int color); void filledRectangle(int x1, int y1, int x2, int y2, int color); void arc(int cx, int cy, int w, int h, int s, int e, int color); enum FontStyle { FontTiny, FontSmall, FontMedium, FontLarge, FontGiant }; void drawChar(int x, int y, char ch, int color, FontStyle style = FontMedium); void drawString(int x, int y, const char* str, int color, FontStyle style = FontMedium); void printPng(std::ostream& out) const; }; inline std::ostream& operator<< (std::ostream& out, const Gd& img) { img.printPng(out); return out; } } #endif // GDPP_H tntnet-3.0/demo/gd/gd.ecpp000066400000000000000000000024601365471676700155010ustar00rootroot00000000000000<%args> str = "Hello"; red = "255"; green = "0"; blue = "0"; <%cpp> /* we could put the string directly to the img tag using: but then the string is not correctly url encoded. Hence we build a QueryParams object which has a method getUrl(), which returns a url encoded string with the parameters. */ cxxtools::QueryParams q; q.add("str", str); q.add("red", red); q.add("green", green); q.add("blue", blue); ecpp-application gd

gd demo application

This application demostrates how to create graphics dynamically in tntnet using the famous gd library.

Text
Red
Green
Blue

tntnet-3.0/demo/gd/imgstr.ecpp000066400000000000000000000011001365471676700164020ustar00rootroot00000000000000<%args> str = "Hello"; unsigned x = 200; unsigned y = 20; int red = 255; int green = 0; int blue = 0; <%pre> #include "gd++.h" <%cpp> // create image gd::Gd image(x, y); // allocate background color (background color is the first allocated color in gd) int white = image.colorAllocate(255, 255, 255); // allocate color for string int color = image.colorAllocate(red, green, blue); // write text to image image.drawString(0, 0, str.c_str(), color); // output image reply.setContentType("image/png"); reply.out() << image; tntnet-3.0/demo/gd/main.cpp000066400000000000000000000035721365471676700156730ustar00rootroot00000000000000/* * Copyright (C) 2018 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include int main(int argc, char* argv[]) { try { std::ifstream in("tntnet.xml"); tnt::TntConfig config; in >> cxxtools::xml::Xml(config); log_init(config.logConfiguration); tnt::Tntnet app(config); app.mapUrl("^/$", "gd"); app.mapUrl("^/(.*)$", "$1"); app.run(); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } tntnet-3.0/demo/hello/000077500000000000000000000000001365471676700147455ustar00rootroot00000000000000tntnet-3.0/demo/hello/Makefile.am000066400000000000000000000007151365471676700170040ustar00rootroot00000000000000bin_PROGRAMS = hello hello_SOURCES = \ hello.ecpp \ main.cpp \ tntnet.png AM_CPPFLAGS = -I$(top_srcdir)/framework/common hello_LDADD = $(top_builddir)/framework/common/libtntnet.la -lcxxtools noinst_DATA = tntnet.xml dist_noinst_DATA = README CLEANFILES = hello.cpp tntnet.cpp ECPPC=$(top_builddir)/sdk/tools/ecppc/ecppc SUFFIXES=.ecpp .png .cpp .ecpp.cpp: $(ECPPC) $(AM_V_GEN)$(ECPPC) -o $@ $< .png.cpp: $(AM_V_GEN)$(ECPPC) -b -m image/png -o $@ $< tntnet-3.0/demo/hello/README000066400000000000000000000007531365471676700156320ustar00rootroot00000000000000Demo-application "hello" ======================== This application shows a very simple form and how to process arguments received from the form. It also shows how to compile a image into the application. To run the application enter "tntnet" in this directory. If you have not yet installed but only built tntnet, you need to enter the path to the generated tntnet-program: "../../../framework/runtime/tntnet" You can see the result in your browser at http://localhost:8000/hello tntnet-3.0/demo/hello/hello.ecpp000066400000000000000000000005711365471676700167240ustar00rootroot00000000000000<# this is a simple hello-world-application #> <%args> name = "World"; Hello World-application for tntnet

Hello <$ name $>

What's your name?
tntnet-3.0/demo/hello/img.gif000066400000000000000000000004331365471676700162100ustar00rootroot00000000000000GIF89ah!Created with The GIMP! ,hٌڋ޼HڴmS[y뱄 HI&rcBldF0>hJTY5spwVp,]NZ 85Te8g5Wɳ#SH)%Yi'Gԙ)f++U8W) <;GYlGͪEU׍]/?O_oP;tntnet-3.0/demo/hello/main.cpp000066400000000000000000000035751365471676700164070ustar00rootroot00000000000000/* * Copyright (C) 2018 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include int main(int argc, char* argv[]) { try { std::ifstream in("tntnet.xml"); tnt::TntConfig config; in >> cxxtools::xml::Xml(config); log_init(config.logConfiguration); tnt::Tntnet app(config); app.mapUrl("^/$", "hello"); app.mapUrl("^/(.*)$", "$1"); app.run(); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } tntnet-3.0/demo/hello/tntnet.png000066400000000000000000000070051365471676700167710ustar00rootroot00000000000000PNG  IHDRU] sBIT|d IDATx}xT՝?gfJDBQ yلHаu@E)V_ԺSѢ4(nQX-`Y@&ؕP6@B1Dd6y=5`f@2ɝ{_s%ߜsϹ~s K1$%4)I4B)%BЊGԵwS~٨Xi/7ɠseNNLJJz%AFsD[ϲI-zo*:GHm2a evVoZ$Ndݾ i[@o͝> p/<‖ZFx qYAֆszbCy- Z6&Ҵz\ikk"&uλ=1I4r;߱8c*÷xOIoa[{7-#*gT~*^ ?R(  ̼7jK] _Ndχc4tCŠܣ2.&9j|R|OU#U]$!JoOtmxN>n""H񮯙3RGk⿞!KQ0HsQv2\ O?-JȔq3 쾖@3LTNxҝ"0\fs;_H CCjkHuty7|M|r6hfp<pS`?)ݹ+/sWK?W=1biic} jx"̓@V;_dQZu ^ӳ4Ax<+_pFVdb|199nlcZn|b.LOVz\]8<0) .;RB^Nc+Y9!66ofZ^(TQ'l\x3QÑ/.g~NV4x53y=cs }KzYK2vlRPc?G+cկohaIY*9tmU;䌪X?_}7*wLK¼J=X&Ur_ L [IS_U2r;$1ot<=SP8soT)ݵ%ayRhl.}OZxXu'ĨL:4y[5ܽ'-Fӑ#L4&TImmׇhѥ^Hά=G\J@BocĘXt)WWm[J0bLB3(aFGGdɒ+.]bӦMZF[hfKgϞͭz]Bְ0bL'SX)%%%%j}'{ye۶m,X@ce3R1 7&Ox̟?+lB}}c>ekzꧮU6Fi(x#){#4X|Ʌ+, EEEqb#D7- (,,ZG1bLAWGOF1]~4Aw-c7MϏ&Gtսr ,tLO>Wn`Z~=_9/v~8R;0-&/ ]/&+4:s^v"O)8&lrP\N5+'^b$=&{O:j]BtqX3Gč4^m5#buO3ߛ~XYհd2}Rӑ ק = V24, |.%q 0[l3PfC/[ !@ecee&sik tk<Y0&/%CܝTiz%lU9bU;y8"~b(y\k8і` =y]^8qL(8e`[ONCJցo=`H9?/[]xfI,p{`'ަAyb6;l9b&L;TܧHޜ$-=7|tVY=Rw2Q~g7xOG9ӧhAgG,f䬛ybzCGW3SEDO+{~ʱ뎔׹^{*C`׻YJ׺[e `6T~"G G c<;RY`Bup~]1Vd0,^%骺dD)~N8 L\iXEn ˃tu)0i5ݽva W-^mr٭2@HQnES[zA\63❂t Ee_ė$9/l\zիh!@45>+ }!4K9&bpuN}庌f;/P9X/)W|p'&7$%>F7/CQJ~|bgvT2hh pz%<.0 q]NqT7+bP6u@C qa,_Hőxpi8^)1^?o++Y1Zk&Q\ǚr2pg19+kN52E$`h>Oť9Єx\~+y-%tp8-g#Qqʋ2oVn܎G #.HID'~ 4 f5Nfk7IXo`"i |T0ɑlw2#J7T˴!",` ` 6s91T1e~8?:THIENDB`tntnet-3.0/demo/hello/tntnet.xml000066400000000000000000000015511365471676700170050ustar00rootroot00000000000000 8000 INFO tntnet INFO component.hello INFO tntnet-3.0/demo/newsdb/000077500000000000000000000000001365471676700151245ustar00rootroot00000000000000tntnet-3.0/demo/newsdb/Makefile.am000066400000000000000000000010121365471676700171520ustar00rootroot00000000000000bin_PROGRAMS = newsdb newsdb_SOURCES = \ index.ecpp \ main.cpp \ news.ecpp \ newscss.css AM_CPPFLAGS = -I$(top_srcdir)/framework/common newsdb_LDFLAGS = -ltntdb newsdb_LDADD = $(top_builddir)/framework/common/libtntnet.la -lcxxtools noinst_DATA = tntnet.xml dist_noinst_DATA = global.ecpp newsdb.sql README CLEANFILES = index.cpp news.cpp newscss.cpp ECPPC=$(top_builddir)/sdk/tools/ecppc/ecppc ECPPFLAGS=-I $(top_srcdir)/demo/newsdb SUFFIXES=.ecpp .css .cpp .ecpp.cpp: $(AM_V_GEN)$(ECPPC) $(ECPPFLAGS) -o $@ $< tntnet-3.0/demo/newsdb/README000066400000000000000000000055431365471676700160130ustar00rootroot00000000000000This demo shows, how to access a database with Tntnet using Tntdb. It uses connectionpooling and prepared statements with automatic caching for best performance. It is not built automatically, when Tntnet is built, because Tntnet does not check for Tntdb, which is needed here. A simple Makefile is provided, which builts the demo by entering just 'make' in a shell. It works with sqlite3, postgresql and mysql. The database is choosen in tntnet.xml (this also demonstrates, how to access tntnet.xml in your applications). The application uses a variable dburl, which specifies the connectionstring. It defaults to "sqlite:newsdb.db". You can guess, what it menans: use sqlite3 with the file newsdb.db. The connectionstrings for postgresql and mysql are commented out in the example tntnet.xml. For setting up the database there is one sql-script newsdb.sql to create the table and a shell-script newsdata.sh to generate test data. The shell-script creates 20 articles by default. When called with one parameter, the parameter is interpreted as the number of articles to generate. With 2 parameters the first parameter specifies a startvalue ant the second the number of articles to generate. Sqlite ------ To create the database enter these commands: sqlite3 newsdb.db #include #include <%config> // read variable from tntnet.xml with default value dburl = "sqlite:newsdb.db"; <%request> // fetch a connection from the tntdb connection cache tntdb::Connection conn(tntdb::connectCached(dburl)); tntnet-3.0/demo/newsdb/index.ecpp000066400000000000000000000023321365471676700171040ustar00rootroot00000000000000<%include>global.ecpp <%pre> #include #include <%args> unsigned limit = 6; unsigned offset = 0; <%cpp> tntdb::Statement stmt = conn.prepareCached( "select id, title, short_text" " from article" " order by ctime desc, id"); Ecpp-News-Demo

Ecpp-News-Demo


<{ unsigned count = 0; for (tntdb::Statement::const_iterator cur = stmt.begin(); cur != stmt.end() && count < offset + limit; ++cur, ++count) { if (count < offset) continue; tntdb::Row row = *cur; int id = 0; std::string title; std::string shorttext; row[0].get(id); row[1].get(title); row[2].get(shorttext); }>

<$ title $>

<$ shorttext $>

% }
% if (offset >= limit) { previous page % } next page tntnet-3.0/demo/newsdb/main.cpp000066400000000000000000000035211365471676700165550ustar00rootroot00000000000000/* * Copyright (C) 2018 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include int main(int argc, char* argv[]) { try { std::ifstream in("tntnet.xml"); tnt::TntConfig config; in >> cxxtools::xml::Xml(config); tnt::Tntnet app(config); app.mapUrl("^/$", "index"); app.mapUrl("^/(.*)$", "$1"); app.run(); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } tntnet-3.0/demo/newsdb/news.ecpp000066400000000000000000000013341365471676700167520ustar00rootroot00000000000000<%include>global.ecpp <%args> int id; <%pre> #include #include <%cpp> tntdb::Statement stmt = conn.prepareCached( "select title, ctime, long_text" " from article" " where id = :id"); stmt.set("id", id); tntdb::Row row = stmt.selectRow(); std::string title; std::string time; std::string longtext; row[0].get(title); row[1].get(time); row[2].get(longtext); Ecpp-News-Demo

<$title$>

<$time$>

<$longtext$>

tntnet-3.0/demo/newsdb/newscss.css000066400000000000000000000010261365471676700173220ustar00rootroot00000000000000h1.ecppdemo { font-size: 14pt; font-family: Verdana, Arial, sansserif } h1.title { font-size: 14pt; font-family: Verdana, Arial, sansserif } h1.title a { text-decoration: none; } p.shorttext { font-size: 8pt; font-family: Times New Roman, Times, serif; } p.link { font-size: 8pt; font-family: Times New Roman, Times, serif; } p.time { font-size: 8pt; font-family: Times New Roman, Times, serif; } p.longtext { font-size: 8pt; font-family: Times New Roman, Times, serif; } a.link { } a.navigation { } tntnet-3.0/demo/newsdb/newsdata.sh000077500000000000000000000013571365471676700172770ustar00rootroot00000000000000#!/bin/bash # # print insert-statements for testdata for newsdb # # usage: # # ./newsdata.sh # generates articles 1-20 (startvalue=1, count=20) # # ./newsdata.sh 5 # generates articles 1-5 (startvalue=1, count=5) # # ./newsdata.sh 100 5 # generates articles 100-104 (startvalue=100, count=5) # if [ ! -z "$2" ] then START=$1 COUNT=$2 elif [ ! -z "$1" ] then START=1 COUNT=$1 else START=1 COUNT=20 fi END=$((START+COUNT)) for ((i = $START; i < $END; i = i + 1)) do cat < sqlite:newsdb.db 8000 INFO tntnet INFO component.newsdb INFO tntnet-3.0/demo/rest/000077500000000000000000000000001365471676700146175ustar00rootroot00000000000000tntnet-3.0/demo/rest/Makefile.am000066400000000000000000000013511365471676700166530ustar00rootroot00000000000000noinst_PROGRAMS = rest putdata getdata deldata noinst_DATA = tntnet.properties dist_noinst_DATA = README rest_SOURCES = \ getvalue.ecpp \ putvalue.ecpp \ delvalue.ecpp \ rest.cpp putdata_SOURCES = \ putdata.cpp getdata_SOURCES = \ getdata.cpp deldata_SOURCES = \ deldata.cpp EXTRA_DIST = \ global.ecpp AM_CPPFLAGS = -I$(top_srcdir)/framework/common rest_LDADD = $(top_builddir)/framework/common/libtntnet.la -lcxxtools putdata_LDADD = -lcxxtools -lcxxtools-http getdata_LDADD = -lcxxtools -lcxxtools-http deldata_LDADD = -lcxxtools -lcxxtools-http CLEANFILES = tntnet.properties SUFFIXES=.ecpp .cpp .ecpp.cpp: $(AM_V_GEN)$(top_builddir)/sdk/tools/ecppc/ecppc -o $@ $< tntnet.properties: $(AM_V_GEN)echo "rootlogger=INFO" > $@ tntnet-3.0/demo/rest/README000066400000000000000000000003141365471676700154750ustar00rootroot00000000000000REST demo Requests -------- Get put a value; value in body method PUT url /key Get the value method GET url /key Delete the value method DELETE url /key Get all keys method GET url / tntnet-3.0/demo/rest/deldata.cpp000066400000000000000000000044421365471676700167250ustar00rootroot00000000000000/* * Copyright (C) 2016 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include int main(int argc, char* argv[]) { try { log_init(); cxxtools::Arg ip(argc, argv, 'l'); cxxtools::Arg port(argc, argv, 'p', 8000); cxxtools::http::Client client(ip, port); if (argc <= 1) { std::cerr << "missing parameter; usage: " << argv[0] << " key" << std::endl; return -1; } std::string key = argv[1]; cxxtools::http::Request request('/' + key); request.method("DELETE"); client.execute(request); const cxxtools::http::Reply& reply = client.readBody(); std::cout << "http return code " << reply.httpReturnCode() << std::endl; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } tntnet-3.0/demo/rest/delvalue.ecpp000066400000000000000000000003111365471676700172640ustar00rootroot00000000000000<%include>global.ecpp <%cpp> std::string key = request.getArg("key"); Data::const_iterator it = data.find(key); if (it == data.end()) return HTTP_NOT_FOUND; data.erase(it); tntnet-3.0/demo/rest/getdata.cpp000066400000000000000000000042231365471676700167350ustar00rootroot00000000000000/* * Copyright (C) 2016 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include int main(int argc, char* argv[]) { try { log_init(); cxxtools::Arg ip(argc, argv, 'l'); cxxtools::Arg port(argc, argv, 'p', 8000); cxxtools::http::Client client(ip, port); for (int a = 1; a < argc; ++a) { const cxxtools::http::Reply& reply = client.get(std::string("/") + argv[a]); if (reply.httpReturnCode() == HTTP_OK) std::cout << reply.body() << std::endl; else std::cout << "http return code " << reply.httpReturnCode() << std::endl; } } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } tntnet-3.0/demo/rest/getvalue.ecpp000066400000000000000000000003701365471676700173040ustar00rootroot00000000000000<%include>global.ecpp <%cpp> std::string key = request.getArg("key"); Data::const_iterator it = data.find(key); if (it == data.end()) return HTTP_NOT_FOUND; reply.setContentType("text/plain"); reply.out() << it->second; tntnet-3.0/demo/rest/global.ecpp000066400000000000000000000006071365471676700167330ustar00rootroot00000000000000<%pre> #include #include typedef std::map Data; <%application include="map"> // We define a simple in memory key value map as a storage. // The scope is `application` so that all requests see the same map. // Note that using `application` the data is locked for every request and // hence access is serialized. Data data; tntnet-3.0/demo/rest/putdata.cpp000066400000000000000000000045521365471676700167730ustar00rootroot00000000000000/* * Copyright (C) 2016 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include int main(int argc, char* argv[]) { try { log_init(); cxxtools::Arg ip(argc, argv, 'l'); cxxtools::Arg port(argc, argv, 'p', 8000); cxxtools::http::Client client(ip, port); if (argc <= 2) { std::cerr << "missing parameter; usage: " << argv[0] << " key value" << std::endl; return -1; } std::string key = argv[1]; std::string value = argv[2]; cxxtools::http::Request request('/' + key); request.method("PUT"); request.body() << value; client.execute(request); const cxxtools::http::Reply& reply = client.readBody(); std::cout << "http return code " << reply.httpReturnCode() << std::endl; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } tntnet-3.0/demo/rest/putvalue.ecpp000066400000000000000000000003061365471676700173340ustar00rootroot00000000000000<%include>global.ecpp <%cpp> std::string key = request.getArg("key"); std::string body = request.getBody(); log_info("key: " << key << " value: " << body); data[key] = body; tntnet-3.0/demo/rest/rest.cpp000066400000000000000000000055421365471676700163060ustar00rootroot00000000000000/* * Copyright (C) 2016 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include int main(int argc, char* argv[]) { try { // read listen ip from command line switch -l with default to empty, which // means: all interfaces cxxtools::Arg ip(argc, argv, 'l'); // read listen port from command line switch -p with default to 8000 cxxtools::Arg port(argc, argv, 'p', 8000); // initialize logging - this is optional. If log_init is not called, // logging is not enabled log_init("tntnet.properties"); // instantiate the tnt::Tntnet application class tnt::Tntnet app; // optionally set the application name app.setAppName("rest"); // set up mappings // Map method GET to "getvalue" and pass url as argument "key". app.mapUrl("^/(.*)$", "getvalue") .setMethod("^GET$") .setArg("key", "$1"); // Map method PUT to "putvalue" and pass url as argument "key". // The value is read from the http body. app.mapUrl("^/(.*)$", "putvalue") .setMethod("^PUT$") .setArg("key", "$1"); // Map method DELETE to "delvalue" and pass url as argument "key". app.mapUrl("^/(.*)$", "delvalue") .setMethod("^DELETE$") .setArg("key", "$1"); // configure listener app.listen(ip, port); // note that a empty ip address tells tntnet to listen on all local interfaces // run the application app.run(); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } tntnet-3.0/demo/savepoint/000077500000000000000000000000001365471676700156525ustar00rootroot00000000000000tntnet-3.0/demo/savepoint/Makefile.am000066400000000000000000000011061365471676700177040ustar00rootroot00000000000000pkglib_LTLIBRARIES = savepoint.la savepoint_la_SOURCES = \ savepoint.ecpp AM_CPPFLAGS = -I$(top_srcdir)/framework/common savepoint_la_LDFLAGS = -module @SHARED_LIB_FLAG@ savepoint_la_LIBADD = $(top_builddir)/framework/common/libtntnet.la noinst_DATA = tntnet.xml CLEANFILES = savepoint.cpp tntnet.xml SUFFIXES=.ecpp .cpp .ecpp.cpp: $(AM_V_GEN)$(top_builddir)/sdk/tools/ecppc/ecppc -o $@ $< tntnet.xml: $(AM_V_GEN)$(SHELL) $(top_builddir)/misc/tntnet-project --config=savepoint|$(AWK) '/<\/tntnet>/{print " \n .libs\n "} {print}' >$@ tntnet-3.0/demo/savepoint/savepoint.ecpp000066400000000000000000000010411365471676700205270ustar00rootroot00000000000000<%pre> #include

savepoint-demo

<{ try { tnt::Savepoint sv(reply); // everything from here until catch is not sent, because // the exception rolls back the savepoint }>

Title2 <{ throw std::runtime_error("test"); // this skips end-tag "

" }> <{ sv.commit(); } catch (const std::exception& e) { reply.out() << e.what() << std::endl; } }> This is no header, because the h2-tag is removed from the output. tntnet-3.0/demo/session/000077500000000000000000000000001365471676700153255ustar00rootroot00000000000000tntnet-3.0/demo/session/Makefile.am000066400000000000000000000011351365471676700173610ustar00rootroot00000000000000pkglib_LTLIBRARIES = session.la session_la_SOURCES = \ session.ecpp \ appsession.ecpp AM_CPPFLAGS = -I$(top_srcdir)/framework/common session_la_LDFLAGS = -module @SHARED_LIB_FLAG@ session_la_LIBADD = $(top_builddir)/framework/common/libtntnet.la noinst_DATA = tntnet.xml CLEANFILES = session.cpp appsession.cpp \ tntnet.xml SUFFIXES=.ecpp .cpp .ecpp.cpp: $(AM_V_GEN)$(top_builddir)/sdk/tools/ecppc/ecppc -o $@ $< tntnet.xml: $(AM_V_GEN)$(SHELL) $(top_builddir)/misc/tntnet-project --config=session|$(AWK) '/<\/tntnet>/{print " \n .libs\n "} {print}' >$@ tntnet-3.0/demo/session/appsession.ecpp000066400000000000000000000004011365471676700203550ustar00rootroot00000000000000<%session> unsigned s(0); <%session scope="shared"> unsigned sa(0); Sessioncounter (component): <$ ++s $>
Sessioncounter (application): <$ ++sa $>
all vars reload this tntnet-3.0/demo/session/session.ecpp000066400000000000000000000046221365471676700176650ustar00rootroot00000000000000<%pre> class MyClass { public: MyClass() { log_debug("MyClass ctor"); } ~MyClass() { log_debug("MyClass dtor"); } }; <%session> unsigned s(0); <%session scope="shared"> unsigned sa(0); <%session scope="page"> unsigned sp(0); MyClass myObject; <%securesession> unsigned ss(0); <%securesession scope="shared"> unsigned ssa(0); <%securesession scope="page"> unsigned ssp(0); <%application> unsigned a(0); <%application scope="page"> unsigned ap(0); <%request> unsigned r(0); <%request scope="page"> unsigned rp(0); <%thread> unsigned t(0); <%thread scope="page"> unsigned tp(0); <%cpp> MyClass* p = request.getSessionScope().get("foo"); if (p) { log_debug("instance of MyClass found"); } else { log_debug("create instance of MyClass"); p = new MyClass(); log_debug("put instance of MyClass into session scope"); request.getSessionScope().put("foo", p); // ownership is transfered to the scope here } Sessioncounter (component): <$ ++s $>
Sessioncounter (application): <$ ++sa $>
Sessioncounter (page): <$ ++sp $>
Secure sessioncounter (component): <$ ++ss $>
Secure sessioncounter (application): <$ ++ssa $>
Secure sessioncounter (page): <$ ++ssp $>
Applicationcounter (component): <$ ++a $>
Applicationcounter (page): <$ ++ap $>
Requestcounter (component): <$ ++r $>
Requestcounter (page): <$ ++rp $>
Threadcounter (component): <$ ++t $>
Threadcounter (page): <$ ++tp $>
<& subcomp &>
reload this - applicationsession only <%def subcomp> <%session> unsigned s(0); <%application> unsigned a(0); <%request> unsigned r(0); <%thread> unsigned t(0);

Subcomponent

Sessioncounter (component): <$ ++s $>
Sessioncounter (page): <$ ++sp $>
Applicationcounter (component): <$ ++a $>
Applicationcounter (page): <$ ++ap $>
Requestcounter (component): <$ ++r $>
Requestcounter (page): <$ ++rp $>
Threadcounter (component): <$ ++t $>
Threadcounter (page): <$ ++tp $>
tntnet-3.0/demo/upload/000077500000000000000000000000001365471676700151265ustar00rootroot00000000000000tntnet-3.0/demo/upload/Makefile.am000066400000000000000000000006301365471676700171610ustar00rootroot00000000000000bin_PROGRAMS = upload upload_SOURCES = \ main.cpp \ upload.ecpp AM_CPPFLAGS = -I$(top_srcdir)/framework/common upload_LDFLAGS = -lcxxtools upload_LDADD = $(top_builddir)/framework/common/libtntnet.la -lcxxtools noinst_DATA = tntnet.xml dist_noinst_DATA = README CLEANFILES = upload.cpp ECPPC=$(top_builddir)/sdk/tools/ecppc/ecppc SUFFIXES=.ecpp .cpp .ecpp.cpp: $(ECPPC) $(AM_V_GEN)$(ECPPC) -o $@ $< tntnet-3.0/demo/upload/README000066400000000000000000000006161365471676700160110ustar00rootroot00000000000000Demo-application "upload" ========================= This application demostrates how to handle an upload-button To run the application enter "tntnet" in this directory. If you have not yet installed but only built tntnet, you need to enter the path to the generated tntnet-program: "../../../framework/runtime/tntnet" You can see the result in your browser at http://localhost:8000/upload tntnet-3.0/demo/upload/main.cpp000066400000000000000000000035761365471676700165710ustar00rootroot00000000000000/* * Copyright (C) 2018 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include int main(int argc, char* argv[]) { try { std::ifstream in("tntnet.xml"); tnt::TntConfig config; in >> cxxtools::xml::Xml(config); log_init(config.logConfiguration); tnt::Tntnet app(config); app.mapUrl("^/$", "upload"); app.mapUrl("^/(.*)$", "$1"); app.run(); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } tntnet-3.0/demo/upload/tntnet.xml000066400000000000000000000045021365471676700171650ustar00rootroot00000000000000 8000 INFO tntnet INFO component.upload INFO tntnet-3.0/demo/upload/upload.ecpp000066400000000000000000000030271365471676700172650ustar00rootroot00000000000000<%pre> #include #include <# for upload we need to use this enctype-attribute #>
<{ // request.getMultipart() gives us access to all parts of // the multipart-encoded request const tnt::Multipart& mp = request.getMultipart(); // we look for a part named like our name-attribute of the upload-field tnt::Multipart::const_iterator it = mp.find("upload"); if (it != mp.end()) { // we got a const-iterator to the uploaded data cxxtools::Md5stream md5stream; std::copy(it->getBodyBegin(), it->getBodyEnd(), std::ostreambuf_iterator(md5stream)); }>

<$ it->getSize() $> bytes received
md5sum: <$ md5stream.getHexDigest() $>
data:

<{

  // cxxtools::Hdostream is a outstream, which converts the data to a hexdump
  // and prints it to a target-ostream. "reply.out()" gives us a ostream
  // to our client.

  cxxtools::Hdostream hd(reply.sout());

  // hexdump first 1k of uploaded file
  if (it->getSize() > 1024)
  {
    std::copy(it->getBodyBegin(),
              it->getBodyBegin() + 1024,
              std::ostreambuf_iterator(hd));
  }
  else
  {
    std::copy(it->getBodyBegin(),
              it->getBodyEnd(),
              std::ostreambuf_iterator(hd));
  }

  // print last line
  hd.flush();

}>

<{ } }> tntnet-3.0/doc/000077500000000000000000000000001365471676700134635ustar00rootroot00000000000000tntnet-3.0/doc/Tntnet-Prospekt.odt000066400000000000000000001272061365471676700172640ustar00rootroot00000000000000PK/C^2 ''mimetypeapplication/vnd.oasis.opendocument.textPK/CDDThumbnails/thumbnail.pngPNG  IHDR~pDIDATx UűǏ>#"D),VȦP&` *@",.p ͈, QDcg5}2wf..gݧUܹ3 (-CW ^@Ke%2S@)pI$Pf \(3. LKe%2Sdu=q/sIW8S)qƌ~kZjߗ,YҼys_z;o˖-'p?g?ɾ?_zQG=stP5|VZ^hӦ͑GI&'N꫿o/\n]m׮u?믓zdNVd[|yJ,W~ɓ@oo%+sq10P%6lؐ_UL$'|Vvm&ʐ S f;S2\hX`_ѭ[&MW0iw77.E'͈sdٔB{ 6 f~/RIߟf?{A{%YGer۵kW~C^{-74hbNW\"R2F՟D.WK'G^tSnMܯ-~o&O1iqҔWJg 2  &\}*bѢEL09?|l߾]Po1ɘ ,)#PH+`ڴi3% &Odf\;\yK.4i_ϔNpq衇 7УtLӦM=`(" UXЦM̙1bă>CB ~@?Q?HyNi~ f8x).gι>wd( b dk{ɴ~*%+}g70(%M"F@맞zLp_r#C0pX׬YC2u ᗙ/JLTO>$Pse> `;LRq*dJCWD ,R]~TW#%(QpCV#Lн{w/eua=nbE(//YJupK4LuAliMW}cx r%sɈ9B:+}I>}XѦGC4+2~o zZX$3N>d+B3 cd'iq2],/2_ #4#Xoߞ_)cHR6pL~DMv&tS>PC0ZUPgPelIc"\fϞ=h /^{n7o8B2'qK0o3רQ|8IF `hWĠ1ǀ󪫮?r׸BEש*mqHu3r/U4T ))~pӸ-뾫k,[%3e7Vi8%N DʜtId΄0s2Us0 bdh-[MvI&ЮC! 6b@ ZkMƊ;虜.戊s j˲jܸ1U6 S͝;$ngsI*YP*CF% tz@'L4XР€ }SIҥKe˖m&`>e|  R p8]@U0+<= ܶmu-((t6m2mIMg :U=~.K<$}g 3nspgh;f͚5Hp?"A`@W!ƵL̷zKUfuAX ] e'L8Z2J/A^^^+܎bj:kSNV%;,Gm֬+R KL̨䦭5xc (*cLE^9#nwz0]v'".,iNj.5pc)kРcL|H*FE;}:OӞҗP0Ji`K[l=Ճ?Bai!yK\'bnhpzrCq={ﻻ}>,+G` g.H)u< <12e:,m(QC }^^Gz=s%Tdh.=0itD{x:$eȖ2ԩSP`ReKѮy/B˘FG,ey})nZ鰎2B1ZCЌ^$*ފg % "c+XA%`sv1&\"e"`#4~Rݗ}r3S& * U {=}3K3K'#C$M 0WfHb3,!hMӈ$$B6M2eX7oޜiF;s.@q$sM~oF+d G}5>̩ԩS%@&M0 \5j^w?wҾJ߼ݷx+VD-P GisD@z'Lh4C1PöHOxFO3GO|olH,E^x1]h^ڸ3>)]b0_ZOdBU_{5rS/C+nT-e`)Hӈ 0`@!Υ}8CBfN\ltAk֬9Su30rŊ.L QVd…YZ1 F crk_r{ѮH86x(z$jF.F)C咧W2'o)Nl`ɪ)Y$!+S# 4Qq#uhF2K6nݺI-AJ2ӧOڵk#Y1f~2͍1$T"\OnFIQb{ G.i O+=jժ`5HnǎٳgoذAq>k,ɤId z{A*ÿ\s'aWvIt-s4TZU2wl\s}M.ZҚC(aٲe&%%=hweD*9)>p).ڳ\$Pf \(3e%\޳^ȧB ,VYӇǎ' ;;*U/>ʕ+YwN^ E,Xо}'x!3RۡxڵkuiĺWj.UK"0,g]r9rdÆ Rʫ:`C9Y I㟏=X&M;8pݢEO>YO?tƽ|lْ䂯VٗIt$V6SNumP%+|_-*gÆ nL, .IҮ_~ÇO>M׮]R V%-С;C#^{G}Ă7`JC 2. EG;w.\Ezd+Kܚ5k򔪺& cgПXb|Y$Æ &&M뮻3'&TM6n!?+Z6C\/,;nhƳA^:t ]N;4mQ>^K"qJ3A6mTY^zW^yWJH0+׹+"jW0N"ؗgKԞ w6۶Tw~O8K(qʼ^tWU0RNصvuKPH(Nԍ40Q.dUc(Δ3 5[EjHF K]M|#&ny #wYp$+b_]/:<ǟ(aP.E!3Cw46;ܽn:PPP]a1gȬ4O?E]$e4څ9C8]"8a7 T14ou ܉;SP=Br!`fIDE:~f8SP敲0Whx,ⶏT= %,%hGA'qsS!B@ Aab0kOhbٱjvav%1*v1Y0\b_*@W;s;bĈiH*}#P&y25jT3>?3ouYTUG:w,W9FR=LCKT,e%q+|\I\S!6&G)liP df@q=0Qb7b*:~Kϫ]Tݓԕ^*}#G/l6#~VɤF>s_e*gUVuGն^矆3p6 q=1m۶ܑg~+u56]RaXex.ԉ^OR;s,!UVI?dڗkʸH~8*6eI㥘 t^wz;/JLelj' 4YeK'+) .a3ǁ1!&Sʕ+@L]t4pb:O iJYUz(i,#!\nʷw}!Hz;vh@j\GV# \KcNE(BG/"YQv;hW,W7|OB.(UIS[ӦMI$PVjܸ1={6K|iL#u59Ϗ4]N)h"Րv]r C].ӨrqeEwlxD ; QJ i]$e˖12vA1JR:U:"~[:L Nzތnj"HLXW fx4]25ޡ,f.w?G)|k'=azx@͎d(G%-@#K&/CQb:nʍ)6'>D [?I'ZQEnl]dJF-i%10AIUpEָ,複3XTuGwy&en\I$kW.K;<-G!?'LгgO s2\$r=9K;dgs$2nZRO,C&Y&Kڠŷ4`rRS8EՋ_riRbޥ\԰#VZ!'OX 2Ąu.OnZR|>^u6vX$w ,$K(!ѥ,%1vZչ#$ "Vb!; .\6v@K5Y'CT#UT.t'd)&P H* 4UxӶE#z AsncLd&-ddTr[5םCsseg-4޵^X^ޅ[\`,e%2S@)pI$Pf \(3. LKe%2S@)pI$Pf \(3. LYpg}VR%" ]vΝho,7͘1ct1z5kT^/,,/̙ӭ[7kԨqa+Wnڴip t'g(mVڴie˖7n]wռyy_|C=3ɄG7֝}BS\ҡC[o.6lK/g_AԩSKn߾79|ѱ;ڸsmF[l?SիW.]MmꫦMZW$ WԜY.\pرp)S 5j7\dbRC ޣG҉"rw%'K@e%|SNqoI#Glݺ Hv>{GFN%?6M{t9$^¸CYf#ΨUV{(Q!G;8[:=9)Bzjժ1U0hWW\YM%qE&ՁV NZ...袋^uh{'J%~jhHK:!>yժUy[oر掂>۪U[6!^Ps*As/1-Z;UDED@%t<(E\S`:餓~`,N:[.hzů7Se41d0+VR KѣGF|Y^=Xu2 4EW@TtB'&(!p)W(GfW&60nsS)?FE+}v: Jה(7Ƣ DWסCWJy&#*RcL Q"*y/Kٳ"kQs*`5kV{ZK^En@4>˖r^7̍]tad4s0_~exv^ԾiצQ]yl#=xsSTe3Hr%E)S\S$._Q o*[3{ァVyier%qE&3ao=r/Q$PE.arO*,(Xɽ=E)>7x ?ɊXI i#N8ei8@E׃+|7baˢ4"_AIcS&(\PX r/qLJߛI)WEHj۶-aqB.H3jԨEÆ Ji );v}0YaI &AMa`D#j1]B'iycǎ%O^* "*|Q9'fB,%,Z"Ԯ]lMrŰrC{݀T$*ˁgcq+fRʕDc>_)0jT$޽L[/SeeAЙZC ORiY,;|p]x%3HEӦMW_&gZzSD,i,bYģs4*A%2h>#)옠x,0#/|Q ל%iDKԊ%5IjGOeۯr%L%qeIk@zZjbu{ rFE@upʕ+-ciZ*ZIӥK7L5>_z|)0by-8 R62;|.KyF۸<@g!|Ũ;P)5X\i#sR46,|+VH/ƋQBSN9Y* Hܽ3rp_<>EJ\h7aagJm@0[0B=Qi#sR4Da²ɲȅLZ_}Ż,HW\PejN^R7ؗ&*|YV6^#m֋lo\oJƚmÆ f7õaϬ{02Xٚ0XIJ$_:c3520EuԑlfBPJ Y)AufQZDv38)EsA xrv/|HJ1-#aÆY) .IU?>↖bv֭۽k4Gʥ2;VƏ?ecѢE2ӛ(ҥK'Mt3'%\IFF%2T.p9ڵk=AUW]e-AFRih_~ '_VJKjX9 M457+VG}tËC0IA銊Lo9u̙ikdTꮰ7\*U)\A }OEA,"r5r}0[ʕVmРAZ¹Ҙyr/xquRjh3]J޽ܸS{ژT8RVQxǷ\9;RE #FRz!o,0[.hC Nc3zxH0ޕ'jՊX8s!#\}(E'9@ zi_`o "ҚPɂMTOݔ42G|BJL'fWݘn;YS=z%RďSI'ks+o>orqIR}">۷{ڑw"'OKlF7t9rB|#GŽ2XcB[P֖-[] æM6lU=W!JT>}`\"X%G(R`HoDڡy'ΰ; H_PP`$~Ԟ|XO=ƍ#%ӦԫWO+0\T_"m۶qˉ(q´!ٸk]bdAY lРA½ޫ!3a ;\ at;4oDgU Q\2zOq=И1c}Yfo>XrO<͛75k%:wpI|츄I&7n<Ï=o?UVʕUAԩS޽{[=zyի~_͛|A~֭%[l/GV.ʂKjL~ և Ƶ4$~>}+?OeY@JV{$(U"{)ˍ2r-{>5kVT9+ހ\_7ܑS?2.1Y)<.Y#{KtDjr8SRvڙayv=ˍq_򗬤fϞ}uYίJ14dժUkΛ7$?O qw $ԩS<.^UVt{KtDJ.xe()y*{\/7pݻwg4lr̙Ӽ ||嗊ɣ֭[׿tܒI|g̘aq6l^Nܗ)1*]Gudʑ XvIw;ѩK.gyF.nx֭!Ի(b)rrwHh2u͚5#FiӦo&}麧^>A*^ 󓐗ǂH.a$NByaT@{бܔS++CW^>#|) }HR67|OY ڷt\z뭥\W/+!B|׀,X+IfF!PLF\+(YDвMrw0[QE"muOŽ|J{'̃v2r` #4rHii%L]357Q:s0 5u{oaT0RR+a&I_C=xÉ^$+E:+MjQw?Չ4`^1/IX t< w"z*ln2̭4=(pD1' nhW̮c{;ud嵱t+\|ӣ ܐRfv؟W$=:a7CyСg":,D 0f̘+3~Ë >E|-Bd5A!J ;ĐE@0]3.]Jm;wf:/ n\Bni\Qp s{ˑH4ƍ-҃'PQ _2* 7ܰj*=AQ:NLFQ"~ի嗦W^+C=#wJo)i&|C xQJЕ֬@ps` ~rfOCK>`*CQbCȖvQP، 7'1Yq qȍ׫TC(WDz.:2@` `^쇨#x뮻WM>"d9 L>.1Oøw#XPT4K૯URW\E:OrcϡhtRN!Lj&߂ ș@!^H. y(:%N<ƺ.HpײeQBHٱc\ťp.\nIW׆{2D%޲aN`M` W]aCTupbdW BrfE`.Ѷ"!+pg}KRmJTڶmШQ#E C0¸Z-I P5)W[o߾]]?Hgܸ^*t{J-:iR2,yfa)WXOkOI)QBpB5X0#kHnI')W$7uwH.Lh:rb2;|p|\֠0S낙/HKpgѣr7d.:u* X#TOh@>R crR)dR(w zUL ( ^Zy<,Lfe-U2ͰhҜuY2n8Di ~GT5X˟B&*``1/lCڟR/G 'i5BJx7RRp Lٳ'S"|̙>#F0r#v!,t# ZI8q"zk׮fHM" X߿?&ܹs6lL;`$#Bo( C4ÑZCǏRJkTQj\rt<eZ@R:rCxHLp ̨XJHHQb’GʓRIޢAeL0O-g|3%yʕ+3N&dDiuI/ C':Sz+0@^U˗W40fD*,(mVL֭'d*Cn|&s`rKWـE^^"4ޮ;JB`HZT@!1'} doˍ;L9dHŘ3Pzv8EfoaV-&`!"$`|sa+sgR?{P7cPB{VBLKe%2S@)pI$Pf \(3. LKe%2Sv1-*T~}'1^f4):u&B>}znݎ:(x9~8Pv[nٳgz޲e7nȑs̙3w7Xϛ7o]~K);.a7n駟6o_믙E=܅ NX`B\x<ȃ>dɒb3@Č1N:'N/\?ڀB\l߾twT\mڴ)MuL -~;B\pgԨQ_ulbZv2G?@y2S\2{iF,}4/&8ǪxΜ9Ҷm[V@r 0~xr`mHuy61|!Owy%wBd%+s%Sޕw!N[WD95k֔g;v,дi~[~FjՊe6Lxbr;c[xz뭷q287F.aniV^ФI7x?u 8Y ].:FW_?g\J.=zg~~\/_`M曟`4ez; ) .q}t(k׮Q=9 0vZ8o EgSD"Я( E%+qp9La"WԫGcO{xq?ʖcgK脋? 9@&M߿Z~۶mׯ[o,XN8 -dAv 5ncs+%JPR%V #d"\aQ4Sα8,d趪09=sUVu*BפYnʂK'sĈL'OOu_8V,GT|͙@jո -rM7\k-! X[,R=%={^*KJ?Hj+G}SN:to|VZեKVaSLy6l(ϜzZ\ PAHS.@a4c!G;0壙,| -@TBUfݮ];p+3Œ[)S-@LȦ2WX)3p88N&0 6p 6k,J8В+(w~i9r<[^^ ȕt e%IuRW #ynIjܧAi\qo[OH 0 ^'Me̝̔;B۠AIƍA`@6 h}l!S\3 1ǂ_>>k,.hňK *>JoӦS X>D dB<=E-F'*sʂKTwf̘z*4hPTSb]é5._ً( .N 'Z#}>i+W,i۷嗛5k呔߼KaÆGq*KrAYTj(M|&&{*ʂK*,,P )Q۸kW+L-xO`өשS'= &&pInwK[: VJao(d"ҥKn"_Oen-J{j??(}Kԣ7 X/Pf \(3. LKe%2S@)pI$Pf \(3. LKe%2S@)pI$Pf \(3. LKerI8L⒝;wd 'Pf \(3. LKe%2S@)pI$Pf \(3/΂fGIENDB`PK/C content.xml[KsWƕ]]ibއ޲l~iq2 z@+i |40e% .ˋny3ǥTn, {5=i(mK,'Lְ-8[:v8>wN-@∪y àC2"$ZTpvd pl ˙(»2 6Z% w=rd,x'}cFvfpó uS v΋; v+pp{ 3/`0e&3}֙ZxQd "E =or {2_½P~j*7Z8$bPyFgbK\Pnf I]{*K,_,6+.S ]eVK-4 dQn|YAuU8vM5x1F1;Yݾ7 Q]_GH}jfz.'xMJ9k&xP x΂bfmb*;ΤnsFl=1LC{DbnIb-&O?%Z+ɒJ%/g 9EnyFEc:VΛ&Q33T9oRMcSZhV8LH`P'`m]^Ԍ͙گcLjoMJM$y&Z12$#Ά@fJe>K i E-3@$ ?hmND#4]ʙ}-&="`nWr <d0W> @&K#q,-# XP+/d#ЦAIo-#%Eϩ^2Mm8]1fb폑 f=PlH~wY8NK\ӣ [ DbƆ,b:@Yܪٕ_Òyn"9Ni˸`wVţOxpdҝ*=>1 CMΊc܅9L,^CsS$;`rPp?rBM J)栊n#e-ɥ&^9 lĖw9Nnr)7;bjhS\1/UC@5Wp.OlGY4@БUnH./RFo1%MFc¤7U}jgAZ Hl#@Q]pAQ+6 TiˣeD͎g7ޗsS$t'C @g>csȔtپ֔Ohn}RW2]LBuѷ7bMYx0 NE 2J㛐wֻIIXS8UPBp rXDPbmKQ :WO%_HN} r4.M4D@SQSs(d?9ԙv$tzxa*:%4Q1j龽>l- SԎF?PxYm2D@lV؅m>p:M~N%sc, ]WԺ}~Jv[ІEvI!͚̾ 2] hBֽӑuI;i}?[M_ ^f 15nމ˅bc=pj=?PKN" 3PK/C settings.xmlZ[s6~c!d{>ȒGweH&I 4a]5?XG 9Y3`Cɍ?nЃϽ$%([g}|K+s"CYf$YV^^.̶+kM.P*.|T*ӧ/[=⫬߲✿2I-{~=wh^Ŀc8DݲMYCXwgƸ@<ν>'T~yD#X ,=!6_忻T"`k[.fWA+ZtJJV.{KJ依Ru; q@TR<:{y4DR-BdU4{Q/Kdn*c4)2|r.`߀t09dQ]xW)=?vSU`rj {d-'}?ef9RiӒBiAុ+B=S0b.MK1\ϐ]甯 PD*e!2 @NE Ux(ANƑpP4LvץujMhKq{%dDlu5QO+w݂Sp'rG0*cg4a}4 =>nLкsFΝӿ9t xn6? WӦa($G+u~M +Ux׶}VEu؁!9$_qL7X yo2GOx !x70)FK>`sbː^֧1šR#ǫ( h-3CԔ!'fuQAK.]ᥩdg K6#"![n:.zb譔nњu0bP?)_PK{j@&PK/Cmeta.xmln0q M,Bi4&-v9 627ً-IS){SJ6>}Bt~E+.ArB*eQyΪJI2jVʒ*CI-5X蔦I㺮gu8&d^VPGLRcȠPb2#x`׆ji$8`>_yS#Dvidž%d' Gןx'61 ì6ɽ8E7RUϻ߫h-+0S%3K%dV}ewS}r cA$ؒ%%+{) N{ |r4hx ʂ@wMmB&c*X Ka,u]AU ϠLOaQv6|gQn"{>^:{i%ںe ו}{CEos@̰԰8ڈm_Gg64}ʂq7 \KVݥA{WbuXxh0|r=_aPKLV*HPK/C-Pictures/100002010000020C0000010B42064344.pnguTTm>J tHH7) HIw7 Hw"g_3k)k~su_ϊR_aH!o|~ 9e@d\:Hk;"+_urQ7wq7r2swwgv61r0cw},H G '#I#hE2io0**D[pIIBT9" R%P N~9v$F!]wfΓ.c!oIiOC #oL$shvl9Tphh:Z}Ǜ{;x\g UQOK(e}$uT=Q..= p)w^̔?ӆa>ˡ(i}802gz]Up?9K%=porUq e;לu|'4ȯbe\X6&w0zj3"0bw0_kA[%"1 'FC$Bk{V*n x%W9,0MAr Аh{<Qͣr+s>/QPh҄^+wLRbΉ">,v qb ֡ĸz7m(2wܚ GjלEXz8\G%b}=c9d48Ve0ѥ`?h*Fb NCmԂYΑMXKfw @TP5ÃX*TY~l7uhR*tptRe ʜ-~3'BfP ,J?o%w)s,EOu#^4#y@g|ȷ1)(`oʹc PCO2¥.-H/RJZI33kGۅc} m<=z0ytYi#he]R_3>CF )X#@0N0>$(!M0P=X>U-*nW "P%5]v@w!a_G'y0 oF?jRќi1,7e9xj.vU!t!+` c1\>^g]D[S J7E EUZN|pjlD;8,0_y$!JP\T2 "#cFc2 B_m9$0 ˇ\+UMQeN}t|!9g. _(AzUY<:p8q}us+F7覗!X;hP\܋ B! >Vm)=8`Ӄerk2Ān<}?b)^%:]k3l3J"#sXAJ-oқ& pyߤn,XN (foۄ Nº7wJ1)ptvOe_92kꅘ8osO5i{.{Eij(VC#L (AԷ5?oNmvQ-w^Oې$D52}5}sf0nɏ788tqMW*ҕZ`w%?9[:\"?: *5Eְ]Nh"Çj>3L k _{zOcw⾎OI П58^ס_ yne{>NJ >dQo@ 5sKXj~zRO8qhf?[+ T7d ƭo b隹ih) jZv9)ʫ=M]`iO%*o&gn(oNAz,uQg}*;"/AgHʶvIN[ob8@"HN>oŎ05G/+Th<nW-mB9K\2^[{Bqg{,\2X>qp<ksnAV "TlVQ' ,:=<*PGn2cwKDؗ{ys p"h;b, :DVdNҠ=7?bxz)}_Cct?{ C DZofIuT.phAB]mX `[LC"_AEڒٍ@w/ϱ ;`G aL|a !֒H"+A[^ʈ~JEPm-yћ*T w;Oª'z݋9?>6~j( "ˀ6;^W`Wq>rِtGꖇ4L7=8nmkg4a/2f7kE%k3O*Ha\qQē߭勥E;I){VcCʁ BW_lVz?(zK|7 b,a[u~b!/9;2RhE 0OWq:mR&H#!Π W1w cp5ߴ!8` HR\'B'o{x3ߪRtV0ʁx^Q(Tӣ)j+p,@/Q`㏿x[X?BRʗtcNd;_]kc""Ńy}OM,lW'N3#uٛXGԜК # FD/>wECF7%LB|+(yk f#KRu`ҜĪ_`T?`}얌[0 7 9\]x6o~0uRbٝ#G?ؑ/WӘaNtDИO.zO}XM;ј"Sá^ccKx]W9eWF(w2X듙} ڼ2'r/r) S=vH;ϥN'VP00xq_QLbqJ|bx8S}.-`y9JӒBy[>~$.IÕ+Ζ*~_6cE*V8g{fsJ]T+*ߢ#ʜ qw)hcWDaa_ tL2w|'chT&Pvvv6{6~'a ᖊlwB˥:%G&iӡ1eպDM5ƚWdv>н:="ĺk&/?49""iVӨҠh3#9c D&TܷWLwbܙ"e M7='>٨ڏ/h*}Ktաu:]FЦJ7'p1m„QN94"4PҠFA[--5=㲑/0iqA!agܛa B~>e`ۧwQ$_wIE%t/4M>f)}Gg-TW7*1-=߫7=eUy|X`sFpSPIk3U1fu`Ҁz7[MFF<{EhrAx?d寲y:2/aNn^kNb vHIh罦1|SBrgϨGFNB]-`B=_ |5{ ۫jUp|ki}#wmȰj/]Ft\4G?BF | ;6Qr+CQ஥$~E?b:> Cɵ& v; 1=@,yN_ 'ڹSMY 8X}{fq&WꨈzYrהa w>] G3˧F$O7[׎gu0sԅh9uu AZ[,-U9;ǥ^v=gd=J9zHIvAR#Um# YhIy*⁁_ӶȐRjcXg\q#@ʜ%E.1C鸄PvkB|p}aџ@og|6$r.Nvm3Χ 5fW (Uc*ɇbVqe1?9Yeu7m8߷J"H.TM1*zLg `uw"UY@ uI)>" ޕemnfvf}:(Gq MkSf^.< r~d >T[pt1p:(4u,'D˰@.PE ~#83%>4F&F-!T^KRhLJud ^WU8wRSd(P{gI袬ʦmooa#N+ SJU MXr@6v̈́&wȻ#8$Q0O3#ZE=)jM ^%sʯB `K} 1*P2enqNYvaA6i[ ܎$+MHv"DQ[ 8ˊ$꒱QY DqKlg DDPZr~AۇڱŅ#̉4g-Y5ŕ YW9$P +-GJs矆tm`NZ=Ŏt¶n=z?l'At?SDCƔBWIdINpSms9+s_+TYW6PzVk wS4+,=rFf`(!dFsq8bS,\xdwMTTM`JAN63tv :_AFW/J$YӐjH3*$sC2UK?th4gZ4~5@UB<-Yre@!x3?=+=:t2;6Sub+AF;aN1 ۴})i,y, _{&FVjotn(gX 2QB+YEv+T?-öᄈqy*cvCb=/ ?ҡNr(˲]uVɑt%VX`z?[{qxV}$<O@ A]9 ҂A.yC' J֦~ f'CA({SKSp7Sg_l#.lhv0L{DѬ^GTY^#Yk) 4p5(Ĺ'')[To&cG'doookw˭SIϘp"¢61=͹fͷTqKLf Zx+?2<خngKkU9GYş_whyR[5vddjj ,DDlll[ (5ukv6,llP""Vc8"m111CUڍl.pl\ܢ秺ٜyy} =<=HU/ږW۝Z[<\\n/P9&=sVأWZk{u<1s%åƳU [ݙR%nSR3t=K6^A^~ PGBJJ {UUU*))):R@ R5PQgQQA{DE 9_swE~8ۢ$6~ӳBi 3UϾψ&.>g?#q0L]ճ)c}Uwgd,ByfSȫN 8! '<ll%%F2 _ a N~,e5K㫻n5%죓xMxx8 ?}OVCAٓs'"XŎIщPZh'k=Zu4K;,Uj]o O3JnFz<\?vH_U}s+(8{w][WW7[[Kk\ ߷~qyX7chvIʐN"3ssnE'rrrWL%L0ٝmsO/LUU\)K]B#2h[[;57OG!ybS]2(mvPB 1,}B$‡룁|`!yt~^cgd{{_22SH_!: t]! ;djffx{F*.~' Hi~wؕ6Gەʚ."DDD0պ5jednL\(M!åӛ˱X^6}5[j3w=>ȅ*>Ia#}H#lUuJ%:Gz/S@a~ѓ!}P"zcb&cwb,W@(.bW fumb:gC4v Yuޝ* W4f7I3pGE<AaV¯-}ͷ~"\mG3 ]dPp濳J.$vաc.OZE=<Mb EL gQ^ihn}>~#bТL" 2iC qB6Hd ]?0C -|AR=[Jࢍz~/qŵׁ:bDe-2UfR`첱M$h}uMJS3|3ѱ(Wr^g-&Mvb. ,dLO#J %!ٔEqr,eOpVE.f tJN7vb@Fn|t+(ڠver HT6K V.Bo}ێ#>DԨ{x{uۭ >6i^0鶠[/̹zS`gߟloKRFEEOaPudwܟC#vոXpEk[]!3p;>콽= y\"ehMdzfLk!jw *VՎO5P͈ +s'iߒ'uU]%3ڊC(܌MN~5N1g hv2yYČIVN(aqR Ǥbik! Ϗwv8TL =MW㳹 MLw#ۆVo9472#Ee(*-rNP*$jWhhhCd|pUSe@T#0G# ?]^s[PE=/*ƃ,,.fPBv+oL!F͟2nommoz^<uqivAGGfm\BڝܞBYY`"K"iIp#u ӖSER>wNDDL5iii^i̺ A6ǭ0lytK v a @)dr5:Z9KY|( _hM#ffg^?(Jk6" )昀0aIlBPucћX?Ҋ}olfm}p;ۤ hS&v=E@K4y.LL`U+u>O+ڀgzT$:٤jLgX  tXMK+l1T5 qrbbB55sGZSzP qhp}{8q"ubaPg .b5U z5}(^̺zP,ŦlsroD^LNmŌX!4$dUрN` r&Iđ$Iy+'lUXw!LH""鷪UY@R&' =`dgjl@a2>0{;2hp4 2[PH迅@.~/I^'F]qJ>F#t0*ӎ C.~~Šy3++ֳn.OW%L=>&=G]qq||g¾) ۮ„PLYgT_Y  6"QḡW^0Y6DEҔw,/<!{5pDz`0:6&c-]tS{nx #Ɨq[пeP!$3"I&~C{h?jܘ:ׅftp`}"G;\ +jdbӘ2R v0ר0 Օ+1lsZbOc+/w}2ɹKsײ.Bڊt= H',i2T4:< AöMŷ=w%YueXvb?v%0K m&zZ\U&`3&'`wT{c=>}&$r 3ValB.:'.4_UW %viyM\6?|M? ʮ 1;:x¡ ~zx ?.S򩢚l8vC1ɫ }'[v4f9jpzY+TT4YVQ3r0k>mMY-jYN 2bb a劣۶2^]'! oCZ=Ϛ8#e %騹(SG'|u[ݑZ ek\'c_76.QOB@XsN{OZd^ Ź ĂZ*"q7̉j}lQuFw fqJVpEݳiHoBI J5`ˆ4=ٰfg%#t\ Нrص!IۿpwUa~ 21mP/:O1|;\䜇/G~UDs;qw7DБLzk'TiR?"lB̠cFw4}~ւ?kQd%6垠E IVTV@ ȏM}W,MH2':6d[Ih+O #횩(l6xzZrl,|)?eL vek#(-t,Dr׿CU6Me4uBE6dZYC _xh3tQ9E<#˺i6֊pʖ؜Gk&]NXFȒ%«/O53ޱRBp |)+=U*+V{V諭Od#)?̝`pƹ;kɱֻ,Ik !$z6M@hBP7=g5n: ֚̅xzI}. >i)[* p@g IƸch@|R^:Մ?j;VZ*f&CT^9`[ܼER8U9n'mXᤏS1'A<0Bh\bPWThqPHQBLA)[Ϫu8`-HIɱms 14 9[qQ84ߑ<3% .sO7rIOd8f+*Utshve]n*ɏQ|̋azS˰Am[|wI~g}O@/NMi#Q_R:_(g"/XGdE+$$tbmc-/"9A\tCYAQGj*st$"oMk #zO·i/DEJOpfBfHSl_?a \:gfX?1"ʇj`TÍ9'\joqiS8 ]V8kd^?,SdZ(<+z7  `6/AL۱6kᇻHVx|9%cA4l#4.亄a Ԇ;o9^@T![ßЗoi|9aʏ/K&0j3kHaO-LNJu&;I^eVN->F2XԦ^TLwf|8[Psb:ZeNV"ۆ3sÒlfxLtSd{?(ʄ)+|i#m;ӟW[uzxAXJom-j,Z@7.Mk8%*{"B(^G%|}?3] s5s`j+)h57t`ۘ-T~kW<"S5%}"{ʍ.Nf8F1dxSX٫ѦZ͕0 hk 7OEjk |.Dil[u#~UFV;nۉ{E؉ڿn8&!O_F9&5}`jCJy ֨%_%Ʈ)-t͌]_7dIcJݘ[+S#= c<_앚_Vij @6y,bw  ᶈ9_F/z>~- .Mpt?E׍ǚ'b+6e[lc%/ck}b4&>4$Ѯ[#Prnb6PTh~aáEUpfWB;{:|o# Vf7SuR\c7C:2Ngz=g%LE (M5iu" ׄ? A 0Xl[,@~i^r^9$¯{k7]Fj*s*q2mNOw_|4ׇ$vw:,ЩHCX~f>N l`ZW_CCkƲi)2bbYwc Qһ8x 2u˧$_+\TVC9Ӽؗ7Bmg(P!% ?pʈok1U xh4hȳY0o]v,JAeͳ*O_l:CpMBNv6 tm-ϟ e3Q=^\3 |K`V.Kș I+8ś1[b5Q xzR^:A[Z#_KdYt^¡Ό]nLj;TrB>Ȼ/* CYۛ:Gkݳo@5>oFCיq hguQW=I9Y=)ʡQh!z ]3,{,pn'-UH9⥽{LNv',)lp`#<<3w]Ǝ.(]:9(27X.ZFiz-%WXvy#yag3T~C-_EĻQ.…Kx!OPG {,So7b}c\'N]x|ןY#i}i9UR/ndތǫTRs`#;:,aJ'x2܄~!iE/r+he=re=áGN}K?[wÅ뮤׹KYtZ`Mv|Y8bD/|ܤ<.Xk@[8N2l)V0"^Yft~F^4\v;Q#Ziv.*)Qε/@GDZa;``vCA 7k )~)D+\ LI%gj|"ܢ(p- 25),wJ\I,02(F^bH6'yeN~7EnTBd{.7@FKnb5jy"$Eu-Q4z>Jr@ݼQ!@oCb_'_cl'clHJN  裬t5H͸C0;q6?V]hEZ_VǤk?|٘5;Fy&Qs$0{@S{NWsbZwc} F*h){=Ք}ʒB1k !X?64uA+oPGn~Dh%9hg " s:F.|C?@j+߮}<̜v!='6_ERv.=d͇,/] TO 7C{9c끣"g8T)b{܋2!(Sw_dowi#AVD^9HxU<p`&ߜ?)ϱOA}n76W/hIkU9#pH_Q1GoMh+# Ї`QxKEB0Twe,'Ś)!ڇ #N. <󘑱<.'ZFV wQK#9:1 I8)xEUmD?hY$ellRMu#>fAz$x 0PKDWA^CPK/C styles.xmlَ6}p}-ݳ =f@yhD|뷊D]nAà:XHّJD0O|FTd?}wt7_>ݎti#/jcJASTmt%-<&ޘa6 ԚTbmђ rHIrJӐ|'v"JE^:R9+>Zt:-N념er4Z++ V.)Z&dqsT7-UC4YU=QMz royt󮳐6'0b|n|ASBܖRǴ! lqWq|*I2Me^EO Ok|Hi,#GtS-УoBZYu9/zԽ̲ATgPG2uw `S$)SW x8u؀I*u߉C@p J ٦šJr^", Ǖ$| =;()W>ڼQ/7 0E% 03~&9ϑM>W)ˈ"JviOoIq}q5篤 nI^2B9Ɍ'}]Wlx܅SxP-sYhO 4H%RxX_@ԫ6B$"TpנM^X̹uetG*Ca/Iy`﨔fH(BD=a^ڨa/i>t:F$)t`C`BU#ʗQhLC'iw{J"Q]8 BTZR,¢^@4,([.2 2ۖ"X)2BBFG{5hUMjYAIO1&R5N}EYjW$HA@ Otxayc AQY+DXUg.Gdńg9şSeU 1dù5t%qxF`ZA ]fIF۹`!vm$ +L}gC*+u蠼¿m;$NC簓VHtg&ȭ GR:J'RZFZ>苁uڮ޽DA(K9 p| #O&HT6:Ԭm8b]+»' t6э.#l*m++c5,'&ӥ13RWd4y8Г<efՆg-O(#m]C haLyxJؐy&5m3 ~N NF{p✚׋j8ZYn;%^ 2X qV55ҳZ 6eag߭Tf!$͙L.nͺx6L,A9 _xL;vjz^bE|R0FRv k=p{v a%͢_ <̯_yE.@bKͭLiaޖzyOF-+2 ġ۔b{$NqD^G5Le pi{x]V@v(ʵ~rݼSnߩ\ީ\{rݽSߩ\I BSm4ך6u'!׈w#J=쫗il;rD%E6& гG4 m3{8}pu3Ǥ;`HmMpk"  y`mr2OH^@\.nčpp dB6302 @bp eZoQZ!GJP 3 DZ;Xf/H;^mIu/  Ivh?ɹV$(,mORc-J}aMb2Cvxu>vdWJ[״kס.uh8a=P/棥`Ϩ ~\8{+hGKpQ"9 <;ÿ?PK}*PK/C manifest.rdf͓n0PK/C^2 ''mimetypePK/CDDMThumbnails/thumbnail.pngPK/CN" 3 VEcontent.xmlPK/C{j@& Psettings.xmlPK/CLV*HWmeta.xmlPK/CDWA^C-ZPictures/100002010000020C0000010B42064344.pngPK/C}* styles.xmlPK/Ch ͤmanifest.rdfPK/C Configurations2/statusbar/PK/CDConfigurations2/toolbar/PK/CzConfigurations2/menubar/PK/CConfigurations2/floater/PK/C'Configurations2/accelerator/current.xmlPK/C=Configurations2/images/Bitmaps/PK/CzConfigurations2/toolpanel/PK/CConfigurations2/progressbar/PK/CConfigurations2/popupmenu/PK/C'>$META-INF/manifest.xmlPKtntnet-3.0/doc/chunked-encoding-howto.markdown000066400000000000000000000053721365471676700216010ustar00rootroot00000000000000Chunked encoding ================ Why chunked encoding -------------------- By default tntnet uses normal http. The http reply consists of http headers and a http body. The header specifies the number of bytes of the body. For tntnet that implies, that it has to know the size of the reply before starting to send the reply. Since tntnet components are dynamic the only way to know that is to collect the output somewhere. This of course needs some memory and delays the answer on the client side. This is ok for most of the requests since the reply is normally quite small. For bigger replies this may not be the best way. Therefore the designers of http invented another operation mode. Chunked encoding do not send the full size of the reply at start but sends the reply in smaller portions. The server do not need to know how many bytes will be sent when starting and it can start sending before processing is finished. Starting with tntnet 2.3 supports chunked encoding. How to use chunked encoding --------------------------- Using chunked encoding in tntnet is so easy that it do not really fill a whole document. The component must enable it by calling the method: reply.setChunkedEncoding(); After that output is sent in chunks of 8192 bytes to the client. The application can flush the output stream in which case all data collected so far is sent in a possibly smaller chunk to the client. This is done with the normal flush operation of the output stream. In C++ sections the flush method can be used: reply.out().flush(); Alternatively in ecpp the `std::flush` manipulator may be sent: <$ std::flush $> It makes no difference whether the flush is done on `reply.out()` or `reply.sout()`. The former is the "raw" output stream and the latter is the output stream which escapes html output. Limitations of chunked encoding ------------------------------- Unfortunately there are some limitations in tntnet when using chunked encoding. The first request of a session must not be chunked encoding since tntnet checks after the request processing whether session variables were used and when so and no session cookie was received before, a cookie is sent. Since enabling chunked encoding sends the headers already and starts sending the body, tntnet can't send the session cookie any more. Also the request is not allowed to fail after enabling chunked encoding. Normally a request can throw a exception and tntnet will reply with a internal server error to the client. Tntnet can't do that when it has already send the http ok code. Throwing an exception in the component will just close the connection, which results in a incomplete reply. The component may set http headers like setting the content type. The component has to do that before enabling chunked encoding. tntnet-3.0/doc/jquery-howto.markdown000066400000000000000000000317431365471676700177140ustar00rootroot00000000000000Using jQuery in Tntnet applications =================================== Introduction ------------ [jQuery](http://jquery.com) is a fast, small, and feature-rich JavaScript library. It makes things like HTML document traversal and manipulation, event handling, animation, and Ajax much simpler with an easy-to-use API that works across a multitude of browsers. With a combination of versatility and extensibility, jQuery has changed the way that millions of people write JavaScript. To integrate jQuery in a web application, the jQuery library must be made available to the web application. This is normally done by copying the jQuery to the web space of a web server. From the point of view of the web server it is just a static file. Since this is valid for many javascipt libraries, this same howto can be used to integrate other javascript libraries as well. Make jQuery available to the application ---------------------------------------- When using jQuery in a web application, jQuery becomes a essential part of the application. In tntnet all those parts are typically compiled into the application, so that the resulting binary will be self contained. There are more than one way to do it in tntnet but lets concentrate to the simplest one first. The `ecppc` compiler has a binary mode, which do not interpret any tags in the source. This is used to compile static files like the jquery.js file into C++ code. The flag `-b` must be passed to `ecppc`. The command is: ecppc -b jquery.js This generates a jquery.cpp, which can be compiled and linked into your web application. The code must be compiled and linked into your application. The next step is to make it available to the browser. For this a suitable mapping from url to the component name is needed. The name of the resulting component is the basename of our file, so it is _jquery_ here. When you for example compile and link the resulting code into a library named _myapp_ the full component name for the mapping is _jquery@myapp_. The generated applications use a standard mapping: $1@myapp ^/([^.]+)(\..+)? This is fine here. The url _/jquery.js_ is mapped to our component and hence delivers the jquery library to the browser under this url. To use it in a html page, you have to add this into the `` section of the page: And we are done. TODO full html example Adding jQuery UI ---------------- The [jQuery UI](http://jqueryui.com) library adds many widgets and effects to the jQuery library like date pickers or progress bars. Compared to jQuery, the jQuery UI is not just one file but a whole directory structure. This makes it a little more complicated to compile it into your application. But once understood it is not really difficult. Since there are so many files, it is much easier and also cheaper to put all the files into one single component. This is done using the multibinary feature of `ecppc` by passing the option `-bb`. This feature can combine multiple files into a single tntnet component. To access a single file in that component the path info must be set in the mapping. This sounds complicated but it isn't. First we create a component from our files. We download jQuery UI from the web site and unpack the files in our project first. Lets assume, our jQuery UI files can be found in our project directory under the path _jquery-ui-1.10.3_. The multibinary feature of `ecppc` expects a list of file names as command line parameters. You should set a suitable component name using the option `-n` also since by default the name is just `image`, which will result in duplicate component names if you have multiple multibinary components in your application. The simplest way is to use the command: ecppc -bb -n jqueryui -p $(find jquery-ui-1.10.3 -type f) Which uses the shell to find all files in our jQuery UI distribution and passes those to `ecppc`. The option `-p` is important here also since by default the path is stripped from our files when generating urls, which must not be done for jQuery UI. Since the output file name is built from the component name, the resulting file is named jqueryui.cpp. This can be again compiled and linked into our application. Note that we need to pass the full path name including _jquery-ui-1.10.3_ to the _jqueryui_ component in the mapping. The standard mapping is not suitable any more. We need our own mapping. We generate a mapping, where we strip or directory prefix away: jqueryui@myapp ^/(.*)? jquery-ui-1.10.3/$1 Now we are ready to use jQuery UI in our web application. As a example, we create a text field with a date picker. For that we need to load some javascript files and on css file. We add this to our ``: Now we are ready to add a datepicker to our text fields by using the `datepicker` function of jquery-ui on initialization: We assume we have a input element in our html page somewhere:

Date:

For details about the datepicker you may want to read the manual of jQuery UI. For completeness, here is the full page: ecpp application jdate

jQuery UI datepicker demo

Date:

Using Ajax ---------- Ajax is an acronym for Asyncronous JavaScript and XML. Despite the name the use of XML is not required. Today most Ajax requests do not actually use XML at all. Frequently JSON or just HTML fragments are sent from the server as a reply of asynchronous requests. The jQuery library makes it easy to work with those asynchronous requests. And since for Ajax applications it is typical, that many small requests are sent to the server, it is recommended to uses a quick server side framework like tntnet. So lets look for a example how to work with Ajax with jQuery and tntnet. We create a page with 2 buttons. Clicking on a button will load a html fragment from the server. We already have integrated jQuery into our application. Now we add a page, say `mainpage.ecpp` and 2 html fragments `page1.ecpp` and `page2.ecpp`. The `mainpage.ecpp` is here: jQuery demo application

jQuery Ajax demo

So actually a very simple jQuery application. Clicking on one of the buttons will load the subpage into our content div. The `page1.ecpp` and `page2.ecpp` may contain ecpp code including dynamic content, which is loaded into the div without reloading the whole page. The special here regarding tntnet is that there is nothing special here. It just gives us the chance to load dynamic html fragments from the server. Json ---- Instead of loading html fragments, it is sometimes more convenient to load just the data and process data on the client side in JavaScript. In tntnet server side processing is done using C++. Data processing results in C++ objects or structs. We need a facility to transfer those C++ objects to the JavaScript world and make them accessible there. We cannot send C++ objects over the wire and neither can use C++ objects in JavaScript. So we need a way to convert those C++ objects into JavaScript. Luckily we have JSON support in the serialization framework of cxxtools which greatly simplifies that. On the client side we use the function `jQuery.getJSON()`. To demonstrate the use, we need to write 2 components. One component is the page, which displays the screen and requests the data and the other component processes that request and sends the result back in JSON format. In our example we create a screen, which shows a product in a table with buttons to request the next and previous product. For simplicity we omit any kind of error handling. So here is our screen, which shows the products: Products

Products

Name
Price
The html part shows a simple table with one product. In the JavaScript part we define a variable `currentRec` which holds the current record number and a function `loadData` which loads the current record into the screen using JSON. We implement and bind appropriate JavaScript functions for the two buttons to load the next or previous records. The function `$.getJSON` expects a JSON result and calls the callback function when the reply returns with success. In that callback we get the JSON stucture already parsed. So it is very easy to access the members of our product. Note that we pass the requested record number as `recno` to the server. In the next step we need to implement the server side component, which returns the selected record. Here is the code: <%args> unsigned recno; <%pre> #include #include // we define a data structure: struct Product { std::string name; double price; }; // to convert the struct to JSON we need to make it serializable by defining a // serialization operator for that: inline void operator<<= (cxxtools::SerializationInfo& si, const Product& product) { si.addMember("name") <<= product.name; si.addMember("price") <<= product.price; } // This is our "database" Product products[] = { { "Milk", 1.5 }, { "Honey", 3.2 } }; const unsigned productCount = sizeof(products)/sizeof(Product); <%cpp> if (recno < productCount) { // convert the selected record to JSON using the JSON serializer of cxxtools: cxxtools::JsonSerializer serializer(reply.out()); serializer.serialize(products[recno]); } Here we define a C++ structure and make it serializable by defining the serialization operator. In a real world project we would implement that in separate C++ files and headers but here we just put it inline into our component. We simulate a database using just a static array of products. Using `cxxtools::JsonSerializer` we convert the requested product into JSON format, which can be easily processed on the client side using JavaScript as seen above. Conclusion ---------- Using jQuery with tntnet it is easy to create powerful and highly responsive applications. Tntnet gives the developer the power and flexibility on the server side. jQuery makes it easy on the client side. Using the serialization it is even easy to use C++ data structures in JavaScript code. The demonstration code can be found at [github](https://github.com/maekitalo/jqtnt). tntnet-3.0/doc/man/000077500000000000000000000000001365471676700142365ustar00rootroot00000000000000tntnet-3.0/doc/man/Makefile.am000066400000000000000000000006201365471676700162700ustar00rootroot00000000000000dist_man_MANS = \ tntnet.8 \ ecppc.1 \ ecpp.7 \ tntnet-defcomp.1 \ tntnet.xml.7 if GENERATE_MAN tntnet.8: tntnet.8.markdown $(MD2MAN) -in $< -out $@ ecppc.1: ecppc.1.markdown $(MD2MAN) -in $< -out $@ ecpp.7: ecpp.7.markdown $(MD2MAN) -in $< -out $@ tntnet-defcomp.1: tntnet-defcomp.1.markdown $(MD2MAN) -in $< -out $@ tntnet.xml.7: tntnet.xml.7.markdown $(MD2MAN) -in $< -out $@ endif tntnet-3.0/doc/man/README.md000066400000000000000000000005041365471676700155140ustar00rootroot00000000000000The man pages are maintained in markdown format and converted with go-md2man to a man page. To generate e.g. tntnet.xml.7 this command was used: go-md2man -in tntnet.xml.7.markdown -out tntnet.xml.7 To generate all man pages run this: for a in *.markdown; do go-md2man -in $a -out $(basename $a .markdown); done tntnet-3.0/doc/man/ecpp.7000066400000000000000000000361261365471676700152650ustar00rootroot00000000000000.TH ecpp 7 "2006\-07\-23" Tntnet "Tntnet users guide" .SH NAME .PP ecpp \- template language for tntnet(8) .SH DESCRIPTION .PP \fB\fCecpp\fR is the template language used by the tntnet system to generate dynamic content. .PP A template consists of normal content (normally html data) enriched with special tags, which trigger some special handling. .PP One ecpp file is compiled into a C++ class. The C++ class is placed into the namespace component. A ecpp file compiled into a C++ class is called component. The name of the class is the basename of the file. .SS \fB\fCrequest\fR, \fB\fCreply\fR, \fB\fCqparam\fR .PP Each component has 3 parameters: \fB\fCrequest\fR, \fB\fCreply\fR and \fB\fCqparam\fR\&. \fB\fCrequest\fR holds information about the client request like http headers and the url, but also additional parameters specified in the config file tntnet.xml(7). The type of request is \fB\fCtnt::HttpRequest\fR\&. .PP \fB\fCreply\fR receives the answer from the component. The component can set additional http headers here, set cookies and \- most important \- generate output. The most important methods here are \fB\fCreply.out()\fR and \fB\fCreply.sout()\fR\&. Both return a \fB\fCstd::ostream\fR, which receives the output of the component. \fB\fCreply.sout()\fR has a filter installed, which translates some characters, with special meanings in html to the corresponding html entities. The characters are \fB\fC<\fR, \fB\fC>\fR, \fB\fC\&\fR, \fB\fC"\fR and \fB\fC\&'\fR\&. This is useful for printing values from variables to the html code. .PP \fB\fCqparam\fR holds the query parameters parsed from GET\- or POST\-parameters or received from other components. The type of \fB\fCqparam\fR is \fB\fCtnt::QueryParams\fR\&. Normally you use a \fB\fC<%args>\fR block to specify the parameters, but there are special cases, where it is useful to access these directly. .SS component addressing .PP Each component has a unique name. The name is composed from the class name, the character '@' and the name of the shared library, it is located. Components can have internal sub components. The name of the internal sub component is appended to the class name separated by a dot (.). .SS special rule for line feeds after a \fB\fC\fR\-tag .PP A line feed immediately after a closing tag for all \fB\fC<%something>\fR blocks are ignored. Hence blocks followed immediately one after another does not generate white space in output, which is often undesirable. .SS errorhandling .PP Error handling is done by exception. Tntnet catches all exceptions thrown by components and handles them properly. Exceptions must be derived from std::exception. Exceptions derived from \fB\fCtnt::HttpError\fR, are handled separately. They carry a http return code, which is sent to the client. Other exceptions derived from std::exception, result in a http error code 500 (Internal Server Error). .SH TAGS .PP \fB\fC<$ expr $>\fR Print expressions \fB\fCexpr\fR to the output stream. The characters \fB\fC<\fR, \fB\fC>\fR, \fB\fC\&\fR, \fB\fC"\fR and \fB\fC\&'\fR, which have special meanings in html, are translated to the corresponding html entities. .PP \fB\fC<$$ expr $>\fR Print expressions \fB\fCexpr\fR without translating characters with special meaning in html to html entities to the output stream. .PP \fB\fC\fR Conditional output. Print expression \fB\fCexpr\fR to the output stream, if \fB\fCcond\fR evaluates to true. Characters with special meaning in html are translated to the corresponding html entities. .PP \fB\fC\fR Conditional output. Print expression \fB\fCexpr\fR to the output stream, if \fB\fCcond\fR evaluates to true. Characters with special meaning in html are not translated to the corresponding html entities. .PP \fB\fC<\& component [ arguments ] >\fR Call the specified component. The output of the component is printed into the output stream. If the component name does not start with a letter, the ecpp compiler treats it as a expression, which returns the name of the component. You must surround the expression in brackets, if it contains spaces. .PP The arguments part specify the parameters, the component will receive. Arguments are name value pairs separated by '='. They are put in the \fB\fCqparam\fR parameter of the component and are normally declared in the \fB\fC<%args>\fR block. Values can be specified in 3 forms: .PP As a plain word without spaces .PP As a string enclosed in quotation marks .PP As a expression enclosed in brackets .PP A single plain word in the argument list is treated as a variable of type \fB\fCcxxtools::QueryParams\fR and a copy is passed to the component. Other parameters are added to this copy. If you want to pass all parameters of the current component put the variable \fB\fCqparam\fR as a plain word in the argument list. .PP \fB\fC\fR Closing tag for a component call. When components are called, this closing tag might occur later. The code in \fB\fC<%close>\fR block is placed here. .PP \fB\fC<{...}>\fR C++ inline processing block. The code in this block is copied into the C++ class unchanged. .PP A linefeed after the closing tag is not ignored. .PP \fB\fC<#...#>\fR Comment block. Everything in this block is ignored. .PP \fB\fC<%application [ scope="component|page|shared|global" ] >...\fR Variables defined here, have the lifetime of the application. .PP Application scope is automatically locked. .PP \fB\fC<%args>...\fR Defines GET or POST parameters received by the component. .PP Each argument has a name and optionally a default value. The default value is delimited by '=' from the name. A single argument definition followed by a semicolon (;). In the component a variable with the same name of type std::string is defined, which receives the value. .PP A argument name can be prefixed by a type definition. The ecpp compiler generates code, which tries to convert the value with the \fB\fCcxxtools\fR deserialization operator. If the argument can't be converted, the default value is set. .PP Argument names can be postfixed by empty square brackets. This defines a std::vector with the specified type or std::string, if no type is specified. This way multiple values with the same name can be received. If a type is specified, each value is converted to the target type. .PP \fB\fC<%attr>...\fR Components may define attributes, which can be queried from other components. These values are strings and are defined by specifying a name followed by '=' and the string value. No type is allowed here. .PP A other component can the fetch a reference to the component using \fB\fCfetchComp(name)\fR\&. \fB\fCfetchComp\fR is a member of the base class \fB\fCtnt::EcppComponent\fR of components built with ecpp. .PP The component has then a member method \fB\fCgetAttribute(name)\fR, which returns the attribute or a empty string when not found. A different default string can be passed as a second parameter to \fB\fCgetAttribute\fR\&. .SS Example: .PP A content component specifies a title: .PP .RS .nf <%attr> title = "my title"; .fi .RE .PP A component \fB\fCwebmain\fR want to add a title depending on a content component: .PP .RS .nf <$ fetchComp("theContent").getAttribute("title", "default title") $> ... .fi .RE .PP To separte the C++ code from the html, the actual doing can be moved to a C++ section. The component can then be also called later to generate the content: .PP .RS .nf <%cpp> tnt::Component\& theContent = fetchComp("theContent"); std::string title = theContent.getAttribute("title", "default title"); <$ title $> ...
<{ theContent(request, reply, qparam); }>
.fi .RE .PP \fB\fC<%close>...\fR Code in these tags is placed into the calling component, when a closing tag \fB\fC\fR is found. .PP The \fB\fC<%close>\fR receives the same parameters like the corresponding normal component call. .PP This tag is deprecated and should not be used any more. .PP \fB\fC<%config>...\fR Often web applications need some configuration like database names or login information to the database. These configuration variables can be read from the tntnet.xml. Variable names ended with a semicolon are defined as static std::string variables and filled from tntnet.xml. A variable can be prepended by a type. The value from tntnet.xml is then converted with a \fB\fCstd::istream\fR\&. .PP You can also specify a default value by appending a '=' and the value to the variable. .SS Example: .PP .RS .nf <%config> dburl = "sqlite:db=mydbfile.sqlite"; int maxvalue = 10; .fi .RE .PP tntnet.xml: \fB\fCpostgresql:dbname=mydb\fR .PP \fB\fC<%cpp>...\fR C++ processing block. The code between these tags are copied into the C++ class unchanged. .PP A linefeed after the closing tag is ignored. .PP \fB\fC<%def name>...\fR Defines a internal sub component with the name name, which can be called like other components. .PP \fB\fC<%doc>...\fR Comment block. Everything in this block is ignored. .PP A linefeed after the closing tag is ignored. .PP \fB\fC<%get>...\fR Works like a \fB\fC<%args>\fR block but receives only GET parameters. .PP \fB\fC<%include>filename\fR The specified file is read and compiled. .PP \fB\fC<%param>...\fR Defines parameter received from calling components. In contrast to query parameters these variables can be of any type. The syntax (and the underlying technology) is the same like in scoped variables. See the description about scoped variables to see how to define parameters. The main difference is, that a parameter variable has no scope, since the parameter is always local to the component. .PP \fB\fC<%out> expr \fR Same as \fB\fC<$$ ... $>\fR\&. Prints the contained C++ expression \fB\fCexpr\fR\&. .PP \fB\fC<%post>...\fR Works like a \fB\fC<%args>\fR block but receives only POST parameters. .PP \fB\fC<%pre>...\fR Defines C++ code, which is placed outside the C++ class and outside the namespace definition. This is a good place to define #include directives. .PP \fB\fC<%request [ scope="component|page|shared|global" ] >...\fR Define request scope variables. Variables defined here, has the lifetime of the request. .PP \fB\fC<%session [ scope="component|page|shared|global" ] >...\fR Variables defined here, has the lifetime of the session. .PP Sessions are identified with cookies. If a \fB\fC<%session>\fR block is defined somewhere in a component, a session cookie is sent to the client. .PP Sessions are automatically locked. .PP \fB\fC<%securesession [ scope="component|page|shared|global" ] >...\fR Secure session is just like session but a secure cookie is used to identify the session. Secure cookies are transferred only over a ssl connection from the browser and hence the variables are only kept in a ssl secured application. .PP If a variable defined here is used in a non ssl page, the variable values are lost after the current request. .PP \fB\fC<%sout> expr \fR Same as \fB\fC<$ ... $>\fR\&. Prints the contained C++ expression \fB\fCexpr\fR\&. The characters \fB\fC<\fR, \fB\fC>\fR, \fB\fC\&\fR, \fB\fC"\fR and \fB\fC\&'\fR, which have special meanings in html, are translated to the corresponding html entities. .PP \fB\fC<%thread [ scope="component|page|shared|global" ] >...\fR Variables defined here, has the lifetime of the thread. Each thread has his own instance of these variables. .PP Thread scope variables do not need to be locked at all, because they are only valid in the current thread. .SH SCOPED VARIABLES .PP Scoped variables are c++ variables, whose lifetime is handled by tntnet. These variables has a lifetime and a scope. The lifetime is defined by the tag, used to declare the variable and the scope is passed as a parameter to the tag. .PP There are 5 different lifetimes for scoped variables: .PP \fB\fCrequest\fR The variable is valid in the current request. The tag is \fB\fC<%request>\fR\&. .PP \fB\fCapplication\fR The variable is valid in the application. The tag is \fB\fC<%application>\fR\&. The application is specified by the shared library of the top level component. .PP \fB\fCsession\fR The variable is valid for the current session. The tag is \fB\fC<%session>\fR\&. If at least session variable is declared in the current request, a session cookie is sent to the client. .PP \fB\fCthread\fR The variable is valid in the current thread. The tag is \fB\fC<%thread>\fR\&. .PP \fB\fCparam\fR The variable receives parameters. The tag is \fB\fC<%param>\fR\&. .PP And 3 scopes: .PP \fB\fCcomponent\fR The variable is only valid in the same component. This is the default scope. .PP \fB\fCpage\fR The variable is shared between the components in a single ecpp file. You can specify multiple internal sub components in a \fB\fC<%def>\fR block. Variables, defined in page scope are shared between these sub components. .PP \fB\fCglobal\fR or \fB\fCshared\fR Variables are shared between all components. If you define the same variable with shared scope in different components, they must have the same type. This is achieved most easily defining them in a separate file and include them with a \fB\fC<%include>\fR block. The \fB\fCglobal\fR and \fB\fCshared\fR are just synonyms. .PP Variables are automatically locked as needed. If you use session variables, tntnet ensures, that all requests of the same session are serialized. If you use application variables, tntnet serializes all requests to the same application scope. Request and thread scope variables do not need to be locked at all, because they are not shared between threads. .SS Syntax of scoped variables .PP Scoped variables are declared with exactly the same syntax as normal variables in c++ code. They can be of any type and are instantiated, when needed. Objects, which do not have default constructors, need to be specified with proper constructor parameters in brackets or separated by '='. The parameters are only used, if the variable need to be instantiated. This means, that parameters to e.g. application scope variables are only used once. When the same component is called later in the same or another request, the parameters are not used any more. .SS Examples .PP Specify a application specific shared variable, which is initialized with 0: .PP .RS .nf <%application> unsigned count = 0; .fi .RE .PP Specify a variable with a user defined type, which holds the state of the session: .PP .RS .nf <%session> MyClass sessionState; .fi .RE .PP Specify a persistent database connection, which is initialized, when first needed and hold for the lifetime of the current thread. This variable may be used in other components: .PP .RS .nf <%thread scope="shared"> tntdb::Connection conn(dburl); .fi .RE .SH AUTHOR .PP This manual page was written by Tommi Mäkitalo \[la]tommi@tntnet.org\[ra]\&. .SH SEE ALSO .PP tntnet(8), ecppc(1) tntnet-3.0/doc/man/ecpp.7.markdown000066400000000000000000000341331365471676700171020ustar00rootroot00000000000000ecpp 7 "2006-07-23" Tntnet "Tntnet users guide" =============================================== NAME ---- ecpp - template language for tntnet(8) DESCRIPTION ----------- `ecpp` is the template language used by the tntnet system to generate dynamic content. A template consists of normal content (normally html data) enriched with special tags, which trigger some special handling. One ecpp file is compiled into a C++ class. The C++ class is placed into the namespace component. A ecpp file compiled into a C++ class is called component. The name of the class is the basename of the file. ### `request`, `reply`, `qparam` Each component has 3 parameters: `request`, `reply` and `qparam`. `request` holds information about the client request like http headers and the url, but also additional parameters specified in the config file tntnet.xml(7). The type of request is `tnt::HttpRequest`. `reply` receives the answer from the component. The component can set additional http headers here, set cookies and - most important - generate output. The most important methods here are `reply.out()` and `reply.sout()`. Both return a `std::ostream`, which receives the output of the component. `reply.sout()` has a filter installed, which translates some characters, with special meanings in html to the corresponding html entities. The characters are `<`, `>`, `&`, `"` and `'`. This is useful for printing values from variables to the html code. `qparam` holds the query parameters parsed from GET- or POST-parameters or received from other components. The type of `qparam` is `tnt::QueryParams`. Normally you use a `<%args>` block to specify the parameters, but there are special cases, where it is useful to access these directly. ### component addressing Each component has a unique name. The name is composed from the class name, the character '@' and the name of the shared library, it is located. Components can have internal sub components. The name of the internal sub component is appended to the class name separated by a dot (.). ### special rule for line feeds after a ``-tag A line feed immediately after a closing tag for all `<%something>` blocks are ignored. Hence blocks followed immediately one after another does not generate white space in output, which is often undesirable. ### errorhandling Error handling is done by exception. Tntnet catches all exceptions thrown by components and handles them properly. Exceptions must be derived from std::exception. Exceptions derived from `tnt::HttpError`, are handled separately. They carry a http return code, which is sent to the client. Other exceptions derived from std::exception, result in a http error code 500 (Internal Server Error). TAGS ---- `<$ expr $>` Print expressions `expr` to the output stream. The characters `<`, `>`, `&`, `"` and `'`, which have special meanings in html, are translated to the corresponding html entities. `<$$ expr $>` Print expressions `expr` without translating characters with special meaning in html to html entities to the output stream. `` Conditional output. Print expression `expr` to the output stream, if `cond` evaluates to true. Characters with special meaning in html are translated to the corresponding html entities. `` Conditional output. Print expression `expr` to the output stream, if `cond` evaluates to true. Characters with special meaning in html are not translated to the corresponding html entities. `<& component [ arguments ] >` Call the specified component. The output of the component is printed into the output stream. If the component name does not start with a letter, the ecpp compiler treats it as a expression, which returns the name of the component. You must surround the expression in brackets, if it contains spaces. The arguments part specify the parameters, the component will receive. Arguments are name value pairs separated by '='. They are put in the `qparam` parameter of the component and are normally declared in the `<%args>` block. Values can be specified in 3 forms: As a plain word without spaces As a string enclosed in quotation marks As a expression enclosed in brackets A single plain word in the argument list is treated as a variable of type `cxxtools::QueryParams` and a copy is passed to the component. Other parameters are added to this copy. If you want to pass all parameters of the current component put the variable `qparam` as a plain word in the argument list. `` Closing tag for a component call. When components are called, this closing tag might occur later. The code in `<%close>` block is placed here. `<{...}>` C++ inline processing block. The code in this block is copied into the C++ class unchanged. A linefeed after the closing tag is not ignored. `<#...#>` Comment block. Everything in this block is ignored. `<%application [ scope="component|page|shared|global" ] >...` Variables defined here, have the lifetime of the application. Application scope is automatically locked. `<%args>...` Defines GET or POST parameters received by the component. Each argument has a name and optionally a default value. The default value is delimited by '=' from the name. A single argument definition followed by a semicolon (;). In the component a variable with the same name of type std::string is defined, which receives the value. A argument name can be prefixed by a type definition. The ecpp compiler generates code, which tries to convert the value with the `cxxtools` deserialization operator. If the argument can't be converted, the default value is set. Argument names can be postfixed by empty square brackets. This defines a std::vector with the specified type or std::string, if no type is specified. This way multiple values with the same name can be received. If a type is specified, each value is converted to the target type. `<%attr>...` Components may define attributes, which can be queried from other components. These values are strings and are defined by specifying a name followed by '=' and the string value. No type is allowed here. A other component can the fetch a reference to the component using `fetchComp(name)`. `fetchComp` is a member of the base class `tnt::EcppComponent` of components built with ecpp. The component has then a member method `getAttribute(name)`, which returns the attribute or a empty string when not found. A different default string can be passed as a second parameter to `getAttribute`. ### Example: A content component specifies a title: <%attr> title = "my title"; A component `webmain` want to add a title depending on a content component: <$ fetchComp("theContent").getAttribute("title", "default title") $> ... To separte the C++ code from the html, the actual doing can be moved to a C++ section. The component can then be also called later to generate the content: <%cpp> tnt::Component& theContent = fetchComp("theContent"); std::string title = theContent.getAttribute("title", "default title"); <$ title $> ...
<{ theContent(request, reply, qparam); }>
`<%close>...` Code in these tags is placed into the calling component, when a closing tag `` is found. The `<%close>` receives the same parameters like the corresponding normal component call. This tag is deprecated and should not be used any more. `<%config>...` Often web applications need some configuration like database names or login information to the database. These configuration variables can be read from the tntnet.xml. Variable names ended with a semicolon are defined as static std::string variables and filled from tntnet.xml. A variable can be prepended by a type. The value from tntnet.xml is then converted with a `std::istream`. You can also specify a default value by appending a '=' and the value to the variable. ### Example: <%config> dburl = "sqlite:db=mydbfile.sqlite"; int maxvalue = 10; tntnet.xml: `postgresql:dbname=mydb` `<%cpp>...` C++ processing block. The code between these tags are copied into the C++ class unchanged. A linefeed after the closing tag is ignored. `<%def name>...` Defines a internal sub component with the name name, which can be called like other components. `<%doc>...` Comment block. Everything in this block is ignored. A linefeed after the closing tag is ignored. `<%get>...` Works like a `<%args>` block but receives only GET parameters. `<%include>filename` The specified file is read and compiled. `<%param>...` Defines parameter received from calling components. In contrast to query parameters these variables can be of any type. The syntax (and the underlying technology) is the same like in scoped variables. See the description about scoped variables to see how to define parameters. The main difference is, that a parameter variable has no scope, since the parameter is always local to the component. `<%out> expr ` Same as `<$$ ... $>`. Prints the contained C++ expression `expr`. `<%post>...` Works like a `<%args>` block but receives only POST parameters. `<%pre>...` Defines C++ code, which is placed outside the C++ class and outside the namespace definition. This is a good place to define #include directives. `<%request [ scope="component|page|shared|global" ] >...` Define request scope variables. Variables defined here, has the lifetime of the request. `<%session [ scope="component|page|shared|global" ] >...` Variables defined here, has the lifetime of the session. Sessions are identified with cookies. If a `<%session>` block is defined somewhere in a component, a session cookie is sent to the client. Sessions are automatically locked. `<%securesession [ scope="component|page|shared|global" ] >...` Secure session is just like session but a secure cookie is used to identify the session. Secure cookies are transferred only over a ssl connection from the browser and hence the variables are only kept in a ssl secured application. If a variable defined here is used in a non ssl page, the variable values are lost after the current request. `<%sout> expr ` Same as `<$ ... $>`. Prints the contained C++ expression `expr`. The characters `<`, `>`, `&`, `"` and `'`, which have special meanings in html, are translated to the corresponding html entities. `<%thread [ scope="component|page|shared|global" ] >...` Variables defined here, has the lifetime of the thread. Each thread has his own instance of these variables. Thread scope variables do not need to be locked at all, because they are only valid in the current thread. SCOPED VARIABLES ---------------- Scoped variables are c++ variables, whose lifetime is handled by tntnet. These variables has a lifetime and a scope. The lifetime is defined by the tag, used to declare the variable and the scope is passed as a parameter to the tag. There are 5 different lifetimes for scoped variables: `request` The variable is valid in the current request. The tag is `<%request>`. `application` The variable is valid in the application. The tag is `<%application>`. The application is specified by the shared library of the top level component. `session` The variable is valid for the current session. The tag is `<%session>`. If at least session variable is declared in the current request, a session cookie is sent to the client. `thread` The variable is valid in the current thread. The tag is `<%thread>`. `param` The variable receives parameters. The tag is `<%param>`. And 3 scopes: `component` The variable is only valid in the same component. This is the default scope. `page` The variable is shared between the components in a single ecpp file. You can specify multiple internal sub components in a `<%def>` block. Variables, defined in page scope are shared between these sub components. `global` or `shared` Variables are shared between all components. If you define the same variable with shared scope in different components, they must have the same type. This is achieved most easily defining them in a separate file and include them with a `<%include>` block. The `global` and `shared` are just synonyms. Variables are automatically locked as needed. If you use session variables, tntnet ensures, that all requests of the same session are serialized. If you use application variables, tntnet serializes all requests to the same application scope. Request and thread scope variables do not need to be locked at all, because they are not shared between threads. ### Syntax of scoped variables Scoped variables are declared with exactly the same syntax as normal variables in c++ code. They can be of any type and are instantiated, when needed. Objects, which do not have default constructors, need to be specified with proper constructor parameters in brackets or separated by '='. The parameters are only used, if the variable need to be instantiated. This means, that parameters to e.g. application scope variables are only used once. When the same component is called later in the same or another request, the parameters are not used any more. ### Examples Specify a application specific shared variable, which is initialized with 0: <%application> unsigned count = 0; Specify a variable with a user defined type, which holds the state of the session: <%session> MyClass sessionState; Specify a persistent database connection, which is initialized, when first needed and hold for the lifetime of the current thread. This variable may be used in other components: <%thread scope="shared"> tntdb::Connection conn(dburl); AUTHOR ------ This manual page was written by Tommi Mäkitalo . SEE ALSO -------- tntnet(8), ecppc(1) tntnet-3.0/doc/man/ecppc.1000066400000000000000000000102661365471676700154170ustar00rootroot00000000000000.TH ecppc 1 "2006\-07\-23" Tntnet "Tntnet users guide" .SH NAME .PP ecppc \- compiler for ecpp(7) .SH SYNOPSIS .PP \fB\fCecppc\fR [\fB\fC\-bhszvtM\fR] [\fB\fC\-s\-\fR] [\fB\fC\-o\fR \fIfilename\fP] [\fB\fC\-n\fR \fIname\fP] [\fB\fC\-m\fR \fImimetype\fP] [\fB\fC\-\-mimetypes\fR \fIfilename\fP] [\fB\fC\-I\fR \fIdir\fP] [\fB\fC\-l\fR \fIlog\-category\fP] \fIfilename\fP .PP \fB\fCecppc\fR \fB\fC\-bb\fR \fIfilename\fP ... .PP \fB\fCecppc\fR [\fB\fCOPTION\fR] .SH DESCRIPTION .PP \fB\fCecppc\fR is the compiler for the ecpp\-language. \fB\fCecpp\fR is a template language, which lets the user embed C++\-code into HTML for use in tntnet(8). \fB\fCecppc\fR generates a C++\-class from a ecpp template. It can also compile binary data into a C++\-class, which makes it possible to integrate them in a tntnet application. .SH OPTIONS .PP \fB\fC\-b\fR This enables binary\-mode. Ecppc does not look for ecpp\-tags, but creates a class, which just copies the data .PP \fB\fC\-bb\fR This enables multi\-binary\-mode. Every binary\-file has some overhead, when packed into a tntnet\-application. This overhead can be quite significant, when binary\-files are small, like small icons in a web application. To reduce this overhead, multiple binaries can be packed into a single class, which removes the per\-binary overhead completely. .PP When the component is called, it uses the path\-info\-parameter (request.getPathInfo()) from the request, to decide, which binary to send. If no filename matches the path\-info, processing is declined. The binaries need not be of same mime\-type, since the mime\-type is looked automatically from the mime\-database by file\- extension of the source\-file. .PP \fB\fC\-i\fR \fIfilename\fP In multi binary mode (option \fB\fC\-bb\fR) filenames can be read from the file specified with this option. This can be useful when the command line gets too long or just for convenience. .PP \fB\fC\-I\fR \fIdir\fP Search include\-files in directory. This option can be passed multiple times. All specified directories are searched in turn for include\-files. .PP \fB\fC\-l\fR \fIlog\-category\fP Set log category. Default is \fIcomponent.componentname\fP\&. .PP \fB\fC\-L\fR Disable generation of #line\-directives .PP \fB\fC\-m\fR \fImimetype\fP Set mimetype of output. This is the mimetype, sent by the component to the browser in the Content\-Type\- header. Without this parameter the mimetype is looked up from the mime\-database of your system using the file\-extension of the source\-file. .PP \fB\fC\-\-mimetypes\fR \fIfile\fP Read mimetypes from file (default: /etc/mime.types). .PP \fB\fC\-M\fR This disables normal processing and prints just the ecpp\-dependencies from this component. The output can be included into a Makefile. Ecpp\-dependencies are introduces by the <%include>\-tag. .PP \fB\fC\-C, \-\-cmake\fR Prints ecpp dependencies in a syntax, which \fB\fCcmake\fR understands. .PP \fB\fC\-n\fR \fIname\fP Set the name of the component. Normally this is derived from the source\-file\-name by removing the path and .ecpp\-extension. .PP \fB\fC\-o\fR \fIfilename\fP Write the generated file to the specified file instead of deriving the filename from the source\-file\-name. The outputfilename is normally the source\-file where the extension is replaced by .cpp. .PP \fB\fC\-p\fR Keep path name when deriving name of component from input file name. .PP \fB\fC\-s\fR Generate singleton. Normally ecppc decides automatically, if the template is suitable for a singleton. This option force ecppc to generate a singleton. .PP \fB\fC\-s\-\fR Do not generate a singleton. .PP \fB\fC\-v\fR Enable verbose mode. This prints additional information about the processing on the standard\-output. .PP \fB\fC\-z\fR Compress the data in the component. Compressed data is automatically decopressed on first use. This reduces the code\-size, but slightly slows down the first call of the component. .PP \fB\fC\-h, \-\-help\fR display this information .PP \fB\fC\-V, \-\-version\fR display program version .SH AUTHOR .PP This manual page was written by Tommi Mäkitalo \[la]tommi@tntnet.org\[ra]\&. .SH SEE ALSO .PP tntnet(8), ecpp(7) tntnet-3.0/doc/man/ecppc.1.markdown000066400000000000000000000073731365471676700172450ustar00rootroot00000000000000ecppc 1 "2006-07-23" Tntnet "Tntnet users guide" ================================================ NAME ---- ecppc - compiler for ecpp(7) SYNOPSIS -------- `ecppc` [`-bhszvtM`] [`-s-`] [`-o` *filename*] [`-n` *name*] [`-m` *mimetype*] [`--mimetypes` *filename*] [`-I` *dir*] [`-l` *log-category*] *filename* `ecppc` `-bb` *filename* ... `ecppc` [`OPTION`] DESCRIPTION ----------- `ecppc` is the compiler for the ecpp-language. `ecpp` is a template language, which lets the user embed C++-code into HTML for use in tntnet(8). `ecppc` generates a C++-class from a ecpp template. It can also compile binary data into a C++-class, which makes it possible to integrate them in a tntnet application. OPTIONS ------- `-b` This enables binary-mode. Ecppc does not look for ecpp-tags, but creates a class, which just copies the data `-bb` This enables multi-binary-mode. Every binary-file has some overhead, when packed into a tntnet-application. This overhead can be quite significant, when binary-files are small, like small icons in a web application. To reduce this overhead, multiple binaries can be packed into a single class, which removes the per-binary overhead completely. When the component is called, it uses the path-info-parameter (request.getPathInfo()) from the request, to decide, which binary to send. If no filename matches the path-info, processing is declined. The binaries need not be of same mime-type, since the mime-type is looked automatically from the mime-database by file- extension of the source-file. `-i` *filename* In multi binary mode (option `-bb`) filenames can be read from the file specified with this option. This can be useful when the command line gets too long or just for convenience. `-I` *dir* Search include-files in directory. This option can be passed multiple times. All specified directories are searched in turn for include-files. `-l` *log-category* Set log category. Default is *component.componentname*. `-L` Disable generation of #line-directives `-m` *mimetype* Set mimetype of output. This is the mimetype, sent by the component to the browser in the Content-Type- header. Without this parameter the mimetype is looked up from the mime-database of your system using the file-extension of the source-file. `--mimetypes` *file* Read mimetypes from file (default: /etc/mime.types). `-M` This disables normal processing and prints just the ecpp-dependencies from this component. The output can be included into a Makefile. Ecpp-dependencies are introduces by the <%include>-tag. `-C, --cmake` Prints ecpp dependencies in a syntax, which `cmake` understands. `-n` *name* Set the name of the component. Normally this is derived from the source-file-name by removing the path and .ecpp-extension. `-o` *filename* Write the generated file to the specified file instead of deriving the filename from the source-file-name. The outputfilename is normally the source-file where the extension is replaced by .cpp. `-p` Keep path name when deriving name of component from input file name. `-s` Generate singleton. Normally ecppc decides automatically, if the template is suitable for a singleton. This option force ecppc to generate a singleton. `-s-` Do not generate a singleton. `-v` Enable verbose mode. This prints additional information about the processing on the standard-output. `-z` Compress the data in the component. Compressed data is automatically decopressed on first use. This reduces the code-size, but slightly slows down the first call of the component. `-h, --help` display this information `-V, --version` display program version AUTHOR ------ This manual page was written by Tommi Mäkitalo . SEE ALSO -------- tntnet(8), ecpp(7) tntnet-3.0/doc/man/tntnet-defcomp.1000066400000000000000000000111521365471676700172470ustar00rootroot00000000000000.TH tntnet\-defcomp 1 "2013\-05\-27" Tntnet "Tntnet users guide" .SH NAME .PP tntnet \- default components for tntnet(8) .SH DESCRIPTION .PP By default tntnet can just return a http error 404 \- not found. To do something meaningful tntnet loads shared libraries with components. By defining suitable mappings in tntnet.xml(7) tntnet loads those components, which does the actual work. .PP Since in the web world there are some really basic tasks, which every web server should be able to do, tntnet brings some standard components. The shared library, which does that is called \fB\fCtntnet\fR and hence every standard component has a component identifier of \fIcomponentname\fP\fB\fC@tntnet\fR\&. They are documented here. .SS static .PP The most commonly used standard component is \fB\fCstatic@tntnet\fR\&. It gives tntnet the ability to deliver files from the file system. For this it uses the \fB\fCpathinfo\fR setting from the mapping in tntnet.xml(7) as a file name and delivers the files. The extension of the files is used to look up the content type. The same mime database is used as in the next component \fB\fCmime@tntnet\fR\&. .PP \fIExample\fP .PP .RS .nf (.*) static@tntnet /var/www/htdocs/$1 .fi .RE .PP This setting configures tntnet as simple web server for static pages. .SS mime .PP The component \fB\fCmime@tntnet\fR sets just the content type header. The value is fetched from the argument "contenttype" if set. Otherwise the path info is used to detect the correct content type from the file extension using the configured mime db. .SS empty .PP The component \fB\fCempty@tntnet\fR generates just an empty result. By default a http return code OK (200) is set but can be changed with the argument \fIhttpcode\fP\&. Other arguments are interpreted as additional http headers, so that e.g. the content type header can be set. .PP \fIExample\fP .PP .RS .nf \\.js$ empty@tntnet application/javascript .fi .RE .PP This tells tntnet to reply all requests with a url ending \fI\&.js\fP with an empty javascript file. .SS unzip .PP The component \fB\fCunzip@tntnet\fR reads static data from a zip file. The file name is read from the argument "file" and the actual file from the path info. .PP If the argument "contenttype" is set, the content type http header is set from that value. Otherwise the path info is used to look up the content type from the file extension using the configured mime db. .PP \fIExample\fP .PP .RS .nf /thefile/(.*) unzip@tntnet $1 /var/www/thefile.zip .fi .RE .PP Reads file from the specified zip file when the url starts with \fB\fC/thefile/\fR\&. The actual file in the zip file is read from the rest of the url. The content type header is set according the the file extenxion and the file is sent to the client. .SS redirect .PP The component \fB\fCredirect@tntnet\fR just returns with a redirect to another page. The location for the redirect is specified in the \fB\fC\fR setting. .PP By default a temporary redirect code (301) is sent, but can be configured by adding a configuration argument "type". The value of the type can be "temporarily", "permanently" or a number, which is used. .PP \fIExample\fP .PP .RS .nf ^/$ redirect@tntnet /login.html .fi .RE .PP This setting redirects the client to the index.html file when the root directory is requested. .PP \fIExample for a permanent redirect\fP .PP .RS .nf ^/$ redirect@tntnet /index.html permanently .fi .RE .PP This setting redirects the client to the index.html file when the root directory is requested. .SS error .PP The error component returns a specific error code to the client when called. The code is specified using the argument \fB\fC\fR and the message using the argument \fB\fC\fR\&. The message may be omitted in which case a default error code specific text is used. .PP \fIExample\fP .PP .RS .nf ^POST$ error@tntnet 405 .fi .RE .PP This setting prevents tntnet to accept POST message. .SH AUTHOR .PP This manual page was written by Tommi Mäkitalo \[la]tommi@tntnet.org\[ra]\&. .SH SEE ALSO .PP tntnet\-project(1), ecpp(7), ecppc(1), tntnet.xml(7), tntnet-3.0/doc/man/tntnet-defcomp.1.markdown000066400000000000000000000107241365471676700210740ustar00rootroot00000000000000tntnet-defcomp 1 "2013-05-27" Tntnet "Tntnet users guide" ========================================================= NAME ---- tntnet - default components for tntnet(8) DESCRIPTION ----------- By default tntnet can just return a http error 404 - not found. To do something meaningful tntnet loads shared libraries with components. By defining suitable mappings in tntnet.xml(7) tntnet loads those components, which does the actual work. Since in the web world there are some really basic tasks, which every web server should be able to do, tntnet brings some standard components. The shared library, which does that is called `tntnet` and hence every standard component has a component identifier of *componentname*`@tntnet`. They are documented here. ### static The most commonly used standard component is `static@tntnet`. It gives tntnet the ability to deliver files from the file system. For this it uses the `pathinfo` setting from the mapping in tntnet.xml(7) as a file name and delivers the files. The extension of the files is used to look up the content type. The same mime database is used as in the next component `mime@tntnet`. *Example* (.*) static@tntnet /var/www/htdocs/$1 This setting configures tntnet as simple web server for static pages. ### mime The component `mime@tntnet` sets just the content type header. The value is fetched from the argument "contenttype" if set. Otherwise the path info is used to detect the correct content type from the file extension using the configured mime db. ### empty The component `empty@tntnet` generates just an empty result. By default a http return code OK (200) is set but can be changed with the argument _httpcode_. Other arguments are interpreted as additional http headers, so that e.g. the content type header can be set. *Example* \.js$ empty@tntnet application/javascript This tells tntnet to reply all requests with a url ending _.js_ with an empty javascript file. ### unzip The component `unzip@tntnet` reads static data from a zip file. The file name is read from the argument "file" and the actual file from the path info. If the argument "contenttype" is set, the content type http header is set from that value. Otherwise the path info is used to look up the content type from the file extension using the configured mime db. *Example* /thefile/(.*) unzip@tntnet $1 /var/www/thefile.zip Reads file from the specified zip file when the url starts with `/thefile/`. The actual file in the zip file is read from the rest of the url. The content type header is set according the the file extenxion and the file is sent to the client. ### redirect The component `redirect@tntnet` just returns with a redirect to another page. The location for the redirect is specified in the `` setting. By default a temporary redirect code (301) is sent, but can be configured by adding a configuration argument "type". The value of the type can be "temporarily", "permanently" or a number, which is used. *Example* ^/$ redirect@tntnet /login.html This setting redirects the client to the index.html file when the root directory is requested. *Example for a permanent redirect* ^/$ redirect@tntnet /index.html permanently This setting redirects the client to the index.html file when the root directory is requested. ### error The error component returns a specific error code to the client when called. The code is specified using the argument `` and the message using the argument ``. The message may be omitted in which case a default error code specific text is used. *Example* ^POST$ error@tntnet 405 This setting prevents tntnet to accept POST message. AUTHOR ------ This manual page was written by Tommi Mäkitalo . SEE ALSO -------- tntnet-project(1), ecpp(7), ecppc(1), tntnet.xml(7), tntnet-3.0/doc/man/tntnet-project.1000066400000000000000000000040601365471676700173000ustar00rootroot00000000000000.TH tntnet\-project 1 "2014\-09\-09" Tntnet "Tntnet users guide" .SH NAME .PP tntnet\-project \- project builder for tntnet(8) .SH SYNOPSIS .PP \fItntnet\-project\fP [\fB\fCOPTIONS\fR] <\fIproject name\fP> .PP \fItntnet\-project\fP [\fB\fC\-t \fR] [\fB\fC\-\-type=\fR] [\fB\fC\-m \fR] [\fB\fC\-\-model=\fR] <\fIproject name\fP> .SH DESCRIPTION .PP This manual page documents the \fB\fCtntnet\-project\fR command. .PP \fB\fCtntnet\-project\fR creates projects for tntnet(8). .SH OPTIONS .PP This programs options start with one dash (\fB\fC\-\fR) or two dashes (\fB\fC\-\-\fR). A summary of options is included below. .PP \fB\fC\-t , \-\-type=\fR .PP specifies application type .PP \fB\fC\-m , \-\-model=\fR .PP specifies application model .SS Types: .PP \fB\fCclassic\fR create a simple application with one page (default) .PP \fB\fCmvc\fR create a application with the mvc pattern .SS Models: .PP \fB\fCstandalone\fR create a standalone web application (default) .PP \fB\fCmodule\fR create a module to be loaded into the tntnet application server .SH EXAMPLES .PP \fItntnet\-project\fP \fImyApp\fP .PP create a \fIdefault\fP tntnet project .PP \fItntnet\-project\fP \fB\fC\-t mvc\fR \fImyApp\fP .PP \fItntnet\-project\fP \fB\fC\-\-type=mvc\fR \fImyApp\fP .PP create a tntnet \fIstandalone application\fP project with \fImvc\fP pattern .PP \fItntnet\-project\fP \fB\fC\-m module\fR \fImyApp\fP .PP \fItntnet\-project\fP \fB\fC\-\-model=module\fR \fImyApp\fP .PP create a tntnet \fIapplication server\fP project .PP \fItntnet\-project\fP \fB\fC\-t mvc \-m module\fR \fImyApp\fP .PP \fItntnet\-project\fP \fB\fC\-\-type=mvc \-\-model=module\fR \fImyApp\fP .PP create a \fImvc\fP pattern \fIapplication server\fP project .SH AUTHOR .PP tntnet was written by Tommi Mäkitalo \[la]tommi@tntnet.org\[ra]\&. .PP This manual page was written by Ralf Schülke \[la]ralf.schuelke@gmail.com\[ra] .SH SEE ALSO .PP tntnet(8), ecppc(1), tntnet.xml(7). .PP More documentation can be found in /usr/share/doc/tntnet\-doc/. tntnet-3.0/doc/man/tntnet-project.1.markdown000066400000000000000000000033541365471676700211260ustar00rootroot00000000000000tntnet-project 1 "2014-09-09" Tntnet "Tntnet users guide" ======================================================== NAME ---- tntnet-project - project builder for tntnet(8) SYNOPSIS -------- *tntnet-project* [`OPTIONS`] <*project name*> *tntnet-project* [`-t `] [`--type=`] [`-m `] [`--model=`] <*project name*> DESCRIPTION ----------- This manual page documents the `tntnet-project` command. `tntnet-project` creates projects for tntnet(8). OPTIONS ------- This programs options start with one dash (`-`) or two dashes (`--`). A summary of options is included below. `-t , --type=` specifies application type `-m , --model=` specifies application model ### Types: `classic` create a simple application with one page (default) `mvc` create a application with the mvc pattern ### Models: `standalone` create a standalone web application (default) `module` create a module to be loaded into the tntnet application server EXAMPLES -------- *tntnet-project* *myApp* create a *default* tntnet project *tntnet-project* `-t mvc` *myApp* *tntnet-project* `--type=mvc` *myApp* create a tntnet *standalone application* project with *mvc* pattern *tntnet-project* `-m module` *myApp* *tntnet-project* `--model=module` *myApp* create a tntnet *application server* project *tntnet-project* `-t mvc -m module` *myApp* *tntnet-project* `--type=mvc --model=module` *myApp* create a *mvc* pattern *application server* project AUTHOR ------ tntnet was written by Tommi Mäkitalo . This manual page was written by Ralf Schülke SEE ALSO -------- tntnet(8), ecppc(1), tntnet.xml(7). More documentation can be found in /usr/share/doc/tntnet-doc/. tntnet-3.0/doc/man/tntnet.8000066400000000000000000000041001365471676700156360ustar00rootroot00000000000000.TH tntnet 8 "2006\-07\-23" Tntnet "Tntnet users guide" .SH NAME .PP tntnet \- web application server for c++ .SH SYNOPSIS .PP \fB\fCtntnet\fR [\fB\fC\-c\fR \fIfile\fP] [\fB\fC\-\-logall\fR] .PP \fB\fCtntnet\fR\-C [\fB\fC\-q\fR \fIquery\-string\fP] \fIcomponentId\fP ... .SH DESCRIPTION .PP This manual page documents briefly the \fB\fCtntnet\fR command. .PP \fB\fCtntnet\fR is a web server that can generate dynamic content via precompiled C++ modules. .SH OPTIONS .PP A summary of options is included below. .PP \fB\fC\-c\fR \fIfile\fP Use file as the configuration file. If the \-c is omitted, the first nonoption argument is used as the config file. .PP \fB\fC\-\-logall\fR Initialize logging earlier. Normally logging is initialized after starting the listeners and changing user so that logfiles are created with the right owner. For debugging reasons this option forces to do that earlier. .PP \fB\fC\-C\fR Call components and print the result to stdout instead of starting tntnet as a webserver .PP \fB\fC\-q\fR \fIquery\-string\fP In \-C mode pass this query string to the component. The option may be repeated multiple times to pass name\-value\-pairs easily. .SH EXAMPLE .PP \fB\fCtntnet\fR \fB\fC\-C\fR \fB\fC\-q\fR \fB\fCarg1=35\fR \fB\fC\-q\fR \fB\fCarg2=7\fR \fB\fC\-q\fR \fB\fCop=/\fR \fIcalc@calc\fP .PP calls the component \fIcalc@calc\fP with query parameters and prints the result to stdout. .SH FILES .PP \fI/etc/tntnet/tntnet.xml\fP The default configuration file. .SH ENVIRONMENT .PP \fB\fCTNTNET\_CONF\fR This is checked for the configuration file name if it is not specified on the command line. .SH AUTHOR .PP tntnet was written by Tommi Mäkitalo \[la]tommi@tntnet.org\[ra]\&. .PP This manual page was written by Kari Pahula \[la]kaol@debian.org\[ra], for the Debian project (but may be used by others). .SH SEE ALSO .PP tntnet\-project(1), ecpp(7), ecppc(1), tntnet.xml(7), tntnet\-defcomp(1) Tntnet homepage \[la]http://www.tntnet.org\[ra]\&. More documentation can be found in /usr/share/doc/tntnet\-doc/. .PP Tntnet July 23, 2006 tntnet(8) tntnet-3.0/doc/man/tntnet.8.markdown000066400000000000000000000035721365471676700174730ustar00rootroot00000000000000tntnet 8 "2006-07-23" Tntnet "Tntnet users guide" ================================================ NAME ---- tntnet - web application server for c++ SYNOPSIS -------- `tntnet` [`-c` *file*] [`--logall`] `tntnet`-C [`-q` *query-string*] *componentId* ... DESCRIPTION ----------- This manual page documents briefly the `tntnet` command. `tntnet` is a web server that can generate dynamic content via precompiled C++ modules. OPTIONS ------- A summary of options is included below. `-c` *file* Use file as the configuration file. If the -c is omitted, the first nonoption argument is used as the config file. `--logall` Initialize logging earlier. Normally logging is initialized after starting the listeners and changing user so that logfiles are created with the right owner. For debugging reasons this option forces to do that earlier. `-C` Call components and print the result to stdout instead of starting tntnet as a webserver `-q` *query-string* In -C mode pass this query string to the component. The option may be repeated multiple times to pass name-value-pairs easily. EXAMPLE ----------- `tntnet` `-C` `-q` `arg1=35` `-q` `arg2=7` `-q` `op=/` *calc@calc* calls the component *calc@calc* with query parameters and prints the result to stdout. FILES ----------- */etc/tntnet/tntnet.xml* The default configuration file. ENVIRONMENT ----------- `TNTNET_CONF` This is checked for the configuration file name if it is not specified on the command line. AUTHOR ------ tntnet was written by Tommi Mäkitalo . This manual page was written by Kari Pahula , for the Debian project (but may be used by others). SEE ALSO -------- tntnet-project(1), ecpp(7), ecppc(1), tntnet.xml(7), tntnet-defcomp(1) [Tntnet homepage] (http://www.tntnet.org). More documentation can be found in /usr/share/doc/tntnet-doc/. Tntnet July 23, 2006 tntnet(8) tntnet-3.0/doc/man/tntnet.xml.7000066400000000000000000000722601365471676700164500ustar00rootroot00000000000000.TH tntnet.xml 7 "2006\-07\-23" Tntnet "Tntnet users guide" .SH NAME .PP tntnet.xml \- configuration file for tntnet(8) .SH DESCRIPTION .PP Tntnet is configured using a xml file. The name of the file is \fItntnet.xml\fP\&. The root node of \fItntnet.xml\fP should be \fB\fCtntnet\fR while it is not checked. Most of the settings are just single values. They are described here in alphabetical order. .SH SETTINGS .PP This section describes the variables, used by Tntnet (8). .PP \fB\fC\fR\fIfilename\fP\fB\fC\fR .PP Writes a log entry for each request in a common format. This format is compatible with most log file analyze systems for http servers. .PP The log file has the fields: \fB\fCpeer ip\fR \- \fB\fCusername\fR [\fB\fCtime\fR] "\fB\fChttp method\fR \fB\fCquery string\fR HTTP/\fB\fCmajor version\fR\&.\fB\fCminor version\fR" \fB\fChttp return code\fR \fB\fCcontent size\fR "\fB\fCreferer\fR" "\fB\fCuser agent\fR" .PP The \fB\fCusername\fR, \fB\fCreferer\fR and \fB\fCuser agent\fR may be '\-' when the value is not available. Also the \fB\fCcontent\-size\fR can be empty in some cases. .PP \fIExample\fP .PP .RS .nf /var/log/tntnet/access.log\fR\fIbytes\fP\fB\fC\fR .PP Specifies the number of bytes sent in a single system call. This does not limit anything in application level. It does not affect e.g. savepoints or exception handling. Component output is collected completely and then passed in chunks of \fB\fCbufferSize\fR bytes to the operating system. .PP The default value is 16384. .PP \fB\fC\fR [ \fB\fC\fR\fIpath1\fP\fB\fC\fR ] \fB\fC\fR .PP \fB\fCcomppath\fR specifies, where tntnet should search for webapplications. Tntnet searches first in the current directory and then in each directory, you specify here, until a library is found. You can repeat the directive as many times as desired to add more entries. If it is not found, the next \fB\fCmappings\fR entry is tried. .PP \fIExample\fP .PP .RS .nf /usr/local/lib/tntnet /usr/local/share/tntnet .fi .RE .PP \fB\fC\fR\fIdirectory\fP\fB\fC\fR .PP Does a chroot(2) system call on startup, which locks the process into the directory at system level. .PP \fIExample\fP .PP .RS .nf /var/tntnet .fi .RE .PP \fB\fC\fR\fI0|1\fP\fB\fC\fR .PP If this flag is set to 1, Tntnet forks at startup and terminates the parent process on successful initialization. .PP \fB\fC\fR\fIdirectory\fP\fB\fC\fR .PP Changes the current working directory of the process on startup. .PP \fIExample\fP .PP .RS .nf /var/tntnet .fi .RE .PP \fB\fC\fR\fIcontentType\fP\fB\fC\fR .PP Sets the content type header of the reply. The content type may be changed in the application using \fB\fCreply.setContentType("something")\fR\&. .PP By default "text/html; charset=UTF\-8" is set. .PP \fIExample\fP .PP .RS .nf text/html; charset=ISO\-8858\-1 .fi .RE .PP \fB\fC\fR\fIyes|no\fP\fB\fC\fR .PP Specifies, if Tntnet should use gzip compression at http level. By default Tntnet use compression. A http client like a web browser can send a header "Accept\-Encoding", to tell Tntnet, that it would accept compressed data. Tntnet then can decide, if it use compression. When the body is complete, Tntnet tries to compress the body. If the data can be compressed by more than 10%, Tntnet sends this compressed data. With this flag, this feature can be turned off. .PP Compression slows down processing but reduces the network load. Normally the size of html pages can be compressed by about 70%, while Tntnet slows down by up to 30%. .PP \fIExample\fP .PP .RS .nf no .fi .RE .PP \fB\fC\fR \fB\fC\fR\fIvalue1\fP\fB\fC\fR \fB\fC\fR\fIvalue2\fP\fB\fC\fR \fB\fC\fR .PP Sets environment variables. .PP \fB\fC\fR\fIfilename\fP\fB\fC\fR .PP Redirects stderr to the specified file when tntnet runs as a daemon. If ErrorLog is not set stderr is redirected to /dev/null. .PP \fIExample\fP .PP .RS .nf /var/log/tntnet/error.log .fi .RE .PP \fB\fC\fR\fIunix\-group\-id\fP\fB\fC\fR .PP Changes the group under which tntnet runs. .PP The user is changes using the system call setgid(2), which is only allowed, when tntnet starts as root user. .PP \fIExample\fP .PP .RS .nf tntnet\-group .fi .RE .PP \fB\fC\fR\fImilliseconds\fP\fB\fC\fR .PP Sets the timeout for keep\-alive requests. .PP Tntnet tries to do keep\-alive\-requests wherever possible. This has the effect, that tntnet can receive multiple requests within a single tcp connection. The connection times out after KeepAliveTimeout milliseconds. The timeout defaults to 15000ms. .PP \fIExample\fP .PP .RS .nf 300000 .fi .RE .PP \fB\fC\fR\fInumber\fP\fB\fC\fR .PP Sets the maximum number of request per tcp connection. This defaults to 100. .PP \fIExample\fP .PP .RS .nf 10 .fi .RE .PP \fB\fC\fR\fIlistener definition\fP\fB\fC\fR .PP Specifies, on which local interfaces tntnet waits for connections. There can be more than one Listen directives, in which case tntnet waits on every address. .PP See separate section \fIListeners\fP .PP \fB\fC\fR\fIlogger definition\fP\fB\fC\fR .PP Configures logging. See separate section \fIlogging\fP .PP \fB\fC\fR\fInumber\fP\fB\fC\fR .PP On startup Tntnet calls listen on the specified port. When the systemcall returns with an error, Tntnet tries again and fails after the specified number of attempts. .PP The default number is 5. .PP \fIExample\fP .PP .RS .nf 10 .fi .RE .PP \fB\fC\fR\fInumber\fP\fB\fC\fR .PP The system call listen(3p) needs a parameter backlog, which specifies, how many pending connections the operating system should queue before it starts to ignore new request. The value is configurable here. .PP The default value is 16. .PP \fIExample\fP .PP .RS .nf 64 .fi .RE .PP \fB\fC\fR\fIurlmappings\fP\fB\fC\fR .PP This is the most important setting for tntnet. It specifies, which components schould be called on which urls. .PP For details see the section \fIURL MAPPING\fP\&. .PP \fB\fC\fR\fInumber\fP\fB\fC\fR .PP Mapping urls to components is done using regular expressions. Executing these expressions is quite expensive while the number of different urls is quite limited in typical web applications. Hence tntnet caches the results. .PP The caching algorithm is very simple. Tntnet just collects the results in a map. When the maximum size of the list is reached, it is cleared. This makes management of the cache very cheap. .PP This setting sets the maximum number of entries in the map. .PP If you see frequently a warning message, that the cache is cleared, you may consider increasing the size. .PP The default value is 8192. .PP \fIExample\fP .PP .RS .nf 32768 .fi .RE .PP \fB\fC\fR\fInumber\fP\fB\fC\fR .PP This directive limits the size of the request. After \fInumber\fP Bytes the connection is just closed. This prevents denial of service attacks through long requests. Every request is read into memory, so it must fit into it. Bear in mind, that if you use file upload fields a request might be larger than just a few bytes. .PP The value defaults to 0, which means, that there is no limit at all. .PP \fIExample\fP .PP .RS .nf 65536 .fi .RE .PP \fB\fC\fR\fIseconds\fP\fB\fC\fR .PP In daemon mode tntnet has a watchdog, which restarts tntnet when the maximum request time is exceeded. This happens, when a request is in a endless loop or otherwise hangs. Restarting tntnet looses all active sessions and the currently running requests. Therefore the timeout should be well long enough for the longes request. .PP The default value is 600 seconds, which is normally much longer than a http request should run. If the Timeout is set to 0, the watchdog is deactivated. .PP \fIExample\fP .PP .RS .nf 1200 .fi .RE .PP \fB\fC\fR\fInumber\fP\fB\fC\fR .PP Tntnet uses a dynamic pool of worker threads, which wait for incoming requests. MinThreads specifies, how many worker threads there have to be. This defaults to 5. .PP \fIExample\fP .PP .RS .nf 10 .fi .RE .PP \fB\fC\fR\fInumber\fP\fB\fC\fR .PP Http compression for replies smaller than this are not compressed at all. .PP The default value for this is 1024. .PP \fIExample\fP .PP .RS .nf 256 .fi .RE .PP \fB\fC\fR\fIfilename\fP\fB\fC\fR .PP Specify filename for mime db. The default is /etc/mime.types. .PP The format of the file is just like this /etc/mime.types. A mime type is followed after white space by a list of file extensions delimited by white space. .PP \fB\fC\fR\fInumber\fP\fB\fC\fR .PP Tntnet uses a dynamic pool of worker threads, which wait for incoming requests. \fB\fCmaxThreads\fR limits the number of threads. .PP The default is 100. .PP \fIExample\fP .PP .RS .nf 200 .fi .RE .PP \fB\fC\fR\fIfilename\fP\fB\fC\fR .PP When run in daemon mode, tntnet writes the process id of the monitor process to filename. When the monitor process is deactivated, the pid of the worker process is written. This ensures, that sending a sigkill to the the stored process id stops tntnet. .PP \fIExample\fP .PP .RS .nf /var/run/tntnet.pid .fi .RE .PP \fB\fC\fR\fInumber\fP\fB\fC\fR .PP Tntnet has a request queue, where new requests wait for service. This sets a maximum size of this queue, after wich new requests are not accepted. .PP The default value is 1000. .PP \fIExample\fP .PP .RS .nf 50 .fi .RE .PP \fB\fC\fR\fI0|1\fP\fB\fC\fR .PP The flag specifies whether the socket option SO\_REUSEADDR should be set. When the entry is omitted the flag is set. .PP \fB\fC\fR\fIname\fP\fB\fC\fR .PP Set the server response header. Tntnet sets the http header "Server:" to "Tntnet/version" by default. Whith this setting the header can be changed. .PP \fIExample\fP .PP .RS .nf Myserver version 1.2 .fi .RE .PP \fB\fC\fR\fIseconds\fP\fB\fC\fR .PP This sets the number of seconds without requests after which a sesssion is timed out. .PP The default value is 300 seconds. .PP \fIExample\fP .PP .RS .nf 600 .fi .RE .PP \fB\fC\fR\fImilliseconds\fP\fB\fC\fR .PP A worker thread waits for some milliseconds on incoming data. If there is no data, the job is put into a queue and another thread waits with poll(2) on incoming data on multiple sockets. The workerthreads are freed and they can respond to other requests quickly. The default value is 10 milliseconds, which is good for normal operation. A value of 0 results in non blocking read. If timeout is reached, this does not mean, that the socket is closed. A small timeout reduces contextswitches on slow connections. .PP \fIExample\fP .PP .RS .nf 0 .fi .RE .PP \fB\fC\fR\fImilliseconds\fP\fB\fC\fR .PP This defines the time, how long the workerthreads wait on write. If the timeout is exceeded, the socket is closed and the browser might not get all data. The default value is 10000 milliseconds. .PP \fIExample\fP .PP .RS .nf 20000 .fi .RE .PP \fB\fC\fR\fIms\fP\fB\fC\fR .PP When additional worker threads are needed tntnet waits the number of milliseconds before it starts additional threads to prevent high load when starting many threads at once. .PP The default value is 10ms. .PP \fIExample\fP .PP .RS .nf 1000 .fi .RE .PP \fB\fC\fR\fIusername\fP\fB\fC\fR .PP Changes the user under which tntnet answers requests. .PP The user is changes using the system call setuid(2), which is only allowed, when tntnet starts as root user. .PP \fIExample\fP .PP .RS .nf www\-data .fi .RE .PP \fB\fC { \fR\fIhostname\-regex\fP\fB\fC\fR\fImappings\fP\fB\fC }\fR .PP Defines mappings for virtual hosts. These mappings are valid only when the host header matches the \fIhostname\-regex\fP\&. See section \fIURL MAPPING\fP for details about how to define actual mappings .PP A \fIvhost\fP entry in the mappings should be empty since it is already specified for the whole group. .PP The mappings defined here are always matched before the mappings on the top level of the configuration. .PP \fIExample\fP .PP .RS .nf www\\.tntnet\\.org ^/$ static@tntent htdocs/index.html ^/(.*)$ static@tntent htdocs/$1 .fi .RE .SH URL MAPPING .PP Tntnet is a web server, which receives http requests from a http client and answers them. A http request has a url and other attributes, which are used to decide, how the answer should look like. This is done my mapping urls to components. .PP A component is something, which generates a http reply. They are normally generated with the ecpp compiler ecppc(1). The ecppc compiler generated C++ classes with component names. The classes are compiled and linked into a shared library. Both the component name and the shared library name is needed to identify a component. .PP The component identifier is a string built from the component name, the @ character and the shared library name. A example is \fB\fCmyclass@myapplication\fR\&. This tells tntnet: load shared library \fB\fCmyapplication\fR and call the component with the name \fB\fCmyclass\fR in that library, which creates the reply to the request. .PP To tell tntnet, which component to call, url mappings must be configured. .PP Configuration is done in the xml section \fB\fC\fR\&. Multiple mappings can be configured there. A mapping has a condition and a target. Tntnet looks in the list of mappings for the first mapping, where the condition is met and uses that to call the component. The component may return either a reply \- then the request is done or a special value \fB\fCDECLINED\fR, which tells tntnet to continue in the list and look for the next mapping, where the condition is met. .PP The component, which returns \fB\fCDECLINED\fR may already have generated part of the request. This is preserved for the next mapping. A common use case is to write a special component, which just checks the user name and password. If the user name and password is valid, \fB\fCDECLINED\fR is returned and tntnet calls the next mapping where the condition is met. .PP Also when the condition is met, but the component could not be loaded, tntnet continues with the next mapping. .PP When the end of the list is reached and no mapping returned a http reply code, tntnet replies with http not found (404) error. .PP So how these mapping are specified then? .PP The mapping contains 3 kind of nodes: .PP \fB\fCconditions\fR Multiple conditions can be specified. All conditions must be met when the mapping is to be used. .PP The most important is \fB\fC\fR, which contains a extended regular expression (see regex(7) for details). This expression is checked against the url of the request. If the url tag is omitted, the mapping is used for every url. .PP The condition \fB\fC\fR specifies the virtual host, for which this mapping is valid. When this is specified, the mapping is only valid for requests, where the virtual host matches the setting. The value is also a extended regular expression. Note, that a dot matches any character in regular expressions, which may be irritating here. If you want to specify a mapping for the all hosts of the domain \fB\fCtntnet.org\fR, you have to set \fB\fCtntnet\\.org$\fR\&. Also the dollar sign at the end is important, since it matches the end of the string. Otherwise the mapping would be also valid for a virtual host like \fB\fCtntnet.org.foo.com\fR, which may not be what you meant. .PP The condition \fB\fCmethod\fR specifies the http method for which the mapping should be considered. Again a extended regular expression is used. .PP The condition \fB\fCssl\fR is a boolean value. The value should be 0 or 1. The setting checks, whether this mapping should be used depending on ssl. If the value is 1, the condition is met, when the request is sent via ssl. If the value is 0, the condition is met, when the request is sent without ssl. .PP \fB\fCtarget\fR The mapping node contains a node \fB\fC\fR, which contains the component name, which is to be called when the conditions are met. .PP The target may contain back references to the regular expression in the \fB\fC\fR condition. Parts of the regular expression may be in brackets. In the target $1 is replaced with the first bracketed expression, $2 with the second and so on. .PP This target node is mandatory. .PP Optionally there may be another node \fB\fC\fR, which specifies the default http return code of components. The component may return with the special constant DEFAULT, which instructs tntnet to return the default http return code for this mapping. The ecpp compiler generates components, which return exactly that value and the default value is HTTP\_OK. The value of the node may be a numeric http return code or the word DECLINED, which instructs tntnet to continue with the next mapping. .PP \fB\fCparameters\fR When the condition is met, additional parameters may be passed to the called component. There are 2 nodes for this. .PP The node \fB\fC\fR can be requested in the component using \fB\fCrequest.getPathInfo()\fR\&. If the node is not set, the url is set as path info. .PP The node \fB\fC\fR contains additional parameters, which can be passed to the component. The node can have any number of nodes with values. The tags are used as a parameter name and the content as the value. The method \fB\fCrequest.getArg(\fR\fIname\fP\fB\fC)\fR returns the value of the specified \fIname\fP\&. When the node is not set, the method returns a empty string. Optionally a diffrent default value can be passed to the method as an additional parameter like \fB\fCrequest.getArg(\fR\fIname\fP\fB\fC,\fR\fIdefaultValue\fP\fB\fC)\fR\&. .PP For compatibility reasons with older tntnet \fB\fCrequest.getArg\fR accepts a numeric argument. Previously the arguments did not have names but were accessed by index. To emulate this, \fB\fCrequest.getArg\fR with a numeric argument translates the number into the name "\fB\fCarg\fR\fInumber\fP". So accessing \fB\fCrequest.getArg(\fR\fI2\fP\fB\fC)\fR returns the value of the argument with the name \fB\fCarg2\fR\&. Accessing a numeric argument equal or greater than the number of arguments (the first is number 0) used to be not allowed. Now a empty string is returned. .PP \fIExample\fP .PP .RS .nf index@myapp ^/$ index.html action@myapp POST localhost 1 $1@myapp ^/([^.]+)(\\.(.+))? $2 .fi .RE .SH LISTENERS .PP The section \fB\fC\fR specifies the ip addresses and ports, where tntnet waits for incoming requests. Multiple listeners may be defined, when tntnet should listen on multiple ip addresses or ports. .PP Each listener is defined in a node \fB\fC\fR\&. A listener must have a subnode \fB\fC\fR\&. The node \fB\fC\fR may contain a ip address or hostname or may be left empty or even omitted. If the node is empty, any interface is used. The \fB\fC\fR must contain the numeric port number. .PP The ip address may be a IPv4 or IPv6 address. .PP \fIExample\fP .PP .RS .nf 80 .fi .RE .SH SSL .PP Optionally a tag \fB\fC\fR may be added. This enables ssl on the interface and specifies the ssl host certificate for the interface. .PP The ssl key can be stored in a separate file. A tag \fB\fC\fR specifies, where to find it. It is really encouraged to do so and to remove group and other readability from the key file. .PP \fIExample\fP .PP .RS .nf 443 tntnet.pem tntnet.key .fi .RE .PP Client certificates are supported. The tags \fB\fC\fR and \fB\fC\fR can be added to specify the type of check. If \fB\fC\fR to \fB\fC1\fR, a client certificate is requested but tntnet accepts, if the client sends no certificate. The application can check the certificate using \fB\fCrequest.getSslCertificate()\fR\&. It returns a certificate object, which may be empty. .PP If \fB\fC\fR is \fB\fC2\fR, a client certificate is mandatory. A connection without a certificate is not accepted. .PP In any case the client certificate is verified against the CA specified by \fB\fC\fR\&. .PP \fIExample\fP .PP .RS .nf 443 tntnet.pem tntnet.key 2 myCa.pem .fi .RE .PP With this setting clients has to send a certificate signed by the CA \fB\fCmyCa.pem\fR\&. .SH LISTENER SETTINGS .PP We summarize the settings for the listeners here. .PP \fB\fC\fR\fIip\fP\fB\fC\fR .PP .RS .nf Optional setting for the ip address where tntnet should listen on. .fi .RE .PP \fB\fC\fR\fIport\fP\fB\fC\fR .PP .RS .nf Mandatory setting on which tntnet should listen on. .fi .RE .PP \fB\fC\fR\fIcertificate\fP\fB\fC\fR .PP .RS .nf A certificate file, which contains the ssl server certificate for ssl. .fi .RE .PP \fB\fC\fR\fIkey\fP\fB\fC\fR .PP .RS .nf The private key for the server certificate. If the key is not specified, tntnet expects the key in the certificate file. .fi .RE .PP \fB\fC\fR\fI0|1|2\fP\fB\fC\fR .PP .RS .nf Enables client certificates. When set to 0, no client certificate is needed. When set to 1 a client certificate is requested but optional. It is just passed to the application when available. When set to 2 a client certificate is requested and needed to connect. .fi .RE .PP \fB\fC\fR\fICA\-file\fP\fB\fC\fR .PP .RS .nf The certificate authority the client certificate is checked against. Only client certificates, which can be verified by this authority are accepted. This settins is mandatory when `sslVerifyLevel` is set to 1 or 2. .fi .RE .SH LOGGING .PP Logging is configured in the \fB\fC\fR section. .PP Every log output has a category and a level. Categories are hierarchical. .PP The configuration tells which category is output at which level and where the output is written to. .PP The main log levels are in decreasing severity \fIFATAL\fP, \fIERROR\fP, \fIWARN\fP, \fIINFO\fP, \fIDEBUG\fP, \fIFINER\fP, \fIFINEST\fP\&. The severity \fIFINE\fP is the same as \fIDEBUG\fP\&. A special level is \fITRACE\fP\&. .PP The settings are: .PP \fB\fC\fR\fIlevel\fP\fB\fC\fR .PP .RS .nf Sets the main level used, when nothing else is specified. The default is \_FATAL\_. .fi .RE .PP \fB\fC\fR\fIloggers\fP\fB\fC\fR .PP .RS .nf Specifies the log levels for a category. See separate section about *loggers* for details. .fi .RE .PP \fB\fC\fR\fIfilename\fP\fB\fC\fR .PP .RS .nf Log output is written to file. Default is *stderr*. .fi .RE .PP \fB\fC\fR\fIsize\fP\fB\fC\fR .PP .RS .nf Specifies maximum \_size\_ of file. The size is a number in bytes or it can be prepended by a unit of 'k', 'm' or 'g', which specified kilo, mega or gigabytes. The unit is not case sensitive. After reaching the size, a log message is written into the current file and renamed by appending a '.0' to it. A new file is then created. .fi .RE .PP \fB\fC\fR\fInumber\fP\fB\fC\fR .PP .RS .nf If the *maxfilesize* was reached and there is already a file with a *.0* extension it is renamed to .1. This happens up to the specified number. So if *maxfilesize* is e.g. 4 the log files are rolled up to .4, so that 5 files are kept. .fi .RE .PP \fB\fC\fR\fIportnumber\fP\fB\fC\fR .PP .RS .nf When a *portnumber* is specified and no *file* is specified (*file* has higher priority), log messages are sent to the specified udp port. .fi .RE .PP \fB\fC\fR\fIhost\fP\fB\fC\fR .PP .RS .nf When *logport* and *loghost are set, the messages are sent to the host. .fi .RE .PP \fB\fC\fR\fIboolean\fP\fB\fC\fR .PP .RS .nf When the host address is a network address, the *broadcast* flag must be set. Then the messages are sent as broadcast udp messages to the network. A boolean value is false when it is empty or starts with '0', 'f', 'F', 'n' or 'N'. .fi .RE .PP \fB\fC\fR\fIboolean\fP\fB\fC\fR .PP .RS .nf When no file or loghost is set output and this flag is set, the output is written to *stdout*. The default is *stderr*. A boolean value is false when it is empty or starts with '0', 'f', 'F', 'n' or 'N'. .fi .RE .SS loggers .PP In the section \fB\fC\fR a list of \fB\fC\fR is specified. A logger has this settings: .PP \fB\fC\fR\fIcategory\fP\fB\fC\fR .PP .RS .nf Specifies the category .fi .RE .PP \fB\fC\fR\fIlevel\fP\fB\fC\fR .PP .RS .nf Specifies the level for this category. The level can be one of the log levels \_FATAL\_, \_ERROR\_, \_WARN\_, \_INFO\_, \_DEBUG\_, \_FINE\_, \_FINER\_ or \_FINEST\_. The all messages with a level of this or higher are output. So e.g. setting \_DEBUG\_ outputs all messages from \_FATAL\_ to \_DEBUG\_. It is enough to specify the first character (except \_FINE\_, \_FINER\_ and \_FINEST\_). Setting \_TRACE\_ (or \_T\_) is like \_DEBUG\_ plus all \_TRACE\_ messages. \_TRACE\_ is special since it outputs a message when a the code is reached and a exit message when the scope of the code is exited. Typically the \_TRACE\_ messages are put at the start of functions so that the log shows when a function is called and when it is exited. Multiple log levels can be separated by '|'. In that case only those levels are output. E.g. \_WARN|DEBUG\_ prints just warning and debug messages. When just one level should be printed, it can be prepended by '|', so e.g. \_|ERROR\_ prints just error messages. Prepending a 'T' to the log level adds always traces. E.g. *TINFO* prints info messages and above and traces. \_TFINEST\_ prints just everything. .fi .RE .PP Note that all components has a automatic log category of \fIcomponent.\fIname\fP\fP set. .SS logger examples .PP .RS .nf tntnet DEBUG .fi .RE .PP Prints much debug information when tntnet runs. .PP .RS .nf tntnet.dispatcher DEBUG component TRACE .fi .RE .PP Prints debug messages about the processing of url mappings and traces about called (ecpp\-)components. .PP Other useful categories are \fItntnet.messageheader\fP, which outputs debug messages for each header sent from the client or \fItntnet.httpreply\fP, where we can see the reply headers. .SH AUTHOR .PP This manual page was written by Tommi Mäkitalo \[la]tommi@tntnet.org\[ra]\&. .SH SEE ALSO .PP tntnet (1) tntnet-3.0/doc/man/tntnet.xml.7.markdown000066400000000000000000000646651365471676700203030ustar00rootroot00000000000000tntnet.xml 7 "2006-07-23" Tntnet "Tntnet users guide" ===================================================== NAME ---- tntnet.xml - configuration file for tntnet(8) DESCRIPTION ----------- Tntnet is configured using a xml file. The name of the file is *tntnet.xml*. The root node of *tntnet.xml* should be `tntnet` while it is not checked. Most of the settings are just single values. They are described here in alphabetical order. SETTINGS -------- This section describes the variables, used by Tntnet (8). ``*filename*`` Writes a log entry for each request in a common format. This format is compatible with most log file analyze systems for http servers. The log file has the fields: `peer ip` - `username` [`time`] "`http method` `query string` HTTP/`major version`.`minor version`" `http return code` `content size` "`referer`" "`user agent`" The `username`, `referer` and `user agent` may be '-' when the value is not available. Also the `content-size` can be empty in some cases. *Example* /var/log/tntnet/access.log`*bytes*`` Specifies the number of bytes sent in a single system call. This does not limit anything in application level. It does not affect e.g. savepoints or exception handling. Component output is collected completely and then passed in chunks of `bufferSize` bytes to the operating system. The default value is 16384. `` [ ``*path1*`` ] `` `comppath` specifies, where tntnet should search for webapplications. Tntnet searches first in the current directory and then in each directory, you specify here, until a library is found. You can repeat the directive as many times as desired to add more entries. If it is not found, the next `mappings` entry is tried. *Example* /usr/local/lib/tntnet /usr/local/share/tntnet ``*directory*`` Does a chroot(2) system call on startup, which locks the process into the directory at system level. *Example* /var/tntnet ``*0|1*`` If this flag is set to 1, Tntnet forks at startup and terminates the parent process on successful initialization. ``*directory*`` Changes the current working directory of the process on startup. *Example* /var/tntnet ``*contentType*`` Sets the content type header of the reply. The content type may be changed in the application using `reply.setContentType("something")`. By default "text/html; charset=UTF-8" is set. *Example* text/html; charset=ISO-8858-1 ``*yes|no*`` Specifies, if Tntnet should use gzip compression at http level. By default Tntnet use compression. A http client like a web browser can send a header "Accept-Encoding", to tell Tntnet, that it would accept compressed data. Tntnet then can decide, if it use compression. When the body is complete, Tntnet tries to compress the body. If the data can be compressed by more than 10%, Tntnet sends this compressed data. With this flag, this feature can be turned off. Compression slows down processing but reduces the network load. Normally the size of html pages can be compressed by about 70%, while Tntnet slows down by up to 30%. *Example* no `` ``*value1*`` ``*value2*`` `` Sets environment variables. ``*filename*`` Redirects stderr to the specified file when tntnet runs as a daemon. If ErrorLog is not set stderr is redirected to /dev/null. *Example* /var/log/tntnet/error.log ``*unix-group-id*`` Changes the group under which tntnet runs. The user is changes using the system call setgid(2), which is only allowed, when tntnet starts as root user. *Example* tntnet-group ``*milliseconds*`` Sets the timeout for keep-alive requests. Tntnet tries to do keep-alive-requests wherever possible. This has the effect, that tntnet can receive multiple requests within a single tcp connection. The connection times out after KeepAliveTimeout milliseconds. The timeout defaults to 15000ms. *Example* 300000 ``*number*`` Sets the maximum number of request per tcp connection. This defaults to 100. *Example* 10 ``*listener definition*`` Specifies, on which local interfaces tntnet waits for connections. There can be more than one Listen directives, in which case tntnet waits on every address. See separate section *Listeners* ``*logger definition*`` Configures logging. See separate section *logging* ``*number*`` On startup Tntnet calls listen on the specified port. When the systemcall returns with an error, Tntnet tries again and fails after the specified number of attempts. The default number is 5. *Example* 10 ``*number*`` The system call listen(3p) needs a parameter backlog, which specifies, how many pending connections the operating system should queue before it starts to ignore new request. The value is configurable here. The default value is 16. *Example* 64 ``*urlmappings*`` This is the most important setting for tntnet. It specifies, which components schould be called on which urls. For details see the section *URL MAPPING*. ``*number*`` Mapping urls to components is done using regular expressions. Executing these expressions is quite expensive while the number of different urls is quite limited in typical web applications. Hence tntnet caches the results. The caching algorithm is very simple. Tntnet just collects the results in a map. When the maximum size of the list is reached, it is cleared. This makes management of the cache very cheap. This setting sets the maximum number of entries in the map. If you see frequently a warning message, that the cache is cleared, you may consider increasing the size. The default value is 8192. *Example* 32768 ``*number*`` This directive limits the size of the request. After *number* Bytes the connection is just closed. This prevents denial of service attacks through long requests. Every request is read into memory, so it must fit into it. Bear in mind, that if you use file upload fields a request might be larger than just a few bytes. The value defaults to 0, which means, that there is no limit at all. *Example* 65536 ``*seconds*`` In daemon mode tntnet has a watchdog, which restarts tntnet when the maximum request time is exceeded. This happens, when a request is in a endless loop or otherwise hangs. Restarting tntnet looses all active sessions and the currently running requests. Therefore the timeout should be well long enough for the longes request. The default value is 600 seconds, which is normally much longer than a http request should run. If the Timeout is set to 0, the watchdog is deactivated. *Example* 1200 ``*number*`` Tntnet uses a dynamic pool of worker threads, which wait for incoming requests. MinThreads specifies, how many worker threads there have to be. This defaults to 5. *Example* 10 ``*number*`` Http compression for replies smaller than this are not compressed at all. The default value for this is 1024. *Example* 256 ``*filename*`` Specify filename for mime db. The default is /etc/mime.types. The format of the file is just like this /etc/mime.types. A mime type is followed after white space by a list of file extensions delimited by white space. ``*number*`` Tntnet uses a dynamic pool of worker threads, which wait for incoming requests. `maxThreads` limits the number of threads. The default is 100. *Example* 200 ``*filename*`` When run in daemon mode, tntnet writes the process id of the monitor process to filename. When the monitor process is deactivated, the pid of the worker process is written. This ensures, that sending a sigkill to the the stored process id stops tntnet. *Example* /var/run/tntnet.pid ``*number*`` Tntnet has a request queue, where new requests wait for service. This sets a maximum size of this queue, after wich new requests are not accepted. The default value is 1000. *Example* 50 ``*0|1*`` The flag specifies whether the socket option SO\_REUSEADDR should be set. When the entry is omitted the flag is set. ``*name*`` Set the server response header. Tntnet sets the http header "Server:" to "Tntnet/version" by default. Whith this setting the header can be changed. *Example* Myserver version 1.2 ``*seconds*`` This sets the number of seconds without requests after which a sesssion is timed out. The default value is 300 seconds. *Example* 600 ``*milliseconds*`` A worker thread waits for some milliseconds on incoming data. If there is no data, the job is put into a queue and another thread waits with poll(2) on incoming data on multiple sockets. The workerthreads are freed and they can respond to other requests quickly. The default value is 10 milliseconds, which is good for normal operation. A value of 0 results in non blocking read. If timeout is reached, this does not mean, that the socket is closed. A small timeout reduces contextswitches on slow connections. *Example* 0 ``*milliseconds*`` This defines the time, how long the workerthreads wait on write. If the timeout is exceeded, the socket is closed and the browser might not get all data. The default value is 10000 milliseconds. *Example* 20000 ``*ms*`` When additional worker threads are needed tntnet waits the number of milliseconds before it starts additional threads to prevent high load when starting many threads at once. The default value is 10ms. *Example* 1000 ``*username*`` Changes the user under which tntnet answers requests. The user is changes using the system call setuid(2), which is only allowed, when tntnet starts as root user. *Example* www-data ` { `*hostname-regex*``*mappings*` }` Defines mappings for virtual hosts. These mappings are valid only when the host header matches the *hostname-regex*. See section *URL MAPPING* for details about how to define actual mappings A *vhost* entry in the mappings should be empty since it is already specified for the whole group. The mappings defined here are always matched before the mappings on the top level of the configuration. *Example* www\.tntnet\.org ^/$ static@tntent htdocs/index.html ^/(.*)$ static@tntent htdocs/$1 URL MAPPING ----------- Tntnet is a web server, which receives http requests from a http client and answers them. A http request has a url and other attributes, which are used to decide, how the answer should look like. This is done my mapping urls to components. A component is something, which generates a http reply. They are normally generated with the ecpp compiler ecppc(1). The ecppc compiler generated C++ classes with component names. The classes are compiled and linked into a shared library. Both the component name and the shared library name is needed to identify a component. The component identifier is a string built from the component name, the @ character and the shared library name. A example is `myclass@myapplication`. This tells tntnet: load shared library `myapplication` and call the component with the name `myclass` in that library, which creates the reply to the request. To tell tntnet, which component to call, url mappings must be configured. Configuration is done in the xml section ``. Multiple mappings can be configured there. A mapping has a condition and a target. Tntnet looks in the list of mappings for the first mapping, where the condition is met and uses that to call the component. The component may return either a reply - then the request is done or a special value `DECLINED`, which tells tntnet to continue in the list and look for the next mapping, where the condition is met. The component, which returns `DECLINED` may already have generated part of the request. This is preserved for the next mapping. A common use case is to write a special component, which just checks the user name and password. If the user name and password is valid, `DECLINED` is returned and tntnet calls the next mapping where the condition is met. Also when the condition is met, but the component could not be loaded, tntnet continues with the next mapping. When the end of the list is reached and no mapping returned a http reply code, tntnet replies with http not found (404) error. So how these mapping are specified then? The mapping contains 3 kind of nodes: `conditions` Multiple conditions can be specified. All conditions must be met when the mapping is to be used. The most important is ``, which contains a extended regular expression (see regex(7) for details). This expression is checked against the url of the request. If the url tag is omitted, the mapping is used for every url. The condition `` specifies the virtual host, for which this mapping is valid. When this is specified, the mapping is only valid for requests, where the virtual host matches the setting. The value is also a extended regular expression. Note, that a dot matches any character in regular expressions, which may be irritating here. If you want to specify a mapping for the all hosts of the domain `tntnet.org`, you have to set `tntnet\.org$`. Also the dollar sign at the end is important, since it matches the end of the string. Otherwise the mapping would be also valid for a virtual host like `tntnet.org.foo.com`, which may not be what you meant. The condition `method` specifies the http method for which the mapping should be considered. Again a extended regular expression is used. The condition `ssl` is a boolean value. The value should be 0 or 1. The setting checks, whether this mapping should be used depending on ssl. If the value is 1, the condition is met, when the request is sent via ssl. If the value is 0, the condition is met, when the request is sent without ssl. `target` The mapping node contains a node ``, which contains the component name, which is to be called when the conditions are met. The target may contain back references to the regular expression in the `` condition. Parts of the regular expression may be in brackets. In the target $1 is replaced with the first bracketed expression, $2 with the second and so on. This target node is mandatory. Optionally there may be another node ``, which specifies the default http return code of components. The component may return with the special constant DEFAULT, which instructs tntnet to return the default http return code for this mapping. The ecpp compiler generates components, which return exactly that value and the default value is HTTP\_OK. The value of the node may be a numeric http return code or the word DECLINED, which instructs tntnet to continue with the next mapping. `parameters` When the condition is met, additional parameters may be passed to the called component. There are 2 nodes for this. The node `` can be requested in the component using `request.getPathInfo()`. If the node is not set, the url is set as path info. The node `` contains additional parameters, which can be passed to the component. The node can have any number of nodes with values. The tags are used as a parameter name and the content as the value. The method `request.getArg(`*name*`)` returns the value of the specified *name*. When the node is not set, the method returns a empty string. Optionally a diffrent default value can be passed to the method as an additional parameter like `request.getArg(`*name*`, `*defaultValue*`)`. For compatibility reasons with older tntnet `request.getArg` accepts a numeric argument. Previously the arguments did not have names but were accessed by index. To emulate this, `request.getArg` with a numeric argument translates the number into the name "`arg`*number*". So accessing `request.getArg(`*2*`)` returns the value of the argument with the name `arg2`. Accessing a numeric argument equal or greater than the number of arguments (the first is number 0) used to be not allowed. Now a empty string is returned. *Example* index@myapp ^/$ index.html action@myapp POST localhost 1 $1@myapp ^/([^.]+)(\.(.+))? $2 LISTENERS --------- The section `` specifies the ip addresses and ports, where tntnet waits for incoming requests. Multiple listeners may be defined, when tntnet should listen on multiple ip addresses or ports. Each listener is defined in a node ``. A listener must have a subnode ``. The node `` may contain a ip address or hostname or may be left empty or even omitted. If the node is empty, any interface is used. The `` must contain the numeric port number. The ip address may be a IPv4 or IPv6 address. *Example* 80 SSL --- Optionally a tag `` may be added. This enables ssl on the interface and specifies the ssl host certificate for the interface. The ssl key can be stored in a separate file. A tag `` specifies, where to find it. It is really encouraged to do so and to remove group and other readability from the key file. *Example* 443 tntnet.pem tntnet.key Client certificates are supported. The tags `` and `` can be added to specify the type of check. If `` to `1`, a client certificate is requested but tntnet accepts, if the client sends no certificate. The application can check the certificate using `request.getSslCertificate()`. It returns a certificate object, which may be empty. If `` is `2`, a client certificate is mandatory. A connection without a certificate is not accepted. In any case the client certificate is verified against the CA specified by ``. *Example* 443 tntnet.pem tntnet.key 2 myCa.pem With this setting clients has to send a certificate signed by the CA `myCa.pem`. LISTENER SETTINGS ----------------- We summarize the settings for the listeners here. ``*ip*`` Optional setting for the ip address where tntnet should listen on. ``*port*`` Mandatory setting on which tntnet should listen on. ``*certificate*`` A certificate file, which contains the ssl server certificate for ssl. ``*key*`` The private key for the server certificate. If the key is not specified, tntnet expects the key in the certificate file. ``*0|1|2*`` Enables client certificates. When set to 0, no client certificate is needed. When set to 1 a client certificate is requested but optional. It is just passed to the application when available. When set to 2 a client certificate is requested and needed to connect. ``*CA-file*`` The certificate authority the client certificate is checked against. Only client certificates, which can be verified by this authority are accepted. This settins is mandatory when `sslVerifyLevel` is set to 1 or 2. LOGGING ------- Logging is configured in the `` section. Every log output has a category and a level. Categories are hierarchical. The configuration tells which category is output at which level and where the output is written to. The main log levels are in decreasing severity _FATAL_, _ERROR_, _WARN_, _INFO_, _DEBUG_, _FINER_, _FINEST_. The severity _FINE_ is the same as _DEBUG_. A special level is _TRACE_. The settings are: ``*level*`` Sets the main level used, when nothing else is specified. The default is _FATAL_. ``*loggers*`` Specifies the log levels for a category. See separate section about *loggers* for details. ``*filename*`` Log output is written to file. Default is *stderr*. ``*size*`` Specifies maximum _size_ of file. The size is a number in bytes or it can be prepended by a unit of 'k', 'm' or 'g', which specified kilo, mega or gigabytes. The unit is not case sensitive. After reaching the size, a log message is written into the current file and renamed by appending a '.0' to it. A new file is then created. ``*number*`` If the *maxfilesize* was reached and there is already a file with a *.0* extension it is renamed to .1. This happens up to the specified number. So if *maxfilesize* is e.g. 4 the log files are rolled up to .4, so that 5 files are kept. ``*portnumber*`` When a *portnumber* is specified and no *file* is specified (*file* has higher priority), log messages are sent to the specified udp port. ``*host*`` When *logport* and *loghost are set, the messages are sent to the host. ``*boolean*`` When the host address is a network address, the *broadcast* flag must be set. Then the messages are sent as broadcast udp messages to the network. A boolean value is false when it is empty or starts with '0', 'f', 'F', 'n' or 'N'. ``*boolean*`` When no file or loghost is set output and this flag is set, the output is written to *stdout*. The default is *stderr*. A boolean value is false when it is empty or starts with '0', 'f', 'F', 'n' or 'N'. ### loggers In the section `` a list of `` is specified. A logger has this settings: ``*category*`` Specifies the category ``*level*`` Specifies the level for this category. The level can be one of the log levels _FATAL_, _ERROR_, _WARN_, _INFO_, _DEBUG_, _FINE_, _FINER_ or _FINEST_. The all messages with a level of this or higher are output. So e.g. setting _DEBUG_ outputs all messages from _FATAL_ to _DEBUG_. It is enough to specify the first character (except _FINE_, _FINER_ and _FINEST_). Setting _TRACE_ (or _T_) is like _DEBUG_ plus all _TRACE_ messages. _TRACE_ is special since it outputs a message when a the code is reached and a exit message when the scope of the code is exited. Typically the _TRACE_ messages are put at the start of functions so that the log shows when a function is called and when it is exited. Multiple log levels can be separated by '|'. In that case only those levels are output. E.g. _WARN|DEBUG_ prints just warning and debug messages. When just one level should be printed, it can be prepended by '|', so e.g. _|ERROR_ prints just error messages. Prepending a 'T' to the log level adds always traces. E.g. *TINFO* prints info messages and above and traces. _TFINEST_ prints just everything. Note that all components has a automatic log category of _component.*name*_ set. ### logger examples tntnet DEBUG Prints much debug information when tntnet runs. tntnet.dispatcher DEBUG component TRACE Prints debug messages about the processing of url mappings and traces about called (ecpp-)components. Other useful categories are *tntnet.messageheader*, which outputs debug messages for each header sent from the client or *tntnet.httpreply*, where we can see the reply headers. AUTHOR ------ This manual page was written by Tommi Mäkitalo . SEE ALSO -------- tntnet (1) tntnet-3.0/doc/process.txt000066400000000000000000000033021365471676700157000ustar00rootroot00000000000000case: daemon with monitor ========================= main monitor worker | |-fork------ | \ | | |-read----->| | | | |--fork----- | | \ | | | | |-read----->| | | | | | listen | | | | |<----write-| | | | | read-ok | | | | | | accept | | | |<----write-| | | | | read-ok |-waitpid-->| | | exit(0) v case: daemon with monitor with listen-error =========================================== main monitor worker | |-fork------ | \ | | |-read----->| | | | |--fork----- | | \ | | | | |-read----->| | | | | | listen => error | | | | | exit(1) | | | read-fail | | | exit(1) | read-fail | exit(1) case: daemon without monitor ============================ main worker | |-fork------ | \ | | |-read----->| | | | listen | | |<----write-| | | | accept | | | v read-ok | exit(0) case: daemon without monitor with listen-error ============================================== main worker | |-fork------ | \ | | |-read----->| | | | listen => error | | | exit(1) | read-fail | exit(1) tntnet-3.0/doc/quick-start-guide.markdown000066400000000000000000000135371365471676700206020ustar00rootroot00000000000000Tntnet quick start guide ======================== Authors: Tommi Mäkitalo, Andreas Welchlin This quick start guide includes: * How to install tntnet * Build and run your first application * Explanation of this first application * Further reading Tntnet is developed and tested on GNU/Linux. It is known to run on Sun Solaris, IBM AIX and FreeBSD. Installation ------------ You can install through the package manager in your operating system, if those packages are outdated (< cxxtools, tntnet 2.3), follow this instruction: To install Tntnet you will first need to install cxxtools. You can find cxxtools on the tntnet [homepage] (http://www.tntnet.org/download.html) and install it with: $ tar xzf cxxtools-x.x.tar.gz $ cd cxxtools-2.x $ ./configure $ make $ sudo make install $ sudo ldconfig The same installation procedure is used for tntnet. Install it with: $ tar xzf tntnet-x.x.tar.gz $ cd tntnet-x.x $ ./configure $ make $ sudo make install $ sudo ldconfig Now you have a working Tntnet environment. How to create your first web application ---------------------------------------- To create a web application we need to create a project. The easiest way is to use the helper script `tntnet-project`. We execute on the command line: $ tntnet-project myfirstproject This creates a initial web project, which uses autotools as a build system. It is created in a directory named myfirstproject. The most interesting files, which are created are: * configure.ac - the configuration file for autoconf * Makefile.am - the rules to build the project with automake * main.cpp - the file with the `main` function * myfirstproject.ecpp - our fist web page * log.properties - configuration file for logging * resources/myfirstproject.css - a static file of our web application For quick information about autotools using, read this mini howto: http://www.niksula.hut.fi/~mkomu/docs/autohowto.html To build and execute your first application enter the following commands: $ cd myfirstproject $ make $ tntnet Now you can start your web browser and navigate to `http://localhost:8000/myfirstproject`. You can see the result of your first running tntnet application, which prints the name of the application. What have we done? ------------------ The source file myfirstproject.ecpp has been translated to C++. This C++ program was used to build a shared library which contains the whole web application. A tntnet web application is a simple web page with special tags like `<$ ...$>`. The ecpp compiler `ecppc` creates a C++ source file and a header file with the same base name. These contain a class which has also the same name as the file. You can look into the generated code if you want, and sometimes it is useful to read it for further understanding of tntnet applications. If the C++ compiler has problems with your application it is a good idea to first check the generated code. The tags `<$ ... $>` output a C++ expression. The result of the expression is printed into the resulting page when the page is requested (on runtime). For this purpose, a `std::ostream` is used, so that the type of the result can be any object, which has an output operator `operator<<(ostream&, T)` defined. The configuration file `tntnet.xml` contains the settings. The two most important ones are the definitions of the listeners and URL mappings. The listeners define, on which interface tntnet waits for requests. You define an IP address of the local interface and a port. The IP address may be empty or omitted. If omitted tntnet listens on all local interfaces. The mappings tell tntnet what to do with incoming requests. Without this entry tntnet answers every request with `http error 404 – not found`. A mapping maps the URL - which is sent from a web browser - to a tntnet component. A component is the piece of code, which is normally generated by the ecpp compiler (ecppc). That's what we did above with `myfirstproject.ecpp`. Components are identified by their (class) name and the shared library which contains this class. We named our class "myfirstproject" and our shared library "myfirstproject.so". The component identifier is then `myfirstproject@myfirstproject`. So the mapping tells tntnet to call this component, when the URL `/test.html` is requested. How to add static files to your web application ----------------------------------------------- Web applications typically contain static and dynamic content. Static files are images, css or javascript source files. In the example application we already have a css file. All static files are located in the resources directory. When you add new files, add the to the top level `Makefile.am` under the variable `staticSources` also so that they are compiled into the web application. All files specified this way are sent to the browser as is. No ecpp processing takes place. After adding the files you have to compile the application and rerun it. Also after each change of a static file the application must be recompiled. Note also that the browser may cache static files so that you may need to deactivate or clear the cache to get the changed pages. Adding dynamic files -------------------- Dynamic files are compiled into components and may contain all ecpp tags documented in the ecpp(7) man page. Put them into your project and add them to the `ecppSources` variable into the `Makefile.am`. Here also a recompile and rerun is needed after every change. Where to go from here --------------------- The tool `tntnet-project` creates a project template. You may specify a different template for more sophisticated applications. Try `tntnet-project -h` to get help and `tntnet-project -l` to list the available templates. The templates contain a REAME.md, which shortly describes the structure of the created projects. tntnet-3.0/doc/static-howto.markdown000066400000000000000000000163141365471676700176610ustar00rootroot00000000000000Static files with Tntnet ======================== Introduction ------------ Tntnet is a web application server for C++. That means, that it is easy to create dynamic web pages using C++ embedded into HTML. But this does not mean, that Tntnet can't send static pages. Static pages are almost always needed in web applications. Css, Images or Javascript libraries are seldom dynamically generated. There are several solutions to send static pages. Since there are different situations and hence different needs, it is not uncommon to use more than one solution in your application. We will discuss here the possible solutions and the strength and caveats of each of them. Using the binary mode of ecppc ------------------------------ The simplest solution is to use the binary mode of ecppc. This is enabled by passing -b to ecppc. The binary mode disables interpretation of ecpp tags, when the file is compiled. So if the content of the file happens to contain e.g. the character sequence `<$`, which normally introduces the start of a c++ expression, it is still sent as is. As with dynamic content, the mime type is looked up using the extension of the file. If ecppc happens to fail here and you know better, you may pass the correct mime type using the -m switch. The advantage here is, that you can handle static files just like dynamic ones. The static files are also compiled into the web application, so you do not have to bother, how tntnet finds the source files. There are 2 caveats though. If you frequently change the static files, you have to recompile your application. And the memory overhead may be quite significant. I've measured additional on one specific system 8k in binary size for each component. So if you have a quite small static file of e.g. 0.5k, you have additional 8.5k in your binary. Sending static files using a special component ---------------------------------------------- If you really want to read the data from a external source like the file system, you are always free to send the content from your own written component. You may pass a file name to the component using a query parameter or the path info, which can also be set in the url mapping. Let's create a simple solution: <%pre> #include #include <%cpp> std::ifstream in(("./" + request.getPathInfo()).c_str()); if (!in) return DECLINED; tnt::MimeDb mimeDb("/etc/mime.types"); reply.setContentType(mimeDb.getMimetype(request.getPathInfo())); reply.out() << in.rdbuf(); // send the content of the ifstream to the page We add a mapping to the tntnet.xml: . static@static This works fine. Notice, that the component sends a DECLINED, if the file is not found. This tells Tntnet to look for the next url mapping. If tntnet do not find any mappings any more, it sends HTTP_NOT_FOUND to the browser. That's what we want to see, if there is no file found. Instead of getting the path from the path info variable, you may also read it from a query parameter. But you have to be really careful. The path name should not break out of the directory you have intended to read the data from. Think about a path name like "../../../etc/passwd". You don't really want to publish that file to the web! Tntnet checks automatically the request path for these double dot attacks, so the solution above works fine. But it can't check it from query parameters. You have to do that on your own. Let's look at the advantages using this solution. It is totally under your control, what to send when. You are not limited to read data from a file but you can also read the data e.g. from a database. The disadvantage is, that it is quite difficult to do correctly. Using static@tntnet ------------------- Since it is so common to send files from the file system, tntnet has a standard component for that. It is called static@tntnet. You just need to add a url mapping for that. The component does almost that, what the code from the previous example does. Additionally it sends modification dates and sends http code 304 (not modified) if it makes sense. This is needed to enable caching of files in the browser. Also it uses some optimizations like the sendfile system call if available and suitable. For completeness here is a url mapping for this component: ^/(.*) static@tntnet /var/www/htdocs/$1 This makes the content of the directory /var/www/htdocs available to the world. But keep in mind, that you can't list directory contents with this component. There is also no standard component for this. As a side effect, static@tntnet looks for files with a .gz extension. If the client accepts gzip compression and the corresponding file with a .gz extension is found, that one is sent. If the file is not found in the file system, static@tntnet sends a DECLINED just like in the custom component above, so it is also possible to chain multiple search paths for files. Multibinary components ---------------------- Let's return to the first solution. We mentioned the significant overhead for each component. If you have many small files, the overhead gets larger and larger. The solution is a multibinary component. This is a component, which has multiple static pages. We get only once the 8k overhead. As a side effect compile time is significantly reduced. To create multibinary components, we pass -bb to ecppc (or -b -b) and a list of file names, which to include into the component. Normally you want to pass a component name with -n to ecppc. By default ecppc uses the name "image". Useful is also to disable stripping paths from the file names with -p. Normally ecppc takes only the base name of the files. What we need is a suitable mapping. We have to tell the new component, which file to send. This is done using the path info, which we can pass from the url mapping after the component name. Lets looks at an example. We have 2 files p/foo.html and p/bar.html and want to create a multibinary component named static. This is done using the command: ecppc -bb -n static -p p/foo.html p/bar.html Now we have a static.cpp in the current directory. Next we create the mapping. Our shared library is called myapp. We want to send the component foo.html using the path /myfiles/p/foo.html and bar.html using /myfiles/p/bar.html: ^/myfiles/(.*) static@myapp $1 And we are done. Conclusion ---------- You have to choose from the 4 presented solutions, which one fits best to your problem. Just compiling each file into a component is easy and done quickly. Most larger applications have a bunch of static files, which are best placed into a multibinary component. For less static data you may decide to put the files into the file system using static@tntnet or in the database using your own custom code. Chaining is a interesting technique. You may choose to put the static files on development time into the file system first, so you can quickly test them. If you are happy with the content, just compile the file into your application and remove the file from the file system. tntnet-3.0/doc/upload-howto.markdown000066400000000000000000000066741365471676700176660ustar00rootroot00000000000000Howto upload files with Tntnet ============================== This document describes, how to upload files with Tntnet. Sometimes there is a need for uploading files to the web application. This is done with a special html input element of type "file". The form element needs to specify an enctype of with the parameter "multipart/form-data". This enctype changes the way, form-data is sent to your webapplication. Luckily Tntnet handles all difficult stuff for you and fill your aruments specified in `<%args>` sections. But with upload files the situation is a little different. First the file-data might be quite large and in would be not the most efficient way to put the data into a `std::string` like other arguments. The second problem is, that the file might have a additional attribute: the filename. Therefore Tntnet has a special API to handle this uploaded data. The data comes in a special multipart structure, which is represented in Tntnet by the class `tnt::Multipart`. This has references to all query parameters including uploaded files. You get a const reference to this multipart object with the method `getMultipart()` of your request object. Within this multipart object you can find your file with the method `find(partName)`. The parameter partName is the same name, you gave your upload field in your html form. You get a `tnt::Multipart::const_iterator` to the part. If the file is not found, the iterator points to the end-iterator retrieved with `request.getMultipart().end()`. If found, the dereferenced iterator is a reference to a `tnt::Part-object`, which represents your uploaded file. You can ask for the mime type with `tnt::Part::getMimetype()` and for the filename with `tnt::Part::getFilename()`. The simplest way to fetch the data is to call `tnt::Part::getBody()`. You get the data as a `std::string`. But this is not the most efficient way, because Tntnet needs instantiate a `std::string` and copy the data. There is a iterator interface for this. `tnt::Part` defines a `const_iterator`. Iterators to the start of your body is fetched with the `getBodyBegin()` and part the end with `getBodyEnd()`. If you don't need a `std::string` this is more efficient. This all sounds very complicated, but I hope it gets a little clearer, when you see a example. The form looks like this:
And the code to process the uploaded file: <%cpp> const tnt::Multipart& mp = request.getMultipart(); tnt::Multipart::const_iterator it = mp.find("myfile"); if (it != mp.end()) { // we found a uploaded file - write it to some upload-area std::ofstream out("upload/" + it->getFilename()); out << it->getBody(); // this is less efficient, because a temporary std::string // is created and the data is copied into it // more efficient is the use of iterators: for (tnt::Part::const_iterator pi = it->getBodyBegin(); pi != it->getBodyEnd(); ++pi) out << *pi; // ... or using STL-algorithm and ostreambuf_iterator: std::copy(it->getBodyBegin(), it->getBodyEnd(), std::ostreambuf_iterator(out)); } The application is a little online hexdumper for the web. The user can upload a file and see the first 1024 bytes as a hexdump. You can find another example in the tntnet package in sdk/demos/upload. tntnet-3.0/etc/000077500000000000000000000000001365471676700134715ustar00rootroot00000000000000tntnet-3.0/etc/Makefile.am000066400000000000000000000007261365471676700155320ustar00rootroot00000000000000nobase_dist_noinst_DATA = \ tntnet/tntnet.xml.in nobase_sysconf_DATA = \ tntnet/tntnet.xml CLEANFILES = tntnet.xml tntnet/tntnet.xml: tntnet/tntnet.xml.in $(AM_V_GEN) \ $(MKDIR_P) tntnet && \ $(SED) -e 's,@libdir\@,@libdir@,g;' \ -e 's,@pkglibdir\@,@pkglibdir@,g;' \ -e 's,@sysconfdir\@,@sysconfdir@,g;' \ -e 's,@localstatedir\@,@localstatedir@,g;' \ -e 's,@datadir\@,@datadir@,g;' < $(srcdir)/tntnet/tntnet.xml.in > tntnet/tntnet.xml tntnet-3.0/etc/tntnet/000077500000000000000000000000001365471676700150055ustar00rootroot00000000000000tntnet-3.0/etc/tntnet/tntnet.xml.in000066400000000000000000000035041365471676700174520ustar00rootroot00000000000000 redirect@tntnet ^/demos/controls$ /demos/controls/ $1@controls ^/demos/controls/(.+)\..* index@controls ^/demos/controls/$ index index@controls ^/demos/controls/(.+) $1 $1@$1 ^/demos/(.+)\..* $1 $1@$1 ^/demos/(.+) tntnet@hello ^/demos/tntnet.jpg static@tntnet (.*)/$ /$1/index.html static@tntnet ^/(.*)$ /$1 80 1 tntnet tntnet @localstatedir@/run/tntnet.pid /var/www @libdir@/tntnet INFO tntnet INFO /var/log/tntnet/tntnet.log 1MB 2 tntnet-3.0/framework/000077500000000000000000000000001365471676700147135ustar00rootroot00000000000000tntnet-3.0/framework/common/000077500000000000000000000000001365471676700162035ustar00rootroot00000000000000tntnet-3.0/framework/common/Makefile.am000066400000000000000000000045231365471676700202430ustar00rootroot00000000000000lib_LTLIBRARIES = libtntnet.la libtntnet_la_SOURCES = \ chunkedostream.cpp \ cmd.cpp \ compident.cpp \ comploader.cpp \ component.cpp \ componentfactory.cpp \ contentdisposition.cpp \ contenttype.cpp \ cookie.cpp \ cstream.cpp \ deflatestream.cpp \ dispatcher.cpp \ ecpp.cpp \ encoding.cpp \ htmlescostream.cpp \ httperror.cpp \ httpheader.cpp \ httpmessage.cpp \ httpparser.cpp \ httprequest.cpp \ httpreply.cpp \ job.cpp \ listener.cpp \ mbcomponent.cpp \ messageattribute.cpp \ messageheader.cpp \ messageheaderparser.cpp \ mimedb.cpp \ multipart.cpp \ poller.cpp \ pollerimpl.cpp \ savepoint.cpp \ scope.cpp \ scopemanager.cpp \ stringlessignorecase.cpp \ tcpjob.cpp \ tntconfig.cpp \ tntnet.cpp \ tntnetimpl.cpp \ unzipfile.cpp \ urlescostream.cpp \ urlmapper.cpp \ util.cpp \ worker.cpp \ zdata.cpp \ crypt.h nobase_include_HEADERS = \ tnt/applicationunlocker.h \ tnt/chunkedostream.h \ tnt/cmd.h \ tnt/compident.h \ tnt/comploader.h \ tnt/component.h \ tnt/componentfactory.h \ tnt/configurator.h \ tnt/contentdisposition.h \ tnt/contenttype.h \ tnt/cookie.h \ tnt/data.h \ tnt/deflatestream.h \ tnt/ecpp.h \ tnt/encoding.h \ tnt/htmlescostream.h \ tnt/http.h \ tnt/httperror.h \ tnt/httpheader.h \ tnt/httpmessage.h \ tnt/httpparser.h \ tnt/httprequest.h \ tnt/httpreply.h \ tnt/mapping.h \ tnt/maptarget.h \ tnt/mbcomponent.h \ tnt/messageattribute.h \ tnt/messageheader.h \ tnt/messageheaderparser.h \ tnt/mimedb.h \ tnt/multipart.h \ tnt/object.h \ tnt/parser.h \ tnt/query_params.h \ tnt/savepoint.h \ tnt/scope.h \ tnt/scopemanager.h \ tnt/sessionscope.h \ tnt/sessionunlocker.h \ tnt/socketif.h \ tnt/stringlessignorecase.h \ tnt/threadcontext.h \ tnt/tntconfig.h \ tnt/tntnet.h \ tnt/unzipfile.h \ tnt/urlescostream.h \ tnt/urlmapper.h \ tnt/zdata.h noinst_HEADERS = \ tnt/cstream.h \ tnt/dispatcher.h \ tnt/job.h \ tnt/listener.h \ tnt/poller.h \ tnt/pollerimpl.h \ tnt/tcpjob.h \ tnt/util.h \ tnt/worker.h \ tntnetimpl.h \ ioapi.h \ unzip.h libtntnet_la_CXXFLAGS = -DPKGLIBDIR=\"@libdir@/@PACKAGE@\" libtntnet_la_LDFLAGS = -version-info @sonumber@ @SHARED_LIB_FLAG@ libtntnet_la_LIBADD = -lz -lcxxtools if HAVE_MINIZIP libtntnet_la_CXXFLAGS += $(MINIZIP_CFLAGS) libtntnet_la_LDFLAGS += $(MINIZIP_LIBS) else libtntnet_la_SOURCES += \ ioapi.c \ unzip.c endif tntnet-3.0/framework/common/chunkedostream.cpp000066400000000000000000000047121365471676700217270ustar00rootroot00000000000000/* * Copyright (C) 2014 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include namespace tnt { int ChunkedWriter::sync() { static const char hex[] = "0123456789ABCDEF"; unsigned size = pptr() - pbase(); if (size > 0) { unsigned b = 0; while ((static_cast(0xf << b)) < size) b += 4; while (b > 0) { _obuf->sputc(hex[(size >> b) & 0xf]); b -= 4; } _obuf->sputc(hex[size & 0xf]); _obuf->sputc('\r'); _obuf->sputc('\n'); _obuf->sputn(pbase(), size); _obuf->sputc('\r'); _obuf->sputc('\n'); setp(_buffer, _buffer + _bufsize); _bytesWritten += size; return _obuf->pubsync(); } return 0; } ChunkedWriter::int_type ChunkedWriter::overflow(int_type ch) { if (_buffer == 0) { _buffer = new char[_bufsize]; setp(_buffer, _buffer + _bufsize); } else { sync(); } if (ch != traits_type::eof()) sputc(ch); return ch; } ChunkedWriter::int_type ChunkedWriter::underflow() { return traits_type::eof(); } void ChunkedWriter::finish() { sync(); _obuf->sputn("0\r\n", 3); } } tntnet-3.0/framework/common/cmd.cpp000066400000000000000000000066271365471676700174650ustar00rootroot00000000000000/* * Copyright (C) 2010 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include log_define("tntnet.cmd") namespace tnt { namespace { // SocketIf methods class NullSocketIf : public SocketIf { bool _ssl; public: explicit NullSocketIf(bool ssl) : _ssl(ssl) { } std::string getPeerIp() const { return std::string(); } std::string getServerIp() const { return std::string(); } bool isSsl() const { return _ssl; } cxxtools::SslCertificate getSslCertificate() const { return cxxtools::SslCertificate(); } }; NullSocketIf socketIf(false); } Cmd::Cmd(std::ostream& out) : _request(_application, &socketIf), _reply(out, false) { _reply.setDirectModeNoFlush(); } void Cmd::call(const Compident& ci, const QueryParams& q) { _request.setQueryString(q.getUrl()); call(ci); } void Cmd::call(const Compident& ci) { log_debug("call " << ci); _request.doPostParse(); // set thread context for thread scope log_debug("set thread context"); _request.setThreadContext(&threadContext); if (!_sessionId.empty()) { std::string cookieName; if (ci.libname.empty()) cookieName = "tntnet"; else { cookieName = "tntnet."; cookieName.append(ci.libname); } Cookies c; c.setCookie(cookieName, _sessionId); std::ostringstream s; s << c; _request.setHeader(httpheader::cookie, s.str()); } // sets session and application scope log_debug("set session and application scope; session id=<" << _sessionId << '>'); _scopeManager.preCall(_request, ci.libname); _scopeManager.setSessionId(_request, _sessionId); // fetch and call the component log_debug("do call"); _comploader.fetchComp(ci)(_request, _reply, _request.getQueryParams()); // sets session cookie if needed _sessionId = _scopeManager.postCall(_request, _reply, _application.getAppName()); log_debug("session id = " << _sessionId); _request.clear(); } } tntnet-3.0/framework/common/compident.cpp000066400000000000000000000032121365471676700206670ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/compident.h" namespace tnt { Compident::Compident(const std::string& ident) { std::string::size_type pos = ident.find('@'); if (pos == std::string::npos) compname = ident; else { compname = ident.substr(0, pos); libname = ident.substr(pos + 1); } } } tntnet-3.0/framework/common/comploader.cpp000066400000000000000000000171251365471676700210420ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include namespace { cxxtools::ReadWriteMutex mutex; } namespace tnt { //////////////////////////////////////////////////////////////////////// // ComponentLibrary // log_define("tntnet.comploader") void* ComponentLibrary::dlopen(const std::string& name, bool local) { log_debug("dlopen <" << name << ">, " << local); int flags = local ? RTLD_NOW|RTLD_LOCAL: RTLD_NOW|RTLD_GLOBAL; std::string n = name; if (!n.empty() && n[0] == '!') { flags = RTLD_NOW|RTLD_GLOBAL; n.erase(0, 1); log_debug("dlopen => <" << n << '>'); } void* ret = ::dlopen((n + ".so").c_str(), flags); if (ret != 0) { log_info("library \"" << n << ".so\""); return ret; } ret = ::dlopen((n + ".a").c_str(), flags); if (ret != 0) { log_info("library \"" << n << ".a\""); return ret; } ret = ::dlopen((n + ".dll").c_str(), flags); if (ret != 0) { log_info("library \"" << n << ".dll\""); return ret; } ret = ::dlopen(n.c_str(), flags); if (ret == 0) log_warn("failed to load library \"" << n << '"'); else log_info("library \"" << n << "\""); return ret; } void ComponentLibrary::init(const std::string& name, bool local) { void* handle = dlopen(name, local); if (handle) _handlePtr = new HandleType(handle); } Component* ComponentLibrary::create(const std::string& component_name, Comploader& cl, const Urlmapper& rootmapper) { log_debug("create \"" << component_name << '"'); ComponentFactory* factory; // look for factory in my map factoryMapType::const_iterator i = _factoryMap.find(component_name); if (i == _factoryMap.end()) throw NotFoundException(component_name); factory = i->second; // call the creator Compident ci = Compident(_libname, component_name); log_debug("call creator for \"" << ci << '"'); return factory->create(ci, rootmapper, cl); } //////////////////////////////////////////////////////////////////////// // Comploader // Comploader::librarymap_type& Comploader::getLibrarymap() { static librarymap_type librarymap; return librarymap; } ComponentLibrary::factoryMapType* Comploader::currentFactoryMap = 0; Component& Comploader::fetchComp(const Compident& ci, const Urlmapper& rootmapper) { log_debug("fetchComp \"" << ci << '"'); cxxtools::ReadLock rlock(mutex); cxxtools::WriteLock wlock(mutex, false); // lookup Component componentmap_type::iterator it = componentmap.find(ci); if (it == componentmap.end()) { rlock.unlock(); wlock.lock(); it = componentmap.find(ci); if (it == componentmap.end()) { ComponentLibrary& lib = fetchLib(ci.libname); Component* comp = lib.create(ci.compname, *this, rootmapper); componentmap[ci] = comp; return *comp; } } return *(it->second); } Component* Comploader::createComp(const Compident& ci, const Urlmapper& rootmapper) { log_debug("createComp \"" << ci << '"'); ComponentLibrary& lib = fetchLib(ci.libname); Component* comp = lib.create(ci.compname, *this, rootmapper); return comp; } namespace { template class ValueResetter { T& _value; T _null; public: explicit ValueResetter(T& value, T null = T()) : _value(value), _null(null) { } ~ValueResetter() { _value = _null; } }; } ComponentLibrary& Comploader::fetchLib(const std::string& libname) { log_debug("fetchLib \"" << libname << '"'); std::string n = libname; bool local = false; if (!n.empty() && n[0] == '!') { local = true; n.erase(0, 1); } librarymap_type& librarymap = getLibrarymap(); librarymap_type::iterator it = librarymap.find(n); if (it == librarymap.end()) { ComponentLibrary::factoryMapType factoryMap; currentFactoryMap = &factoryMap; ValueResetter valueResetter(currentFactoryMap, 0); // load library log_info("load library \"" << n << '"'); ComponentLibrary lib; for (TntConfig::CompPathType::const_iterator p = TntConfig::it().compPath.begin(); !lib && p != TntConfig::it().compPath.end(); ++p) { log_debug("load library \"" << n << "\" from " << *p << " dir"); lib = ComponentLibrary(*p, n, local); } if (!lib) { log_debug("load library \"" << n << "\" from current dir"); lib = ComponentLibrary(".", n, local); } #ifdef PKGLIBDIR if (!lib) { log_debug("load library \"" << n << "\" from package lib dir <" << PKGLIBDIR << '>'); lib = ComponentLibrary(PKGLIBDIR, n, local); } #endif if (!lib) { log_debug("library \"" << n << "\" in current dir not found - search lib-path"); lib = ComponentLibrary(n, local); } if (!lib) throw LibraryNotFound(n); lib._factoryMap = factoryMap; log_debug("insert new library " << n); it = librarymap.insert(librarymap_type::value_type(n, lib)).first; } else log_debug("library " << n << " found"); return it->second; } void Comploader::registerFactory(const std::string& component_name, ComponentFactory* factory) { log_debug("Comploader::registerFactory(" << component_name << ", " << factory << ')'); if (currentFactoryMap) currentFactoryMap->insert(ComponentLibrary::factoryMapType::value_type(component_name, factory)); else { librarymap_type& librarymap = getLibrarymap(); log_debug("register component without library-name"); librarymap_type::iterator it = librarymap.find(std::string()); if (it == librarymap.end()) { // empty library not in map - create a new empty library-object it = librarymap.insert(librarymap_type::value_type(std::string(), ComponentLibrary())).first; } it->second.registerFactory(component_name, factory); } } } tntnet-3.0/framework/common/component.cpp000066400000000000000000000051351365471676700207150ustar00rootroot00000000000000/* * Copyright (C) 2003-2006 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/component.h" #include "tnt/http.h" #include "tnt/httpreply.h" #include "tnt/httprequest.h" #include namespace tnt { void Component::configure(const tnt::TntConfig&) { } unsigned Component::topCall(HttpRequest& request, HttpReply& reply, tnt::QueryParams& qparam) { return operator() (request, reply, qparam); } unsigned Component::operator() (HttpRequest&, HttpReply&, tnt::QueryParams&) { return DECLINED; } unsigned Component::endTag(HttpRequest&, HttpReply&, tnt::QueryParams&) { return DECLINED; } std::string Component::getAttribute(const std::string& /* name */, const std::string& def) const { return def; } unsigned Component::call(HttpRequest& request, HttpReply& reply) { tnt::QueryParams qparam; return call(request, reply, qparam); } std::string Component::scall(HttpRequest& request, tnt::QueryParams& qparam) { // set up new reply object std::ostringstream result; HttpReply reply(result); // don't output any http headers reply.setDirectModeNoFlush(); // call the component (*this)(request, reply, qparam); return result.str(); } std::string Component::scall(HttpRequest& request) { tnt::QueryParams qparam; return scall(request, qparam); } } tntnet-3.0/framework/common/componentfactory.cpp000066400000000000000000000041331365471676700223020ustar00rootroot00000000000000/* * Copyright (C) 2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/componentfactory.h" #include "tnt/comploader.h" #include "tnt/tntconfig.h" #include log_define("tntnet.componentfactory") namespace tnt { const std::string factorySuffix = "__factory"; ComponentFactory::ComponentFactory(const std::string& componentName) : _component(0) { log_debug("create componentfactory for " << componentName); Comploader::registerFactory(componentName, this); } ComponentFactory::~ComponentFactory() { delete _component; } Component* ComponentFactory::create(const tnt::Compident& ci, const tnt::Urlmapper& um, tnt::Comploader& cl) { if (_component == 0) { _component = doCreate(ci, um, cl); _component->configure(TntConfig::it()); } return _component; } } tntnet-3.0/framework/common/contentdisposition.cpp000066400000000000000000000037241365471676700226540ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include namespace tnt { Contentdisposition::return_type Contentdisposition::onType( const std::string& t, const std::string& subtype) { if (!subtype.empty()) return FAIL; _type = t; std::transform(_type.begin(), _type.end(), _type.begin(), ::tolower); return OK; } Contentdisposition::return_type Contentdisposition::onParameter(const std::string& attribute, const std::string& value) { if (attribute == "name") { _name = value; } else if (attribute == "filename") _filename = value; return OK; } } tntnet-3.0/framework/common/contenttype.cpp000066400000000000000000000057351365471676700212750ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include log_define("tntnet.contenttype") namespace tnt { Contenttype::Contenttype(const std::string& ct) { log_debug("Contenttype <= " << ct); std::istringstream in(ct); in >> *this; if (!in) { std::ostringstream msg; msg << "error 1 parsing content-type-header at " << in.tellg() << ": " << ct; throwRuntimeError(msg.str()); } if (in.get() != std::ios::traits_type::eof()) { std::ostringstream msg; msg << "error 2 parsing content-type-header at " << in.tellg() << ": " << ct; throwRuntimeError(msg.str()); } } Contenttype::return_type Contenttype::onType( const std::string& t, const std::string& s) { log_debug("Contenttype::onType " << t << ", " << s); if (s.empty()) return FAIL; _type = t; _subtype = s; std::transform(_type.begin(), _type.end(), _type.begin(), ::tolower); std::transform(_subtype.begin(), _subtype.end(), _subtype.begin(), ::tolower); return OK; } Contenttype::return_type Contenttype::onParameter( const std::string& attribute, const std::string& value) { log_debug("Contenttype::onParameter " << attribute << ", " << value); std::string att = attribute; std::transform(att.begin(), att.end(), att.begin(), ::tolower); _parameter.insert(parameter_type::value_type(att, value)); if (attribute == "boundary") _boundary = value; return OK; } } tntnet-3.0/framework/common/cookie.cpp000066400000000000000000000303001365471676700201540ustar00rootroot00000000000000/* * Copyright (C) 2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include log_define("tntnet.cookie") namespace tnt { namespace { bool ishexdigit(char ch) { return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); } char hexvalue(char ch) { if (ch >= '0' && ch <= '9') return ch - '0'; else if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10; else if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10; else return '\0'; } char hexvalue(char upper, char lower) { return (hexvalue(upper) << 4) + hexvalue(lower); } } const Cookie Cookies::_emptyCookie; const std::string Cookie::maxAge = "Max-Age"; const std::string Cookie::comment = "Comment"; const std::string Cookie::domain = "Domain"; const std::string Cookie::path = "Path"; const std::string Cookie::secure = "Secure"; const std::string Cookie::version = "Version"; const std::string Cookie::expires = "Expires"; unsigned Cookie::getMaxAge() const { std::string a = getAttr(maxAge); if (!a.empty()) { std::istringstream s(a); unsigned ret; s >> ret; if (s) return ret; } return 0; } Cookie& Cookie::setMaxAge(unsigned v) { std::ostringstream s; s << v; setAttr(maxAge, s.str()); return *this; } void Cookies::clearCookie(const std::string& name) { cookies_type::iterator it = _data.find(name); if (it != _data.end()) { it->second.setAttr(Cookie::maxAge, "0"); it->second.setAttr(Cookie::expires, HttpMessage::htdate(static_cast(0))); } else { Cookie c; c.setAttr(Cookie::maxAge, "0"); c.setAttr(Cookie::expires, HttpMessage::htdate(static_cast(0))); setCookie(name, c); } } void Cookies::clearCookie(const std::string& name, const Cookie& c) { Cookie cc(c); cc.setAttr(Cookie::maxAge, "0"); setCookie(name, cc); } class CookieParser { // Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme" Cookie::attrs_type common_attrs; Cookie::attrs_type* current_attrs; Cookie current_cookie; bool attr; std::string current_cookie_name; std::string name; std::string value; Cookies& mycookies; void store_cookie(); void process_nv(); public: CookieParser(Cookies& c) : current_attrs(&common_attrs), mycookies(c) { } void parse(const std::string& header); }; void Cookies::set(const std::string& header) { CookieParser parser(*this); parser.parse(header); } void CookieParser::store_cookie() { if (!mycookies.hasCookie(current_cookie_name)) mycookies.setCookie(current_cookie_name, current_cookie); current_cookie._value.clear(); } void CookieParser::process_nv() { if (attr) { if (name == Cookie::secure) { log_debug("attribute: secure"); current_cookie._secureFlag = true; } else { log_debug("attribute: " << name << '=' << value); current_attrs->insert( Cookie::attrs_type::value_type(name, value)); } } else { if (!current_cookie_name.empty()) store_cookie(); log_debug("Cookie: " << name << '=' << value); current_cookie_name = name; current_cookie._value = value; current_cookie._secureFlag = false; name.clear(); current_attrs = ¤t_cookie._attrs; current_cookie._attrs = common_attrs; } } namespace { void throwInvalidCookie(const std::string& cookie) { throw HttpError(HTTP_BAD_REQUEST, "invalid cookie: " + cookie); } } void CookieParser::parse(const std::string& header) { // Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme" enum state_type { state_0, state_name, state_eq, state_value0, state_value, state_valueh1, state_valueh2, state_valuee, state_qvalue, state_qvalueh1, state_qvalueh2, state_qvaluee }; state_type state = state_0; char h = '\0'; for (std::string::const_iterator it = header.begin(); it != header.end(); ++it) { char ch = *it; switch(state) { case state_0: if (ch == '$') { attr = true; name.clear(); state = state_name; } else if (!std::isspace(ch)) { attr = false; name = ch; state = state_name; } break; case state_name: if (std::isspace(ch)) state = (name == Cookie::secure ? state_valuee : state_eq); else if (ch == '=') { if (name == Cookie::secure) state = state_valuee; else { value.clear(); value.reserve(32); state = state_value0; } } else if (ch == ';' && name == Cookie::secure) state = state_valuee; else name += ch; break; case state_eq: if (ch == '=') { value.clear(); value.reserve(32); state = state_value0; } else if (!std::isspace(ch)) { log_warn("invalid cookie: " << header << " - '=' expected"); throwInvalidCookie(header); } break; case state_value0: if (ch == '"') state = state_qvalue; else if (ch == '%') state = state_valueh1; else if (ch == ';') { process_nv(); state = state_0; } else if (!std::isspace(ch)) { value += ch; state = state_value; } break; case state_value: if (ch == ';') { process_nv(); state = state_0; } else if (ch == '%') state = state_valueh1; else if (ch == '+') value += ' '; else value += ch; break; case state_valueh1: if (ishexdigit(ch)) { h = ch; state = state_valueh2; } else if (ch == ';') { value += '%'; process_nv(); state = state_0; } else if (ch == '+') { value += '%'; value += ' '; state = state_value; } else { value += '%'; value += ch; state = state_value; } break; case state_valueh2: if (ishexdigit(ch)) { value += hexvalue(h, ch); state = state_value; } else if (ch == ';') { value += '%'; value += h; process_nv(); state = state_0; } else if (ch == '+') { value += hexvalue(h); value += ' '; state = state_value; } else { value += hexvalue(h); value += ch; state = state_value; } break; case state_valuee: if (ch == ';') { process_nv(); state = state_0; } else if (ch == '+') value += ' '; else if (std::isspace(ch)) state = state_valuee; else { log_warn("invalid cookie: " << header << " - semicolon expected after value"); throwInvalidCookie(header); } break; case state_qvalue: if (ch == '"') state = state_qvaluee; else if (ch == '%') state = state_qvalueh1; else if (ch == '+') value += ' '; else value += ch; break; case state_qvalueh1: if (ishexdigit(ch)) { h = ch; state = state_qvalueh2; } else if (ch == '"') { value += '%'; state = state_qvaluee; } else if (ch == '+') { value += '%'; value += ' '; state = state_qvalue; } else { value += '%'; value += ch; state = state_qvalue; } break; case state_qvalueh2: if (ishexdigit(ch)) { value += hexvalue(h, ch); state = state_qvalue; } else if (ch == '"') { value += '%'; value += h; state = state_qvaluee; } else if (ch == '+') { value += hexvalue(h); value += ' '; state = state_qvalue; } else { value += hexvalue(h); value += ch; state = state_qvalue; } break; case state_qvaluee: if (ch == ';') { process_nv(); state = state_0; } else if (!std::isspace(ch)) { log_warn("invalid cookie: " << header << " - semicolon expected"); throwInvalidCookie(header); } break; } } if (state == state_qvaluee || state == state_value || state == state_value0) process_nv(); else if (state != state_0) { log_warn("invalid cookie: " << header << " - invalid state " << state); throwInvalidCookie(header); } if (!current_cookie._value.empty()) store_cookie(); } void Cookie::write(std::ostream& out, const std::string& name) const { // print name (Customer="WILE_E_COYOTE") out << name << '='; UrlEscOstream u(out); u << getValue(); // print secure-attribute if (_secureFlag) out << "; " << Cookie::secure; // print attributes for (Cookie::attrs_type::const_iterator a = _attrs.begin(); a != _attrs.end(); ++a) out << "; " << a->first << '=' << a->second; if (_attrs.find(Cookie::version) == _attrs.end()) out << ";Version=1"; } std::ostream& operator<< (std::ostream& out, const Cookies& c) { // Set-Cookie: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme" bool first = true; for (Cookies::cookies_type::const_iterator it = c._data.begin(); it != c._data.end(); ++it) { if (first) first = false; else out << ','; it->second.write(out, it->first); } return out; } } tntnet-3.0/framework/common/crypt.h000066400000000000000000000112271365471676700175200ustar00rootroot00000000000000/* crypt.h -- base code for crypt/uncrypt ZIPfile Version 1.01e, February 12th, 2005 Copyright (C) 1998-2005 Gilles Vollant This code is a modified version of crypting code in Infozip distribution The encryption/decryption parts of this source code (as opposed to the non-echoing password parts) were originally written in Europe. The whole source package can be freely distributed, including from the USA. (Prior to January 2000, re-export from the US was a violation of US law.) This encryption code is a direct transcription of the algorithm from Roger Schlafly, described by Phil Katz in the file appnote.txt. This file (appnote.txt) is distributed with the PKZIP program (even in the version without encryption capabilities). If you don't need crypting in your application, just define symbols NOCRYPT and NOUNCRYPT. This code support the "Traditional PKWARE Encryption". The new AES encryption added on Zip format by Winzip (see the page http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong Encryption is not supported. */ #define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) /*********************************************************************** * Return the next byte in the pseudo-random sequence */ static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) { unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an * unpredictable manner on 16-bit systems; not a problem * with any known compiler so far, though */ temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); } /*********************************************************************** * Update the encryption keys with the next byte of plain text */ static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) { (*(pkeys+0)) = CRC32((*(pkeys+0)), c); (*(pkeys+1)) += (*(pkeys+0)) & 0xff; (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; { register int keyshift = (int)((*(pkeys+1)) >> 24); (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); } return c; } /*********************************************************************** * Initialize the encryption keys and the random header according to * the given password. */ static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) { *(pkeys+0) = 305419896L; *(pkeys+1) = 591751049L; *(pkeys+2) = 878082192L; while (*passwd != '\0') { update_keys(pkeys,pcrc_32_tab,(int)*passwd); passwd++; } } #define zdecode(pkeys,pcrc_32_tab,c) \ (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) #define zencode(pkeys,pcrc_32_tab,c,t) \ (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) #ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED #define RAND_HEAD_LEN 12 /* "last resort" source for second part of crypt seed pattern */ # ifndef ZCR_SEED2 # define ZCR_SEED2 3141592654UL /* use PI as default pattern */ # endif static int crypthead(const char* passwd, /* password string */ unsigned char* buf, /* where to write header */ int bufSize, unsigned long* pkeys, const unsigned long* pcrc_32_tab, unsigned long crcForCrypting) { int n; /* index in random header */ int t; /* temporary */ int c; /* random byte */ unsigned char header[RAND_HEAD_LEN-2]; /* random header */ static unsigned calls = 0; /* ensure different random header each time */ if (bufSize> 7) & 0xff; header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); } /* Encrypt random header (last two bytes is high word of crc) */ init_keys(passwd, pkeys, pcrc_32_tab); for (n = 0; n < RAND_HEAD_LEN-2; n++) { buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); } buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); return n; } #endif tntnet-3.0/framework/common/cstream.cpp000066400000000000000000000064261365471676700203550ustar00rootroot00000000000000/* * Copyright (C) 2014 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include log_define("tntnet.cstream") namespace tnt { cstreambuf::~cstreambuf() { log_debug(static_cast(this) << " delete " << _chunks.size() << " chunks (dtor)"); for (size_type n = 0; n < _chunks.size(); ++n) delete[] _chunks[n]; } void cstreambuf::makeEmpty() { log_debug(static_cast(this) << " makeEmpty; " << _chunks.size() << " chunks"); if (_chunks.size() > 0) { if (_chunks.size() > 1) { for (size_type n = 1; n < _chunks.size(); ++n) { log_debug(static_cast(this) << " delete chunk " << n); delete[] _chunks[n]; } _chunks.resize(1); } setp(_chunks[0], _chunks[0] + _chunksize); } } std::streambuf::int_type cstreambuf::overflow(std::streambuf::int_type ch) { char* chunk = new char[_chunksize]; log_debug(static_cast(this) << " new chunk " << static_cast(chunk)); _chunks.push_back(chunk); setp(_chunks.back(), _chunks.back() + _chunksize); if (ch != traits_type::eof()) sputc(traits_type::to_char_type(ch)); return 0; } std::streambuf::int_type cstreambuf::underflow() { return traits_type::eof(); } int cstreambuf::sync() { return 0; } void cstreambuf::rollback(size_type n) { if (n == 0) { makeEmpty(); } else { size_type c = (n-1) / _chunksize; for (size_type cc = c + 1; cc < _chunks.size(); ++cc) { log_debug(static_cast(this) << " delete chunk " << cc); delete[] _chunks[cc]; } _chunks.resize(c + 1); setp(_chunks[c], _chunks[c] + _chunksize); pbump(n % _chunksize); } } std::string ocstream::str() const { std::string ret; ret.reserve(size()); for (unsigned n = 0; n < chunkcount(); ++n) ret.append(chunk(n), chunksize(n)); return ret; } void ocstream::output(std::ostream& out) const { for (unsigned n = 0; n < chunkcount(); ++n) out.write(chunk(n), chunksize(n)); } } tntnet-3.0/framework/common/deflatestream.cpp000066400000000000000000000136261365471676700215370ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/deflatestream.h" #include #include #include log_define("tntnet.deflatestream") namespace tnt { namespace { int checkError(int ret, z_stream& stream) { if (ret != Z_OK && ret != Z_STREAM_END) { log_error("DeflateError " << ret << ": \"" << (stream.msg ? stream.msg : "") << '"'); std::ostringstream msg; msg << "deflate-error " << ret; if (stream.msg) msg << ": " << stream.msg; throw DeflateError(ret, msg.str()); } return ret; } } DeflateStreamBuf::DeflateStreamBuf(std::streambuf* sink, int level, int windowBits, unsigned bufsize) : _obuffer(bufsize), _sink(sink) { memset(&_stream, 0, sizeof(z_stream)); _stream.zalloc = Z_NULL; _stream.zfree = Z_NULL; _stream.opaque = 0; _stream.total_out = 0; _stream.total_in = 0; _stream.next_in = Z_NULL; _stream.next_out = Z_NULL; _stream.avail_in = 0; _stream.avail_out = 0; int strategy = Z_DEFAULT_STRATEGY; log_debug("deflateInit2(" << static_cast(&_stream) << ')'); checkError(::deflateInit2(&_stream, level, Z_DEFLATED, windowBits, 8, strategy), _stream); setp(&_obuffer[0], &_obuffer[0] + _obuffer.size()); } DeflateStreamBuf::~DeflateStreamBuf() { log_debug("deflateEnd(" << static_cast(&_stream) << ')'); ::deflateEnd(&_stream); } DeflateStreamBuf::int_type DeflateStreamBuf::overflow(int_type c) { // initialize input-stream _stream.next_in = reinterpret_cast(&_obuffer[0]); _stream.avail_in = pptr() - &_obuffer[0]; // initialize zbuffer for deflated data char zbuffer[8192]; _stream.next_out = reinterpret_cast(zbuffer); _stream.avail_out = sizeof(zbuffer); // deflate log_debug("deflate(" << static_cast(&_stream) << ", Z_NO_FLUSH)"); checkError(::deflate(&_stream, Z_NO_FLUSH), _stream); // copy zbuffer to sink / consume deflated data std::streamsize count = sizeof(zbuffer) - _stream.avail_out; if (count > 0) { std::streamsize n = _sink->sputn(zbuffer, count); if (n < count) return traits_type::eof(); } // move remaining characters to start of obuffer if (_stream.avail_in > 0) memmove(&_obuffer[0], _stream.next_in, _stream.avail_in); // reset outbuffer setp(&_obuffer[0] + _stream.avail_in, &_obuffer[0] + _obuffer.size()); if (c != traits_type::eof()) sputc(traits_type::to_char_type(c)); return 0; } DeflateStreamBuf::int_type DeflateStreamBuf::underflow() { return traits_type::eof(); } int DeflateStreamBuf::sync() { // initialize input-stream for _stream.next_in = reinterpret_cast(&_obuffer[0]); _stream.avail_in = pptr() - pbase(); char zbuffer[8192]; while (_stream.avail_in > 0) { // initialize zbuffer _stream.next_out = (Bytef*)zbuffer; _stream.avail_out = sizeof(zbuffer); log_debug("deflate(" << static_cast(&_stream) << ", Z_SYNC_FLUSH)"); checkError(::deflate(&_stream, Z_SYNC_FLUSH), _stream); // copy zbuffer to sink std::streamsize count = sizeof(zbuffer) - _stream.avail_out; if (count > 0) { std::streamsize n = _sink->sputn(zbuffer, count); if (n < count) return -1; } }; // reset outbuffer setp(&_obuffer[0], &_obuffer[0] + _obuffer.size()); return 0; } int DeflateStreamBuf::end() { char zbuffer[8192]; // initialize input-stream for _stream.next_in = reinterpret_cast(&_obuffer[0]); _stream.avail_in = pptr() - pbase(); while (true) { // initialize zbuffer _stream.next_out = (Bytef*)zbuffer; _stream.avail_out = sizeof(zbuffer); log_debug("deflate(" << static_cast(&_stream) << ", Z_FINISH)"); int ret = checkError(::deflate(&_stream, Z_FINISH), _stream); // copy zbuffer to sink std::streamsize count = sizeof(zbuffer) - _stream.avail_out; if (count > 0) { std::streamsize n = _sink->sputn(zbuffer, count); if (n < count) return -1; } if (ret == Z_STREAM_END) break; }; // reset outbuffer setp(&_obuffer[0], &_obuffer[0] + _obuffer.size()); return 0; } void DeflateStreamBuf::reinitialize() { log_debug("deflateReset(" << static_cast(&_stream) << ')'); checkError(::deflateReset(&_stream), _stream); } void DeflateStream::end() { if (_streambuf.end() != 0) setstate(failbit); } } tntnet-3.0/framework/common/dispatcher.cpp000066400000000000000000000154331365471676700210430ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/dispatcher.h" #include #include #include #include #include #include #include #include log_define("tntnet.dispatcher") namespace tnt { namespace { std::ostream& operator<< (std::ostream& out, const Mapping& r) { out << r.getVHost() << ':' << r.getUrl(); if (r.getSsl() != SSL_ALL || !r.getMethod().empty()) out << ':' << r.getMethod(); if (r.getSsl() == SSL_NO) out << ":NOSSL"; else if (r.getSsl() == SSL_YES) out << ":SSL"; return out; } } Mapping::Mapping(const std::string& vhost, const std::string& url, const std::string& method, int ssl, const Maptarget& target) : _vhost(vhost), _url(url), _method(method), _ssl(ssl), _regexVhost(vhost), _regexUrl(url), _regexMethod(method), _target(target) { } Mapping& Mapping::pushArg(const std::string& value) { std::ostringstream k; k << "arg" << _target.getArgs().size(); return setArg(k.str(), value); } bool Mapping::match(const HttpRequest& request, cxxtools::RegexSMatch& smatch) const { return (_vhost.empty() || _regexVhost.match(request.getHost())) && (_url.empty() || _regexUrl.match(request.getUrl(), smatch)) && (_method.empty() || _regexMethod.match(request.getMethod())) && (_ssl == SSL_ALL || (_ssl == SSL_YES && request.isSsl()) || (_ssl == SSL_NO && !request.isSsl())); } Dispatcher::UrlMapCacheKey::UrlMapCacheKey(const HttpRequest& request, urlmap_type::size_type pos) : _vhost(request.getHost()), _url(request.getUrl()), _method(request.getMethod()), _ssl(request.isSsl()), _pos(pos) { } bool Dispatcher::UrlMapCacheKey::operator< (const UrlMapCacheKey& other) const { int c; c = _vhost.compare(other._vhost); if (c != 0) return c < 0; c = _url.compare(other._url); if (c != 0) return c < 0; c = _method.compare(other._method); if (c != 0) return c < 0; if (_ssl != other._ssl) return _ssl < other._ssl; return _pos < other._pos; } Mapping& Dispatcher::addUrlMapEntry(const std::string& vhost, const std::string& url, const std::string& method, int ssl, const Maptarget& ci) { cxxtools::WriteLock lock(_mutex); log_debug("map vhost <" << vhost << "> url <" << url << "> method <" << method << "> ssl <" << ssl << "> to <" << ci << '>'); _urlmap.push_back(Mapping(vhost, url, method, ssl, ci)); return _urlmap.back(); } namespace { class regmatch_formatter : public std::unary_function { public: cxxtools::RegexSMatch what; std::string operator() (const std::string& s) const { return what.format(s); } }; } Maptarget Dispatcher::mapCompNext(const HttpRequest& request, Dispatcher::urlmap_type::size_type& pos) const { std::string vhost = request.getHost(); std::string compUrl = request.getUrl(); if (pos < _urlmap.size()) { // check cache cxxtools::ReadLock lock(_urlMapCacheMutex, false); urlMapCacheType::key_type cacheKey(request, pos); log_debug("host=\"" << cacheKey.getHost() << "\" url=\"" << cacheKey.getUrl() << "\" method=\"" << cacheKey.getMethod() << "\" ssl=" << cacheKey.getSsl() << " pos=" << cacheKey.getPos()); if (TntConfig::it().maxUrlMapCache > 0) { lock.lock(); urlMapCacheType::const_iterator um = _urlMapCache.find(cacheKey); if (um != _urlMapCache.end()) { pos = um->second.pos; log_debug("match <" << _urlmap[pos] << "> => " << um->second.ci << " (cached)"); return um->second.ci; } log_debug("entry not found in cache"); } else log_debug("cache disabled"); // no cache hit regmatch_formatter formatter; for (; pos < _urlmap.size(); ++pos) { if (_urlmap[pos].match(request, formatter.what)) { const Maptarget& src = _urlmap[pos].getTarget(); Maptarget ci; ci.libname = formatter(src.libname); ci.compname = formatter(src.compname); ci.setHttpReturn(src.getHttpReturn()); if (src.hasPathInfo()) ci.setPathInfo(formatter(src.getPathInfo())); for (Maptarget::args_type::const_iterator it = src.getArgs().begin(); it != src.getArgs().end(); ++it) ci._args[it->first] = formatter(it->second); if (TntConfig::it().maxUrlMapCache > 0) { lock.unlock(); cxxtools::WriteLock wlock(_urlMapCacheMutex); // clear cache after maxUrlMapCache distinct requests if (_urlMapCache.size() > TntConfig::it().maxUrlMapCache) { log_warn("clear url-map-cache"); _urlMapCache.clear(); } _urlMapCache.insert(urlMapCacheType::value_type(cacheKey, UrlMapCacheValue(ci, pos))); } log_debug("match <" << _urlmap[pos] << "> => " << ci); return ci; } else { log_debug("no match <" << _urlmap[pos] << '>'); } } } throw NotFoundException(compUrl, vhost); } Maptarget Dispatcher::PosType::getNext() { if (_first) _first = false; else ++_pos; return _dis.mapCompNext(_request, _pos); } } tntnet-3.0/framework/common/ecpp.cpp000066400000000000000000000113471365471676700176440ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include log_define("tntnet.ecpp") namespace tnt { ////////////////////////////////////////////////////////////////////// // Subcompident // inline std::ostream& operator<< (std::ostream& out, const Subcompident& comp) { return out << comp.toString(); } Subcompident::Subcompident(const std::string& ident) : tnt::Compident(ident) { std::string::size_type pos = compname.find('.'); if (pos != std::string::npos) { subname = compname.substr(pos + 1); compname = compname.substr(0, pos); } } std::string Subcompident::toString() const { std::string ret = tnt::Compident::toString(); if (!subname.empty()) { ret += '.'; ret += subname; } return ret; } ////////////////////////////////////////////////////////////////////// // EcppComponent // EcppComponent::EcppComponent(const Compident& ci, const Urlmapper& um, Comploader& cl) : _myident(ci), _rootmapper(um), _loader(cl) { } EcppComponent::~EcppComponent() { } void EcppComponent::registerSubComp(const std::string& name, EcppSubComponent* comp) { log_debug(getCompident() << ": registerSubComp " << name); subcomps_type::const_iterator it = getSubcomps().find(name); if (it != getSubcomps().end()) log_error("duplicate subcomp " << name); else getSubcomps().insert(subcomps_type::value_type(name, comp)); } Component& EcppComponent::fetchComp(const std::string& url) const { log_debug("fetchComp(\"" << url << "\")"); Subcompident ci(url); if (ci.libname.empty()) ci.libname = _myident.libname; if (ci.compname.empty()) ci.compname = _myident.compname; Component* comp; // fetch component by name comp = &_loader.fetchComp(ci, _rootmapper); // if there is a subcomponent, fetch it if (!ci.subname.empty()) { try { EcppComponent& e = dynamic_cast(*comp); comp = &e.fetchSubComp(ci.subname); } catch (const NotFoundException&) { throw; } catch (const std::exception&) { throw NotFoundException(url); } } return *comp; } Component& EcppComponent::fetchComp(const Compident& ci) const { if (ci.libname.empty()) { Compident cii(ci); cii.libname = _myident.libname; return _loader.fetchComp(cii, _rootmapper); } else return _loader.fetchComp(ci, _rootmapper); } Component* EcppComponent::createComp(const Compident& ci) const { log_debug("createComp(" << ci << ")"); if (ci.libname.empty()) { Compident cii(ci); cii.libname = _myident.libname; return _loader.createComp(cii, _rootmapper); } else return _loader.createComp(ci, _rootmapper); } EcppSubComponent& EcppComponent::fetchSubComp(const std::string& sub) const { log_debug(getCompident() << ": fetchSubComp(\"" << sub << "\")"); subcomps_type::const_iterator it = getSubcomps().find(sub); if (it == getSubcomps().end()) throw NotFoundException(Subcompident(getCompident(), sub).toString()); return *it->second; } /////////////////////////////////////////////////////////////////////// // ecppSubComponent // void EcppSubComponent::drop() { } } tntnet-3.0/framework/common/encoding.cpp000066400000000000000000000206351365471676700205030ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/encoding.h" #include "tnt/util.h" #include #include log_define("tntnet.encoding") namespace tnt { namespace { enum State { state_0, state_encoding, state_encoding_sp, state_quality, state_qualityq, state_qualityeq, state_qualitypoint, state_qualitytenths, state_qualityhundredths, state_qualitythousandths, state_quality_sp }; void throwInvalidHeader(const char* header, const char* p, State state) { log_warn("invalid encoding string <" << header << "> at position " << (p - header) << " in state " << static_cast(state) << " ok <" << std::string(header, p - header) << '>'); throwRuntimeError(std::string("invalid accept-encoding string \"") + header + '"'); } } void Encoding::parse(const char* header) { _encodingMap.clear(); if (header == 0) return; log_debug("encoding header <" << header << '>'); State state = state_0; std::string encoding; unsigned quality = 0; const char* p; for (p = header; *p; ++p) { char ch = *p; switch (state) { case state_0: if (!std::isspace(ch)) { encoding.clear(); encoding.reserve(8); encoding += ch; state = state_encoding; } break; case state_encoding: if (ch == ';') state = state_qualityq; else if (ch == ',') { log_debug("encoding <" << encoding << "> quality 1000"); _encodingMap.insert(encodingMapType::value_type(encoding, 1000)); state = state_0; } else if (std::isspace(ch)) state = state_encoding_sp; else encoding += ch; break; case state_encoding_sp: if (ch == ';') state = state_qualityq; else if (ch == ',') { log_debug("encoding <" << encoding << "> quality " << quality); _encodingMap.insert(encodingMapType::value_type(encoding, 1000)); state = state_0; } else if (std::isspace(ch)) ; else throwInvalidHeader(header, p, state); break; case state_qualityq: if (ch == 'q') state = state_qualityeq; else if (!std::isspace(ch)) throwInvalidHeader(header, p, state); break; case state_qualityeq: if (ch == '=') state = state_quality; else if (!std::isspace(ch)) throwInvalidHeader(header, p, state); break; case state_quality: if (ch == '0') { quality = 0; state = state_qualitypoint; } else if (ch == '1') { quality = 1000; state = state_qualitypoint; } else if (!std::isspace(ch)) throwInvalidHeader(header, p, state); break; case state_qualitypoint: if (ch == '.') state = state_qualitytenths; else if (ch == ',') { log_debug("encoding <" << encoding << "> quality " << quality); _encodingMap.insert(encodingMapType::value_type(encoding, quality)); state = state_0; } else if (std::isspace(ch)) { log_debug("encoding <" << encoding << "> quality " << quality); _encodingMap.insert(encodingMapType::value_type(encoding, quality)); state = state_quality_sp; } else throwInvalidHeader(header, p, state); break; case state_quality_sp: if (ch == ',') state = state_0; else if (!std::isspace(ch)) throwInvalidHeader(header, p, state); break; case state_qualitytenths: if (std::isdigit(ch)) { quality += (ch - '0') * 100; state = state_qualityhundredths; } else if (std::isspace(ch)) { log_debug("encoding <" << encoding << "> quality " << quality); _encodingMap.insert(encodingMapType::value_type(encoding, quality)); state = state_quality_sp; } break; case state_qualityhundredths: if (std::isdigit(ch)) { quality += (ch - '0') * 10; state = state_qualitythousandths; } else if (ch == ',') { log_debug("encoding <" << encoding << "> quality " << quality); _encodingMap.insert(encodingMapType::value_type(encoding, quality)); state = state_0; } else if (std::isspace(ch)) { log_debug("encoding <" << encoding << "> quality " << quality); _encodingMap.insert(encodingMapType::value_type(encoding, quality)); state = state_quality_sp; } break; case state_qualitythousandths: if (std::isdigit(ch)) { quality += (ch - '0'); log_debug("encoding <" << encoding << "> quality " << quality); _encodingMap.insert(encodingMapType::value_type(encoding, quality)); state = state_quality_sp; } else if (ch == ',') { log_debug("encoding <" << encoding << "> quality " << quality); _encodingMap.insert(encodingMapType::value_type(encoding, quality)); state = state_0; } else if (std::isspace(ch)) { log_debug("encoding <" << encoding << "> quality " << quality); _encodingMap.insert(encodingMapType::value_type(encoding, quality)); state = state_quality_sp; } else throwInvalidHeader(header, p, state); break; } } switch (state) { case state_encoding: case state_encoding_sp: log_debug("encoding <" << encoding << "> quality 1000"); _encodingMap.insert(encodingMapType::value_type(encoding, 1000)); break; case state_quality: case state_qualitypoint: case state_qualitytenths: case state_qualityhundredths: case state_qualitythousandths: log_debug("encoding <" << encoding << "> quality " << quality); _encodingMap.insert(encodingMapType::value_type(encoding, quality)); break; case state_qualityq: case state_qualityeq: throwInvalidHeader(header, p, state); case state_0: case state_quality_sp: break; } } unsigned Encoding::accept(const std::string& encoding) const { // check, if encoding is specified encodingMapType::const_iterator it = _encodingMap.find(encoding); if (it != _encodingMap.end()) return it->second; // check, if a wildcard-rule is specified it = _encodingMap.find("*"); if (it != _encodingMap.end()) return it->second; // return 1000 (accept), if encoding is identity, 0 otherwise return encoding == "identity" ? 1001 : 0; } } tntnet-3.0/framework/common/htmlescostream.cpp000066400000000000000000000036711365471676700217500ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/htmlescostream.h" namespace tnt { std::streambuf::int_type HtmlEscStreamBuf::overflow(std::streambuf::int_type ch) { switch (ch) { case '<': return _sink->sputn("<", 4); case '>': return _sink->sputn(">", 4); case '&': return _sink->sputn("&", 5); case '"': return _sink->sputn(""", 6); case '\'': return _sink->sputn("'", 5); default: return _sink->sputc(ch); } } std::streambuf::int_type HtmlEscStreamBuf::underflow() { return traits_type::eof(); } int HtmlEscStreamBuf::sync() { return _sink->pubsync(); } } tntnet-3.0/framework/common/httperror.cpp000066400000000000000000000163311365471676700207440ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include namespace tnt { //////////////////////////////////////////////////////////////////////// // HttpError // namespace { std::string httpErrorFormat(unsigned errcode, const std::string& msg) { char d[3]; d[2] = '0' + errcode % 10; errcode /= 10; d[1] = '0' + errcode % 10; errcode /= 10; d[0] = '0' + errcode % 10; std::string ret(d, 3); ret += ' '; ret += msg; return ret; } struct HttpMsg { unsigned statusCode; const char* statusText; }; const static HttpMsg httpMsgs[] = { { 0, "UNKNOWN" }, { HTTP_CONTINUE, "Continue" }, { HTTP_SWITCHING_PROTOCOLS, "Switching Protocols" }, { HTTP_PROCESSING, "Processing" }, { HTTP_OK, "OK" }, { HTTP_CREATED, "Created" }, { HTTP_ACCEPTED, "Accepted" }, { HTTP_NON_AUTHORITATIVE, "Non-Authoritative Information" }, { HTTP_NO_CONTENT, "No Content" }, { HTTP_RESET_CONTENT, "Reset Content" }, { HTTP_PARTIAL_CONTENT, "Partial Content" }, { HTTP_MULTI_STATUS, "Multi Status" }, { HTTP_MULTIPLE_CHOICES, "Multiple Choices" }, { HTTP_MOVED_PERMANENTLY, "Moved Permanently" }, { HTTP_MOVED_TEMPORARILY, "Moved Temporarily" }, { HTTP_SEE_OTHER, "See Other" }, { HTTP_NOT_MODIFIED, "Not Modified" }, { HTTP_USE_PROXY, "Use Proxy" }, { HTTP_TEMPORARY_REDIRECT, "Temporary Redirect" }, { HTTP_BAD_REQUEST, "Bad Request" }, { HTTP_UNAUTHORIZED, "Unauthorized" }, { HTTP_PAYMENT_REQUIRED, "Payment Required" }, { HTTP_FORBIDDEN, "Forbidden" }, { HTTP_NOT_FOUND, "Not Found" }, { HTTP_METHOD_NOT_ALLOWED, "Method Not Allowed" }, { HTTP_NOT_ACCEPTABLE, "Not Acceptable" }, { HTTP_PROXY_AUTHENTICATION_REQUIRED, "Proxy Authentication Required" }, { HTTP_REQUEST_TIME_OUT, "Request Time-out" }, { HTTP_CONFLICT, "Conflict" }, { HTTP_GONE, "Gone" }, { HTTP_LENGTH_REQUIRED, "Length Required" }, { HTTP_PRECONDITION_FAILED, "Precondition Failed" }, { HTTP_REQUEST_ENTITY_TOO_LARGE, "Request Entity Too Large" }, { HTTP_REQUEST_URI_TOO_LARGE, "Request URI Too Large" }, { HTTP_UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type" }, { HTTP_RANGE_NOT_SATISFIABLE, "Range not satisfiable" }, { HTTP_EXPECTATION_FAILED, "Expectation Failed" }, { HTTP_UNPROCESSABLE_ENTITY, "Unprocessable Entity" }, { HTTP_LOCKED, "Locked" }, { HTTP_FAILED_DEPENDENCY, "Failed Dependency" }, { HTTP_UPGRADE_REQUIRED, "Upgrade Required" }, { HTTP_INTERNAL_SERVER_ERROR, "Internal Server Error" }, { HTTP_NOT_IMPLEMENTED, "Not Implemented" }, { HTTP_BAD_GATEWAY, "Bad Gateway" }, { HTTP_SERVICE_UNAVAILABLE, "Service Unavailable" }, { HTTP_GATEWAY_TIME_OUT, "Gateway Time Out" }, { HTTP_VERSION_NOT_SUPPORTED, "Version Not Supported" }, { HTTP_VARIANT_ALSO_VARIES, "Variant Also Varies" }, { HTTP_INSUFFICIENT_STORAGE, "Insufficient Storage" }, { HTTP_NOT_EXTENDED, "Not Extended" } }; const static HttpMsg* httpMsgsBegin = httpMsgs; const static HttpMsg* httpMsgsEnd = httpMsgs + sizeof(httpMsgs)/sizeof(HttpMsg); inline bool operator< (const HttpMsg& m1, const HttpMsg& m2) { return m1.statusCode < m2.statusCode; } } HttpReturn::HttpReturn(unsigned returncode) : _returncode(returncode), _msg(httpMessage(returncode)) { } HttpReturn::HttpReturn(unsigned returncode, const char* msg) : _returncode(returncode), _msg(msg) { } const char* HttpReturn::httpMessage(unsigned httpstatus) { HttpMsg msg; msg.statusCode = httpstatus; const HttpMsg* m = std::lower_bound(httpMsgsBegin, httpMsgsEnd, msg); return m == httpMsgsEnd || m->statusCode != httpstatus ? "-" : m->statusText; } HttpError::HttpError(unsigned errcode) : _msg(HttpReturn::httpMessage(errcode)) { std::ostringstream b; HtmlEscOstream sb(b); b << "

Error

"; sb << _msg; b << "

"; _body = b.str(); _msg = httpErrorFormat(errcode, _msg); } HttpError::HttpError(unsigned errcode, const std::string& m) : _msg(httpErrorFormat(errcode, m)) { std::ostringstream b; HtmlEscOstream sb(b); b << "

Error

"; sb << m; b << "

"; _body = b.str(); } HttpError::HttpError(unsigned errcode, const std::string& m, const std::string& b) : _msg(httpErrorFormat(errcode, m)), _body(b) { } std::string HttpError::getErrmsg() const { std::string::size_type p = _msg.find('\n', 4); return p == std::string::npos ? _msg.substr(4) : _msg.substr(4, p - 4); } namespace { std::string notFoundMsg(const std::string& url, const std::string& vhost) { std::string msg = "Not Found: "; if (!vhost.empty()) { msg += "vhost: "; msg += vhost; msg += ' '; } msg += url; return msg; } } NotFoundException::NotFoundException(const std::string& url, const std::string& vhost) : HttpError(HTTP_NOT_FOUND, notFoundMsg(url, vhost)), _url(url), _vhost(vhost) { } NotAuthorized::NotAuthorized(const std::string& realm) : HttpError(HTTP_UNAUTHORIZED, "Unauthorized", "

not authorized

") { setHeader(httpheader::wwwAuthenticate, "Basic realm=\"" + realm + '"'); } MovedTemporarily::MovedTemporarily(const std::string& url) : HttpError(HTTP_MOVED_TEMPORARILY, "Moved Temporarily", "moved to " + url + "") { setHeader(httpheader::location, url); } } tntnet-3.0/framework/common/httpheader.cpp000066400000000000000000000056471365471676700210530ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/httpheader.h" namespace tnt { namespace httpheader { const char* contentType = "Content-Type:"; const char* contentLength = "Content-Length:"; const char* connection = "Connection:"; const char* connectionClose = "close"; const char* connectionKeepAlive = "Keep-Alive"; const char* lastModified = "Last-Modified:"; const char* server = "Server:"; const char* location = "Location:"; const char* accept = "Accept:"; const char* acceptLanguage = "Accept-Language:"; const char* acceptEncoding = "Accept-Encoding:"; const char* acceptCharset = "Accept-Charset:"; const char* acceptRanges = "Accept-Ranges:"; const char* contentEncoding = "Content-Encoding:"; const char* date = "Date:"; const char* keepAlive = "Keep-Alive:"; const char* ifModifiedSince = "If-Modified-Since:"; const char* host = "Host:"; const char* cacheControl = "Cache-Control:"; const char* contentMD5 = "Content-MD5:"; const char* setCookie = "Set-Cookie:"; const char* cookie = "Cookie:"; const char* pragma = "Pragma:"; const char* expires = "Expires:"; const char* userAgent = "User-Agent:"; const char* wwwAuthenticate = "WWW-Authenticate:"; const char* authorization = "Authorization:"; const char* referer = "Referer:"; const char* range = "Range:"; const char* contentRange = "Content-Range:"; const char* contentLocation = "Content-Location:"; const char* contentDisposition = "Content-Disposition:"; const char* age = "Age:"; const char* transferEncoding = "Transfer-Encoding:"; } } tntnet-3.0/framework/common/httpmessage.cpp000066400000000000000000000131561365471676700212410ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include namespace tnt { //////////////////////////////////////////////////////////////////////// // HttpMessage // void HttpMessage::clear() { header.clear(); _majorVersion = 1; _minorVersion = 0; } const char* HttpMessage::getHeader(const char* key, const char* def) const { header_type::const_iterator i = header.find(key); return i == header.end() ? def : i->second; } std::string HttpMessage::dumpHeader() const { std::ostringstream h; dumpHeader(h); return h.str(); } void HttpMessage::dumpHeader(std::ostream& out) const { for (header_type::const_iterator it = header.begin(); it != header.end(); ++it) out << it->first << ' ' << it->second << '\n'; } std::string HttpMessage::htdate(time_t t) { struct ::tm tm; gmtime_r(&t, &tm); char date[30]; htdate(date, t); return date; } void HttpMessage::htdate(char* date, time_t t) { struct ::tm tm; gmtime_r(&t, &tm); htdate(date, &tm); } std::string HttpMessage::htdate(const struct ::tm* tm) { char date[30]; htdate(date, tm); return date; } void HttpMessage::htdate(char* date, const struct ::tm* tm) { static const char* wday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; static const char* monthn[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; sprintf(date, "%s, %02d %s %d %02d:%02d:%02d GMT", wday[tm->tm_wday], tm->tm_mday, monthn[tm->tm_mon], tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec); } std::string HttpMessage::htdateCurrent() { char current[30]; htdateCurrent(current); return current; } void HttpMessage::htdateCurrent(char* current) { static struct ::tm lastTm; static time_t lastDay = 0; static time_t lastTime = 0; static char lastHtdate[30]; static cxxtools::Mutex mutex; /* * we cache the last split tm-struct here, because it is pretty expensive * to calculate the date with gmtime_r. */ time_t t; time(&t); cxxtools::MutexLock lock(mutex); if (lastTime != t) { time_t day = t / (24*60*60); if (day != lastDay) { // Day differs, we calculate new date. gmtime_r(&t, &lastTm); lastDay = day; } lastTm.tm_sec = t % 60; t /= 60; lastTm.tm_min = t % 60; t /= 60; lastTm.tm_hour = t % 24; htdate(lastHtdate, &lastTm); lastTime = t; } // we do a copy of lastHtdate first to make sure we have the lock std::strcpy(current, lastHtdate); } namespace { class Pstr { private: const char* _start; const char* _end; public: typedef size_t size_type; Pstr(const char* s, const char* e) : _start(s), _end(e) { } void setStart(const char* s) { _start = s; } void setEnd(const char* e) { _end = e; } size_type size() const { return _end - _start; } bool empty() const { return _start == _end; } bool operator== (const Pstr& s) const { return size() == s.size() && std::equal(_start, _end, s._start); } bool operator== (const char* str) const { size_type i; for (i = 0; i < size() && str[i] != '\0'; ++i) if (_start[i] != str[i]) return false; return i == size() && str[i] == '\0'; } }; } bool HttpMessage::checkUrl(const std::string& url) { unsigned level = 0; const char* p = url.data(); const char* e = p + url.size(); Pstr str(p, p); for (; p != e; ++p) { if (*p == '/') { str.setEnd(p); if (!str.empty()) { if (str == ".") ; else if (str == "..") { if (level == 0) return false; --level; } else ++level; } str.setStart(p + 1); } } if (level == 0 && (str.setEnd(p), str == "..")) return false; return true; } } tntnet-3.0/framework/common/httpparser.cpp000066400000000000000000000265241365471676700211140ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #define SET_STATE(new_state) _state = &Parser::new_state namespace tnt { namespace { std::string chartoprint(char ch) { const static char hex[] = "0123456789abcdef"; if (std::isprint(ch)) return std::string(1, '\'') + ch + '\''; else return std::string("'\\x") + hex[(ch >> 4) & 0xf] + hex[ch & 0xf] + '\''; } inline bool istokenchar(char ch) { static const char s[] = "\"(),/:;<=>?@[\\]{}"; return std::isalpha(ch) || std::binary_search(s, s + sizeof(s) - 1, ch); } inline bool isHexDigit(char ch) { return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f'); } inline unsigned valueOfHexDigit(char ch) { return ch >= '0' && ch <= '9' ? ch - '0' : ch >= 'a' && ch <= 'z' ? ch - 'a' + 10 : ch >= 'A' && ch <= 'Z' ? ch - 'A' + 10 : 0; } } log_define("tntnet.httpmessage.parser") bool RequestSizeMonitor::post(bool ret) { if (++_requestSize > TntConfig::it().maxRequestSize && TntConfig::it().maxRequestSize > 0) { requestSizeExceeded(); return true; } return ret; } void RequestSizeMonitor::requestSizeExceeded() { } void HttpRequest::Parser::reset() { _message.clear(); SET_STATE(state_cmd0); _httpCode = HTTP_OK; _failedFlag = false; RequestSizeMonitor::reset(); _headerParser.reset(); } bool HttpRequest::Parser::state_cmd0(char ch) { if (istokenchar(ch)) { _message._method[0] = ch; _message._methodLen = 1; SET_STATE(state_cmd); } else if (ch != ' ' && ch != '\t') { log_warn("invalid character " << chartoprint(ch) << " in method"); _httpCode = HTTP_BAD_REQUEST; _failedFlag = true; } return _failedFlag; } bool HttpRequest::Parser::state_cmd(char ch) { if (istokenchar(ch)) { if (_message._methodLen >= sizeof(_message._method) - 1) { log_debug("invalid method field; method=" << std::string(_message._method, _message._methodLen) << ", len=" << _message._methodLen); throw HttpError(HTTP_BAD_REQUEST, "invalid method field"); } _message._method[_message._methodLen++] = ch; } else if (ch == ' ') { _message._method[_message._methodLen] = '\0'; log_debug("method=" << _message._method); SET_STATE(state_url0); } else { log_warn("invalid character " << chartoprint(ch) << " in method"); _httpCode = HTTP_BAD_REQUEST; _failedFlag = true; } return _failedFlag; } bool HttpRequest::Parser::state_url0(char ch) { if (ch == ' ' || ch == '\t') { } else if (ch == '/') { _message._url.clear(); _message._url.reserve(32); _message._url += ch; SET_STATE(state_url); } else if (std::isalpha(ch)) { SET_STATE(state_protocol); } else { log_warn("invalid character " << chartoprint(ch) << " in url"); _httpCode = HTTP_BAD_REQUEST; _failedFlag = true; } return _failedFlag; } bool HttpRequest::Parser::state_protocol(char ch) { if (ch == ':') SET_STATE(state_protocol_slash1); else if (!std::isalpha(ch)) { log_warn("invalid character " << chartoprint(ch) << " in url"); _httpCode = HTTP_BAD_REQUEST; _failedFlag = true; } return _failedFlag; } bool HttpRequest::Parser::state_protocol_slash1(char ch) { if (ch == '/') SET_STATE(state_protocol_slash2); else { log_warn("invalid character " << chartoprint(ch) << " in url"); _httpCode = HTTP_BAD_REQUEST; _failedFlag = true; } return _failedFlag; } bool HttpRequest::Parser::state_protocol_slash2(char ch) { if (ch == '/') SET_STATE(state_protocol_host); else { log_warn("invalid character " << chartoprint(ch) << " in url"); _httpCode = HTTP_BAD_REQUEST; _failedFlag = true; } return _failedFlag; } bool HttpRequest::Parser::state_protocol_host(char ch) { if (ch == '/') { _message._url.clear(); _message._url.reserve(32); _message._url += ch; SET_STATE(state_url); } else if (!std::isalpha(ch) && !std::isdigit(ch) && ch != '[' && ch != ']' && ch != '.' && ch != ':') { log_warn("invalid character " << chartoprint(ch) << " in url"); _httpCode = HTTP_BAD_REQUEST; _failedFlag = true; } return _failedFlag; } bool HttpRequest::Parser::state_url(char ch) { if (ch == '?') { log_debug("url=" << _message._url); SET_STATE(state_qparam); } else if (ch == '\r') { log_debug("url=" << _message._url); SET_STATE(state_end0); } else if (ch == '\n') { log_debug("url=" << _message._url); SET_STATE(state_header); } else if (ch == ' ' || ch == '\t') { log_debug("url=" << _message._url); SET_STATE(state_version); } else if (ch == '%') { SET_STATE(state_urlesc); _message._url += ch; } else if (ch > ' ') _message._url += ch; else { log_warn("invalid character " << chartoprint(ch) << " in url"); _httpCode = HTTP_BAD_REQUEST; _failedFlag = true; } return _failedFlag; } bool HttpRequest::Parser::state_urlesc(char ch) { if (isHexDigit(ch)) { if (_message._url.size() >= 2 && _message._url[_message._url.size() - 2] == '%') { unsigned v = (valueOfHexDigit(_message._url[_message._url.size() - 1]) << 4) | valueOfHexDigit(ch); if (v == 0) throw HttpError(HTTP_BAD_REQUEST, "invalid value in url"); _message._url[_message._url.size() - 2] = static_cast(v); _message._url.resize(_message._url.size() - 1); SET_STATE(state_url); } else { _message._url += ch; } return false; } else { SET_STATE(state_url); return state_url(ch); } } bool HttpRequest::Parser::state_qparam(char ch) { if (ch == ' ' || ch == '\t') { log_debug("queryString=" << _message._queryString); SET_STATE(state_version); } else _message._queryString += ch; return false; } bool HttpRequest::Parser::state_version(char ch) { if (ch == '/') { _message.setVersion(0, 0); skipWs(&Parser::state_version_major); } else if (ch == '\r') { log_warn("invalid character " << chartoprint(ch) << " in version"); _httpCode = HTTP_BAD_REQUEST; _failedFlag = true; } return _failedFlag; } bool HttpRequest::Parser::state_version_major(char ch) { if (ch == '.') SET_STATE(state_version_minor0); else if (std::isdigit(ch)) _message.setVersion(_message.getMajorVersion() * 10 + (ch - '0'), _message.getMinorVersion()); else if (ch == ' ' || ch == '\t') SET_STATE(state_version_major_sp); else { log_warn("invalid character " << chartoprint(ch) << " in version-major"); _httpCode = HTTP_BAD_REQUEST; _failedFlag = true; } return _failedFlag; } bool HttpRequest::Parser::state_version_major_sp(char ch) { if (ch == '.') SET_STATE(state_version_minor0); else { log_warn("invalid character " << chartoprint(ch) << " in version-major"); _httpCode = HTTP_BAD_REQUEST; _failedFlag = true; } return _failedFlag; } bool HttpRequest::Parser::state_version_minor0(char ch) { return ch == ' ' || ch == '\t' ? _failedFlag : state_version_minor(ch); } bool HttpRequest::Parser::state_version_minor(char ch) { if (ch == '\n') SET_STATE(state_header); else if (ch == ' ' || ch == '\t' || ch == '\r') SET_STATE(state_end0); else if (std::isdigit(ch)) _message.setVersion(_message.getMajorVersion(), _message.getMinorVersion() * 10 + (ch - '0')); else { log_warn("invalid character " << chartoprint(ch) << " in version-minor"); _httpCode = HTTP_BAD_REQUEST; _failedFlag = true; } return _failedFlag; } bool HttpRequest::Parser::state_end0(char ch) { if (ch == '\n') SET_STATE(state_header); else if (ch != ' ' && ch != '\t') { log_warn("invalid character " << chartoprint(ch) << " in end"); _httpCode = HTTP_BAD_REQUEST; _failedFlag = true; } return _failedFlag; } bool HttpRequest::Parser::state_header(char ch) { if (_headerParser.parse(ch)) { if (_headerParser.failed()) { _httpCode = HTTP_BAD_REQUEST; _failedFlag = true; return true; } const char* content_length_header = _message.getHeader(httpheader::contentLength); if (*content_length_header) { _bodySize = 0; for (const char* c = content_length_header; *c; ++c) { if (*c > '9' || *c < '0') throw HttpError(HTTP_BAD_REQUEST, "invalid Content-Length"); _bodySize = _bodySize * 10 + *c - '0'; } if (TntConfig::it().maxRequestSize > 0 && getCurrentRequestSize() + _bodySize > TntConfig::it().maxRequestSize) { requestSizeExceeded(); return true; } _message._contentSize = _bodySize; if (_bodySize == 0) return true; else { SET_STATE(state_body); _message._body.reserve(_bodySize); return false; } } return true; } return false; } bool HttpRequest::Parser::state_body(char ch) { _message._body += ch; return --_bodySize == 0; } void HttpRequest::Parser::requestSizeExceeded() { log_warn("max request size " << TntConfig::it().maxRequestSize << " exceeded"); _httpCode = HTTP_REQUEST_ENTITY_TOO_LARGE; _failedFlag = true; } } tntnet-3.0/framework/common/httpreply.cpp000066400000000000000000000411521365471676700207450ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace tnt { log_define("tntnet.httpreply") namespace { class Compressor { ocstream _zbody; DeflateStream _deflator; uLong _crc; unsigned _size; public: Compressor() : _deflator(_zbody), _crc(0), _size(0) { } void compress(const char* d, unsigned s) { _deflator.write(d, s); _size += s; _crc = crc32(_crc, reinterpret_cast(d), s); } void finalize() { _deflator.end(); } std::string::size_type uncompressedSize() { return _size; } std::string::size_type zsize() { return _zbody.size(); } std::string str() const { return _zbody.str(); } void output(std::ostream& out) { _zbody.output(out); } void clear() { _zbody.makeEmpty(); _deflator.reinitialize(); _crc = 0; _size = 0; } }; } //////////////////////////////////////////////////////////////////////// // HttpReply // ////////////////////////////////////////////////////////////////////// // HttpReply::Impl // struct HttpReply::Impl { std::ostream* socket; ocstream outstream; HtmlEscOstream safeOutstream; UrlEscOstream urlOutstream; ChunkedOStream chunkedOutstream; Compressor compressor; Encoding acceptEncoding; unsigned keepAliveCounter; bool sendStatusLine; bool headRequest; bool clearSession; Impl(std::ostream& s, bool sendStatusLine); struct Pool { std::vector pool; cxxtools::Mutex poolMutex; ~Pool() { for (unsigned n = 0; n < pool.size(); ++n) delete pool[n]; } Impl* getInstance(std::ostream& s, bool sendStatusLine); void releaseInstance(Impl* inst); void clear(); }; static Pool pool; private: Impl(const Impl&); Impl& operator=(const Impl&); }; HttpReply::Impl::Pool HttpReply::Impl::pool; HttpReply::Impl* HttpReply::Impl::Pool::getInstance(std::ostream& s, bool sendStatusLine) { cxxtools::MutexLock lock(poolMutex); if (pool.empty()) return new Impl(s, sendStatusLine); Impl* impl = pool.back(); pool.pop_back(); impl->socket = &s; impl->keepAliveCounter = 0; impl->sendStatusLine = sendStatusLine; impl->headRequest = false; impl->clearSession = false; impl->acceptEncoding.clear(); impl->safeOutstream.setSink(impl->outstream.rdbuf()); impl->chunkedOutstream.setSink(impl->outstream.rdbuf()); return impl; } void HttpReply::Impl::Pool::releaseInstance(Impl* inst) { cxxtools::MutexLock lock(poolMutex); if (pool.size() < 64) { inst->outstream.clear(); inst->outstream.makeEmpty(); inst->safeOutstream.clear(); inst->urlOutstream.clear(); inst->chunkedOutstream.clear(); inst->compressor.clear(); pool.push_back(inst); } else { delete inst; } } void HttpReply::Impl::Pool::clear() { cxxtools::MutexLock lock(poolMutex); for (unsigned n = 0; n < pool.size(); ++n) delete pool[n]; pool.clear(); } HttpReply::Impl::Impl(std::ostream& s, bool sendStatusLine_) : socket(&s), safeOutstream(outstream), urlOutstream(outstream), chunkedOutstream(s), keepAliveCounter(0), sendStatusLine(sendStatusLine_), headRequest(false), clearSession(false) { } HttpReply::HttpReply(std::ostream& s, bool sendStatusLine) : _impl(Impl::pool.getInstance(s, sendStatusLine)), _currentOutstream(&_impl->outstream), _safeOutstream(&_impl->safeOutstream), _urlOutstream(&_impl->urlOutstream) { } HttpReply::~HttpReply() { Impl::pool.releaseInstance(_impl); } void HttpReply::setHeadRequest(bool sw) { _impl->headRequest = sw; } void HttpReply::clearSession() { _impl->clearSession = true; } bool HttpReply::isClearSession() const { return _impl->clearSession; } void HttpReply::resetContent() { _impl->outstream.makeEmpty(); } void HttpReply::rollbackContent(unsigned size) { _impl->outstream.rollback(size); } bool HttpReply::isDirectMode() const { return _currentOutstream == _impl->socket; } std::string::size_type HttpReply::getContentSize() const { return _impl->outstream.size(); } unsigned HttpReply::chunkedBytesWritten() const { return _impl->chunkedOutstream.bytesWritten(); } std::ostream& HttpReply::getDirectStream() { return *_impl->socket; } void HttpReply::setKeepAliveCounter(unsigned c) { _impl->keepAliveCounter = c; } unsigned HttpReply::getKeepAliveCounter() const { return _impl->keepAliveCounter; } void HttpReply::setAcceptEncoding(const Encoding& enc) { _impl->acceptEncoding = enc; } bool HttpReply::tryCompress(std::string& body) { Compressor compressor; compressor.compress(body.data(), body.size()); compressor.finalize(); std::string::size_type oldSize = body.size(); // only send compressed data, if the data is compressed more than 1/8th if (oldSize - (oldSize >> 3) > compressor.zsize()) { body = compressor.str(); log_info("gzip body " << oldSize << " bytes to " << compressor.zsize() << " bytes"); return true; } return false; } void HttpReply::postRunCleanup() { Impl::pool.clear(); } void HttpReply::sendHttpStatus(std::ostream& hsocket, unsigned ret, const char* msg) const { if (_impl->sendStatusLine) { if (msg == 0) msg = HttpReturn::httpMessage(ret); log_debug("HTTP/" << getMajorVersion() << '.' << getMinorVersion() << ' ' << ret << ' ' << msg); hsocket << "HTTP/" << getMajorVersion() << '.' << getMinorVersion() << ' ' << ret << ' ' << msg << "\r\n"; } } void HttpReply::sendHttpHeaders(std::ostream& hsocket) const { if (!hasHeader(httpheader::date)) { char current[50]; htdateCurrent(current); log_debug(httpheader::date << ' ' << current); hsocket << httpheader::date << ' ' << current << "\r\n"; } if (!TntConfig::it().server.empty() && !hasHeader(httpheader::server)) { log_debug(httpheader::server << ' ' << TntConfig::it().server); hsocket << httpheader::server << ' ' << TntConfig::it().server << "\r\n"; } for (header_type::const_iterator it = header.begin(); it != header.end(); ++it) { log_debug(it->first << ' ' << it->second); hsocket << it->first << ' ' << it->second << "\r\n"; } if (hasCookies()) { log_debug(httpheader::setCookie << ' ' << httpcookies); for (Cookies::cookies_type::const_iterator it = httpcookies._data.begin(); it != httpcookies._data.end(); ++it) { hsocket << httpheader::setCookie << ' '; it->second.write(hsocket, it->first); hsocket << "\r\n"; } } } void HttpReply::send(unsigned ret, const char* msg, bool ready) const { std::ostream hsocket(_impl->socket->rdbuf()); // send header sendHttpStatus(hsocket, ret, msg); sendHttpHeaders(hsocket); bool compressed = false; if (ready) { if (_currentOutstream == &_impl->chunkedOutstream) { log_debug(httpheader::transferEncoding << " chunked"); hsocket << httpheader::transferEncoding << " chunked\r\n"; } else { ocstream& body = _impl->outstream; if (body.size() >= TntConfig::it().minCompressSize && !hasHeader(httpheader::contentEncoding) && _impl->acceptEncoding.accept("gzip") && !hasHeader(httpheader::contentLength)) { for (unsigned n = 0; n < body.chunkcount(); ++n) _impl->compressor.compress(body.chunk(n), body.chunksize(n)); _impl->compressor.finalize(); compressed = true; log_debug(httpheader::contentEncoding << " gzip"); log_debug(httpheader::contentLength << ' ' << _impl->compressor.zsize()); hsocket << httpheader::contentLength << ' ' << _impl->compressor.zsize() << "\r\n" << httpheader::contentEncoding << " gzip\r\n"; log_info("gzip body " << body.size() << " bytes to " << _impl->compressor.zsize() << " bytes"); } else { if (!hasHeader(httpheader::contentLength)) { log_debug(httpheader::contentLength << ' ' << body.size()); hsocket << httpheader::contentLength << ' ' << body.size() << "\r\n"; } } } if (!hasHeader(httpheader::contentType)) { log_debug(httpheader::contentType << ' ' << TntConfig::it().defaultContentType); hsocket << httpheader::contentType << ' ' << TntConfig::it().defaultContentType << "\r\n"; } if (!hasHeader(httpheader::connection)) { if (TntConfig::it().keepAliveTimeout > 0 && getKeepAliveCounter() > 0) { log_debug(httpheader::keepAlive << " timeout=" << TntConfig::it().keepAliveTimeout << ", max=" << getKeepAliveCounter()); log_debug(httpheader::connection << ' ' << httpheader::connectionKeepAlive); hsocket << httpheader::keepAlive << " timeout=" << TntConfig::it().keepAliveTimeout << ", max=" << getKeepAliveCounter() << "\r\n" << httpheader::connection << ' ' << httpheader::connectionKeepAlive << "\r\n"; } else { log_debug(httpheader::connection << ' ' << httpheader::connectionClose); hsocket << httpheader::connection << ' ' << httpheader::connectionClose << "\r\n"; } } } hsocket << "\r\n"; // send body if (_impl->headRequest) log_debug("HEAD-request - empty body"); else { ocstream& body = _impl->outstream; if (_currentOutstream == &_impl->chunkedOutstream) { body.output(*_currentOutstream); } else { if (compressed) { log_debug("send " << _impl->compressor.zsize() << " bytes body (compressed)"); _impl->compressor.output(hsocket); } else { log_debug("send " << body.size() << " bytes body"); body.output(hsocket); } } } } bool HttpReply::sendReply(unsigned ret, const char* msg) { log_debug("sendReply"); if (_currentOutstream == &_impl->chunkedOutstream) { log_debug("finish chunked encoding"); _impl->chunkedOutstream.finish(); *_impl->socket << "\r\n"; } else if (!isDirectMode()) { log_debug("send data"); send(ret, msg, true); } _impl->socket->flush(); return !_impl->socket->fail(); } void HttpReply::setMd5Sum() { cxxtools::Md5stream md5; const tnt::ocstream& c = _impl->outstream; for (unsigned n = 0; n < c.chunkcount(); ++n) md5.write(c.chunk(n), c.chunksize(n)); setHeader(httpheader::contentMD5, md5.getHexDigest()); } unsigned HttpReply::redirect(const std::string& newLocation, Redirect type) { setHeader(httpheader::location, newLocation); _impl->outstream.makeEmpty(); _impl->outstream << "moved to " << newLocation << ""; unsigned httpCode = static_cast(type); throw HttpReturn(httpCode); return httpCode; } unsigned HttpReply::notAuthorized(const std::string& realm) { setHeader(httpheader::wwwAuthenticate, "Basic realm=\"" + realm + '"'); _impl->outstream.makeEmpty(); _impl->outstream << "

not authorized

"; throw HttpReturn(HTTP_UNAUTHORIZED); return HTTP_UNAUTHORIZED; } void HttpReply::setContentLengthHeader(size_t size) { char buffer[32]; snprintf(buffer, sizeof(buffer), "%lu", static_cast(size)); header.setHeader(httpheader::contentLength, buffer, true); } void HttpReply::setKeepAliveHeader() { log_debug("setKeepAliveHeader()"); removeHeader(httpheader::connection); removeHeader(httpheader::keepAlive); if (TntConfig::it().keepAliveTimeout > 0 && getKeepAliveCounter() > 0) { char buffer[64]; snprintf(buffer, sizeof(buffer), "timeout=%lu, max=%u", static_cast(TntConfig::it().keepAliveTimeout.totalSeconds()), static_cast(getKeepAliveCounter())); header.setHeader(httpheader::keepAlive, buffer, true); header.setHeader(httpheader::connection, httpheader::connectionKeepAlive, true); } else header.setHeader(httpheader::connection, httpheader::connectionClose, true); } void HttpReply::setMaxAgeHeader(unsigned seconds) { if (seconds > 0) { char buffer[64]; snprintf(buffer, sizeof(buffer), "max-age=%u", seconds); header.setHeader(httpheader::cacheControl, buffer, true); header.setHeader(httpheader::age, "0", true); } else { header.setHeader(httpheader::cacheControl, "no-cache", true); header.setHeader(httpheader::pragma, "no-cache", true); header.setHeader(httpheader::expires, "-1", true); } } void HttpReply::setDirectMode(unsigned ret, const char* msg) { if (!isDirectMode()) { log_debug("enable direct mode"); send(ret, msg, false); setDirectModeNoFlush(); } } void HttpReply::setDirectModeNoFlush() { _currentOutstream = _impl->socket; _impl->safeOutstream.setSink(*_impl->socket); _impl->urlOutstream.setSink(*_impl->socket); } void HttpReply::setChunkedEncoding(unsigned ret, const char* msg) { log_debug("set chunked encoding"); _currentOutstream = &_impl->chunkedOutstream; _impl->chunkedOutstream.setSink(*_impl->socket); _impl->safeOutstream.setSink(_impl->chunkedOutstream.rdbuf()); _impl->urlOutstream.setSink(_impl->chunkedOutstream.rdbuf()); send(ret, msg, true); } bool HttpReply::isChunkedEncoding() const { return _currentOutstream == &_impl->chunkedOutstream; } void HttpReply::setCookie(const std::string& name, const Cookie& value) { log_debug("setCookie(\"" << name << "\",\"" << value.getValue() << "\")"); tnt::Cookie cookie(value); if (!cookie.hasPath()) cookie.setPath("/"); httpcookies.setCookie(name, cookie); } void HttpReply::clearCookie(const std::string& name) { log_debug("clearCookie(\"" << name << "\")"); tnt::Cookie cookie; cookie.setPath("/"); httpcookies.clearCookie(name, cookie); } bool HttpReply::keepAlive() const { if (isDirectMode()) { header_type::const_iterator it = header.find(httpheader::connection); return it != header.end() && tnt::StringCompareIgnoreCase( it->second, httpheader::connectionKeepAlive) == 0; } else { return TntConfig::it().keepAliveTimeout > 0 && getKeepAliveCounter() > 0; } } } tntnet-3.0/framework/common/httprequest.cpp000066400000000000000000000321221365471676700212770ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include #include namespace tnt { log_define("tntnet.httprequest") //////////////////////////////////////////////////////////////////////// // HttpRequest // std::atomic HttpRequest::_nextSerial(0); HttpRequest::HttpRequest(Tntnet& application, const SocketIf* socketIf) : _socketIf(socketIf), _encodingRead(false), _requestScope(0), _applicationScope(0), _sessionScope(0), _secureSessionScope(0), _threadContext(0), _applicationScopeLocked(false), _sessionScopeLocked(false), _secureSessionScopeLocked(false), _application(application) { } HttpRequest::HttpRequest(Tntnet& application, const std::string& url, const SocketIf* socketIf) : _socketIf(socketIf), _requestScope(0), _applicationScope(0), _sessionScope(0), _secureSessionScope(0), _threadContext(0), _applicationScopeLocked(false), _sessionScopeLocked(false), _secureSessionScopeLocked(false), _application(application) { std::istringstream s("GET " + url + " HTTP/1.1\r\n\r\n"); parse(s); } HttpRequest::HttpRequest(const HttpRequest& r) : _methodLen(0), _pathinfo(r._pathinfo), _args(r._args), _getparam(r._getparam), _postparam(r._postparam), _qparam(r._qparam), _socketIf(r._socketIf), _ct(r._ct), _mp(r._mp), _serial(r._serial), _requestScope(r._requestScope), _applicationScope(r._applicationScope), _sessionScope(r._sessionScope), _secureSessionScope(r._secureSessionScope), _threadContext(r._threadContext), _applicationScopeLocked(false), _sessionScopeLocked(false), _secureSessionScopeLocked(false), _application(r._application) { if (_requestScope) _requestScope->addRef(); if (_applicationScope) _applicationScope->addRef(); if (_sessionScope) _sessionScope->addRef(); if (_secureSessionScope) _secureSessionScope->addRef(); } HttpRequest::~HttpRequest() { releaseLocks(); if (_requestScope && _requestScope->release() == 0) delete _requestScope; if (_applicationScope && _applicationScope->release() == 0) delete _applicationScope; if (_sessionScope && _sessionScope->release() == 0) delete _sessionScope; if (_secureSessionScope && _secureSessionScope->release() == 0) delete _secureSessionScope; } HttpRequest& HttpRequest::operator= (const HttpRequest& r) { _pathinfo = r._pathinfo; _args = r._args; _getparam = r._getparam; _postparam = r._postparam; _qparam = r._qparam; _ct = r._ct; _mp = r._mp; _socketIf = r._socketIf; _serial = r._serial; _requestScope = r._requestScope; _applicationScope = r._applicationScope; _sessionScope = r._sessionScope; _secureSessionScope = r._secureSessionScope; _threadContext = r._threadContext; _applicationScopeLocked = false; _sessionScopeLocked = false; _secureSessionScopeLocked = false; if (_requestScope) _requestScope->addRef(); if (_applicationScope) _applicationScope->addRef(); if (_sessionScope) _sessionScope->addRef(); if (_secureSessionScope) _secureSessionScope->addRef(); return *this; } void HttpRequest::clear() { HttpMessage::clear(); _body.clear(); _methodLen = 0; _method[0] = '\0'; _url.clear(); _queryString.clear(); _contentSize = 0; _pathinfo.clear(); _args.clear(); _getparam.clear(); _postparam.clear(); _qparam.clear(); _ct = Contenttype(); _mp = Multipart(); if (_requestScope) { if (_requestScope->release() == 0) delete _requestScope; _requestScope = 0; } httpcookies.clear(); _encodingRead = false; _username.clear(); _password.clear(); releaseLocks(); if (_applicationScope) { if (_applicationScope->release() == 0) delete _applicationScope; _applicationScope = 0; } if (_sessionScope) { if (_sessionScope->release() == 0) delete _sessionScope; _sessionScope = 0; } if (_secureSessionScope) { if (_secureSessionScope->release() == 0) delete _secureSessionScope; _secureSessionScope = 0; } _threadContext = 0; } void HttpRequest::setMethod(const char* m) { if (strlen(m) >= 7) throw HttpError(HTTP_BAD_REQUEST, "invalid method"); std::strcpy(_method, m); } void HttpRequest::setArgs(const args_type& a, bool addToQparam) { _args = a; for (args_type::const_iterator it = a.begin(); it != a.end(); ++it) _qparam.add(it->first, it->second); } std::string HttpRequest::getArgDef(args_type::size_type n, const std::string& def) const { std::ostringstream k; k << "arg" << n; return getArg(k.str(), def); } std::string HttpRequest::getArg(const std::string& name, const std::string& def) const { args_type::const_iterator it = _args.find(name); return it == _args.end() ? def : it->second; } void HttpRequest::parse(std::istream& in) { Parser p(*this); p.parse(in); if (!p.failed()) doPostParse(); } void HttpRequest::doPostParse() { if (hasHeader("Expect:")) throw HttpError(HTTP_EXPECTATION_FAILED, "expectation failed", "Expect not supported by this server"); _getparam.parse_url(getQueryString()); if (isMethodPOST()) { std::istringstream in(getHeader(httpheader::contentType)); in >> _ct; if (in) { if (_ct.isMultipart()) { _mp.set(_ct.getBoundary(), getBody()); for (Multipart::const_iterator it = _mp.begin(); it != _mp.end(); ++it) { // don't copy uploaded files into qparam to prevent unnecessery // copies of large chunks if (it->getFilename().empty()) { std::string multipartBody(it->getBodyBegin(), it->getBodyEnd()); _postparam.add(it->getName(), multipartBody); } } } else if (_ct.getType() == "application" && _ct.getSubtype() == "x-www-form-urlencoded") { _postparam.parse_url(getBody()); } } } _qparam.add(_getparam); _qparam.add(_postparam); _serial = ++_nextSerial; } const Cookies& HttpRequest::getCookies() const { if (!httpcookies.hasCookies()) { header_type::const_iterator it = header.find(httpheader::cookie); if (it != header.end()) const_cast(this)->httpcookies.set(it->second); } return httpcookies; } const Encoding& HttpRequest::getEncoding() const { if (!_encodingRead) { _encoding.parse(getHeader(httpheader::acceptEncoding)); _encodingRead = true; } return _encoding; } const std::string& HttpRequest::getUsername() const { if (_username.empty() && hasHeader(httpheader::authorization)) { std::istringstream authHeader(getHeader(httpheader::authorization)); while (authHeader && authHeader.get() != ' ') ; cxxtools::Base64istream in(authHeader); std::getline(in, _username, ':'); std::getline(in, _password); } return _username; } const std::string& HttpRequest::getPassword() const { getUsername(); return _password; } bool HttpRequest::verifyPassword(const std::string& password) const { getUsername(); return _password == password; } bool HttpRequest::keepAlive() const { // request is keep alive when either a connection header is explicitely set to keep alive // or the http version is 1.1 Messageheader::const_iterator it = header.find(httpheader::connection); return it == header.end() ? getMinorVersion() >= 1 && getMajorVersion() >= 1 : tnt::StringCompareIgnoreCase(it->second, httpheader::connectionKeepAlive) == 0; } const Contenttype& HttpRequest::getContentTypePriv() const { std::istringstream in(getHeader(httpheader::contentType)); in >> _ct; return _ct; } void HttpRequest::setApplicationScope(Scope* s) { if (_applicationScope == s) return; if (_applicationScope) { releaseApplicationScopeLock(); if (_applicationScope->release() == 0) delete _applicationScope; } if (s) s->addRef(); _applicationScope = s; } void HttpRequest::setSessionScope(Sessionscope* s) { if (_sessionScope == s) return; if (_sessionScope) { if (_sessionScopeLocked) { _sessionScope->unlock(); _sessionScopeLocked = false; } if (_sessionScope->release() == 0) delete _sessionScope; } if (s) s->addRef(); _sessionScope = s; } void HttpRequest::setSecureSessionScope(Sessionscope* s) { if (_secureSessionScope == s) return; if (_secureSessionScope) { if (_secureSessionScopeLocked) { _secureSessionScope->unlock(); _secureSessionScopeLocked = false; } if (_secureSessionScope->release() == 0) delete _secureSessionScope; } if (s) s->addRef(); _secureSessionScope = s; } void HttpRequest::ensureApplicationScopeLock() { ensureSessionScopeLock(); if (_applicationScope && !_applicationScopeLocked) { _applicationScope->lock(); _applicationScopeLocked = true; } } void HttpRequest::ensureSessionScopeLock() { if (_sessionScope && !_sessionScopeLocked) { _sessionScope->lock(); _sessionScopeLocked = true; } if (_secureSessionScope && !_secureSessionScopeLocked) { _secureSessionScope->lock(); _secureSessionScopeLocked = true; } } void HttpRequest::releaseApplicationScopeLock() { releaseSessionScopeLock(); if (_applicationScope && _applicationScopeLocked) { _applicationScopeLocked = false; _applicationScope->unlock(); } } void HttpRequest::releaseSessionScopeLock() { if (_secureSessionScope && _secureSessionScopeLocked) { _secureSessionScopeLocked = false; _secureSessionScope->unlock(); } if (_sessionScope && _sessionScopeLocked) { _sessionScopeLocked = false; _sessionScope->unlock(); } } Scope& HttpRequest::getRequestScope() { if (_requestScope == 0) _requestScope = new Scope(); return *_requestScope; } Scope& HttpRequest::getThreadScope() { if (_threadContext == 0) throwRuntimeError("threadcontext not set"); return _threadContext->getScope(); } Scope& HttpRequest::getApplicationScope() { ensureApplicationScopeLock(); return *_applicationScope; } Sessionscope& HttpRequest::getSessionScope() { if (!_sessionScope) _sessionScope = new Sessionscope(); ensureSessionScopeLock(); return *_sessionScope; } Sessionscope& HttpRequest::getSecureSessionScope() { if (!_secureSessionScope) _secureSessionScope = new Sessionscope(); ensureSessionScopeLock(); return *_secureSessionScope; } bool HttpRequest::hasSessionScope() const { return _sessionScope != 0 && !_sessionScope->empty(); } bool HttpRequest::hasSecureSessionScope() const { return _secureSessionScope != 0 && !_secureSessionScope->empty(); } void HttpRequest::postRunCleanup() { #ifdef ENABLE_LOCALE tnt::clearLocaleCache(); #endif } } tntnet-3.0/framework/common/ioapi.c000066400000000000000000000200441365471676700174500ustar00rootroot00000000000000/* ioapi.h -- IO base function header for compress/uncompress .zip part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) Modifications for Zip64 support Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) For more info read MiniZip_info.txt */ #if defined(_WIN32) && (!(defined(_CRT_SECURE_NO_WARNINGS))) #define _CRT_SECURE_NO_WARNINGS #endif #if defined(__APPLE__) || defined(IOAPI_NO_64) /* In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions */ #define FOPEN_FUNC(filename, mode) fopen(filename, mode) #define FTELLO_FUNC(stream) ftello(stream) #define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) #else #define FOPEN_FUNC(filename, mode) fopen64(filename, mode) #define FTELLO_FUNC(stream) ftello64(stream) #define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) #endif #include "ioapi.h" voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) { if (pfilefunc->zfile_func64.zopen64_file != NULL) return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); else { return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); } } long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) { if (pfilefunc->zfile_func64.zseek64_file != NULL) return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); else { uLong offsetTruncated = (uLong)offset; if (offsetTruncated != offset) return -1; else return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); } } ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) { if (pfilefunc->zfile_func64.zseek64_file != NULL) return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); else { uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); if ((tell_uLong) == MAXU32) return (ZPOS64_T)-1; else return tell_uLong; } } void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) { p_filefunc64_32->zfile_func64.zopen64_file = NULL; p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; p_filefunc64_32->zfile_func64.ztell64_file = NULL; p_filefunc64_32->zfile_func64.zseek64_file = NULL; p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; } static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) { FILE* file = NULL; const char* mode_fopen = NULL; if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) mode_fopen = "rb"; else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) mode_fopen = "r+b"; else if (mode & ZLIB_FILEFUNC_MODE_CREATE) mode_fopen = "wb"; if ((filename!=NULL) && (mode_fopen != NULL)) file = fopen(filename, mode_fopen); return file; } static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) { FILE* file = NULL; const char* mode_fopen = NULL; if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) mode_fopen = "rb"; else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) mode_fopen = "r+b"; else if (mode & ZLIB_FILEFUNC_MODE_CREATE) mode_fopen = "wb"; if ((filename!=NULL) && (mode_fopen != NULL)) file = FOPEN_FUNC((const char*)filename, mode_fopen); return file; } static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) { uLong ret; ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); return ret; } static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) { uLong ret; ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); return ret; } static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) { long ret; ret = ftell((FILE *)stream); return ret; } static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) { ZPOS64_T ret; ret = FTELLO_FUNC((FILE *)stream); return ret; } static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) { int fseek_origin=0; long ret; switch (origin) { case ZLIB_FILEFUNC_SEEK_CUR : fseek_origin = SEEK_CUR; break; case ZLIB_FILEFUNC_SEEK_END : fseek_origin = SEEK_END; break; case ZLIB_FILEFUNC_SEEK_SET : fseek_origin = SEEK_SET; break; default: return -1; } ret = 0; if (fseek((FILE *)stream, offset, fseek_origin) != 0) ret = -1; return ret; } static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) { int fseek_origin=0; long ret; switch (origin) { case ZLIB_FILEFUNC_SEEK_CUR : fseek_origin = SEEK_CUR; break; case ZLIB_FILEFUNC_SEEK_END : fseek_origin = SEEK_END; break; case ZLIB_FILEFUNC_SEEK_SET : fseek_origin = SEEK_SET; break; default: return -1; } ret = 0; if(FSEEKO_FUNC((FILE *)stream, offset, fseek_origin) != 0) ret = -1; return ret; } static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) { int ret; ret = fclose((FILE *)stream); return ret; } static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) { int ret; ret = ferror((FILE *)stream); return ret; } void fill_fopen_filefunc (pzlib_filefunc_def) zlib_filefunc_def* pzlib_filefunc_def; { pzlib_filefunc_def->zopen_file = fopen_file_func; pzlib_filefunc_def->zread_file = fread_file_func; pzlib_filefunc_def->zwrite_file = fwrite_file_func; pzlib_filefunc_def->ztell_file = ftell_file_func; pzlib_filefunc_def->zseek_file = fseek_file_func; pzlib_filefunc_def->zclose_file = fclose_file_func; pzlib_filefunc_def->zerror_file = ferror_file_func; pzlib_filefunc_def->opaque = NULL; } void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) { pzlib_filefunc_def->zopen64_file = fopen64_file_func; pzlib_filefunc_def->zread_file = fread_file_func; pzlib_filefunc_def->zwrite_file = fwrite_file_func; pzlib_filefunc_def->ztell64_file = ftell64_file_func; pzlib_filefunc_def->zseek64_file = fseek64_file_func; pzlib_filefunc_def->zclose_file = fclose_file_func; pzlib_filefunc_def->zerror_file = ferror_file_func; pzlib_filefunc_def->opaque = NULL; } tntnet-3.0/framework/common/ioapi.h000066400000000000000000000156321365471676700174640ustar00rootroot00000000000000/* ioapi.h -- IO base function header for compress/uncompress .zip part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) Modifications for Zip64 support Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) For more info read MiniZip_info.txt Changes Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. More if/def section may be needed to support other platforms Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. (but you should use iowin32.c for windows instead) */ #ifndef _ZLIBIOAPI64_H #define _ZLIBIOAPI64_H #if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) /* Linux needs this to support file operation on files larger then 4+GB */ /* But might need better if/def to select just the platforms that needs them. */ #ifndef __USE_FILE_OFFSET64 #define __USE_FILE_OFFSET64 #endif #ifndef __USE_LARGEFILE64 #define __USE_LARGEFILE64 #endif #ifndef _LARGEFILE64_SOURCE #define _LARGEFILE64_SOURCE #endif #ifndef _FILE_OFFSET_BIT #define _FILE_OFFSET_BIT 64 #endif #endif #include #include #include "zlib.h" #if defined(USE_FILE32API) #define fopen64 fopen #define ftello64 ftell #define fseeko64 fseek #else #ifdef __FreeBSD__ #define fopen64 fopen #define ftello64 ftello #define fseeko64 fseeko #endif #ifdef _MSC_VER #define fopen64 fopen #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) #define ftello64 _ftelli64 #define fseeko64 _fseeki64 #else /* old MSC */ #define ftello64 ftell #define fseeko64 fseek #endif #endif #endif /* #ifndef ZPOS64_T #ifdef _WIN32 #define ZPOS64_T fpos_t #else #include #define ZPOS64_T uint64_t #endif #endif */ #ifdef HAVE_MINIZIP64_CONF_H #include "mz64conf.h" #endif /* a type choosen by DEFINE */ #ifdef HAVE_64BIT_INT_CUSTOM typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; #else #ifdef HAS_STDINT_H #include "stdint.h" typedef uint64_t ZPOS64_T; #else /* Maximum unsigned 32-bit value used as placeholder for zip64 */ #define MAXU32 0xffffffff #if defined(_MSC_VER) || defined(__BORLANDC__) typedef unsigned __int64 ZPOS64_T; #else typedef unsigned long long int ZPOS64_T; #endif #endif #endif #ifdef __cplusplus extern "C" { #endif #define ZLIB_FILEFUNC_SEEK_CUR (1) #define ZLIB_FILEFUNC_SEEK_END (2) #define ZLIB_FILEFUNC_SEEK_SET (0) #define ZLIB_FILEFUNC_MODE_READ (1) #define ZLIB_FILEFUNC_MODE_WRITE (2) #define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) #define ZLIB_FILEFUNC_MODE_EXISTING (4) #define ZLIB_FILEFUNC_MODE_CREATE (8) #ifndef ZCALLBACK #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) #define ZCALLBACK CALLBACK #else #define ZCALLBACK #endif #endif typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); /* here is the "old" 32 bits structure structure */ typedef struct zlib_filefunc_def_s { open_file_func zopen_file; read_file_func zread_file; write_file_func zwrite_file; tell_file_func ztell_file; seek_file_func zseek_file; close_file_func zclose_file; testerror_file_func zerror_file; voidpf opaque; } zlib_filefunc_def; typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); typedef struct zlib_filefunc64_def_s { open64_file_func zopen64_file; read_file_func zread_file; write_file_func zwrite_file; tell64_file_func ztell64_file; seek64_file_func zseek64_file; close_file_func zclose_file; testerror_file_func zerror_file; voidpf opaque; } zlib_filefunc64_def; void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); /* now internal definition, only for zip.c and unzip.h */ typedef struct zlib_filefunc64_32_def_s { zlib_filefunc64_def zfile_func64; open_file_func zopen32_file; tell_file_func ztell32_file; seek_file_func zseek32_file; } zlib_filefunc64_32_def; #define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) #define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) /*#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) */ /*#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) */ #define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) #define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); #define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) #define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) #define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) #ifdef __cplusplus } #endif #endif tntnet-3.0/framework/common/job.cpp000066400000000000000000000036421365471676700174660ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/job.h" #include "tnt/tntconfig.h" namespace tnt { Job::Job(Tntnet& app, const SocketIf* socketIf) : _keepAliveCounter(TntConfig::it().keepAliveMax), _request(app, socketIf), _parser(_request), _lastAccessTime(0) { } Job::~Job() { } void Job::clear() { _parser.reset(); _request.clear(); } cxxtools::Milliseconds Job::msecToTimeout(time_t currentTime) const { return cxxtools::Seconds(_lastAccessTime - currentTime + 1) + TntConfig::it().keepAliveTimeout - TntConfig::it().socketReadTimeout; } } tntnet-3.0/framework/common/listener.cpp000066400000000000000000000066051365471676700205430ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/listener.h" #include "tnt/tntnet.h" #include "tnt/job.h" #include #include #include #include "config.h" log_define("tntnet.listener") namespace tnt { namespace { void doListenRetry(cxxtools::net::TcpServer& server, const std::string& ipaddr, unsigned short int port) { for (unsigned n = 1; true; ++n) { try { log_debug("listen " << ipaddr << ':' << port); #ifdef HAVE_CXXTOOLS_REUSEADDR int flags = cxxtools::net::TcpServer::DEFER_ACCEPT; if (TntConfig::it().reuseAddress) flags |= cxxtools::net::TcpServer::REUSEADDR; server.listen(ipaddr, port, TntConfig::it().listenBacklog, flags); #else server.listen(ipaddr, port, TntConfig::it().listenBacklog, cxxtools::net::TcpServer::DEFER_ACCEPT); #endif return; } catch (const cxxtools::net::AddressInUse& e) { log_debug("cxxtools::net::AddressInUse"); if (n > TntConfig::it().listenRetry) { log_debug("rethrow exception"); throw; } log_warn("address " << ipaddr << ':' << port << " in use - retry; n = " << n); ::sleep(1); } } } } Listener::Listener(Tntnet& application, const std::string& ipaddr, unsigned short int port, Jobqueue& q, const std::string& certificateFile, const std::string& privateKeyFile, int sslVerifyLevel, const std::string& sslCa) : _queue(q), _certificateFile(certificateFile), _privateKeyFile(privateKeyFile), _sslVerifyLevel(sslVerifyLevel), _sslCa(sslCa) { log_info("listen ip=" << ipaddr << " port=" << port); doListenRetry(_server, ipaddr, port); Jobqueue::JobPtr p = new Tcpjob(application, _server, _queue, certificateFile, privateKeyFile, sslVerifyLevel, sslCa); _queue.put(p); } void Listener::terminate() { log_info("stop listener"); _server.terminateAccept(); } } tntnet-3.0/framework/common/mbcomponent.cpp000066400000000000000000000122701365471676700212320ustar00rootroot00000000000000/* * Copyright (C) 2010 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include log_define("tntnet.mbcomponent") namespace tnt { namespace { inline bool charpLess(const char* a, const char* b) { return std::strcmp(a, b) < 0; } } void MbComponent::init(const char* rawData, const char** urls, const char** mimetypes, const char** ctimes) { _rawData = rawData; _urls = urls; _mimetypes = mimetypes; _ctimes = ctimes; tnt::DataChunks data(rawData); _compressedData.resize(data.size()); } unsigned MbComponent::operator() (tnt::HttpRequest& request, tnt::HttpReply& reply, tnt::QueryParams& qparam) { return doCall(request, reply, qparam, false); } unsigned MbComponent::topCall(tnt::HttpRequest& request, tnt::HttpReply& reply, tnt::QueryParams& qparam) { return doCall(request, reply, qparam, true); } unsigned MbComponent::doCall(tnt::HttpRequest& request, tnt::HttpReply& reply, tnt::QueryParams&, bool top) { log_trace("MbComponent " << getCompident()); tnt::DataChunks data(_rawData); unsigned url_idx = 0; if (_urls) { const char* url = request.getPathInfo().c_str(); log_debug("search for \"" << url << '"'); const char** urls_end = _urls + data.size(); const char** it = std::lower_bound(_urls, urls_end, url, charpLess); if (it == urls_end || std::strcmp(url, *it) != 0) { log_debug("file \"" << url << "\" not found"); return DECLINED; } url_idx = it - _urls; log_debug("file \"" << url << "\" found; idx=" << url_idx); } if (top) { reply.setKeepAliveHeader(); reply.setContentType(_mimetypes[url_idx]); if (!reply.hasHeader(httpheader::cacheControl)) { std::string maxAgeStr = request.getArg("maxAge"); unsigned maxAge = maxAgeStr.empty() ? 14400 : cxxtools::convert(maxAgeStr); reply.setMaxAgeHeader(maxAge); } std::string s = request.getHeader(tnt::httpheader::ifModifiedSince); if (s == _ctimes[url_idx]) return HTTP_NOT_MODIFIED; reply.setHeader(tnt::httpheader::lastModified, _ctimes[url_idx]); if (request.getEncoding().accept("gzip")) { cxxtools::ReadLock lock(_mutex); if (_compressedData[url_idx].empty()) { lock.unlock(); cxxtools::WriteLock wlock(_mutex); if (_compressedData[url_idx].empty()) { // check for compression std::string body(data[url_idx].getData(), data[url_idx].getLength()); log_debug("compress"); if (reply.tryCompress(body)) { log_info("compressed from " << data[url_idx].getLength() << " to " << body.size()); _compressedData[url_idx] = body; } else { log_info("not compressed " << data[url_idx].getLength()); _compressedData[url_idx] = "-"; } } } if (_compressedData[url_idx] != "-") { log_debug("compressed data found; content size " << data[url_idx].getLength() << " to " << _compressedData[url_idx].size()); reply.setContentLengthHeader(_compressedData[url_idx].size()); reply.setHeader(httpheader::contentEncoding, "gzip"); if (!request.isMethodHEAD()) { reply.setDirectMode(); reply.out() << _compressedData[url_idx]; } return HTTP_OK; } } reply.setContentLengthHeader(data.size(url_idx)); if (!request.isMethodHEAD()) { log_debug("send data"); reply.setDirectMode(); } } if (!request.isMethodHEAD()) reply.out() << data[url_idx]; return HTTP_OK; } } tntnet-3.0/framework/common/messageattribute.cpp000066400000000000000000000206261365471676700222650ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include namespace tnt { namespace { static inline bool istokenchar(char ch) { return ch >= 33 && ch <= 126 && ch != '(' && ch != ')' && ch != '<' && ch != '>' && ch != '@' && ch != ',' && ch != ';' && ch != ':' && ch != '\\' && ch != '"' && ch != '/' && ch != '[' && ch != ']' && ch != '?' && ch != '='; } static inline bool tnt_isblank(char ch) { return ch == ' ' || ch == '\t'; } } void MessageattributeParser::parse(std::istream& in) { enum state_type { state_0, state_type0, state_type_sp, state_subtype0, state_subtype, state_subtype_sp, state_attribute0, state_attribute, state_attribute_sp, state_value0, state_value, state_qvalue, state_end }; state_type state = state_0; std::streambuf* buf = in.rdbuf(); std::string type, subtype, attribute, value; while (state != state_end && buf->sgetc() != std::ios::traits_type::eof()) { char ch = buf->sgetc(); switch (state) { case state_0: if (istokenchar(ch)) { type.clear(); type.reserve(16); type += ch; state = state_type0; } else if (std::isspace(ch)) in.setstate(std::ios::failbit); break; case state_type0: if (tnt_isblank(ch)) state = state_type_sp; else if (ch == '/') state = state_subtype0; else if (ch == ';') { switch (onType(type, std::string())) { case OK: state = state_attribute0; break; case FAIL: in.setstate(std::ios::failbit); break; case END: state = state_end; break; } } else if (istokenchar(ch)) type += ch; else in.setstate(std::ios::failbit); break; case state_type_sp: if (ch == '/') state = state_subtype0; else if (ch == ';') { switch (onType(type, std::string())) { case OK: state = state_attribute0; break; case FAIL: in.setstate(std::ios::failbit); break; case END: state = state_end; break; } } else if (!tnt_isblank(ch)) in.setstate(std::ios::failbit); break; case state_subtype0: if (istokenchar(ch)) { subtype = ch; state = state_subtype; } else if (!tnt_isblank(ch)) in.setstate(std::ios::failbit); break; case state_subtype: if (ch == ';') { switch (onType(type, subtype)) { case OK: state = state_attribute0; break; case FAIL: in.setstate(std::ios::failbit); break; case END: state = state_end; break; } } else if (tnt_isblank(ch)) { switch (onType(type, subtype)) { case OK: state = state_subtype_sp; break; case FAIL: in.setstate(std::ios::failbit); break; case END: state = state_end; break; } } else if (istokenchar(ch)) subtype += ch; else in.setstate(std::ios::failbit); break; case state_subtype_sp: if (ch == ';') state = state_attribute0; else if (!tnt_isblank(ch)) state = state_end; break; case state_attribute0: if (istokenchar(ch)) { attribute = ch; state = state_attribute; } break; case state_attribute: if (istokenchar(ch)) attribute += ch; else if (tnt_isblank(ch)) state = state_attribute_sp; else if (ch == '=') state = state_value0; else in.setstate(std::ios::failbit); break; case state_attribute_sp: if (ch == '=') state = state_value0; else if (!tnt_isblank(ch)) in.setstate(std::ios::failbit); break; case state_value0: if (ch == '"') state = state_qvalue; else if (istokenchar(ch)) { value.clear(); value.reserve(16); value += ch; state = state_value; } else in.setstate(std::ios::failbit); break; case state_qvalue: if (ch == '"') { switch (onParameter(attribute, value)) { case OK: state = state_subtype_sp; attribute.clear(); value.clear(); break; case FAIL: in.setstate(std::ios::failbit); break; case END: state = state_end; break; } } else value += ch; break; case state_value: if (istokenchar(ch)) value += ch; else if (tnt_isblank(ch)) { switch (onParameter(attribute, value)) { case OK: state = state_subtype_sp; attribute.clear(); value.clear(); break; case FAIL: in.setstate(std::ios::failbit); break; case END: state = state_end; break; } } else if (ch == ';') { switch (onParameter(attribute, value)) { case OK: state = state_attribute0; attribute.clear(); value.clear(); break; case FAIL: in.setstate(std::ios::failbit); break; case END: state = state_end; break; } } else in.setstate(std::ios::failbit); break; case state_end: // not reachable but to satisfy the compiler we put it here break; } if (state != state_end) buf->sbumpc(); } // process last parameter if (in.fail()) return; switch (state) { case state_0: case state_type0: break; case state_type_sp: case state_subtype0: case state_subtype: if (onType(type, subtype) == FAIL) in.setstate(std::ios::failbit); break; case state_subtype_sp: case state_attribute0: break; case state_attribute: case state_attribute_sp: case state_value0: case state_qvalue: in.setstate(std::ios::failbit); break; case state_value: if(onParameter(attribute, value) == FAIL) in.setstate(std::ios::failbit); break; case state_end: break; }; if (buf->sgetc() == std::ios::traits_type::eof()) in.setstate(std::ios::eofbit); } } tntnet-3.0/framework/common/messageheader.cpp000066400000000000000000000100161365471676700215020ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include namespace tnt { log_define("tntnet.messageheader") const unsigned Messageheader::MAXHEADERSIZE; bool Messageheader::compareHeader(const char* key, const char* value) const { const_iterator it = find(key); return it == end() ? false : tnt::StringCompareIgnoreCase(it->second, value) == 0; } void Messageheader::removeHeader(const char* key) { if (!*key) throw std::runtime_error("empty key not allowed in messageheader"); char* p = getEnd(); const_iterator it = begin(); while (it != end()) { if (StringCompareIgnoreCase(key, it->first) == 0) { unsigned slen = it->second - it->first + std::strlen(it->second) + 1; std::memmove( const_cast(it->first), it->first + slen, p - it->first + slen); p -= slen; it.fixup(); } else ++it; } _endOffset = p - _rawdata; } Messageheader::const_iterator Messageheader::find(const char* key) const { for (const_iterator it = begin(); it != end(); ++it) { if (StringCompareIgnoreCase(key, it->first) == 0) return it; } return end(); } void Messageheader::clear() { #ifdef DEBUG std::memset(_rawdata, '\xfe', sizeof(_rawdata)); #endif _rawdata[0] = _rawdata[1] = '\0'; _endOffset = 0; } void Messageheader::setHeader(const char* key, const char* value, bool replace) { if (!*key) throw std::runtime_error("empty key not allowed in messageheader"); if (replace) removeHeader(key); char* p = getEnd(); size_t lk = std::strlen(key); // length of key size_t lk2 = key[lk-1] == ':' ? lk + 1 : lk + 2; // length of key including trailing ':' and terminator size_t lv = std::strlen(value); // length of value if (p - _rawdata + lk2 + lv + 3 > MAXHEADERSIZE) throw std::runtime_error("message header too big"); std::strcpy(p, key); // copy key p += lk2; *(p - 2) = ':'; // make sure, key is prepended by ':' *(p - 1) = '\0'; std::strcpy(p, value); // copy value p[lv + 1] = '\0'; // put new message end marker in place _endOffset = (p + lv + 1) - _rawdata; } Messageheader::return_type Messageheader::onField(const char* name, const char* value) { log_debug(name << ' ' << value); return OK; } std::istream& operator>> (std::istream& in, Messageheader& data) { Messageheader::Parser p(data); p.parse(in); return in; } } tntnet-3.0/framework/common/messageheaderparser.cpp000066400000000000000000000155541365471676700227330ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include namespace tnt { namespace { std::string chartoprint(char ch) { const static char hex[] = "0123456789abcdef"; if (std::isprint(ch)) return std::string(1, '\'') + ch + '\''; else return std::string("'\\x") + hex[ch >> 4] + hex[ch & 0xf] + '\''; } } log_define("tntnet.messageheader.parser") #define SET_STATE(new_state) _state = &Parser::new_state bool Messageheader::Parser::state_0(char ch) { if (ch >= 33 && ch <= 126 && ch != ':') { _fieldnamePtr = _headerdataPtr; checkHeaderspace(1); *_headerdataPtr++ = ch; SET_STATE(state_fieldname); } else if (ch == '\n') return true; else if (ch == '\r') SET_STATE(state_cr); else if (!std::isspace(ch)) { log_warn("invalid character " << chartoprint(ch)); _failedFlag = true; return true; } return false; } bool Messageheader::Parser::state_cr(char ch) { if (ch != '\n') { log_warn("invalid character " << chartoprint(ch) << " in state-cr"); _failedFlag = true; } return true; } bool Messageheader::Parser::state_fieldname(char ch) { if (ch == ':') // Field-name: { checkHeaderspace(2); *_headerdataPtr++ = ch; *_headerdataPtr++ = '\0'; _fieldbodyPtr = _headerdataPtr; SET_STATE(state_fieldbody0); } else if (ch >= 33 && ch <= 126) { checkHeaderspace(1); *_headerdataPtr++ = ch; } else if (std::isspace(ch)) { checkHeaderspace(2); *_headerdataPtr++ = ':'; *_headerdataPtr++ = '\0'; _fieldbodyPtr = _headerdataPtr; SET_STATE(state_fieldnamespace); } else { log_warn("invalid character " << chartoprint(ch) << " in fieldname"); _failedFlag = true; return true; } return false; } bool Messageheader::Parser::state_fieldnamespace(char ch) { if (ch == ':') // "Field-name :" SET_STATE(state_fieldbody0); else if (!std::isspace(ch)) { log_warn("invalid character " << chartoprint(ch) << " in fieldname-space"); _failedFlag = true; return true; } return false; } bool Messageheader::Parser::state_fieldbody0(char ch) { if (ch == '\r') { checkHeaderspace(1); *_headerdataPtr++ = '\0'; SET_STATE(state_fieldbody_cr); } else if (ch == '\n') { checkHeaderspace(1); *_headerdataPtr++ = '\0'; SET_STATE(state_fieldbody_crlf); } else if (!std::isspace(ch)) { checkHeaderspace(1); *_headerdataPtr++ = ch; SET_STATE(state_fieldbody); } return false; } bool Messageheader::Parser::state_fieldbody(char ch) { if (ch == '\r') { checkHeaderspace(1); *_headerdataPtr++ = '\0'; SET_STATE(state_fieldbody_cr); } else if (ch == '\n') { checkHeaderspace(1); *_headerdataPtr++ = '\0'; SET_STATE(state_fieldbody_crlf); } else { checkHeaderspace(1); *_headerdataPtr++ = ch; } return false; } bool Messageheader::Parser::state_fieldbody_cr(char ch) { if (ch == '\n') SET_STATE(state_fieldbody_crlf); else { log_warn("invalid character " << chartoprint(ch) << " in fieldbody-cr"); _failedFlag = true; return true; } return false; } bool Messageheader::Parser::state_fieldbody_crlf(char ch) { if (ch == '\r') SET_STATE(state_end_cr); else if (ch == '\n') { log_debug("header " << _fieldnamePtr << ": " << _fieldbodyPtr); if (_header.onField(_fieldnamePtr, _fieldbodyPtr) == FAIL) { _failedFlag = true; log_warn("invalid character " << chartoprint(ch) << " in fieldbody"); } *_headerdataPtr = '\0'; return true; } else if (std::isspace(ch)) { // continuation line checkHeaderspace(1); *(_headerdataPtr - 1) = '\n'; *_headerdataPtr++ = ch; SET_STATE(state_fieldbody); } else if (ch >= 33 && ch <= 126) { switch (_header.onField(_fieldnamePtr, _fieldbodyPtr)) { case OK: SET_STATE(state_fieldname); break; case FAIL: _failedFlag = true; log_warn("invalid character " << chartoprint(ch) << " in fieldbody"); break; case END: return true; break; } _fieldnamePtr = _headerdataPtr; checkHeaderspace(1); *_headerdataPtr++ = ch; } return false; } bool Messageheader::Parser::state_end_cr(char ch) { if (ch == '\n') { if (_header.onField(_fieldnamePtr, _fieldbodyPtr) == FAIL) { log_warn("invalid header " << _fieldnamePtr << ' ' << _fieldbodyPtr); _failedFlag = true; } *_headerdataPtr = '\0'; return true; } else { log_warn("invalid character " << chartoprint(ch) << " in end-cr"); _failedFlag = true; return true; } return false; } void Messageheader::Parser::checkHeaderspace(unsigned chars) const { if (_headerdataPtr + chars >= _header._rawdata + sizeof(_header._rawdata)) { _header._rawdata[sizeof(_header._rawdata) - 1] = '\0'; throw HttpError(HTTP_REQUEST_ENTITY_TOO_LARGE, "header too large"); } } void Messageheader::Parser::reset() { _failedFlag = false; _headerdataPtr = _header._rawdata; SET_STATE(state_0); } } tntnet-3.0/framework/common/mimedb.cpp000066400000000000000000000104041365471676700201430ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include namespace tnt { log_define("tntnet.mime") void MimeDb::read(const std::string& mimefile) { std::ifstream in(mimefile.c_str()); read(in); } void MimeDb::read(const char* mimefile) { std::ifstream in(mimefile); read(in); } void MimeDb::read(std::istream& in) { enum state_type { state_0, state_comment, state_mime, state_ext0, state_ext } state = state_0; std::string mime; std::string ext; std::streambuf* buf = in.rdbuf(); while (buf->sgetc() != std::ios::traits_type::eof()) { char ch = buf->sbumpc(); switch (state) { case state_0: if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) { mime = ch; state = state_mime; } else if (ch == '#') state = state_comment; else if (!std::isspace(ch)) throwRuntimeError("parse error in mimedb"); break; case state_comment: if (ch == '\n') state = state_0; break; case state_mime: if (ch == '\n') state = state_0; else if (std::isspace(ch)) state = state_ext0; else mime += ch; break; case state_ext0: if (ch == '\n') state = state_0; else if (ch == '.') { ext.clear(); state = state_ext; } else if (!std::isspace(ch)) { ext = ch; state = state_ext; } break; case state_ext: if (std::isspace(ch)) { log_debug(ext << " => " << mime); _mimeDb.insert(MimeDbType::value_type(ext, mime)); state = ch == '\n' ? state_0 : state_ext0; } else ext += ch; } } } void MimeDb::addType(const std::string& ext, const std::string& mimeType) { if (ext.size() > 0 && ext.at(0) == '.') _mimeDb.insert(MimeDbType::value_type(ext.substr(1), mimeType)); else _mimeDb.insert(MimeDbType::value_type(ext, mimeType)); } std::string MimeDb::getMimetype(const std::string& fname) const { log_debug("get mimetype for \"" << fname << '"'); std::string ext; std::string::size_type p = fname.rfind('.'); if (p != std::string::npos) ext = fname.substr(p + 1); else ext = fname; log_debug("ext=" << ext); MimeDbType::const_iterator it = _mimeDb.find(ext); if (it == _mimeDb.end()) { log_debug("no mimetype found for ext \"" << ext << '"'); return std::string(); } else { log_debug("mimetype for ext \"" << ext << "\": " << it->second); return it->second; } } } tntnet-3.0/framework/common/multipart.cpp000066400000000000000000000106071365471676700207340ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include namespace { template class iterator_streambuf : public std::streambuf { public: typedef unsigned long streamsize; private: iterator& _begin; iterator _end; char_type _buffer[2]; protected: std::streambuf::int_type overflow(std::streambuf::int_type /* ch */) { return traits_type::eof(); } int sync() { if (gptr() == _buffer + 1) ++_begin; setg(0, 0, 0); return 0; } std::streambuf::int_type underflow() { if (_begin == _end) return traits_type::eof(); if (gptr() == _buffer + 1) ++_begin; _buffer[0] = *_begin; setg(_buffer, _buffer, _buffer + 1); return _buffer[0]; } public: iterator_streambuf(iterator& b, iterator e) : _begin(b), _end(e) { } }; } namespace tnt { Partheader::return_type Partheader::onField(const char* name, const char* value) { if (tnt::StringCompareIgnoreCase(name, "Content-Disposition:") == 0) { std::istringstream in(value); in >> _cd; if (!in) return FAIL; } return Messageheader::onField(name, value); } Part::Part(const_iterator b, const_iterator e) { iterator_streambuf buf(b, e); std::istream in(&buf); in >> _header; if (!in) throwRuntimeError("error in parsing message-header"); in.sync(); _bodyBegin = b; _bodyEnd = e; } std::string Part::getHeader(const std::string& key) const { Messageheader::const_iterator it = _header.find(key); if (it != _header.end()) return it->second; return std::string(); } std::string Partheader::getMimetype() const { const_iterator it = find(httpheader::contentType); return it == end() ? std::string() : it->second; } void Multipart::set(const std::string& boundary, const std::string& b) { _body = b; std::string::size_type bpos = _body.find(boundary); while (bpos != std::string::npos) { bpos += boundary.size(); if (_body[bpos] == '\r') ++bpos; if (_body[bpos] == '\n') ++bpos; std::string::size_type bend = _body.find(boundary, bpos); if (bend == std::string::npos) return; std::string::size_type nbegin = bend; if (_body[bend-1] == '-') --bend; if (_body[bend-1] == '-') --bend; if (_body[bend-1] == '\n') --bend; if (_body[bend-1] == '\r') --bend; _parts.push_back(part_type(_body.begin() + bpos, _body.begin() + bend)); bpos = nbegin; } } Multipart::const_iterator Multipart::find(const std::string& part_name, Multipart::const_iterator start) const { for (const_iterator it = start; it != end(); ++it) if (it->getName() == part_name) return it; return end(); } } tntnet-3.0/framework/common/poller.cpp000066400000000000000000000030501365471676700202020ustar00rootroot00000000000000/* * Copyright (C) 2005-2006 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/poller.h" #include "tnt/pollerimpl.h" namespace tnt { PollerIf::~PollerIf() { } Poller::Poller(Jobqueue& q) : _impl(new PollerImpl(q)) { } void Poller::run() { _impl->run(); } } tntnet-3.0/framework/common/pollerimpl.cpp000066400000000000000000000245721365471676700211000ustar00rootroot00000000000000/* * Copyright (C) 2005-2006 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/pollerimpl.h" #include "tnt/tntnet.h" #include #include #include #include #include #ifdef WITH_EPOLL # include # include #endif log_define("tntnet.pollerimpl") namespace tnt { #ifdef WITH_EPOLL PollerImpl::PollerImpl(Jobqueue& q) : _queue(q), _pollFd(-1), _pollTimeout(-1) { #ifdef HAVE_EPOLL_CREATE1 _pollFd = ::epoll_create1(EPOLL_CLOEXEC); if (_pollFd < 0) throw cxxtools::SystemError("epoll_create1"); #else _pollFd = ::epoll_create(1); if (_pollFd < 0) throw cxxtools::SystemError("epoll_create"); int flags = ::fcntl(_pollFd, F_GETFD); flags |= FD_CLOEXEC ; int ret = ::fcntl(_pollFd, F_SETFD, flags); if(-1 == ret) throw cxxtools::SystemError("fcntl(FD_CLOEXEC)"); #endif fcntl(_notifyPipe.getReadFd(), F_SETFL, O_NONBLOCK); addFd(_notifyPipe.getReadFd()); } PollerImpl::~PollerImpl() { close(_pollFd); } void PollerImpl::addFd(int fd) { log_trace("addFd(" << fd << ')'); epoll_event e; e.events = EPOLLIN; e.data.fd = fd; int ret = ::epoll_ctl(_pollFd, EPOLL_CTL_ADD, fd, &e); if (ret < 0) throw cxxtools::SystemError("epoll_ctl(EPOLL_CTL_ADD)"); } bool PollerImpl::removeFd(int fd) { epoll_event e; e.data.fd = fd; int ret = ::epoll_ctl(_pollFd, EPOLL_CTL_DEL, fd, &e); if (ret < 0) { if (errno == EBADF || errno == ENOENT) return false; else throw cxxtools::SystemError("epoll_ctl(EPOLL_CTL_DEL)"); } return true; } void PollerImpl::doStop() { _notifyPipe.write('A'); } void PollerImpl::addIdleJob(Jobqueue::JobPtr& job) { if (job->getFd() == -1) { log_debug("ignore idle socket which is not connected any more"); cxxtools::MutexLock lock(_mutex); job = 0; } else { log_debug("add idle socket " << job->getFd()); cxxtools::MutexLock lock(_mutex); _newJobs.push_back(job); job = 0; } _notifyPipe.write('A'); } void PollerImpl::appendNewJobs() { cxxtools::MutexLock lock(_mutex); if (!_newJobs.empty()) { // append new jobs to current log_trace("append " << _newJobs.size() << " sockets to poll"); time_t currentTime; time(¤tTime); for (new_jobs_type::iterator it = _newJobs.begin(); it != _newJobs.end(); ++it) { try { addFd((*it)->getFd()); _jobs[(*it)->getFd()] = *it; int msec = (*it)->msecToTimeout(currentTime); if (_pollTimeout < 0) _pollTimeout = msec; else if (msec < _pollTimeout) _pollTimeout = msec; } catch (const std::exception& e) { log_error("failed to add fd " << (*it)->getFd() << " to poll: " << e.what()); } } _newJobs.clear(); } } void PollerImpl::run() { epoll_event events[16]; time_t pollTime; time(&pollTime); while (!Tntnet::shouldStop()) { usleep(100); appendNewJobs(); if (_jobs.empty()) _pollTimeout = -1; int ret = ::epoll_wait(_pollFd, events, 16, _pollTimeout); if (ret < 0) { if (errno != EINTR) throw cxxtools::SystemError("epoll_wait"); } else if (ret == 0) { // timeout reached - check for timed out requests and get next timeout _pollTimeout = -1; time_t currentTime; time(¤tTime); for (jobs_type::iterator it = _jobs.begin(); it != _jobs.end(); ) { int msec = it->second->msecToTimeout(currentTime); if (msec <= 0) { log_debug("timeout for fd " << it->second->getFd() << " reached"); jobs_type::iterator it2 = it++; _jobs.erase(it2); } else { if (_pollTimeout < 0 || msec < _pollTimeout) _pollTimeout = msec; ++it; } } } else { time_t currentTime; time(¤tTime); _pollTimeout -= (currentTime - pollTime) * 1000; if (_pollTimeout <= 0) _pollTimeout = 100; pollTime = currentTime; // no timeout - process events bool rebuildPollFd = false; for (int i = 0; i < ret; ++i) { if (events[i].data.fd == _notifyPipe.getReadFd()) { if (Tntnet::shouldStop()) { log_info("stop poller"); break; } char buffer[64]; _notifyPipe.read(buffer, sizeof(buffer)); } else { jobs_type::iterator it = _jobs.find(events[i].data.fd); if (it == _jobs.end()) { log_fatal("internal error: job for fd " << events[i].data.fd << " not found in jobs-list"); ::close(events[i].data.fd); rebuildPollFd = true; } else { Jobqueue::JobPtr j = it->second; int ev = events[i].events; _jobs.erase(it); if (!removeFd(events[i].data.fd)) rebuildPollFd = true; if (ev & EPOLLIN) _queue.put(j); } } } if (rebuildPollFd) { // rebuild poll-structure log_warn("need to rebuild poll structure"); close(_pollFd); _pollFd = ::epoll_create(256); if (_pollFd < 0) throw cxxtools::SystemError("epoll_create"); int ret = fcntl(_notifyPipe.getReadFd(), F_SETFL, O_NONBLOCK); if (ret < 0) throw cxxtools::SystemError("fcntl"); addFd(_notifyPipe.getReadFd()); for (jobs_type::iterator it = _jobs.begin(); it != _jobs.end(); ++it) addFd(it->first); } } } } #else PollerImpl::PollerImpl(Jobqueue& q) : _queue(q), _pollTimeout(-1) { fcntl(_notifyPipe.getReadFd(), F_SETFL, O_NONBLOCK); _pollfds.push_back(pollfd()); _pollfds.back().fd = _notifyPipe.getReadFd(); _pollfds.back().events = POLLIN; _pollfds.back().revents = 0; } void PollerImpl::appendNewJobs() { cxxtools::MutexLock lock(_mutex); if (!_newJobs.empty()) { // append new jobs to current log_trace("append " << _newJobs.size() << " sockets to poll"); time_t currentTime; time(¤tTime); for (jobs_type::iterator it = _newJobs.begin(); it != _newJobs.end(); ++it) { append(*it); int msec = (*it)->msecToTimeout(currentTime); if (_pollTimeout < 0 || msec < _pollTimeout) _pollTimeout = msec; } _newJobs.clear(); } } void PollerImpl::append(Jobqueue::JobPtr& job) { _currentJobs.push_back(job); _pollfds.push_back(pollfd()); _pollfds.back().fd = job->getFd(); _pollfds.back().events = POLLIN; } void PollerImpl::run() { while (!Tntnet::shouldStop()) { usleep(100); appendNewJobs(); try { ::poll(&_pollfds[0], _pollfds.size(), _pollTimeout); _pollTimeout = -1; if (_pollfds[0].revents != 0) { if (Tntnet::shouldStop()) { log_info("stop poller"); break; } char buffer[64]; _notifyPipe.read(buffer, sizeof(buffer)); _pollfds[0].revents = 0; } if (_currentJobs.size() > 0) dispatch(); } catch (const std::exception& e) { log_error("error in poll-loop: " << e.what()); } } } void PollerImpl::doStop() { _notifyPipe.write('A'); } void PollerImpl::dispatch() { time_t currentTime; time(¤tTime); for (unsigned i = 0; i < _currentJobs.size(); ) { if (_pollfds[i + 1].revents & POLLIN) { // put job into work-queue _queue.put(_currentJobs[i]); remove(i); } else if (_pollfds[i + 1].revents != 0) remove(i); else { // check timeout int msec = _currentJobs[i]->msecToTimeout(currentTime); if (msec <= 0) remove(i); else if (_pollTimeout < 0 || msec < _pollTimeout) _pollTimeout = msec; ++i; } } } void PollerImpl::remove(jobs_type::size_type n) { // replace job with last job in poller-list jobs_type::size_type last = _currentJobs.size() - 1; if (n != last) { _pollfds[n + 1] = _pollfds[last + 1]; _currentJobs[n] = _currentJobs[last]; } _pollfds.pop_back(); _currentJobs.pop_back(); } void PollerImpl::addIdleJob(Jobqueue::JobPtr& job) { if (job->getFd() == -1) { log_debug("ignore idle socket which is not connected any more"); cxxtools::MutexLock lock(_mutex); job = 0; } else { log_debug("add idle socket " << job->getFd()); cxxtools::MutexLock lock(_mutex); _newJobs.push_back(job); job = 0; } _notifyPipe.write('A'); } #endif // #else WITH_EPOLL } tntnet-3.0/framework/common/savepoint.cpp000066400000000000000000000036321365471676700207230ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include namespace tnt { log_define("tntnet.savepoint") void Savepoint::save() { _pos = _reply.getContentSize(); _active = true; log_debug("set Savepoint " << _pos); } void Savepoint::commit() { log_debug("commit Savepoint " << _pos); _active = false; } void Savepoint::rollback() { if (_active) { log_debug("rollback to Savepoint " << _pos); _reply.rollbackContent(_pos); _active = false; } else log_error("not rolling back not active Savepoint"); } } tntnet-3.0/framework/common/scope.cpp000066400000000000000000000030771365471676700200270ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include namespace tnt { Scope::Scope() { addRef(); } Scope::~Scope() { } void Scope::privatePut(const std::string& key, Scope::pointer_type o) { _data.insert(container_type::value_type(key, o)); } } tntnet-3.0/framework/common/scopemanager.cpp000066400000000000000000000255111365471676700213570ustar00rootroot00000000000000/* * Copyright (C) 2003-2006 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/scopemanager.h" #include "tnt/sessionscope.h" #include "tnt/httprequest.h" #include "tnt/httpreply.h" #include #include #include #include log_define("tntnet.scopemanager") namespace tnt { ScopeManager::ScopeManager() { } ScopeManager::~ScopeManager() { for (sessionscopes_type::iterator it = _sessionScopes.begin(); it != _sessionScopes.end(); ++it) { if (it->second->release() == 0) delete it->second; } for (scopes_type::iterator it = _applicationScopes.begin(); it != _applicationScopes.end(); ++it) { if (it->second->release() == 0) delete it->second; } } Scope* ScopeManager::getApplicationScope(const std::string& appname) { cxxtools::MutexLock lock(_applicationScopesMutex); scopes_type::iterator it = _applicationScopes.find(appname); if (it == _applicationScopes.end()) { log_debug("applicationscope <" + appname + "> not found - create new"); Scope* s = new Scope(); it = _applicationScopes.insert(scopes_type::value_type(appname, s)).first; return s; } else log_debug("applicationscope <" + appname + "> found"); return it->second; } Sessionscope* ScopeManager::getSessionScope(const std::string& sessioncookie) { log_debug("getSessionScope(\"" << sessioncookie << "\")"); cxxtools::MutexLock lock(_sessionScopesMutex); sessionscopes_type::iterator it = _sessionScopes.find(sessioncookie); if (it == _sessionScopes.end()) { log_debug("session " << sessioncookie << " not found"); return 0; } else { log_debug("session " << sessioncookie << " found"); it->second->touch(); return it->second; } } bool ScopeManager::hasSessionScope(const std::string& sessioncookie) { cxxtools::MutexLock lock(_sessionScopesMutex); sessionscopes_type::iterator it = _sessionScopes.find(sessioncookie); return it != _sessionScopes.end(); } void ScopeManager::putSessionScope(const std::string& sessioncookie, Sessionscope* s) { s->addRef(); cxxtools::MutexLock lock(_sessionScopesMutex); sessionscopes_type::iterator it = _sessionScopes.find(sessioncookie); if (it != _sessionScopes.end()) { if (it->second->release() == 0) delete it->second; it->second = s; } else _sessionScopes[sessioncookie] = s; } void ScopeManager::removeApplicationScope(const std::string& appname) { log_debug("remove application scope <" << appname << '>'); cxxtools::MutexLock lock(_applicationScopesMutex); scopes_type::iterator it = _applicationScopes.find(appname); if (it != _applicationScopes.end()) { if (it->second->release() == 0) delete it->second; _applicationScopes.erase(it); } } void ScopeManager::removeSessionScope(const std::string& sessioncookie) { cxxtools::MutexLock lock(_sessionScopesMutex); sessionscopes_type::iterator it = _sessionScopes.find(sessioncookie); if (it != _sessionScopes.end()) { if (it->second->release() == 0) delete it->second; _sessionScopes.erase(it); } } void ScopeManager::preCall(HttpRequest& request, const std::string& app) { // check session-cookie std::string currentSessionCookieName = app.empty() ? std::string("tntnet") : "tntnet." + app; std::string currentSecureSessionCookieName = app.empty() ? std::string("stntnet") : "stntnet." + app; Cookie c = request.getCookie(currentSessionCookieName); if (c.getValue().empty()) { /* cxxtools::MutexLock lock(sessionScopesMutex); log_debug(sessionScopes.size() << " sessions available"); for (sessionscopes_type::iterator it = sessionScopes.begin(); it != sessionScopes.end(); ++it) log_debug("available session " << it->first << " value " << it->second); */ log_debug("session cookie " << currentSessionCookieName << " not found - keep session"); } else { log_debug("session cookie " << currentSessionCookieName << " found: " << c.getValue()); cxxtools::MutexLock lock(_sessionScopesMutex); Sessionscope* sessionScope; sessionscopes_type::iterator it = _sessionScopes.find(c.getValue()); if (it == _sessionScopes.end()) { log_debug("session not found - create new"); sessionScope = new Sessionscope(); _sessionScopes.insert(sessionscopes_type::value_type(c.getValue(), sessionScope)); } else { log_debug("session found"); sessionScope = it->second; sessionScope->touch(); } request.setSessionScope(sessionScope); } if (request.isSsl()) { c = request.getCookie(currentSecureSessionCookieName); if (c.getValue().empty()) { log_debug("secure session cookie " << currentSecureSessionCookieName << " not found - keep session"); } else if (request.isSsl()) { log_debug("secure session cookie " << currentSecureSessionCookieName << " found: " << c.getValue()); cxxtools::MutexLock lock(_sessionScopesMutex); Sessionscope* sessionScope; sessionscopes_type::iterator it = _sessionScopes.find(c.getValue()); if (it == _sessionScopes.end()) { log_debug("session not found - create new"); sessionScope = new Sessionscope(); _sessionScopes.insert(sessionscopes_type::value_type(c.getValue(), sessionScope)); } else { log_debug("session found"); sessionScope = it->second; sessionScope->touch(); } request.setSecureSessionScope(sessionScope); } } else { log_debug("secure session cookie " << currentSessionCookieName << " not checked in non ssl request"); } // set application-scope request.setApplicationScope(getApplicationScope(app)); } void ScopeManager::setSessionId(HttpRequest& request, const std::string& sessionId) { if (sessionId.empty()) { request.setSessionScope(0); } else { Sessionscope* sessionScope = getSessionScope(sessionId); if (sessionScope != 0) { log_debug("session found"); request.setSessionScope(sessionScope); } } } std::string ScopeManager::postCall(HttpRequest& request, HttpReply& reply, const std::string& app) { std::string currentSessionCookieName = app.empty() ? std::string("tntnet") : "tntnet." + app; std::string currentSecureSessionCookieName = app.empty() ? std::string("stntnet") : "stntnet." + app; std::string sessionId; if (reply.isClearSession()) { sessionId = request.getCookie(currentSessionCookieName); if (!sessionId.empty()) removeSessionScope(sessionId); std::string secureSessionId = request.getCookie(currentSecureSessionCookieName); if (!secureSessionId.empty()) removeSessionScope(secureSessionId); } else { if (request.hasSessionScope()) { // request has session scope sessionId = request.getCookie(currentSessionCookieName); if (sessionId.empty()) { // client has no sessionId cxxtools::Md5stream c; c << request.getSerial() << '-' << ::pthread_self() << '-' << rand(); sessionId = c.getHexDigest(); log_info("create new session " << sessionId); reply.setCookie(currentSessionCookieName, sessionId); putSessionScope(sessionId, &request.getSessionScope()); } else if (!hasSessionScope(sessionId)) { // client has a sessionId but no associated session // this may happen, when tntnet is restarted while the browser has a session putSessionScope(sessionId, &request.getSessionScope()); } } if (request.isSsl() && request.hasSecureSessionScope()) { // request has secure session scope std::string sessionId = request.getCookie(currentSecureSessionCookieName); if (sessionId.empty()) { // client has no sessionId cxxtools::Md5stream c; c << request.getSerial() << '-' << ::pthread_self() << '-' << rand(); sessionId = c.getHexDigest(); log_info("create new secure session " << sessionId); tnt::Cookie cookie(sessionId); cookie.setSecure(); reply.setCookie(currentSecureSessionCookieName, cookie); putSessionScope(sessionId, &request.getSecureSessionScope()); } else if (!hasSessionScope(sessionId)) { // client has a sessionId but no associated session // this may happen, when tntnet is restarted while the browser has a session putSessionScope(sessionId, &request.getSecureSessionScope()); } } } return sessionId; } void ScopeManager::checkSessionTimeout() { time_t currentTime; time(¤tTime); cxxtools::MutexLock lock(_sessionScopesMutex); sessionscopes_type::iterator it = _sessionScopes.begin(); unsigned count = 0; while (it != _sessionScopes.end()) { Sessionscope* s = it->second; if (cxxtools::Seconds(currentTime - s->getAtime()) > s->getTimeout()) { log_info("sessiontimeout for session " << it->first << " reached"); sessionscopes_type::iterator it2 = it; ++it; if (s->release() == 0) delete s; _sessionScopes.erase(it2); ++count; } else ++it; } } } tntnet-3.0/framework/common/stringlessignorecase.cpp000066400000000000000000000036221365471676700231470ustar00rootroot00000000000000/* * Copyright (C) 2009 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/stringlessignorecase.h" namespace tnt { template <> int StringCompareIgnoreCase(const char* const& s1, const char* const& s2) { const char* it1 = s1; const char* it2 = s2; while (*it1 && *it2) { if (*it1 != *it2) { char c1 = std::toupper(*it1); char c2 = std::toupper(*it2); if (c1 < c2) return -1; else if (c2 < c1) return 1; } ++it1; ++it2; } return *it1 ? 1 : *it2 ? -1 : 0; } } tntnet-3.0/framework/common/tcpjob.cpp000066400000000000000000000107101365471676700201670ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/tcpjob.h" #include "tntnetimpl.h" #include #include #include #include #include log_define("tntnet.tcpjob") namespace tnt { //////////////////////////////////////////////////////////////////////// // Tcpjob // std::string Tcpjob::getPeerIp() const { return _socket.getPeerAddr(); } std::string Tcpjob::getServerIp() const { return _socket.getSockAddr(); } bool Tcpjob::isSsl() const { return !_certificateFile.empty(); } cxxtools::SslCertificate Tcpjob::getSslCertificate() const { return _socket.getSslPeerCertificate(); } void Tcpjob::accept() { _socket.accept(_listener); log_debug("connection accepted from " << getPeerIp()); } void Tcpjob::regenerateJob() { Jobqueue::JobPtr p; if (TntnetImpl::shouldStop()) p = this; else p = new Tcpjob(getRequest().getApplication(), _listener, _queue, _certificateFile, _privateKeyFile, _sslVerifyLevel, _sslCa); _queue.put(p); } std::iostream& Tcpjob::getStream() { if (!_socket.isConnected()) { try { log_debug("accept socket"); accept(); touch(); } catch (const std::exception& e) { regenerateJob(); log_debug("exception occured in accept: " << e.what()); throw; } regenerateJob(); } if (!_socket.isSslConnected() && !_certificateFile.empty()) { if (!_sslInitialized) { _socket.socket().loadSslCertificateFile(_certificateFile, _privateKeyFile); _socket.socket().setSslVerify(_sslVerifyLevel, _sslCa); _sslInitialized = true; } log_debug("accept ssl " << getFd()); _socket.sslAccept(); touch(); } return _socket; } int Tcpjob::getFd() const { return _socket.getFd(); } void Tcpjob::setRead() { _socket.setTimeout(TntConfig::it().socketReadTimeout); } void Tcpjob::setWrite() { _socket.setTimeout(TntConfig::it().socketWriteTimeout); } ////////////////////////////////////////////////////////////////////// // Jobqueue // void Jobqueue::put(JobPtr& j, bool force) { j->touch(); cxxtools::MutexLock lock(_mutex); if (!force && _capacity > 0) { while (_jobs.size() >= _capacity) { log_warn("Jobqueue full"); _notFull.wait(lock); } } _jobs.push_back(j); // We have to drop ownership before releasing the lock of the queue. // Therefore we set the smart pointer to 0. j = 0; if (_waitThreads == 0) noWaitThreads.signal(); _notEmpty.signal(); } Jobqueue::JobPtr Jobqueue::get() { cxxtools::MutexLock lock(_mutex); // wait, until a job is available ++_waitThreads; while (_jobs.empty()) _notEmpty.wait(lock); --_waitThreads; // take next job (queue is locked) JobPtr j = _jobs.front(); _jobs.pop_front(); // if there are threads waiting, wake another if (!_jobs.empty() && _waitThreads > 0) _notEmpty.signal(); _notFull.signal(); return j; } } tntnet-3.0/framework/common/tnt/000077500000000000000000000000001365471676700170105ustar00rootroot00000000000000tntnet-3.0/framework/common/tnt/applicationunlocker.h000066400000000000000000000047111365471676700232320ustar00rootroot00000000000000/* * Copyright (C) 2009 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_APPLICATIONUNLOCKER_H #define TNT_APPLICATIONUNLOCKER_H #include namespace tnt { /** Unlocks the application (and session) as long as the object is in scope. Normally the application is locked as soon as a request uses an application-scope variable somewhere. Sometimes it is desirable to explicitly release that lock, e.g. when a request will take some time. */ class ApplicationUnlocker { HttpRequest& _request; bool _locked; public: explicit ApplicationUnlocker(HttpRequest& request, bool release = true) : _request(request), _locked(request._applicationScopeLocked) { if (_locked && release) _request.releaseApplicationScopeLock(); } ~ApplicationUnlocker() { if (_locked) _request.ensureApplicationScopeLock(); } void unlock() { _request.releaseApplicationScopeLock(); _locked = false; } void lock() { _request.ensureApplicationScopeLock(); _locked = true; } }; } #endif // TNT_APPLICATIONUNLOCKER_H tntnet-3.0/framework/common/tnt/chunkedostream.h000066400000000000000000000054741365471676700222070ustar00rootroot00000000000000/* * Copyright (C) 2014 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_CHUNKEDOSTREAM_H #define TNT_CHUNKEDOSTREAM_H #include namespace tnt { class ChunkedWriter : public std::streambuf { std::streambuf* _obuf; char* _buffer; unsigned _bufsize; unsigned _bytesWritten; public: explicit ChunkedWriter(std::streambuf* obuf, unsigned bufsize = 8192) : _obuf(obuf), _buffer(0), _bufsize(bufsize) { } ~ChunkedWriter() { delete _buffer; } virtual int sync(); virtual int_type overflow(int_type ch); virtual int_type underflow(); void finish(); void setSink(std::streambuf* obuf) { _obuf = obuf; _bytesWritten = 0; } unsigned bytesWritten() const { return _bytesWritten; } }; class ChunkedOStream : public std::ostream { ChunkedWriter _streambuf; public: explicit ChunkedOStream(std::ostream& sink) : std::ostream(0), _streambuf(sink.rdbuf()) { std::ostream::init(&_streambuf); } explicit ChunkedOStream(std::streambuf* obuf) : std::ostream(0), _streambuf(obuf) { std::ostream::init(&_streambuf); } void finish() { _streambuf.finish(); } void setSink(std::ostream& sink) { _streambuf.setSink(sink.rdbuf()); } void setSink(std::streambuf* sink) { _streambuf.setSink(sink); } unsigned bytesWritten() const { return _streambuf.bytesWritten(); } }; } #endif // TNT_CHUNKEDOSTREAM_H tntnet-3.0/framework/common/tnt/cmd.h000066400000000000000000000044411365471676700177270ustar00rootroot00000000000000/* * Copyright (C) 2010 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_CMD_H #define TNT_CMD_H #include #include #include #include #include #include #include #include namespace tnt { class Cmd { Tntnet _application; ScopeManager _scopeManager; HttpRequest _request; HttpReply _reply; Comploader _comploader; std::string _sessionId; // thread context methods class MyThreadContext : public ThreadContext { Scope _threadScope; public: void touch() { } Scope& getScope() { return _threadScope; } } threadContext; public: explicit Cmd(std::ostream& out); Tntnet& getApplication() { return _application; } HttpRequest& request() { return _request; } void call(const Compident& ci, const QueryParams& q); void call(const Compident& ci); }; } #endif // TNT_CMD_H tntnet-3.0/framework/common/tnt/compident.h000066400000000000000000000057661365471676700211610ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_COMPIDENT_H #define TNT_COMPIDENT_H #include #include namespace tnt { /** This class is an identifier for a tntnet component It encapsulates the name of a component plus optionally the library it is in. */ struct Compident { mutable std::string compident; public: std::string libname; std::string compname; bool operator< (const Compident& ci) const { return libname < ci.libname || (libname == ci.libname && compname < ci.compname); } /// Create an empty Compident object Compident() { } /// Create a Compident object with the given library and component name Compident(const std::string& lib, const std::string& comp) : libname(lib), compname(comp) { } /** Create a Compident from an identification string The string has to be either only the component name or the library name + the character '@' + the component name. */ explicit Compident(const std::string& ident); /// Get component identifier as a string const std::string& toString() const { return libname.empty() ? compname : (compident.empty() ? (compident = compname + '@' + libname) : compident); } /// Check whether the Compident is empty bool empty() const { return libname.empty() && compname.empty(); } /// Erase the content of the library and component strings void clear() { libname.clear(); compname.clear(); } }; inline std::ostream& operator<< (std::ostream& out, const Compident& comp) { return out << comp.toString(); } } #endif // TNT_COMPIDENT_H tntnet-3.0/framework/common/tnt/comploader.h000066400000000000000000000104751365471676700213150ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_COMPLOADER_H #define TNT_COMPLOADER_H #include #include #include #include #include #include #include /// @cond internal namespace tnt { class Comploader; class ComponentFactory; class LibraryNotFound : public std::exception { std::string _libname; std::string _msg; public: explicit LibraryNotFound(const std::string& libname) : _libname(libname), _msg("Library not found: " + libname) { } ~LibraryNotFound() throw() { } const char* what() const throw() { return _msg.c_str(); } const std::string& getLibname() const { return _libname; } }; template class Dlcloser { protected: void destroy(objectType* ptr) { ::dlclose(*ptr); delete ptr; } }; class ComponentLibrary { friend class Comploader; typedef void* HandleType; typedef cxxtools::SmartPtr HandlePointer; typedef std::map factoryMapType; HandlePointer _handlePtr; factoryMapType _factoryMap; std::string _libname; std::string _path; void* dlopen(const std::string& name, bool local); void init(const std::string& name, bool local); public: ComponentLibrary() { } ComponentLibrary(const std::string& path, const std::string& name, bool local) : _libname(name), _path(path) { init(path + '/' + name, local); } ComponentLibrary(const std::string& name, bool local) : _libname(name) { init(name, local); } operator const void* () const { return _handlePtr.getPointer(); } Component* create(const std::string& compname, Comploader& cl, const Urlmapper& rootmapper); const std::string& getName() const { return _libname; } void registerFactory(const std::string& compname, ComponentFactory* factory) { _factoryMap.insert(factoryMapType::value_type(compname, factory)); } }; class Comploader { typedef std::map librarymap_type; typedef std::map componentmap_type; // loaded libraries static librarymap_type& getLibrarymap(); // map soname/compname to compinstance componentmap_type componentmap; static ComponentLibrary::factoryMapType* currentFactoryMap; public: Component& fetchComp(const Compident& compident, const Urlmapper& rootmapper = Urlmapper()); Component* createComp(const Compident& compident, const Urlmapper& rootmapper); const char* getLangData(const Compident& compident, const std::string& lang); // lookup library; load if needed ComponentLibrary& fetchLib(const std::string& libname); static void registerFactory(const std::string& compname, ComponentFactory* factory); }; } #endif // TNT_COMPLOADER_H tntnet-3.0/framework/common/tnt/component.h000066400000000000000000000171761365471676700211770ustar00rootroot00000000000000/* * Copyright (C) 2003-2006 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_COMPONENT_H #define TNT_COMPONENT_H #include #include namespace tnt { class HttpRequest; class HttpReply; class QueryParams; struct TntConfig; class Component { public: virtual ~Component() { } virtual void configure(const tnt::TntConfig&); virtual unsigned topCall(HttpRequest&, HttpReply&, tnt::QueryParams&); virtual unsigned operator() (HttpRequest&, HttpReply&, tnt::QueryParams&); virtual unsigned endTag (HttpRequest&, HttpReply&, tnt::QueryParams&); /** Get the value of the given attribute, or `def` if the attribute is unset Attributes are set using the ECPP tag `<%attr>`. */ virtual std::string getAttribute(const std::string& name, const std::string& def = std::string()) const; /// Component call - sometimes more readable than operator() unsigned call(HttpRequest& request, HttpReply& reply, tnt::QueryParams& qparam) { return operator() (request, reply, qparam); } /// Call component without parameters unsigned call(HttpRequest&, HttpReply&); /// Get output as a string rather than outputting to stream std::string scall(HttpRequest&, tnt::QueryParams&); /// Get output as a string rather than outputting to stream without query-parameters std::string scall(HttpRequest&); }; #define TNT_VAR(scope, type, varname, key, construct) \ type* varname##_pointer; \ { \ const std::string varname##_scopekey = key; \ tnt::Scope& _scope = scope; \ varname##_pointer = _scope.get< type >(varname##_scopekey); \ if ( ! varname##_pointer ) \ _scope.put< type >(varname##_scopekey, \ varname##_pointer = new type construct); \ } \ type& varname = *varname##_pointer; #define TNT_SESSION_COMPONENT_VAR(type, varname, construct) \ TNT_VAR(request.getSessionScope(), type, varname, getCompident().toString() + "%" #type "%" #varname, construct) #define TNT_SESSION_PAGE_VAR(type, varname, construct) \ TNT_VAR(request.getSessionScope(), type, varname, getCompident().toString() + "%" #type "%" #varname, construct) #define TNT_SESSION_SHARED_VAR(type, varname, construct) \ TNT_VAR(request.getSessionScope(), type, varname, #type "%" #varname, construct) #define TNT_SESSION_GLOBAL_VAR(type, varname, construct) \ TNT_VAR(request.getSessionScope(), type, varname, #type "%" #varname, construct) #define TNT_SESSION_FILE_VAR(type, varname, file, construct) \ TNT_VAR(request.getSessionScope(), type, varname, #file "%" #type "%" #varname, construct) #define TNT_SECURE_SESSION_COMPONENT_VAR(type, varname, construct) \ TNT_VAR(request.getSecureSessionScope(), type, varname, getCompident().toString() + ":" #type "%" #varname, construct) #define TNT_SECURE_SESSION_PAGE_VAR(type, varname, construct) \ TNT_VAR(request.getSecureSessionScope(), type, varname, getCompident().toString() + ":" #type "%" #varname, construct) #define TNT_SECURE_SESSION_SHARED_VAR(type, varname, construct) \ TNT_VAR(request.getSecureSessionScope(), type, varname, #type "%" #varname, construct) #define TNT_SECURE_SESSION_GLOBAL_VAR(type, varname, construct) \ TNT_VAR(request.getSecureSessionScope(), type, varname, #type "%" #varname, construct) #define TNT_SECURE_SESSION_FILE_VAR(type, varname, file, construct) \ TNT_VAR(request.getSecureSessionScope(), type, varname, #file "%" #type "%" #varname, construct) #define TNT_APPLICATION_COMPONENT_VAR(type, varname, construct) \ TNT_VAR(request.getApplicationScope(), type, varname, getCompident().toString() + ":" #type "%" #varname, construct) #define TNT_APPLICATION_PAGE_VAR(type, varname, construct) \ TNT_VAR(request.getApplicationScope(), type, varname, getCompident().toString() + ":" #type "%" #varname, construct) #define TNT_APPLICATION_SHARED_VAR(type, varname, construct) \ TNT_VAR(request.getApplicationScope(), type, varname, #type "%" #varname, construct) #define TNT_APPLICATION_GLOBAL_VAR(type, varname, construct) \ TNT_VAR(request.getApplicationScope(), type, varname, #type "%" #varname, construct) #define TNT_APPLICATION_FILE_VAR(type, varname, file, construct) \ TNT_VAR(request.getApplicationScope(), type, varname, #file "%" #type "%" #varname, construct) #define TNT_THREAD_COMPONENT_VAR(type, varname, construct) \ TNT_VAR(request.getThreadScope(), type, varname, getCompident().toString() + ":" #type "%" #varname, construct) #define TNT_THREAD_PAGE_VAR(type, varname, construct) \ TNT_VAR(request.getThreadScope(), type, varname, getCompident().toString() + ":" #type "%" #varname, construct) #define TNT_THREAD_SHARED_VAR(type, varname, construct) \ TNT_VAR(request.getThreadScope(), type, varname, #type "%" #varname, construct) #define TNT_THREAD_GLOBAL_VAR(type, varname, construct) \ TNT_VAR(request.getThreadScope(), type, varname, #type "%" #varname, construct) #define TNT_THREAD_FILE_VAR(type, varname, file, construct) \ TNT_VAR(request.getThreadScope(), type, varname, #file "%" #type "%" #varname, construct) #define TNT_REQUEST_COMPONENT_VAR(type, varname, construct) \ TNT_VAR(request.getRequestScope(), type, varname, getCompident().toString() + ":" #type "%" #varname, construct) #define TNT_REQUEST_PAGE_VAR(type, varname, construct) \ TNT_VAR(request.getRequestScope(), type, varname, getCompident().toString() + ":" #type "%" #varname, construct) #define TNT_REQUEST_SHARED_VAR(type, varname, construct) \ TNT_VAR(request.getRequestScope(), type, varname, #type "%" #varname, construct) #define TNT_REQUEST_GLOBAL_VAR(type, varname, construct) \ TNT_VAR(request.getRequestScope(), type, varname, #type "%" #varname, construct) #define TNT_REQUEST_FILE_VAR(type, varname, file, construct) \ TNT_VAR(request.getRequestScope(), type, varname, #file "%" #type "%" #varname, construct) #define TNT_PARAM(type, varname, construct) \ TNT_VAR(qparam.getScope(), type, varname, #varname, construct) } #endif // TNT_COMPONENT_H tntnet-3.0/framework/common/tnt/componentfactory.h000066400000000000000000000047731365471676700225660ustar00rootroot00000000000000/* * Copyright (C) 2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_COMPONENTFACTORY_H #define TNT_COMPONENTFACTORY_H #include namespace tnt { extern const std::string factorySuffix; class Component; struct Compident; class Comploader; class Urlmapper; struct TntConfig; class ComponentFactory { // noncopyable ComponentFactory(const ComponentFactory&); ComponentFactory& operator= (const ComponentFactory&); Component* _component; protected: virtual Component* doCreate(const tnt::Compident& ci, const tnt::Urlmapper& um, tnt::Comploader& cl) = 0; public: ComponentFactory(const std::string& componentName); virtual ~ComponentFactory(); virtual Component* create(const tnt::Compident& ci, const tnt::Urlmapper& um, tnt::Comploader& cl); }; template class ComponentFactoryImpl : public ComponentFactory { public: explicit ComponentFactoryImpl(const std::string& componentName) : ComponentFactory(componentName) { } virtual Component* doCreate(const tnt::Compident&, const tnt::Urlmapper&, tnt::Comploader&) { return new ComponentType(); } }; } #endif // TNT_COMPONENTFACTORY_H tntnet-3.0/framework/common/tnt/configurator.h000066400000000000000000000234551365471676700216740ustar00rootroot00000000000000/* * Copyright (C) 2008 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_CONFIGURATOR_H #define TNT_CONFIGURATOR_H #include #include #include #include namespace tnt { /** Helper class for easier configuration of tntnet when used as library. Configuration of tntnet is spread througout the system and it is a tendious task to search the right place, where to set some setting. This Class helps here and offers methods for all settings in one place. The methods dispatch the setting to the right place, so the user needs to know only this class, when he wants to set some settings. This is yet deprecated since all configuration is done in tnt::TntConfig. */ class Configurator { Tntnet& _tntnet; public: explicit Configurator(tnt::Tntnet& tntnet) : _tntnet(tntnet) { } /// Returns the minimum number of worker threads. unsigned getMinThreads() const { return TntConfig::it().minThreads; } /// Sets the minimum number of worker threads. void setMinThreads(unsigned n) { TntConfig::it().minThreads = n; } /// Returns the maximum number of worker threads. unsigned getMaxThreads() const { return TntConfig::it().maxThreads; } /// Sets the maximum number of worker threads. void setMaxThreads(unsigned n) { TntConfig::it().maxThreads = n; } /// Returns the time in seconds after which cleanup like checking sessiontimeout is done. cxxtools::Seconds getTimerSleep() const { return TntConfig::it().timerSleep; } /// Sets the time in seconds after which cleanup like checking sessiontimeout is done. void setTimerSleep(cxxtools::Seconds sec) { TntConfig::it().timerSleep = sec; } /// Returns the time in seconds between thread starts. cxxtools::Milliseconds getThreadStartDelay() const { return TntConfig::it().threadStartDelay; } /// Sets the time in seconds between thread starts. void setThreadStartDelay(cxxtools::Milliseconds sec) { TntConfig::it().threadStartDelay = sec; } /// Returns the maximum number of jobs waiting for processing. unsigned getQueueSize() const { return TntConfig::it().queueSize; } /// Sets the maximum number of jobs waiting for processing. void setQueueSize(unsigned n) { TntConfig::it().queueSize = n; } /// Returns the maximum request time, after which tntnet is automatically restarted in daemon mode. cxxtools::Seconds getMaxRequestTime() const { return TntConfig::it().maxRequestTime; } /// Sets the maximum request time, after which tntnet is automatically restarted in daemon mode. void setMaxRequestTime(cxxtools::Seconds sec) { TntConfig::it().maxRequestTime = sec; } /// Returns true, when http compression is used. bool getEnableCompression() const { return TntConfig::it().enableCompression; } /// enables or disables http compression. void setEnableCompression(bool sw = true) { TntConfig::it().enableCompression = sw; } /// Returns the time of inactivity in seconds after which a session is destroyed cxxtools::Seconds getSessionTimeout() const { return TntConfig::it().sessionTimeout; } /// Sets the time of inactivity in seconds after which a session is destroyed void setSessionTimeout(cxxtools::Seconds sec) { TntConfig::it().sessionTimeout = sec; } /// Returns the listen backlog parameter (see also listen(2)). int getListenBacklog() const { return TntConfig::it().listenBacklog; } /// Sets the listen backlog parameter (see also listen(2)). void setListenBacklog(int n) { TntConfig::it().listenBacklog = n; } /// Returns the number of retries, when a listen retried, when failing. unsigned getListenRetry() const { return TntConfig::it().listenRetry; } /// Sets the number of retries, when a listen retried, when failing. void setListenRetry(int n) { TntConfig::it().listenRetry = n; } /// Returns the maximum number of cached urlmappings. /// The cache stores results of the regular expressions used for defining /// mappings. Since the number of different urls used is normally quite /// limited, the cache reduces significantly the number of executed /// regular expressions. unsigned getMaxUrlMapCache() const { return TntConfig::it().maxUrlMapCache; } /// Sets the maximum number of cached urlmappings. void setMaxUrlMapCache(int n) { TntConfig::it().maxUrlMapCache = n; } /// Returns the maximum size of a request. /// Requestdata are collected in memory and therefore requests, which /// exceed the size of available memory may lead to a denial of service. size_t getMaxRequestSize() const { return TntConfig::it().maxRequestSize; } /// Sets the maximum size of a request. void setMaxRequestSize(size_t s) { TntConfig::it().maxRequestSize = s; } /// Returns the read timeout in millisecods after which the request is passed to the poller. /// Tntnet tries to keep a connection on the same thread to reduce /// context switches by waiting a short period if additional data /// arrives. After that period the request is passed to the poller, /// which waits for activity on the socket. The default value is /// 10 ms. cxxtools::Milliseconds getSocketReadTimeout() const { return TntConfig::it().socketReadTimeout; } /// Sets the timeout in millisecods after which the request is passed to the poller. void setSocketReadTimeout(cxxtools::Milliseconds ms) { TntConfig::it().socketReadTimeout = ms; } /// Returns the write timeout in millisecods after which the request is timed out. /// The default value is 10000 ms. cxxtools::Milliseconds getSocketWriteTimeout() const { return TntConfig::it().socketWriteTimeout; } /// Sets the write timeout in millisecods after which the request is timed out. void setSocketWriteTimeout(cxxtools::Milliseconds ms) { TntConfig::it().socketWriteTimeout = ms; } /// Returns the maximum number of requests handled over a single connection. /// The default value is 1000. unsigned getKeepAliveMax() const { return TntConfig::it().keepAliveMax; } /// Sets the maximum number of requests handled over a single connection. void setKeepAliveMax(unsigned ms) { TntConfig::it().keepAliveMax = ms; } /// Returns the size of the socket buffer. /// This specifies the maximum number of bytes after which the data sent /// or received over a socket is passed to the operating system. /// The default value is 16384 bytes (16 kBytes). unsigned getSocketBufferSize() const { return TntConfig::it().socketBufferSize; } /// Sets the size of the socket buffer. void setSocketBufferSize(unsigned ms) { TntConfig::it().socketBufferSize = ms; } /// Returns the minimum size of a request body for compression. /// Small requests are not worth compressing, so tntnet has a limit, /// to save cpu. The default value is 1024 bytes. unsigned getMinCompressSize() const { return TntConfig::it().minCompressSize; } /// Sets the minimum size of a request body for compression. void setMinCompressSize(unsigned s) { TntConfig::it().minCompressSize = s; } /// Returns the keep alive timeout in milliseconds. /// This specifies, how long a connection is kept for keep alive. A keep /// alive request binds (little) resources, so it is good to free it /// after some time of inactivity. The default value if 15000 ms. cxxtools::Seconds getKeepAliveTimeout() const { return TntConfig::it().keepAliveTimeout; } /// Sets the keep alive timeout in milliseconds. void setKeepAliveTimeout(cxxtools::Seconds s) { TntConfig::it().keepAliveTimeout = s; } /// Returns the default content type. /// The default content type is "text/html; charset=iso-8859-1". const std::string& getDefaultContentType() const { return TntConfig::it().defaultContentType; } /// Sets the default content type. void setDefaultContentType(const std::string& s) { TntConfig::it().defaultContentType = s; } void setAccessLog(const std::string& accessLog) { TntConfig::it().accessLog = accessLog; } }; } #endif // TNT_CONFIGURATOR_H tntnet-3.0/framework/common/tnt/contentdisposition.h000066400000000000000000000043661365471676700231310ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_CONTENTDISPOSITION_H #define TNT_CONTENTDISPOSITION_H #include namespace tnt { /** Content-Disposition-Header. (Content-Disposition: form-data; name="mein-upload-feld"; filename="ttt.sh") */ class Contentdisposition : public MessageattributeParser { std::string _type; std::string _name; std::string _filename; virtual return_type onType(const std::string& type, const std::string& subtype); virtual return_type onParameter(const std::string& attribute, const std::string& value); public: const std::string& getType() const { return _type; } const std::string& getName() const { return _name; } const std::string& getFilename() const { return _filename; } }; inline std::istream& operator>> (std::istream& in, Contentdisposition& ct) { ct.parse(in); return in; } } #endif // TNT_CONTENTDISPOSITION_H tntnet-3.0/framework/common/tnt/contenttype.h000066400000000000000000000066171365471676700215470ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_CONTENTTYPE_H #define TNT_CONTENTTYPE_H #include #include namespace tnt { /// Content-type field like rfc2045 class Contenttype : public MessageattributeParser { public: typedef std::multimap parameter_type; typedef parameter_type::const_iterator parameter_iterator; private: virtual return_type onType(const std::string& type, const std::string& subtype); virtual return_type onParameter(const std::string& attribute, const std::string& value); std::string _type; std::string _subtype; parameter_type _parameter; std::string _boundary; public: /// Create an empty Contenttype object Contenttype() { } explicit Contenttype(const std::string& ct); /// Create a Contenttype object with the given type and subtype Contenttype(const std::string& type, const std::string& subtype) : _type(type), _subtype(subtype) { } const std::string& getType() const { return _type; } const std::string& getSubtype() const { return _subtype; } const std::string& getBoundary() const { return _boundary; } bool isMultipart() const { return _type == "multipart" && !_boundary.empty(); } parameter_iterator parameter_begin() const { return _parameter.begin(); } parameter_iterator parameter_end() const { return _parameter.end(); } parameter_iterator parameter_find(parameter_type::key_type key) const { return _parameter.find(key); } parameter_iterator parameter_upper_bound(parameter_type::key_type key) const { return _parameter.upper_bound(key); } bool operator== (const Contenttype& ct) const { return _type == ct._type && _subtype == ct._subtype && _parameter == ct._parameter && _boundary == ct._boundary; } }; inline std::istream& operator>> (std::istream& in, Contenttype& ct) { ct.parse(in); return in; } } #endif // TNT_CONTENTTYPE_H tntnet-3.0/framework/common/tnt/cookie.h000066400000000000000000000132341365471676700204350ustar00rootroot00000000000000/* * Copyright (C) 2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_COOKIE_H #define TNT_COOKIE_H #include #include #include #include namespace tnt { class Cookies; class CookieParser; class Cookie { friend std::ostream& operator<< (std::ostream& out, const Cookies& c); friend class CookieParser; friend class HttpReply; public: static const std::string maxAge; static const std::string comment; static const std::string domain; static const std::string path; static const std::string secure; static const std::string version; static const std::string expires; private: typedef std::map > attrs_type; std::string _value; attrs_type _attrs; bool _secureFlag; void write(std::ostream& out, const std::string& name) const; public: Cookie() : _secureFlag(false) { } Cookie(const std::string& v, unsigned maxAge = 0) : _value(v), _secureFlag(false) { if (maxAge) setMaxAge(maxAge); } Cookie(const char* v, unsigned maxAge = 0) : _value(v), _secureFlag(false) { if (maxAge) setMaxAge(maxAge); } const std::string& getValue() const { return _value; } std::string getAttr(const std::string& name) const { attrs_type::const_iterator it = _attrs.find(name); return it == _attrs.end() ? std::string() : it->second; } operator const std::string& () const { return _value; } Cookie& setAttr(const std::string& name, const std::string& value) { _attrs[name] = value; return *this; } bool hasAttr(const std::string& name) const { return _attrs.find(name) != _attrs.end(); } unsigned getMaxAge() const; std::string getComment() const { return getAttr(comment); } std::string getDomain() const { return getAttr(domain); } std::string getPath() const { return getAttr(path); } std::string getVersion() const { return getAttr(version); } std::string getExpires() const { return getAttr(expires); } bool isSecure() const { return _secureFlag; } Cookie& setMaxAge(unsigned seconds); Cookie& setComment(const std::string& value) { return setAttr(comment, value); } Cookie& setDomain(const std::string& value) { return setAttr(domain, value); } Cookie& setPath(const std::string& value) { return setAttr(path, value); } Cookie& setVersion(const std::string& value) { return setAttr(version, value); } Cookie& setExpires(const std::string& value) { return setAttr(expires, value); } Cookie& setSecure(bool f = true) { _secureFlag = f; return *this; } bool hasMaxAge() const { return hasAttr(maxAge); } bool hasComment() const { return hasAttr(comment); } bool hasDomain() const { return hasAttr(domain); } bool hasPath() const { return hasAttr(path); } bool hasVersion() const { return hasAttr(version); } bool hasExpires() const { return hasAttr(expires); } }; class Cookies { friend std::ostream& operator<< (std::ostream& out, const Cookies& c); friend class HttpReply; typedef std::map > cookies_type; cookies_type _data; static const Cookie _emptyCookie; public: void set(const std::string& header); void clear() { _data.clear(); } const Cookie& getCookie(const std::string& name) const { cookies_type::const_iterator it = _data.find(name); return it == _data.end() ? _emptyCookie : it->second; } void setCookie(const std::string& name, const Cookie& value) { _data[name] = value; } void clearCookie(const std::string& name); void clearCookie(const std::string& name, const Cookie& c); bool hasCookie(const std::string& name) const { return _data.find(name) != _data.end(); } bool hasCookies() const { return !_data.empty(); } }; std::ostream& operator<< (std::ostream& out, const Cookies& c); } #endif // TNT_COOKIE_H tntnet-3.0/framework/common/tnt/cstream.h000066400000000000000000000063241365471676700206240ustar00rootroot00000000000000/* * Copyright (C) 2014 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_CSTREAM #define TNT_CSTREAM #include #include /// @cond internal namespace tnt { class cstreambuf : public std::streambuf { typedef std::vector _chunks_type; unsigned _chunksize; _chunks_type _chunks; public: typedef _chunks_type::size_type size_type; explicit cstreambuf(unsigned chunksize = 32768) : _chunksize(chunksize) { } ~cstreambuf(); size_type chunkcount() const { return _chunks.size(); } size_type size() const { return _chunks.size() == 0 ? 0 : (_chunks.size() - 1) * _chunksize + pptr() - _chunks.back(); } size_type chunksize(size_type n) const { return _chunks.size() == 0 ? 0 : n + 1 < _chunks.size() ? _chunksize : n + 1 == _chunks.size() ? static_cast(pptr() - _chunks.back()) : 0; } const char* chunk(size_type n) const { return _chunks[n]; } void rollback(size_type n); void makeEmpty(); private: std::streambuf::int_type overflow(std::streambuf::int_type ch); std::streambuf::int_type underflow(); int sync(); }; class ocstream : public std::ostream { cstreambuf _streambuf; public: typedef cstreambuf::size_type size_type; explicit ocstream(unsigned chunksize = 32768) : std::ostream(0), _streambuf(chunksize) { init(&_streambuf); } size_type chunkcount() const { return _streambuf.chunkcount(); } const char* chunk(size_type n) const { return _streambuf.chunk(n); } size_type chunksize(size_type n) const { return _streambuf.chunksize(n); } size_type size() const { return _streambuf.size(); } void rollback(size_type n) { _streambuf.rollback(n); } void makeEmpty() { _streambuf.makeEmpty(); } std::string str() const; void output(std::ostream& out) const; }; } #endif // TNT_CSTREAM tntnet-3.0/framework/common/tnt/data.h000066400000000000000000000063621365471676700201010ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_DATA_H #define TNT_DATA_H #include /// @cond internal namespace tnt { class DataChunk { const char* _data; unsigned _len; public: DataChunk(const char* data, const char* end) : _data(data), _len(static_cast(end - data)) { } DataChunk(const char* data, unsigned len) : _data(data), _len(len) { } const char* getData() const { return _data; } unsigned getLength() const { return _len; } }; ////////////////////////////////////////////////////////////////////// // interpretes raw data as a data-structure with chunks // unsigned: number of chunks // count X unsigned: offsets // data // class DataChunks { const char* _dataObject; const unsigned* udata() const { const char* d = _dataObject; return reinterpret_cast(d); } public: DataChunks(const char* d = 0) : _dataObject(d) { } const char* data() const { return _dataObject; } void setData(const char* d) { _dataObject = d; } // number of chunks unsigned size() const { return (udata()[0] / sizeof(unsigned)) - 1; } // offset of n-th chunk from start unsigned offset(unsigned n) const { return udata()[n] - udata()[0]; } // size of nth chunk in bytes unsigned size(unsigned n) const { return udata()[n + 1] - udata()[n]; } // pointer to n-th chunk const char* ptr(unsigned n) const { const char* d = _dataObject; return d + udata()[n]; } DataChunk operator[] (unsigned n) const { return DataChunk(ptr(n), size(n)); } }; inline std::ostream& operator << (std::ostream& out, const DataChunk& c) { out.write(c.getData(), c.getLength()); return out; } } /// @endcond internal #endif // TNT_DATA_H tntnet-3.0/framework/common/tnt/deflatestream.h000066400000000000000000000064131365471676700220050ustar00rootroot00000000000000/* * Copyright (C) 2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_DEFLATESTREAM_H #define TNT_DEFLATESTREAM_H #include #include #include #include namespace tnt { class DeflateError : public std::runtime_error { int _zRet; public: DeflateError(int zRet, const std::string& msg) : std::runtime_error(msg), _zRet(zRet) { } int getRet() const { return _zRet; } }; class DeflateStreamBuf : public std::streambuf { z_stream _stream; std::vector _obuffer; std::streambuf* _sink; public: explicit DeflateStreamBuf(std::streambuf* sink_, int level, int windowBits, unsigned bufsize); ~DeflateStreamBuf(); /// see std::streambuf int_type overflow(int_type c); /// see std::streambuf int_type underflow(); /// see std::streambuf int sync(); /// end deflate-stream int end(); void reinitialize(); void setSink(std::streambuf* sink) { _sink = sink; } uLong getAdler() const { return _stream.adler; } }; class DeflateStream : public std::ostream { DeflateStreamBuf _streambuf; public: explicit DeflateStream(std::streambuf* sink, int level = Z_DEFAULT_COMPRESSION, int windowBits = 16 + MAX_WBITS) : std::ostream(0), _streambuf(sink, level, windowBits, 8192) { init(&_streambuf); } explicit DeflateStream(std::ostream& sink, int level = Z_DEFAULT_COMPRESSION, int windowBits = 16 + MAX_WBITS) : std::ostream(0), _streambuf(sink.rdbuf(), level, windowBits, 8192) { init(&_streambuf); } void end(); void reinitialize() { _streambuf.reinitialize(); } void setSink(std::streambuf* sink) { _streambuf.setSink(sink); } void setSink(std::ostream& sink) { _streambuf.setSink(sink.rdbuf()); } uLong getAdler() const { return _streambuf.getAdler(); } }; } #endif // TNT_DEFLATESTREAM_H tntnet-3.0/framework/common/tnt/dispatcher.h000066400000000000000000000076411365471676700213170ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_DISPATCHER_H #define TNT_DISPATCHER_H #include #include #include #include #include #include namespace tnt { class HttpRequest; /// @cond internal class Dispatcher : public Urlmapper // one per host { friend class PosType; typedef std::vector urlmap_type; urlmap_type _urlmap; // map url to soname/compname mutable cxxtools::ReadWriteMutex _mutex; class UrlMapCacheKey { std::string _vhost; std::string _url; std::string _method; bool _ssl; urlmap_type::size_type _pos; public: UrlMapCacheKey() { } UrlMapCacheKey(const HttpRequest& request, urlmap_type::size_type pos); bool operator< (const UrlMapCacheKey& other) const; const std::string& getHost() const { return _vhost; } const std::string& getUrl() const { return _url; } const std::string& getMethod() const { return _method; } bool getSsl() const { return _ssl; } urlmap_type::size_type getPos() const { return _pos; } }; struct UrlMapCacheValue { Maptarget ci; urlmap_type::size_type pos; UrlMapCacheValue() { } UrlMapCacheValue(const Maptarget& ci_, urlmap_type::size_type pos_) : ci(ci_), pos(pos_) { } }; typedef std::map urlMapCacheType; mutable cxxtools::ReadWriteMutex _urlMapCacheMutex; mutable urlMapCacheType _urlMapCache; Maptarget mapCompNext(const HttpRequest& request, urlmap_type::size_type& pos) const; public: virtual ~Dispatcher() { } Mapping& addUrlMapEntry(const std::string& vhost, const std::string& url, const std::string& method, int ssl, const Maptarget& ci); Mapping& addUrlMapEntry(const std::string& vhost, const std::string& url, const Maptarget& ci) { return addUrlMapEntry(vhost, url, std::string(), SSL_ALL, ci); } class PosType { const Dispatcher& _dis; cxxtools::ReadLock _lock; urlmap_type::size_type _pos; const HttpRequest& _request; bool _first; public: PosType(const Dispatcher& d, const HttpRequest& r) : _dis(d), _lock(d._mutex), _pos(0), _request(r), _first(true) { } Maptarget getNext(); }; }; /// @endcond internal } #endif // TNT_DISPATCHER_H tntnet-3.0/framework/common/tnt/ecpp.h000066400000000000000000000174741365471676700201250ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_ECPP_H #define TNT_ECPP_H #include #include #include #include #include #include #include #include namespace tnt { class Urlmapper; class Comploader; class EcppSubComponent; ////////////////////////////////////////////////////////////////////// // Subcompident // struct Subcompident : public tnt::Compident { std::string subname; Subcompident(const tnt::Compident& ci, const std::string& sub) : tnt::Compident(ci), subname(sub) { } Subcompident(const std::string& lib, const std::string& comp, const std::string& sub) : tnt::Compident(lib, comp), subname(sub) { } explicit Subcompident(const std::string& ident); std::string toString() const; }; ////////////////////////////////////////////////////////////////////// // EcppComponent // class EcppComponent : public Component { friend class EcppSubComponent; typedef std::map subcomps_type; typedef std::set compnotfound_type; Compident _myident; const Urlmapper& _rootmapper; Comploader& _loader; subcomps_type _subcomps; virtual subcomps_type& getSubcomps() { return _subcomps; } virtual const subcomps_type& getSubcomps() const { return _subcomps; } protected: virtual ~EcppComponent(); void registerSubComp(const std::string& name, EcppSubComponent* comp); Component& fetchComp(const std::string& url) const; Component& fetchComp(const Compident& ci) const; Component& fetchComp(const Subcompident& ci) const; Component* createComp(const Compident& ci) const; Component* createComp(const std::string& url) const { return createComp(Compident(url)); } /// helper-methods for calling components template unsigned callComp(const compident_type& ci, HttpRequest& request, parameter1_type& p1, parameter2_type& p2) { return fetchComp(ci).call(request, p1, p2); } template unsigned callComp(const compident_type& ci, HttpRequest& request, parameter_type& p1) { return fetchComp(ci).call(request, p1); } template unsigned callComp(const compident_type& ci, HttpRequest& request) { return fetchComp(ci).call(request); } /// helper-methods for fetching contents of components template std::string scallComp(const compident_type& ci, HttpRequest& request, parameter1_type& p1) { return fetchComp(ci).scall(request, p1); } template std::string scallComp(const compident_type& ci, HttpRequest& request) { return fetchComp(ci).scall(request); } public: EcppComponent(const Compident& ci, const Urlmapper& um, Comploader& cl); const Compident& getCompident() const { return _myident; } EcppSubComponent& fetchSubComp(const std::string& sub) const; /// helper-methods for calling subcomponents template unsigned callSubComp(const std::string& sub, HttpRequest& request, parameter1_type& p1, parameter2_type& p2) const; template unsigned callSubComp(const std::string& sub, HttpRequest& request, parameter1_type& p1) const; /// helper-methods for fetching contents of subcomponents template std::string scallSubComp(const std::string& sub, HttpRequest& request, parameter1_type& p1) const; }; ////////////////////////////////////////////////////////////////////// // EcppSubComponent // class EcppSubComponent : public EcppComponent { EcppComponent& _main; std::string _subcompname; virtual subcomps_type& getSubcomps() { return _main.getSubcomps(); } virtual const subcomps_type& getSubcomps() const { return _main.getSubcomps(); } public: EcppSubComponent(EcppComponent& p, const std::string& name) : EcppComponent(p._myident, p._rootmapper, p._loader), _main(p), _subcompname(name) { p.registerSubComp(name, this); } virtual void drop(); Subcompident getCompident() const { return Subcompident(_main.getCompident(), _subcompname); } EcppComponent& getMainComponent() const { return _main; } }; ////////////////////////////////////////////////////////////////////// // inline methods // inline Component& EcppComponent::fetchComp(const Subcompident& ci) const { return dynamic_cast( fetchComp( static_cast(ci) ) ) .fetchSubComp(ci.subname); } template unsigned EcppComponent::callSubComp( const std::string& sub, HttpRequest& request, parameter1_type& p1, parameter2_type& p2) const { return fetchSubComp(sub).call(request, p1, p2); } template unsigned EcppComponent::callSubComp( const std::string& sub, HttpRequest& request, parameter1_type& p1) const { return fetchSubComp(sub).call(request, p1); } /// helper-methods for fetching contents of subcomponents template std::string EcppComponent::scallSubComp( const std::string& sub, HttpRequest& request, parameter1_type& p1) const { return fetchSubComp(sub).scall(request, p1); } template class EcppComponentFactoryImpl : public ComponentFactory { public: explicit EcppComponentFactoryImpl(const std::string& componentName) : ComponentFactory(componentName) { } virtual Component* doCreate(const tnt::Compident& ci, const tnt::Urlmapper& um, tnt::Comploader& cl) { return new ComponentType(ci, um, cl); } }; } #endif // TNT_ECPP_H tntnet-3.0/framework/common/tnt/encoding.h000066400000000000000000000035711365471676700207550ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_ENCODING_H #define TNT_ENCODING_H #include #include namespace tnt { class Encoding { typedef std::map encodingMapType; encodingMapType _encodingMap; public: Encoding() { } explicit Encoding(const char* header) { parse(header); } void parse(const char* header); void clear() { _encodingMap.clear(); } /// Get the quality value in the range 0..10 unsigned accept(const std::string& encoding) const; }; } #endif // TNT_ENCODING_H tntnet-3.0/framework/common/tnt/htmlescostream.h000066400000000000000000000045441365471676700222220ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_HTMLESCOSTREAM_H #define TNT_HTMLESCOSTREAM_H #include namespace tnt { class HtmlEscStreamBuf : public std::streambuf { std::streambuf* _sink; std::streambuf::int_type overflow(std::streambuf::int_type ch); std::streambuf::int_type underflow(); int sync(); public: HtmlEscStreamBuf(std::streambuf* sink) : _sink(sink) { } void setSink(std::streambuf* sink) { _sink = sink; } }; class HtmlEscOstream : public std::ostream { HtmlEscStreamBuf _streambuf; public: HtmlEscOstream(std::ostream& sink) : std::ostream(0), _streambuf(sink.rdbuf()) { init(&_streambuf); } HtmlEscOstream(std::streambuf* sink) : std::ostream(0), _streambuf(sink) { init(&_streambuf); } void setSink(std::ostream& sink) { _streambuf.setSink(sink.rdbuf()); } void setSink(std::streambuf* sink) { _streambuf.setSink(sink); } }; } #endif // TNT_HTMLESCOSTREAM_H tntnet-3.0/framework/common/tnt/http.h000066400000000000000000000076151365471676700201510ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_HTTP_H #define TNT_HTTP_H static const unsigned DECLINED = 0; static const unsigned DEFAULT = 1; static const unsigned HTTP_CONTINUE = 100; static const unsigned HTTP_SWITCHING_PROTOCOLS = 101; static const unsigned HTTP_PROCESSING = 102; static const unsigned HTTP_OK = 200; static const unsigned HTTP_CREATED = 201; static const unsigned HTTP_ACCEPTED = 202; static const unsigned HTTP_NON_AUTHORITATIVE = 203; static const unsigned HTTP_NO_CONTENT = 204; static const unsigned HTTP_RESET_CONTENT = 205; static const unsigned HTTP_PARTIAL_CONTENT = 206; static const unsigned HTTP_MULTI_STATUS = 207; static const unsigned HTTP_MULTIPLE_CHOICES = 300; static const unsigned HTTP_MOVED_PERMANENTLY = 301; static const unsigned HTTP_MOVED_TEMPORARILY = 302; // obsolete static const unsigned HTTP_FOUND = 302; static const unsigned HTTP_SEE_OTHER = 303; static const unsigned HTTP_NOT_MODIFIED = 304; static const unsigned HTTP_USE_PROXY = 305; static const unsigned HTTP_TEMPORARY_REDIRECT = 307; static const unsigned HTTP_BAD_REQUEST = 400; static const unsigned HTTP_UNAUTHORIZED = 401; static const unsigned HTTP_PAYMENT_REQUIRED = 402; static const unsigned HTTP_FORBIDDEN = 403; static const unsigned HTTP_NOT_FOUND = 404; static const unsigned HTTP_METHOD_NOT_ALLOWED = 405; static const unsigned HTTP_NOT_ACCEPTABLE = 406; static const unsigned HTTP_PROXY_AUTHENTICATION_REQUIRED = 407; static const unsigned HTTP_REQUEST_TIME_OUT = 408; static const unsigned HTTP_CONFLICT = 409; static const unsigned HTTP_GONE = 410; static const unsigned HTTP_LENGTH_REQUIRED = 411; static const unsigned HTTP_PRECONDITION_FAILED = 412; static const unsigned HTTP_REQUEST_ENTITY_TOO_LARGE = 413; static const unsigned HTTP_REQUEST_URI_TOO_LARGE = 414; static const unsigned HTTP_UNSUPPORTED_MEDIA_TYPE = 415; static const unsigned HTTP_RANGE_NOT_SATISFIABLE = 416; static const unsigned HTTP_EXPECTATION_FAILED = 417; static const unsigned HTTP_UNPROCESSABLE_ENTITY = 422; static const unsigned HTTP_LOCKED = 423; static const unsigned HTTP_FAILED_DEPENDENCY = 424; static const unsigned HTTP_UPGRADE_REQUIRED = 426; static const unsigned HTTP_INTERNAL_SERVER_ERROR = 500; static const unsigned HTTP_NOT_IMPLEMENTED = 501; static const unsigned HTTP_BAD_GATEWAY = 502; static const unsigned HTTP_SERVICE_UNAVAILABLE = 503; static const unsigned HTTP_GATEWAY_TIME_OUT = 504; static const unsigned HTTP_VERSION_NOT_SUPPORTED = 505; static const unsigned HTTP_VARIANT_ALSO_VARIES = 506; static const unsigned HTTP_INSUFFICIENT_STORAGE = 507; static const unsigned HTTP_NOT_EXTENDED = 510; #endif // TNT_HTTP_H tntnet-3.0/framework/common/tnt/httperror.h000066400000000000000000000064361365471676700212230ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_HTTPERROR_H #define TNT_HTTPERROR_H #include #include #include namespace tnt { class HttpReturn { unsigned _returncode; const char* _msg; public: explicit HttpReturn(unsigned errcode); HttpReturn(unsigned errcode, const char* msg); unsigned getReturnCode() const { return _returncode; } const char* getMessage() const { return _msg; } static const char* httpMessage(unsigned httpstatus); }; /// HTTP-error-class class HttpError : public std::exception, public HttpMessage { std::string _msg; std::string _body; public: explicit HttpError(unsigned errcode); HttpError(unsigned errcode, const std::string& msg); HttpError(unsigned errcode, const std::string& msg, const std::string& b); ~HttpError() throw() { } const char* what() const throw () { return _msg.c_str(); } std::string getErrcodeStr() const { return _msg.substr(0, 3); } unsigned getErrcode() const { return (_msg[0] - '0') * 100 + (_msg[1] - '0') * 10 + (_msg[2] - '0'); } std::string getErrmsg() const; /// returns the body of the message. const std::string& getBody() const { return _body; } }; /// HTTP-error 404 class NotFoundException : public HttpError { std::string _url; std::string _vhost; public: explicit NotFoundException(const std::string& url, const std::string& vhost = std::string()); ~NotFoundException() throw() { } const std::string& getUrl() const { return _url; } const std::string& getVHost() const { return _vhost; } }; class NotAuthorized : public HttpError { public: explicit NotAuthorized(const std::string& realm); }; class MovedTemporarily : public HttpError { public: explicit MovedTemporarily(const std::string& url); }; } #endif // TNT_HTTPERROR_H tntnet-3.0/framework/common/tnt/httpheader.h000066400000000000000000000052441365471676700213160ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_HTTPHEADER_H #define TNT_HTTPHEADER_H #include namespace tnt { namespace httpheader { extern const char* contentType; extern const char* contentLength; extern const char* connection; extern const char* connectionClose; extern const char* connectionKeepAlive; extern const char* lastModified; extern const char* server; extern const char* location; extern const char* accept; extern const char* acceptLanguage; extern const char* acceptEncoding; extern const char* acceptCharset; extern const char* acceptRanges; extern const char* contentEncoding; extern const char* date; extern const char* keepAlive; extern const char* ifModifiedSince; extern const char* host; extern const char* cacheControl; extern const char* contentMD5; extern const char* setCookie; extern const char* cookie; extern const char* pragma; extern const char* expires; extern const char* userAgent; extern const char* wwwAuthenticate; extern const char* authorization; extern const char* referer; extern const char* range; extern const char* contentRange; extern const char* contentLocation; extern const char* contentDisposition; extern const char* age; extern const char* transferEncoding; } } #endif // TNT_HTTPHEADER_H tntnet-3.0/framework/common/tnt/httpmessage.h000066400000000000000000000112171365471676700215070ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_HTTPMESSAGE_H #define TNT_HTTPMESSAGE_H #include #include #include #include namespace tnt { /// Base class for HTTP messages class HttpMessage { public: typedef Messageheader header_type; private: unsigned short _majorVersion; unsigned short _minorVersion; protected: header_type header; Cookies httpcookies; public: HttpMessage() : _majorVersion(1), _minorVersion(0) { } virtual ~HttpMessage() { } /// Remove all request-specific content virtual void clear(); /// @{ /// Check whether the message has the specified header bool hasHeader(const char* key) const { return header.hasHeader(key); } bool hasHeader(const std::string& key) const { return header.hasHeader(key); } /// @} /// Get the content of the specified header if it is set, /// the passed default otherwise const char* getHeader(const char* key, const char* def = "") const; /// Get the major http version number unsigned short getMajorVersion() const { return _majorVersion; } /// Get the minor http version number unsigned short getMinorVersion() const { return _minorVersion; } /// Set the http version number void setVersion(unsigned short majorVersion, unsigned short minorVersion) { _majorVersion = majorVersion; _minorVersion = minorVersion; } /** Get a constant iterator which points to the first header The value type of the iterator is std::pair */ header_type::const_iterator header_begin() const { return header.begin(); } /// Get a constant iterator which points past the last header header_type::const_iterator header_end() const { return header.end(); } /// Add the specified header to the message void setHeader(const std::string& key, const std::string& value, bool replace = true) { header.setHeader(key, value, replace); } /// Remove the specified header from the message void removeHeader(const std::string& key) { header.removeHeader(key); } /// Get all headers in one string std::string dumpHeader() const; /// Print all headers to the specified output stream void dumpHeader(std::ostream& out) const; /// @{ /// Get a date string, formatted as needed in http static std::string htdate(time_t t); static std::string htdate(const struct ::tm* tm); // date buffer must be at least 30 bytes long static void htdate(char* date, time_t t); static void htdate(char* date, const struct ::tm* tm); /// @} /// Get a string for the current time, formatted as needed in http static std::string htdateCurrent(); /// Get a string for the current time, formatted as needed in http /// buffer must point to at least 30 bytes static void htdateCurrent(char* current); // TODO: Documentation revision: Is this meant to check for absolute URLs? /** Check for double-dot-url @return false if the url used as a filename would escape from the basedir */ static bool checkUrl(const std::string& url); }; } #endif // TNT_HTTPMESSAGE_H tntnet-3.0/framework/common/tnt/httpparser.h000066400000000000000000000062141365471676700213600ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_HTTPPARSER_H #define TNT_HTTPPARSER_H #include #include #include #include namespace tnt { class RequestSizeMonitor { size_t _requestSize; protected: virtual ~RequestSizeMonitor() { } void pre(char /* ch */) { } bool post(bool ret); virtual void requestSizeExceeded(); public: RequestSizeMonitor() : _requestSize(0) { } size_t getCurrentRequestSize() const { return _requestSize; } void reset() { _requestSize = 0; } }; class HttpRequest::Parser : public tnt::Parser { HttpRequest& _message; Messageheader::Parser _headerParser; unsigned _httpCode; size_t _bodySize; bool state_cmd0(char ch); bool state_cmd(char ch); bool state_url0(char ch); bool state_protocol(char ch); bool state_protocol_slash1(char ch); bool state_protocol_slash2(char ch); bool state_protocol_host(char ch); bool state_url(char ch); bool state_urlesc(char ch); bool state_qparam(char ch); bool state_version(char ch); bool state_version_major(char ch); bool state_version_major_sp(char ch); bool state_version_minor0(char ch); bool state_version_minor(char ch); bool state_end0(char ch); bool state_header(char ch); bool state_body(char ch); protected: virtual void requestSizeExceeded(); public: Parser(tnt::HttpRequest& message) : tnt::Parser(&Parser::state_cmd0), _message(message), _headerParser(message.header), _httpCode(HTTP_OK) { } void reset(); }; } #endif // TNT_HTTPPARSER_H tntnet-3.0/framework/common/tnt/httpreply.h000066400000000000000000000147231365471676700212230ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_HTTPREPLY_H #define TNT_HTTPREPLY_H #include #include #include namespace tnt { class Savepoint; class Encoding; /// HTTP reply message class HttpReply : public HttpMessage { private: struct Impl; Impl* _impl; std::ostream* _currentOutstream; std::ostream* _safeOutstream; std::ostream* _urlOutstream; void sendHttpStatus(std::ostream& hsocket, unsigned ret, const char* msg) const; void sendHttpHeaders(std::ostream& hsocket) const; void send(unsigned ret, const char* msg, bool ready) const; public: explicit HttpReply(std::ostream& s, bool sendStatusLine = true); ~HttpReply(); static bool tryCompress(std::string& body); static void postRunCleanup(); void setContentType(const char* t) { setHeader(httpheader::contentType, t); } void setContentType(const std::string& t) { setHeader(httpheader::contentType, t); } const char* getContentType() const { return getHeader(httpheader::contentType); } void setHeadRequest(bool sw = true); /// Configure the session to be cleared after the current request void clearSession(); /// Check if the session is configured to be cleared after the current request bool isClearSession() const; enum Redirect { permanently = HTTP_MOVED_PERMANENTLY, temporarily = HTTP_TEMPORARY_REDIRECT }; /// @{ /** Redirect the user to another URL This function never returns as it throws an exception to actually send the redirect header. */ unsigned redirect(const std::string& newLocation, Redirect type = temporarily); unsigned redirectTemporary(const std::string& newLocation) { return redirect(newLocation, temporarily); } unsigned redirectPermantently(const std::string& newLocation) { return redirect(newLocation, permanently); } /// @} /** Request authorization from the client This will result in a dialog being shown in the user's web browser. */ unsigned notAuthorized(const std::string& realm); bool sendReply(unsigned ret, const char* msg = "OK"); bool sendReply(unsigned ret, const std::string& msg) { return sendReply(ret, msg.c_str()); } /// Get output stream std::ostream& out() { return *_currentOutstream; } /// Get safe output stream (unsafe html characters written into this stream are escaped) std::ostream& sout() { return *_safeOutstream; } /// Get url output stream (everything written into this stream is url-encoded) std::ostream& uout() { return *_urlOutstream; } void resetContent(); void rollbackContent(unsigned size); void setContentLengthHeader(size_t size); void setKeepAliveHeader(); void setMaxAgeHeader(unsigned seconds); virtual void setDirectMode(unsigned ret = HTTP_OK, const char* msg = "OK"); virtual void setDirectModeNoFlush(); virtual bool isDirectMode() const; std::string::size_type getContentSize() const; unsigned chunkedBytesWritten() const; std::ostream& getDirectStream(); /** Enable chunked encoding for the current request When enabling chunked encoding, the content is sent immediately in chunks instead of collecting content into a string before sending. After enabling chunked encoding, it must be ensured that no exceptions are thrown. Also, headers are sent immediately after enabling chunked encoding and hence setting headers must happen before calling this method. Furthermore, session cookies cannot be sent with chunked encoding enabled, hence when a new session is created, chunked encoding must not be used. Sessions are created automatically when a session variable is used and no session cookie was received. */ void setChunkedEncoding(unsigned ret = HTTP_OK, const char* msg = 0); /// Check whether chunked encoding is enabled bool isChunkedEncoding() const; // TODO: Documentation revision /** Sets the content-md5 header. The current content is used to calculate the md5 header. Hence no output must be created after calling that method. Normally there is no good reason to call that method at all. */ void setMd5Sum(); void setCookie(const std::string& name, const Cookie& value); void setCookie(const std::string& name, const std::string& value, unsigned seconds) { setCookie(name, Cookie(value, seconds)); } void setCookies(const Cookies& c) { httpcookies = c; } void clearCookie(const std::string& name); void clearCookie(const std::string& name, const Cookie& c) { httpcookies.clearCookie(name, c); } bool hasCookies() const { return httpcookies.hasCookies(); } const Cookies& getCookies() const { return httpcookies; } void setKeepAliveCounter(unsigned c); unsigned getKeepAliveCounter() const; void setAcceptEncoding(const Encoding& enc); bool keepAlive() const; }; } #endif // TNT_HTTPREPLY_H tntnet-3.0/framework/common/tnt/httprequest.h000066400000000000000000000234671365471676700215650ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_HTTPREQUEST_H #define TNT_HTTPREQUEST_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace tnt { class Sessionscope; class Tntnet; /// HTTP request message class HttpRequest : public HttpMessage { friend class SessionUnlocker; friend class ApplicationUnlocker; public: // forward declaration of subclass defined in httpparser.h class Parser; typedef std::map args_type; private: std::string _body; unsigned _methodLen; char _method[8]; std::string _url; std::string _queryString; size_t _contentSize; std::string _pathinfo; args_type _args; tnt::QueryParams _getparam; tnt::QueryParams _postparam; tnt::QueryParams _qparam; const SocketIf* _socketIf; mutable Contenttype _ct; Multipart _mp; unsigned _serial; static std::atomic _nextSerial; mutable Encoding _encoding; mutable bool _encodingRead; mutable std::string _username; mutable std::string _password; Scope* _requestScope; Scope* _applicationScope; Sessionscope* _sessionScope; Sessionscope* _secureSessionScope; ThreadContext* _threadContext; bool _applicationScopeLocked; bool _sessionScopeLocked; bool _secureSessionScopeLocked; mutable std::string _peerAddrStr; mutable std::string _serverAddrStr; Tntnet& _application; void ensureApplicationScopeLock(); void ensureSessionScopeLock(); void releaseApplicationScopeLock(); void releaseSessionScopeLock(); void releaseLocks() { releaseApplicationScopeLock(); } const Contenttype& getContentTypePriv() const; public: explicit HttpRequest(Tntnet& application, const SocketIf* socketIf = 0); HttpRequest(Tntnet& application, const std::string& url, const SocketIf* socketIf = 0); HttpRequest(const HttpRequest& r); ~HttpRequest(); HttpRequest& operator= (const HttpRequest& r); void clear(); /// Get the body of the message const std::string& getBody() const { return _body; } /// Set the body of the message void setBody(const std::string& body) { _body = body; } /// @{ /// Get the http method of a request (usually GET or POST) std::string getMethod() const { return _method; } const char* getMethod_cstr() const { return _method; } /// @} /// Check whether http method used is GET bool isMethodGET() const { return std::strcmp(_method, "GET") == 0; } /// Check whether http method used is POST bool isMethodPOST() const { return std::strcmp(_method, "POST") == 0; } /// Check whether http method used is HEAD bool isMethodHEAD() const { return std::strcmp(_method, "HEAD") == 0; } /// Set the http method of this request void setMethod(const char* _method); /// Get url with GET parameters std::string getQuery() const { return _queryString.empty() ? _url : _url + '?' + _queryString; } /// Get the request url without GET parameters const std::string& getUrl() const { return _url; } /// Get the query string (GET parameters string) const std::string& getQueryString() const { return _queryString; } /// Set the query string void setQueryString(const std::string& queryString) { _queryString = queryString; } void setPathInfo(const std::string& p) { _pathinfo = p; } const std::string& getPathInfo() const { return _pathinfo; } void setArgs(const args_type& a, bool addToQparam = true); const args_type& getArgs() const { return _args; } args_type& getArgs() { return _args; } /// @{ /// @deprecated std::string getArgDef(args_type::size_type n, const std::string& def = std::string()) const; std::string getArg(args_type::size_type n) const { return getArgDef(n); } args_type::size_type getArgsCount() const { return _args.size(); } /// @} std::string getArg(const std::string& name, const std::string& def = std::string()) const; void parse(std::istream& in); void doPostParse(); /// @{ /// Get query parameters (GET and POST) tnt::QueryParams& getQueryParams() { return _qparam; } const tnt::QueryParams& getQueryParams() const { return _qparam; } /// @} /// Get GET parameters const tnt::QueryParams& getGetParams() const { return _getparam; } /// Get POST parameters const tnt::QueryParams& getPostParams() const { return _postparam; } /// Set query parameters (GET and POST) void setQueryParams(const tnt::QueryParams& q) { _qparam = q; } /// Get the IP the request was sent from std::string getPeerIp() const { return _socketIf ? _socketIf->getPeerIp() : std::string(); } cxxtools::SslCertificate getSslCertificate() const { cxxtools::SslCertificate ret; if (_socketIf) ret = _socketIf->getSslCertificate(); return ret; } /// Get the IP the request was sent to std::string getServerIp() const { return _socketIf ? _socketIf->getServerIp() : std::string(); } /// Check whether the request was sent over an SSL (https) connection bool isSsl() const { return _socketIf && _socketIf->isSsl(); } const Contenttype& getContentType() const { return _ct.getType().empty() && hasHeader(httpheader::contentType) ? getContentTypePriv() : _ct; } bool isMultipart() const { return getContentType().isMultipart(); } const Multipart& getMultipart() const { return _mp; } unsigned getSerial() const { return _serial; } const Cookies& getCookies() const; bool hasCookie(const std::string& name) const { return getCookies().hasCookie(name); } bool hasCookies() const { return getCookies().hasCookies(); } Cookie getCookie(const std::string& name) const { return getCookies().getCookie(name); } const Encoding& getEncoding() const; /// Get the user agent (webbrowser) HTTP header const char* getUserAgent() const { return getHeader(httpheader::userAgent); } /// Get the host (operating system) HTTP header const char* getHost() const { return getHeader(httpheader::host); } /// Get the HTTP-Auth username const std::string& getUsername() const; /// Get the HTTP-Auth password const std::string& getPassword() const; /// Check equality of the HTTP-Auth password and the parameter bool verifyPassword(const std::string& password) const; bool keepAlive() const; /// Check whether the client accepts gzip compression bool acceptGzipEncoding() const { return getEncoding().accept("gzip"); } void setApplicationScope(Scope* s); void setApplicationScope(Scope& s) { setApplicationScope(&s); } void setSessionScope(Sessionscope* s); void setSessionScope(Sessionscope& s) { setSessionScope(&s); } void setSecureSessionScope(Sessionscope* s); void setSecureSessionScope(Sessionscope& s) { setSecureSessionScope(&s); } void setThreadContext(ThreadContext* ctx) { _threadContext = ctx; } Scope& getRequestScope(); Scope& getApplicationScope(); Scope& getThreadScope(); Sessionscope& getSessionScope(); Sessionscope& getSecureSessionScope(); bool hasSessionScope() const; bool hasSecureSessionScope() const; /// Get the value of the content-size HTTP header size_t getContentSize() const { return _contentSize; } /// Get the virtual-host HTTP header std::string getVirtualHost() const { return getHeader(httpheader::host); } Tntnet& getApplication() { return _application; } /// Rewind watchdog timer void touch() { _threadContext->touch(); } static void postRunCleanup(); }; inline std::istream& operator>> (std::istream& in, HttpRequest& msg) { msg.parse(in); return in; } } #endif // TNT_HTTPREQUEST_H tntnet-3.0/framework/common/tnt/job.h000066400000000000000000000063051365471676700177370ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_JOB_H #define TNT_JOB_H #include #include #include #include #include #include #include /// @cond internal namespace tnt { class Tntnet; class Job : public cxxtools::RefCounted { unsigned _keepAliveCounter; HttpRequest _request; HttpRequest::Parser _parser; time_t _lastAccessTime; public: explicit Job(Tntnet& app, const SocketIf* socketIf = 0); virtual ~Job(); virtual std::iostream& getStream() = 0; virtual int getFd() const = 0; virtual void setRead() = 0; virtual void setWrite() = 0; HttpRequest& getRequest() { return _request; } HttpRequest::Parser& getParser() { return _parser; } unsigned decrementKeepAliveCounter() { return _keepAliveCounter > 0 ? --_keepAliveCounter : 0; } void clear(); void touch() { time(&_lastAccessTime); } cxxtools::Milliseconds msecToTimeout(time_t currentTime) const; }; class Jobqueue { public: typedef cxxtools::SmartPtr JobPtr; cxxtools::Condition noWaitThreads; private: std::deque _jobs; cxxtools::Mutex _mutex; cxxtools::Condition _notEmpty; cxxtools::Condition _notFull; unsigned _waitThreads; unsigned _capacity; public: explicit Jobqueue(unsigned capacity = 1000) : _waitThreads(0), _capacity(capacity) { } void put(JobPtr& j, bool force = false); JobPtr get(); void setCapacity(unsigned c) { _capacity = c; } unsigned getCapacity() const { return _capacity; } unsigned getWaitThreadCount() const { return _waitThreads; } bool empty() const { return _jobs.empty(); } }; } #endif // TNT_JOB_H tntnet-3.0/framework/common/tnt/listener.h000066400000000000000000000040301365471676700210030ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_LISTENER_H #define TNT_LISTENER_H #include #include "tnt/tcpjob.h" #include namespace tnt { class Listener { cxxtools::net::TcpServer _server; Jobqueue& _queue; std::string _certificateFile; std::string _privateKeyFile; int _sslVerifyLevel; std::string _sslCa; public: Listener(Tntnet& application, const std::string& ipaddr, unsigned short int port, Jobqueue& q, const std::string& certificateFile = std::string(), const std::string& privateKeyFile = std::string(), int sslVerifyLevel = 0, const std::string& sslCa = std::string()); void terminate(); }; } #endif // TNT_LISTENER_H tntnet-3.0/framework/common/tnt/mapping.h000066400000000000000000000071351365471676700206220ustar00rootroot00000000000000/* * Copyright (C) 2015 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_MAPPING_H #define TNT_MAPPING_H #include #include namespace tnt { class HttpRequest; class Mapping { std::string _vhost; std::string _url; std::string _method; int _ssl; cxxtools::Regex _regexVhost; cxxtools::Regex _regexUrl; cxxtools::Regex _regexMethod; Maptarget _target; public: typedef Maptarget::args_type args_type; Mapping() { } Mapping(const std::string& vhost, const std::string& url, const std::string& method, int ssl, const Maptarget& target); const std::string& getVHost() const { return _vhost; } const std::string& getUrl() const { return _url; } const std::string& getMethod() const { return _method; } int getSsl() const { return _ssl; } const Maptarget& getTarget() const { return _target; } Mapping& setPathInfo(const std::string& p) { _target.setPathInfo(p); return *this; } Mapping& setHttpReturn(unsigned httpreturn) { _target.setHttpReturn(httpreturn); return *this; } Mapping& setArgs(const args_type& a) { _target.setArgs(a); return *this; } Mapping& setArg(const std::string& name, const std::string& value) { _target.setArg(name, value); return *this; } /// Emulate old positional argument list. /// @deprecated Mapping& pushArg(const std::string& value); Mapping& setVHost(const std::string& vhost) { _vhost = vhost; _regexVhost = cxxtools::Regex(vhost); return *this; } Mapping& setUrl(const std::string& url) { _url = url; _regexUrl = cxxtools::Regex(url); return *this; } Mapping& setMethod(const std::string& method) { _method = method; _regexMethod = cxxtools::Regex(method); return *this; } Mapping& setSsl(bool sw) { _ssl = (sw ? SSL_YES : SSL_NO); return *this; } Mapping& unsetSsl() { _ssl = SSL_ALL; return *this; } bool match(const HttpRequest& request, cxxtools::RegexSMatch& smatch) const; }; } #endif // TNT_MAPPING_H tntnet-3.0/framework/common/tnt/maptarget.h000066400000000000000000000055121365471676700211500ustar00rootroot00000000000000/* * Copyright (C) 2007 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_MAPTARGET_H #define TNT_MAPTARGET_H #include #include #include #include namespace tnt { /// @cond internal class Maptarget : public Compident { friend class Dispatcher; public: typedef std::map args_type; private: std::string _pathinfo; args_type _args; bool _pathinfoSet; unsigned _httpreturn; public: Maptarget() : _pathinfoSet(false), _httpreturn(HTTP_OK) { } explicit Maptarget(const std::string& ident) : Compident(ident), _pathinfoSet(false), _httpreturn(HTTP_OK) { } Maptarget(const Compident& ident) : Compident(ident), _pathinfoSet(false), _httpreturn(HTTP_OK) { } bool hasPathInfo() const { return _pathinfoSet; } Maptarget& setPathInfo(const std::string& p) { _pathinfo = p; _pathinfoSet = true; return *this; } void setArgs(const args_type& a) { _args = a; } void setHttpReturn(unsigned ret) { _httpreturn = ret; } unsigned getHttpReturn() const { return _httpreturn; } const std::string& getPathInfo() const { return _pathinfo; } const args_type& getArgs() const { return _args; } Maptarget& setArg(const std::string& name, const std::string& value) { _args[name] = value; return *this; } }; /// @endcond internal } #endif // TNT_MAPTARGET_H tntnet-3.0/framework/common/tnt/mbcomponent.h000066400000000000000000000062721365471676700215110ustar00rootroot00000000000000/* * Copyright (C) 2010 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_MBCOMPONENT_H #define TNT_MBCOMPONENT_H #include #include #include namespace tnt { class MbComponent : public EcppComponent { const char* _rawData; const char** _urls; const char** _mimetypes; const char** _ctimes; std::vector _compressedData; cxxtools::ReadWriteMutex _mutex; protected: void init(const char* rawData, const char** urls, const char** mimetypes, const char** ctimes); void init(const char* rawData, const char* &mimetype, const char* &ctime) { init(rawData, 0, &mimetype, &ctime); } public: MbComponent(const Compident& ci, const Urlmapper& um, Comploader& cl) : EcppComponent(ci, um, cl), _rawData(0), _urls(0), _mimetypes(0), _ctimes(0) { } MbComponent(const Compident& ci, const Urlmapper& um, Comploader& cl, const char* rawData, const char** urls, const char** mimetypes, const char** ctimes) : EcppComponent(ci, um, cl), _rawData(0), _urls(0), _mimetypes(0), _ctimes(0) { init(rawData, urls, mimetypes, ctimes); } MbComponent(const Compident& ci, const Urlmapper& um, Comploader& cl, const char* rawData, const char* &mimetype, const char* &ctime) : EcppComponent(ci, um, cl), _rawData(0), _urls(0), _mimetypes(0), _ctimes(0) { init(rawData, mimetype, ctime); } unsigned operator() (HttpRequest& request, HttpReply& reply, tnt::QueryParams& qparam); unsigned topCall(tnt::HttpRequest& request, tnt::HttpReply& reply, tnt::QueryParams& qparam); private: unsigned doCall(tnt::HttpRequest& request, tnt::HttpReply& reply, tnt::QueryParams& qparam, bool top); }; } #endif // TNT_MBCOMPONENT_H tntnet-3.0/framework/common/tnt/messageattribute.h000066400000000000000000000040601365471676700225310ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_MESSAGEATTRIBUTE_H #define TNT_MESSAGEATTRIBUTE_H #include #include namespace tnt { /// Messageattribute like form-data; name="my-upload-field"; filename="ttt.sh" /// or application/x-shellscript /// see also rfc2045 class MessageattributeParser { public: enum return_type { OK, FAIL, END }; private: virtual return_type onType(const std::string& type, const std::string& subtype) = 0; virtual return_type onParameter(const std::string& attribute, const std::string& value) = 0; public: virtual ~MessageattributeParser() { } void parse(std::istream& in); }; } #endif // TNT_MESSAGEATTRIBUTE_H tntnet-3.0/framework/common/tnt/messageheader.h000066400000000000000000000114001365471676700217520ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_MESSAGEHEADER_H #define TNT_MESSAGEHEADER_H #include #include #include #include namespace tnt { /// Standard-message-header like rfc822 class Messageheader { public: static const unsigned MAXHEADERSIZE = 4096; private: char _rawdata[MAXHEADERSIZE]; // key_1\0value_1\0key_2\0value_2\0...key_n\0value_n\0\0 unsigned _endOffset; char* getEnd() { return _rawdata + _endOffset; } public: class Parser; typedef std::pair value_type; class const_iterator : public std::iterator { friend class Messageheader; value_type _currentVal; void fixup() { if (*_currentVal.first) _currentVal.second = _currentVal.first + std::strlen(_currentVal.first) + 1; else _currentVal.first = _currentVal.second = 0; } void moveForward() { _currentVal.first = _currentVal.second + std::strlen(_currentVal.second) + 1; fixup(); } public: const_iterator() : _currentVal(static_cast(0), static_cast(0)) { } explicit const_iterator(const char* p) : _currentVal(p, p) { fixup(); } bool operator== (const const_iterator& it) const { return _currentVal.first == it._currentVal.first; } bool operator!= (const const_iterator& it) const { return _currentVal.first != it._currentVal.first; } const_iterator& operator++() { moveForward(); return *this; } const_iterator operator++(int) { const_iterator ret = *this; moveForward(); return ret; } const value_type& operator* () const { return _currentVal; } const value_type* operator-> () const { return &_currentVal; } }; protected: enum return_type { OK, FAIL, END }; virtual return_type onField(const char* name, const char* value); public: Messageheader() { clear(); } virtual ~Messageheader() { } const_iterator begin() const { return const_iterator(_rawdata); } const_iterator end() const { return const_iterator(); } const_iterator find(const char* key) const; const_iterator find(const std::string& key) const { return find(key.c_str()); } bool hasHeader(const char* key) const { return find(key) != end(); } bool hasHeader(const std::string& key) const { return hasHeader(key.c_str()); } bool compareHeader(const char* key, const char* value) const; bool compareHeader(const std::string& key, const std::string& value) const { return compareHeader(key.c_str(), value.c_str()); } void removeHeader(const char* key); void removeHeader(const std::string& key) { removeHeader(key.c_str()); } void clear(); void setHeader(const char* key, const char* value, bool replace); void setHeader(const std::string& key, const std::string& value, bool replace) { setHeader(key.c_str(), value.c_str(), replace); } }; std::istream& operator>> (std::istream& in, Messageheader& data); } #endif // TNT_MESSAGEHEADER_H tntnet-3.0/framework/common/tnt/messageheaderparser.h000066400000000000000000000045171365471676700232020ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_MESSAGEHEADERPARSER_H #define TNT_MESSAGEHEADERPARSER_H #include #include namespace tnt { class Messageheader::Parser : public tnt::Parser { Messageheader& _header; char* _headerdataPtr; char* _fieldnamePtr; char* _fieldbodyPtr; bool state_0(char ch); bool state_cr(char ch); bool state_fieldname(char ch); bool state_fieldnamespace(char ch); bool state_fieldbody0(char ch); bool state_fieldbody(char ch); bool state_fieldbody_cr(char ch); bool state_fieldbody_crlf(char ch); bool state_end_cr(char ch); void checkHeaderspace(unsigned chars) const; public: explicit Parser(Messageheader& header) : tnt::Parser(&Parser::state_0), _header(header), _headerdataPtr(header._rawdata), _fieldnamePtr(0), _fieldbodyPtr(0) { } void reset(); }; } #endif // TNT_MESSAGEHEADERPARSER_H tntnet-3.0/framework/common/tnt/mimedb.h000066400000000000000000000041131365471676700204150ustar00rootroot00000000000000/* * Copyright (C) 2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_MIMEDB_H #define TNT_MIMEDB_H #include #include #include #include namespace tnt { class MimeDb { typedef std::map > MimeDbType; MimeDbType _mimeDb; public: MimeDb() { } explicit MimeDb(const std::string& mimefile) { read(mimefile); } explicit MimeDb(const char* mimefile) { read(mimefile); } void read(const std::string& mimefile); void read(const char* mimefile); void read(std::istream& in); void addType(const std::string& ext, const std::string& mimeType); std::string getMimetype(const std::string& fname) const; }; } #endif // TNT_MIMEDB_H tntnet-3.0/framework/common/tnt/multipart.h000066400000000000000000000116561365471676700212130ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_MULTIPART_H #define TNT_MULTIPART_H #include #include #include #include namespace tnt { /// header of a MIME-multipart-object class Partheader : public Messageheader { Contentdisposition _cd; protected: return_type onField(const char* name, const char* value); public: const Contentdisposition& getContentDisposition() const { return _cd; } std::string getMimetype() const; }; /// Part of a MIME-multipart-object class Part { public: typedef std::string::const_iterator const_iterator; typedef std::string::const_iterator iterator; typedef std::string::size_type size_type; typedef std::string::value_type value_type; typedef std::string::pointer pointer; typedef std::string::reference reference; typedef std::string::const_reference const_reference; typedef std::string::difference_type difference_type; private: Partheader _header; const_iterator _bodyBegin; const_iterator _bodyEnd; public: Part() { } Part(const_iterator b, const_iterator e); /// returns the Partheader-object of this Part. const Partheader& getHeader() const { return _header; } /// returns a single header-value or empty string if not set. std::string getHeader(const std::string& key) const; /// returns the type of this Part const std::string& getType() const { return _header.getContentDisposition().getType(); } /// returns the type of this Part std::string getMimetype() const { return _header.getMimetype(); } /// returns the name of this Part (name-attribute of html-input-field) const std::string& getName() const { return _header.getContentDisposition().getName(); } /// returns the passed filename of the Part or empty string. const std::string& getFilename() const { return _header.getContentDisposition().getFilename(); } /// returns a const iterator to the start of data. const_iterator getBodyBegin() const { return _bodyBegin; } /// returns a const iterator past the end of data. const_iterator getBodyEnd() const { return _bodyEnd; } /// less efficient (a temporary string is created), but easier to use: std::string getBody() const { return std::string(getBodyBegin(), getBodyEnd()); } bool isEmpty() const { return getBodyBegin() == getBodyEnd(); } size_type getSize() const { return getBodyEnd() - getBodyBegin(); } // stl-style accessors const_iterator begin() const { return getBodyBegin(); } const_iterator end() const { return getBodyEnd(); } size_type size() const { return getSize(); } bool empty() const { return isEmpty(); } }; /// a MIME-Multipart-Object class Multipart { public: typedef Part part_type; typedef std::vector parts_type; typedef parts_type::const_iterator const_iterator; typedef parts_type::value_type value_type; private: std::string _body; parts_type _parts; public: Multipart() { } void set(const std::string& boundary, const std::string& body); const_iterator begin() const { return _parts.begin(); } const_iterator end() const { return _parts.end(); } const_iterator find(const std::string& partName, const_iterator start) const; const_iterator find(const std::string& partName) const { return find(partName, begin()); } }; } #endif // TNT_MULTIPART_H tntnet-3.0/framework/common/tnt/object.h000066400000000000000000000053411365471676700204320ustar00rootroot00000000000000/* * Copyright (C) 2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_OBJECT_H #define TNT_OBJECT_H #include #include namespace tnt { class Object : public cxxtools::RefCounted { public: virtual ~Object() { } typedef cxxtools::SmartPtr pointer_type; template data_type* cast(); }; template class destroyPolicy = cxxtools::DeletePolicy> class PointerObject : public Object, public destroyPolicy { data_type* _ptr; public: explicit PointerObject(data_type* ptr = 0) : _ptr(ptr) { } ~PointerObject() { destroyPolicy::destroy(_ptr); } void set(data_type* ptr) { destroyPolicy::destroy(_ptr); _ptr = ptr; } data_type* get() { return _ptr; } }; template Object::pointer_type createPointerObject(const data_type& d) { // assign the PointerObject to a smart pointer prior calling the ctor of // the created object to prevent memory leaky in case the ctor throws an // exception PointerObject* _ptr = new PointerObject(); Object::pointer_type ret = _ptr; _ptr->set(new data_type(d)); return ret; } template data_type* Object::cast() { return static_cast*>(this)->get(); } } #endif // TNT_OBJECT_H tntnet-3.0/framework/common/tnt/parser.h000066400000000000000000000060301365471676700204540ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_PARSER_H #define TNT_PARSER_H #include /// @cond internal namespace tnt { class PrePostNop { protected: void pre(char /* ch */) { } bool post(bool ret) { return ret; } }; template class Parser : public PrePostProcessor { protected: typedef bool (this_type::*state_type)(char); state_type _state; state_type _nextState; bool _failedFlag; bool state_skipws(char ch) { if (ch != ' ' && ch != '\t') { _state = _nextState; return (static_cast(this)->*_state)(ch); } else return false; } void skipWs(state_type nextState) { _state = &Parser::state_skipws; _nextState = nextState; } public: explicit Parser(state_type initialState) : _state(initialState), _nextState(0), _failedFlag(false) { } bool parse(char ch) { PrePostProcessor::pre(ch); return PrePostProcessor::post( (static_cast(this)->*_state)(ch) ); } bool parse(const char* str, unsigned size) { for (unsigned s = 0; s < size; ++s) if (parse(str[s])) return true; return false; } bool parse(std::istream& in) { std::streambuf* buf = in.rdbuf(); while (buf->sgetc() != std::ios::traits_type::eof()) if ( parse(buf->sbumpc()) ) return true; in.setstate(std::ios::eofbit); return false; } bool failed() const { return _failedFlag; } }; } #endif // TNT_PARSER_H tntnet-3.0/framework/common/tnt/poller.h000066400000000000000000000042371365471676700204640ustar00rootroot00000000000000/* * Copyright (C) 2005-2006 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_POLLER_H #define TNT_POLLER_H #include namespace tnt { /// @cond internal class PollerIf { PollerIf(const PollerIf&) { } PollerIf& operator=(const PollerIf&) { return *this; } public: PollerIf() { } virtual ~PollerIf(); virtual void run() = 0; virtual void doStop() = 0; virtual void addIdleJob(Jobqueue::JobPtr& job) = 0; }; class Poller { Poller(const Poller&) { } Poller& operator=(const Poller&) { return *this; } PollerIf* _impl; public: explicit Poller(Jobqueue& q); ~Poller() { delete _impl; } void run(); void doStop() { _impl->doStop(); } void addIdleJob(Jobqueue::JobPtr& job) { _impl->addIdleJob(job); } }; /// @endcond internal } #endif // TNT_POLLER_H tntnet-3.0/framework/common/tnt/pollerimpl.h000066400000000000000000000054361365471676700213500ustar00rootroot00000000000000/* * Copyright (C) 2007 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_POLLERIMPL_H #define TNT_POLLERIMPL_H #include #include "tnt/job.h" #include "tnt/poller.h" #include #include #if defined(HAVE_EPOLL_CREATE) || defined(HAVE_EPOLL_CREATE1) # define WITH_EPOLL # include #else # include # include # include #endif namespace tnt { /// @cond internal class PollerImpl : public PollerIf { private: Jobqueue& _queue; cxxtools::posix::Pipe _notifyPipe; cxxtools::Mutex _mutex; #ifdef WITH_EPOLL int _pollFd; typedef std::map jobs_type; typedef std::vector new_jobs_type; jobs_type _jobs; new_jobs_type _newJobs; int _pollTimeout; void addFd(int fd); bool removeFd(int fd); void appendNewJobs(); #else typedef std::deque jobs_type; typedef std::vector pollfds_type; jobs_type _currentJobs; pollfds_type _pollfds; jobs_type _newJobs; int _pollTimeout; void appendNewJobs(); void append(Jobqueue::JobPtr& job); void dispatch(); void remove(jobs_type::size_type n); #endif // #else WITH_EPOLL public: PollerImpl(Jobqueue& q); #ifdef WITH_EPOLL ~PollerImpl(); #endif virtual void run(); void doStop(); void addIdleJob(Jobqueue::JobPtr& job); }; /// @endcond internal } #endif // TNT_POLLER_H tntnet-3.0/framework/common/tnt/query_params.h000066400000000000000000000264031365471676700216760ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_QUERY_PARAMS_H #define TNT_QUERY_PARAMS_H #include #include #include #include #include #include #include namespace tnt { class QueryParams; /// @cond internal namespace qhelper { //////////////////////////////////////////////////////////////////////// // generic helper functions // template class QArg { public: static Type get(const QueryParams& q, const std::string& name, const Type& def = Type()); static std::vector getvector(const QueryParams& q, const std::string& name); }; //////////////////////////////////////////////////////////////////////// // specialization for std::string // template <> class QArg { public: static std::string get(const QueryParams& q, const std::string& name, const std::string& def = std::string()); static std::vector getvector(const QueryParams& q, const std::string& name); }; //////////////////////////////////////////////////////////////////////// // specialization for char // template <> class QArg { public: static char get(const QueryParams& q, const std::string& name, char def = '\0'); static std::vector getvector(const QueryParams& q, const std::string& name); }; //////////////////////////////////////////////////////////////////////// // specialization for bool // template <> class QArg { public: static bool get(const QueryParams& q, const std::string& name); static bool get(const QueryParams& q, const std::string& name, bool def); }; template class QAdd { public: static void add(QueryParams& q, const std::string& name, const Type& value); }; template <> class QAdd { public: static void add(QueryParams& q, const std::string& name, const std::string& value); }; template <> class QAdd { public: static void add(QueryParams& q, const std::string& name, char value); }; template <> class QAdd { public: static void add(QueryParams& q, const std::string& name, bool value); }; } /// @endcond internal /// Container for GET and POST parameters class QueryParams : public cxxtools::QueryParams { template friend class qhelper::QAdd; Scope* _paramScope; mutable cxxtools::SerializationInfo _si; mutable bool _siInit; public: /// Create an empty %QueryParams object QueryParams() : _paramScope(0), _siInit(false) { } QueryParams(const QueryParams& src) : cxxtools::QueryParams(src), _paramScope(src._paramScope), _siInit(false) { if (_paramScope) _paramScope->addRef(); } explicit QueryParams(const std::string& url) : cxxtools::QueryParams(url), _paramScope(0), _siInit(false) { } QueryParams& operator= (const QueryParams& src) { if (this == &src) return *this; cxxtools::QueryParams::operator=(src); if (_paramScope != src._paramScope) { if (_paramScope->release() == 0) delete _paramScope; _paramScope = src._paramScope; if (_paramScope) _paramScope->addRef(); } _siInit = false; return *this; } ~QueryParams() { if (_paramScope && _paramScope->release() == 0) delete _paramScope; } void clear() { cxxtools::QueryParams::clear(); _si.clear(); _siInit = false; } cxxtools::SerializationInfo& si() { if (!_siInit) { _si <<= *this; _siInit = true; } return _si; } const cxxtools::SerializationInfo& si() const { if (!_siInit) { _si <<= *this; _siInit = true; } return _si; } Scope& getScope() { if (!_paramScope) _paramScope = new Scope(); return *_paramScope; } /// Get parameter with name `name` if available. Returns `def` if not found. /// For string type the value is returned. /// Boolean returns `true` if it is found, `false` otherwise. /// Other types are converted using the cxxtools serialization framework. template Type get(const std::string& name, const Type& def) const { return qhelper::QArg::get(*this, name, def); } /// Get parameter with name `name` if available. Returns default value if not found. /// For string type the value is returned. /// Boolean returns `true` if it is found, `false` otherwise. /// Other types are converted using the cxxtools serialization framework. template Type get(const std::string& name) const { return qhelper::QArg::get(*this, name); } /// alias for `get` /// @deprecated template Type arg(const std::string& name, const Type& def) const { return qhelper::QArg::get(*this, name, def); } /// alias for `get` /// @deprecated template Type arg(const std::string& name) const { return qhelper::QArg::get(*this, name); } template std::vector getvector(const std::string& name) const { return qhelper::QArg::getvector(*this, name); } /// alias for `getvector` /// @deprecated template std::vector args(const std::string& name) const { return qhelper::QArg::getvector(*this, name); } template QueryParams& add(const std::string& name, const Type& value) { qhelper::QAdd::add(*this, name, value); return *this; } QueryParams& add(const std::string& name, const char* value) { cxxtools::QueryParams::add(name, value); return *this; } QueryParams& add(const cxxtools::QueryParams& q) { cxxtools::QueryParams::add(q); return *this; } }; namespace qhelper { //////////////////////////////////////////////////////////////////////// // generic helper functions // template Type QArg::get(const QueryParams& q, const std::string& name, const Type& def) { const cxxtools::SerializationInfo* pi; try { pi = &q.si().getMember(name); } catch (const cxxtools::SerializationMemberNotFound&) { return def; } Type ret; *pi >>= ret; return ret; } template std::vector QArg::getvector(const QueryParams& q, const std::string& name) { std::vector ret; const cxxtools::SerializationInfo* pi; try { pi = &q.si().getMember(name); } catch (const cxxtools::SerializationMemberNotFound&) { return ret; } *pi >>= ret; return ret; } //////////////////////////////////////////////////////////////////////// // specialization for std::string // inline std::string QArg::get(const QueryParams& q, const std::string& name, const std::string& def) { return q.param(name, def); } inline std::vector QArg::getvector(const QueryParams& q, const std::string& name) { return std::vector(q.begin(name + "[]"), q.end()); } //////////////////////////////////////////////////////////////////////// // specialization for char // inline char QArg::get(const QueryParams& q, const std::string& name, char def) { std::string p = q.param(name); return p.empty() ? def : p[0]; } inline std::vector QArg::getvector(const QueryParams& q, const std::string& name) { std::vector ret; for (QueryParams::const_iterator it = q.begin(name + "[]"); it != q.end(); ++it) ret.push_back(it->empty() ? '\0' : (*it)[0]); return ret; } //////////////////////////////////////////////////////////////////////// // specialization for bool // inline bool QArg::get(const QueryParams& q, const std::string& name) { return !q.param(name).empty(); } inline bool QArg::get(const QueryParams& q, const std::string& name, bool def) { try { bool ret; q.si().getMember(name) >>= ret; return ret; } catch (const cxxtools::SerializationMemberNotFound&) { return def; } } //////////////////////////////////////////////////////////////////////// template void QAdd::add(QueryParams& q, const std::string& name, const Type& value) { std::ostringstream s; s << value; static_cast(q).add(name, s.str()); q._si.clear(); q._siInit = false; } inline void QAdd::add(QueryParams& q, const std::string& name, const std::string& value) { static_cast(q).add(name, value); q._si.clear(); q._siInit = false; } inline void QAdd::add(QueryParams& q, const std::string& name, char value) { static_cast(q).add(name, std::string(1, value)); q._si.clear(); q._siInit = false; } inline void QAdd::add(QueryParams& q, const std::string& name, bool value) { static_cast(q).add(name, value ? std::string(1, '1') : std::string()); q._si.clear(); q._siInit = false; } } } #endif // TNT_QUERY_PARAMS_H tntnet-3.0/framework/common/tnt/savepoint.h000066400000000000000000000035631365471676700212000ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_SAVEPOINT_H #define TNT_SAVEPOINT_H #include namespace tnt { class Savepoint { bool _active; HttpReply& _reply; std::string::size_type _pos; public: Savepoint(HttpReply& reply, bool active = true) : _active(false), _reply(reply) { if (active) save(); } ~Savepoint() { if (_active) rollback(); } void save(); void commit(); void rollback(); }; } #endif // TNT_SAVEPOINT_H tntnet-3.0/framework/common/tnt/scope.h000066400000000000000000000076721365471676700203060ustar00rootroot00000000000000/* * Copyright (C) 2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_SCOPE_H #define TNT_SCOPE_H #include #include #include #include #include namespace tnt { template class NullDestroyPolicy { public: static void destroy(objectType*) { } }; class Scope : public cxxtools::AtomicRefCounted { public: typedef Object::pointer_type pointer_type; private: typedef std::map container_type; container_type _data; mutable cxxtools::Mutex _mutex; void privatePut(const std::string& key, pointer_type o); // non-copyable Scope(const Scope&); Scope& operator=(const Scope&); public: Scope(); virtual ~Scope(); void lock() { _mutex.lock(); } void unlock() { _mutex.unlock(); } bool has(const std::string& key) const { return _data.find(key) != _data.end(); } template T* get(const std::string& key) { container_type::iterator it = _data.find(key); return it == _data.end() ? 0 : it->second->cast(); } /// Put new Object in scope. If key already exists, /// it is replaced and old Object released. template class destroyPolicy> void put(const std::string& key, T* o) { try { tnt::PointerObject* ptr = new tnt::PointerObject(o); privatePut(key, ptr); } catch (const std::bad_alloc&) { destroyPolicy::destroy(o); throw; } } template void put(const std::string& key, T* o) { put(key, o); } template void put(const std::string& key, T* o, bool transferOwnership) { if (transferOwnership) put(key, o); else put(key, o); } void erase(const std::string& key) { _data.erase(key); } bool empty() const { return _data.empty(); } void clear() { _data.clear(); } typedef container_type::const_iterator const_iterator; typedef container_type::iterator iterator; typedef container_type::value_type value_type; const_iterator begin() const { return _data.begin(); } const_iterator end() const { return _data.end(); } iterator begin() { return _data.begin(); } iterator end() { return _data.end(); } }; } #endif // TNT_SCOPE_H tntnet-3.0/framework/common/tnt/scopemanager.h000066400000000000000000000053021365471676700216250ustar00rootroot00000000000000/* * Copyright (C) 2003-2006 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_SCOPEMANAGER_H #define TNT_SCOPEMANAGER_H #include #include #include #include namespace tnt { class Scope; class Sessionscope; class HttpRequest; class HttpReply; /// @cond internal class ScopeManager { public: typedef std::map scopes_type; typedef std::map sessionscopes_type; private: scopes_type _applicationScopes; sessionscopes_type _sessionScopes; cxxtools::Mutex _applicationScopesMutex; cxxtools::Mutex _sessionScopesMutex; Scope* getApplicationScope(const std::string& appname); Sessionscope* getSessionScope(const std::string& sessioncookie); bool hasSessionScope(const std::string& sessioncookie); void putSessionScope(const std::string& sessioncookie, Sessionscope* s); void removeApplicationScope(const std::string& appname); void removeSessionScope(const std::string& sessioncookie); public: ScopeManager(); ~ScopeManager(); void preCall(HttpRequest& request, const std::string& app); void setSessionId(HttpRequest& request, const std::string& sessionId); std::string postCall(HttpRequest& request, HttpReply& reply, const std::string& app); void checkSessionTimeout(); }; /// @endcond internal } #endif // TNT_SCOPEMANAGER_H tntnet-3.0/framework/common/tnt/sessionscope.h000066400000000000000000000036611365471676700217040ustar00rootroot00000000000000/* * Copyright (C) 2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_SESSIONSCOPE_H #define TNT_SESSIONSCOPE_H #include #include #include namespace tnt { class Sessionscope : public Scope { time_t _atime; cxxtools::Seconds _timeout; public: Sessionscope() : _timeout(TntConfig::it().sessionTimeout) { touch(); } void touch() { time(&_atime); } time_t getAtime() const { return _atime; } cxxtools::Seconds getTimeout() const { return _timeout; } void setTimeout(cxxtools::Seconds t) { _timeout = t; } }; } #endif // TNT_SESSIONSCOPE_H tntnet-3.0/framework/common/tnt/sessionunlocker.h000066400000000000000000000047571365471676700224240ustar00rootroot00000000000000/* * Copyright (C) 2009 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_SESSIONUNLOCKER_H #define TNT_SESSIONUNLOCKER_H #include namespace tnt { /** Unlocks the session as long as the object is in scope. Normally the session is locked as soon as a request uses somewhere a session variable. Sometimes it is desirable to explicitely release that lock, e.g. when a request has some longer task to do. This frequently happens in reverse ajax, where the request blocks while waiting for a event. */ class SessionUnlocker { HttpRequest& _request; bool _locked; public: explicit SessionUnlocker(HttpRequest& request, bool release = true) : _request(request), _locked(request._sessionScopeLocked) { if (_locked && release) _request.releaseSessionScopeLock(); } ~SessionUnlocker() { if (_locked) _request.ensureSessionScopeLock(); } void unlock() { _request.releaseSessionScopeLock(); _locked = false; } void lock() { _request.ensureSessionScopeLock(); _locked = true; } }; } #endif // TNT_SESSIONUNLOCKER_H tntnet-3.0/framework/common/tnt/socketif.h000066400000000000000000000034461365471676700207770ustar00rootroot00000000000000/* * Copyright (C) 2009 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_SOCKETIF_H #define TNT_SOCKETIF_H #include namespace cxxtools { class SslCertificate; } /// @cond internal namespace tnt { class SocketIf { protected: virtual ~SocketIf() { } public: virtual std::string getPeerIp() const = 0; virtual std::string getServerIp() const = 0; virtual bool isSsl() const = 0; virtual cxxtools::SslCertificate getSslCertificate() const = 0; }; } #endif // TNT_SOCKETIF_H tntnet-3.0/framework/common/tnt/stringlessignorecase.h000066400000000000000000000052501365471676700234200ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_STRINGLESSIGNORECASE_H #define TNT_STRINGLESSIGNORECASE_H #include #include #include namespace tnt { template int StringCompareIgnoreCase(const stringType& s1, const stringType& s2) { typename stringType::const_iterator it1 = s1.begin(); typename stringType::const_iterator it2 = s2.begin(); while (it1 != s1.end() && it2 != s2.end()) { if (*it1 != *it2) { char c1 = std::toupper(*it1); char c2 = std::toupper(*it2); if (c1 < c2) return -1; else if (c2 < c1) return 1; } ++it1; ++it2; } return it1 == s1.end() ? (it2 != s2.end()) ? -1 : 0 : 1; } template <> int StringCompareIgnoreCase(const char* const& s1, const char* const& s2); inline int StringCompareIgnoreCase(const std::string& s1, const std::string& s2) { return StringCompareIgnoreCase(s1, s2); } template class StringLessIgnoreCase : public std::binary_function { public: bool operator()(const stringType& s1, const stringType& s2) const { return StringCompareIgnoreCase(s1, s2) < 0; } }; } #endif // TNT_STRINGLESSIGNORECASE_H tntnet-3.0/framework/common/tnt/tcpjob.h000066400000000000000000000054361365471676700204520ustar00rootroot00000000000000/* * Copyright (C) 2007 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_TCPJOB_H #define TNT_TCPJOB_H #include #include #include #include /// @cond internal namespace tnt { class Tcpjob : public Job, private SocketIf { cxxtools::net::TcpStream _socket; const cxxtools::net::TcpServer& _listener; Jobqueue& _queue; bool _sslInitialized; std::string _certificateFile; std::string _privateKeyFile; int _sslVerifyLevel; std::string _sslCa; void accept(); void regenerateJob(); virtual std::string getPeerIp() const; virtual std::string getServerIp() const; virtual bool isSsl() const; virtual cxxtools::SslCertificate getSslCertificate() const; public: Tcpjob(Tntnet& app, const cxxtools::net::TcpServer& listener, Jobqueue& queue, const std::string& certificateFile, const std::string& privateKeyFile, int sslVerifyLevel, const std::string& sslCa) : Job(app, this), _socket(TntConfig::it().socketBufferSize, TntConfig::it().socketReadTimeout), _listener(listener), _queue(queue), _sslInitialized(false), _certificateFile(certificateFile), _privateKeyFile(privateKeyFile), _sslVerifyLevel(sslVerifyLevel), _sslCa(sslCa) { } std::iostream& getStream(); int getFd() const; void setRead(); void setWrite(); }; } #endif // TNT_TCPJOB_H tntnet-3.0/framework/common/tnt/threadcontext.h000066400000000000000000000032301365471676700220330ustar00rootroot00000000000000/* * Copyright (C) 2009 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_THREADCONTEXT_H #define TNT_THREADCONTEXT_H namespace tnt { class Scope; /// @cond internal class ThreadContext { protected: virtual ~ThreadContext() { } public: virtual void touch() = 0; // wake watchdog timer virtual Scope& getScope() = 0; }; } #endif // TNT_THREADCONTEXT_H tntnet-3.0/framework/common/tnt/tntconfig.h000066400000000000000000000413741365471676700211650ustar00rootroot00000000000000/* * Copyright (C) 2012 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_TNTCONFIG_H #define TNT_TNTCONFIG_H #include #include #include #include #include #include #include namespace tnt { static const int SSL_ALL = 0; static const int SSL_NO = 1; static const int SSL_YES = 2; /** This structure represents the configuration of a tntnet server. On startup tntnet (the tntnet server executable) reads the configuration from tntnet.xml or tntnet.json into a static instance of TntConfig. This static configuration can be accessed using TntConfig::it(). %TntConfig has many predefined configuration parameters but may contain additional custom attributes, which can be used in applications using the #config member. The easiest way to access additional configuration options is to add a <%config> section into the ecpp components where they are used. Variables specified there are automatically read from the static %TntConfig instance and deserialized into the specified data type. In standalone applications, the configuration file is not automatically read. It is up to the user to configure the application. Still this class can help setting up a server. Using Tntnet::init(), the user can pass the configuration to the application class. Since the class is also deserializable with cxxtools, it is easy to read the configuration from a file as the tntnet executable does. Example: @code // Create a configuration object tnt::TntConfig config; // Alternatively, the static instance can be used: // tnt::TntConfig& config = tnt::TntConfig::it(); // Open the configfile std::ifstream tntnetXml("tntnet.xml"); // Deserialize the content of tntnetXml and save it to config tntnetXml >> cxxtools::xml::Xml(config); // Instantiate an application object tnt::Tntnet app; // Pass the configuration to the application object app.init(config); // or intantiate with configuration tnt::Tntnet app(config); @endcode Note: This deserialization code only works when is included and you have cxxtools >= 2.3 installed. In previous cxxtools versions the deserialization has to be done like this: @code // Deserialize the content of tntnetXml and save it to config cxxtools::xml::XmlDeserializer deserializer(tntnetXml); deserializer.deserialize(config); @endcode */ struct TntConfig { /// A mapping entry struct Mapping { std::string target; std::string url; std::string vhost; std::string method; std::string pathinfo; unsigned httpreturn; int ssl; typedef std::map ArgsType; ArgsType args; Mapping() : httpreturn(HTTP_OK) { } }; /// A listener entry struct Listener { std::string ip; unsigned short port; }; /// An SSL listener entry struct SslListener : public Listener { std::string certificate; std::string key; int sslVerifyLevel; std::string sslCa; }; typedef std::vector MappingsType; typedef std::vector ListenersType; typedef std::vector SslListenersType; typedef std::vector CompPathType; typedef std::map EnvironmentType; /** A list of mappings (see Mapping) default: none */ MappingsType mappings; /** A list of listeners (see Listener) default: none */ ListenersType listeners; /** A list of ssl listeners (see SslListener) default: none */ SslListenersType ssllisteners; /** The maximal size of a request If a larger request is sent, it is ignored. This limit prevents Denial of Service attacks through long requests. Bear in mind though that this also limits the possible size of file uploads. default: 0 (no limit) */ unsigned maxRequestSize; /** The maximal time (in seconds) a worker thread may use to answer an http request If answering the request takes longer, the whole tntnet server is restarted, which means dropping all active connections. Therefore the time set here should be at least as long as the most time-intensive request may take. default: 600 seconds */ cxxtools::Seconds maxRequestTime; /** The unix user id of the user tntnet should switch to when executed as root If this string is unset (empty) or tntnet is not executed as root, the user under which tntnet operates does not change. The switching is done through setuid(). default: (empty) */ std::string user; /** The unix group id of the group tntnet should switch to when executed as root If this option is unset (empty) or tntnet is not executed as root, the group under which tntnet operates does not change. The switching is done through setgid(). default: (empty) */ std::string group; /** The working dir in which tntnet should operate If this option is unset (empty), tntnet keeps the working directory from which it is executed. default: (empty) */ std::string dir; /** A directory into which tntnet should switch with chroot This locks tntnet into that directory through chroot(), which means files outside it are no more visible and the directory becomes the root directory ("/") for file access operations. If this option is unset (empty), no chroot is performed. default: (empty) */ std::string chrootdir; /** A file to which the process id (pid) should be written The pid that is written into the file will be the one of the monitor process as long as it exists. If it is deactivated, the pid of the worker thread is written into the file. If this option is unset (empty), no file is written. default: (empty) */ std::string pidfile; /** Whether to run tntnet as daemon If this is set to true, tntnet forks itself and terminates the parent process. default: false */ bool daemon; /** The minimal number of worker threads default: 5 */ unsigned minThreads; /** The maximal number of worker threads default: 100 */ unsigned maxThreads; /** Time (in milliseconds) to wait before spawning a new worker thread When many new worker threads are needed, this delay prevents high processor load that may be caused by spawning them all as soon as possible. default: 10 milliseconds */ cxxtools::Milliseconds threadStartDelay; /** Limit for the size of the request queue The limit for the number of request that can simultaneously be queued while waiting to be processed. default: 1000 */ unsigned queueSize; /** The paths where tntnet searches for the compiled webapps. By default only the working directory and the systems library search path are used for the search. default: (none) */ CompPathType compPath; /** Size (in bytes) of data bundled for a system call This setting tunes the size of the input and output buffer for the socket. Each connection allocates that many bytes for the buffer. default: 16384 */ unsigned socketBufferSize; /** The timeout (in milliseconds) for reading data from a client If keep-alive is activated (default), tntnet starts waiting for requests on every new socket after the initial request. To reduce context switches between threads the corresponding thread waits for new requests for the specified time after the initial request and puts the connection into the queue of idle connections afterwards. default: 10 milliseconds */ cxxtools::Milliseconds socketReadTimeout; /** The timeout (in milliseconds) for writing data to a client Writing to clients is entirely done in one thread. Normally writing never blocks, but if that happens, this timeout ensures that that does not lock the whole server. default: 10 Seconds */ cxxtools::Milliseconds socketWriteTimeout; /** The timeout (in milliseconds) for keeping a TCP connection alive Per default, keep-alive connections are used, which means TCP connections between server and client stay for multiple requests. This option controls how long TCP connections are kept alive. default: 30 seconds */ cxxtools::Seconds keepAliveTimeout; /** Maximal amount of requests per TCP connection in keep alive default: 1000 */ unsigned keepAliveMax; /** The amount of time (in seconds) after which a session times out default: 300 */ cxxtools::Seconds sessionTimeout; /** The amount of connection requests to be queued by the system Before tntnet accepts an incoming TCP connection request, it is stored in the OS'es backlog. This option determines how many connections the OS should store in the backlog. When this limit is reached, new connection requests are rejected. default: 512 */ unsigned listenBacklog; /** The amount of retries to listen for incoming connections If listening on a local interface fails, tntnet will retry for the specified amount of times. default: 5 */ unsigned listenRetry; // TODO: Where do the 10% come from? Was this an old behaviour replaced // by minCompressSize or is this an additional (unconfigurable) check? /** Whether to enable gzip compression for data sent to the client Unless this is set to false, tntnet compresses all data using gzip if @li the data can be compressed by more than 10% and @li the client sends the flag "Accept-Encoding" in the http request header default: true */ bool enableCompression; /** Minimal size (in bytes) of http reply body to be compressed If an http body is smaller than this, it will not be compressed. default: 1024 */ unsigned minCompressSize; /** Filename of the mime database The mime database is used to look up the mime-type that is sent in the http header. default: "/etc/mime.types" */ std::string mimeDb; /** The maximal amount of entries in the url map cache tntnet caches the results of component lookups because going through the whole mapping table and possibly executing many regular expressions is time expensive. After this limit for the amout of entries is reached, the cache is cleared. default: 8192 */ unsigned maxUrlMapCache; /** The default mime-type for the http header Sets the content type header of the reply. The content type may be changed in the application using `reply.setContentType("something")`. default: "text/html; charset=UTF-8" */ std::string defaultContentType; /** Logfile for server requests The format of the logging entries is compatible with logging tools for http servers. If this option is unset (empty), no logfile is written. default: (empty) */ std::string accessLog; /** Logfile for errors This option redirects stderr to the specified file. It is crucial to set this if you run tntnet as daemon. If this option is unset (empty), no logfile is written. default: (empty) */ std::string errorLog; /** The timer interval, when session timeout are monitored. A timer thread periodically checks whether a session times out. This setting specifies how often this is checked. default: 10 (seconds) */ cxxtools::Seconds timerSleep; /** Contains the whole configuration as a cxxtools::SerializationInfo cxxtools::SerializatioInfo is a generic structure which can be used to read custom information from the configuration file. This member is automatically set when deserializing a file to a TntConfig object and should not be used otherwise. default: (empty object) */ cxxtools::SerializationInfo config; /** Logging configuration for cxxtools logging. */ cxxtools::LogConfiguration logConfiguration; /** Sets environment variables. A std::map of environment variables to set when Tntnet starts. default: (empty map) */ EnvironmentType environment; /** The directory under which the component static\@tntnet searches for files If this option is unset (empty), static\@tntnet searches for files in the working directory. default: (empty) */ std::string documentRoot; /** Sets the Server header in http reply. The server header in the http reply is normally set to the used server software. For Tntnet, the default is "Tntnet" plus the version number but you can override that. The Server header will get omitted if this option is unset (empty). default: Tntnet/'version-number' */ std::string server; /** Sets the SO_REUSEADDR flag on the connection. * * This flag specifies wheter SO_REUSEADDR is enabled on the listener * sockets. * The value may be 0/1 or true/false. * * default: true */ bool reuseAddress; /** Files from which to read additional options Through this option you can specify additional files from which more configuration options should be read. default: (none) */ std::vector includes; /** Restrict the list of SSL ciphers The format of the string is described in https://www.openssl.org/docs/manmaster/apps/ciphers.html default: (none) */ std::string sslCipherList; /** Restrict the list of SSL protocols +SSLv3 enable SSLv3 -SSLv3 disable SSLv3 +TLSv1_0 enable TLSv1 -TLSv1_0 disable TLSv1 +TLSv1_1 enable TLSv1.1 -TLSv1_1 disable TLSv1.1 +TLSv1_2 enable TLSv1.2 -TLSv1_2 disable TLSv1.2 */ std::string sslProtocols; /// Create a %TntConfig object with default configuration TntConfig(); /// Check whether a setting with the specified key is set in the configuration bool hasValue(const std::string& key) const { return config.findMember(key) != 0; } /** Returns the instance of %TntConfig used by the tntnet server at startup When starting tntnet (the executable), configuration is read from a xml or json file. Applications get access to the configuration through this object. */ static TntConfig& it(); }; /// Deserialization operator for TntConfig::Mapping void operator>>= (const cxxtools::SerializationInfo& si, TntConfig::Mapping& mapping); /// Deserialization operator for TntConfig::Listener void operator>>= (const cxxtools::SerializationInfo& si, TntConfig::Listener& listener); /// Deserialization operator for TntConfig::SslListener void operator>>= (const cxxtools::SerializationInfo& si, TntConfig::SslListener& ssllistener); /// Deserialization operator for TntConfig void operator>>= (const cxxtools::SerializationInfo& si, TntConfig& config); } #endif // TNT_TNTCONFIG_H tntnet-3.0/framework/common/tnt/tntnet.h000066400000000000000000000200411365471676700204720ustar00rootroot00000000000000/* * Copyright (C) 2003-2007 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_TNTNET_H #define TNT_TNTNET_H #include #include #include namespace tnt { struct TntConfig; class TntnetImpl; /** Main application class for stand-alone tntnet web application The Tntnet class is used to compile a web application into a simple executable. The compiled program then works as a webserver, handling the server requests for the web application. This is the alternative to compiling it into a shared library and using the tntnet program to handle the server requests. This is the minimal set of things you have to include in your code to create a standalone tntnet web application: @li The instantiation of a Tntnet object @li A call to listen and/or sslListen @li One or more calls to mapUrl or vMapUrl @li A call to run() Example: @code #include #include int main() { try { tnt::Tntnet app; app.listen(8000); app.mapUrl("^/$", "index"); app.mapUrl("^/(.*)$", "$1"); app.mapUrl("^/.*$", "404"); app.run(); } catch(const std::exception& e) { std::cerr << e.what() << std::endl; return 1; } return 0; } @endcode */ class Tntnet { public: /** Create a %Tntnet object with default configuration For information on the default configuration options, see TntConfig. */ Tntnet(); /** Copy constructor. Both instances will point to the same implementation. */ Tntnet(const Tntnet& t); /** Initialize a tntnet server object with a configuration object. */ explicit Tntnet(const TntConfig& config); /** Assignment. Both instances will point to the same implementation. */ Tntnet& operator=(const Tntnet& t); /// Load server configuration from a TntConfig object void init(const TntConfig& config); /** Set up a listener for the specified ip address and port. An empty string means listening on all interfaces – you can simply use the listen() method with one parameter to do that though. This method solely does the setup, the actual listening starts in run(). */ void listen(const std::string& ipaddr, unsigned short int port); /** Set up a listener for the specified port which listens on all local interfaces As the above method, this doesn't start the actual listening. */ void listen(unsigned short int port) { listen(std::string(), port); } /** Set up a ssl listener for the specified ip address and port See listen() for more information. */ void sslListen(const std::string& ipaddr, unsigned short int port, const std::string& certificateFile, const std::string& keyFile = std::string(), int sslVerifyLevel = 0, const std::string& sslCa = std::string()); /// @deprecated void sslListen(const std::string& certificateFile, const std::string& keyFile, const std::string& ipaddr, unsigned short int port) { sslListen(ipaddr, port, certificateFile, keyFile); } /** Set up a ssl listener for the specified port which listens on all local interfaces See listen() for more information. */ void sslListen(const std::string& certificateFile, const std::string& keyFile, unsigned short int port) { sslListen(certificateFile, keyFile, std::string(), port); } /** Start all needed threads and the application loop If no listeners were set up through listen or sslListen, a default listener is instantiated. It listens on all local interfaces on either port 80 (when the program is executed as root) or port 8000 (other users). */ void run(); /// Request all %Tntnet instances to shut down static void shutdown(); /// Tells whether a shutdown request was initiated static bool shouldStop(); /// Get the minimum number of worker threads unsigned getMinThreads() const; /// Set the minimum number of worker threads void setMinThreads(unsigned n); /// Get the maximum number of worker threads unsigned getMaxThreads() const; /// Set the maximum number of worker threads void setMaxThreads(unsigned n); /// @{ /** @name URL mapping Add a mapping from a url to a component The matching url's are specified using a regular expression. The mapping target may contain back references to the expression using $1, $2 and so on. @param url The path requested by the client. The path includes everything between the domain name and the get parameters. It always begins with a '/'. @param ci The identifier for the component to which the url is mapped. The first method simply passes the string to the CompIdent constructor. */ Mapping& mapUrl(const std::string& url, const std::string& ci); Mapping& mapUrl(const std::string& url, const Compident& ci); /// @deprecated void mapUrl(const std::string& url, const std::string& pathinfo, const std::string& ci); /// @deprecated Mapping& mapUrl(const std::string& url, const Maptarget& ci); /// @deprecated Mapping& vMapUrl(const std::string& vhost, const std::string& url, const Maptarget& ci); /** Set the app name The app name is used for the session cookie name if the web application is linked directly to a stand-alone executable. The name of the session cookie then is "tntnet." plus the library name of the web application. Since there is no library name if the application is run through the Tntnet application class, this applications name is used instead. Setting the app name explicitely reduces potential conflicts if multiple tntnet application servers are run on the same host on different ports. */ void setAppName(const std::string& appname); /// Get the app name – for details see setAppName() const std::string& getAppName() const; /** Enable access logging The used log format is the common logfile format (CLF), the same format Apache uses for its access logs. @param logfile_path The path to the log file. */ void setAccessLog(const std::string& logfile_path); private: TntnetImpl* _impl; }; } #endif // TNT_TNTNET_H tntnet-3.0/framework/common/tnt/unzipfile.h000066400000000000000000000107541365471676700211750ustar00rootroot00000000000000/* * Copyright (C) 2003/2006 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_UNZIPFILE_H #define TNT_UNZIPFILE_H #include #include #include namespace tnt { class unzipError : public std::runtime_error { int _err; static std::string formatMsg(int e, const char* msg, const char* function); public: unzipError(int e, const std::string& msg = "unzipError") : std::runtime_error(msg), _err(e) { } unzipError(int e, const char* msg, const char* function) : std::runtime_error(formatMsg(e, msg, function)), _err(e) { } int getErr() const { return _err; } }; class unzipFileNotFound : public unzipError { public: unzipFileNotFound(const std::string& file) : unzipError(0, "file not found " + file) { } }; class unzipEndOfListOfFile : public unzipError { public: unzipEndOfListOfFile(const char* function = 0); }; class unzipParamError : public unzipError { public: unzipParamError(const char* function = 0); }; class unzipBadZipFile : public unzipError { public: unzipBadZipFile(const char* function = 0); }; class unzipInternalError : public unzipError { public: unzipInternalError(const char* function = 0); }; class unzipCrcError : public unzipError { public: unzipCrcError(const char* function = 0); }; class unzipFile { struct unzFileStruct; unzFileStruct* _file; public: unzipFile() : _file(0) { } unzipFile(const std::string& path) : _file(0) { open(path); } ~unzipFile(); void open(const std::string& path); void close(); void goToFirstFile(); void goToNextFile(); void locateFile(const std::string& fileName, bool caseSensitivity = true); void openCurrentFile(); void openCurrentFile(const std::string& pw); void closeCurrentFile(); int readCurrentFile(void* buf, unsigned len); }; class unzipFileStreamBuf : public std::streambuf { char_type _buffer[512]; unzipFile& _file; public: unzipFileStreamBuf(unzipFile& file, const std::string& fileName, bool caseSensitivity) : _file(file) { file.locateFile(fileName, caseSensitivity); file.openCurrentFile(); } unzipFileStreamBuf(unzipFile& file, const std::string& fileName, bool caseSensitivity, const std::string& password) : _file(file) { file.locateFile(fileName, caseSensitivity); file.openCurrentFile(password); } ~unzipFileStreamBuf() { _file.closeCurrentFile(); } /// overridden from std::streambuf int_type overflow(int_type c); /// overridden from std::streambuf int_type underflow(); /// overridden from std::streambuf int sync(); }; class unzipFileStream : public std::istream { unzipFileStreamBuf _streambuf; public: unzipFileStream(unzipFile& file, const std::string& fileName, bool caseSensitivity = true) : std::istream(0), _streambuf(file, fileName, caseSensitivity) { init(&_streambuf); } }; } #endif // TNT_UNZIPFILE_H tntnet-3.0/framework/common/tnt/urlescostream.h000066400000000000000000000046151365471676700220570ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_URLESCOSTREAM_H #define TNT_URLESCOSTREAM_H #include namespace tnt { class UrlEscStreamBuf : public std::streambuf { std::streambuf* _sink; std::streambuf::int_type overflow(std::streambuf::int_type ch); std::streambuf::int_type underflow(); int sync(); public: UrlEscStreamBuf(std::streambuf* sink) : _sink(sink) { } void setSink(std::streambuf* sink) { _sink = sink; } }; class UrlEscOstream : public std::ostream { UrlEscStreamBuf _streambuf; public: UrlEscOstream(std::ostream& sink) : std::ostream(0), _streambuf(sink.rdbuf()) { init(&_streambuf); } UrlEscOstream(std::streambuf* sink) : std::ostream(0), _streambuf(sink) { init(&_streambuf); } void setSink(std::ostream& sink) { _streambuf.setSink(sink.rdbuf()); } void setSink(std::streambuf* sink) { _streambuf.setSink(sink); } }; std::string urlEscape(const std::string& str); } #endif // TNT_URLESCOSTREAM_H tntnet-3.0/framework/common/tnt/urlmapper.h000066400000000000000000000032121365471676700211660ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_URLMAPPER_H #define TNT_URLMAPPER_H #include namespace tnt { // map compUrl to compident class Urlmapper { public: virtual ~Urlmapper() { } virtual Compident mapComp(const std::string& vhost, const std::string& compUrl) const; }; } #endif // TNT_URLMAPPER_H tntnet-3.0/framework/common/tnt/util.h000066400000000000000000000030161365471676700201360ustar00rootroot00000000000000/* * Copyright (C) 2008 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_UTIL_H #define TNT_UTIL_H #include namespace tnt { void throwRuntimeError(const std::string& msg); void throwRuntimeError(const char* msg); } #endif // TNT_UTIL_H tntnet-3.0/framework/common/tnt/worker.h000066400000000000000000000052421365471676700204750ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_WORKER_H #define TNT_WORKER_H #include #include #include #include #include #include #include /// @cond internal namespace tnt { class HttpRequest; class HttpReply; class Worker : public cxxtools::DetachedThread, private ThreadContext { typedef std::set workers_type; static cxxtools::Mutex _mutex; TntnetImpl& _application; static Comploader _comploader; Scope _threadScope; pthread_t _threadId; const char* _state; time_t _lastWaitTime; static workers_type _workers; bool processRequest(HttpRequest& request, std::iostream& socket, unsigned keepAliveCount); void logRequest(const HttpRequest& request, const HttpReply& reply, unsigned httpReturn); void healthCheck(time_t currentTime); // thread context methods void touch(); // wake watchdog timer Scope& getScope(); public: explicit Worker(TntnetImpl& app); virtual void run(); void dispatch(HttpRequest& request, HttpReply& reply); static void timer(); static workers_type::size_type getCountThreads(); static Comploader& getComponentLoader() { return _comploader; } }; } #endif // TNT_WORKER_H tntnet-3.0/framework/common/tnt/zdata.h000066400000000000000000000036731365471676700202750ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_ZDATA_H #define TNT_ZDATA_H #include /// @cond internal namespace tnt { class Zdata { const char* _zptr; const unsigned _zdataLen; const unsigned _dataLen; std::atomic _refs; char* _data; public: Zdata(const char* zptr, unsigned zdataLen, unsigned dataLen) : _zptr(zptr), _zdataLen(zdataLen), _dataLen(dataLen), _refs(0), _data(0) { } void addRef(); void release(); operator const char* () const { return _data; } }; } /// @endcond internal #endif // TNT_ZDATA_H tntnet-3.0/framework/common/tntconfig.cpp000066400000000000000000000207351365471676700207110ustar00rootroot00000000000000/* * Copyright (C) 2012 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "config.h" log_define("tntnet.tntconfig") namespace tnt { namespace { struct VirtualHost { std::string hostname; TntConfig::MappingsType mappings; }; void operator>>= (const cxxtools::SerializationInfo& si, VirtualHost& virtualHost) { si.getMember("hostname") >>= virtualHost.hostname; si.getMember("mappings") >>= virtualHost.mappings; for (TntConfig::MappingsType::iterator it = virtualHost.mappings.begin(); it != virtualHost.mappings.end(); ++it) { if (!it->vhost.empty()) log_warn("vhost entry not empty in mapping \"" << it->url << "\" in virtual host \"" << virtualHost.hostname); it->vhost = virtualHost.hostname; } } } void operator>>= (const cxxtools::SerializationInfo& si, TntConfig::Mapping& mapping) { si.getMember("target") >>= mapping.target; si.getMember("url", mapping.url); si.getMember("vhost", mapping.vhost); si.getMember("method", mapping.method); si.getMember("pathinfo", mapping.pathinfo); // accept values "DECLINED" or a numeric http return code for *httpreturn* // *httpreturn* specifies the default return code of components. const cxxtools::SerializationInfo* psi = si.findMember("httpreturn"); if (psi) { std::string httpreturn; *psi >>= httpreturn; if (httpreturn == "DECLINED") mapping.httpreturn = DECLINED; else *psi >>= mapping.httpreturn; } bool ssl; if (si.getMember("ssl", ssl)) mapping.ssl = ssl ? SSL_YES : SSL_NO; else mapping.ssl = SSL_ALL; const cxxtools::SerializationInfo* args = si.findMember("args"); if (args) { for (cxxtools::SerializationInfo::ConstIterator it = args->begin(); it != args->end(); ++it) { std::string value; it->getValue(value); mapping.args[it->name()] = value; } } } void operator>>= (const cxxtools::SerializationInfo& si, TntConfig::Listener& listener) { si.getMember("ip", listener.ip); si.getMember("port") >>= listener.port; } void operator>>= (const cxxtools::SerializationInfo& si, TntConfig::SslListener& ssllistener) { si.getMember("ip", ssllistener.ip); si.getMember("port") >>= ssllistener.port; si.getMember("certificate") >>= ssllistener.certificate; if (!si.getMember("key", ssllistener.key)) ssllistener.key = ssllistener.certificate; ssllistener.sslVerifyLevel = 0; if (si.getMember("sslVerifyLevel", ssllistener.sslVerifyLevel) && ssllistener.sslVerifyLevel > 0) si.getMember("sslCa") >>= ssllistener.sslCa; } void operator>>= (const cxxtools::SerializationInfo& si, TntConfig& config) { std::vector virtualHosts; if (si.getMember("virtualhosts", virtualHosts)) { for (std::vector::const_iterator it = virtualHosts.begin(); it != virtualHosts.end(); ++it) config.mappings.insert(config.mappings.end(), it->mappings.begin(), it->mappings.end()); } TntConfig::MappingsType mappings; if (si.getMember("mappings", mappings)) config.mappings.insert(config.mappings.end(), mappings.begin(), mappings.end()); TntConfig::ListenersType& listeners = config.listeners; TntConfig::SslListenersType& ssllisteners = config.ssllisteners; const cxxtools::SerializationInfo* lsi = si.findMember("listeners"); if (lsi != 0) { for (cxxtools::SerializationInfo::ConstIterator it = lsi->begin(); it != lsi->end(); ++it) { if (it->findMember("certificate") != 0) { ssllisteners.resize(ssllisteners.size() + 1); *it >>= ssllisteners.back(); } else { listeners.resize(listeners.size() + 1); *it >>= listeners.back(); } } } lsi = si.findMember("listener"); if (lsi != 0) { if (lsi->findMember("certificate") != 0) { ssllisteners.resize(ssllisteners.size() + 1); *lsi >>= ssllisteners.back(); } else { listeners.resize(listeners.size() + 1); *lsi >>= listeners.back(); } } si.getMember("maxRequestSize", config.maxRequestSize); si.getMember("maxRequestTime", config.maxRequestTime); si.getMember("user", config.user); si.getMember("group", config.group); si.getMember("dir", config.dir); si.getMember("chrootdir", config.chrootdir); si.getMember("pidfile", config.pidfile); si.getMember("daemon", config.daemon); si.getMember("minThreads", config.minThreads); si.getMember("maxThreads", config.maxThreads); si.getMember("threadStartDelay", config.threadStartDelay); si.getMember("queueSize", config.queueSize); si.getMember("compPath", config.compPath); si.getMember("socketBufferSize", config.socketBufferSize); si.getMember("socketReadTimeout", config.socketReadTimeout); si.getMember("socketWriteTimeout", config.socketWriteTimeout); si.getMember("keepAliveTimeout", config.keepAliveTimeout); si.getMember("keepAliveMax", config.keepAliveMax); si.getMember("sessionTimeout", config.sessionTimeout); si.getMember("listenBacklog", config.listenBacklog); si.getMember("listenRetry", config.listenRetry); si.getMember("enableCompression", config.enableCompression); si.getMember("minCompressSize", config.minCompressSize); si.getMember("mimeDb", config.mimeDb); si.getMember("maxUrlMapCache", config.maxUrlMapCache); si.getMember("defaultContentType", config.defaultContentType); si.getMember("accessLog", config.accessLog); si.getMember("errorLog", config.errorLog); si.getMember("timerSleep", config.timerSleep); si.getMember("documentRoot", config.documentRoot); si.getMember("server", config.server); si.getMember("reuseAddress", config.reuseAddress); si.getMember("includes", config.includes); si.getMember("logging", config.logConfiguration); si.getMember("sslCipherList", config.sslCipherList); si.getMember("sslProtocols", config.sslProtocols); config.config = si; const cxxtools::SerializationInfo* p = si.findMember("environment"); if (p) { for (cxxtools::SerializationInfo::ConstIterator it = p->begin(); it != p->end(); ++it) { std::string value; it->getValue(value); config.environment[it->name()] = value; } } } TntConfig::TntConfig() : maxRequestSize(0), maxRequestTime(600), daemon(false), minThreads(5), maxThreads(100), threadStartDelay(10), queueSize(1000), socketBufferSize(16384), socketReadTimeout(10), socketWriteTimeout(cxxtools::Seconds(10)), keepAliveTimeout(cxxtools::Seconds(30)), keepAliveMax(1000), sessionTimeout(300), listenBacklog(512), listenRetry(5), enableCompression(true), minCompressSize(1024), mimeDb("/etc/mime.types"), maxUrlMapCache(8192), defaultContentType("text/html; charset=UTF-8"), timerSleep(10), server("Tntnet/" VERSION), reuseAddress(true) { } TntConfig& TntConfig::it() { static TntConfig theConfig; return theConfig; } } tntnet-3.0/framework/common/tntnet.cpp000066400000000000000000000100761365471676700202270ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/tntnet.h" #include "tntnetimpl.h" namespace tnt { //////////////////////////////////////////////////////////////////////// // Tntnet // Tntnet::Tntnet() : _impl(new TntnetImpl()) { _impl->addRef(); } Tntnet::Tntnet(const Tntnet& t) : _impl(t._impl) { if (_impl) _impl->addRef(); } Tntnet::Tntnet(const TntConfig& config) : _impl(new TntnetImpl()) { _impl->addRef(); init(config); } Tntnet& Tntnet::operator= (const Tntnet& t) { if (_impl == t._impl) return *this; if (_impl && _impl->release() == 0) delete _impl; _impl = t._impl; if (_impl) _impl->addRef(); return *this; } void Tntnet::init(const TntConfig& config) { _impl->init(*this, config); } void Tntnet::listen(const std::string& ip, unsigned short int port) { _impl->listen(*this, ip, port); } void Tntnet::sslListen(const std::string& ipaddr, unsigned short int port, const std::string& certificateFile, const std::string& keyFile, int sslVerifyLevel, const std::string& sslCa) { _impl->sslListen(*this, ipaddr, port, certificateFile, keyFile, sslVerifyLevel, sslCa); } void Tntnet::run() { _impl->run(); } unsigned Tntnet::getMinThreads() const { return _impl->getMinThreads(); } void Tntnet::setMinThreads(unsigned n) { _impl->setMinThreads(n); } unsigned Tntnet::getMaxThreads() const { return _impl->getMaxThreads(); } void Tntnet::setMaxThreads(unsigned n) { _impl->setMaxThreads(n); } void Tntnet::shutdown() { TntnetImpl::shutdown(); } bool Tntnet::shouldStop() { return TntnetImpl::shouldStop(); } Mapping& Tntnet::mapUrl(const std::string& url, const std::string& ci) { return _impl->mapUrl(url, Maptarget(ci)); } Mapping& Tntnet::mapUrl(const std::string& url, const Compident& ci) { return _impl->mapUrl(url, Maptarget(ci)); } void Tntnet::mapUrl(const std::string& url, const std::string& pathinfo, const std::string& ci) { _impl->mapUrl(url, Maptarget(ci)).setPathInfo(pathinfo); } Mapping& Tntnet::mapUrl(const std::string& url, const Maptarget& ci) { return _impl->mapUrl(url, ci); } Mapping& Tntnet::vMapUrl(const std::string& vhost, const std::string& url, const Maptarget& ci) { return _impl->vMapUrl(vhost, url, ci); } void Tntnet::setAppName(const std::string& appname) { _impl->setAppName(appname); } /// Get the app name – for details see setAppName() const std::string& Tntnet::getAppName() const { return _impl->getAppName(); } void Tntnet::setAccessLog(const std::string& logfile_path) { _impl->setAccessLog(logfile_path); } } tntnet-3.0/framework/common/tntnetimpl.cpp000066400000000000000000000214621365471676700211120ustar00rootroot00000000000000/* * Copyright (C) 2015 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tntnetimpl.h" #include "tnt/worker.h" #include "tnt/listener.h" #include "tnt/http.h" #include "tnt/httpreply.h" #include "tnt/sessionscope.h" #include "tnt/tntconfig.h" #include "tnt/util.h" #include #include #include #include #include #include log_define("tntnet.tntnet.impl") namespace tnt { namespace { void configureDispatcher(Dispatcher& dis) { const TntConfig::MappingsType& mappings = TntConfig::it().mappings; for (TntConfig::MappingsType::const_iterator it = mappings.begin(); it != mappings.end(); ++it) { Maptarget ci(it->target); if (!it->pathinfo.empty()) ci.setPathInfo(it->pathinfo); ci.setHttpReturn(it->httpreturn); ci.setArgs(it->args); dis.addUrlMapEntry(it->vhost, it->url, it->method, it->ssl, ci); } } typedef std::set TntnetInstancesType; cxxtools::Mutex allTntnetInstancesMutex; TntnetInstancesType allRunningTntnetInstances; } //////////////////////////////////////////////////////////////////////// // Tntnet // TntnetImpl::TntnetImpl() : _minthreads(TntConfig::it().minThreads), _maxthreads(TntConfig::it().maxThreads), _pollerthread(cxxtools::callable(_poller, &Poller::run)), _poller(_queue) { } bool TntnetImpl::_stop = false; cxxtools::Mutex TntnetImpl::_timeStopMutex; cxxtools::Condition TntnetImpl::_timerStopCondition; TntnetImpl::listeners_type TntnetImpl::_allListeners; void TntnetImpl::init(Tntnet& app, const TntConfig& config) { TntConfig::it() = config; log_init(config.logConfiguration); _minthreads = config.minThreads; _maxthreads = config.maxThreads; _queue.setCapacity(config.queueSize); for (TntConfig::EnvironmentType::const_iterator it = config.environment.begin(); it != config.environment.end(); ++it) { std::string name = it->first; std::string value = it->second; #ifdef HAVE_SETENV log_debug("setenv " << name << "=\"" << value << '"'); ::setenv(name.c_str(), value.c_str(), 1); #else char* env = new char[name.size() + value.size() + 2]; name.copy(env, name.size()); env[name.size()] = '='; value.copy(env + name.size() + 1, value.size()); env[name.size() + value.size() + 1] = '\0'; log_debug("putenv(" << env << ')'); ::putenv(env); #endif } configureDispatcher(_dispatcher); // initialize listeners for (TntConfig::ListenersType::const_iterator it = config.listeners.begin(); it != config.listeners.end(); ++it) { listen(app, it->ip, it->port); } for (TntConfig::SslListenersType::const_iterator it = config.ssllisteners.begin(); it != config.ssllisteners.end(); ++it) { sslListen(app, it->ip, it->port, it->certificate, it->key, it->sslVerifyLevel, it->sslCa); } } void TntnetImpl::listen(Tntnet& app, const std::string& ip, unsigned short int port) { log_debug("listen on ip " << ip << " port " << port); Listener* listener = new Listener(app, ip, port, _queue); _listeners.insert(listener); _allListeners.insert(listener); } void TntnetImpl::sslListen(Tntnet& app, const std::string& ipaddr, unsigned short int port, const std::string& certificateFile, const std::string& keyFile, int sslVerifyLevel, const std::string& sslCa) { log_debug("listen on ip " << ipaddr << " port " << port << " (ssl)"); Listener* listener = new Listener(app, ipaddr, port, _queue, certificateFile, keyFile, sslVerifyLevel, sslCa); _listeners.insert(listener); _allListeners.insert(listener); } void TntnetImpl::run() { log_debug("worker-process"); _stop = false; if (_listeners.empty()) throwRuntimeError("no listeners defined"); log_debug(_listeners.size() << " listeners"); if (_listeners.size() >= _minthreads) { log_warn("at least one more worker than listeners needed - set MinThreads to " << _listeners.size() + 1); _minthreads = _listeners.size() + 1; } if (_maxthreads < _minthreads) { log_warn("MaxThreads < MinThreads - set MaxThreads = MinThreads = " << _minthreads); _maxthreads = _minthreads; } // initialize worker-process // SIGPIPE must be ignored struct sigaction sa; sa.sa_handler = SIG_IGN; sa.sa_flags = 0; if (sigaction(SIGPIPE, &sa, 0) == -1) cxxtools::throwSystemError("sigaction"); // create worker-threads log_info("create " << _minthreads << " worker threads"); for (unsigned i = 0; i < _minthreads; ++i) { log_debug("create worker " << i); Worker* s = new Worker(*this); s->create(); } // create poller-thread log_debug("start poller thread"); _pollerthread.start(); log_debug("start timer thread"); cxxtools::AttachedThread timerThread(cxxtools::callable(*this, &TntnetImpl::timerTask)); timerThread.start(); { cxxtools::MutexLock lock(allTntnetInstancesMutex); allRunningTntnetInstances.insert(this); } // mainloop cxxtools::Mutex mutex; while (!_stop) { { cxxtools::MutexLock lock(mutex); _queue.noWaitThreads.wait(lock); } if (_stop) break; if (Worker::getCountThreads() < _maxthreads) { log_info("create workerthread"); Worker* s = new Worker(*this); s->create(); } else log_info("max worker-threadcount " << _maxthreads << " reached"); if (TntConfig::it().threadStartDelay > 0) usleep(TntConfig::it().threadStartDelay.totalUSecs()); } log_info("stopping TntnetImpl"); { cxxtools::MutexLock lock(allTntnetInstancesMutex); allRunningTntnetInstances.erase(this); } log_info("stop listener"); for (listeners_type::iterator it = _listeners.begin(); it != _listeners.end(); ++it) (*it)->terminate(); log_info("stop poller thread"); _poller.doStop(); _pollerthread.join(); log_info("stop timer thread"); timerThread.join(); if (Worker::getCountThreads() > 0) { log_info("wait for " << Worker::getCountThreads() << " worker threads to stop"); while (Worker::getCountThreads() > 0) { log_debug("wait for worker threads to stop; " << Worker::getCountThreads() << " left"); usleep(100); } } log_debug("destroy listener"); for (listeners_type::iterator it = _listeners.begin(); it != _listeners.end(); ++it) delete *it; _listeners.clear(); HttpReply::postRunCleanup(); HttpRequest::postRunCleanup(); log_info("all threads stopped"); } void TntnetImpl::setMinThreads(unsigned n) { if (_listeners.size() >= n) { log_warn("at least one more worker than listeners needed - set MinThreads to " << _listeners.size() + 1); _minthreads = _listeners.size() + 1; } else _minthreads = n; } void TntnetImpl::timerTask() { log_debug("timer thread"); while (true) { { cxxtools::MutexLock timeStopLock(_timeStopMutex); if (_stop || _timerStopCondition.wait(timeStopLock, TntConfig::it().timerSleep)) break; } getScopemanager().checkSessionTimeout(); Worker::timer(); } _queue.noWaitThreads.signal(); _minthreads = _maxthreads = 0; } void TntnetImpl::shutdown() { _stop = true; _timerStopCondition.broadcast(); } } tntnet-3.0/framework/common/tntnetimpl.h000066400000000000000000000065011365471676700205540ustar00rootroot00000000000000/* * Copyright (C) 2015 Tommi Maekitalo * */ #ifndef TNTNETIMPL_H #define TNTNETIMPL_H #include #include #include #include #include #include #include #include #include #include namespace tnt { class Listener; struct TntConfig; class TntnetImpl : public cxxtools::RefCounted { friend class Worker; typedef std::set listeners_type; unsigned _minthreads; unsigned _maxthreads; Jobqueue _queue; static bool _stop; listeners_type _listeners; static listeners_type _allListeners; cxxtools::AttachedThread _pollerthread; Poller _poller; Dispatcher _dispatcher; ScopeManager _scopemanager; std::string _appname; std::ofstream _accessLog; cxxtools::Mutex _accessLogMutex; void timerTask(); static cxxtools::Condition _timerStopCondition; static cxxtools::Mutex _timeStopMutex; // non copyable and assignable TntnetImpl(const TntnetImpl&); TntnetImpl& operator= (const TntnetImpl&); public: TntnetImpl(); void init(Tntnet& app, const TntConfig& config); void listen(Tntnet& app, const std::string& ipaddr, unsigned short int port); void sslListen(Tntnet& app, const std::string& ipaddr, unsigned short int port, const std::string& certificateFile, const std::string& keyFile, int sslVerifyLevel, const std::string& sslCa); void run(); static void shutdown(); static bool shouldStop() { return _stop; } Jobqueue& getQueue() { return _queue; } Poller& getPoller() { return _poller; } const Dispatcher& getDispatcher() const { return _dispatcher; } ScopeManager& getScopemanager() { return _scopemanager; } unsigned getMinThreads() const { return _minthreads; } void setMinThreads(unsigned n); unsigned getMaxThreads() const { return _maxthreads; } void setMaxThreads(unsigned n) { _maxthreads = n; } Mapping& mapUrl(const std::string& url, const std::string& ci) { return _dispatcher.addUrlMapEntry(std::string(), url, Maptarget(ci)); } Mapping& mapUrl(const std::string& url, const Compident& ci) { return _dispatcher.addUrlMapEntry(std::string(), url, Maptarget(ci)); } void mapUrl(const std::string& url, const std::string& pathinfo, const std::string& ci) { _dispatcher.addUrlMapEntry(std::string(), url, Maptarget(ci)).setPathInfo(pathinfo); } Mapping& mapUrl(const std::string& url, const Maptarget& ci) { return _dispatcher.addUrlMapEntry(std::string(), url, ci); } Mapping& vMapUrl(const std::string& vhost, const std::string& url, const Maptarget& ci) { return _dispatcher.addUrlMapEntry(vhost, url, ci); } void setAppName(const std::string& appname) { _appname = appname; } const std::string& getAppName() const { return _appname; } void setAccessLog(const std::string& logfile_path) { _accessLog.open(logfile_path.c_str(), std::ios::out | std::ios::app); } }; } #endif // TNTNETIMPL_H tntnet-3.0/framework/common/unzip.c000066400000000000000000002127641365471676700175300ustar00rootroot00000000000000/* unzip.c -- IO for uncompress .zip files using zlib Version 1.1, February 14h, 2010 part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) Modifications of Unzip for Zip64 Copyright (C) 2007-2008 Even Rouault Modifications for Zip64 support on both zip and unzip Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) For more info read MiniZip_info.txt ------------------------------------------------------------------------------------ Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of compatibility with older software. The following is from the original crypt.c. Code woven in by Terry Thorsen 1/2003. Copyright (c) 1990-2000 Info-ZIP. All rights reserved. See the accompanying file LICENSE, version 2000-Apr-09 or later (the contents of which are also included in zip.h) for terms of use. If, for some reason, all these files are missing, the Info-ZIP license also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] The encryption/decryption parts of this source code (as opposed to the non-echoing password parts) were originally written in Europe. The whole source package can be freely distributed, including from the USA. (Prior to January 2000, re-export from the US was a violation of US law.) This encryption code is a direct transcription of the algorithm from Roger Schlafly, described by Phil Katz in the file appnote.txt. This file (appnote.txt) is distributed with the PKZIP program (even in the version without encryption capabilities). ------------------------------------------------------------------------------------ Changes in unzip.c 2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz* 2007-2008 - Even Rouault - Remove old C style function prototypes 2007-2008 - Even Rouault - Add unzip support for ZIP64 Copyright (C) 2007-2008 Even Rouault Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G should only read the compressed/uncompressed size from the Zip64 format if the size from normal header was 0xFFFFFFFF Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required) Patch created by Daniel Borca Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson */ #include #include #include #ifndef NOUNCRYPT #define NOUNCRYPT #endif #include "zlib.h" #include "unzip.h" #ifdef STDC # include # include # include #endif #ifdef NO_ERRNO_H extern int errno; #else # include #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ #ifndef CASESENSITIVITYDEFAULT_NO # if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) # define CASESENSITIVITYDEFAULT_NO # endif #endif #ifndef UNZ_BUFSIZE #define UNZ_BUFSIZE (16384) #endif #ifndef UNZ_MAXFILENAMEINZIP #define UNZ_MAXFILENAMEINZIP (256) #endif #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif #ifndef TRYFREE # define TRYFREE(p) {if (p) free(p);} #endif #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) const char unz_copyright[] = " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; /* unz_file_info_interntal contain internal info about a file in zipfile*/ typedef struct unz_file_info64_internal_s { ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */ } unz_file_info64_internal; /* file_in_zip_read_info_s contain internal information about a file in zipfile, when reading and decompress it */ typedef struct { char *read_buffer; /* internal buffer for compressed data */ z_stream stream; /* zLib stream structure for inflate */ #ifdef HAVE_BZIP2 bz_stream bstream; /* bzLib stream structure for bziped */ #endif ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ uLong stream_initialised; /* flag set if stream structure is initialised*/ ZPOS64_T offset_local_extrafield;/* offset of the local extra field */ uInt size_local_extrafield;/* size of the local extra field */ ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/ ZPOS64_T total_out_64; uLong crc32; /* crc32 of all data uncompressed */ uLong crc32_wait; /* crc32 we must obtain after decompress all */ ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ zlib_filefunc64_32_def z_filefunc; voidpf filestream; /* io structore of the zipfile */ uLong compression_method; /* compression method (0==store) */ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ int raw; } file_in_zip64_read_info_s; /* unz64_s contain internal information about the zipfile */ typedef struct { zlib_filefunc64_32_def z_filefunc; int is64bitOpenFunction; voidpf filestream; /* io structore of the zipfile */ unz_global_info64 gi; /* public global information */ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ ZPOS64_T num_file; /* number of the current file in the zipfile*/ ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ ZPOS64_T central_pos; /* position of the beginning of the central dir*/ ZPOS64_T size_central_dir; /* size of the central directory */ ZPOS64_T offset_central_dir; /* offset of start of central directory with respect to the starting disk number */ unz_file_info64 cur_file_info; /* public info about the current file in zip*/ unz_file_info64_internal cur_file_info_internal; /* private info about it*/ file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current file if we are decompressing it */ int encrypted; int isZip64; # ifndef NOUNCRYPT unsigned long keys[3]; /* keys defining the pseudo-random sequence */ const z_crc_t* pcrc_32_tab; # endif } unz64_s; #ifndef NOUNCRYPT #include "crypt.h" #endif /* =========================================================================== Read a byte from a gz_stream; update next_in and avail_in. Return EOF for end of file. IN assertion: the stream s has been sucessfully opened for reading. */ local int unz64local_getByte OF(( const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)); local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi) { unsigned char c; int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); if (err==1) { *pi = (int)c; return UNZ_OK; } else { if (ZERROR64(*pzlib_filefunc_def,filestream)) return UNZ_ERRNO; else return UNZ_EOF; } } /* =========================================================================== Reads a long in LSB order from the given gz_stream. Sets */ local int unz64local_getShort OF(( const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX) { uLong x ; int i = 0; int err; err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((uLong)i)<<8; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } local int unz64local_getLong OF(( const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX) { uLong x ; int i = 0; int err; err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((uLong)i)<<8; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((uLong)i)<<16; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<24; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } local int unz64local_getLong64 OF(( const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) { ZPOS64_T x ; int i = 0; int err; err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x = (ZPOS64_T)i; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<8; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<16; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<24; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<32; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<40; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<48; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<56; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } /* My own strcmpi / strcasecmp */ local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2) { for (;;) { char c1=*(fileName1++); char c2=*(fileName2++); if ((c1>='a') && (c1<='z')) c1 -= 0x20; if ((c2>='a') && (c2<='z')) c2 -= 0x20; if (c1=='\0') return ((c2=='\0') ? 0 : -1); if (c2=='\0') return 1; if (c1c2) return 1; } } #ifdef CASESENSITIVITYDEFAULT_NO #define CASESENSITIVITYDEFAULTVALUE 2 #else #define CASESENSITIVITYDEFAULTVALUE 1 #endif #ifndef STRCMPCASENOSENTIVEFUNCTION #define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal #endif /* Compare two filename (fileName1,fileName2). If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi or strcasecmp) If iCaseSenisivity = 0, case sensitivity is defaut of your operating system (like 1 on Unix, 2 on Windows) */ extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, const char* fileName2, int iCaseSensitivity) { if (iCaseSensitivity==0) iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; if (iCaseSensitivity==1) return strcmp(fileName1,fileName2); return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); } #ifndef BUFREADCOMMENT #define BUFREADCOMMENT (0x400) #endif /* Locate the Central directory of a zipfile (at the end, just before the global comment) */ local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ ZPOS64_T uPosFound=0; if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) return 0; uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) return 0; uBackRead = 4; while (uBackReaduMaxBack) uBackRead = uMaxBack; else uBackRead+=BUFREADCOMMENT; uReadPos = uSizeFile-uBackRead ; uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) break; if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) { uPosFound = uReadPos+i; break; } if (uPosFound!=0) break; } TRYFREE(buf); return uPosFound; } /* Locate the Central directory 64 of a zipfile (at the end, just before the global comment) */ local ZPOS64_T unz64local_SearchCentralDir64 OF(( const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ ZPOS64_T uPosFound=0; uLong uL; ZPOS64_T relativeOffset; if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) return 0; uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) return 0; uBackRead = 4; while (uBackReaduMaxBack) uBackRead = uMaxBack; else uBackRead+=BUFREADCOMMENT; uReadPos = uSizeFile-uBackRead ; uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) break; if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) { uPosFound = uReadPos+i; break; } if (uPosFound!=0) break; } TRYFREE(buf); if (uPosFound == 0) return 0; /* Zip64 end of central directory locator */ if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) return 0; /* the signature, already checked */ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) return 0; /* number of the disk with the start of the zip64 end of central directory */ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) return 0; if (uL != 0) return 0; /* relative offset of the zip64 end of central directory record */ if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK) return 0; /* total number of disks */ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) return 0; if (uL != 1) return 0; /* Goto end of central directory record */ if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) return 0; /* the signature */ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) return 0; if (uL != 0x06064b50) return 0; return relativeOffset; } /* Open a Zip file. path contain the full pathname (by example, on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer "zlib/zlib114.zip". If the zipfile cannot be opened (file doesn't exist or in not valid), the return value is NULL. Else, the return value is a unzFile Handle, usable with other function of this unzip package. */ local unzFile unzOpenInternal (const void *path, zlib_filefunc64_32_def* pzlib_filefunc64_32_def, int is64bitOpenFunction) { unz64_s us; unz64_s *s; ZPOS64_T central_pos; uLong uL; uLong number_disk; /* number of the current dist, used for spaning ZIP, unsupported, always 0*/ uLong number_disk_with_CD; /* number the the disk with central dir, used for spaning ZIP, unsupported, always 0*/ ZPOS64_T number_entry_CD; /* total number of entries in the central dir (same than number_entry on nospan) */ int err=UNZ_OK; if (unz_copyright[0]!=' ') return NULL; us.num_file = 0; us.z_filefunc.zseek32_file = NULL; us.z_filefunc.ztell32_file = NULL; if (pzlib_filefunc64_32_def==NULL) fill_fopen64_filefunc(&us.z_filefunc.zfile_func64); else us.z_filefunc = *pzlib_filefunc64_32_def; us.is64bitOpenFunction = is64bitOpenFunction; us.filestream = ZOPEN64(us.z_filefunc, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING); if (us.filestream==NULL) return NULL; central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream); if (central_pos) { uLong uS; ZPOS64_T uL64; us.isZip64 = 1; if (ZSEEK64(us.z_filefunc, us.filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) err=UNZ_ERRNO; /* the signature, already checked */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; /* size of zip64 end of central directory record */ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK) err=UNZ_ERRNO; /* version made by */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) err=UNZ_ERRNO; /* version needed to extract */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) err=UNZ_ERRNO; /* number of this disk */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) err=UNZ_ERRNO; /* number of the disk with the start of the central directory */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) err=UNZ_ERRNO; /* total number of entries in the central directory on this disk */ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) err=UNZ_ERRNO; /* total number of entries in the central directory */ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) err=UNZ_ERRNO; if ((number_entry_CD!=us.gi.number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=UNZ_BADZIPFILE; /* size of the central directory */ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) err=UNZ_ERRNO; /* offset of start of central directory with respect to the starting disk number */ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) err=UNZ_ERRNO; us.gi.size_comment = 0; } else { central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream); if (central_pos==0) err=UNZ_ERRNO; us.isZip64 = 0; if (ZSEEK64(us.z_filefunc, us.filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) err=UNZ_ERRNO; /* the signature, already checked */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; /* number of this disk */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) err=UNZ_ERRNO; /* number of the disk with the start of the central directory */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) err=UNZ_ERRNO; /* total number of entries in the central dir on this disk */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; us.gi.number_entry = uL; /* total number of entries in the central dir */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; number_entry_CD = uL; if ((number_entry_CD!=us.gi.number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=UNZ_BADZIPFILE; /* size of the central directory */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; us.size_central_dir = uL; /* offset of start of central directory with respect to the starting disk number */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; us.offset_central_dir = uL; /* zipfile comment length */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) err=UNZ_ERRNO; } if ((central_pospfile_in_zip_read!=NULL) unzCloseCurrentFile(file); ZCLOSE64(s->z_filefunc, s->filestream); TRYFREE(s); return UNZ_OK; } /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info) { unz64_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; *pglobal_info=s->gi; return UNZ_OK; } extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32) { unz64_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; /* to do : check if number_entry is not truncated */ pglobal_info32->number_entry = (uLong)s->gi.number_entry; pglobal_info32->size_comment = s->gi.size_comment; return UNZ_OK; } /* Translate date/time from Dos format to tm_unz (readable more easilty) */ local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) { ZPOS64_T uDate; uDate = (ZPOS64_T)(ulDosDate>>16); ptm->tm_mday = (uInt)(uDate&0x1f) ; ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; } /* Get Info about the current file in the zipfile, with internal only info */ local int unz64local_GetCurrentFileInfoInternal OF((unzFile file, unz_file_info64 *pfile_info, unz_file_info64_internal *pfile_info_internal, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize)); local int unz64local_GetCurrentFileInfoInternal (unzFile file, unz_file_info64 *pfile_info, unz_file_info64_internal *pfile_info_internal, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize) { unz64_s* s; unz_file_info64 file_info; unz_file_info64_internal file_info_internal; int err=UNZ_OK; uLong uMagic; long lSeek=0; uLong uL; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; if (ZSEEK64(s->z_filefunc, s->filestream, s->pos_in_central_dir+s->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET)!=0) err=UNZ_ERRNO; /* we check the magic */ if (err==UNZ_OK) { if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) err=UNZ_ERRNO; else if (uMagic!=0x02014b50) err=UNZ_BADZIPFILE; } if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) err=UNZ_ERRNO; unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) err=UNZ_ERRNO; file_info.compressed_size = uL; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) err=UNZ_ERRNO; file_info.uncompressed_size = uL; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) err=UNZ_ERRNO; /* relative offset of local header */ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) err=UNZ_ERRNO; file_info_internal.offset_curfile = uL; lSeek+=file_info.size_filename; if ((err==UNZ_OK) && (szFileName!=NULL)) { uLong uSizeRead ; if (file_info.size_filename0) && (fileNameBufferSize>0)) if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) err=UNZ_ERRNO; lSeek -= uSizeRead; } /* Read extrafield */ if ((err==UNZ_OK) && (extraField!=NULL)) { ZPOS64_T uSizeRead ; if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) lSeek=0; else err=UNZ_ERRNO; } if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead) err=UNZ_ERRNO; lSeek += file_info.size_file_extra - (uLong)uSizeRead; } else lSeek += file_info.size_file_extra; if ((err==UNZ_OK) && (file_info.size_file_extra != 0)) { uLong acc = 0; /* since lSeek now points to after the extra field we need to move back */ lSeek -= file_info.size_file_extra; if (lSeek!=0) { if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) lSeek=0; else err=UNZ_ERRNO; } while(acc < file_info.size_file_extra) { uLong headerId; uLong dataSize; if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK) err=UNZ_ERRNO; /* ZIP64 extra fields */ if (headerId == 0x0001) { uLong uL; if(file_info.uncompressed_size == MAXU32) { if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) err=UNZ_ERRNO; } if(file_info.compressed_size == MAXU32) { if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) err=UNZ_ERRNO; } if(file_info_internal.offset_curfile == MAXU32) { /* Relative Header offset */ if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) err=UNZ_ERRNO; } if(file_info.disk_num_start == MAXU32) { /* Disk Start Number */ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) err=UNZ_ERRNO; } } else { if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0) err=UNZ_ERRNO; } acc += 2 + 2 + dataSize; } } if ((err==UNZ_OK) && (szComment!=NULL)) { uLong uSizeRead ; if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) lSeek=0; else err=UNZ_ERRNO; } if ((file_info.size_file_comment>0) && (commentBufferSize>0)) if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) err=UNZ_ERRNO; lSeek+=file_info.size_file_comment - uSizeRead; } else lSeek+=file_info.size_file_comment; if ((err==UNZ_OK) && (pfile_info!=NULL)) *pfile_info=file_info; if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) *pfile_info_internal=file_info_internal; return err; } /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file, unz_file_info64 * pfile_info, char * szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char* szComment, uLong commentBufferSize) { return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL, szFileName,fileNameBufferSize, extraField,extraFieldBufferSize, szComment,commentBufferSize); } extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, unz_file_info * pfile_info, char * szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char* szComment, uLong commentBufferSize) { int err; unz_file_info64 file_info64; err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL, szFileName,fileNameBufferSize, extraField,extraFieldBufferSize, szComment,commentBufferSize); if ((err==UNZ_OK) && (pfile_info != NULL)) { pfile_info->version = file_info64.version; pfile_info->version_needed = file_info64.version_needed; pfile_info->flag = file_info64.flag; pfile_info->compression_method = file_info64.compression_method; pfile_info->dosDate = file_info64.dosDate; pfile_info->crc = file_info64.crc; pfile_info->size_filename = file_info64.size_filename; pfile_info->size_file_extra = file_info64.size_file_extra; pfile_info->size_file_comment = file_info64.size_file_comment; pfile_info->disk_num_start = file_info64.disk_num_start; pfile_info->internal_fa = file_info64.internal_fa; pfile_info->external_fa = file_info64.external_fa; pfile_info->tmu_date = file_info64.tmu_date, pfile_info->compressed_size = (uLong)file_info64.compressed_size; pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; } return err; } /* Set the current file of the zipfile to the first file. return UNZ_OK if there is no problem */ extern int ZEXPORT unzGoToFirstFile (unzFile file) { int err=UNZ_OK; unz64_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; s->pos_in_central_dir=s->offset_central_dir; s->num_file=0; err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } /* Set the current file of the zipfile to the next file. return UNZ_OK if there is no problem return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. */ extern int ZEXPORT unzGoToNextFile (unzFile file) { unz64_s* s; int err; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ if (s->num_file+1==s->gi.number_entry) return UNZ_END_OF_LIST_OF_FILE; s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; s->num_file++; err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } /* Try locate the file szFileName in the zipfile. For the iCaseSensitivity signification, see unzStringFileNameCompare return value : UNZ_OK if the file is found. It becomes the current file. UNZ_END_OF_LIST_OF_FILE if the file is not found */ extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) { unz64_s* s; int err; /* We remember the 'current' position in the file so that we can jump * back there if we fail. */ unz_file_info64 cur_file_infoSaved; unz_file_info64_internal cur_file_info_internalSaved; ZPOS64_T num_fileSaved; ZPOS64_T pos_in_central_dirSaved; if (file==NULL) return UNZ_PARAMERROR; if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) return UNZ_PARAMERROR; s=(unz64_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; /* Save the current state */ num_fileSaved = s->num_file; pos_in_central_dirSaved = s->pos_in_central_dir; cur_file_infoSaved = s->cur_file_info; cur_file_info_internalSaved = s->cur_file_info_internal; err = unzGoToFirstFile(file); while (err == UNZ_OK) { char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; err = unzGetCurrentFileInfo64(file,NULL, szCurrentFileName,sizeof(szCurrentFileName)-1, NULL,0,NULL,0); if (err == UNZ_OK) { if (unzStringFileNameCompare(szCurrentFileName, szFileName,iCaseSensitivity)==0) return UNZ_OK; err = unzGoToNextFile(file); } } /* We failed, so restore the state of the 'current file' to where we * were. */ s->num_file = num_fileSaved ; s->pos_in_central_dir = pos_in_central_dirSaved ; s->cur_file_info = cur_file_infoSaved; s->cur_file_info_internal = cur_file_info_internalSaved; return err; } /* /////////////////////////////////////////// // Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) // I need random access // // Further optimization could be realized by adding an ability // to cache the directory in memory. The goal being a single // comprehensive file read to put the file I need in a memory. */ /* typedef struct unz_file_pos_s { ZPOS64_T pos_in_zip_directory; // offset in file ZPOS64_T num_of_file; // # of file } unz_file_pos; */ extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) { unz64_s* s; if (file==NULL || file_pos==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; file_pos->pos_in_zip_directory = s->pos_in_central_dir; file_pos->num_of_file = s->num_file; return UNZ_OK; } extern int ZEXPORT unzGetFilePos( unzFile file, unz_file_pos* file_pos) { unz64_file_pos file_pos64; int err = unzGetFilePos64(file,&file_pos64); if (err==UNZ_OK) { file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; file_pos->num_of_file = (uLong)file_pos64.num_of_file; } return err; } extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) { unz64_s* s; int err; if (file==NULL || file_pos==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; /* jump to the right spot */ s->pos_in_central_dir = file_pos->pos_in_zip_directory; s->num_file = file_pos->num_of_file; /* set the current file */ err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); /* return results */ s->current_file_ok = (err == UNZ_OK); return err; } extern int ZEXPORT unzGoToFilePos( unzFile file, unz_file_pos* file_pos) { unz64_file_pos file_pos64; if (file_pos == NULL) return UNZ_PARAMERROR; file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; file_pos64.num_of_file = file_pos->num_of_file; return unzGoToFilePos64(file,&file_pos64); } /* // Unzip Helper Functions - should be here? /////////////////////////////////////////// */ /* Read the local header of the current zipfile Check the coherency of the local header and info in the end of central directory about this file store in *piSizeVar the size of extra info in local header (filename and size of extra field data) */ local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar, ZPOS64_T * poffset_local_extrafield, uInt * psize_local_extrafield) { uLong uMagic,uData,uFlags; uLong size_filename; uLong size_extra_field; int err=UNZ_OK; *piSizeVar = 0; *poffset_local_extrafield = 0; *psize_local_extrafield = 0; if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (err==UNZ_OK) { if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) err=UNZ_ERRNO; else if (uMagic!=0x04034b50) err=UNZ_BADZIPFILE; } if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) err=UNZ_ERRNO; /* else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) err=UNZ_BADZIPFILE; */ if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) err=UNZ_BADZIPFILE; if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && /* #ifdef HAVE_BZIP2 */ (s->cur_file_info.compression_method!=Z_BZIP2ED) && /* #endif */ (s->cur_file_info.compression_method!=Z_DEFLATED)) err=UNZ_BADZIPFILE; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ err=UNZ_ERRNO; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ err=UNZ_ERRNO; else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ err=UNZ_ERRNO; else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) err=UNZ_ERRNO; else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) err=UNZ_BADZIPFILE; *piSizeVar += (uInt)size_filename; if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) err=UNZ_ERRNO; *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_filename; *psize_local_extrafield = (uInt)size_extra_field; *piSizeVar += (uInt)size_extra_field; return err; } /* Open for reading data the current file in the zipfile. If there is no error and the file is opened, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, int* level, int raw, const char* password) { int err=UNZ_OK; uInt iSizeVar; unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ uInt size_local_extrafield; /* size of the local extra field */ # ifndef NOUNCRYPT char source[12]; # else if (password != NULL) return UNZ_PARAMERROR; # endif if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; if (!s->current_file_ok) return UNZ_PARAMERROR; if (s->pfile_in_zip_read != NULL) unzCloseCurrentFile(file); if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) return UNZ_BADZIPFILE; pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s)); if (pfile_in_zip_read_info==NULL) return UNZ_INTERNALERROR; pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; pfile_in_zip_read_info->pos_local_extrafield=0; pfile_in_zip_read_info->raw=raw; if (pfile_in_zip_read_info->read_buffer==NULL) { TRYFREE(pfile_in_zip_read_info); return UNZ_INTERNALERROR; } pfile_in_zip_read_info->stream_initialised=0; if (method!=NULL) *method = (int)s->cur_file_info.compression_method; if (level!=NULL) { *level = 6; switch (s->cur_file_info.flag & 0x06) { case 6 : *level = 1; break; case 4 : *level = 2; break; case 2 : *level = 9; break; } } if ((s->cur_file_info.compression_method!=0) && /* #ifdef HAVE_BZIP2 */ (s->cur_file_info.compression_method!=Z_BZIP2ED) && /* #endif */ (s->cur_file_info.compression_method!=Z_DEFLATED)) err=UNZ_BADZIPFILE; pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; pfile_in_zip_read_info->crc32=0; pfile_in_zip_read_info->total_out_64=0; pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; pfile_in_zip_read_info->filestream=s->filestream; pfile_in_zip_read_info->z_filefunc=s->z_filefunc; pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; pfile_in_zip_read_info->stream.total_out = 0; if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw)) { #ifdef HAVE_BZIP2 pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; pfile_in_zip_read_info->bstream.bzfree = (free_func)0; pfile_in_zip_read_info->bstream.opaque = (voidpf)0; pfile_in_zip_read_info->bstream.state = (voidpf)0; pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; pfile_in_zip_read_info->stream.zfree = (free_func)0; pfile_in_zip_read_info->stream.opaque = (voidpf)0; pfile_in_zip_read_info->stream.next_in = (voidpf)0; pfile_in_zip_read_info->stream.avail_in = 0; err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); if (err == Z_OK) pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; else { TRYFREE(pfile_in_zip_read_info); return err; } #else pfile_in_zip_read_info->raw=1; #endif } else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw)) { pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; pfile_in_zip_read_info->stream.zfree = (free_func)0; pfile_in_zip_read_info->stream.opaque = (voidpf)0; pfile_in_zip_read_info->stream.next_in = 0; pfile_in_zip_read_info->stream.avail_in = 0; err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); if (err == Z_OK) pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; else { TRYFREE(pfile_in_zip_read_info); return err; } /* windowBits is passed < 0 to tell that there is no zlib header. * Note that in this case inflate *requires* an extra "dummy" byte * after the compressed stream in order to complete decompression and * return Z_STREAM_END. * In unzip, i don't wait absolutely Z_STREAM_END because I known the * size of both compressed and uncompressed data */ } pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size ; pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size ; pfile_in_zip_read_info->pos_in_zipfile = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar; pfile_in_zip_read_info->stream.avail_in = (uInt)0; s->pfile_in_zip_read = pfile_in_zip_read_info; s->encrypted = 0; # ifndef NOUNCRYPT if (password != NULL) { int i; s->pcrc_32_tab = get_crc_table(); init_keys(password,s->keys,s->pcrc_32_tab); if (ZSEEK64(s->z_filefunc, s->filestream, s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile, SEEK_SET)!=0) return UNZ_INTERNALERROR; if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12) return UNZ_INTERNALERROR; for (i = 0; i<12; i++) zdecode(s->keys,s->pcrc_32_tab,source[i]); s->pfile_in_zip_read->pos_in_zipfile+=12; s->encrypted=1; } # endif return UNZ_OK; } extern int ZEXPORT unzOpenCurrentFile (unzFile file) { return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); } extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password) { return unzOpenCurrentFile3(file, NULL, NULL, 0, password); } extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw) { return unzOpenCurrentFile3(file, method, level, raw, NULL); } /** Addition for GDAL : START */ extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; s=(unz64_s*)file; if (file==NULL) return 0; /*UNZ_PARAMERROR; */ pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return 0; /*UNZ_PARAMERROR; */ return pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile; } /** Addition for GDAL : END */ /* Read bytes from the current file. buf contain buffer where data must be copied len the size of buf. return the number of byte copied if somes bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) { int err=UNZ_OK; uInt iRead = 0; unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->read_buffer == NULL) return UNZ_END_OF_LIST_OF_FILE; if (len==0) return 0; pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; pfile_in_zip_read_info->stream.avail_out = (uInt)len; if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && (!(pfile_in_zip_read_info->raw))) pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_uncompressed; if ((len>pfile_in_zip_read_info->rest_read_compressed+ pfile_in_zip_read_info->stream.avail_in) && (pfile_in_zip_read_info->raw)) pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_compressed+ pfile_in_zip_read_info->stream.avail_in; while (pfile_in_zip_read_info->stream.avail_out>0) { if ((pfile_in_zip_read_info->stream.avail_in==0) && (pfile_in_zip_read_info->rest_read_compressed>0)) { uInt uReadThis = UNZ_BUFSIZE; if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; if (uReadThis == 0) return UNZ_EOF; if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (ZREAD64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, pfile_in_zip_read_info->read_buffer, uReadThis)!=uReadThis) return UNZ_ERRNO; # ifndef NOUNCRYPT if(s->encrypted) { uInt i; for(i=0;iread_buffer[i] = zdecode(s->keys,s->pcrc_32_tab, pfile_in_zip_read_info->read_buffer[i]); } # endif pfile_in_zip_read_info->pos_in_zipfile += uReadThis; pfile_in_zip_read_info->rest_read_compressed-=uReadThis; pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->read_buffer; pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; } if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) { uInt uDoCopy,i ; if ((pfile_in_zip_read_info->stream.avail_in == 0) && (pfile_in_zip_read_info->rest_read_compressed == 0)) return (iRead==0) ? UNZ_EOF : iRead; if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in) uDoCopy = pfile_in_zip_read_info->stream.avail_out ; else uDoCopy = pfile_in_zip_read_info->stream.avail_in ; for (i=0;istream.next_out+i) = *(pfile_in_zip_read_info->stream.next_in+i); pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy; pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, pfile_in_zip_read_info->stream.next_out, uDoCopy); pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; pfile_in_zip_read_info->stream.avail_in -= uDoCopy; pfile_in_zip_read_info->stream.avail_out -= uDoCopy; pfile_in_zip_read_info->stream.next_out += uDoCopy; pfile_in_zip_read_info->stream.next_in += uDoCopy; pfile_in_zip_read_info->stream.total_out += uDoCopy; iRead += uDoCopy; } else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) { #ifdef HAVE_BZIP2 uLong uTotalOutBefore,uTotalOutAfter; const Bytef *bufBefore; uLong uOutThis; pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in; pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; pfile_in_zip_read_info->bstream.total_in_hi32 = 0; pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out; pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; pfile_in_zip_read_info->bstream.total_out_hi32 = 0; uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32; bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out; err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32; uOutThis = uTotalOutAfter-uTotalOutBefore; pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in; pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out; pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; if (err==BZ_STREAM_END) return (iRead==0) ? UNZ_EOF : iRead; if (err!=BZ_OK) break; #endif } /* end Z_BZIP2ED */ else { ZPOS64_T uTotalOutBefore,uTotalOutAfter; const Bytef *bufBefore; ZPOS64_T uOutThis; int flush=Z_SYNC_FLUSH; uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; bufBefore = pfile_in_zip_read_info->stream.next_out; /* if ((pfile_in_zip_read_info->rest_read_uncompressed == pfile_in_zip_read_info->stream.avail_out) && (pfile_in_zip_read_info->rest_read_compressed == 0)) flush = Z_FINISH; */ err=inflate(&pfile_in_zip_read_info->stream,flush); if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) err = Z_DATA_ERROR; uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; uOutThis = uTotalOutAfter-uTotalOutBefore; pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); if (err==Z_STREAM_END) return (iRead==0) ? UNZ_EOF : iRead; if (err!=Z_OK) break; } } if (err==Z_OK) return iRead; return err; } /* Give the current position in uncompressed data */ extern z_off_t ZEXPORT unztell (unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; return (z_off_t)pfile_in_zip_read_info->stream.total_out; } extern ZPOS64_T ZEXPORT unztell64 (unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return (ZPOS64_T)-1; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return (ZPOS64_T)-1; return pfile_in_zip_read_info->total_out_64; } /* return 1 if the end of file was reached, 0 elsewhere */ extern int ZEXPORT unzeof (unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->rest_read_uncompressed == 0) return 1; else return 0; } /* Read extra field from the current file (opened by unzOpenCurrentFile) This is the local-header version of the extra field (sometimes, there is more info in the local-header version than in the central-header) if buf==NULL, it return the size of the local extra field that can be read if buf!=NULL, len is the size of the buffer, the extra header is copied in buf. the return value is the number of bytes copied in buf, or (if <0) the error code */ extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; uInt read_now; ZPOS64_T size_to_read; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; size_to_read = (pfile_in_zip_read_info->size_local_extrafield - pfile_in_zip_read_info->pos_local_extrafield); if (buf==NULL) return (int)size_to_read; if (len>size_to_read) read_now = (uInt)size_to_read; else read_now = (uInt)len ; if (read_now==0) return 0; if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, pfile_in_zip_read_info->offset_local_extrafield + pfile_in_zip_read_info->pos_local_extrafield, ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (ZREAD64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, buf,read_now)!=read_now) return UNZ_ERRNO; return (int)read_now; } /* Close the file in zip opened with unzOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ extern int ZEXPORT unzCloseCurrentFile (unzFile file) { int err=UNZ_OK; unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && (!pfile_in_zip_read_info->raw)) { if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) err=UNZ_CRCERROR; } TRYFREE(pfile_in_zip_read_info->read_buffer); pfile_in_zip_read_info->read_buffer = NULL; if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) inflateEnd(&pfile_in_zip_read_info->stream); #ifdef HAVE_BZIP2 else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); #endif pfile_in_zip_read_info->stream_initialised = 0; TRYFREE(pfile_in_zip_read_info); s->pfile_in_zip_read=NULL; return err; } /* Get the global comment string of the ZipFile, in the szComment buffer. uSizeBuf is the size of the szComment buffer. return the number of byte copied or an error code <0 */ extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf) { unz64_s* s; uLong uReadThis ; if (file==NULL) return (int)UNZ_PARAMERROR; s=(unz64_s*)file; uReadThis = uSizeBuf; if (uReadThis>s->gi.size_comment) uReadThis = s->gi.size_comment; if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (uReadThis>0) { *szComment='\0'; if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) return UNZ_ERRNO; } if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) *(szComment+s->gi.size_comment)='\0'; return (int)uReadThis; } /* Additions by RX '2004 */ extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) { unz64_s* s; if (file==NULL) return 0; /*UNZ_PARAMERROR; */ s=(unz64_s*)file; if (!s->current_file_ok) return 0; if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) if (s->num_file==s->gi.number_entry) return 0; return s->pos_in_central_dir; } extern uLong ZEXPORT unzGetOffset (unzFile file) { ZPOS64_T offset64; if (file==NULL) return 0; /*UNZ_PARAMERROR; */ offset64 = unzGetOffset64(file); return (uLong)offset64; } extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) { unz64_s* s; int err; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; s->pos_in_central_dir = pos; s->num_file = s->gi.number_entry; /* hack */ err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) { return unzSetOffset64(file,pos); } tntnet-3.0/framework/common/unzip.h000066400000000000000000000377401365471676700175340ustar00rootroot00000000000000/* unzip.h -- IO for uncompress .zip files using zlib Version 1.1, February 14h, 2010 part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) Modifications of Unzip for Zip64 Copyright (C) 2007-2008 Even Rouault Modifications for Zip64 support on both zip and unzip Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) For more info read MiniZip_info.txt --------------------------------------------------------------------------------- Condition of use and distribution are the same than zlib : This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. --------------------------------------------------------------------------------- Changes See header of unzip64.c */ #ifndef _unz64_H #define _unz64_H #ifdef __cplusplus extern "C" { #endif #ifndef _ZLIB_H #include "zlib.h" #endif #ifndef _ZLIBIOAPI_H #include "ioapi.h" #endif #ifdef HAVE_BZIP2 #include "bzlib.h" #endif #define Z_BZIP2ED 12 #if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) /* like the STRICT of WIN32, we define a pointer that cannot be converted from (void*) without cast */ typedef struct TagunzFile__ { int unused; } unzFile__; typedef unzFile__ *unzFile; #else typedef voidp unzFile; #endif #define UNZ_OK (0) #define UNZ_END_OF_LIST_OF_FILE (-100) #define UNZ_ERRNO (Z_ERRNO) #define UNZ_EOF (0) #define UNZ_PARAMERROR (-102) #define UNZ_BADZIPFILE (-103) #define UNZ_INTERNALERROR (-104) #define UNZ_CRCERROR (-105) /* tm_unz contain date/time info */ typedef struct tm_unz_s { uInt tm_sec; /* seconds after the minute - [0,59] */ uInt tm_min; /* minutes after the hour - [0,59] */ uInt tm_hour; /* hours since midnight - [0,23] */ uInt tm_mday; /* day of the month - [1,31] */ uInt tm_mon; /* months since January - [0,11] */ uInt tm_year; /* years - [1980..2044] */ } tm_unz; /* unz_global_info structure contain global data about the ZIPfile These data comes from the end of central dir */ typedef struct unz_global_info64_s { ZPOS64_T number_entry; /* total number of entries in the central dir on this disk */ uLong size_comment; /* size of the global comment of the zipfile */ } unz_global_info64; typedef struct unz_global_info_s { uLong number_entry; /* total number of entries in the central dir on this disk */ uLong size_comment; /* size of the global comment of the zipfile */ } unz_global_info; /* unz_file_info contain information about a file in the zipfile */ typedef struct unz_file_info64_s { uLong version; /* version made by 2 bytes */ uLong version_needed; /* version needed to extract 2 bytes */ uLong flag; /* general purpose bit flag 2 bytes */ uLong compression_method; /* compression method 2 bytes */ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ uLong crc; /* crc-32 4 bytes */ ZPOS64_T compressed_size; /* compressed size 8 bytes */ ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ uLong size_filename; /* filename length 2 bytes */ uLong size_file_extra; /* extra field length 2 bytes */ uLong size_file_comment; /* file comment length 2 bytes */ uLong disk_num_start; /* disk number start 2 bytes */ uLong internal_fa; /* internal file attributes 2 bytes */ uLong external_fa; /* external file attributes 4 bytes */ tm_unz tmu_date; } unz_file_info64; typedef struct unz_file_info_s { uLong version; /* version made by 2 bytes */ uLong version_needed; /* version needed to extract 2 bytes */ uLong flag; /* general purpose bit flag 2 bytes */ uLong compression_method; /* compression method 2 bytes */ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ uLong crc; /* crc-32 4 bytes */ uLong compressed_size; /* compressed size 4 bytes */ uLong uncompressed_size; /* uncompressed size 4 bytes */ uLong size_filename; /* filename length 2 bytes */ uLong size_file_extra; /* extra field length 2 bytes */ uLong size_file_comment; /* file comment length 2 bytes */ uLong disk_num_start; /* disk number start 2 bytes */ uLong internal_fa; /* internal file attributes 2 bytes */ uLong external_fa; /* external file attributes 4 bytes */ tm_unz tmu_date; } unz_file_info; extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, const char* fileName2, int iCaseSensitivity)); /* Compare two filename (fileName1,fileName2). If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi or strcasecmp) If iCaseSenisivity = 0, case sensitivity is defaut of your operating system (like 1 on Unix, 2 on Windows) */ extern unzFile ZEXPORT unzOpen OF((const char *path)); extern unzFile ZEXPORT unzOpen64 OF((const void *path)); /* Open a Zip file. path contain the full pathname (by example, on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". If the zipfile cannot be opened (file don't exist or in not valid), the return value is NULL. Else, the return value is a unzFile Handle, usable with other function of this unzip package. the "64" function take a const void* pointer, because the path is just the value passed to the open64_file_func callback. Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* does not describe the reality */ extern unzFile ZEXPORT unzOpen2 OF((const char *path, zlib_filefunc_def* pzlib_filefunc_def)); /* Open a Zip file, like unzOpen, but provide a set of file low level API for read/write the zip file (see ioapi.h) */ extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, zlib_filefunc64_def* pzlib_filefunc_def)); /* Open a Zip file, like unz64Open, but provide a set of file low level API for read/write the zip file (see ioapi.h) */ extern int ZEXPORT unzClose OF((unzFile file)); /* Close a ZipFile opened with unzOpen. If there is files inside the .Zip opened with unzOpenCurrentFile (see later), these files MUST be closed with unzCloseCurrentFile before call unzClose. return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, unz_global_info *pglobal_info)); extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, unz_global_info64 *pglobal_info)); /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalComment OF((unzFile file, char *szComment, uLong uSizeBuf)); /* Get the global comment string of the ZipFile, in the szComment buffer. uSizeBuf is the size of the szComment buffer. return the number of byte copied or an error code <0 */ /***************************************************************************/ /* Unzip package allow you browse the directory of the zipfile */ extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); /* Set the current file of the zipfile to the first file. return UNZ_OK if there is no problem */ extern int ZEXPORT unzGoToNextFile OF((unzFile file)); /* Set the current file of the zipfile to the next file. return UNZ_OK if there is no problem return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. */ extern int ZEXPORT unzLocateFile OF((unzFile file, const char *szFileName, int iCaseSensitivity)); /* Try locate the file szFileName in the zipfile. For the iCaseSensitivity signification, see unzStringFileNameCompare return value : UNZ_OK if the file is found. It becomes the current file. UNZ_END_OF_LIST_OF_FILE if the file is not found */ /* ****************************************** */ /* Ryan supplied functions */ /* unz_file_info contain information about a file in the zipfile */ typedef struct unz_file_pos_s { uLong pos_in_zip_directory; /* offset in zip file directory */ uLong num_of_file; /* # of file */ } unz_file_pos; extern int ZEXPORT unzGetFilePos( unzFile file, unz_file_pos* file_pos); extern int ZEXPORT unzGoToFilePos( unzFile file, unz_file_pos* file_pos); typedef struct unz64_file_pos_s { ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ ZPOS64_T num_of_file; /* # of file */ } unz64_file_pos; extern int ZEXPORT unzGetFilePos64( unzFile file, unz64_file_pos* file_pos); extern int ZEXPORT unzGoToFilePos64( unzFile file, const unz64_file_pos* file_pos); /* ****************************************** */ extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, unz_file_info64 *pfile_info, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize)); extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, unz_file_info *pfile_info, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize)); /* Get Info about the current file if pfile_info!=NULL, the *pfile_info structure will contain somes info about the current file if szFileName!=NULL, the filemane string will be copied in szFileName (fileNameBufferSize is the size of the buffer) if extraField!=NULL, the extra field information will be copied in extraField (extraFieldBufferSize is the size of the buffer). This is the Central-header version of the extra field if szComment!=NULL, the comment string of the file will be copied in szComment (commentBufferSize is the size of the buffer) */ /** Addition for GDAL : START */ extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); /** Addition for GDAL : END */ /***************************************************************************/ /* for reading the content of the current zipfile, you can open it, read data from it, and close it (you can close it before reading all the file) */ extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); /* Open for reading data the current file in the zipfile. If there is no error, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, const char* password)); /* Open for reading data the current file in the zipfile. password is a crypting password If there is no error, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, int* method, int* level, int raw)); /* Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) if raw==1 *method will receive method of compression, *level will receive level of compression note : you can set level parameter as NULL (if you did not want known level, but you CANNOT set method parameter as NULL */ extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, int* method, int* level, int raw, const char* password)); /* Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) if raw==1 *method will receive method of compression, *level will receive level of compression note : you can set level parameter as NULL (if you did not want known level, but you CANNOT set method parameter as NULL */ extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); /* Close the file in zip opened with unzOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ extern int ZEXPORT unzReadCurrentFile OF((unzFile file, voidp buf, unsigned len)); /* Read bytes from the current file (opened by unzOpenCurrentFile) buf contain buffer where data must be copied len the size of buf. return the number of byte copied if somes bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ extern z_off_t ZEXPORT unztell OF((unzFile file)); extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); /* Give the current position in uncompressed data */ extern int ZEXPORT unzeof OF((unzFile file)); /* return 1 if the end of file was reached, 0 elsewhere */ extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, voidp buf, unsigned len)); /* Read extra field from the current file (opened by unzOpenCurrentFile) This is the local-header version of the extra field (sometimes, there is more info in the local-header version than in the central-header) if buf==NULL, it return the size of the local extra field if buf!=NULL, len is the size of the buffer, the extra header is copied in buf. the return value is the number of bytes copied in buf, or (if <0) the error code */ /***************************************************************************/ /* Get the current file offset */ extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file); extern uLong ZEXPORT unzGetOffset (unzFile file); /* Set the current file offset */ extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos); extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); #ifdef __cplusplus } #endif #endif /* _unz64_H */ tntnet-3.0/framework/common/unzipfile.cpp000066400000000000000000000120461365471676700207170ustar00rootroot00000000000000/* * Copyright (C) 2003-2006 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/unzipfile.h" #include #include "unzip.h" namespace tnt { namespace { int checkError(int ret, const char* function) { if (ret < 0) { switch (ret) { case UNZ_END_OF_LIST_OF_FILE: throw unzipEndOfListOfFile(function); case UNZ_PARAMERROR: throw unzipParamError(function); case UNZ_BADZIPFILE: throw unzipBadZipFile(function); case UNZ_INTERNALERROR: throw unzipInternalError(function); case UNZ_CRCERROR: throw unzipCrcError(function); } throw unzipError(ret, "unknown error", function); } return ret; } } std::string unzipError::formatMsg(int err, const char* msg, const char* function) { std::ostringstream s; s << "unzip-error " << err; if (function && function[0]) s << " in function \"" << function << '"'; s << ": " << msg; return s.str(); } unzipEndOfListOfFile::unzipEndOfListOfFile(const char* function) : unzipError(UNZ_END_OF_LIST_OF_FILE, "end of list of file", function) { } unzipParamError::unzipParamError(const char* function) : unzipError(UNZ_PARAMERROR, "parameter error", function) { } unzipBadZipFile::unzipBadZipFile(const char* function) : unzipError(UNZ_PARAMERROR, "bad zip file", function) { } unzipInternalError::unzipInternalError(const char* function) : unzipError(UNZ_PARAMERROR, "internal error", function) { } unzipCrcError::unzipCrcError(const char* function) : unzipError(UNZ_PARAMERROR, "crc error", function) { } ////////////////////////////////////////////////////////////////////// // unzipFile // struct unzipFile::unzFileStruct { unzFile file; }; void unzipFile::open(const std::string& path) { close(); _file = new unzFileStruct; if (!(_file->file = ::unzOpen(path.c_str()))) { delete _file; _file = 0; throw unzipFileNotFound(path); } } void unzipFile::close() { if (_file) { unzClose(_file->file); delete _file; _file = 0; } } unzipFile::~unzipFile() { if (_file) { unzClose(_file->file); delete _file; } } void unzipFile::goToFirstFile() { checkError(::unzGoToFirstFile(_file->file), "unzGoToFirstFile"); } void unzipFile::goToNextFile() { checkError(::unzGoToNextFile(_file->file), "unzGoToNextFile"); } void unzipFile::locateFile(const std::string& fileName, bool caseSensitivity) { checkError(::unzLocateFile(_file->file, fileName.c_str(), caseSensitivity ? 1 : 0), "unzLocateFile"); } void unzipFile::openCurrentFile() { checkError(::unzOpenCurrentFile(_file->file), "unzOpenCurrentFile"); } void unzipFile::openCurrentFile(const std::string& pw) { checkError(::unzOpenCurrentFilePassword(_file->file, pw.c_str()), "unzOpenCurrentFilePassword"); } void unzipFile::closeCurrentFile() { checkError(::unzCloseCurrentFile(_file->file), "unzCloseCurrentFile"); } int unzipFile::readCurrentFile(void* buf, unsigned len) { return checkError(::unzReadCurrentFile(_file->file, buf, len), "unzReadCurrentFile"); } ////////////////////////////////////////////////////////////////////// // unzipFileStreamBuf // unzipFileStreamBuf::int_type unzipFileStreamBuf::overflow(unzipFileStreamBuf::int_type /* c */) { return traits_type::eof(); } unzipFileStreamBuf::int_type unzipFileStreamBuf::underflow() { int n = _file.readCurrentFile(_buffer, sizeof(_buffer)); if (n == 0) return traits_type::eof(); setg(_buffer, _buffer, _buffer + n); return traits_type::to_int_type(_buffer[0]); } int unzipFileStreamBuf::sync() { return 0; } } tntnet-3.0/framework/common/urlescostream.cpp000066400000000000000000000041631365471676700216030ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/urlescostream.h" #include namespace tnt { std::streambuf::int_type UrlEscStreamBuf::overflow(std::streambuf::int_type ch) { static const char hex[] = "0123456789ABCDEF"; if (ch > 32 && ch < 127 && ch != '%' && ch != '+' && ch != '=' && ch != '&') _sink->sputc(ch); else if (ch == ' ') _sink->sputc('+'); else { _sink->sputc('%'); _sink->sputc(hex[(ch >> 4) & 0x0f]); _sink->sputc(hex[ch & 0x0f]); } return 0; } std::streambuf::int_type UrlEscStreamBuf::underflow() { return traits_type::eof(); } int UrlEscStreamBuf::sync() { return _sink->pubsync(); } std::string urlEscape(const std::string& str) { std::ostringstream s; UrlEscOstream e(s); e << str; return s.str(); } } tntnet-3.0/framework/common/urlmapper.cpp000066400000000000000000000030501365471676700207140ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/urlmapper.h" #include "tnt/httperror.h" namespace tnt { Compident Urlmapper::mapComp(const std::string& vhost, const std::string& compUrl) const { throw NotFoundException(compUrl, vhost); } } tntnet-3.0/framework/common/util.cpp000066400000000000000000000030741365471676700176700ustar00rootroot00000000000000/* * Copyright (C) 2008 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include namespace tnt { void throwRuntimeError(const std::string& msg) { throw std::runtime_error(msg); } void throwRuntimeError(const char* msg) { throwRuntimeError(std::string(msg)); } } tntnet-3.0/framework/common/worker.cpp000066400000000000000000000405731365471676700202310ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/worker.h" #include "tnt/dispatcher.h" #include "tnt/job.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" log_define("tntnet.worker") namespace { static const char stateStarting[] = "0 starting"; static const char stateWaitingForJob[] = "1 waiting for job"; static const char stateParsing[] = "2 parsing request"; static const char statePostParsing[] = "3 post parsing"; static const char stateDispatch[] = "4 dispatch"; static const char stateProcessingRequest[] = "5 processing request"; static const char stateFlush[] = "6 flush"; static const char stateSendReply[] = "7 send reply"; static const char stateSendError[] = "8 send error"; static const char stateStopping[] = "9 stopping"; } namespace tnt { cxxtools::Mutex Worker::_mutex; Worker::workers_type Worker::_workers; Comploader Worker::_comploader; Worker::Worker(TntnetImpl& app) : _application(app), _threadId(0), _state(stateStarting), _lastWaitTime(0) { cxxtools::MutexLock lock(_mutex); _workers.insert(this); } void Worker::run() { _threadId = pthread_self(); Jobqueue& queue = _application.getQueue(); log_debug("start thread " << _threadId); while (queue.getWaitThreadCount() < _application.getMinThreads()) { _state = stateWaitingForJob; Jobqueue::JobPtr j = queue.get(); if (TntnetImpl::shouldStop()) { // put job back to queue to wake up next worker if any left queue.put(j); break; } try { std::iostream& socket = j->getStream(); if (TntnetImpl::shouldStop()) break; bool keepAlive; do { time(&_lastWaitTime); keepAlive = false; _state = stateParsing; try { j->getParser().parse(socket); _state = statePostParsing; if (socket.eof()) log_debug("eof"); else if (j->getParser().failed()) { _state = stateSendError; log_warn("bad request"); tnt::HttpReply errorReply(socket); errorReply.setVersion(1, 0); errorReply.setContentType("text/html"); errorReply.setKeepAliveCounter(0); errorReply.out() << "

Error

bad request

\n"; errorReply.sendReply(400, "Bad Request"); logRequest(j->getRequest(), errorReply, 400); } else if (socket.fail()) log_debug("socket failed"); else { j->getRequest().doPostParse(); j->setWrite(); keepAlive = processRequest(j->getRequest(), socket, j->decrementKeepAliveCounter()); if (keepAlive) { j->setRead(); j->clear(); if (!socket.rdbuf()->in_avail()) { if (queue.getWaitThreadCount() == 0 && !queue.empty()) { // if there is something to do and no threads waiting, we take // the next job just to improve responsiveness. log_debug("put job back into queue"); queue.put(j, true); keepAlive = false; } else { struct pollfd fd; fd.fd = j->getFd(); fd.events = POLLIN; if (::poll(&fd, 1, TntConfig::it().socketReadTimeout) == 0) { log_debug("pass job to poll-thread"); _application.getPoller().addIdleJob(j); keepAlive = false; } } } } } } catch (const HttpError& e) { keepAlive = false; _state = stateSendError; log_warn("http-Error: " << e.what()); HttpReply errorReply(socket); errorReply.setVersion(1, 0); errorReply.setKeepAliveCounter(0); for (HttpMessage::header_type::const_iterator it = e.header_begin(); it != e.header_end(); ++it) errorReply.setHeader(it->first, it->second); errorReply.out() << e.getBody() << '\n'; errorReply.sendReply(e.getErrcode(), e.getErrmsg()); logRequest(j->getRequest(), errorReply, e.getErrcode()); } } while (keepAlive); } catch (const cxxtools::IOTimeout& e) { log_debug("IOTimeout"); _application.getPoller().addIdleJob(j); } catch (const cxxtools::net::AcceptTerminated&) { log_debug("listener terminated"); break; } catch (const std::exception& e) { log_warn("unexpected exception: " << e.what()); } } time(&_lastWaitTime); _state = stateStopping; cxxtools::MutexLock lock(_mutex); _workers.erase(this); log_debug("end worker thread " << _threadId << " - " << _workers.size() << " threads left - " << _application.getQueue().getWaitThreadCount() << " waiting threads"); } bool Worker::processRequest(HttpRequest& request, std::iostream& socket, unsigned keepAliveCount) { // log message log_info("request " << request.getMethod_cstr() << ' ' << request.getQuery() << " from client " << request.getPeerIp() << " user-Agent \"" << request.getUserAgent() << "\" user \"" << request.getUsername() << '"'); // create reply-object HttpReply reply(socket); reply.setVersion(request.getMajorVersion(), request.getMinorVersion()); if (request.isMethodHEAD()) reply.setHeadRequest(); #ifdef ENABLE_LOCALE reply.setLocale(request.getLocale()); #endif if (request.keepAlive()) reply.setKeepAliveCounter(keepAliveCount); if (TntConfig::it().enableCompression) reply.setAcceptEncoding(request.getEncoding()); // process request try { try { dispatch(request, reply); if (!request.keepAlive() || !reply.keepAlive()) keepAliveCount = 0; if (keepAliveCount > 0) log_debug("keep alive"); else { log_debug("no keep alive request/reply=" << request.keepAlive() << '/' << reply.keepAlive()); } } catch (const HttpError& e) { throw; } catch (const std::exception& e) { throw HttpError(HTTP_INTERNAL_SERVER_ERROR, e.what()); } catch (...) { log_error("unknown exception"); throw HttpError(HTTP_INTERNAL_SERVER_ERROR, "unknown error"); } } catch (const HttpError& e) { _state = stateSendError; log_warn("http-Error: " << e.what()); HttpReply errorReply(socket); errorReply.setVersion(request.getMajorVersion(), request.getMinorVersion()); if (request.keepAlive()) errorReply.setKeepAliveCounter(keepAliveCount); else keepAliveCount = 0; for (HttpMessage::header_type::const_iterator it = e.header_begin(); it != e.header_end(); ++it) errorReply.setHeader(it->first, it->second); errorReply.out() << e.getBody() << '\n'; errorReply.sendReply(e.getErrcode(), e.getErrmsg()); logRequest(request, errorReply, e.getErrcode()); } return keepAliveCount > 0; } void Worker::logRequest(const HttpRequest& request, const HttpReply& reply, unsigned httpReturn) { static std::atomic waitCount(0); ++waitCount; std::ofstream& accessLog = _application._accessLog; if (!accessLog.is_open()) { const std::string& fname = TntConfig::it().accessLog; if (fname.empty()) { log_debug("accesLog setting is empty"); return; } cxxtools::MutexLock lock(_application._accessLogMutex); if (!accessLog.is_open()) { log_debug("access log is not open - open now"); accessLog.open(fname.c_str(), std::ios::out | std::ios::app); if (accessLog.fail()) { std::cerr << "failed to open access log \"" << fname << '"' << std::endl; TntConfig::it().accessLog.clear(); } } } log_debug("log request to access log with return code " << httpReturn); static const std::string unknown("-"); std::string user = request.getUsername(); if (user.empty()) user = unknown; std::string peerIp = request.getPeerIp(); if (peerIp.empty()) peerIp = unknown; std::string query = request.getQuery(); if (query.empty()) query = unknown; time_t t; ::time(&t); cxxtools::MutexLock lock(_application._accessLogMutex); // cache for timestamp of access log static time_t lastLogTime = 0; static char timebuf[40]; if (t != lastLogTime) { struct tm tm; ::localtime_r(&t, &tm); strftime(timebuf, sizeof(timebuf), "%d/%b/%Y:%H:%M:%S %z", &tm); lastLogTime = t; } accessLog << peerIp << " - " << user << " [" << timebuf << "] \"" << request.getMethod_cstr() << ' ' << query << ' ' << "HTTP/" << request.getMajorVersion() << '.' << request.getMinorVersion() << "\" " << httpReturn << ' '; std::string::size_type contentSize = reply.getContentSize(); if (contentSize != 0) accessLog << contentSize; else accessLog << '-'; accessLog << " \"" << request.getHeader(httpheader::referer, "-") << "\" \"" << request.getHeader(httpheader::userAgent, "-") << "\"\n"; if (--waitCount == 0) accessLog.flush(); } void Worker::dispatch(HttpRequest& request, HttpReply& reply) { _state = stateDispatch; const std::string& url = request.getUrl(); if (!HttpRequest::checkUrl(url)) { log_info("illegal url <" << url << '>'); throw HttpError(HTTP_BAD_REQUEST, "illegal url"); } request.setThreadContext(this); Dispatcher::PosType pos(_application.getDispatcher(), request); while (true) { _state = stateDispatch; // pos.getNext() throws NotFoundException at end Maptarget ci = pos.getNext(); try { Component* comp = 0; try { if (ci.libname == _application.getAppName()) { // if the libname is the app name look first, if the component is // linked directly try { Compident cii = ci; cii.libname = std::string(); comp = &_comploader.fetchComp(cii, _application.getDispatcher()); } catch (const NotFoundException&) { // if the component is not found in the binary, fetchComp throws // NotFoundException and comp remains 0. // so we can ignore the exceptioni and just continue } } if (comp == 0) comp = &_comploader.fetchComp(ci, _application.getDispatcher()); } catch (const NotFoundException& e) { log_debug("NotFoundException catched - url " << e.getUrl() << " try next mapping"); continue; } request.setPathInfo(ci.hasPathInfo() ? ci.getPathInfo() : url); request.setArgs(ci.getArgs()); std::string appname = _application.getAppName().empty() ? ci.libname : _application.getAppName(); _application.getScopemanager().preCall(request, appname); _state = stateProcessingRequest; unsigned http_return; const char* http_msg; std::string msg; try { http_return = comp->topCall(request, reply, request.getQueryParams()); if (http_return == DEFAULT) http_return = ci.getHttpReturn(); http_msg = HttpReturn::httpMessage(http_return); } catch (const HttpReturn& e) { http_return = e.getReturnCode(); msg = e.getMessage(); http_msg = msg.c_str(); } if (http_return != DECLINED) { if (reply.isDirectMode()) { log_info("request " << request.getMethod_cstr() << ' ' << request.getQuery() << " ready, returncode " << http_return << ' ' << http_msg); _state = stateFlush; reply.out().flush(); } else { log_info_if(!reply.isChunkedEncoding(), "request " << request.getMethod_cstr() << ' ' << request.getQuery() << " ready, returncode " << http_return << ' ' << http_msg << " - ContentSize: " << reply.getContentSize()); _application.getScopemanager().postCall(request, reply, appname); _state = stateSendReply; if (reply.sendReply(http_return, http_msg)) { log_debug("reply sent"); } else { reply.setKeepAliveCounter(0); log_warn("sending failed"); } log_info_if(reply.isChunkedEncoding(), "request " << request.getMethod_cstr() << ' ' << request.getQuery() << " ready, returncode " << http_return << ' ' << http_msg << " - ContentSize: " << reply.chunkedBytesWritten() << " (chunked)"); } logRequest(request, reply, http_return); return; } else log_debug("component " << ci << " returned DECLINED"); } catch (const LibraryNotFound& e) { log_warn("library " << e.getLibname() << " not found"); } } throw NotFoundException(request.getUrl()); } void Worker::timer() { time_t currentTime; time(¤tTime); cxxtools::MutexLock lock(_mutex); for (workers_type::iterator it = _workers.begin(); it != _workers.end(); ++it) { (*it)->healthCheck(currentTime); } } void Worker::healthCheck(time_t currentTime) { if (_state == stateProcessingRequest && _lastWaitTime != 0 && TntConfig::it().maxRequestTime > 0) { if (static_cast(currentTime - _lastWaitTime) > TntConfig::it().maxRequestTime) { log_fatal("requesttime " << TntConfig::it().maxRequestTime << " seconds in thread " << _threadId << " exceeded - exit process"); log_info("current state: " << _state); ::_exit(111); } } } void Worker::touch() { time(&_lastWaitTime); } Scope& Worker::getScope() { return _threadScope; } Worker::workers_type::size_type Worker::getCountThreads() { cxxtools::MutexLock lock(_mutex); return _workers.size(); } } tntnet-3.0/framework/common/zdata.cpp000066400000000000000000000045071365471676700200200ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include log_define("tntnet.data") namespace tnt { void Zdata::addRef() { if (++_refs == 1) { // allocate uncompressed data _data = new char[_dataLen]; // uncompress Zdata => data log_debug("uncompress " << _zdataLen << " to " << _dataLen << " bytes"); uLong dest_len = _dataLen; int z_ret = uncompress((Bytef*)_data, &dest_len, (const Bytef*)_zptr, _zdataLen); if (z_ret != Z_OK) { throwRuntimeError(std::string("error uncompressing data: ") + (z_ret == Z_MEM_ERROR ? "Z_MEM_ERROR" : z_ret == Z_BUF_ERROR ? "Z_BUF_ERROR" : z_ret == Z_DATA_ERROR ? "Z_DATA_ERROR" : "unknown error")); } log_debug("uncompress ready"); } } void Zdata::release() { if (--_refs == 0) { log_debug("release " << _dataLen << " uncompressed bytes"); delete[] _data; _data = 0; } } } tntnet-3.0/framework/defcomp/000077500000000000000000000000001365471676700163305ustar00rootroot00000000000000tntnet-3.0/framework/defcomp/Makefile.am000066400000000000000000000006741365471676700203730ustar00rootroot00000000000000AM_CPPFLAGS = -I$(top_srcdir)/framework/common pkglib_LTLIBRARIES = tntnet.la noinst_HEADERS = \ mime.h \ mimehandler.h \ static.h tntnet_la_SOURCES = \ error.cpp \ mime.cpp \ mimehandler.cpp \ empty.cpp \ proxy.cpp \ redirect.cpp \ setheader.cpp \ static.cpp \ unzipcomp.cpp tntnet_la_LDFLAGS = -module -version-info @sonumber@ @SHARED_LIB_FLAG@ -lcxxtools-http tntnet_la_LIBADD = $(top_builddir)/framework/common/libtntnet.la tntnet-3.0/framework/defcomp/empty.cpp000066400000000000000000000050761365471676700202020ustar00rootroot00000000000000/* * Copyright (C) 2015 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include namespace tnt { class Urlmapper; class Comploader; //////////////////////////////////////////////////////////////////////// // component declaration // class Empty : public tnt::Component { friend class EmptyFactory; public: Empty() { } virtual unsigned operator() (tnt::HttpRequest&, tnt::HttpReply&, tnt::QueryParams&); }; //////////////////////////////////////////////////////////////////////// // factory // static ComponentFactoryImpl EmptyFactory("empty"); //////////////////////////////////////////////////////////////////////// // component definition // unsigned Empty::operator() (tnt::HttpRequest& request, tnt::HttpReply& reply, tnt::QueryParams&) { unsigned httpcode = 200; for (tnt::HttpRequest::args_type::const_iterator it = request.getArgs().begin(); it != request.getArgs().end(); ++it) { if (it->first == "httpcode") httpcode = cxxtools::convert(it->second); else reply.setHeader(it->first + ':' , it->second); } return httpcode; } } tntnet-3.0/framework/defcomp/error.cpp000066400000000000000000000051721365471676700201720ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include namespace tnt { class Urlmapper; class Comploader; //////////////////////////////////////////////////////////////////////// // component declaration // class Error : public tnt::Component { friend class ErrorFactory; public: Error() { } virtual unsigned operator() (tnt::HttpRequest&, tnt::HttpReply&, tnt::QueryParams&); }; //////////////////////////////////////////////////////////////////////// // factory // static ComponentFactoryImpl errorFactory("error"); //////////////////////////////////////////////////////////////////////// // component definition // unsigned Error::operator() (tnt::HttpRequest& request, tnt::HttpReply&, tnt::QueryParams&) { std::istringstream s(request.getArg("code")); unsigned errorcode; s >> errorcode; if (!s || errorcode < 300 || errorcode >= 1000) throw tnt::HttpError(HTTP_INTERNAL_SERVER_ERROR, "configuration error"); std::string msg = request.getArg("message"); if (msg.empty()) msg = HttpReturn::httpMessage(errorcode); throw tnt::HttpError(errorcode, msg); return DECLINED; } } tntnet-3.0/framework/defcomp/fstatic.cpp000066400000000000000000000076061365471676700205020ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "fstatic.h" #include #include #include #include #include #include #include #include #include #include #include #include log_define("tntnet.fstatic") namespace tnt { //////////////////////////////////////////////////////////////////////// // factory // class FstaticFactory : public tnt::SingletonComponentFactory { public: FstaticFactory(const std::string& componentName) : tnt::SingletonComponentFactory(componentName) { } virtual tnt::Component* doCreate(const tnt::Compident&, const tnt::Urlmapper&, tnt::Comploader&); }; tnt::Component* FstaticFactory::doCreate(const tnt::Compident&, const tnt::Urlmapper&, tnt::Comploader&) { return new Fstatic(); } TNT_COMPONENTFACTORY(fstatic, FstaticFactory) ////////////////////////////////////////////////////////////////////// // component definition // unsigned Fstatic::operator() (tnt::HttpRequest& request, tnt::HttpReply& reply, tnt::QueryParams&) { if (!tnt::HttpRequest::checkUrl(request.getPathInfo()) || request.getPathInfo().find('\0') != std::string::npos) throw tnt::HttpError(HTTP_BAD_REQUEST, "illegal url"); std::string file; if (!getDocumentRoot().empty()) file = getDocumentRoot() + '/'; file += request.getPathInfo(); log_debug("file: " << file); struct stat st; if (stat(file.c_str(), &st) != 0) { log_warn("error in stat for file \"" << file << "\""); reply.throwNotFound(request.getPathInfo()); } if (!S_ISREG(st.st_mode)) { log_warn("no regular file \"" << file << "\""); reply.throwNotFound(request.getPathInfo()); } std::ifstream in(file.c_str()); if (!in) { log_warn("file \"" << file << "\" not found"); reply.throwNotFound(request.getPathInfo()); } // set Content-Type if (request.getArgs().size() > 0) reply.setContentType(request.getArg(0)); // set Content-Length reply.setContentLengthHeader(st.st_size); // set Keep-Alive if (request.keepAlive()) reply.setHeader(tnt::httpheader::connection, tnt::httpheader::connectionKeepAlive); // send data log_info("send static file \"" << file << "\" size " << st.st_size << " bytes"); reply.setDirectMode(); reply.out() << in.rdbuf(); return HTTP_OK; } void Fstatic::drop() { factory.drop(this); } } tntnet-3.0/framework/defcomp/fstatic.h000066400000000000000000000032111365471676700201330ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_FSTATIC_H #define TNT_FSTATIC_H #include "static.h" namespace tnt { class Fstatic : public Static { friend class FstaticFactory; public: virtual unsigned operator() (tnt::HttpRequest&, tnt::HttpReply&, tnt::QueryParams&); virtual void drop(); }; } #endif // TNT_FSTATIC_H tntnet-3.0/framework/defcomp/mime.cpp000066400000000000000000000045231365471676700177670ustar00rootroot00000000000000/* * Copyright (C) 2003,2007 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mime.h" #include "mimehandler.h" #include #include #include #include #include namespace tnt { //////////////////////////////////////////////////////////////////////// // factory // static ComponentFactoryImpl mimeFactory("mime"); //////////////////////////////////////////////////////////////////////// // component definition // Mime::~Mime() { delete _handler; } void Mime::configure(const tnt::TntConfig&) { if (_handler == 0) _handler = new MimeHandler(); } unsigned Mime::operator() (HttpRequest& request, HttpReply& reply, QueryParams&) { std::string mimeType = request.getArg("contenttype"); if (mimeType.empty()) reply.setContentType(_handler->getMimeType(request.getPathInfo()).c_str()); else reply.setContentType(mimeType); // we do not produce any content, so we pass the request to the next handler: return DECLINED; } } tntnet-3.0/framework/defcomp/mime.h000066400000000000000000000034311365471676700174310ustar00rootroot00000000000000/* * Copyright (C) 2007 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_MIME_H #define TNT_MIME_H #include namespace tnt { class MimeHandler; class Mime : public tnt::Component { friend class MimeFactory; MimeHandler* _handler; public: Mime() : _handler(0) { } ~Mime(); virtual void configure(const tnt::TntConfig&); virtual unsigned operator() (tnt::HttpRequest&, tnt::HttpReply&, tnt::QueryParams&); }; } #endif // TNT_MIME_H tntnet-3.0/framework/defcomp/mimehandler.cpp000066400000000000000000000037531365471676700213310ustar00rootroot00000000000000/* * Copyright (C) 2003,2007 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include log_define("tntnet.mime.handler") namespace tnt { MimeHandler::MimeHandler() { _mimeDb.read(TntConfig::it().mimeDb); } std::string MimeHandler::getMimeType(const std::string& path) const { std::string mimeType = _mimeDb.getMimetype(path); if (mimeType.empty()) { log_debug("unknown type in url-path \"" << path << "\" set DefaultContentType " << TntConfig::it().defaultContentType); return TntConfig::it().defaultContentType; } else { log_debug("url-path=\"" << path << "\" type=" << mimeType); return mimeType; } } } tntnet-3.0/framework/defcomp/mimehandler.h000066400000000000000000000032001365471676700207610ustar00rootroot00000000000000/* * Copyright (C) 2007 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_MIMEHANDLER_H #define TNT_MIMEHANDLER_H #include #include namespace tnt { class MimeHandler { tnt::MimeDb _mimeDb; public: MimeHandler(); std::string getMimeType(const std::string& path) const; }; } #endif // TNT_MIMEHANDLER_H tntnet-3.0/framework/defcomp/proxy.cpp000066400000000000000000000200641365471676700202170ustar00rootroot00000000000000/* * Copyright (C) 2012 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include log_define("tntnet.proxy") namespace tnt { class Urlmapper; class Comploader; //////////////////////////////////////////////////////////////////////// // component declaration // class Proxy : public tnt::EcppComponent { friend class ProxyFactory; public: Proxy(const tnt::Compident& ci, const tnt::Urlmapper& um, tnt::Comploader& cl) : EcppComponent(ci, um, cl) { } virtual unsigned operator() (tnt::HttpRequest& request, tnt::HttpReply& reply, tnt::QueryParams& qparam); }; //////////////////////////////////////////////////////////////////////// // factory // class ProxyFactory : public tnt::ComponentFactory { public: ProxyFactory(const std::string& componentName) : tnt::ComponentFactory(componentName) { } virtual tnt::Component* doCreate(const tnt::Compident& ci, const tnt::Urlmapper& um, tnt::Comploader& cl); }; tnt::Component* ProxyFactory::doCreate(const tnt::Compident& ci, const tnt::Urlmapper& um, tnt::Comploader& cl) { return new Proxy(ci, um, cl); } static ProxyFactory proxyFactory("proxy"); //////////////////////////////////////////////////////////////////////// // component definition // unsigned Proxy::operator() (tnt::HttpRequest& request, tnt::HttpReply& reply, tnt::QueryParams& qparam) { std::string uriStr = request.getArg("uri"); if (uriStr.empty()) uriStr = request.getArg(0); // for compatibility if (uriStr.empty()) { log_error("proxy uri missing in configuration"); throw std::runtime_error("proxy uri missing in configuration"); } TNT_THREAD_COMPONENT_VAR(std::string, currentProxyHost, ()); TNT_THREAD_COMPONENT_VAR(unsigned short, currentProxyPort, ()); TNT_THREAD_COMPONENT_VAR(cxxtools::http::Client, client, ()); cxxtools::net::Uri uri(uriStr); std::string url = uri.path(); bool urlEndsWithSlash = !url.empty() && url[url.size()-1] == '/'; bool pathInfoStartsWithSlash = !request.getPathInfo().empty() && request.getPathInfo()[0] == '/'; if (urlEndsWithSlash && pathInfoStartsWithSlash) { // Avoid double slash, if getPathInfo starts with '/' (which is normally the case). url.erase (url.size()-1, 1); } else if (!urlEndsWithSlash && !pathInfoStartsWithSlash) { url += '/'; } url += request.getPathInfo(); if (!request.getQueryString().empty()) { url += '?'; url += request.getQueryString(); } if (currentProxyHost != uri.host() || currentProxyPort != uri.port()) { log_debug("connect to " << uri.host() << ':' << uri.port()); client.connect(uri.host(), uri.port()); currentProxyHost = uri.host(); currentProxyPort = uri.port(); } else log_debug("already connected to " << uri.host() << ':' << uri.port()); log_info("get file " << url << " qparam=" << qparam.getUrl() << " from " << uri.host() << ':' << uri.port() << " body size=" << request.getBody().size()); // set up client request cxxtools::http::Request clientRequest(url); clientRequest.method(request.getMethod()); clientRequest.body() << request.getBody(); const char* value; clientRequest.setHeader ("Host", uri.host().c_str()); std::string peerIp = request.getPeerIp(); clientRequest.setHeader ("X-Real-IP", peerIp.c_str()); clientRequest.addHeader ("X-Forwarded-For", peerIp.c_str()); value = request.getHeader(tnt::httpheader::contentType, 0); if (value) clientRequest.header().setHeader("Content-Type", value); value = request.getHeader(tnt::httpheader::cookie, 0); if (value) clientRequest.header().setHeader("Cookie", value); value = request.getHeader(tnt::httpheader::authorization, 0); if (value) clientRequest.header().setHeader("Authorization", value); value = request.getHeader(tnt::httpheader::ifModifiedSince, 0); if (value) clientRequest.header().setHeader("If-Modified-Since", value); std::vector forwardHeaders; log_debug("forwardHeaders: \"" << request.getArg("forwardHeaders") << '"'); cxxtools::split(',', request.getArg("forwardHeaders"), std::back_inserter(forwardHeaders)); for (unsigned n = 0; n < forwardHeaders.size(); ++n) { log_debug("forward header \"" << forwardHeaders[n] << '"'); value = request.getHeader((forwardHeaders[n] + ':').c_str(), 0); if (value) { log_debug("value \"" << value << '"'); clientRequest.header().setHeader(forwardHeaders[n].c_str(), value); } } // execute client request client.execute(clientRequest); // retrieve result std::string body = client.readBody(); unsigned httpReturnCode = client.header().httpReturnCode(); const char* contentType = client.header().getHeader("Content-type"); for (cxxtools::http::MessageHeader::const_iterator it = client.header().begin(); it != client.header().end(); ++it) { if (strcasecmp(it->first, "Set-Cookie") == 0) { log_info("cookie: " << it->first << " value: " << it->second); reply.setHeader(tnt::httpheader::setCookie, it->second, false); } } value = client.header().getHeader ("p3p"); if (value) reply.setHeader("p3p:", value); value = client.header().getHeader("Cache-Control"); if (value) reply.setHeader(tnt::httpheader::cacheControl, value); value = client.header().getHeader("Expires"); if (value) reply.setHeader(tnt::httpheader::expires, value); value = client.header().getHeader("Last-Modified"); if (value) reply.setHeader(tnt::httpheader::lastModified, value); value = client.header().getHeader("Location"); if (value) reply.setHeader(tnt::httpheader::location, value); value = client.header().getHeader("Content-Disposition"); if (value) reply.setHeader("Content-Disposition:", value); value = client.header().getHeader("WWW-Authenticate"); if (value) reply.setHeader(tnt::httpheader::wwwAuthenticate, value); log_debug("got file " << request.getPathInfo() << " with http return code=" << httpReturnCode << " content type=" << (contentType ? contentType : "NULL")); if (httpReturnCode == HTTP_NOT_FOUND) return DECLINED; if (contentType) reply.setContentType(contentType); reply.out() << body; return httpReturnCode; } } tntnet-3.0/framework/defcomp/redirect.cpp000066400000000000000000000050511365471676700206360ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include namespace tnt { class Urlmapper; class Comploader; //////////////////////////////////////////////////////////////////////// // component declaration // class Redirect : public tnt::Component { friend class RedirectFactory; public: virtual unsigned operator() (tnt::HttpRequest&, tnt::HttpReply&, tnt::QueryParams&); }; static ComponentFactoryImpl redirectFactory("redirect"); //////////////////////////////////////////////////////////////////////// // component definition // unsigned Redirect::operator() (tnt::HttpRequest& request, tnt::HttpReply& reply, tnt::QueryParams&) { std::string type = request.getArg("type"); HttpReply::Redirect httpCode = HttpReply::temporarily; if (type == "permanently") httpCode = HttpReply::permanently; else if (type == "temporarily") httpCode = HttpReply::temporarily; else if (!type.empty()) httpCode = static_cast(cxxtools::convert(type)); return reply.redirect(request.getPathInfo(), httpCode); } } tntnet-3.0/framework/defcomp/setheader.cpp000066400000000000000000000045051365471676700210040ustar00rootroot00000000000000/* * Copyright (C) 2015 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include namespace tnt { class Urlmapper; class Comploader; //////////////////////////////////////////////////////////////////////// // component declaration // class Setheader : public tnt::Component { friend class SetheaderFactory; public: virtual unsigned operator() (tnt::HttpRequest&, tnt::HttpReply&, tnt::QueryParams&); }; static ComponentFactoryImpl setheaderFactory("setheader"); //////////////////////////////////////////////////////////////////////// // component definition // unsigned Setheader::operator() (tnt::HttpRequest& request, tnt::HttpReply& reply, tnt::QueryParams&) { for (tnt::HttpRequest::args_type::const_iterator it = request.getArgs().begin(); it != request.getArgs().end(); ++it) reply.setHeader(it->first, it->second); return DECLINED; } } tntnet-3.0/framework/defcomp/static.cpp000066400000000000000000000320231365471676700203230ustar00rootroot00000000000000/* * Copyright (C) 2003,2007 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "static.h" #include "mimehandler.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(HAVE_SENDFILE) && defined(HAVE_SYS_SENDFILE_H) #include #include #include #include #include #include #include #include #include #include #endif log_define("tntnet.static") namespace tnt { namespace { bool parseRange(const char* range, off_t& offset, off_t& count) { enum { state_0, state_1, state_from0, state_from, state_from_e, state_to0, state_to, state_e } state = state_0; const char* prefix = "bytes="; off_t firstPos = 0; off_t lastPos = count; for (const char* p = range; *p && state != state_e; ++p) { char ch = *p; switch (state) { case state_0: case state_1: if (ch == *prefix) { ++prefix; if (*prefix == '\0') { log_debug("prefix ends"); state = state_from0; } else state = state_1; } else if (state == state_1 || ch != ' ') return false; break; case state_from0: if (std::isdigit(ch)) { log_debug("from found"); firstPos = ch - '0'; state = state_from; } else if (ch == '-') state = state_to0; else if (ch != ' ') return false; break; case state_from: if (std::isdigit(ch)) firstPos = firstPos * 10 + ch - '0'; else if (ch == '-') state = state_to0; else if (ch == ' ') state = state_from_e; else return false; break; case state_from_e: if (ch == '-') state = state_to0; else if (ch != ' ') return false; break; case state_to0: if (std::isdigit(ch)) { lastPos = ch - '0'; state = state_to; } else if (ch != ' ') return false; break; case state_to: if (std::isdigit(ch)) lastPos = lastPos * 10 + ch - '0'; else if (ch == ' ') state = state_e; else return false; break; case state_e: // not reachable but to satisfy the compiler we put it here break; } } switch (state) { case state_to0: case state_to: case state_e: if (lastPos > firstPos) { offset = firstPos; count = lastPos - firstPos; log_debug("firstPos=" << firstPos << " lastPos=" << lastPos << " offset=" << offset << " count=" << count); return true; } break; default: break; } return false; } #if defined(HAVE_SENDFILE) && defined(HAVE_SYS_SENDFILE_H) class Fdfile { private: int _fd; public: Fdfile(const char* pathname, int flags) : _fd(open(pathname, flags)) { if (_fd < 0) throw cxxtools::SystemError("open"); } ~Fdfile() { if (_fd >= 0) ::close(_fd); } int getFd() const { return _fd; } }; void pollout(int fd, int timeout) { struct pollfd fds; fds.fd = fd; fds.events = POLLOUT; log_debug("poll timeout " << timeout); int p = ::poll(&fds, 1, timeout); log_debug("poll returns " << p << " revents " << fds.revents); if (p < 0) { log_error("error in poll; errno=" << errno); throw cxxtools::SystemError("poll"); } else if (p == 0) { log_debug("poll timeout (" << timeout << ')'); throw cxxtools::IOTimeout(); } } #endif } ////////////////////////////////////////////////////////////////////// // factory // static ComponentFactoryImpl staticFactory("static"); ////////////////////////////////////////////////////////////////////// // component definition // Static::~Static() { delete _handler; } void Static::configure(const TntConfig&) { if (_handler == 0) _handler = new MimeHandler(); } void Static::setContentType(HttpRequest& request, HttpReply& reply) { if (_handler) reply.setContentType(_handler->getMimeType(request.getPathInfo()).c_str()); } unsigned Static::operator() (HttpRequest& request, HttpReply& reply, QueryParams& qparam) { return doCall(request, reply, qparam, false); } unsigned Static::topCall(HttpRequest& request, HttpReply& reply, QueryParams& qparam) { return doCall(request, reply, qparam, true); } unsigned Static::doCall(HttpRequest& request, HttpReply& reply, QueryParams&, bool top) { if (!tnt::HttpRequest::checkUrl(request.getPathInfo()) || request.getPathInfo().find('\0') != std::string::npos) throw tnt::HttpError(HTTP_BAD_REQUEST, "illegal url"); // fetch document root from arguments or take global setting as default std::string file = request.getArg("documentRoot", TntConfig::it().documentRoot); log_debug("document root =\"" << file << '"'); if (!file.empty() && *file.rbegin() != '/') file += '/'; file += request.getPathInfo(); log_debug("file: " << file); struct stat st; bool localEnableGzip = false; if (request.getEncoding().accept("gzip") && TntConfig::it().enableCompression) { std::string gzfile = file + ".gz"; if (stat(gzfile.c_str(), &st) == 0 && S_ISREG(st.st_mode)) { log_debug("enable compression"); file = gzfile; localEnableGzip = true; reply.setHeader(httpheader::contentEncoding, "gzip"); } else { log_debug("compressed file \"" << gzfile << "\" not found or not a regular file"); } } if (!localEnableGzip) { if (stat(file.c_str(), &st) != 0) { log_debug("can't stat file \"" << file << "\""); return DECLINED; } if (!S_ISREG(st.st_mode)) { log_debug("no regular file \"" << file << "\""); return DECLINED; } } off_t offset = 0; off_t count = st.st_size; unsigned httpOkReturn = HTTP_OK; if (top) { // set Content-Type std::string contentType = request.getArg("contentType"); if (!contentType.empty()) { log_debug("content type is \"" << contentType << '"'); reply.setContentType(contentType.c_str()); } else setContentType(request, reply); std::string lastModified = HttpMessage::htdate(st.st_ctime); { std::string s = request.getHeader(httpheader::ifModifiedSince); if (s == lastModified) return HTTP_NOT_MODIFIED; } reply.setHeader(httpheader::lastModified, lastModified); reply.setKeepAliveHeader(); reply.setHeader(httpheader::acceptRanges, "bytes"); if (!reply.hasHeader(httpheader::cacheControl)) { std::string maxAgeStr = request.getArg("maxAge"); unsigned maxAge = maxAgeStr.empty() ? 14400 : cxxtools::convert(maxAgeStr); reply.setMaxAgeHeader(maxAge); } // check for byte range (only "bytes=from-" or "bytes=from-to" are supported) const char* range = request.getHeader(httpheader::range, 0); if (range) { if (parseRange(range, offset, count)) { if (offset > st.st_size) return HTTP_RANGE_NOT_SATISFIABLE; if (offset + count > st.st_size) count = st.st_size - offset; reply.setHeader(httpheader::contentLocation, request.getUrl()); std::ostringstream contentRange; contentRange << offset << '-' << (offset+count)-1 << '/' << st.st_size; reply.setHeader(httpheader::contentRange, contentRange.str()); httpOkReturn = HTTP_PARTIAL_CONTENT; } else { log_debug("invalid byte range " << range); return HTTP_RANGE_NOT_SATISFIABLE; } } // set Content-Length reply.setContentLengthHeader(reply.getContentSize() + count); if (request.isMethodHEAD()) { log_debug("head request"); return httpOkReturn; } else { log_debug("no head request"); } // send data log_info("send file \"" << file << "\" size " << st.st_size << " bytes; offset=" << offset << " count=" << count); #if defined(HAVE_SENDFILE) && defined(HAVE_SYS_SENDFILE_H) if (request.isSsl()) { log_debug("no sendfile on ssl"); } else { try { int on = 1; int off = 0; cxxtools::net::iostream& tcpStream = dynamic_cast(reply.getDirectStream()); if (::setsockopt(tcpStream.getFd(), SOL_TCP, TCP_NODELAY, &off, sizeof(off)) < 0) throw cxxtools::SystemError("setsockopt(TCP_NODELAY)"); if (::setsockopt(tcpStream.getFd(), SOL_TCP, TCP_CORK, &on, sizeof(on)) < 0) throw cxxtools::SystemError("setsockopt(TCP_CORK)"); reply.setDirectMode(httpOkReturn, HttpReturn::httpMessage(httpOkReturn)); tcpStream.flush(); Fdfile in(file.c_str(), O_RDONLY); ssize_t s; while(tcpStream) { do { log_debug("sendfile offset " << offset << " size " << count); s = sendfile(tcpStream.getFd(), in.getFd(), &offset, count); log_debug("sendfile returns " << s); } while (s < 0 && errno == EINTR); if (s < 0 && errno != EAGAIN) throw cxxtools::SystemError("sendfile"); if (offset >= count || s == 0) break; log_debug("poll"); pollout(tcpStream.getFd(), tcpStream.getTimeout()); } if (::setsockopt(tcpStream.getFd(), SOL_TCP, TCP_CORK, &off, sizeof(off)) < 0) throw cxxtools::SystemError("setsockopt(TCP_CORK)"); if (::setsockopt(tcpStream.getFd(), SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) throw cxxtools::SystemError("setsockopt(TCP_NODELAY)"); return httpOkReturn; } catch (const std::bad_cast& e) { log_debug("stream is no tcpstream - don't use sendfile"); } } #endif reply.setDirectMode(); } std::ifstream in(file.c_str()); in.seekg(offset); if (!in) { log_debug("can't open file \"" << file << '"'); return DECLINED; } if (offset == 0 && count == st.st_size && count > 0) { reply.out() << in.rdbuf() << std::flush; if (in.fail()) throw std::runtime_error("failed to send file \"" + file + '"'); } else { char ch; off_t o; for (o = 0; in.get(ch) && o < count; ++o) reply.out().put(ch); if (o < count) throw std::runtime_error("failed to send file \"" + file + '"'); } return httpOkReturn; } } tntnet-3.0/framework/defcomp/static.h000066400000000000000000000040061365471676700177700ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_STATIC_H #define TNT_STATIC_H #include #include namespace tnt { class MimeHandler; class Static : public Component { friend class StaticFactory; MimeHandler* _handler; unsigned doCall(HttpRequest&, HttpReply&, QueryParams&, bool top); protected: void setContentType(HttpRequest&, HttpReply&); public: Static() : _handler(0) { } ~Static(); virtual void configure(const TntConfig&); virtual unsigned topCall(HttpRequest&, HttpReply&, QueryParams&); virtual unsigned operator() (HttpRequest&, HttpReply&, QueryParams&); }; } #endif // TNT_STATIC_H tntnet-3.0/framework/defcomp/unzipcomp.cpp000066400000000000000000000055051365471676700210650ustar00rootroot00000000000000/* * Copyright (C) 2003 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "static.h" #include "unzip.h" #include #include #include #include #include #include #include #include log_define("tntnet.unzip") namespace tnt { class MimeHandler; //////////////////////////////////////////////////////////////////////// // component declaration // class Unzip : public Static { friend class UnzipFactory; public: virtual unsigned operator() (tnt::HttpRequest&, tnt::HttpReply&, tnt::QueryParams&); }; static ComponentFactoryImpl factory("unzip"); //////////////////////////////////////////////////////////////////////// // component definition // unsigned Unzip::operator() (tnt::HttpRequest& request, tnt::HttpReply& reply, tnt::QueryParams&) { std::string pi = request.getPathInfo(); log_debug("unzip archive \"" << request.getArg("file") << "\" file \"" << pi << '"'); try { unzipFile f(request.getArg("file")); unzipFileStream in(f, pi, false); // set Content-Type std::string contentType = request.getArg("contenttype"); if (contentType.empty()) setContentType(request, reply); else reply.setContentType(contentType); reply.out() << in.rdbuf(); } catch (const unzipEndOfListOfFile&) { log_debug("file \"" << pi << "\" not found in archive"); return DECLINED; } return HTTP_OK; } } tntnet-3.0/framework/runtime/000077500000000000000000000000001365471676700163765ustar00rootroot00000000000000tntnet-3.0/framework/runtime/Makefile.am000066400000000000000000000005461365471676700204370ustar00rootroot00000000000000AM_CPPFLAGS = -I$(top_srcdir)/framework/common bin_PROGRAMS = tntnet tntnet_SOURCES = \ main.cpp \ process.cpp nobase_include_HEADERS = \ tnt/process.h tntnet_LDADD = $(top_builddir)/framework/common/libtntnet.la tntnet_LDFLAGS = -lcxxtools tntnet_CXXFLAGS=-DTNTNET_CONF=\"@sysconfdir@/tntnet/tntnet.xml\" -DTNTNET_PID=\"@localstatedir@/tntnet.pid\" tntnet-3.0/framework/runtime/main.cpp000066400000000000000000000164201365471676700200310ustar00rootroot00000000000000/* * Copyright (C) 2007 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/process.h" #include "tnt/tntnet.h" #include "tnt/cmd.h" #include "tnt/tntconfig.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #ifndef TNTNET_CONF # define TNTNET_CONF "/etc/tntnet.xml" #endif #ifndef TNTNET_PID # define TNTNET_PID "/var/run/tntnet.pid" #endif log_define("tntnet.main") namespace tnt { namespace { class Glob { private: glob_t _gl; unsigned _n; // non-copyable // TODO [tntnet-3.0]: use C++11 " = delete" syntax Glob(const Glob&); Glob& operator= (const Glob&); public: explicit Glob(const std::string& pattern, int flags = 0); ~Glob(); const char* current() const { return _gl.gl_pathv ? _gl.gl_pathv[_n] : 0; } const char* next() { if (_gl.gl_pathv && _gl.gl_pathv[_n]) ++_n; return current(); } }; Glob::Glob(const std::string& pattern, int flags) : _n(0) { int ret = ::glob(pattern.c_str(), flags, 0, &_gl); if (ret == GLOB_NOMATCH) { _gl.gl_pathv = 0; } else if (ret != 0) { std::ostringstream msg; msg << "failed to process glob pattern <" << pattern << "> errorcode " << ret; throw std::runtime_error(msg.str()); } } Glob::~Glob() { globfree(&_gl); } template void processConfigFile(const std::string& configFile, std::set& filesProcessed) { TntConfig& config = TntConfig::it(); std::ifstream in(configFile.c_str()); if (!in) throw std::runtime_error("failed to open configuration file \"" + configFile + '"'); Deserializer deserializer(in); deserializer.deserialize(config); in.close(); filesProcessed.insert(configFile); for (std::vector::size_type n = 0; n < config.includes.size(); ++n) { for (Glob glob(config.includes[n]); glob.current(); glob.next()) { std::string configFile = glob.current(); if (filesProcessed.find(configFile) == filesProcessed.end()) processConfigFile(glob.current(), filesProcessed); } } } #ifdef CXXTOOLS_XMLDESERIALISER_ATTR class XmlDeserializer : public cxxtools::xml::XmlDeserializer { public: XmlDeserializer(std::istream& is) : cxxtools::xml::XmlDeserializer(is, true) { } }; #endif } // namespace class TntnetProcess : public Process { private: tnt::Tntnet _tntnet; bool _logall; void initializeLogging(); protected: virtual void onInit(); virtual void doWork(); virtual void doShutdown(); public: TntnetProcess(int& argc, char* argv[]); }; TntnetProcess::TntnetProcess(int& argc, char* argv[]) : _logall(cxxtools::Arg(argc, argv, "--logall")) { std::string configFile; cxxtools::Arg jsonConfig(argc, argv, 'j'); // check for argument -c cxxtools::Arg conf(argc, argv, 'c'); if (conf.isSet()) configFile = conf; else { // read 1st parameter from argument-list cxxtools::Arg conf(argc, argv); if (conf.isSet()) configFile = conf; else { // check environment-variable TNTNET_CONF const char* tntnetConf = ::getenv("TNTNET_CONF"); if (tntnetConf) configFile = tntnetConf; else if (getuid() != 0) configFile = "tntnet.xml"; else configFile = TNTNET_CONF; // take default } } std::set filesProcessed; if (jsonConfig) processConfigFile(configFile, filesProcessed); else #ifdef CXXTOOLS_XMLDESERIALISER_ATTR processConfigFile(configFile, filesProcessed); #else processConfigFile(configFile, filesProcessed); #endif if (_logall) initializeLogging(); } void TntnetProcess::initializeLogging() { log_init(TntConfig::it().logConfiguration); } void TntnetProcess::onInit() { _tntnet.init(TntConfig::it()); } void TntnetProcess::doWork() { _tntnet.run(); } void TntnetProcess::doShutdown() { tnt::Tntnet::shutdown(); } } int main(int argc, char* argv[]) { std::ios::sync_with_stdio(false); try { cxxtools::Arg version(argc, argv, 'V'); cxxtools::Arg versionLong(argc, argv, "--version"); if (version || versionLong) { std::cout << PACKAGE_STRING << std::endl; return 0; } cxxtools::Arg help(argc, argv, 'h'); cxxtools::Arg helpLong(argc, argv, "--help"); if (help || helpLong) { // TODO: Add short explanation of available options std::cout << "usage: " << argv[0] << " [options] [config-file (default: " TNTNET_CONF ")]\n" "more info with \"man 8 tntnet\"" << std::endl; return 0; } cxxtools::Arg cmd(argc, argv, 'C'); if (cmd) { log_init("tntnet.xml"); tnt::Cmd cmdapp(std::cout); tnt::QueryParams queryParams; while (true) { cxxtools::Arg param(argc, argv, 'q'); if (!param.isSet()) break; queryParams.parse_url(param); } for (int a = 1; a < argc; ++a) { log_info("calling component <" << argv[a] << '>'); cmdapp.call(tnt::Compident(argv[a]), queryParams); } } else { tnt::TntnetProcess app(argc, argv); app.run(); } } catch(const std::exception& e) { log_fatal(e.what()); std::cerr << e.what() << std::endl; return -1; } } tntnet-3.0/framework/runtime/process.cpp000066400000000000000000000213241365471676700205620ustar00rootroot00000000000000/* * Copyright (C) 2006 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tnt/process.h" #include "tnt/tntconfig.h" #include #include #include #include #include #include #include #include #include #include #include log_define("tntnet.process") namespace { tnt::Process* theProcess = 0; extern "C" void sigEnd(int) { signal(SIGTERM, sigEnd); if (theProcess) theProcess->shutdown(); } extern "C" void sigReload(int) { signal(SIGHUP, sigReload); if (theProcess) theProcess->restart(); } void setGroup(const std::string& group) { struct group * gr = ::getgrnam(group.c_str()); if (gr == 0) throw std::runtime_error("unknown group " + group); log_debug("change group to " << group << '(' << gr->gr_gid << ')'); int ret = ::setgid(gr->gr_gid); if (ret != 0) throw cxxtools::SystemError("setgid"); } void setUser(const std::string& user) { struct passwd * pw = getpwnam(user.c_str()); if (pw == 0) throw std::runtime_error("unknown user " + user); log_debug("change user to " << user << '(' << pw->pw_uid << ')'); int ret = ::setgroups(0, NULL); if (ret != 0) throw cxxtools::SystemError("setgroups"); ret = ::setuid(pw->pw_uid); if (ret != 0) throw cxxtools::SystemError("getuid"); } void setDir(const std::string& dir) { log_debug("chdir(" << dir << ')'); if (::chdir(dir.c_str()) == -1) throw cxxtools::SystemError("chdir"); } void setRootdir(const std::string& dir) { if (::chroot(dir.c_str()) == -1) throw cxxtools::SystemError("chroot"); } class PidFile { private: std::string _pidFileName; public: PidFile(const std::string& pidFileName, pid_t pid); ~PidFile(); void releasePidFile() { _pidFileName.clear(); } }; PidFile::PidFile(const std::string& pidFileName, pid_t pid) : _pidFileName(pidFileName) { if (_pidFileName.empty()) return; if (_pidFileName[0] != '/') { // prepend current working-directory to pidfilename if not absolute std::vector buf(256); const char* cwd; while (true) { cwd = ::getcwd(&buf[0], buf.size()); if (cwd) break; else if (errno == ERANGE) buf.resize(buf.size() * 2); else throw cxxtools::SystemError("getcwd"); } _pidFileName = std::string(cwd) + '/' + _pidFileName; log_debug("pidfile=" << _pidFileName); } std::ofstream pidfile(_pidFileName.c_str()); if (pidfile.fail()) throw std::runtime_error("unable to open pid-file " + _pidFileName); pidfile << pid; if (pidfile.fail()) throw std::runtime_error("error writing to pid-file " + _pidFileName); } PidFile::~PidFile() { if (!_pidFileName.empty()) ::unlink(_pidFileName.c_str()); } void closeStdHandles(const std::string& errorLog = std::string()) { if (::freopen("/dev/null", "r", stdin) == 0) throw cxxtools::SystemError("freopen(stdin)"); if (::freopen("/dev/null", "w", stdout) == 0) throw cxxtools::SystemError("freopen(stdout)"); if (!errorLog.empty()) { if (::freopen(errorLog.c_str(), "a+", stderr) == 0) throw cxxtools::SystemError("freopen(stderr)"); } } } namespace tnt { Process::Process() { theProcess = this; } Process::~Process() { if (theProcess == this) theProcess = 0; } void Process::runMonitor(cxxtools::posix::Pipe& mainPipe) { log_debug("run monitor"); // setsid if (setsid() == -1) throw cxxtools::SystemError("setsid"); bool first = true; while (true) { cxxtools::posix::Pipe monitorPipe; cxxtools::posix::Fork fork; if (fork.child()) { // worker process log_debug("close read-fd of monitor-pipe"); monitorPipe.closeReadFd(); initWorker(); if (first) { log_debug("signal initialization ready"); mainPipe.write('1'); log_debug("close write-fd of main-pipe"); mainPipe.closeWriteFd(); } log_debug("close standard-handles"); closeStdHandles(tnt::TntConfig::it().errorLog); _exitRestart = false; log_debug("do work"); doWork(); // normal shutdown if (_exitRestart) log_debug("restart"); else { log_debug("signal shutdown"); try { monitorPipe.write('s'); } catch (const std::exception& e) { log_debug("ingore exception from monitor pipe: " << e.what()); } } return; } // monitor process log_debug("write pid " << fork.getPid() << " to \"" << tnt::TntConfig::it().pidfile << '"'); PidFile p(tnt::TntConfig::it().pidfile, fork.getPid()); if (first) { log_debug("close standard-handles"); closeStdHandles(); first = false; } monitorPipe.closeWriteFd(); try { log_debug("monitor child"); char dummy; size_t c = monitorPipe.read(&dummy, 1); if (c > 0) { log_debug("child terminated normally"); return; } log_debug("nothing read from monitor-pipe - restart child"); } catch (const cxxtools::SystemError&) { log_debug("child exited without notification"); } log_debug("wait for child-termination"); fork.wait(); ::sleep(1); } } void Process::initWorker() { log_debug("init worker"); log_debug("onInit"); onInit(); if (!tnt::TntConfig::it().group.empty()) { log_debug("set group to \"" << tnt::TntConfig::it().group << '"'); ::setGroup(tnt::TntConfig::it().group); } if (!tnt::TntConfig::it().user.empty()) { log_debug("set user to \"" << tnt::TntConfig::it().user << '"'); ::setUser(tnt::TntConfig::it().user); } if (!tnt::TntConfig::it().dir.empty()) { log_debug("set dir to \"" << tnt::TntConfig::it().dir << '"'); ::setDir(tnt::TntConfig::it().dir); } if (!tnt::TntConfig::it().chrootdir.empty()) { log_debug("change root to \"" << tnt::TntConfig::it().chrootdir << '"'); ::setRootdir(tnt::TntConfig::it().chrootdir); } signal(SIGTERM, sigEnd); signal(SIGINT, sigEnd); signal(SIGHUP, sigReload); } void Process::run() { if (tnt::TntConfig::it().daemon) { log_debug("run daemon-mode"); // We receive the writing-end of the notify pipe. // After successful initialization we need to write a byte to this fd. cxxtools::posix::Pipe mainPipe; cxxtools::posix::Fork fork; if (fork.parent()) { log_debug("close write-fd of main-pipe"); mainPipe.closeWriteFd(); log_debug("wait for child to initialize"); mainPipe.read(); log_debug("child initialized"); fork.setNowait(); } else { log_debug("close read-fd of main-pipe"); mainPipe.closeReadFd(); runMonitor(mainPipe); } } else { log_debug("run"); initWorker(); log_debug("do work"); doWork(); } } void Process::shutdown() { doShutdown(); } void Process::restart() { _exitRestart = true; doShutdown(); } } tntnet-3.0/framework/runtime/tnt/000077500000000000000000000000001365471676700172035ustar00rootroot00000000000000tntnet-3.0/framework/runtime/tnt/process.h000066400000000000000000000035671365471676700210450ustar00rootroot00000000000000/* * Copyright (C) 2007 Tommi Maekitalo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * As a special exception, you may use this file as part of a free * software library without restriction. Specifically, if other files * instantiate templates or use macros or inline functions from this * file, or you compile this file and link it with other files to * produce an executable, this file does not by itself cause the * resulting executable to be covered by the GNU General Public * License. This exception does not however invalidate any other * reasons why the executable file might be covered by the GNU Library * General Public License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TNT_PROCESS_H #define TNT_PROCESS_H #include #include namespace tnt { class Process { bool _exitRestart; int mkDaemon(cxxtools::posix::Pipe& pipe); void runMonitor(cxxtools::posix::Pipe& mainPipe); void initWorker(); public: Process(); ~Process(); void run(); void shutdown(); void restart(); protected: virtual void onInit() = 0; virtual void doWork() = 0; virtual void doShutdown() = 0; }; } #endif // TNT_PROCESS_H tntnet-3.0/m4/000077500000000000000000000000001365471676700132365ustar00rootroot00000000000000tntnet-3.0/m4/acx_pthread.m4000066400000000000000000000224171365471676700157700ustar00rootroot00000000000000dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) dnl dnl @summary figure out how to build C programs using POSIX threads dnl dnl This macro figures out how to build C programs using POSIX threads. dnl It sets the PTHREAD_LIBS output variable to the threads library and dnl linker flags, and the PTHREAD_CFLAGS output variable to any special dnl C compiler flags that are needed. (The user can also force certain dnl compiler flags/libs to be tested by setting these environment dnl variables.) dnl dnl Also sets PTHREAD_CC to any special C compiler that is needed for dnl multi-threaded programs (defaults to the value of CC otherwise). dnl (This is necessary on AIX to use the special cc_r compiler alias.) dnl dnl NOTE: You are assumed to not only compile your program with these dnl flags, but also link it with them as well. e.g. you should link dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS dnl $LIBS dnl dnl If you are only building threads programs, you may wish to use dnl these variables in your default LIBS, CFLAGS, and CC: dnl dnl LIBS="$PTHREAD_LIBS $LIBS" dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" dnl CC="$PTHREAD_CC" dnl dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). dnl dnl ACTION-IF-FOUND is a list of shell commands to run if a threads dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the dnl default action will define HAVE_PTHREAD. dnl dnl Please let the authors know if this macro fails on any platform, or dnl if you have any other suggestions or comments. This macro was based dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros dnl posted by Alejandro Forero Cuervo to the autoconf macro repository. dnl We are also grateful for the helpful feedback of numerous users. dnl dnl @category InstalledPackages dnl @author Steven G. Johnson dnl @version 2005-06-15 dnl @license GPLWithACException AC_DEFUN([ACX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_SAVE AC_LANG_C acx_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) AC_MSG_RESULT($acx_pthread_ok) if test x"$acx_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. acx_pthread_flags="pthreads pthread none -Kthread -kthread lthread -pthread -pthreads -mthreads -mt --thread-safe pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case "${host_cpu}-${host_os}" in *solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: acx_pthread_flags="-pthreads -mt pthread -pthread $acx_pthread_flags" ;; esac if test x"$acx_pthread_ok" = xno; then for flag in $acx_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; pthread-config) AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) if test x"$acx_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [acx_pthread_ok=yes]) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT($acx_pthread_ok) if test "x$acx_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$acx_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_MSG_CHECKING([for joinable pthread attribute]) attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_TRY_LINK([#include ], [int attr=$attr; return attr;], [attr_name=$attr; break]) done AC_MSG_RESULT($attr_name) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, [Define to necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case "${host_cpu}-${host_os}" in *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; esac AC_MSG_RESULT(${flag}) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: must compile with cc_r AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC}) AC_CHECK_PROG(PTHREAD_CXX, CC_r, CC_r, ${CXX}) else PTHREAD_CC="$CC" PTHREAD_CXX="$CXX" fi AC_SUBST(PTHREAD_LIBS) AC_SUBST(PTHREAD_CFLAGS) AC_SUBST(PTHREAD_CC) AC_SUBST(PTHREAD_CXX) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$acx_pthread_ok" = xyes; then ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) : else acx_pthread_ok=no $2 fi AC_LANG_RESTORE ])dnl ACX_PTHREAD tntnet-3.0/m4/ax_check_compile_flag.m4000066400000000000000000000062511365471676700177520ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) # # DESCRIPTION # # Check whether the given FLAG works with the current language's compiler # or gives an error. (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 2 AC_DEFUN([AX_CHECK_COMPILE_FLAG], [AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_COMPILE_FLAGS tntnet-3.0/m4/ax_compiler_vendor.m4000066400000000000000000000066161365471676700173700ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_compiler_vendor.html # =========================================================================== # # SYNOPSIS # # AX_COMPILER_VENDOR # # DESCRIPTION # # Determine the vendor of the C/C++ compiler, e.g., gnu, intel, ibm, sun, # hp, borland, comeau, dec, cray, kai, lcc, metrowerks, sgi, microsoft, # watcom, etc. The vendor is returned in the cache variable # $ax_cv_c_compiler_vendor for C and $ax_cv_cxx_compiler_vendor for C++. # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # Copyright (c) 2008 Matteo Frigo # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 11 AC_DEFUN([AX_COMPILER_VENDOR], [AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor, [# note: don't check for gcc first since some other compilers define __GNUC__ vendors="intel: __ICC,__ECC,__INTEL_COMPILER ibm: __xlc__,__xlC__,__IBMC__,__IBMCPP__ pathscale: __PATHCC__,__PATHSCALE__ clang: __clang__ gnu: __GNUC__ sun: __SUNPRO_C,__SUNPRO_CC hp: __HP_cc,__HP_aCC dec: __DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland: __BORLANDC__,__TURBOC__ comeau: __COMO__ cray: _CRAYC kai: __KCC lcc: __LCC__ sgi: __sgi,sgi microsoft: _MSC_VER metrowerks: __MWERKS__ watcom: __WATCOMC__ portland: __PGI unknown: UNKNOWN" for ventest in $vendors; do case $ventest in *:) vendor=$ventest; continue ;; *) vencpp="defined("`echo $ventest | sed 's/,/) || defined(/g'`")" ;; esac AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[ #if !($vencpp) thisisanerror; #endif ])], [break]) done ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=`echo $vendor | cut -d: -f1` ]) ]) tntnet-3.0/m4/ax_cxx_compile_stdcxx_11.m4000066400000000000000000000112751365471676700204060ustar00rootroot00000000000000# ============================================================================ # http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html # ============================================================================ # # SYNOPSIS # # AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional]) # # DESCRIPTION # # Check for baseline language coverage in the compiler for the C++11 # standard; if necessary, add switches to CXXFLAGS to enable support. # # The first argument, if specified, indicates whether you insist on an # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. # -std=c++11). If neither is specified, you get whatever works, with # preference for an extended mode. # # The second argument, if specified 'mandatory' or if left unspecified, # indicates that baseline C++11 support is required and that the macro # should error out if no mode with that support is found. If specified # 'optional', then configuration proceeds regardless, after defining # HAVE_CXX11 if and only if a supporting mode is found. # # LICENSE # # Copyright (c) 2008 Benjamin Kosnik # Copyright (c) 2012 Zack Weinberg # Copyright (c) 2013 Roy Stogner # Copyright (c) 2014 Alexey Sokolov # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 4 m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[ template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; struct Base { virtual void f() {} }; struct Child : public Base { virtual void f() override {} }; typedef check> right_angle_brackets; int a; decltype(a) b; typedef check check_type; check_type c; check_type&& cr = static_cast(c); auto d = a; auto l = [](){}; ]]) AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl m4_if([$1], [], [], [$1], [ext], [], [$1], [noext], [], [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl m4_if([$2], [], [ax_cxx_compile_cxx11_required=true], [$2], [mandatory], [ax_cxx_compile_cxx11_required=true], [$2], [optional], [ax_cxx_compile_cxx11_required=false], [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])]) AC_LANG_PUSH([C++])dnl ac_success=no AC_CACHE_CHECK(whether $CXX supports C++11 features by default, ax_cv_cxx_compile_cxx11, [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [ax_cv_cxx_compile_cxx11=yes], [ax_cv_cxx_compile_cxx11=no])]) if test x$ax_cv_cxx_compile_cxx11 = xyes; then ac_success=yes fi m4_if([$1], [noext], [], [dnl if test x$ac_success = xno; then for switch in -std=gnu++11 -std=gnu++0x; do cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, $cachevar, [ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [eval $cachevar=yes], [eval $cachevar=no]) CXXFLAGS="$ac_save_CXXFLAGS"]) if eval test x\$$cachevar = xyes; then CXXFLAGS="$CXXFLAGS $switch" ac_success=yes break fi done fi]) m4_if([$1], [ext], [], [dnl if test x$ac_success = xno; then for switch in -std=c++11 -std=c++0x; do cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, $cachevar, [ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [eval $cachevar=yes], [eval $cachevar=no]) CXXFLAGS="$ac_save_CXXFLAGS"]) if eval test x\$$cachevar = xyes; then CXXFLAGS="$CXXFLAGS $switch" ac_success=yes break fi done fi]) AC_LANG_POP([C++]) if test x$ax_cxx_compile_cxx11_required = xtrue; then if test x$ac_success = xno; then AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.]) fi else if test x$ac_success = xno; then HAVE_CXX11=0 AC_MSG_NOTICE([No compiler with C++11 support was found]) else HAVE_CXX11=1 AC_DEFINE(HAVE_CXX11,1, [define if the compiler supports basic C++11 syntax]) fi AC_SUBST(HAVE_CXX11) fi ]) tntnet-3.0/m4/pkg.m4000066400000000000000000000124731365471676700142700ustar00rootroot00000000000000# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 1 (pkg-config-0.24) # # Copyright © 2004 Scott James Remnant . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # PKG_PROG_PKG_CONFIG([MIN-VERSION]) # ---------------------------------- AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_PATH)?$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])# PKG_PROG_PKG_CONFIG # PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # # Check to see whether a particular set of modules exists. Similar # to PKG_CHECK_MODULES(), but does not set variables or print errors. # # Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) # only at the first occurence in configure.ac, so if the first place # it's called might be skipped (such as if it is within an "if", you # have to call PKG_CHECK_EXISTS manually # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) # --------------------------------------------- m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])# _PKG_CONFIG # _PKG_SHORT_ERRORS_SUPPORTED # ----------------------------- AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])# _PKG_SHORT_ERRORS_SUPPORTED # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], # [ACTION-IF-NOT-FOUND]) # # # Note that if there is a possibility the first call to # PKG_CHECK_MODULES might not happen, you should be sure to include an # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac # # # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT]) ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .]) ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])# PKG_CHECK_MODULES tntnet-3.0/misc/000077500000000000000000000000001365471676700136515ustar00rootroot00000000000000tntnet-3.0/misc/Makefile.am000066400000000000000000000115231365471676700157070ustar00rootroot00000000000000bin_SCRIPTS = tntnet-project nobase_dist_pkgdata_DATA = \ template/module/resources/@PROJECT@.css \ template/module/Makefile.am \ template/module/m4/ax_cxx_compile_stdcxx_11.m4 \ template/module/m4/ax_check_compile_flag.m4 \ template/module/tntnet.xml \ template/module/configure.ac \ template/module/log.properties \ template/module/@PROJECT@.ecpp \ template/default/resources/@PROJECT@.css \ template/default/README.md \ template/default/main.cpp \ template/default/Makefile.am \ template/default/m4/ax_cxx_compile_stdcxx_11.m4 \ template/default/m4/ax_check_compile_flag.m4 \ template/default/configure.ac \ template/default/@PROJECT@.ecpp \ template/default/@PROJECT@.xml \ template/webapp/README.md \ template/webapp/resources/app/actions.js \ template/webapp/resources/app/json.js \ template/webapp/resources/app/main.js \ template/webapp/resources/app/dbaccess.js \ template/webapp/resources/app/dbinsert.js \ template/webapp/resources/css/noty/themes/nest.css \ template/webapp/resources/css/noty/themes/relax.css \ template/webapp/resources/css/noty/themes/mint.css \ template/webapp/resources/css/noty/themes/semanticui.css \ template/webapp/resources/css/noty/themes/light.css \ template/webapp/resources/css/noty/themes/metroui.css \ template/webapp/resources/css/noty/themes/sunset.css \ template/webapp/resources/css/noty/themes/bootstrap-v4.css \ template/webapp/resources/css/noty/themes/bootstrap-v3.css \ template/webapp/resources/css/@PROJECT@.css \ template/webapp/resources/css/statusbar.css \ template/webapp/resources/css/noty.css.map \ template/webapp/resources/css/noty.css \ template/webapp/resources/css/dropdown.css \ template/webapp/resources/html/json.html \ template/webapp/resources/html/dbaccess.html \ template/webapp/resources/html/dbinsert.html \ template/webapp/resources/html/actions.html \ template/webapp/resources/js/require.js \ template/webapp/resources/js/main.js \ template/webapp/resources/js/jquery-3.3.1.min.js \ template/webapp/resources/js/noty.min.js \ template/webapp/resources/js/tntnet.js \ template/webapp/resources/js/noty.js \ template/webapp/webmain.ecpp \ template/webapp/json/getnumbers.ecpp \ template/webapp/json/example.ecpp \ template/webapp/json/dbaccess.ecpp \ template/webapp/include/actionreply.h \ template/webapp/include/@PROJECT@/config.h \ template/webapp/include/noty.h \ template/webapp/@PROJECT@.xml \ template/webapp/src/main.cpp \ template/webapp/src/@PROJECT@/config.cpp \ template/webapp/Makefile.am \ template/webapp/action.ecpp \ template/webapp/m4/ax_cxx_compile_stdcxx_11.m4 \ template/webapp/m4/ax_check_compile_flag.m4 \ template/webapp/action/README \ template/webapp/action/myaction.cpp \ template/webapp/action/insertdata.ecpp \ template/webapp/action/myaction.ecpp \ template/webapp/configure.ac \ template/webapp/log.properties \ template/webapp/test.sql \ template/webapp/actionmain.ecpp \ template/mvc/resources/@PROJECT@.css \ template/mvc/resources/mypage.js \ template/mvc/resources/js/noty/jquery.noty.js \ template/mvc/resources/js/noty/packaged/jquery.noty.packaged.min.js \ template/mvc/resources/js/noty/packaged/jquery.noty.packaged.js \ template/mvc/resources/js/noty/layouts/centerRight.js \ template/mvc/resources/js/noty/layouts/bottom.js \ template/mvc/resources/js/noty/layouts/top.js \ template/mvc/resources/js/noty/layouts/topCenter.js \ template/mvc/resources/js/noty/layouts/topLeft.js \ template/mvc/resources/js/noty/layouts/bottomLeft.js \ template/mvc/resources/js/noty/layouts/bottomRight.js \ template/mvc/resources/js/noty/layouts/topRight.js \ template/mvc/resources/js/noty/layouts/bottomCenter.js \ template/mvc/resources/js/noty/layouts/inline.js \ template/mvc/resources/js/noty/layouts/centerLeft.js \ template/mvc/resources/js/noty/layouts/center.js \ template/mvc/resources/js/noty/promise.js \ template/mvc/resources/js/noty/themes/relax.js \ template/mvc/resources/js/noty/themes/bootstrap.js \ template/mvc/resources/js/noty/themes/default.js \ template/mvc/resources/js/tntnet.js \ template/mvc/resources/js/jquery-3.3.1.min.js \ template/mvc/resources/myapp.css \ template/mvc/README.md \ template/mvc/webmain.ecpp \ template/mvc/json/example.ecpp \ template/mvc/json/README \ template/mvc/main.cpp \ template/mvc/model/index.ecpp \ template/mvc/html/README \ template/mvc/@PROJECT@.xml \ template/mvc/configuration.h \ template/mvc/actionreply.h \ template/mvc/Makefile.am \ template/mvc/controller/index.ecpp \ template/mvc/action.ecpp \ template/mvc/m4/ax_cxx_compile_stdcxx_11.m4 \ template/mvc/m4/ax_check_compile_flag.m4 \ template/mvc/action/README \ template/mvc/action/myaction.ecpp \ template/mvc/noty.h \ template/mvc/session.ecpp \ template/mvc/configuration.cpp \ template/mvc/configure.ac \ template/mvc/view/mypage.ecpp \ template/mvc/view/index.ecpp \ template/mvc/actionmain.ecpp tntnet-3.0/misc/ecpp.vim000066400000000000000000000110531365471676700153150ustar00rootroot00000000000000" Vim syntax file " Language: ECPP " Maintainer: Tommi Maekitalo " Last change: 2003 Sep 10 " URL: http://www.maekitalo.de/vim/ecpp.vim " " if version < 600 syn clear elseif exists("b:current_syntax") finish endif " The HTML syntax file included below uses this variable. " if !exists("main_syntax") let main_syntax = 'ecpp' endif " First pull in the HTML syntax. " if version < 600 so :p:h/html.vim else runtime! syntax/html.vim unlet b:current_syntax endif syn cluster htmlPreproc add=@ecppTop " Now pull in the cpp syntax. " if version < 600 syn include @cppTop :p:h/cpp.vim else syn include @cppTop syntax/cpp.vim endif " It's hard to reduce down to the correct sub-set of Cpp to highlight in some " of these cases so I've taken the safe option of just using cppTop in all of " them. If you have any suggestions, please let me know. " syn match ecppCondExprDelim "?" " Eat opening braces when starting c++-regions - I don't exactly know, why " this is needed - it just works better syn region ecppLine matchgroup=Delimiter start="^%" end="{*\s*$" contains=@cppTop syn region ecppExpr matchgroup=Delimiter start="<\$" end="{*\s*\$>" contains=@cppTop syn region ecppCondExpr matchgroup=Delimiter start="" contains=ecppCondExprDelim,@cppTop syn region ecppCpp matchgroup=Delimiter start="<%cpp>" end="{*\s*" contains=@cppTop syn region ecppCpps matchgroup=Delimiter start="<{" end="}>" contains=@cppTop syn region ecppComp keepend matchgroup=Delimiter start="<&" end=">" contains=@cppTop syn region ecppEndComp keepend matchgroup=Delimiter start="" contains=@cppTop syn region ecppArgs matchgroup=Delimiter start="<%args>" end="" contains=@cppTop syn region ecppGet matchgroup=Delimiter start="<%get>" end="" contains=@cppTop syn region ecppPost matchgroup=Delimiter start="<%post>" end="" contains=@cppTop syn region ecppConfig matchgroup=Delimiter start="<%config>" end="" contains=@cppTop syn region ecppAttr matchgroup=Delimiter start="<%attr>" end="" contains=@cppTop syn region ecppVar matchgroup=Delimiter start='<%\z(application\|session\|securesession\|request\|thread\)\s*\n*\s*\(scope\s*=\s*"\(shared\|global\|page\|component\)"\)\?\s*\n*\s*\(include\s*=\s*".*"\s*\n*\s*\)*\s*>' end='' contains=@cppTop syn region ecppVar matchgroup=Delimiter start="<%param>" end="" contains=@cppTop syn region ecppInit matchgroup=Delimiter start="<%init>" end="" contains=@cppTop syn region ecppPre matchgroup=Delimiter start="<%pre>" end="" contains=@cppTop syn region ecppCleanup matchgroup=Delimiter start="<%cleanup>" end="" contains=@cppTop syn region ecppShared matchgroup=Delimiter start="<%shared>" end="" contains=@cppTop syn region ecppClose matchgroup=Delimiter start="<%close>" end="" contains=@cppTop syn region ecppSout matchgroup=Delimiter start="<%out>" end="" contains=@cppTop syn region ecppOut matchgroup=Delimiter start="<%sout>" end="" contains=@cppTop syn region ecppIncluded display contained start=+"+ skip=+\\\\\|\\"+ end=+"+ syn match ecppIncluded display contained "<[^>]*>" syn region ecppInclude matchgroup=Delimiter start="<%include>" end="" contains=@ecppIncluded " syn region ecppMethod matchgroup=Delimiter start="<%method[^>]*>" end="" contains=@htmlTop syn region ecppDoc matchgroup=Delimiter start="<%doc>" end="" syn region ecppComment matchgroup=Delimiter start="<#" end="#>" contains=@cCommentGroup syn region ecppCommentm matchgroup=Delimiter start="<%doc>" end="" contains=@cCommentGroup syn region ecppTranslateTag matchgroup=Delimiter start="{" end="}" " syn match ecppTranslate contained "[^}]\+" syn cluster ecppTop contains=ecppLine,ecppExpr,ecppCondExpr,ecppCpp,ecppCpps,ecppComp,ecppEndComp,ecppArgs,ecppAttr,ecppConfig,ecppVar,ecppInit,ecppPre,ecppCleanup,ecppShared,ecppDoc,ecppComment,ecppCommentm,ecppTranslateTag,ecppInclude syn region ecppDef matchgroup=Delimiter start="<%def[^>]*>" end="" contains=@htmlTop " Set up default highlighting. Almost all of this is done in the included " syntax files. " if version >= 508 || !exists("did_ecpp_syn_inits") if version < 508 let did_ecpp_syn_inits = 1 com -nargs=+ HiLink hi link else com -nargs=+ HiLink hi def link endif HiLink ecppDoc Comment HiLink ecppComment Comment HiLink ecppCommentm Comment HiLink ecppTranslateTag Identifier HiLink ecppIncluded String delc HiLink endif let b:current_syntax = "ecpp" if main_syntax == 'ecpp' unlet main_syntax endif tntnet-3.0/misc/ecpp.xpt.vim000066400000000000000000000045651365471676700161410ustar00rootroot00000000000000XPTemplate priority=personal let s:f = g:XPTfuncs() XPTinclude \ _common/common let s:nIndent = 0 fun! s:f.ecpp_cont_ontype() let v = self.V() if v =~ '\V\n' let v = matchstr( v, '\V\.\*\S\ze\s\*\n' ) let s:nIndent = &indentexpr != '' \ ? eval( substitute( &indentexpr, '\Vv:lnum', 'line(".")', '') ) - indent( line( "." ) - 1 ) \ : self.NIndent() return self.FinishOuter( v . "\n" . repeat( '', s:nIndent ) ) else return v endif endfunction fun! s:f.ecpp_cont_helper() let v = self.V() if v =~ '\V\n' return self.ResetIndent( -s:nIndent, "\n" ) else return matchstr( v, '\V\^\s\*' ) endif endfunction XPT # XSET content|ontype=ecpp_cont_ontype() <#` `content^^`content^ecpp_cont_helper()^#> XPT $ " <$ expr $> <$ `expr^ $> XPT $$ " <$$ expr $> <$$ `expr^ $> XPT ? " XPT ?? " XPT & " <& component [ arguments ] > <& `component^` `arguments^ &> XPT <{ " <{...}> <{ `cursor^ }> XPT app " <%application>... <%application` scope="`scope`"^> `cursor^ XSET scope=ChooseStr('component', 'page', 'shared') XSET scope|post=Echo( V() =~ '""' ? "" : V() ) XPT arg " <%args>... <%args> `cursor^ XPT conf " <%config>... <%config> `cursor^ XPT cpp " <%cpp>... <%cpp> `cursor^ XPT def " <%def>... <%def `name^> `cursor^ XPT doc " <%doc>... <%doc> `cursor^ XPT inc " <%include>... <%include> `cursor^ XPT par " <%param>... <%param` scope="`scope`"^> `cursor^ XSET scope=ChooseStr('component', 'page', 'shared') XSET scope|post=Echo( V() =~ '""' ? "" : V() ) XPT pre " <%pre>... <%pre> `cursor^ XPT req " <%request>... <%request` scope="`scope`"^> `cursor^ XSET scope=ChooseStr('component', 'page', 'shared') XSET scope|post=Echo( V() =~ '""' ? "" : V() ) XPT ses " ... <%session` scope="`scope`"^> `cursor^ XSET scope=ChooseStr('component', 'page', 'shared') XSET scope|post=Echo( V() =~ '""' ? "" : V() ) XPT thr " ... <%thread` scope="`scope`"^> `cursor^ XSET scope=ChooseStr('component', 'page', 'shared') XSET scope|post=Echo( V() =~ '""' ? "" : V() ) tntnet-3.0/misc/template/000077500000000000000000000000001365471676700154645ustar00rootroot00000000000000tntnet-3.0/misc/template/default/000077500000000000000000000000001365471676700171105ustar00rootroot00000000000000tntnet-3.0/misc/template/default/@PROJECT@.ecpp000066400000000000000000000011051365471676700212640ustar00rootroot00000000000000<%pre> // put your includes here // #include "@PROJECT@.h" <%args> // define the query parameters // bar; <%session> // define your session scope variables here // std::string mySessionState; <%cpp> // put your C++ code here tntnet application @PROJECT@

@PROJECT@

Hello world!

tntnet-3.0/misc/template/default/@PROJECT@.xml000066400000000000000000000016121365471676700211400ustar00rootroot00000000000000 8000 INFO tntnet INFO component.@PROJECT@ INFO @PROJECT@ tntnet-3.0/misc/template/default/Makefile.am000066400000000000000000000015571365471676700211540ustar00rootroot00000000000000ACLOCAL_AMFLAGS = -I m4 AUTOMAKE_OPTIONS = subdir-objects bin_PROGRAMS = @PROJECT@ ecppSources = \ @PROJECT@.ecpp staticSources = \ resources/@PROJECT@.css @CPROJECT@_SOURCES = \ main.cpp \ $(ecppSources) nodist_@CPROJECT@_SOURCES = \ resources.cpp @CPROJECT@_LDADD = -lcxxtools -ltntnet nobase_dist_noinst_DATA = $(staticSources) CLEANFILES = $(ecppSources:.ecpp=.cpp) $(ecppSources:.ecpp=.deps) resources.cpp # # Rules for tntnet applications # ECPPFLAGS=-I$(srcdir) resources.cpp: $(staticSources) Makefile.am $(AM_V_GEN)$(ECPPC) -bb -z -n resources -p -o resources.cpp $(ECPPFLAGS) $(staticSources) SUFFIXES=.ecpp .cpp .ecpp.cpp: $(AM_V_GEN)$(ECPPC) -n `echo $<|$(SED) 's|^$(srcdir)/||; s|\.ecpp$$||'` $(ECPPFLAGS) -o $@ $< .ecpp.deps: $(AM_V_GEN)$(ECPPC) -M $(ECPPFLAGS) $< | $(SED) '1s|\(.*\).cpp:|\1.cpp $@:|' > $@ -include $(ecppSources:.ecpp=.deps) tntnet-3.0/misc/template/default/README.md000066400000000000000000000016261365471676700203740ustar00rootroot00000000000000Tntnet project @PROJECT@ =========================== This is a simple tntnet web project, which runs as a standalone application. Autoconf, automake and libtool, commonly known as the autotools, is used for building the application. Building -------- The `autotools` are set up and `autoreconf -i` is run already. To build run `./configure && make`. To rebuild after changing code run just `make`. To add new source files to the project add them to `Makefile.am`. Adding files ------------ When you create ecpp files, don't forget to add them to `Makefile.am`. Static files belong to to the _resources_ directory and also to `Makefile.am`. Deployment ---------- To deploy a application add your e-mail address into configure.ac and possibly change the version number. Calling `make dist` creates a tar.gz archive with source of the application. Building that application autotools are not needed any more. tntnet-3.0/misc/template/default/configure.ac000066400000000000000000000012221365471676700213730ustar00rootroot00000000000000AC_INIT([@PROJECT@], [0.1], [your-email@somewhere]) AM_INIT_AUTOMAKE([foreign]) LT_INIT AC_CONFIG_MACRO_DIR([m4]) AC_PROG_CXX AC_LANG(C++) AX_CXX_COMPILE_STDCXX_11(noext, optional) AC_CONFIG_HEADERS([config.h]) AC_CHECK_HEADER([cxxtools/mutex.h], , AC_MSG_ERROR([cxxtools headers not found])) AC_CHECK_HEADER([tnt/httpreply.h], , AC_MSG_ERROR([tntnet headers not found])) #AC_CHECK_HEADER([tntdb/connection.h], , AC_MSG_ERROR([tntdb headers not found])) AC_CHECK_PROGS(ECPPC, [ecppc]) AC_PROG_SED AX_CHECK_COMPILE_FLAG([-Wall], [CPPFLAGS="$CPPFLAGS -Wall"]) AX_CHECK_COMPILE_FLAG([-pedantic], [CPPFLAGS="$CPPFLAGS -pedantic"]) AC_OUTPUT([ Makefile ]) tntnet-3.0/misc/template/default/m4/000077500000000000000000000000001365471676700174305ustar00rootroot00000000000000tntnet-3.0/misc/template/default/m4/ax_check_compile_flag.m4000066400000000000000000000064111365471676700241420ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # # Check whether the given FLAG works with the current language's compiler # or gives an error. (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # INPUT gives an alternative input source to AC_COMPILE_IFELSE. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 3 AC_DEFUN([AX_CHECK_COMPILE_FLAG], [AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_COMPILE_FLAGS tntnet-3.0/misc/template/default/m4/ax_cxx_compile_stdcxx_11.m4000066400000000000000000000112751365471676700246000ustar00rootroot00000000000000# ============================================================================ # http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html # ============================================================================ # # SYNOPSIS # # AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional]) # # DESCRIPTION # # Check for baseline language coverage in the compiler for the C++11 # standard; if necessary, add switches to CXXFLAGS to enable support. # # The first argument, if specified, indicates whether you insist on an # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. # -std=c++11). If neither is specified, you get whatever works, with # preference for an extended mode. # # The second argument, if specified 'mandatory' or if left unspecified, # indicates that baseline C++11 support is required and that the macro # should error out if no mode with that support is found. If specified # 'optional', then configuration proceeds regardless, after defining # HAVE_CXX11 if and only if a supporting mode is found. # # LICENSE # # Copyright (c) 2008 Benjamin Kosnik # Copyright (c) 2012 Zack Weinberg # Copyright (c) 2013 Roy Stogner # Copyright (c) 2014 Alexey Sokolov # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 4 m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[ template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; struct Base { virtual void f() {} }; struct Child : public Base { virtual void f() override {} }; typedef check> right_angle_brackets; int a; decltype(a) b; typedef check check_type; check_type c; check_type&& cr = static_cast(c); auto d = a; auto l = [](){}; ]]) AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl m4_if([$1], [], [], [$1], [ext], [], [$1], [noext], [], [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl m4_if([$2], [], [ax_cxx_compile_cxx11_required=true], [$2], [mandatory], [ax_cxx_compile_cxx11_required=true], [$2], [optional], [ax_cxx_compile_cxx11_required=false], [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])]) AC_LANG_PUSH([C++])dnl ac_success=no AC_CACHE_CHECK(whether $CXX supports C++11 features by default, ax_cv_cxx_compile_cxx11, [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [ax_cv_cxx_compile_cxx11=yes], [ax_cv_cxx_compile_cxx11=no])]) if test x$ax_cv_cxx_compile_cxx11 = xyes; then ac_success=yes fi m4_if([$1], [noext], [], [dnl if test x$ac_success = xno; then for switch in -std=gnu++11 -std=gnu++0x; do cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, $cachevar, [ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [eval $cachevar=yes], [eval $cachevar=no]) CXXFLAGS="$ac_save_CXXFLAGS"]) if eval test x\$$cachevar = xyes; then CXXFLAGS="$CXXFLAGS $switch" ac_success=yes break fi done fi]) m4_if([$1], [ext], [], [dnl if test x$ac_success = xno; then for switch in -std=c++11 -std=c++0x; do cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, $cachevar, [ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [eval $cachevar=yes], [eval $cachevar=no]) CXXFLAGS="$ac_save_CXXFLAGS"]) if eval test x\$$cachevar = xyes; then CXXFLAGS="$CXXFLAGS $switch" ac_success=yes break fi done fi]) AC_LANG_POP([C++]) if test x$ax_cxx_compile_cxx11_required = xtrue; then if test x$ac_success = xno; then AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.]) fi else if test x$ac_success = xno; then HAVE_CXX11=0 AC_MSG_NOTICE([No compiler with C++11 support was found]) else HAVE_CXX11=1 AC_DEFINE(HAVE_CXX11,1, [define if the compiler supports basic C++11 syntax]) fi AC_SUBST(HAVE_CXX11) fi ]) tntnet-3.0/misc/template/default/main.cpp000066400000000000000000000012351365471676700205410ustar00rootroot00000000000000#include #include #include #include int main(int argc, char* argv[]) { try { std::ifstream in("@PROJECT@.xml"); tnt::TntConfig config; in >> cxxtools::xml::Xml(config); tnt::Tntnet app(config); // map static resources app.mapUrl("^/(.*)", "resources") .setPathInfo("resources/$1"); // map / to @PROJECT@ app.mapUrl("^/$", "@PROJECT@"); // map /comp to comp app.mapUrl("^/(.*)", "$1"); app.run(); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } tntnet-3.0/misc/template/default/resources/000077500000000000000000000000001365471676700211225ustar00rootroot00000000000000tntnet-3.0/misc/template/default/resources/@PROJECT@.css000066400000000000000000000000301365471676700231330ustar00rootroot00000000000000/* put your css here */ tntnet-3.0/misc/template/module/000077500000000000000000000000001365471676700167515ustar00rootroot00000000000000tntnet-3.0/misc/template/module/@PROJECT@.ecpp000066400000000000000000000011051365471676700211250ustar00rootroot00000000000000<%pre> // put your includes here // #include "@PROJECT@.h" <%args> // define the query parameters // bar; <%session> // define your session scope variables here // std::string mySessionState; <%cpp> // put your C++ code here tntnet application @PROJECT@

@PROJECT@

Hello world!

tntnet-3.0/misc/template/module/Makefile.am000066400000000000000000000016361365471676700210130ustar00rootroot00000000000000ACLOCAL_AMFLAGS = -I m4 AUTOMAKE_OPTIONS = subdir-objects pkglib_LTLIBRARIES = @PROJECT@.la ecppSources = \ @PROJECT@.ecpp staticSources = \ resources/@PROJECT@.css @CPROJECT@_la_SOURCES = \ $(ecppSources) nodist_@CPROJECT@_la_SOURCES = \ resources.cpp @CPROJECT@_la_LDFLAGS = -module -shared @CPROJECT@_la_LIBADD = -lcxxtools -ltntnet nobase_dist_noinst_DATA = $(staticSources) CLEANFILES = $(ecppSources:.ecpp=.cpp) $(ecppSources:.ecpp=.deps) resources.cpp # # Rules for tntnet applications # ECPPFLAGS=-I$(srcdir) resources.cpp: $(staticSources) Makefile.am $(AM_V_GEN)$(ECPPC) -bb -z -n resources -p -o resources.cpp $(ECPPFLAGS) $(staticSources) SUFFIXES=.ecpp .cpp .ecpp.cpp: $(AM_V_GEN)$(ECPPC) -n `echo $<|$(SED) 's|^$(srcdir)/||; s|\.ecpp$$||'` $(ECPPFLAGS) -o $@ $< .ecpp.deps: $(AM_V_GEN)$(ECPPC) -M $(ECPPFLAGS) $< | $(SED) '1s|\(.*\).cpp:|\1.cpp $@:|' > $@ -include $(ecppSources:.ecpp=.deps) tntnet-3.0/misc/template/module/configure.ac000066400000000000000000000012441365471676700212400ustar00rootroot00000000000000AC_INIT([@PROJECT@], [0.1], [your-email@somewhere]) AM_INIT_AUTOMAKE([foreign]) LT_INIT([disable-static]) AC_CONFIG_MACRO_DIR([m4]) AC_PROG_CXX AC_LANG(C++) AX_CXX_COMPILE_STDCXX_11(noext, optional) AC_CONFIG_HEADERS([config.h]) AC_CHECK_HEADER([cxxtools/mutex.h], , AC_MSG_ERROR([cxxtools headers not found])) AC_CHECK_HEADER([tnt/httpreply.h], , AC_MSG_ERROR([tntnet headers not found])) #AC_CHECK_HEADER([tntdb/connection.h], , AC_MSG_ERROR([tntdb headers not found])) AC_CHECK_PROGS(ECPPC, [ecppc]) AC_PROG_SED AX_CHECK_COMPILE_FLAG([-Wall], [CPPFLAGS="$CPPFLAGS -Wall"]) AX_CHECK_COMPILE_FLAG([-pedantic], [CPPFLAGS="$CPPFLAGS -pedantic"]) AC_OUTPUT([ Makefile ]) tntnet-3.0/misc/template/module/log.properties000066400000000000000000000007621365471676700216550ustar00rootroot00000000000000rootlogger INFO logger.@PROJECT@ INFO # this enables logging to a file #file = @PROJECT@.log # setting maxfilesize and maxbackupindex enables rolling of file # when file reaches maxfilesize, it is renamed to file.0 and a new file is created # file.0 gets file.1 and so on up to maxbackupindex #maxfilesize = 1M #maxbackupindex = 2 # log to stdout instead of stderr if set #stdout = 1 # send loging via udp to host #loghost = hostname # set when loghost is a network address #broadcast = 1 tntnet-3.0/misc/template/module/m4/000077500000000000000000000000001365471676700172715ustar00rootroot00000000000000tntnet-3.0/misc/template/module/m4/ax_check_compile_flag.m4000066400000000000000000000064111365471676700240030ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # # Check whether the given FLAG works with the current language's compiler # or gives an error. (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # INPUT gives an alternative input source to AC_COMPILE_IFELSE. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 3 AC_DEFUN([AX_CHECK_COMPILE_FLAG], [AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_COMPILE_FLAGS tntnet-3.0/misc/template/module/m4/ax_cxx_compile_stdcxx_11.m4000066400000000000000000000112751365471676700244410ustar00rootroot00000000000000# ============================================================================ # http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html # ============================================================================ # # SYNOPSIS # # AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional]) # # DESCRIPTION # # Check for baseline language coverage in the compiler for the C++11 # standard; if necessary, add switches to CXXFLAGS to enable support. # # The first argument, if specified, indicates whether you insist on an # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. # -std=c++11). If neither is specified, you get whatever works, with # preference for an extended mode. # # The second argument, if specified 'mandatory' or if left unspecified, # indicates that baseline C++11 support is required and that the macro # should error out if no mode with that support is found. If specified # 'optional', then configuration proceeds regardless, after defining # HAVE_CXX11 if and only if a supporting mode is found. # # LICENSE # # Copyright (c) 2008 Benjamin Kosnik # Copyright (c) 2012 Zack Weinberg # Copyright (c) 2013 Roy Stogner # Copyright (c) 2014 Alexey Sokolov # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 4 m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[ template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; struct Base { virtual void f() {} }; struct Child : public Base { virtual void f() override {} }; typedef check> right_angle_brackets; int a; decltype(a) b; typedef check check_type; check_type c; check_type&& cr = static_cast(c); auto d = a; auto l = [](){}; ]]) AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl m4_if([$1], [], [], [$1], [ext], [], [$1], [noext], [], [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl m4_if([$2], [], [ax_cxx_compile_cxx11_required=true], [$2], [mandatory], [ax_cxx_compile_cxx11_required=true], [$2], [optional], [ax_cxx_compile_cxx11_required=false], [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])]) AC_LANG_PUSH([C++])dnl ac_success=no AC_CACHE_CHECK(whether $CXX supports C++11 features by default, ax_cv_cxx_compile_cxx11, [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [ax_cv_cxx_compile_cxx11=yes], [ax_cv_cxx_compile_cxx11=no])]) if test x$ax_cv_cxx_compile_cxx11 = xyes; then ac_success=yes fi m4_if([$1], [noext], [], [dnl if test x$ac_success = xno; then for switch in -std=gnu++11 -std=gnu++0x; do cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, $cachevar, [ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [eval $cachevar=yes], [eval $cachevar=no]) CXXFLAGS="$ac_save_CXXFLAGS"]) if eval test x\$$cachevar = xyes; then CXXFLAGS="$CXXFLAGS $switch" ac_success=yes break fi done fi]) m4_if([$1], [ext], [], [dnl if test x$ac_success = xno; then for switch in -std=c++11 -std=c++0x; do cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, $cachevar, [ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [eval $cachevar=yes], [eval $cachevar=no]) CXXFLAGS="$ac_save_CXXFLAGS"]) if eval test x\$$cachevar = xyes; then CXXFLAGS="$CXXFLAGS $switch" ac_success=yes break fi done fi]) AC_LANG_POP([C++]) if test x$ax_cxx_compile_cxx11_required = xtrue; then if test x$ac_success = xno; then AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.]) fi else if test x$ac_success = xno; then HAVE_CXX11=0 AC_MSG_NOTICE([No compiler with C++11 support was found]) else HAVE_CXX11=1 AC_DEFINE(HAVE_CXX11,1, [define if the compiler supports basic C++11 syntax]) fi AC_SUBST(HAVE_CXX11) fi ]) tntnet-3.0/misc/template/module/resources/000077500000000000000000000000001365471676700207635ustar00rootroot00000000000000tntnet-3.0/misc/template/module/resources/@PROJECT@.css000066400000000000000000000000301365471676700227740ustar00rootroot00000000000000/* put your css here */ tntnet-3.0/misc/template/module/tntnet.xml000066400000000000000000000031261365471676700210110ustar00rootroot00000000000000 resources@@PROJECT@ ^/(.*) resources/$1 @PROJECT@@@PROJECT@ ^/$ $1@@PROJECT@ ^/(.*) 8000 INFO tntnet INFO component.@PROJECT@ INFO .libs @PROJECT@ tntnet-3.0/misc/template/mvc/000077500000000000000000000000001365471676700162515ustar00rootroot00000000000000tntnet-3.0/misc/template/mvc/@PROJECT@.xml000066400000000000000000000022601365471676700203010ustar00rootroot00000000000000 8000 INFO tntnet INFO component.foo INFO @PROJECT@ server tntnet-3.0/misc/template/mvc/Makefile.am000066400000000000000000000042231365471676700203060ustar00rootroot00000000000000ACLOCAL_AMFLAGS = -I m4 AUTOMAKE_OPTIONS = subdir-objects models = \ model/index.ecpp views = \ view/index.ecpp \ view/mypage.ecpp controllers = \ controller/index.ecpp actions = \ action/myaction.ecpp bin_PROGRAMS = @PROJECT@ noinst_HEADERS = \ actionreply.h \ action.ecpp \ configuration.h \ noty.h \ session.ecpp \ $(models) ecppSources = \ actionmain.ecpp \ json/example.ecpp \ webmain.ecpp \ $(views) \ $(controllers) \ $(actions) notySources = \ resources/js/noty/packaged/jquery.noty.packaged.min.js \ resources/js/noty/packaged/jquery.noty.packaged.js \ resources/js/noty/promise.js \ resources/js/noty/jquery.noty.js \ resources/js/noty/themes/default.js \ resources/js/noty/themes/relax.js \ resources/js/noty/themes/bootstrap.js \ resources/js/noty/layouts/topRight.js \ resources/js/noty/layouts/topLeft.js \ resources/js/noty/layouts/bottomCenter.js \ resources/js/noty/layouts/top.js \ resources/js/noty/layouts/bottomRight.js \ resources/js/noty/layouts/bottomLeft.js \ resources/js/noty/layouts/center.js \ resources/js/noty/layouts/inline.js \ resources/js/noty/layouts/bottom.js \ resources/js/noty/layouts/topCenter.js \ resources/js/noty/layouts/centerRight.js \ resources/js/noty/layouts/centerLeft.js staticSources = \ $(notySources) \ resources/js/jquery-3.3.1.min.js \ resources/js/tntnet.js \ resources/mypage.js \ resources/@PROJECT@.css @PROJECT@_SOURCES = \ main.cpp \ configuration.cpp \ $(ecppSources) nodist_@PROJECT@_SOURCES = \ resources.cpp @PROJECT@_LDADD = -lcxxtools -ltntnet nobase_dist_noinst_DATA = $(staticSources) CLEANFILES = $(ecppSources:.ecpp=.cpp) $(ecppSources:.ecpp=.deps) resources.cpp EXTRA_DIST = $(staticSources) # # Rules for tntnet applications # ECPPFLAGS=-I$(srcdir) # resources resources.cpp: $(staticSources) Makefile.am $(AM_V_GEN)$(ECPPC) -bb -z -n resources -p -o resources.cpp $(ECPPFLAGS) $(staticSources) SUFFIXES=.ecpp .cpp .ecpp.cpp: $(AM_V_GEN)$(ECPPC) -n `echo $<|$(SED) 's|^$(srcdir)/||; s|\.ecpp$$||'` $(ECPPFLAGS) -o $@ $< .ecpp.deps: $(AM_V_GEN)$(ECPPC) -M $(ECPPFLAGS) $< | $(SED) '1s|\(.*\).cpp:|\1.cpp $@:|' > $@ -include $(ecppSources:.ecpp=.deps) tntnet-3.0/misc/template/mvc/README.md000066400000000000000000000052621365471676700175350ustar00rootroot00000000000000Tntnet project @PROJECT@ =========================== This is a tntnet web project, which follows the mvc pattern and runs as a standalone application. Autoconf, automake and libtool, commonly known as the autotools, is used for building the application. Building -------- The `autotools` are set up and `autoreconf -i` is run already. To build run `./configure && make`. To rebuild after changing code run just `make`. To add new source files to the project add them to `Makefile.am`. Adding files ------------ Static files are put into the `resources` directory and added to the `staticSources` variable in `Makefile.am`. New pages are added to the `view` directory. Those components are embedded into the html page found in `webmain.ecpp`. Html fragments, which are loaded with ajax are created in the `html` directory. They get the ecpp extension but are requested with the filename and the extension .html appended. e.g. the url `/foo.html` calls the component `html/foo.ecpp`. Json requests are created in the `json` directory. A example file can be found there. Those files are requested like html fragments but with the extension .json appended. Other directories may be created and added to the mapping found in `main.cpp`. Deployment ---------- To deploy a application add your e-mail address into configure.ac and possibly change the version number. Calling `make dist` creates a tar.gz archive with source of the application. Building that application autotools are not needed any more. Configuration ------------- The application has a xml configuration file, which is a extended tntnet.xml. See the man page tntnet.xml(7) for the content. You can extend the configuration by extending the class `Configuration` in `configuration.h` and `configuration.cpp`. Two additional configuration parameters are there as examples but also for use. The variable _htdocs_ specifies the source for static files for runtime. If set, the application looks for static files in that directory before looking into compiled resources. Static resources should be compiled into the binary using the _staticSources_ entry in _Makefile.am_. For development time it is frequently convenient to load the static resources from the file system, so that changing the resources do not need a compile cycle. The other variable _dburl_ can be used to configure a database connection. The configuration file already has some examples for database urls for _tntdb_. To actually use it, you need to uncomment the tntdb check in _configure.ac_ and add the link flag _-ltntdb_ into Makefile.am. Then you can get a database connection using this in your code: tntdb::Connection conn = tntdb::connectCached(Configuration::it().dburl()); tntnet-3.0/misc/template/mvc/action.ecpp000066400000000000000000000003051365471676700203750ustar00rootroot00000000000000<%request include="actionreply.h"> // Define object, which stores the reply of a action // This is serialized into json and sent to the browser. ActionReply actionReply; tntnet-3.0/misc/template/mvc/action/000077500000000000000000000000001365471676700175265ustar00rootroot00000000000000tntnet-3.0/misc/template/mvc/action/README000066400000000000000000000016611365471676700204120ustar00rootroot00000000000000Put your actions here. Actions are json requests, which do not expect an reply other than success or error. They have the file extension `.ecpp`. Typically they start with a Tag `<%cpp>` and end with the closing tag ``. On error they throw an exception or return a proper http error code. From your java script code they are accessed using the js method `tntnet.action`. The url is the path to the action code without `action` and the extension. Example: tntnet.action( 'process/activate', // calls the action `action/process/activate.ecpp` { processId: 47 }, // a parameter function(data, textStatus, jqXHR) { // optionally a function, which is called on success information("Process activated"); }, function(data, textStatus, jqXHR) { // optionally a function, which is called on failure error("Failed to activate process: " + data); }); tntnet-3.0/misc/template/mvc/action/myaction.ecpp000066400000000000000000000002561365471676700222250ustar00rootroot00000000000000<%include>action.ecpp <%cpp> // This is a example action, which just opens a notification in the browser. actionReply.information("myaction activated"); tntnet-3.0/misc/template/mvc/actionmain.ecpp000066400000000000000000000013651365471676700212510ustar00rootroot00000000000000<%pre> #include "actionreply.h" #include #include <%include>action.ecpp <%cpp> // A action is a http request, which do not expect any output other than // success or failure or notifications. try { // call the actual action component unsigned ret = callComp("action/" + request.getArg("next"), request, reply, qparam); log_debug("action <" << request.getArg("next") << "> http return code " << ret); if (ret > HTTP_OK) return ret; } catch (const tnt::HttpError& e) { throw; } catch (const std::exception& e) { log_warn(e.what()); actionReply.setFailed(e.what()); } reply.setContentType("application/json"); reply.out() << cxxtools::Json(actionReply); tntnet-3.0/misc/template/mvc/actionreply.h000066400000000000000000000030551365471676700207560ustar00rootroot00000000000000#ifndef ACTIONREPLY_H #define ACTIONREPLY_H #include "noty.h" // Represents a reply for a action. // A action is a http request, which do not expect any output other than // success or failure or notifications. // The class is derived from Noty, which adds methods for noty.js notifications. // On the server side those notifications are displayed when the action request // is sent back. // class ActionReply : public Noty { friend void operator <<= (cxxtools::SerializationInfo& si, const ActionReply& reply); public: ActionReply() : _success(true), _notLoggedIn(false) { } void setSuccess(const cxxtools::String& m = cxxtools::String()) { _success = true; if (!m.empty()) success(m); } void setSuccess(const std::string& m) { _success = true; success(m); } void setFailed(const cxxtools::String& m) { _success = false; error(m); } void setFailed(const std::string& m) { _success = false; error(m); } void setNotLoggedIn() { _success = false; _notLoggedIn = true; } private: bool _success; bool _notLoggedIn; }; inline void operator <<= (cxxtools::SerializationInfo& si, const ActionReply& reply) { if (reply._notLoggedIn) { si.addMember("notLoggedIn") <<= reply._notLoggedIn; } else { si.addMember("success") <<= reply._success; si.addMember("notifications") <<= static_cast(reply); } } #endif // ACTIONREPLY_H tntnet-3.0/misc/template/mvc/configuration.cpp000066400000000000000000000006511365471676700216260ustar00rootroot00000000000000#include #include void operator>>= (const cxxtools::SerializationInfo& si, Configuration& config) { si >>= static_cast(config); si.getMember("htdocs", config._htdocs); si.getMember("dburl", config._dburl); } Configuration::Configuration() { } Configuration& Configuration::it() { static Configuration theConfiguration; return theConfiguration; } tntnet-3.0/misc/template/mvc/configuration.h000066400000000000000000000012701365471676700212710ustar00rootroot00000000000000#ifndef CONFIGURATION_H #define CONFIGURATION_H #include #include class Configuration : public tnt::TntConfig { friend void operator>>= (const cxxtools::SerializationInfo& si, Configuration& config); public: // return the static instance static Configuration& it(); const std::string& htdocs() const { return _htdocs; } const std::string& dburl() const { return _dburl; } private: Configuration(); Configuration(const Configuration&); // no implementation const Configuration& operator=(const Configuration&); // no implementation std::string _htdocs; std::string _dburl; }; #endif // CONFIGURATION_H tntnet-3.0/misc/template/mvc/configure.ac000066400000000000000000000012221365471676700205340ustar00rootroot00000000000000AC_INIT([@PROJECT@], [0.1], [your-email@somewhere]) AM_INIT_AUTOMAKE([foreign]) LT_INIT AC_CONFIG_MACRO_DIR([m4]) AC_PROG_CXX AC_LANG(C++) AX_CXX_COMPILE_STDCXX_11(noext, optional) AC_CONFIG_HEADERS([config.h]) AC_CHECK_HEADER([cxxtools/mutex.h], , AC_MSG_ERROR([cxxtools headers not found])) AC_CHECK_HEADER([tnt/httpreply.h], , AC_MSG_ERROR([tntnet headers not found])) #AC_CHECK_HEADER([tntdb/connection.h], , AC_MSG_ERROR([tntdb headers not found])) AC_CHECK_PROGS(ECPPC, [ecppc]) AC_PROG_SED AX_CHECK_COMPILE_FLAG([-Wall], [CPPFLAGS="$CPPFLAGS -Wall"]) AX_CHECK_COMPILE_FLAG([-pedantic], [CPPFLAGS="$CPPFLAGS -pedantic"]) AC_OUTPUT([ Makefile ]) tntnet-3.0/misc/template/mvc/controller/000077500000000000000000000000001365471676700204345ustar00rootroot00000000000000tntnet-3.0/misc/template/mvc/controller/index.ecpp000066400000000000000000000001701365471676700224120ustar00rootroot00000000000000<%args> <%include>model/index.ecpp <%cpp> // put your controller code for index page here tntnet-3.0/misc/template/mvc/html/000077500000000000000000000000001365471676700172155ustar00rootroot00000000000000tntnet-3.0/misc/template/mvc/html/README000066400000000000000000000004251365471676700200760ustar00rootroot00000000000000Put your html fragments here. Html fragments are loaded via ajax to fill a dom container. Html fragments are called with a .html extension. The basename specifies the name of the component. e.g. the url `/foo.html` calls the component `html/foo.ecpp` in this directory. tntnet-3.0/misc/template/mvc/json/000077500000000000000000000000001365471676700172225ustar00rootroot00000000000000tntnet-3.0/misc/template/mvc/json/README000066400000000000000000000003261365471676700201030ustar00rootroot00000000000000Put your json requests here. Json requests are called with a .json extension. The basename specifies the name of the component. e.g. the url `/foo.json` calls the component `json/foo.ecpp` in this directory. tntnet-3.0/misc/template/mvc/json/example.ecpp000066400000000000000000000003201365471676700215210ustar00rootroot00000000000000<%pre> #include #include <%cpp> std::vector v; v.push_back(17); v.push_back(42); reply.setContentType("application/json"); reply.out() << cxxtools::Json(v); tntnet-3.0/misc/template/mvc/m4/000077500000000000000000000000001365471676700165715ustar00rootroot00000000000000tntnet-3.0/misc/template/mvc/m4/ax_check_compile_flag.m4000066400000000000000000000064111365471676700233030ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # # Check whether the given FLAG works with the current language's compiler # or gives an error. (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # INPUT gives an alternative input source to AC_COMPILE_IFELSE. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 3 AC_DEFUN([AX_CHECK_COMPILE_FLAG], [AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_COMPILE_FLAGS tntnet-3.0/misc/template/mvc/m4/ax_cxx_compile_stdcxx_11.m4000066400000000000000000000112751365471676700237410ustar00rootroot00000000000000# ============================================================================ # http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html # ============================================================================ # # SYNOPSIS # # AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional]) # # DESCRIPTION # # Check for baseline language coverage in the compiler for the C++11 # standard; if necessary, add switches to CXXFLAGS to enable support. # # The first argument, if specified, indicates whether you insist on an # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. # -std=c++11). If neither is specified, you get whatever works, with # preference for an extended mode. # # The second argument, if specified 'mandatory' or if left unspecified, # indicates that baseline C++11 support is required and that the macro # should error out if no mode with that support is found. If specified # 'optional', then configuration proceeds regardless, after defining # HAVE_CXX11 if and only if a supporting mode is found. # # LICENSE # # Copyright (c) 2008 Benjamin Kosnik # Copyright (c) 2012 Zack Weinberg # Copyright (c) 2013 Roy Stogner # Copyright (c) 2014 Alexey Sokolov # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 4 m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[ template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; struct Base { virtual void f() {} }; struct Child : public Base { virtual void f() override {} }; typedef check> right_angle_brackets; int a; decltype(a) b; typedef check check_type; check_type c; check_type&& cr = static_cast(c); auto d = a; auto l = [](){}; ]]) AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl m4_if([$1], [], [], [$1], [ext], [], [$1], [noext], [], [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl m4_if([$2], [], [ax_cxx_compile_cxx11_required=true], [$2], [mandatory], [ax_cxx_compile_cxx11_required=true], [$2], [optional], [ax_cxx_compile_cxx11_required=false], [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])]) AC_LANG_PUSH([C++])dnl ac_success=no AC_CACHE_CHECK(whether $CXX supports C++11 features by default, ax_cv_cxx_compile_cxx11, [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [ax_cv_cxx_compile_cxx11=yes], [ax_cv_cxx_compile_cxx11=no])]) if test x$ax_cv_cxx_compile_cxx11 = xyes; then ac_success=yes fi m4_if([$1], [noext], [], [dnl if test x$ac_success = xno; then for switch in -std=gnu++11 -std=gnu++0x; do cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, $cachevar, [ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [eval $cachevar=yes], [eval $cachevar=no]) CXXFLAGS="$ac_save_CXXFLAGS"]) if eval test x\$$cachevar = xyes; then CXXFLAGS="$CXXFLAGS $switch" ac_success=yes break fi done fi]) m4_if([$1], [ext], [], [dnl if test x$ac_success = xno; then for switch in -std=c++11 -std=c++0x; do cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, $cachevar, [ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [eval $cachevar=yes], [eval $cachevar=no]) CXXFLAGS="$ac_save_CXXFLAGS"]) if eval test x\$$cachevar = xyes; then CXXFLAGS="$CXXFLAGS $switch" ac_success=yes break fi done fi]) AC_LANG_POP([C++]) if test x$ax_cxx_compile_cxx11_required = xtrue; then if test x$ac_success = xno; then AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.]) fi else if test x$ac_success = xno; then HAVE_CXX11=0 AC_MSG_NOTICE([No compiler with C++11 support was found]) else HAVE_CXX11=1 AC_DEFINE(HAVE_CXX11,1, [define if the compiler supports basic C++11 syntax]) fi AC_SUBST(HAVE_CXX11) fi ]) tntnet-3.0/misc/template/mvc/main.cpp000066400000000000000000000052641365471676700177100ustar00rootroot00000000000000#include #include #include #include #include #include #include "configuration.h" log_define("@PROJECT@") int main(int argc, char* argv[]) { try { Configuration& configuration = Configuration::it(); // read option "-c " with default value "@PROJECT@.xml": cxxtools::Arg configfilename(argc, argv, 'c', "@PROJECT@.xml"); std::ifstream configfile(configfilename); if (!configfile) throw std::runtime_error(std::string("could not open configuration file ") + configfilename.getValue()); configfile >> cxxtools::xml::Xml(configuration); tnt::Tntnet app(configuration); // Map static resources // Read static resources from file system when configured // This is useful for development, so that the application do not // need to be compiled and restarted on every change. if (!configuration.htdocs().empty()) { app.mapUrl("^/(.*)", "static@tntnet") .setPathInfo(configuration.htdocs() + "/$1"); } // Read static resources compiled into the binary app.mapUrl("^/(.*)", "resources") .setPathInfo("resources/$1"); // Actions // app.mapUrl("^/(.*)\\.action$", "actionmain") .setArg("next", "$1"); // Controller // // we set the default http return code to DECLINED, so that tntnet continues // with the view component after the controller app.mapUrl("^/$", "controller/index") // controller for index page .setHttpReturn(DECLINED); app.mapUrl("^/(.*)$", "controller/$1") // controller for pages routed through webmain .setHttpReturn(DECLINED); // ajax - map /something.ext to component ext/something // e.g. /request.json to json/request.ecpp // e.g. /foo.html to html/foo.ecpp // // These are requests, which are not routed through webmain and hence // do not have the html frame. app.mapUrl("^/(.*)\\.(.*)$", "$2/$1"); // Return empty file when requesting a js or css file so we can just add a // tag to the page and the script is loaded when found. // The above mapping will load the page when found. Otherwise this will // return a empty js or css. app.mapUrl("\\.js$", "empty@tntnet") .setArg("Content-Type", "application/javascript"); app.mapUrl("\\.css$", "empty@tntnet") .setArg("Content-Type", "text/css"); // View app.mapUrl("^/$", "webmain") // index page .setArg("next", "index"); app.mapUrl("^/(.*)$", "webmain") .setArg("next", "$1"); app.run(); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } tntnet-3.0/misc/template/mvc/model/000077500000000000000000000000001365471676700173515ustar00rootroot00000000000000tntnet-3.0/misc/template/mvc/model/index.ecpp000066400000000000000000000002061365471676700213270ustar00rootroot00000000000000<%request> // define the request scope variables here <%session> // define the session scope variables here tntnet-3.0/misc/template/mvc/noty.h000066400000000000000000000063741365471676700174250ustar00rootroot00000000000000// interface class for JavaScript noty #ifndef NOTY_H #define NOTY_H #include #include #include #include // Represents a single notification, which can be displayed using noty.js struct Notification { enum Severity { ERROR = 4, WARNING = 3, INFORMATION = 2, NOTIFICATION = 1, SUCCESS = 0 }; Notification() { } Notification(Severity s, const cxxtools::String& m, cxxtools::Timespan t) : severity(s), message(m), timeout(t) { } Notification(Severity s, const std::string& m, cxxtools::Timespan t) : severity(s), message(cxxtools::Utf8Codec::decode(m)), timeout(t) { } Severity severity; cxxtools::String message; cxxtools::Timespan timeout; }; // Represents notifications, which can be displayed using noty.js class Noty { friend void operator <<= (cxxtools::SerializationInfo& si, const Noty& reply); public: Noty() { } void error(const cxxtools::String& msg, cxxtools::Milliseconds timeout = -1) { _notifications.push_back(Notification(Notification::ERROR, msg, timeout)); } void error(const std::string& msg, cxxtools::Milliseconds timeout = -1) { _notifications.push_back(Notification(Notification::ERROR, msg, timeout)); } void warning(const cxxtools::String& msg, cxxtools::Milliseconds timeout = -1) { _notifications.push_back(Notification(Notification::WARNING, msg, timeout)); } void warning(const std::string& msg, cxxtools::Milliseconds timeout = -1) { _notifications.push_back(Notification(Notification::WARNING, msg, timeout)); } void information(const cxxtools::String& msg, cxxtools::Milliseconds timeout = 5000) { _notifications.push_back(Notification(Notification::INFORMATION, msg, timeout)); } void information(const std::string& msg, cxxtools::Milliseconds timeout = 5000) { _notifications.push_back(Notification(Notification::INFORMATION, msg, timeout)); } void notification(const cxxtools::String& msg, cxxtools::Milliseconds timeout = 5000) { _notifications.push_back(Notification(Notification::NOTIFICATION, msg, timeout)); } void notification(const std::string& msg, cxxtools::Milliseconds timeout = 5000) { _notifications.push_back(Notification(Notification::NOTIFICATION, msg, timeout)); } void success(const cxxtools::String& msg, cxxtools::Milliseconds timeout = 5000) { _notifications.push_back(Notification(Notification::SUCCESS, msg, timeout)); } void success(const std::string& msg, cxxtools::Milliseconds timeout = 5000) { _notifications.push_back(Notification(Notification::SUCCESS, msg, timeout)); } private: std::vector _notifications; }; inline void operator <<= (cxxtools::SerializationInfo& si, const Notification& notification) { si.addMember("severity") <<= notification.severity; si.addMember("message") <<= notification.message; si.addMember("timeout") <<= static_cast(cxxtools::Milliseconds(notification.timeout)); } inline void operator <<= (cxxtools::SerializationInfo& si, const Noty& noty) { si <<= noty._notifications; } #endif // NOTY_H tntnet-3.0/misc/template/mvc/resources/000077500000000000000000000000001365471676700202635ustar00rootroot00000000000000tntnet-3.0/misc/template/mvc/resources/@PROJECT@.css000066400000000000000000000004751365471676700223110ustar00rootroot00000000000000/* put your css here */ #header { font-size: 18pt; font-family: sans-serif; } #menu { float: left; border: 1px solid black; width: 140px; min-height: 200px; background-color: #eee; } #menu ul { list-style-type: none; padding-right: 5px; padding-left: 5px; } #content { margin-left: 150px; } tntnet-3.0/misc/template/mvc/resources/js/000077500000000000000000000000001365471676700206775ustar00rootroot00000000000000tntnet-3.0/misc/template/mvc/resources/js/jquery-3.3.1.min.js000066400000000000000000002516171365471676700240120ustar00rootroot00000000000000/*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */ !function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){"use strict";var n=[],r=e.document,i=Object.getPrototypeOf,o=n.slice,a=n.concat,s=n.push,u=n.indexOf,l={},c=l.toString,f=l.hasOwnProperty,p=f.toString,d=p.call(Object),h={},g=function e(t){return"function"==typeof t&&"number"!=typeof t.nodeType},y=function e(t){return null!=t&&t===t.window},v={type:!0,src:!0,noModule:!0};function m(e,t,n){var i,o=(t=t||r).createElement("script");if(o.text=e,n)for(i in v)n[i]&&(o[i]=n[i]);t.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[c.call(e)]||"object":typeof e}var b="3.3.1",w=function(e,t){return new w.fn.init(e,t)},T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;w.fn=w.prototype={jquery:"3.3.1",constructor:w,length:0,toArray:function(){return o.call(this)},get:function(e){return null==e?o.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(o.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b="sizzle"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n+~]|"+M+")"+M+"*"),z=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),X=new RegExp(W),U=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+P+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},G=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Q=/^[^{]+\{\s*\[native \w/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,K=/[+~]/,Z=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ee=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},te=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ne=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},re=function(){p()},ie=me(function(e){return!0===e.disabled&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{L.apply(A=H.call(w.childNodes),w.childNodes),A[w.childNodes.length].nodeType}catch(e){L={apply:A.length?function(e,t){q.apply(e,H.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function oe(e,t,r,i){var o,s,l,c,f,h,v,m=t&&t.ownerDocument,T=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==T&&9!==T&&11!==T)return r;if(!i&&((t?t.ownerDocument||t:w)!==d&&p(t),t=t||d,g)){if(11!==T&&(f=J.exec(e)))if(o=f[1]){if(9===T){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return L.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return L.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!S[e+" "]&&(!y||!y.test(e))){if(1!==T)m=t,v=e;else if("object"!==t.nodeName.toLowerCase()){(c=t.getAttribute("id"))?c=c.replace(te,ne):t.setAttribute("id",c=b),s=(h=a(e)).length;while(s--)h[s]="#"+c+" "+ve(h[s]);v=h.join(","),m=K.test(e)&&ge(t.parentNode)||t}if(v)try{return L.apply(r,m.querySelectorAll(v)),r}catch(e){}finally{c===b&&t.removeAttribute("id")}}}return u(e.replace(B,"$1"),t,r,i)}function ae(){var e=[];function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}return t}function se(e){return e[b]=!0,e}function ue(e){var t=d.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function le(e,t){var n=e.split("|"),i=n.length;while(i--)r.attrHandle[n[i]]=t}function ce(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function fe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function pe(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function de(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ie(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function he(e){return se(function(t){return t=+t,se(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}n=oe.support={},o=oe.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},p=oe.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==d&&9===a.nodeType&&a.documentElement?(d=a,h=d.documentElement,g=!o(d),w!==d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",re,!1):i.attachEvent&&i.attachEvent("onunload",re)),n.attributes=ue(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ue(function(e){return e.appendChild(d.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=Q.test(d.getElementsByClassName),n.getById=ue(function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&g)return t.getElementsByClassName(e)},v=[],y=[],(n.qsa=Q.test(d.querySelectorAll))&&(ue(function(e){h.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+P+")"),e.querySelectorAll("[id~="+b+"-]").length||y.push("~="),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+b+"+*").length||y.push(".#.+[+~]")}),ue(function(e){e.innerHTML="";var t=d.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(n.matchesSelector=Q.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ue(function(e){n.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),v.push("!=",W)}),y=y.length&&new RegExp(y.join("|")),v=v.length&&new RegExp(v.join("|")),t=Q.test(h.compareDocumentPosition),x=t||Q.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===d||e.ownerDocument===w&&x(w,e)?-1:t===d||t.ownerDocument===w&&x(w,t)?1:c?O(c,e)-O(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===d?-1:t===d?1:i?-1:o?1:c?O(c,e)-O(c,t):0;if(i===o)return ce(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?ce(a[r],s[r]):a[r]===w?-1:s[r]===w?1:0},d):d},oe.matches=function(e,t){return oe(e,null,null,t)},oe.matchesSelector=function(e,t){if((e.ownerDocument||e)!==d&&p(e),t=t.replace(z,"='$1']"),n.matchesSelector&&g&&!S[t+" "]&&(!v||!v.test(t))&&(!y||!y.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return oe(t,d,null,[e]).length>0},oe.contains=function(e,t){return(e.ownerDocument||e)!==d&&p(e),x(e,t)},oe.attr=function(e,t){(e.ownerDocument||e)!==d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&N.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},oe.escape=function(e){return(e+"").replace(te,ne)},oe.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},oe.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(D),f){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return c=null,e},i=oe.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else while(t=e[r++])n+=i(t);return n},(r=oe.selectors={cacheLength:50,createPseudo:se,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(Z,ee),e[3]=(e[3]||e[4]||e[5]||"").replace(Z,ee),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||oe.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&oe.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=a(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(Z,ee).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=E[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&E(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=oe.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace($," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",y=t.parentNode,v=s&&t.nodeName.toLowerCase(),m=!u&&!s,x=!1;if(y){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===v:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?y.firstChild:y.lastChild],a&&m){x=(d=(l=(c=(f=(p=y)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&y.childNodes[d];while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(m&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===v:1===p.nodeType)&&++x&&(m&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p===t))break;return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||oe.error("unsupported pseudo: "+e);return i[b]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?se(function(e,n){var r,o=i(e,t),a=o.length;while(a--)e[r=O(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:se(function(e){var t=[],n=[],r=s(e.replace(B,"$1"));return r[b]?se(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:se(function(e){return function(t){return oe(e,t).length>0}}),contains:se(function(e){return e=e.replace(Z,ee),function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:se(function(e){return U.test(e||"")||oe.error("unsupported lang: "+e),e=e.replace(Z,ee).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:de(!1),disabled:de(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:he(function(){return[0]}),last:he(function(e,t){return[t-1]}),eq:he(function(e,t,n){return[n<0?n+t:n]}),even:he(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:he(function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function be(e,t,n){for(var r=0,i=t.length;r-1&&(o[l]=!(a[l]=f))}}else v=we(v===a?v.splice(h,v.length):v),i?i(null,a,v,u):L.apply(a,v)})}function Ce(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[" "],u=a?1:0,c=me(function(e){return e===t},s,!0),f=me(function(e){return O(t,e)>-1},s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u1&&xe(p),u>1&&ve(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace(B,"$1"),n,u0,i=e.length>0,o=function(o,a,s,u,c){var f,h,y,v=0,m="0",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG("*",c),E=T+=null==w?1:Math.random()||.1,k=C.length;for(c&&(l=a===d||a||c);m!==k&&null!=(f=C[m]);m++){if(i&&f){h=0,a||f.ownerDocument===d||(p(f),s=!g);while(y=e[h++])if(y(f,a||d,s)){u.push(f);break}c&&(T=E)}n&&((f=!y&&f)&&v--,o&&x.push(f))}if(v+=m,n&&m!==v){h=0;while(y=t[h++])y(x,b,a,s);if(o){if(v>0)while(m--)x[m]||b[m]||(b[m]=j.call(u));b=we(b)}L.apply(u,b),c&&!o&&b.length>0&&v+t.length>1&&oe.uniqueSort(u)}return c&&(T=E,l=w),x};return n?se(o):o}return s=oe.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=a(e)),n=t.length;while(n--)(o=Ce(t[n]))[b]?r.push(o):i.push(o);(o=S(e,Ee(i,r))).selector=e}return o},u=oe.select=function(e,t,n,i){var o,u,l,c,f,p="function"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&"ID"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(Z,ee),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}o=V.needsContext.test(e)?0:u.length;while(o--){if(l=u[o],r.relative[c=l.type])break;if((f=r.find[c])&&(i=f(l.matches[0].replace(Z,ee),K.test(u[0].type)&&ge(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&ve(u)))return L.apply(n,i),n;break}}}return(p||s(e,d))(i,t,!g,n,!t||K.test(e)&&ge(t.parentNode)||t),n},n.sortStable=b.split("").sort(D).join("")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ue(function(e){return 1&e.compareDocumentPosition(d.createElement("fieldset"))}),ue(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||le("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ue(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||le("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ue(function(e){return null==e.getAttribute("disabled")})||le(P,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),oe}(e);w.find=E,w.expr=E.selectors,w.expr[":"]=w.expr.pseudos,w.uniqueSort=w.unique=E.uniqueSort,w.text=E.getText,w.isXMLDoc=E.isXML,w.contains=E.contains,w.escapeSelector=E.escape;var k=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&w(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=w.expr.match.needsContext;function N(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var A=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,t,n){return g(t)?w.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?w.grep(e,function(e){return e===t!==n}):"string"!=typeof t?w.grep(e,function(e){return u.call(t,e)>-1!==n}):w.filter(t,e,n)}w.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,function(e){return 1===e.nodeType}))},w.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(w(e).filter(function(){for(t=0;t1?w.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&D.test(e)?w(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(w.fn.init=function(e,t,n){var i,o;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(i="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:L.exec(e))||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof w?t[0]:t,w.merge(this,w.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:r,!0)),A.test(i[1])&&w.isPlainObject(t))for(i in t)g(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return(o=r.getElementById(i[2]))&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):g(e)?void 0!==n.ready?n.ready(e):e(w):w.makeArray(e,this)}).prototype=w.fn,q=w(r);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};w.fn.extend({has:function(e){var t=w(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&w.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?w.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?u.call(w(e),this[0]):u.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(w.uniqueSort(w.merge(this.get(),w(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}w.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,"parentNode")},parentsUntil:function(e,t,n){return k(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return k(e,"nextSibling")},prevAll:function(e){return k(e,"previousSibling")},nextUntil:function(e,t,n){return k(e,"nextSibling",n)},prevUntil:function(e,t,n){return k(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return N(e,"iframe")?e.contentDocument:(N(e,"template")&&(e=e.content||e),w.merge([],e.childNodes))}},function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=w.filter(r,i)),this.length>1&&(O[e]||w.uniqueSort(i),H.test(e)&&i.reverse()),this.pushStack(i)}});var M=/[^\x20\t\r\n\f]+/g;function R(e){var t={};return w.each(e.match(M)||[],function(e,n){t[n]=!0}),t}w.Callbacks=function(e){e="string"==typeof e?R(e):w.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1){n=a.shift();while(++s-1)o.splice(n,1),n<=s&&s--}),this},has:function(e){return e?w.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l};function I(e){return e}function W(e){throw e}function $(e,t,n,r){var i;try{e&&g(i=e.promise)?i.call(e).done(t).fail(n):e&&g(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}w.extend({Deferred:function(t){var n=[["notify","progress",w.Callbacks("memory"),w.Callbacks("memory"),2],["resolve","done",w.Callbacks("once memory"),w.Callbacks("once memory"),0,"resolved"],["reject","fail",w.Callbacks("once memory"),w.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},"catch":function(e){return i.then(null,e)},pipe:function(){var e=arguments;return w.Deferred(function(t){w.each(n,function(n,r){var i=g(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&g(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var s=this,u=arguments,l=function(){var e,l;if(!(t=o&&(r!==W&&(s=void 0,u=[e]),n.rejectWith(s,u))}};t?c():(w.Deferred.getStackHook&&(c.stackTrace=w.Deferred.getStackHook()),e.setTimeout(c))}}return w.Deferred(function(e){n[0][3].add(a(0,e,g(i)?i:I,e.notifyWith)),n[1][3].add(a(0,e,g(t)?t:I)),n[2][3].add(a(0,e,g(r)?r:W))}).promise()},promise:function(e){return null!=e?w.extend(e,i):i}},o={};return w.each(n,function(e,t){var a=t[2],s=t[5];i[t[1]]=a.add,s&&a.add(function(){r=s},n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+"With"](this===o?void 0:this,arguments),this},o[t[0]+"With"]=a.fireWith}),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=o.call(arguments),a=w.Deferred(),s=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?o.call(arguments):n,--t||a.resolveWith(r,i)}};if(t<=1&&($(e,a.done(s(n)).resolve,a.reject,!t),"pending"===a.state()||g(i[n]&&i[n].then)))return a.then();while(n--)$(i[n],s(n),a.reject);return a.promise()}});var B=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;w.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&B.test(t.name)&&e.console.warn("jQuery.Deferred exception: "+t.message,t.stack,n)},w.readyException=function(t){e.setTimeout(function(){throw t})};var F=w.Deferred();w.fn.ready=function(e){return F.then(e)["catch"](function(e){w.readyException(e)}),this},w.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--w.readyWait:w.isReady)||(w.isReady=!0,!0!==e&&--w.readyWait>0||F.resolveWith(r,[w]))}}),w.ready.then=F.then;function _(){r.removeEventListener("DOMContentLoaded",_),e.removeEventListener("load",_),w.ready()}"complete"===r.readyState||"loading"!==r.readyState&&!r.documentElement.doScroll?e.setTimeout(w.ready):(r.addEventListener("DOMContentLoaded",_),e.addEventListener("load",_));var z=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n)){i=!0;for(s in n)z(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,g(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(w(e),n)})),t))for(;s1,null,!0)},removeData:function(e){return this.each(function(){K.remove(this,e)})}}),w.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=J.get(e,t),n&&(!r||Array.isArray(n)?r=J.access(e,t,w.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=w.queue(e,t),r=n.length,i=n.shift(),o=w._queueHooks(e,t),a=function(){w.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return J.get(e,n)||J.access(e,n,{empty:w.Callbacks("once memory").add(function(){J.remove(e,[t+"queue",n])})})}}),w.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]+)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"
","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&N(e,t)?w.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n-1)i&&i.push(o);else if(l=w.contains(o.ownerDocument,o),a=ye(f.appendChild(o),"script"),l&&ve(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}!function(){var e=r.createDocumentFragment().appendChild(r.createElement("div")),t=r.createElement("input");t.setAttribute("type","radio"),t.setAttribute("checked","checked"),t.setAttribute("name","t"),e.appendChild(t),h.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML="",h.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var be=r.documentElement,we=/^key/,Te=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ce=/^([^.]*)(?:\.(.+)|)/;function Ee(){return!0}function ke(){return!1}function Se(){try{return r.activeElement}catch(e){}}function De(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)De(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=ke;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return w().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=w.guid++)),e.each(function(){w.event.add(this,t,i,r,n)})}w.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.get(e);if(y){n.handler&&(n=(o=n).handler,i=o.selector),i&&w.find.matchesSelector(be,i),n.guid||(n.guid=w.guid++),(u=y.events)||(u=y.events={}),(a=y.handle)||(a=y.handle=function(t){return"undefined"!=typeof w&&w.event.triggered!==t.type?w.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(M)||[""]).length;while(l--)d=g=(s=Ce.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=w.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=w.event.special[d]||{},c=w.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&w.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),w.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.hasData(e)&&J.get(e);if(y&&(u=y.events)){l=(t=(t||"").match(M)||[""]).length;while(l--)if(s=Ce.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){f=w.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,y.handle)||w.removeEvent(e,d,y.handle),delete u[d])}else for(d in u)w.event.remove(e,d+t[l],n,r,!0);w.isEmptyObject(u)&&J.remove(e,"handle events")}},dispatch:function(e){var t=w.event.fix(e),n,r,i,o,a,s,u=new Array(arguments.length),l=(J.get(this,"events")||{})[t.type]||[],c=w.event.special[t.type]||{};for(u[0]=t,n=1;n=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n-1:w.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u\x20\t\r\n\f]*)[^>]*)\/>/gi,Ae=/\s*$/g;function Le(e,t){return N(e,"table")&&N(11!==t.nodeType?t:t.firstChild,"tr")?w(e).children("tbody")[0]||e:e}function He(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Oe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Pe(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(J.hasData(e)&&(o=J.access(e),a=J.set(t,o),l=o.events)){delete a.handle,a.events={};for(i in l)for(n=0,r=l[i].length;n1&&"string"==typeof y&&!h.checkClone&&je.test(y))return e.each(function(i){var o=e.eq(i);v&&(t[0]=y.call(this,i,o.html())),Re(o,t,n,r)});if(p&&(i=xe(t,e[0].ownerDocument,!1,e,r),o=i.firstChild,1===i.childNodes.length&&(i=o),o||r)){for(u=(s=w.map(ye(i,"script"),He)).length;f")},clone:function(e,t,n){var r,i,o,a,s=e.cloneNode(!0),u=w.contains(e.ownerDocument,e);if(!(h.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||w.isXMLDoc(e)))for(a=ye(s),r=0,i=(o=ye(e)).length;r0&&ve(a,!u&&ye(e,"script")),s},cleanData:function(e){for(var t,n,r,i=w.event.special,o=0;void 0!==(n=e[o]);o++)if(Y(n)){if(t=n[J.expando]){if(t.events)for(r in t.events)i[r]?w.event.remove(n,r):w.removeEvent(n,r,t.handle);n[J.expando]=void 0}n[K.expando]&&(n[K.expando]=void 0)}}}),w.fn.extend({detach:function(e){return Ie(this,e,!0)},remove:function(e){return Ie(this,e)},text:function(e){return z(this,function(e){return void 0===e?w.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Re(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Le(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Le(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(w.cleanData(ye(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return w.clone(this,e,t)})},html:function(e){return z(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ae.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=w.htmlPrefilter(e);try{for(;n=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))),u}function et(e,t,n){var r=$e(e),i=Fe(e,t,r),o="border-box"===w.css(e,"boxSizing",!1,r),a=o;if(We.test(i)){if(!n)return i;i="auto"}return a=a&&(h.boxSizingReliable()||i===e.style[t]),("auto"===i||!parseFloat(i)&&"inline"===w.css(e,"display",!1,r))&&(i=e["offset"+t[0].toUpperCase()+t.slice(1)],a=!0),(i=parseFloat(i)||0)+Ze(e,t,n||(o?"border":"content"),a,r,i)+"px"}w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=G(t),u=Xe.test(t),l=e.style;if(u||(t=Je(s)),a=w.cssHooks[t]||w.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ue(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(w.cssNumber[s]?"":"px")),h.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=G(t);return Xe.test(t)||(t=Je(s)),(a=w.cssHooks[t]||w.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),"normal"===i&&t in Ve&&(i=Ve[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),w.each(["height","width"],function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n)return!ze.test(w.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,t,r):se(e,Ue,function(){return et(e,t,r)})},set:function(e,n,r){var i,o=$e(e),a="border-box"===w.css(e,"boxSizing",!1,o),s=r&&Ze(e,t,r,a,o);return a&&h.scrollboxSize()===o.position&&(s-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ze(e,t,"border",!1,o)-.5)),s&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=w.css(e,t)),Ke(e,n,s)}}}),w.cssHooks.marginLeft=_e(h.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,"marginLeft"))||e.getBoundingClientRect().left-se(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),w.each({margin:"",padding:"",border:"Width"},function(e,t){w.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(w.cssHooks[e+t].set=Ke)}),w.fn.extend({css:function(e,t){return z(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=$e(e),i=t.length;a1)}});function tt(e,t,n,r,i){return new tt.prototype.init(e,t,n,r,i)}w.Tween=tt,tt.prototype={constructor:tt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||w.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(w.cssNumber[n]?"":"px")},cur:function(){var e=tt.propHooks[this.prop];return e&&e.get?e.get(this):tt.propHooks._default.get(this)},run:function(e){var t,n=tt.propHooks[this.prop];return this.options.duration?this.pos=t=w.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):tt.propHooks._default.set(this),this}},tt.prototype.init.prototype=tt.prototype,tt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=w.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){w.fx.step[e.prop]?w.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[w.cssProps[e.prop]]&&!w.cssHooks[e.prop]?e.elem[e.prop]=e.now:w.style(e.elem,e.prop,e.now+e.unit)}}},tt.propHooks.scrollTop=tt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},w.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},w.fx=tt.prototype.init,w.fx.step={};var nt,rt,it=/^(?:toggle|show|hide)$/,ot=/queueHooks$/;function at(){rt&&(!1===r.hidden&&e.requestAnimationFrame?e.requestAnimationFrame(at):e.setTimeout(at,w.fx.interval),w.fx.tick())}function st(){return e.setTimeout(function(){nt=void 0}),nt=Date.now()}function ut(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function lt(e,t,n){for(var r,i=(pt.tweeners[t]||[]).concat(pt.tweeners["*"]),o=0,a=i.length;o1)},removeAttr:function(e){return this.each(function(){w.removeAttr(this,e)})}}),w.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?w.prop(e,t,n):(1===o&&w.isXMLDoc(e)||(i=w.attrHooks[t.toLowerCase()]||(w.expr.match.bool.test(t)?dt:void 0)),void 0!==n?null===n?void w.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=w.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!h.radioValue&&"radio"===t&&N(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(M);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),dt={set:function(e,t,n){return!1===t?w.removeAttr(e,n):e.setAttribute(n,n),n}},w.each(w.expr.match.bool.source.match(/\w+/g),function(e,t){var n=ht[t]||w.find.attr;ht[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ht[a],ht[a]=i,i=null!=n(e,t,r)?a:null,ht[a]=o),i}});var gt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;w.fn.extend({prop:function(e,t){return z(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[w.propFix[e]||e]})}}),w.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&w.isXMLDoc(e)||(t=w.propFix[t]||t,i=w.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,"tabindex");return t?parseInt(t,10):gt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),h.optSelected||(w.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),w.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){w.propFix[this.toLowerCase()]=this});function vt(e){return(e.match(M)||[]).join(" ")}function mt(e){return e.getAttribute&&e.getAttribute("class")||""}function xt(e){return Array.isArray(e)?e:"string"==typeof e?e.match(M)||[]:[]}w.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).addClass(e.call(this,t,mt(this)))});if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).removeClass(e.call(this,t,mt(this)))});if(!arguments.length)return this.attr("class","");if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])while(r.indexOf(" "+o+" ")>-1)r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):g(e)?this.each(function(n){w(this).toggleClass(e.call(this,n,mt(this),t),t)}):this.each(function(){var t,i,o,a;if(r){i=0,o=w(this),a=xt(e);while(t=a[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else void 0!==e&&"boolean"!==n||((t=mt(this))&&J.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":J.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&(" "+vt(mt(n))+" ").indexOf(t)>-1)return!0;return!1}});var bt=/\r/g;w.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=g(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,w(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=w.map(i,function(e){return null==e?"":e+""})),(t=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return(t=w.valHooks[i.type]||w.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(bt,""):null==n?"":n}}}),w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,"value");return null!=t?t:vt(w.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),w.each(["radio","checkbox"],function(){w.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=w.inArray(w(e).val(),t)>-1}},h.checkOn||(w.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),h.focusin="onfocusin"in e;var wt=/^(?:focusinfocus|focusoutblur)$/,Tt=function(e){e.stopPropagation()};w.extend(w.event,{trigger:function(t,n,i,o){var a,s,u,l,c,p,d,h,v=[i||r],m=f.call(t,"type")?t.type:t,x=f.call(t,"namespace")?t.namespace.split("."):[];if(s=h=u=i=i||r,3!==i.nodeType&&8!==i.nodeType&&!wt.test(m+w.event.triggered)&&(m.indexOf(".")>-1&&(m=(x=m.split(".")).shift(),x.sort()),c=m.indexOf(":")<0&&"on"+m,t=t[w.expando]?t:new w.Event(m,"object"==typeof t&&t),t.isTrigger=o?2:3,t.namespace=x.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+x.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:w.makeArray(n,[t]),d=w.event.special[m]||{},o||!d.trigger||!1!==d.trigger.apply(i,n))){if(!o&&!d.noBubble&&!y(i)){for(l=d.delegateType||m,wt.test(l+m)||(s=s.parentNode);s;s=s.parentNode)v.push(s),u=s;u===(i.ownerDocument||r)&&v.push(u.defaultView||u.parentWindow||e)}a=0;while((s=v[a++])&&!t.isPropagationStopped())h=s,t.type=a>1?l:d.bindType||m,(p=(J.get(s,"events")||{})[t.type]&&J.get(s,"handle"))&&p.apply(s,n),(p=c&&s[c])&&p.apply&&Y(s)&&(t.result=p.apply(s,n),!1===t.result&&t.preventDefault());return t.type=m,o||t.isDefaultPrevented()||d._default&&!1!==d._default.apply(v.pop(),n)||!Y(i)||c&&g(i[m])&&!y(i)&&((u=i[c])&&(i[c]=null),w.event.triggered=m,t.isPropagationStopped()&&h.addEventListener(m,Tt),i[m](),t.isPropagationStopped()&&h.removeEventListener(m,Tt),w.event.triggered=void 0,u&&(i[c]=u)),t.result}},simulate:function(e,t,n){var r=w.extend(new w.Event,n,{type:e,isSimulated:!0});w.event.trigger(r,null,t)}}),w.fn.extend({trigger:function(e,t){return this.each(function(){w.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return w.event.trigger(e,t,n,!0)}}),h.focusin||w.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){w.event.simulate(t,e.target,w.event.fix(e))};w.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=J.access(r,t);i||r.addEventListener(e,n,!0),J.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=J.access(r,t)-1;i?J.access(r,t,i):(r.removeEventListener(e,n,!0),J.remove(r,t))}}});var Ct=e.location,Et=Date.now(),kt=/\?/;w.parseXML=function(t){var n;if(!t||"string"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,"text/xml")}catch(e){n=void 0}return n&&!n.getElementsByTagName("parsererror").length||w.error("Invalid XML: "+t),n};var St=/\[\]$/,Dt=/\r?\n/g,Nt=/^(?:submit|button|image|reset|file)$/i,At=/^(?:input|select|textarea|keygen)/i;function jt(e,t,n,r){var i;if(Array.isArray(t))w.each(t,function(t,i){n||St.test(e)?r(e,i):jt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)});else if(n||"object"!==x(t))r(e,t);else for(i in t)jt(e+"["+i+"]",t[i],n,r)}w.param=function(e,t){var n,r=[],i=function(e,t){var n=g(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!w.isPlainObject(e))w.each(e,function(){i(this.name,this.value)});else for(n in e)jt(n,e[n],t,i);return r.join("&")},w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=w.prop(this,"elements");return e?w.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!w(this).is(":disabled")&&At.test(this.nodeName)&&!Nt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=w(this).val();return null==n?null:Array.isArray(n)?w.map(n,function(e){return{name:t.name,value:e.replace(Dt,"\r\n")}}):{name:t.name,value:n.replace(Dt,"\r\n")}}).get()}});var qt=/%20/g,Lt=/#.*$/,Ht=/([?&])_=[^&]*/,Ot=/^(.*?):[ \t]*([^\r\n]*)$/gm,Pt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Mt=/^(?:GET|HEAD)$/,Rt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Bt=r.createElement("a");Bt.href=Ct.href;function Ft(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(M)||[];if(g(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function _t(e,t,n,r){var i={},o=e===Wt;function a(s){var u;return i[s]=!0,w.each(e[s]||[],function(e,s){var l=s(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)}),u}return a(t.dataTypes[0])||!i["*"]&&a("*")}function zt(e,t){var n,r,i=w.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&w.extend(!0,e,r),e}function Xt(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}function Ut(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}w.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ct.href,type:"GET",isLocal:Pt.test(Ct.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":w.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,w.ajaxSettings),t):zt(w.ajaxSettings,e)},ajaxPrefilter:Ft(It),ajaxTransport:Ft(Wt),ajax:function(t,n){"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,p,d,h=w.ajaxSetup({},n),g=h.context||h,y=h.context&&(g.nodeType||g.jquery)?w(g):w.event,v=w.Deferred(),m=w.Callbacks("once memory"),x=h.statusCode||{},b={},T={},C="canceled",E={readyState:0,getResponseHeader:function(e){var t;if(c){if(!s){s={};while(t=Ot.exec(a))s[t[1].toLowerCase()]=t[2]}t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return c?a:null},setRequestHeader:function(e,t){return null==c&&(e=T[e.toLowerCase()]=T[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==c&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)E.always(e[E.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||C;return i&&i.abort(t),k(0,t),this}};if(v.promise(E),h.url=((t||h.url||Ct.href)+"").replace(Rt,Ct.protocol+"//"),h.type=n.method||n.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(M)||[""],null==h.crossDomain){l=r.createElement("a");try{l.href=h.url,l.href=l.href,h.crossDomain=Bt.protocol+"//"+Bt.host!=l.protocol+"//"+l.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=w.param(h.data,h.traditional)),_t(It,h,n,E),c)return E;(f=w.event&&h.global)&&0==w.active++&&w.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!Mt.test(h.type),o=h.url.replace(Lt,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(qt,"+")):(d=h.url.slice(o.length),h.data&&(h.processData||"string"==typeof h.data)&&(o+=(kt.test(o)?"&":"?")+h.data,delete h.data),!1===h.cache&&(o=o.replace(Ht,"$1"),d=(kt.test(o)?"&":"?")+"_="+Et+++d),h.url=o+d),h.ifModified&&(w.lastModified[o]&&E.setRequestHeader("If-Modified-Since",w.lastModified[o]),w.etag[o]&&E.setRequestHeader("If-None-Match",w.etag[o])),(h.data&&h.hasContent&&!1!==h.contentType||n.contentType)&&E.setRequestHeader("Content-Type",h.contentType),E.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+$t+"; q=0.01":""):h.accepts["*"]);for(p in h.headers)E.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(g,E,h)||c))return E.abort();if(C="abort",m.add(h.complete),E.done(h.success),E.fail(h.error),i=_t(Wt,h,n,E)){if(E.readyState=1,f&&y.trigger("ajaxSend",[E,h]),c)return E;h.async&&h.timeout>0&&(u=e.setTimeout(function(){E.abort("timeout")},h.timeout));try{c=!1,i.send(b,k)}catch(e){if(c)throw e;k(-1,e)}}else k(-1,"No Transport");function k(t,n,r,s){var l,p,d,b,T,C=n;c||(c=!0,u&&e.clearTimeout(u),i=void 0,a=s||"",E.readyState=t>0?4:0,l=t>=200&&t<300||304===t,r&&(b=Xt(h,E,r)),b=Ut(h,b,E,l),l?(h.ifModified&&((T=E.getResponseHeader("Last-Modified"))&&(w.lastModified[o]=T),(T=E.getResponseHeader("etag"))&&(w.etag[o]=T)),204===t||"HEAD"===h.type?C="nocontent":304===t?C="notmodified":(C=b.state,p=b.data,l=!(d=b.error))):(d=C,!t&&C||(C="error",t<0&&(t=0))),E.status=t,E.statusText=(n||C)+"",l?v.resolveWith(g,[p,C,E]):v.rejectWith(g,[E,C,d]),E.statusCode(x),x=void 0,f&&y.trigger(l?"ajaxSuccess":"ajaxError",[E,h,l?p:d]),m.fireWith(g,[E,C]),f&&(y.trigger("ajaxComplete",[E,h]),--w.active||w.event.trigger("ajaxStop")))}return E},getJSON:function(e,t,n){return w.get(e,t,n,"json")},getScript:function(e,t){return w.get(e,void 0,t,"script")}}),w.each(["get","post"],function(e,t){w[t]=function(e,n,r,i){return g(n)&&(i=i||r,r=n,n=void 0),w.ajax(w.extend({url:e,type:t,dataType:i,data:n,success:r},w.isPlainObject(e)&&e))}}),w._evalUrl=function(e){return w.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},w.fn.extend({wrapAll:function(e){var t;return this[0]&&(g(e)&&(e=e.call(this[0])),t=w(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return g(e)?this.each(function(t){w(this).wrapInner(e.call(this,t))}):this.each(function(){var t=w(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=g(e);return this.each(function(n){w(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){w(this).replaceWith(this.childNodes)}),this}}),w.expr.pseudos.hidden=function(e){return!w.expr.pseudos.visible(e)},w.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},w.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Vt={0:200,1223:204},Gt=w.ajaxSettings.xhr();h.cors=!!Gt&&"withCredentials"in Gt,h.ajax=Gt=!!Gt,w.ajaxTransport(function(t){var n,r;if(h.cors||Gt&&!t.crossDomain)return{send:function(i,o){var a,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(a in t.xhrFields)s[a]=t.xhrFields[a];t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");for(a in i)s.setRequestHeader(a,i[a]);n=function(e){return function(){n&&(n=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?o(0,"error"):o(s.status,s.statusText):o(Vt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=n(),r=s.onerror=s.ontimeout=n("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&e.setTimeout(function(){n&&r()})},n=n("abort");try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}}),w.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),w.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return w.globalEval(e),e}}}),w.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),w.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(i,o){t=w("
<& ("view/" + maincomp) qparam >
tntnet-3.0/misc/template/webapp/000077500000000000000000000000001365471676700167425ustar00rootroot00000000000000tntnet-3.0/misc/template/webapp/@PROJECT@.xml000066400000000000000000000015171365471676700207760ustar00rootroot00000000000000 sqlite:test.db 8000 INFO tntnet INFO component.comp INFO @PROJECT@ tntnet-3.0/misc/template/webapp/Makefile.am000066400000000000000000000042441365471676700210020ustar00rootroot00000000000000ACLOCAL_AMFLAGS = -I m4 AUTOMAKE_OPTIONS = subdir-objects AM_CPPFLAGS = -I$(top_srcdir)/include bin_PROGRAMS = @PROJECT@ ecppSources = \ actionmain.ecpp \ json/example.ecpp \ json/getnumbers.ecpp \ json/dbaccess.ecpp \ action/insertdata.ecpp \ action/myaction.ecpp \ webmain.ecpp staticSources = \ resources/app/actions.js \ resources/app/json.js \ resources/app/main.js \ resources/app/dbaccess.js \ resources/app/dbinsert.js \ resources/css/noty/themes/nest.css \ resources/css/noty/themes/relax.css \ resources/css/noty/themes/mint.css \ resources/css/noty/themes/semanticui.css \ resources/css/noty/themes/light.css \ resources/css/noty/themes/metroui.css \ resources/css/noty/themes/sunset.css \ resources/css/noty/themes/bootstrap-v4.css \ resources/css/noty/themes/bootstrap-v3.css \ resources/css/@PROJECT@.css \ resources/css/statusbar.css \ resources/css/noty.css.map \ resources/css/noty.css \ resources/css/dropdown.css \ resources/html/json.html \ resources/html/dbaccess.html \ resources/html/dbinsert.html \ resources/html/actions.html \ resources/js/require.js \ resources/js/main.js \ resources/js/jquery-3.3.1.min.js \ resources/js/noty.min.js \ resources/js/tntnet.js \ resources/js/noty.js noinst_HEADERS = \ action.ecpp \ include/actionreply.h \ include/noty.h \ include/@PROJECT@/config.h @PROJECT@_SOURCES = \ src/@PROJECT@/config.cpp \ src/main.cpp \ $(ecppSources) nodist_@PROJECT@_SOURCES = \ resources.cpp @PROJECT@_LDADD = -lcxxtools -ltntnet -ltntdb nobase_dist_noinst_DATA = $(staticSources) @PROJECT@.xml CLEANFILES = $(ecppSources:.ecpp=.cpp) $(ecppSources:.ecpp=.deps) resources.cpp # # Rules for tntnet applications # ECPPFLAGS=-I$(srcdir) resources.cpp: $(staticSources) Makefile.am $(AM_V_GEN)$(ECPPC) -bb -z -n resources -p -o resources.cpp $(ECPPFLAGS) $(staticSources) SUFFIXES=.ecpp .cpp .ecpp.cpp: $(AM_V_GEN)$(ECPPC) -n `echo $<|$(SED) 's|^$(srcdir)/||; s|\.ecpp$$||'` $(ECPPFLAGS) -o $@ $< .ecpp.deps: $(AM_V_GEN)$(ECPPC) -M $(ECPPFLAGS) $< | $(SED) '1s|\(.*\).cpp:|\1.cpp $@:|' > $@ -include $(ecppSources:.ecpp=.deps) tntnet-3.0/misc/template/webapp/README.md000066400000000000000000000024661365471676700202310ustar00rootroot00000000000000Tntnet project @PROJECT@ =========================== This is a tntnet web application, which runs as a single page application. Changing pages is done my loading html fragments using ajax calls and placing in the content div. Data is typically loaded using json. Autoconf, automake and libtool, commonly known as the autotools, is used for building the application. The project uses jquery for manipulating the DOM and executing ajax calls. Require.js is used for handling js modules. Noty.js is used for notifications. Building -------- The `autotools` are set up and `autoreconf -i` is run already. To build run `./configure && make`. To rebuild after changing code run just `make`. To add new source files to the project add them to `Makefile.am`. Directory structure and url mapping ----------------------------------- Static files are put into the `resources` directory and added to the `staticSources` variable in `Makefile.am`. Dynamic files are put into sub directories in the source directory. The name of the sub directory is used as the extension in the url. The actual file gets the extension `.ecpp`. Add the files to the variable `ecppSources` in the top level `Makefile.am`. They are compiled with ecpp and the code there is executed at runtime. e.g. the url `/foo.json` calls the component `json/foo.ecpp`. tntnet-3.0/misc/template/webapp/action.ecpp000066400000000000000000000003051365471676700210660ustar00rootroot00000000000000<%request include="actionreply.h"> // Define object, which stores the reply of a action // This is serialized into json and sent to the browser. ActionReply actionReply; tntnet-3.0/misc/template/webapp/action/000077500000000000000000000000001365471676700202175ustar00rootroot00000000000000tntnet-3.0/misc/template/webapp/action/README000066400000000000000000000016611365471676700211030ustar00rootroot00000000000000Put your actions here. Actions are json requests, which do not expect an reply other than success or error. They have the file extension `.ecpp`. Typically they start with a Tag `<%cpp>` and end with the closing tag ``. On error they throw an exception or return a proper http error code. From your java script code they are accessed using the js method `tntnet.action`. The url is the path to the action code without `action` and the extension. Example: tntnet.action( 'process/activate', // calls the action `action/process/activate.ecpp` { processId: 47 }, // a parameter function(data, textStatus, jqXHR) { // optionally a function, which is called on success information("Process activated"); }, function(data, textStatus, jqXHR) { // optionally a function, which is called on failure error("Failed to activate process: " + data); }); tntnet-3.0/misc/template/webapp/action/insertdata.ecpp000066400000000000000000000007561365471676700232360ustar00rootroot00000000000000<%include>action.ecpp <%args> int number; name; <%pre> #include <@PROJECT@/config.h> #include #include <%cpp> tntdb::Connection conn = tntdb::connectCached(@PROJECT@::Config::it().dburl()); tntdb::Statement ins = conn.prepare(R"SQL( insert into test(name, number) values (:name, :number) )SQL"); ins.set("number", number) .set("name", name) .execute(); actionReply.information("one row inserted"); tntnet-3.0/misc/template/webapp/action/myaction.cpp000066400000000000000000000037371365471676700225600ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////// // action/myaction.cpp // generated with ecppc // #include #include #include #include #include #include #include #include #include log_define("component.action.myaction") // <%pre> #include // namespace { class _component_ : public tnt::EcppComponent { _component_& main() { return *this; } protected: ~_component_(); public: _component_(const tnt::Compident& ci, const tnt::Urlmapper& um, tnt::Comploader& cl); unsigned operator() (tnt::HttpRequest& request, tnt::HttpReply& reply, tnt::QueryParams& qparam); }; static tnt::EcppComponentFactoryImpl<_component_> Factory("action/myaction"); // <%shared> // // <%config> // #define SET_LANG(lang) \ do \ { \ request.setLang(lang); \ reply.setLocale(request.getLocale()); \ } while (false) _component_::_component_(const tnt::Compident& ci, const tnt::Urlmapper& um, tnt::Comploader& cl) : EcppComponent(ci, um, cl) { // <%init> // } _component_::~_component_() { // <%cleanup> // } template inline void _tnt_ignore_unused(const T&) { } unsigned _component_::operator() (tnt::HttpRequest& request, tnt::HttpReply& reply, tnt::QueryParams& qparam) { log_trace("action/myaction " << qparam.getUrl()); #line 6 "action.ecpp" typedef ActionReply actionReply_type; TNT_REQUEST_FILE_VAR(ActionReply, actionReply, action.ecpp, ()); // <%request> ActionReply actionReply _tnt_ignore_unused(actionReply); // <%cpp> // <%include> action.ecpp // #line 2 "action/myaction.ecpp" // This is a example action, which just opens a notification in the browser. actionReply.information("myaction executed"); // <%/cpp> return DEFAULT; } } // namespace tntnet-3.0/misc/template/webapp/action/myaction.ecpp000066400000000000000000000002551365471676700227150ustar00rootroot00000000000000<%include>action.ecpp <%cpp> // This is a example action, which just opens a notification in the browser. actionReply.information("myaction executed"); tntnet-3.0/misc/template/webapp/actionmain.ecpp000066400000000000000000000013651365471676700217420ustar00rootroot00000000000000<%pre> #include "actionreply.h" #include #include <%include>action.ecpp <%cpp> // A action is a http request, which do not expect any output other than // success or failure or notifications. try { // call the actual action component unsigned ret = callComp("action/" + request.getArg("next"), request, reply, qparam); log_debug("action <" << request.getArg("next") << "> http return code " << ret); if (ret > HTTP_OK) return ret; } catch (const tnt::HttpError& e) { throw; } catch (const std::exception& e) { log_warn(e.what()); actionReply.setFailed(e.what()); } reply.setContentType("application/json"); reply.out() << cxxtools::Json(actionReply); tntnet-3.0/misc/template/webapp/configure.ac000066400000000000000000000012211365471676700212240ustar00rootroot00000000000000AC_INIT([@PROJECT@], [0.1], [your-email@somewhere]) AM_INIT_AUTOMAKE([foreign]) LT_INIT AC_CONFIG_MACRO_DIR([m4]) AC_PROG_CXX AC_LANG(C++) AX_CXX_COMPILE_STDCXX_11(noext, optional) AC_CONFIG_HEADERS([config.h]) AC_CHECK_HEADER([cxxtools/mutex.h], , AC_MSG_ERROR([cxxtools headers not found])) AC_CHECK_HEADER([tnt/httpreply.h], , AC_MSG_ERROR([tntnet headers not found])) AC_CHECK_HEADER([tntdb/connection.h], , AC_MSG_ERROR([tntdb headers not found])) AC_CHECK_PROGS(ECPPC, [ecppc]) AC_PROG_SED AX_CHECK_COMPILE_FLAG([-Wall], [CPPFLAGS="$CPPFLAGS -Wall"]) AX_CHECK_COMPILE_FLAG([-pedantic], [CPPFLAGS="$CPPFLAGS -pedantic"]) AC_OUTPUT([ Makefile ]) tntnet-3.0/misc/template/webapp/include/000077500000000000000000000000001365471676700203655ustar00rootroot00000000000000tntnet-3.0/misc/template/webapp/include/@PROJECT@/000077500000000000000000000000001365471676700216735ustar00rootroot00000000000000tntnet-3.0/misc/template/webapp/include/@PROJECT@/config.h000066400000000000000000000022141365471676700233100ustar00rootroot00000000000000#ifndef @PROJECT@_CONFIG_H #define @PROJECT@_CONFIG_H #include namespace @PROJECT@ { // This class defines specifies the configuraton variables needed in the web // applicatoin. The base class is `tnt::TntConfig` so that all configurations // defined in tntnet.xml can be used here. // By deriving from that class you may add own variables there. As examples 2 // variables are defined: _htdocs_ and _dburl_. _htdocs_ is used by the // application to load static files from the file system. _dburl_ specifies the // database used in the db examples. It uses `tntdb` to access a database and // hence the rules for dburls of tntdb are used here. // To add own variables, add member variables here and add them to the // deserialization operator in `src/@PROJECT@/config.cpp`. class Config : public tnt::TntConfig { friend void operator>>= (const cxxtools::SerializationInfo& si, Config& config); std::string _htdocs; std::string _dburl; public: Config(); const std::string& htdocs() const { return _htdocs; } const std::string& dburl() const { return _dburl; } static const Config& it(); }; } #endif tntnet-3.0/misc/template/webapp/include/actionreply.h000066400000000000000000000024301365471676700230660ustar00rootroot00000000000000#ifndef ACTIONREPLY_H #define ACTIONREPLY_H #include "noty.h" // Represents a reply for a action. // A action is a http request, which do not expect any output other than // success or failure or notifications. // The class is derived from Noty, which adds methods for noty.js notifications. // On the server side those notifications are displayed when the action request // is sent back. // class ActionReply : public Noty { friend void operator <<= (cxxtools::SerializationInfo& si, const ActionReply& reply); public: ActionReply() : _success(true) { } void setSuccess(const cxxtools::String& m = cxxtools::String()) { _success = true; if (!m.empty()) success(m); } void setSuccess(const std::string& m) { _success = true; success(m); } void setFailed(const cxxtools::String& m) { _success = false; error(m); } void setFailed(const std::string& m) { _success = false; error(m); } private: bool _success; }; inline void operator <<= (cxxtools::SerializationInfo& si, const ActionReply& reply) { si.addMember("success") <<= reply._success; si.addMember("notifications") <<= static_cast(reply); } #endif // ACTIONREPLY_H tntnet-3.0/misc/template/webapp/include/noty.h000066400000000000000000000063741365471676700215410ustar00rootroot00000000000000// interface class for JavaScript noty #ifndef NOTY_H #define NOTY_H #include #include #include #include // Represents a single notification, which can be displayed using noty.js struct Notification { enum Severity { ERROR = 4, WARNING = 3, INFORMATION = 2, NOTIFICATION = 1, SUCCESS = 0 }; Notification() { } Notification(Severity s, const cxxtools::String& m, cxxtools::Timespan t) : severity(s), message(m), timeout(t) { } Notification(Severity s, const std::string& m, cxxtools::Timespan t) : severity(s), message(cxxtools::Utf8Codec::decode(m)), timeout(t) { } Severity severity; cxxtools::String message; cxxtools::Timespan timeout; }; // Represents notifications, which can be displayed using noty.js class Noty { friend void operator <<= (cxxtools::SerializationInfo& si, const Noty& reply); public: Noty() { } void error(const cxxtools::String& msg, cxxtools::Milliseconds timeout = -1) { _notifications.push_back(Notification(Notification::ERROR, msg, timeout)); } void error(const std::string& msg, cxxtools::Milliseconds timeout = -1) { _notifications.push_back(Notification(Notification::ERROR, msg, timeout)); } void warning(const cxxtools::String& msg, cxxtools::Milliseconds timeout = -1) { _notifications.push_back(Notification(Notification::WARNING, msg, timeout)); } void warning(const std::string& msg, cxxtools::Milliseconds timeout = -1) { _notifications.push_back(Notification(Notification::WARNING, msg, timeout)); } void information(const cxxtools::String& msg, cxxtools::Milliseconds timeout = 5000) { _notifications.push_back(Notification(Notification::INFORMATION, msg, timeout)); } void information(const std::string& msg, cxxtools::Milliseconds timeout = 5000) { _notifications.push_back(Notification(Notification::INFORMATION, msg, timeout)); } void notification(const cxxtools::String& msg, cxxtools::Milliseconds timeout = 5000) { _notifications.push_back(Notification(Notification::NOTIFICATION, msg, timeout)); } void notification(const std::string& msg, cxxtools::Milliseconds timeout = 5000) { _notifications.push_back(Notification(Notification::NOTIFICATION, msg, timeout)); } void success(const cxxtools::String& msg, cxxtools::Milliseconds timeout = 5000) { _notifications.push_back(Notification(Notification::SUCCESS, msg, timeout)); } void success(const std::string& msg, cxxtools::Milliseconds timeout = 5000) { _notifications.push_back(Notification(Notification::SUCCESS, msg, timeout)); } private: std::vector _notifications; }; inline void operator <<= (cxxtools::SerializationInfo& si, const Notification& notification) { si.addMember("severity") <<= notification.severity; si.addMember("message") <<= notification.message; si.addMember("timeout") <<= static_cast(cxxtools::Milliseconds(notification.timeout)); } inline void operator <<= (cxxtools::SerializationInfo& si, const Noty& noty) { si <<= noty._notifications; } #endif // NOTY_H tntnet-3.0/misc/template/webapp/json/000077500000000000000000000000001365471676700177135ustar00rootroot00000000000000tntnet-3.0/misc/template/webapp/json/dbaccess.ecpp000066400000000000000000000015541365471676700223400ustar00rootroot00000000000000<%args> int number; bool beautify; <%pre> #include <@PROJECT@/config.h> #include #include #include #include namespace { struct Result { int number; std::string name; }; void operator<<= (cxxtools::SerializationInfo& si, const Result& result) { si.addMember("number") <<= result.number; si.addMember("name") <<= result.name; } } <%cpp> tntdb::Connection conn = tntdb::connectCached(@PROJECT@::Config::it().dburl()); tntdb::Statement sel = conn.prepare(R"SQL( select name from test where number = :number order by number )SQL"); Result result; result.number = number; sel.set("number", number) .selectValue() .get(result.name); reply.setContentType("application/json"); reply.out() << cxxtools::Json(result).beautify(beautify); tntnet-3.0/misc/template/webapp/json/example.ecpp000066400000000000000000000011461365471676700222210ustar00rootroot00000000000000<%args> bool beautify; <%pre> #include #include #include namespace { struct Result { std::vector values; cxxtools::DateTime dt; }; void operator<<= (cxxtools::SerializationInfo& si, const Result& result) { si.addMember("values") <<= result.values; si.addMember("dt") <<= result.dt; } } <%cpp> Result result; result.values.push_back(17); result.values.push_back(42); result.dt = cxxtools::DateTime::localtime(); reply.setContentType("application/json"); reply.out() << cxxtools::Json(result).beautify(beautify); tntnet-3.0/misc/template/webapp/json/getnumbers.ecpp000066400000000000000000000011341365471676700227360ustar00rootroot00000000000000<%args> bool beautify; <%pre> #include <@PROJECT@/config.h> #include #include #include #include #include <%cpp> tntdb::Connection conn = tntdb::connectCached(@PROJECT@::Config::it().dburl()); tntdb::Statement sel = conn.prepare(R"SQL( select number from test )SQL"); std::vector result; for (auto row: sel) { int value; row.get(value); result.push_back(value); } reply.setContentType("application/json"); reply.out() << cxxtools::Json(result).beautify(beautify); tntnet-3.0/misc/template/webapp/log.properties000066400000000000000000000007621365471676700216460ustar00rootroot00000000000000rootlogger INFO logger.@PROJECT@ INFO # this enables logging to a file #file = @PROJECT@.log # setting maxfilesize and maxbackupindex enables rolling of file # when file reaches maxfilesize, it is renamed to file.0 and a new file is created # file.0 gets file.1 and so on up to maxbackupindex #maxfilesize = 1M #maxbackupindex = 2 # log to stdout instead of stderr if set #stdout = 1 # send loging via udp to host #loghost = hostname # set when loghost is a network address #broadcast = 1 tntnet-3.0/misc/template/webapp/m4/000077500000000000000000000000001365471676700172625ustar00rootroot00000000000000tntnet-3.0/misc/template/webapp/m4/ax_check_compile_flag.m4000066400000000000000000000064111365471676700237740ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # # Check whether the given FLAG works with the current language's compiler # or gives an error. (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # INPUT gives an alternative input source to AC_COMPILE_IFELSE. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 3 AC_DEFUN([AX_CHECK_COMPILE_FLAG], [AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_COMPILE_FLAGS tntnet-3.0/misc/template/webapp/m4/ax_cxx_compile_stdcxx_11.m4000066400000000000000000000112751365471676700244320ustar00rootroot00000000000000# ============================================================================ # http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html # ============================================================================ # # SYNOPSIS # # AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional]) # # DESCRIPTION # # Check for baseline language coverage in the compiler for the C++11 # standard; if necessary, add switches to CXXFLAGS to enable support. # # The first argument, if specified, indicates whether you insist on an # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. # -std=c++11). If neither is specified, you get whatever works, with # preference for an extended mode. # # The second argument, if specified 'mandatory' or if left unspecified, # indicates that baseline C++11 support is required and that the macro # should error out if no mode with that support is found. If specified # 'optional', then configuration proceeds regardless, after defining # HAVE_CXX11 if and only if a supporting mode is found. # # LICENSE # # Copyright (c) 2008 Benjamin Kosnik # Copyright (c) 2012 Zack Weinberg # Copyright (c) 2013 Roy Stogner # Copyright (c) 2014 Alexey Sokolov # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 4 m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[ template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; struct Base { virtual void f() {} }; struct Child : public Base { virtual void f() override {} }; typedef check> right_angle_brackets; int a; decltype(a) b; typedef check check_type; check_type c; check_type&& cr = static_cast(c); auto d = a; auto l = [](){}; ]]) AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl m4_if([$1], [], [], [$1], [ext], [], [$1], [noext], [], [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl m4_if([$2], [], [ax_cxx_compile_cxx11_required=true], [$2], [mandatory], [ax_cxx_compile_cxx11_required=true], [$2], [optional], [ax_cxx_compile_cxx11_required=false], [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])]) AC_LANG_PUSH([C++])dnl ac_success=no AC_CACHE_CHECK(whether $CXX supports C++11 features by default, ax_cv_cxx_compile_cxx11, [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [ax_cv_cxx_compile_cxx11=yes], [ax_cv_cxx_compile_cxx11=no])]) if test x$ax_cv_cxx_compile_cxx11 = xyes; then ac_success=yes fi m4_if([$1], [noext], [], [dnl if test x$ac_success = xno; then for switch in -std=gnu++11 -std=gnu++0x; do cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, $cachevar, [ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [eval $cachevar=yes], [eval $cachevar=no]) CXXFLAGS="$ac_save_CXXFLAGS"]) if eval test x\$$cachevar = xyes; then CXXFLAGS="$CXXFLAGS $switch" ac_success=yes break fi done fi]) m4_if([$1], [ext], [], [dnl if test x$ac_success = xno; then for switch in -std=c++11 -std=c++0x; do cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, $cachevar, [ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [eval $cachevar=yes], [eval $cachevar=no]) CXXFLAGS="$ac_save_CXXFLAGS"]) if eval test x\$$cachevar = xyes; then CXXFLAGS="$CXXFLAGS $switch" ac_success=yes break fi done fi]) AC_LANG_POP([C++]) if test x$ax_cxx_compile_cxx11_required = xtrue; then if test x$ac_success = xno; then AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.]) fi else if test x$ac_success = xno; then HAVE_CXX11=0 AC_MSG_NOTICE([No compiler with C++11 support was found]) else HAVE_CXX11=1 AC_DEFINE(HAVE_CXX11,1, [define if the compiler supports basic C++11 syntax]) fi AC_SUBST(HAVE_CXX11) fi ]) tntnet-3.0/misc/template/webapp/resources/000077500000000000000000000000001365471676700207545ustar00rootroot00000000000000tntnet-3.0/misc/template/webapp/resources/app/000077500000000000000000000000001365471676700215345ustar00rootroot00000000000000tntnet-3.0/misc/template/webapp/resources/app/actions.js000066400000000000000000000016201365471676700235310ustar00rootroot00000000000000define(['jquery', 'tntnet'], function($, tntnet) { return { onCreate: function(content) { $('[name=action]', content).click(function() { tntnet.action('myaction'); }); $('[name=error]', content).click(function() { tntnet.error('this is a error'); }); $('[name=warning]', content).click(function() { tntnet.warning('this is a warning'); }); $('[name=information]', content).click(function() { tntnet.information('this is a information'); }); $('[name=notification]', content).click(function() { tntnet.notification('this is a notification'); }); $('[name=success]', content).click(function() { tntnet.success('this is a success'); }); } } }); tntnet-3.0/misc/template/webapp/resources/app/dbaccess.js000066400000000000000000000016171365471676700236460ustar00rootroot00000000000000define(['jquery'], function($) { return { onCreate: function(content) { $('[name=getdata]', content).click(function() { $.getJSON('dbaccess.json', { number: $('#dbnumber', content).val() }, function(result) { $('#dbname').html(result.name); }); }); }, onShow: function(content) { this.updateSelection(); }, updateSelection: function() { $.getJSON("getnumbers.json", function(names) { var sel = $('#dbnumber'); sel.empty(); $('