From 004dec2c2f44a0db510dfd65e5ffd8c9fc4ff83e Mon Sep 17 00:00:00 2001 From: zedshaw Date: Sat, 28 Jan 2006 19:03:53 +0000 Subject: initial import into trunk git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/trunk@4 19e92222-5c0b-0410-8929-a290d50e31e9 --- COPYING | 504 ++++++++ LICENSE | 504 ++++++++ README | 52 + Rakefile | 30 + doc/rdoc/classes/Mongrel.html | 130 ++ doc/rdoc/classes/Mongrel/Error404Handler.html | 171 +++ .../Mongrel/Error404Handler.src/M000019.html | 18 + .../Mongrel/Error404Handler.src/M000020.html | 18 + doc/rdoc/classes/Mongrel/HttpHandler.html | 159 +++ .../classes/Mongrel/HttpHandler.src/M000017.html | 17 + doc/rdoc/classes/Mongrel/HttpParser.html | 265 ++++ .../classes/Mongrel/HttpParser.src/M000001.html | 28 + .../classes/Mongrel/HttpParser.src/M000002.html | 29 + .../classes/Mongrel/HttpParser.src/M000003.html | 29 + .../classes/Mongrel/HttpParser.src/M000004.html | 33 + .../classes/Mongrel/HttpParser.src/M000005.html | 27 + .../classes/Mongrel/HttpParser.src/M000006.html | 27 + .../classes/Mongrel/HttpParser.src/M000007.html | 28 + doc/rdoc/classes/Mongrel/HttpRequest.html | 177 +++ .../classes/Mongrel/HttpRequest.src/M000021.html | 30 + doc/rdoc/classes/Mongrel/HttpResponse.html | 159 +++ .../classes/Mongrel/HttpResponse.src/M000018.html | 18 + doc/rdoc/classes/Mongrel/HttpServer.html | 300 +++++ .../classes/Mongrel/HttpServer.src/M000008.html | 19 + .../classes/Mongrel/HttpServer.src/M000009.html | 59 + .../classes/Mongrel/HttpServer.src/M000010.html | 22 + .../classes/Mongrel/HttpServer.src/M000011.html | 18 + .../classes/Mongrel/HttpServer.src/M000012.html | 18 + doc/rdoc/classes/Mongrel/URIClassifier.html | 257 ++++ .../classes/Mongrel/URIClassifier.src/M000013.html | 54 + .../classes/Mongrel/URIClassifier.src/M000014.html | 50 + .../classes/Mongrel/URIClassifier.src/M000015.html | 36 + .../classes/Mongrel/URIClassifier.src/M000016.html | 73 ++ doc/rdoc/created.rid | 1 + doc/rdoc/files/COPYING.html | 756 +++++++++++ doc/rdoc/files/LICENSE.html | 756 +++++++++++ doc/rdoc/files/README.html | 170 +++ doc/rdoc/files/ext/http11/http11_c.html | 101 ++ doc/rdoc/files/lib/mongrel_rb.html | 110 ++ doc/rdoc/fr_class_index.html | 34 + doc/rdoc/fr_file_index.html | 31 + doc/rdoc/fr_method_index.html | 47 + doc/rdoc/index.html | 24 + doc/rdoc/rdoc-style.css | 208 +++ examples/simpletest.rb | 15 + examples/tepee.rb | 178 +++ examples/webrick_compare.rb | 20 + ext/http11/MANIFEST | 0 ext/http11/ext_help.h | 14 + ext/http11/extconf.rb | 6 + ext/http11/http11.c | 429 ++++++ ext/http11/http11_parser.c | 918 +++++++++++++ ext/http11/http11_parser.h | 37 + ext/http11/http11_parser.rl | 162 +++ ext/http11/tst.h | 40 + ext/http11/tst_cleanup.c | 24 + ext/http11/tst_delete.c | 146 +++ ext/http11/tst_grow_node_free_list.c | 38 + ext/http11/tst_init.c | 41 + ext/http11/tst_insert.c | 192 +++ ext/http11/tst_search.c | 54 + lib/mongrel.rb | 191 +++ setup.rb | 1360 ++++++++++++++++++++ test/.test_ws.rb.swp | Bin 0 -> 12288 bytes test/test_http11.rb | 31 + test/test_uriclassifier.rb | 104 ++ test/test_ws.rb | 33 + tools/rakehelp.rb | 99 ++ 68 files changed, 9729 insertions(+) create mode 100644 COPYING create mode 100644 LICENSE create mode 100644 README create mode 100644 Rakefile create mode 100644 doc/rdoc/classes/Mongrel.html create mode 100644 doc/rdoc/classes/Mongrel/Error404Handler.html create mode 100644 doc/rdoc/classes/Mongrel/Error404Handler.src/M000019.html create mode 100644 doc/rdoc/classes/Mongrel/Error404Handler.src/M000020.html create mode 100644 doc/rdoc/classes/Mongrel/HttpHandler.html create mode 100644 doc/rdoc/classes/Mongrel/HttpHandler.src/M000017.html create mode 100644 doc/rdoc/classes/Mongrel/HttpParser.html create mode 100644 doc/rdoc/classes/Mongrel/HttpParser.src/M000001.html create mode 100644 doc/rdoc/classes/Mongrel/HttpParser.src/M000002.html create mode 100644 doc/rdoc/classes/Mongrel/HttpParser.src/M000003.html create mode 100644 doc/rdoc/classes/Mongrel/HttpParser.src/M000004.html create mode 100644 doc/rdoc/classes/Mongrel/HttpParser.src/M000005.html create mode 100644 doc/rdoc/classes/Mongrel/HttpParser.src/M000006.html create mode 100644 doc/rdoc/classes/Mongrel/HttpParser.src/M000007.html create mode 100644 doc/rdoc/classes/Mongrel/HttpRequest.html create mode 100644 doc/rdoc/classes/Mongrel/HttpRequest.src/M000021.html create mode 100644 doc/rdoc/classes/Mongrel/HttpResponse.html create mode 100644 doc/rdoc/classes/Mongrel/HttpResponse.src/M000018.html create mode 100644 doc/rdoc/classes/Mongrel/HttpServer.html create mode 100644 doc/rdoc/classes/Mongrel/HttpServer.src/M000008.html create mode 100644 doc/rdoc/classes/Mongrel/HttpServer.src/M000009.html create mode 100644 doc/rdoc/classes/Mongrel/HttpServer.src/M000010.html create mode 100644 doc/rdoc/classes/Mongrel/HttpServer.src/M000011.html create mode 100644 doc/rdoc/classes/Mongrel/HttpServer.src/M000012.html create mode 100644 doc/rdoc/classes/Mongrel/URIClassifier.html create mode 100644 doc/rdoc/classes/Mongrel/URIClassifier.src/M000013.html create mode 100644 doc/rdoc/classes/Mongrel/URIClassifier.src/M000014.html create mode 100644 doc/rdoc/classes/Mongrel/URIClassifier.src/M000015.html create mode 100644 doc/rdoc/classes/Mongrel/URIClassifier.src/M000016.html create mode 100644 doc/rdoc/created.rid create mode 100644 doc/rdoc/files/COPYING.html create mode 100644 doc/rdoc/files/LICENSE.html create mode 100644 doc/rdoc/files/README.html create mode 100644 doc/rdoc/files/ext/http11/http11_c.html create mode 100644 doc/rdoc/files/lib/mongrel_rb.html create mode 100644 doc/rdoc/fr_class_index.html create mode 100644 doc/rdoc/fr_file_index.html create mode 100644 doc/rdoc/fr_method_index.html create mode 100644 doc/rdoc/index.html create mode 100644 doc/rdoc/rdoc-style.css create mode 100644 examples/simpletest.rb create mode 100644 examples/tepee.rb create mode 100644 examples/webrick_compare.rb create mode 100644 ext/http11/MANIFEST create mode 100644 ext/http11/ext_help.h create mode 100644 ext/http11/extconf.rb create mode 100644 ext/http11/http11.c create mode 100644 ext/http11/http11_parser.c create mode 100644 ext/http11/http11_parser.h create mode 100644 ext/http11/http11_parser.rl create mode 100644 ext/http11/tst.h create mode 100644 ext/http11/tst_cleanup.c create mode 100644 ext/http11/tst_delete.c create mode 100644 ext/http11/tst_grow_node_free_list.c create mode 100644 ext/http11/tst_init.c create mode 100644 ext/http11/tst_insert.c create mode 100644 ext/http11/tst_search.c create mode 100644 lib/mongrel.rb create mode 100644 setup.rb create mode 100644 test/.test_ws.rb.swp create mode 100644 test/test_http11.rb create mode 100644 test/test_uriclassifier.rb create mode 100644 test/test_ws.rb create mode 100644 tools/rakehelp.rb diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..b1e3f5a --- /dev/null +++ b/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b1e3f5a --- /dev/null +++ b/LICENSE @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/README b/README new file mode 100644 index 0000000..7a8f954 --- /dev/null +++ b/README @@ -0,0 +1,52 @@ +== Mongrel: Simple Fast Mostly Ruby Web Server + +Mongrel is a small library that provides a very fast HTTP 1.1 server for Ruby +web applications. It is not particular to any framework, and is intended to +be just enough to get a web application running behind a more complete and robust +web server. + +What makes Mongrel so fast is the careful use of a C extension to provide fast +HTTP 1.1 protocol parsing and fast URI lookup. This combination makes the server +very fast without too many portability issues. + +== Status + +Mongrel is still very ALPHA work, but you can see how it's used with the +Camping framework (version 1.2) and take a look at how you might use it. +Right now it handles HTTP requests well and process the responses fast, but +you have to "roll your own" response code. + +The next release of Mongrel will have improved IO handling, much more stability, +and should have a better Mongrel::HttpResponse object with more useful features. + +== Install + +You can install it via source from http://www.zedshaw.com/downloads/mongrel/ +or you can gram a RubyGem at http://www.zedshaw.com/downloads/mongrel/ +and install that manually. I'm working on setting up a RubyForge project. + +It doesn't explicitly require Camping, but if you want to run the examples/tepee.rb +example then you'll need to install Camping 1.2 at least (and redcloth I think). +These are all available from RubyGems. + +The library consists of a C extension so you'll need a C compiler or at least a friend +who can build it for you. + + +Finally, the source include a setup.rb for those who hate RubyGems. + +== Usage + +Best place to look for usage examples right now is the examples/ directory. + +== Speed + +This 0.1.2 release will not be as fast as the 0.1.1 release since I've temporarily +removed threads as a test. There were many stability issues related to handling +each request in a thread, especially on OSX. I've taken them out for now to +make things stable. Even with this removed Mongrel is still pretty fast compared +to WEBrick. + +== Contact + +E-mail zedshaw at zedshaw.com and I'll help. Comments about the API are welcome. diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..01557f4 --- /dev/null +++ b/Rakefile @@ -0,0 +1,30 @@ +require 'rake' +require 'rake/testtask' +require 'rake/clean' +require 'rake/gempackagetask' +require 'rake/rdoctask' +require 'tools/rakehelp' +require 'fileutils' +include FileUtils + +setup_tests +setup_clean ["ext/http11/Makefile", "pkg", "lib/*.bundle", "ext/http11/*.bundle"] +setup_rdoc ['README', 'LICENSE', 'COPYING', 'lib/*.rb', + 'doc/**/*.rdoc', 'ext/http11/http11.c'] + +desc "Does a full compile, test run" +task :default => [:compile, :test] + +desc "Compiles all extensions" +task :compile => [:http11] +task :package => [:clean] + +task :ragel do + sh %{/usr/local/bin/ragel ext/http11/http11_parser.rl | /usr/local/bin/rlcodegen -G2 -o ext/http11/http11_parser.c} +end + +setup_extension("http11", "http11") + +summary = "An experimental fast simple web server for Ruby." +test_file = "test/test_ws.rb" +setup_gem("mongrel", "0.1.2", "Zed A. Shaw", summary, [], test_file) diff --git a/doc/rdoc/classes/Mongrel.html b/doc/rdoc/classes/Mongrel.html new file mode 100644 index 0000000..72cd9be --- /dev/null +++ b/doc/rdoc/classes/Mongrel.html @@ -0,0 +1,130 @@ + + + + + + Module: Mongrel + + + + + + + + + + +
+ + + + + + + + + + +
ModuleMongrel
In: + + lib/mongrel.rb + +
+ + ext/http11/http11.c + +
+
+
+ + +
+ + + +
+ +
+

+Mongrel module containing all of the classes +(include C extensions) for running a Mongrel web +server. It contains a minimalist HTTP server with just enough functionality +to service web application requests fast as possible. +

+ +
+ + +
+ + +
+ + + + +
+ + + + + + + + + + + + +
+ + + + + + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/Error404Handler.html b/doc/rdoc/classes/Mongrel/Error404Handler.html new file mode 100644 index 0000000..a227f40 --- /dev/null +++ b/doc/rdoc/classes/Mongrel/Error404Handler.html @@ -0,0 +1,171 @@ + + + + + + Class: Mongrel::Error404Handler + + + + + + + + + + +
+ + + + + + + + + + + + + + +
ClassMongrel::Error404Handler
In: + + lib/mongrel.rb + +
+
Parent: + + HttpHandler + +
+
+ + +
+ + + +
+ +
+

+The server normally returns a 404 response if a URI is requested, but it +also returns a lame empty message. This lets you do a 404 response with a +custom message for special URIs. +

+ +
+ + +
+ +
+

Methods

+ +
+ new   + process   +
+
+ +
+ + + + +
+ + + + + + + + + +
+

Public Class methods

+ +
+ + + + +
+

+Sets the message to return. This is constructed once for the handler so +it’s pretty efficient. +

+
+
+ +

Public Instance methods

+ +
+ + + + +
+

+Just kicks back the standard 404 response with your special message. +

+
+
+ + +
+ + +
+ + + + + + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/Error404Handler.src/M000019.html b/doc/rdoc/classes/Mongrel/Error404Handler.src/M000019.html new file mode 100644 index 0000000..6cb8774 --- /dev/null +++ b/doc/rdoc/classes/Mongrel/Error404Handler.src/M000019.html @@ -0,0 +1,18 @@ + + + + + + new (Mongrel::Error404Handler) + + + + +
    # File lib/mongrel.rb, line 75
+75:     def initialize(msg)
+76:       @response = HttpServer::ERROR_404_RESPONSE + msg
+77:     end
+ + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/Error404Handler.src/M000020.html b/doc/rdoc/classes/Mongrel/Error404Handler.src/M000020.html new file mode 100644 index 0000000..76d5a15 --- /dev/null +++ b/doc/rdoc/classes/Mongrel/Error404Handler.src/M000020.html @@ -0,0 +1,18 @@ + + + + + + process (Mongrel::Error404Handler) + + + + +
    # File lib/mongrel.rb, line 80
+80:     def process(request, response)
+81:       response.socket.write(@response)
+82:     end
+ + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/HttpHandler.html b/doc/rdoc/classes/Mongrel/HttpHandler.html new file mode 100644 index 0000000..55f6f3a --- /dev/null +++ b/doc/rdoc/classes/Mongrel/HttpHandler.html @@ -0,0 +1,159 @@ + + + + + + Class: Mongrel::HttpHandler + + + + + + + + + + +
+ + + + + + + + + + + + + + +
ClassMongrel::HttpHandler
In: + + lib/mongrel.rb + +
+
Parent: + Object +
+
+ + +
+ + + +
+ +
+

+You implement your application handler with this. It’s very light +giving just the minimum necessary for you to handle a request and shoot +back a response. Look at the HttpRequest and +HttpResponse objects for how to use them. +

+ +
+ + +
+ +
+

Methods

+ +
+ process   +
+
+ +
+ + + + +
+ + + + + +
+

Attributes

+ +
+ + + + + + +
script_name [RW] 
+
+
+ + + + +
+

Public Instance methods

+ + + + +
+ + +
+ + + + + + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/HttpHandler.src/M000017.html b/doc/rdoc/classes/Mongrel/HttpHandler.src/M000017.html new file mode 100644 index 0000000..9b5f53c --- /dev/null +++ b/doc/rdoc/classes/Mongrel/HttpHandler.src/M000017.html @@ -0,0 +1,17 @@ + + + + + + process (Mongrel::HttpHandler) + + + + +
    # File lib/mongrel.rb, line 64
+64:     def process(request, response)
+65:     end
+ + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/HttpParser.html b/doc/rdoc/classes/Mongrel/HttpParser.html new file mode 100644 index 0000000..13cc01c --- /dev/null +++ b/doc/rdoc/classes/Mongrel/HttpParser.html @@ -0,0 +1,265 @@ + + + + + + Class: Mongrel::HttpParser + + + + + + + + + + +
+ + + + + + + + + + + + + + +
ClassMongrel::HttpParser
In: + + ext/http11/http11.c + +
+
Parent: + Object +
+
+ + +
+ + + +
+ + + +
+ +
+

Methods

+ +
+ error?   + execute   + finish   + finished?   + new   + nread   + reset   +
+
+ +
+ + + + +
+ + + + + + + + + +
+

Public Class methods

+ +
+ + + + +
+

+Creates a new parser. +

+
+
+ +

Public Instance methods

+ +
+ + + + +
+

+Tells you whether the parser is in an error state. +

+
+
+ +
+ + + + +
+

+Takes a Hash and a String of data, parses the String of data filling in the +Hash returning an Integer to indicate how much of the data has been read. +No matter what the return value, you should call HttpParser#finished? and +HttpParser#error? to figure out if it’s done parsing or there was an +error. +

+
+
+ +
+ + + + +
+

+Finishes a parser early which could put in a "good" or bad state. +You should call reset after finish it or bad things will happen. +

+
+
+ +
+ + + + +
+

+Tells you whether the parser is finished or not and in a good state. +

+
+
+ +
+ + + + +
+

+Returns the amount of data processed so far during this processing cycle. +It is set to 0 on initialize or reset calls and is incremented each time +execute is called. +

+
+
+ +
+ + + + +
+

+Resets the parser to it’s initial state so that you can reuse it +rather than making new ones. +

+
+
+ + +
+ + +
+ + + + + + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/HttpParser.src/M000001.html b/doc/rdoc/classes/Mongrel/HttpParser.src/M000001.html new file mode 100644 index 0000000..47326b1 --- /dev/null +++ b/doc/rdoc/classes/Mongrel/HttpParser.src/M000001.html @@ -0,0 +1,28 @@ + + + + + + new (Mongrel::HttpParser) + + + + +
/**
+ * call-seq:
+ *    parser.new -> parser
+ *
+ * Creates a new parser.
+ */
+VALUE HttpParser_init(VALUE self)
+{
+  http_parser *http = NULL;
+  DATA_GET(self, http_parser, http);
+  http_parser_init(http);
+  
+  return self;
+}
+ + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/HttpParser.src/M000002.html b/doc/rdoc/classes/Mongrel/HttpParser.src/M000002.html new file mode 100644 index 0000000..5ff567b --- /dev/null +++ b/doc/rdoc/classes/Mongrel/HttpParser.src/M000002.html @@ -0,0 +1,29 @@ + + + + + + reset (Mongrel::HttpParser) + + + + +
/**
+ * call-seq:
+ *    parser.reset -> nil
+ *
+ * Resets the parser to it's initial state so that you can reuse it
+ * rather than making new ones.
+ */
+VALUE HttpParser_reset(VALUE self)
+{
+  http_parser *http = NULL;
+  DATA_GET(self, http_parser, http);
+  http_parser_init(http);
+  
+  return Qnil;
+}
+ + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/HttpParser.src/M000003.html b/doc/rdoc/classes/Mongrel/HttpParser.src/M000003.html new file mode 100644 index 0000000..7dfc546 --- /dev/null +++ b/doc/rdoc/classes/Mongrel/HttpParser.src/M000003.html @@ -0,0 +1,29 @@ + + + + + + finish (Mongrel::HttpParser) + + + + +
/**
+ * call-seq:
+ *    parser.finish -> true/false
+ *
+ * Finishes a parser early which could put in a "good" or bad state.
+ * You should call reset after finish it or bad things will happen.
+ */
+VALUE HttpParser_finish(VALUE self)
+{
+  http_parser *http = NULL;
+  DATA_GET(self, http_parser, http);
+  http_parser_finish(http);
+  
+  return http_parser_is_finished(http) ? Qtrue : Qfalse;
+}
+ + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/HttpParser.src/M000004.html b/doc/rdoc/classes/Mongrel/HttpParser.src/M000004.html new file mode 100644 index 0000000..9ee1f57 --- /dev/null +++ b/doc/rdoc/classes/Mongrel/HttpParser.src/M000004.html @@ -0,0 +1,33 @@ + + + + + + execute (Mongrel::HttpParser) + + + + +
/**
+ * call-seq:
+ *    parser.execute(req_hash, data) -> Integer
+ *
+ * Takes a Hash and a String of data, parses the String of data filling in the Hash
+ * returning an Integer to indicate how much of the data has been read.  No matter
+ * what the return value, you should call HttpParser#finished? and HttpParser#error?
+ * to figure out if it's done parsing or there was an error.
+ */
+VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data)
+{
+  http_parser *http = NULL;
+  DATA_GET(self, http_parser, http);
+
+  http->data = (void *)req_hash;
+  http_parser_execute(http, RSTRING(data)->ptr, RSTRING(data)->len);
+  
+  return INT2FIX(http_parser_nread(http));
+}
+ + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/HttpParser.src/M000005.html b/doc/rdoc/classes/Mongrel/HttpParser.src/M000005.html new file mode 100644 index 0000000..e8ebe0e --- /dev/null +++ b/doc/rdoc/classes/Mongrel/HttpParser.src/M000005.html @@ -0,0 +1,27 @@ + + + + + + error? (Mongrel::HttpParser) + + + + +
/**
+ * call-seq:
+ *    parser.error? -> true/false
+ *
+ * Tells you whether the parser is in an error state.
+ */
+VALUE HttpParser_has_error(VALUE self)
+{
+  http_parser *http = NULL;
+  DATA_GET(self, http_parser, http);
+  
+  return http_parser_has_error(http) ? Qtrue : Qfalse;
+}
+ + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/HttpParser.src/M000006.html b/doc/rdoc/classes/Mongrel/HttpParser.src/M000006.html new file mode 100644 index 0000000..a279344 --- /dev/null +++ b/doc/rdoc/classes/Mongrel/HttpParser.src/M000006.html @@ -0,0 +1,27 @@ + + + + + + finished? (Mongrel::HttpParser) + + + + +
/**
+ * call-seq:
+ *    parser.finished? -> true/false
+ *
+ * Tells you whether the parser is finished or not and in a good state.
+ */
+VALUE HttpParser_is_finished(VALUE self)
+{
+  http_parser *http = NULL;
+  DATA_GET(self, http_parser, http);
+  
+  return http_parser_is_finished(http) ? Qtrue : Qfalse;
+}
+ + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/HttpParser.src/M000007.html b/doc/rdoc/classes/Mongrel/HttpParser.src/M000007.html new file mode 100644 index 0000000..2cfaca7 --- /dev/null +++ b/doc/rdoc/classes/Mongrel/HttpParser.src/M000007.html @@ -0,0 +1,28 @@ + + + + + + nread (Mongrel::HttpParser) + + + + +
/**
+ * call-seq:
+ *    parser.nread -> Integer
+ *
+ * Returns the amount of data processed so far during this processing cycle.  It is
+ * set to 0 on initialize or reset calls and is incremented each time execute is called.
+ */
+VALUE HttpParser_nread(VALUE self)
+{
+  http_parser *http = NULL;
+  DATA_GET(self, http_parser, http);
+  
+  return INT2FIX(http->nread);
+}
+ + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/HttpRequest.html b/doc/rdoc/classes/Mongrel/HttpRequest.html new file mode 100644 index 0000000..525ed90 --- /dev/null +++ b/doc/rdoc/classes/Mongrel/HttpRequest.html @@ -0,0 +1,177 @@ + + + + + + Class: Mongrel::HttpRequest + + + + + + + + + + +
+ + + + + + + + + + + + + + +
ClassMongrel::HttpRequest
In: + + lib/mongrel.rb + +
+
Parent: + Object +
+
+ + +
+ + + +
+ +
+

+When a handler is found for a registered URI then this class is constructed +and passed to your HttpHandler::process method. You should assume that +one handler processes all requests. Included in the HttpReqeust is a +HttpRequest.params Hash that matches common CGI params, and a +HttpRequest.body which is a string containing the request body (raw for +now). +

+

+Mongrel really only support small-ish request +bodies right now since really huge ones have to be completely read off the +wire and put into a string. Later there will be several options for +efficiently handling large file uploads. +

+ +
+ + +
+ +
+

Methods

+ +
+ new   +
+
+ +
+ + + + +
+ + + + + +
+

Attributes

+ +
+ + + + + + + + + + + +
body [R] 
params [R] 
+
+
+ + + + +
+

Public Class methods

+ +
+ + + + +
+

+You don’t really call this. It’s made for you. Main thing it +does is hook up the params, and store any remaining body data into the +HttpRequest.body attribute. +

+
+
+ + +
+ + +
+ + + + + + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/HttpRequest.src/M000021.html b/doc/rdoc/classes/Mongrel/HttpRequest.src/M000021.html new file mode 100644 index 0000000..39c1d18 --- /dev/null +++ b/doc/rdoc/classes/Mongrel/HttpRequest.src/M000021.html @@ -0,0 +1,30 @@ + + + + + + new (Mongrel::HttpRequest) + + + + +
    # File lib/mongrel.rb, line 27
+27:     def initialize(params, initial_body, socket)
+28:       @body = initial_body || ""
+29:       @params = params
+30:       @socket = socket
+31: 
+32:       # fix up the CGI requirements
+33:       params['CONTENT_LENGTH'] = params['HTTP_CONTENT_LENGTH'] || 0
+34: 
+35:       # now, if the initial_body isn't long enough for the content length we have to fill it
+36:       # TODO: adapt for big ass stuff by writing to a temp file
+37:       clen = params['HTTP_CONTENT_LENGTH'].to_i
+38:       if @body.length < clen
+39:         @body << @socket.read(clen - @body.length)
+40:       end
+41:     end
+ + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/HttpResponse.html b/doc/rdoc/classes/Mongrel/HttpResponse.html new file mode 100644 index 0000000..89832b0 --- /dev/null +++ b/doc/rdoc/classes/Mongrel/HttpResponse.html @@ -0,0 +1,159 @@ + + + + + + Class: Mongrel::HttpResponse + + + + + + + + + + +
+ + + + + + + + + + + + + + +
ClassMongrel::HttpResponse
In: + + lib/mongrel.rb + +
+
Parent: + Object +
+
+ + +
+ + + +
+ +
+

+Very very simple response object. You basically write your stuff raw to the +HttpResponse.socket variable. This will be made much easier in +future releases allowing you to set status and request headers prior to +sending the response. +

+ +
+ + +
+ +
+

Methods

+ +
+ new   +
+
+ +
+ + + + +
+ + + + + +
+

Attributes

+ +
+ + + + + + +
socket [R] 
+
+
+ + + + +
+

Public Class methods

+ +
+ + + + +
+
+
+ + +
+ + +
+ + + + + + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/HttpResponse.src/M000018.html b/doc/rdoc/classes/Mongrel/HttpResponse.src/M000018.html new file mode 100644 index 0000000..9086679 --- /dev/null +++ b/doc/rdoc/classes/Mongrel/HttpResponse.src/M000018.html @@ -0,0 +1,18 @@ + + + + + + new (Mongrel::HttpResponse) + + + + +
    # File lib/mongrel.rb, line 51
+51:     def initialize(socket)
+52:       @socket = socket
+53:     end
+ + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/HttpServer.html b/doc/rdoc/classes/Mongrel/HttpServer.html new file mode 100644 index 0000000..f3632cc --- /dev/null +++ b/doc/rdoc/classes/Mongrel/HttpServer.html @@ -0,0 +1,300 @@ + + + + + + Class: Mongrel::HttpServer + + + + + + + + + + +
+ + + + + + + + + + + + + + +
ClassMongrel::HttpServer
In: + + lib/mongrel.rb + +
+
Parent: + Object +
+
+ + +
+ + + +
+ +
+

+This is the main driver of Mongrel, while the +Mognrel::HttpParser and Mongrel::URIClassifier make up the majority +of how the server functions. It’s a very simple class that just has a +thread accepting connections and a simple HttpServer.process_client function to do +the heavy lifting with the IO and Ruby. +

+

+*NOTE:* The process_client function +used threads at one time but that proved to have stability issues on Mac +OSX. Actually, Ruby in general has stability issues on Mac OSX. +

+

+You use it by doing the following: +

+
+  server = HttpServer.new("0.0.0.0", 3000)
+  server.register("/stuff", MyNifterHandler.new)
+  server.run.join
+
+

+The last line can be just server.run if you don’t want to join the +thread used. If you don’t though Ruby will mysteriously just exit on +you. +

+ +
+ + +
+ +
+

Methods

+ +
+ new   + process_client   + register   + run   + unregister   +
+
+ +
+ + + + +
+ + +
+

Constants

+ +
+ + + + + + + + + + + + + + + +
ERROR_404_RESPONSE="HTTP/1.1 404 Not Found\r\nConnection: close\r\nContent-Type: text/plain\r\nServer: Mongrel/0.1\r\n\r\n"  +The standard empty 404 response for bad requests. Use Error4040Handler for +custom stuff. + +
CHUNK_SIZE=2048  +For now we just read 2k chunks. Not optimal at all. + +
+
+
+ + + +
+

Attributes

+ +
+ + + + + + +
acceptor [R] 
+
+
+ + + + +
+

Public Class methods

+ +
+ + + + +
+

+Creates a working server on host:port (strange things happen if port +isn’t a Number). Use HttpServer::run to start the server. +

+
+
+ +

Public Instance methods

+ +
+ + + + +
+

+Used internally to process an accepted client. It uses HttpParser and URIClassifier (in ext/http11/http11.c) to do +the heavy work, and mostly just does a hack job at some simple IO. Future +releases will target this area mostly. +

+
+
+ +
+ + + + +
+

+Simply registers a handler with the internal URIClassifier. When the URI is found in the +prefix of a request then your handler’s HttpHandler::process method +is called. See Mongrel::URIClassifier#register for +more information. +

+
+
+ +
+ + + + +
+

+Runs the thing. It returns the thread used so you can "join" it. +You can also access the HttpServer::acceptor attribute to get the thread +later. +

+
+
+ +
+ + + + +
+

+Removes any handler registered at the given URI. See Mongrel::URIClassifier#unregister for +more information. +

+
+
+ + +
+ + +
+ + + + + + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/HttpServer.src/M000008.html b/doc/rdoc/classes/Mongrel/HttpServer.src/M000008.html new file mode 100644 index 0000000..d5b5591 --- /dev/null +++ b/doc/rdoc/classes/Mongrel/HttpServer.src/M000008.html @@ -0,0 +1,19 @@ + + + + + + new (Mongrel::HttpServer) + + + + +
     # File lib/mongrel.rb, line 114
+114:     def initialize(host, port)
+115:       @socket = TCPServer.new(host, port)
+116:       @classifier = URIClassifier.new
+117:     end
+ + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/HttpServer.src/M000009.html b/doc/rdoc/classes/Mongrel/HttpServer.src/M000009.html new file mode 100644 index 0000000..5181e70 --- /dev/null +++ b/doc/rdoc/classes/Mongrel/HttpServer.src/M000009.html @@ -0,0 +1,59 @@ + + + + + + process_client (Mongrel::HttpServer) + + + + +
     # File lib/mongrel.rb, line 122
+122:     def process_client(client)
+123:       begin
+124:         parser = HttpParser.new
+125:         params = {}
+126:         data = ""
+127:         
+128:         while true
+129:           data << client.readpartial(CHUNK_SIZE)
+130:           
+131:           nread = parser.execute(params, data)
+132:           
+133:           if parser.error?
+134:             STDERR.puts "parser error:"
+135:             STDERR.puts data
+136:             break
+137:           elsif parser.finished?
+138:             script_name, path_info, handler = @classifier.resolve(params["PATH_INFO"])
+139:             
+140:             if handler
+141:               params['PATH_INFO'] = path_info
+142:               params['SCRIPT_NAME'] = script_name
+143:               
+144:               request = HttpRequest.new(params, data[nread ... data.length], client)
+145:               response = HttpResponse.new(client)
+146:               
+147:               handler.process(request, response)
+148:             else
+149:               client.write(ERROR_404_RESPONSE)
+150:             end
+151:             
+152:             break
+153:           else
+154:             # gotta stream and read again until we can get the parser to be character safe
+155:             # TODO: make this more efficient since this means we're parsing a lot repeatedly
+156:             parser.reset
+157:           end
+158:         end
+159:       rescue => details
+160:         STDERR.puts "ERROR: #{details}"
+161:         STDERR.puts details.backtrace.join("\n")
+162:       ensure
+163:         client.close
+164:       end
+165:     end
+ + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/HttpServer.src/M000010.html b/doc/rdoc/classes/Mongrel/HttpServer.src/M000010.html new file mode 100644 index 0000000..c79c3e3 --- /dev/null +++ b/doc/rdoc/classes/Mongrel/HttpServer.src/M000010.html @@ -0,0 +1,22 @@ + + + + + + run (Mongrel::HttpServer) + + + + +
     # File lib/mongrel.rb, line 169
+169:     def run
+170:       @acceptor = Thread.new do
+171:         while true
+172:           process_client(@socket.accept)
+173:         end
+174:       end
+175:     end
+ + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/HttpServer.src/M000011.html b/doc/rdoc/classes/Mongrel/HttpServer.src/M000011.html new file mode 100644 index 0000000..7273b5d --- /dev/null +++ b/doc/rdoc/classes/Mongrel/HttpServer.src/M000011.html @@ -0,0 +1,18 @@ + + + + + + register (Mongrel::HttpServer) + + + + +
     # File lib/mongrel.rb, line 181
+181:     def register(uri, handler)
+182:       @classifier.register(uri, handler)
+183:     end
+ + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/HttpServer.src/M000012.html b/doc/rdoc/classes/Mongrel/HttpServer.src/M000012.html new file mode 100644 index 0000000..1b8587c --- /dev/null +++ b/doc/rdoc/classes/Mongrel/HttpServer.src/M000012.html @@ -0,0 +1,18 @@ + + + + + + unregister (Mongrel::HttpServer) + + + + +
     # File lib/mongrel.rb, line 187
+187:     def unregister(uri)
+188:       @classifier.unregister(uri)
+189:     end
+ + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/URIClassifier.html b/doc/rdoc/classes/Mongrel/URIClassifier.html new file mode 100644 index 0000000..4708416 --- /dev/null +++ b/doc/rdoc/classes/Mongrel/URIClassifier.html @@ -0,0 +1,257 @@ + + + + + + Class: Mongrel::URIClassifier + + + + + + + + + + +
+ + + + + + + + + + + + + + +
ClassMongrel::URIClassifier
In: + + ext/http11/http11.c + +
+
Parent: + Object +
+
+ + +
+ + + +
+ + + +
+ +
+

Methods

+ +
+ new   + register   + resolve   + unregister   +
+
+ +
+ + + + +
+ + + + + + + + + +
+

Public Class methods

+ +
+ + + + +
+

+Initializes a new URIClassifier object +that you can use to associate URI sequences with objects. You can actually +use it with any string sequence and any objects, but it’s mostly used +with URIs. +

+

+It uses TST from www.octavian.org/cs/software.html +to build an ternary search trie to hold all of the URIs. It uses this to do +an initial search for the a URI prefix, and then to break the URI into +SCRIPT_NAME and PATH_INFO portions. It actually will do two searches most +of the time in order to find the right handler for the registered prefix +portion. +

+

+Here’s how it all works. Let’s say you register +"/blog" with a BlogHandler. Great. Now, someone goes to +"/blog/zedsucks/ass". You want SCRIPT_NAME to be +"/blog" and PATH_INFO to be "/zedsucks/ass". URIClassifier first does a TST search and +comes up with a failure, but knows that the failure ended at the +"/blog" part. So, that’s the SCRIPT_NAME. It then tries a +second search for just "/blog". If that comes back good then it +sets the rest ("/zedsucks/ass") to the PATH_INFO and returns the +BlogHandler. +

+

+The optimal approach would be to not do the search twice, but the TST lib +doesn’t really support returning prefixes. Might not be hard to add +later. +

+

+The key though is that it will try to match the longest match it +can. If you also register "/blog/zed" then the above URI will +give SCRIPT_NAME="/blog/zed", PATH_INFO="sucks/ass". +Probably not what you want, so your handler will need to do the 404 thing. +

+

+Take a look at the postamble of example/tepee.rb to see how this is handled +for Camping. +

+
+
+ +

Public Instance methods

+ +
+ + + + +
+

+Registers the SampleHandler (one for all requests) with the +"/someuri". When URIClassifier::resolve is called with +"/someuri" it’ll return SampleHandler immediately. When +"/someuri/pathhere" is called it’ll find SomeHandler after +a second search, and setup PATH_INFO="/pathhere". +

+

+You actually can reuse this class to register nearly anything and quickly +resolve it. This could be used for caching, fast mapping, etc. The downside +is it uses much more memory than a Hash, but it can be a lot faster. +It’s main advantage is that it works on prefixes, which is damn hard +to get right with a Hash. +

+
+
+ +
+ + + + +
+

+Attempts to resolve either the whole URI or at the longest prefix, +returning the prefix (as script_info), path (as path_info), and registered +handler (usually an HttpHandler). +

+

+It expects strings. Don‘t try other string-line stuff yet. +

+
+
+ +
+ + + + +
+

+Yep, just removes this uri and it’s handler from the trie. +

+
+
+ + +
+ + +
+ + + + + + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/URIClassifier.src/M000013.html b/doc/rdoc/classes/Mongrel/URIClassifier.src/M000013.html new file mode 100644 index 0000000..a843bc8 --- /dev/null +++ b/doc/rdoc/classes/Mongrel/URIClassifier.src/M000013.html @@ -0,0 +1,54 @@ + + + + + + new (Mongrel::URIClassifier) + + + + +
/**
+ * call-seq:
+ *    URIClassifier.new -> URIClassifier
+ *
+ * Initializes a new URIClassifier object that you can use to associate URI sequences
+ * with objects.  You can actually use it with any string sequence and any objects,
+ * but it's mostly used with URIs.
+ *
+ * It uses TST from http://www.octavian.org/cs/software.html to build an ternary search
+ * trie to hold all of the URIs.  It uses this to do an initial search for the a URI
+ * prefix, and then to break the URI into SCRIPT_NAME and PATH_INFO portions.  It actually
+ * will do two searches most of the time in order to find the right handler for the
+ * registered prefix portion.
+ *
+ * Here's how it all works.  Let's say you register "/blog" with a BlogHandler.  Great.
+ * Now, someone goes to "/blog/zedsucks/ass".  You want SCRIPT_NAME to be "/blog" and
+ * PATH_INFO to be "/zedsucks/ass".  URIClassifier first does a TST search and comes
+ * up with a failure, but knows that the failure ended at the "/blog" part.  So, that's
+ * the SCRIPT_NAME.  It then tries a second search for just "/blog".  If that comes back
+ * good then it sets the rest ("/zedsucks/ass") to the PATH_INFO and returns the BlogHandler.
+ *
+ * The optimal approach would be to not do the search twice, but the TST lib doesn't
+ * really support returning prefixes.  Might not be hard to add later.
+ *
+ * The key though is that it will try to match the *longest* match it can.  If you 
+ * also register "/blog/zed" then the above URI will give SCRIPT_NAME="/blog/zed", 
+ * PATH_INFO="sucks/ass".  Probably not what you want, so your handler will need to
+ * do the 404 thing.
+ *
+ * Take a look at the postamble of example/tepee.rb to see how this is handled for
+ * Camping. 
+ */
+VALUE URIClassifier_init(VALUE self)
+{
+  VALUE hash;
+
+  // we create an internal hash to protect stuff from the GC
+  hash = rb_hash_new();
+  rb_iv_set(self, "handler_map", hash);
+}
+ + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/URIClassifier.src/M000014.html b/doc/rdoc/classes/Mongrel/URIClassifier.src/M000014.html new file mode 100644 index 0000000..5055109 --- /dev/null +++ b/doc/rdoc/classes/Mongrel/URIClassifier.src/M000014.html @@ -0,0 +1,50 @@ + + + + + + register (Mongrel::URIClassifier) + + + + +
/**
+ * call-seq:
+ *    uc.register("/someuri", SampleHandler.new) -> nil
+ *
+ * Registers the SampleHandler (one for all requests) with the "/someuri".
+ * When URIClassifier::resolve is called with "/someuri" it'll return
+ * SampleHandler immediately.  When "/someuri/pathhere" is called it'll
+ * find SomeHandler after a second search, and setup PATH_INFO="/pathhere".
+ *
+ * You actually can reuse this class to register nearly anything and 
+ * quickly resolve it.  This could be used for caching, fast mapping, etc.
+ * The downside is it uses much more memory than a Hash, but it can be
+ * a lot faster.  It's main advantage is that it works on prefixes, which
+ * is damn hard to get right with a Hash.
+ */
+VALUE URIClassifier_register(VALUE self, VALUE uri, VALUE handler)
+{
+  int rc = 0;
+  void *ptr = NULL;
+  struct tst *tst = NULL;
+  DATA_GET(self, struct tst, tst);
+
+  rc = tst_insert((unsigned char *)StringValueCStr(uri), (void *)handler , tst, 0, &ptr);
+
+  if(rc == TST_DUPLICATE_KEY) {
+    rb_raise(rb_eStandardError, "Handler already registered with that name");
+  } else if(rc == TST_ERROR) {
+    rb_raise(rb_eStandardError, "Memory error registering handler");
+  } else if(rc == TST_NULL_KEY) {
+    rb_raise(rb_eStandardError, "URI was empty");
+  }
+  
+  rb_hash_aset(rb_iv_get(self, "handler_map"), uri, handler);
+
+  return Qnil;
+}
+ + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/URIClassifier.src/M000015.html b/doc/rdoc/classes/Mongrel/URIClassifier.src/M000015.html new file mode 100644 index 0000000..4fafe2b --- /dev/null +++ b/doc/rdoc/classes/Mongrel/URIClassifier.src/M000015.html @@ -0,0 +1,36 @@ + + + + + + unregister (Mongrel::URIClassifier) + + + + +
/**
+ * call-seq:
+ *    uc.unregister("/someuri")
+ *
+ * Yep, just removes this uri and it's handler from the trie.
+ */
+VALUE URIClassifier_unregister(VALUE self, VALUE uri)
+{
+  void *handler = NULL;
+  struct tst *tst = NULL;
+  DATA_GET(self, struct tst, tst);
+
+  handler = tst_delete((unsigned char *)StringValueCStr(uri), tst);
+
+  if(handler) {
+    rb_hash_delete(rb_iv_get(self, "handler_map"), uri);
+
+    return (VALUE)handler;
+  } else {
+    return Qnil;
+  }
+}
+ + \ No newline at end of file diff --git a/doc/rdoc/classes/Mongrel/URIClassifier.src/M000016.html b/doc/rdoc/classes/Mongrel/URIClassifier.src/M000016.html new file mode 100644 index 0000000..f545ea2 --- /dev/null +++ b/doc/rdoc/classes/Mongrel/URIClassifier.src/M000016.html @@ -0,0 +1,73 @@ + + + + + + resolve (Mongrel::URIClassifier) + + + + +
/**
+ * call-seq:
+ *    uc.resolve("/someuri") -> "/someuri", "", handler
+ *    uc.resolve("/someuri/pathinfo") -> "/someuri", "/pathinfo", handler
+ *    uc.resolve("/notfound/orhere") -> nil, nil, nil
+ *
+ * Attempts to resolve either the whole URI or at the longest prefix, returning
+ * the prefix (as script_info), path (as path_info), and registered handler
+ * (usually an HttpHandler).
+ *
+ * It expects strings.  Don't try other string-line stuff yet.
+ */
+VALUE URIClassifier_resolve(VALUE self, VALUE uri)
+{
+  void *handler = NULL;
+  int pref_len = 0;
+  struct tst *tst = NULL;
+  VALUE result;
+  VALUE script_name;
+  VALUE path_info;
+  unsigned char *uri_str = NULL;
+  unsigned char *script_name_str = NULL;
+
+  DATA_GET(self, struct tst, tst);
+  uri_str = (unsigned char *)StringValueCStr(uri);
+
+  handler = tst_search(uri_str, tst, &pref_len);
+
+  // setup for multiple return values
+  result = rb_ary_new();
+
+
+  if(handler == NULL) {
+    script_name = rb_str_substr (uri, 0, pref_len);
+    script_name_str = (unsigned char *)StringValueCStr(script_name);
+
+    handler = tst_search(script_name_str, tst, NULL);
+
+    if(handler == NULL) {
+      // didn't find the script name at all
+      rb_ary_push(result, Qnil);
+      rb_ary_push(result, Qnil);
+      rb_ary_push(result, Qnil);
+      return result;
+    } else {
+      // found a handler, setup the path info and we're good
+      path_info = rb_str_substr(uri, pref_len, RSTRING(uri)->len);
+    }
+  } else {
+    // whole thing was found, so uri is the script name, path info empty
+    script_name = uri;
+    path_info = rb_str_new2("");
+  }
+
+  rb_ary_push(result, script_name);
+  rb_ary_push(result, path_info);
+  rb_ary_push(result, (VALUE)handler);
+  return result;
+}
+ + \ No newline at end of file diff --git a/doc/rdoc/created.rid b/doc/rdoc/created.rid new file mode 100644 index 0000000..65487cc --- /dev/null +++ b/doc/rdoc/created.rid @@ -0,0 +1 @@ +Thu Jan 26 01:27:35 EST 2006 diff --git a/doc/rdoc/files/COPYING.html b/doc/rdoc/files/COPYING.html new file mode 100644 index 0000000..9b91916 --- /dev/null +++ b/doc/rdoc/files/COPYING.html @@ -0,0 +1,756 @@ + + + + + + File: COPYING + + + + + + + + + + +
+

COPYING

+ + + + + + + + + +
Path:COPYING +
Last Update:Mon Jan 16 11:34:01 EST 2006
+
+ + +
+ + + +
+ +
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  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
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+
+

+possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). +

+
+  To apply these terms, attach the following notices to the library.  It is
+
+

+safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. +

+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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.
+
+    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+

+Also add information on how to contact you by electronic and paper mail. +

+

+You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: +

+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+

+That’s all there is to it! +

+ +
+ + +
+ + +
+ + + + +
+ + + + + + + + + + + +
+ + + + + + \ No newline at end of file diff --git a/doc/rdoc/files/LICENSE.html b/doc/rdoc/files/LICENSE.html new file mode 100644 index 0000000..b44feb5 --- /dev/null +++ b/doc/rdoc/files/LICENSE.html @@ -0,0 +1,756 @@ + + + + + + File: LICENSE + + + + + + + + + + +
+

LICENSE

+ + + + + + + + + +
Path:LICENSE +
Last Update:Mon Jan 16 11:34:01 EST 2006
+
+ + +
+ + + +
+ +
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  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
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+
+

+possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). +

+
+  To apply these terms, attach the following notices to the library.  It is
+
+

+safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. +

+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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.
+
+    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+

+Also add information on how to contact you by electronic and paper mail. +

+

+You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: +

+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+

+That’s all there is to it! +

+ +
+ + +
+ + +
+ + + + +
+ + + + + + + + + + + +
+ + + + + + \ No newline at end of file diff --git a/doc/rdoc/files/README.html b/doc/rdoc/files/README.html new file mode 100644 index 0000000..9a4fb64 --- /dev/null +++ b/doc/rdoc/files/README.html @@ -0,0 +1,170 @@ + + + + + + File: README + + + + + + + + + + +
+

README

+ + + + + + + + + +
Path:README +
Last Update:Thu Jan 26 01:27:16 EST 2006
+
+ + +
+ + + +
+ +
+

Mongrel: Simple Fast Mostly Ruby Web Server

+

+Mongrel is a small library that +provides a very fast HTTP 1.1 server for Ruby web applications. It is not +particular to any framework, and is intended to be just enough to get a web +application running behind a more complete and robust web server. +

+

+What makes Mongrel so fast is the +careful use of a C extension to provide fast HTTP 1.1 protocol parsing and +fast URI lookup. This combination makes the server very fast without too +many portability issues. +

+

Status

+

+Mongrel is still very ALPHA work, but +you can see how it’s used with the Camping framework (version 1.2) +and take a look at how you might use it. Right now it handles HTTP requests +well and process the responses fast, but you have to "roll your +own" response code. +

+

+The next release of Mongrel will have +improved IO handling, much more stability, and should have a better Mongrel::HttpResponse +object with more useful features. +

+

Install

+

+You can install it via source from www.zedshaw.com/downloads/mongrel/ +or you can gram a RubyGem at www.zedshaw.com/downloads/mongrel/ +and install that manually. I’m working on setting up a RubyForge +project. +

+

+It doesn’t explicitly require Camping, but if you want to run the +examples/tepee.rb example then you’ll need to install Camping 1.2 at +least (and redcloth I think). These are all available from RubyGems. +

+

+The library consists of a C extension so you’ll need a C compiler or +at least a friend who can build it for you. +

+

+Finally, the source include a setup.rb for those who hate RubyGems. +

+

Usage

+

+Best place to look for usage examples right now is the examples/ directory. +

+

Speed

+

+This 0.1.2 release will not be as fast as the 0.1.1 release since +I’ve temporarily removed threads as a test. There were many stability +issues related to handling each request in a thread, especially on OSX. +I’ve taken them out for now to make things stable. Even with this +removed Mongrel is still pretty fast +compared to WEBrick. +

+

Contact

+

+E-mail zedshaw at zedshaw.com and I’ll help. Comments about the API +are welcome. +

+ +
+ + +
+ + +
+ + + + +
+ + + + + + + + + + + +
+ + + + + + \ No newline at end of file diff --git a/doc/rdoc/files/ext/http11/http11_c.html b/doc/rdoc/files/ext/http11/http11_c.html new file mode 100644 index 0000000..b46289f --- /dev/null +++ b/doc/rdoc/files/ext/http11/http11_c.html @@ -0,0 +1,101 @@ + + + + + + File: http11.c + + + + + + + + + + +
+

http11.c

+ + + + + + + + + +
Path:ext/http11/http11.c +
Last Update:Thu Jan 26 00:41:25 EST 2006
+
+ + +
+ + + +
+ + + +
+ + +
+ + + + +
+ + + + + + + + + + + +
+ + + + + + \ No newline at end of file diff --git a/doc/rdoc/files/lib/mongrel_rb.html b/doc/rdoc/files/lib/mongrel_rb.html new file mode 100644 index 0000000..2c7ccb0 --- /dev/null +++ b/doc/rdoc/files/lib/mongrel_rb.html @@ -0,0 +1,110 @@ + + + + + + File: mongrel.rb + + + + + + + + + + +
+

mongrel.rb

+ + + + + + + + + +
Path:lib/mongrel.rb +
Last Update:Thu Jan 26 01:10:22 EST 2006
+
+ + +
+ + + +
+ + +
+

Required files

+ +
+ socket   + http11   + thread   +
+
+ +
+ + +
+ + + + +
+ + + + + + + + + + + +
+ + + + + + \ No newline at end of file diff --git a/doc/rdoc/fr_class_index.html b/doc/rdoc/fr_class_index.html new file mode 100644 index 0000000..ba4bb59 --- /dev/null +++ b/doc/rdoc/fr_class_index.html @@ -0,0 +1,34 @@ + + + + + + + + Classes + + + + + + + + \ No newline at end of file diff --git a/doc/rdoc/fr_file_index.html b/doc/rdoc/fr_file_index.html new file mode 100644 index 0000000..83d0cd2 --- /dev/null +++ b/doc/rdoc/fr_file_index.html @@ -0,0 +1,31 @@ + + + + + + + + Files + + + + + + + + \ No newline at end of file diff --git a/doc/rdoc/fr_method_index.html b/doc/rdoc/fr_method_index.html new file mode 100644 index 0000000..c11dc96 --- /dev/null +++ b/doc/rdoc/fr_method_index.html @@ -0,0 +1,47 @@ + + + + + + + + Methods + + + + + + + + \ No newline at end of file diff --git a/doc/rdoc/index.html b/doc/rdoc/index.html new file mode 100644 index 0000000..fa5d583 --- /dev/null +++ b/doc/rdoc/index.html @@ -0,0 +1,24 @@ + + + + + + + RDoc Documentation + + + + + + + + + + + \ No newline at end of file diff --git a/doc/rdoc/rdoc-style.css b/doc/rdoc/rdoc-style.css new file mode 100644 index 0000000..44c7b3d --- /dev/null +++ b/doc/rdoc/rdoc-style.css @@ -0,0 +1,208 @@ + +body { + font-family: Verdana,Arial,Helvetica,sans-serif; + font-size: 90%; + margin: 0; + margin-left: 40px; + padding: 0; + background: white; +} + +h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; } +h1 { font-size: 150%; } +h2,h3,h4 { margin-top: 1em; } + +a { background: #eef; color: #039; text-decoration: none; } +a:hover { background: #039; color: #eef; } + +/* Override the base stylesheet's Anchor inside a table cell */ +td > a { + background: transparent; + color: #039; + text-decoration: none; +} + +/* and inside a section title */ +.section-title > a { + background: transparent; + color: #eee; + text-decoration: none; +} + +/* === Structural elements =================================== */ + +div#index { + margin: 0; + margin-left: -40px; + padding: 0; + font-size: 90%; +} + + +div#index a { + margin-left: 0.7em; +} + +div#index .section-bar { + margin-left: 0px; + padding-left: 0.7em; + background: #ccc; + font-size: small; +} + + +div#classHeader, div#fileHeader { + width: auto; + color: white; + padding: 0.5em 1.5em 0.5em 1.5em; + margin: 0; + margin-left: -40px; + border-bottom: 3px solid #006; +} + +div#classHeader a, div#fileHeader a { + background: inherit; + color: white; +} + +div#classHeader td, div#fileHeader td { + background: inherit; + color: white; +} + + +div#fileHeader { + background: #057; +} + +div#classHeader { + background: #048; +} + + +.class-name-in-header { + font-size: 180%; + font-weight: bold; +} + + +div#bodyContent { + padding: 0 1.5em 0 1.5em; +} + +div#description { + padding: 0.5em 1.5em; + background: #efefef; + border: 1px dotted #999; +} + +div#description h1,h2,h3,h4,h5,h6 { + color: #125;; + background: transparent; +} + +div#validator-badges { + text-align: center; +} +div#validator-badges img { border: 0; } + +div#copyright { + color: #333; + background: #efefef; + font: 0.75em sans-serif; + margin-top: 5em; + margin-bottom: 0; + padding: 0.5em 2em; +} + + +/* === Classes =================================== */ + +table.header-table { + color: white; + font-size: small; +} + +.type-note { + font-size: small; + color: #DEDEDE; +} + +.xxsection-bar { + background: #eee; + color: #333; + padding: 3px; +} + +.section-bar { + color: #333; + border-bottom: 1px solid #999; + margin-left: -20px; +} + + +.section-title { + background: #79a; + color: #eee; + padding: 3px; + margin-top: 2em; + margin-left: -30px; + border: 1px solid #999; +} + +.top-aligned-row { vertical-align: top } +.bottom-aligned-row { vertical-align: bottom } + +/* --- Context section classes ----------------------- */ + +.context-row { } +.context-item-name { font-family: monospace; font-weight: bold; color: black; } +.context-item-value { font-size: small; color: #448; } +.context-item-desc { color: #333; padding-left: 2em; } + +/* --- Method classes -------------------------- */ +.method-detail { + background: #efefef; + padding: 0; + margin-top: 0.5em; + margin-bottom: 1em; + border: 1px dotted #ccc; +} +.method-heading { + color: black; + background: #ccc; + border-bottom: 1px solid #666; + padding: 0.2em 0.5em 0 0.5em; +} +.method-signature { color: black; background: inherit; } +.method-name { font-weight: bold; } +.method-args { font-style: italic; } +.method-description { padding: 0 0.5em 0 0.5em; } + +/* --- Source code sections -------------------- */ + +a.source-toggle { font-size: 90%; } +div.method-source-code { + background: #262626; + color: #ffdead; + margin: 1em; + padding: 0.5em; + border: 1px dashed #999; + overflow: hidden; +} + +div.method-source-code pre { color: #ffdead; overflow: hidden; } + +/* --- Ruby keyword styles --------------------- */ + +.standalone-code { background: #221111; color: #ffdead; overflow: hidden; } + +.ruby-constant { color: #7fffd4; background: transparent; } +.ruby-keyword { color: #00ffff; background: transparent; } +.ruby-ivar { color: #eedd82; background: transparent; } +.ruby-operator { color: #00ffee; background: transparent; } +.ruby-identifier { color: #ffdead; background: transparent; } +.ruby-node { color: #ffa07a; background: transparent; } +.ruby-comment { color: #b22222; font-weight: bold; background: transparent; } +.ruby-regexp { color: #ffa07a; background: transparent; } +.ruby-value { color: #7fffd4; background: transparent; } \ No newline at end of file diff --git a/examples/simpletest.rb b/examples/simpletest.rb new file mode 100644 index 0000000..c05a745 --- /dev/null +++ b/examples/simpletest.rb @@ -0,0 +1,15 @@ +require 'mongrel' +require 'yaml' + +class SimpleHandler < Mongrel::HttpHandler + + def process(request, response) + response.socket.write("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nhello!\n") + end + +end + +h = Mongrel::HttpServer.new("0.0.0.0", "3000") +h.register("/test", SimpleHandler.new) +h.run.join + diff --git a/examples/tepee.rb b/examples/tepee.rb new file mode 100644 index 0000000..8b45f88 --- /dev/null +++ b/examples/tepee.rb @@ -0,0 +1,178 @@ +#!/usr/bin/ruby +$:.unshift File.dirname(__FILE__) + "/../../lib" +%w(rubygems redcloth camping acts_as_versioned).each { |lib| require lib } + +Camping.goes :Tepee + +module Tepee::Models + def self.schema(&block) + @@schema = block if block_given? + @@schema + end + + class Page < Base + PAGE_LINK = /\[\[([^\]|]*)[|]?([^\]]*)\]\]/ + validates_uniqueness_of :title + before_save { |r| r.title = r.title.underscore } + acts_as_versioned + end +end + +Tepee::Models.schema do + create_table :pages, :force => true do |t| + t.column :title, :string, :limit => 255 + t.column :body, :text + end + Tepee::Models::Page.create_versioned_table +end + +module Tepee::Controllers + class Index < R '/' + def get + redirect Show, 'home_page' + end + end + + class List < R '/list' + def get + @pages = Page.find :all, :order => 'title' + render :list + end + end + + class Show < R '/s/(\w+)', '/s/(\w+)/(\d+)' + def get page_name, version = nil + redirect(Edit, page_name, 1) and return unless @page = Page.find_by_title(page_name) + @version = (version.nil? or version == @page.version.to_s) ? @page : @page.versions.find_by_version(version) + render :show + end + end + + class Edit < R '/e/(\w+)/(\d+)', '/e/(\w+)' + def get page_name, version = nil + @page = Page.find_or_create_by_title(page_name) + @page = @page.versions.find_by_version(version) unless version.nil? or version == @page.version.to_s + render :edit + end + + def post page_name + Page.find_or_create_by_title(page_name).update_attributes :body => input.post_body and redirect Show, page_name + end + end +end + +module Tepee::Views + def layout + html do + head do + title 'test' + end + body do + p do + small do + span "welcome to " ; a 'tepee', :href => "http://code.whytheluckystiff.net/svn/camping/trunk/examples/tepee/" + span '. go ' ; a 'home', :href => R(Show, 'home_page') + span '. list all ' ; a 'pages', :href => R(List) + end + end + div.content do + self << yield + end + end + end + end + + def show + h1 @page.title + div { _markup @version.body } + p do + a 'edit', :href => R(Edit, @version.title, @version.version) + a 'back', :href => R(Show, @version.title, @version.version-1) unless @version.version == 1 + a 'next', :href => R(Show, @version.title, @version.version+1) unless @version.version == @page.version + a 'current', :href => R(Show, @version.title) unless @version.version == @page.version + end + end + + def edit + form :method => 'post', :action => R(Edit, @page.title) do + p do + label 'Body' ; br + textarea @page.body, :name => 'post_body', :rows => 50, :cols => 100 + end + + p do + input :type => 'submit' + a 'cancel', :href => R(Show, @page.title, @page.version) + end + end + end + + def list + h1 'all pages' + ul { @pages.each { |p| li { a p.title, :href => R(Show, p.title) } } } + end + + def _markup body + return '' if body.blank? + body.gsub!(Tepee::Models::Page::PAGE_LINK) do + page = title = $1.underscore + title = $2 unless $2.empty? + if Tepee::Models::Page.find(:all, :select => 'title').collect { |p| p.title }.include?(page) + %Q{#{title}} + else + %Q{#{title}?} + end + end + RedCloth.new(body, [ :hard_breaks ]).to_html + end +end + + +module Tepee + class << self + def mongrel_run(request, response) + req = StringIO.new(request.body) + status = 500 + + resp = "" + begin + klass, path = Controllers.D request.params["PATH_INFO"] + method = request.params['REQUEST_METHOD']||"GET" + klass.class_eval { include C; include Controllers::Base; include Models } + controller = klass.new + resp = controller.service(req, request.params, method, path) + status = controller.status + rescue => e + req.rewind + resp = Controllers::ServerError.new.service(req, request.params, "GET", [klass,method,e]) + end + + response.socket.write("HTTP/1.1 #{status} OK\r\n") + response.socket.write(resp) + end + end +end + +require 'thread' + +class CampingHandler < Mongrel::HttpHandler + def process(request, response) + Tepee.mongrel_run(request, response) + end +end + +if __FILE__ == $0 + $docroot = "/blog" + + db_exists = File.exists?('tepee.db') + Tepee::Models::Base.establish_connection :adapter => 'sqlite3', :database => 'tepee.db' + Tepee::Models::Base.logger = Logger.new('camping.log') + Tepee::Models::Base.threaded_connections=false + ActiveRecord::Schema.define(&Tepee::Models.schema) unless db_exists + + h = Mongrel::HttpServer.new("0.0.0.0", "3000") + h.register("/blog", CampingHandler.new) + h.register("/favicon.ico", Mongrel::Error404Handler.new("")) + h.run.join + +end diff --git a/examples/webrick_compare.rb b/examples/webrick_compare.rb new file mode 100644 index 0000000..15199b0 --- /dev/null +++ b/examples/webrick_compare.rb @@ -0,0 +1,20 @@ +#!/usr/local/bin/ruby +require 'webrick' +include WEBrick + +s = HTTPServer.new( :Port => 4000 ) + +# HTTPServer#mount(path, servletclass) +# When a request referring "/hello" is received, +# the HTTPServer get an instance of servletclass +# and then call a method named do_"a HTTP method". + +class HelloServlet < HTTPServlet::AbstractServlet + def do_GET(req, res) + res.body = "hello!" + res['Content-Type'] = "text/html" + end +end +s.mount("/test", HelloServlet) + +s.start \ No newline at end of file diff --git a/ext/http11/MANIFEST b/ext/http11/MANIFEST new file mode 100644 index 0000000..e69de29 diff --git a/ext/http11/ext_help.h b/ext/http11/ext_help.h new file mode 100644 index 0000000..8b4d754 --- /dev/null +++ b/ext/http11/ext_help.h @@ -0,0 +1,14 @@ +#ifndef ext_help_h +#define ext_help_h + +#define RAISE_NOT_NULL(T) if(T == NULL) rb_raise(rb_eArgError, "NULL found for " # T " when shouldn't be."); +#define DATA_GET(from,type,name) Data_Get_Struct(from,type,name); RAISE_NOT_NULL(name); +#define REQUIRE_TYPE(V, T) if(TYPE(V) != T) rb_raise(rb_eTypeError, "Wrong argument type for " # V " required " # T); + +#ifdef DEBUG +#define TRACE() fprintf(stderr, "> %s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__) +#else +#define TRACE() +#endif + +#endif diff --git a/ext/http11/extconf.rb b/ext/http11/extconf.rb new file mode 100644 index 0000000..e4f6918 --- /dev/null +++ b/ext/http11/extconf.rb @@ -0,0 +1,6 @@ +require 'mkmf' + +dir_config("http11") +have_library("c", "main") + +create_makefile("http11") diff --git a/ext/http11/http11.c b/ext/http11/http11.c new file mode 100644 index 0000000..3755d65 --- /dev/null +++ b/ext/http11/http11.c @@ -0,0 +1,429 @@ +#include "ruby.h" +#include "ext_help.h" +#include +#include +#include "http11_parser.h" +#include +#include "tst.h" + +static VALUE mMongrel; +static VALUE cHttpParser; +static VALUE cURIClassifier; + + +void http_field(void *data, const char *field, size_t flen, const char *value, size_t vlen) +{ + char *ch, *end; + VALUE req = (VALUE)data; + VALUE f = rb_str_new2("HTTP_"); + VALUE v = rb_str_new(value, vlen); + + rb_str_buf_cat(f, field, flen); + + for(ch = RSTRING(f)->ptr, end = ch + RSTRING(f)->len; ch < end; ch++) { + if(*ch == '-') { + *ch = '_'; + } else { + *ch = toupper(*ch); + } + } + + rb_hash_aset(req, f, v); +} + +void request_method(void *data, const char *at, size_t length) +{ + VALUE req = (VALUE)data; + VALUE val = rb_str_new(at, length); + VALUE id = rb_str_new2("REQUEST_METHOD"); + rb_hash_aset(req, id, val); +} + +void path_info(void *data, const char *at, size_t length) +{ + VALUE req = (VALUE)data; + VALUE val = rb_str_new(at, length); + VALUE id = rb_str_new2("PATH_INFO"); + rb_hash_aset(req, id, val); +} + + +void query_string(void *data, const char *at, size_t length) +{ + VALUE req = (VALUE)data; + VALUE val = rb_str_new(at, length); + VALUE id = rb_str_new2("QUERY_STRING"); + rb_hash_aset(req, id, val); +} + +void http_version(void *data, const char *at, size_t length) +{ + VALUE req = (VALUE)data; + VALUE val = rb_str_new(at, length); + VALUE id = rb_str_new2("HTTP_VERSION"); + rb_hash_aset(req, id, val); +} + + + + + +void HttpParser_free(void *data) { + TRACE(); + + if(data) { + free(data); + } +} + + +VALUE HttpParser_alloc(VALUE klass) +{ + TRACE(); + VALUE obj; + http_parser *hp = calloc(1, sizeof(http_parser)); + hp->http_field = http_field; + hp->request_method = request_method; + hp->path_info = path_info; + hp->query_string = query_string; + hp->http_version = http_version; + + obj = Data_Wrap_Struct(klass, NULL, HttpParser_free, hp); + + return obj; +} + + +/** + * call-seq: + * parser.new -> parser + * + * Creates a new parser. + */ +VALUE HttpParser_init(VALUE self) +{ + http_parser *http = NULL; + DATA_GET(self, http_parser, http); + http_parser_init(http); + + return self; +} + + +/** + * call-seq: + * parser.reset -> nil + * + * Resets the parser to it's initial state so that you can reuse it + * rather than making new ones. + */ +VALUE HttpParser_reset(VALUE self) +{ + http_parser *http = NULL; + DATA_GET(self, http_parser, http); + http_parser_init(http); + + return Qnil; +} + + +/** + * call-seq: + * parser.finish -> true/false + * + * Finishes a parser early which could put in a "good" or bad state. + * You should call reset after finish it or bad things will happen. + */ +VALUE HttpParser_finish(VALUE self) +{ + http_parser *http = NULL; + DATA_GET(self, http_parser, http); + http_parser_finish(http); + + return http_parser_is_finished(http) ? Qtrue : Qfalse; +} + + +/** + * call-seq: + * parser.execute(req_hash, data) -> Integer + * + * Takes a Hash and a String of data, parses the String of data filling in the Hash + * returning an Integer to indicate how much of the data has been read. No matter + * what the return value, you should call HttpParser#finished? and HttpParser#error? + * to figure out if it's done parsing or there was an error. + */ +VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data) +{ + http_parser *http = NULL; + DATA_GET(self, http_parser, http); + + http->data = (void *)req_hash; + http_parser_execute(http, RSTRING(data)->ptr, RSTRING(data)->len); + + return INT2FIX(http_parser_nread(http)); +} + + +/** + * call-seq: + * parser.error? -> true/false + * + * Tells you whether the parser is in an error state. + */ +VALUE HttpParser_has_error(VALUE self) +{ + http_parser *http = NULL; + DATA_GET(self, http_parser, http); + + return http_parser_has_error(http) ? Qtrue : Qfalse; +} + + +/** + * call-seq: + * parser.finished? -> true/false + * + * Tells you whether the parser is finished or not and in a good state. + */ +VALUE HttpParser_is_finished(VALUE self) +{ + http_parser *http = NULL; + DATA_GET(self, http_parser, http); + + return http_parser_is_finished(http) ? Qtrue : Qfalse; +} + + +/** + * call-seq: + * parser.nread -> Integer + * + * Returns the amount of data processed so far during this processing cycle. It is + * set to 0 on initialize or reset calls and is incremented each time execute is called. + */ +VALUE HttpParser_nread(VALUE self) +{ + http_parser *http = NULL; + DATA_GET(self, http_parser, http); + + return INT2FIX(http->nread); +} + + +void URIClassifier_free(void *data) +{ + TRACE(); + + if(data) { + tst_cleanup((struct tst *)data); + } +} + + +#define TRIE_INCREASE 30 + +VALUE URIClassifier_alloc(VALUE klass) +{ + TRACE(); + VALUE obj; + struct tst *tst = tst_init(TRIE_INCREASE); + assert(tst && "failed to initialize trie structure"); + + obj = Data_Wrap_Struct(klass, NULL, URIClassifier_free, tst); + + return obj; +} + +/** + * call-seq: + * URIClassifier.new -> URIClassifier + * + * Initializes a new URIClassifier object that you can use to associate URI sequences + * with objects. You can actually use it with any string sequence and any objects, + * but it's mostly used with URIs. + * + * It uses TST from http://www.octavian.org/cs/software.html to build an ternary search + * trie to hold all of the URIs. It uses this to do an initial search for the a URI + * prefix, and then to break the URI into SCRIPT_NAME and PATH_INFO portions. It actually + * will do two searches most of the time in order to find the right handler for the + * registered prefix portion. + * + * Here's how it all works. Let's say you register "/blog" with a BlogHandler. Great. + * Now, someone goes to "/blog/zedsucks/ass". You want SCRIPT_NAME to be "/blog" and + * PATH_INFO to be "/zedsucks/ass". URIClassifier first does a TST search and comes + * up with a failure, but knows that the failure ended at the "/blog" part. So, that's + * the SCRIPT_NAME. It then tries a second search for just "/blog". If that comes back + * good then it sets the rest ("/zedsucks/ass") to the PATH_INFO and returns the BlogHandler. + * + * The optimal approach would be to not do the search twice, but the TST lib doesn't + * really support returning prefixes. Might not be hard to add later. + * + * The key though is that it will try to match the *longest* match it can. If you + * also register "/blog/zed" then the above URI will give SCRIPT_NAME="/blog/zed", + * PATH_INFO="sucks/ass". Probably not what you want, so your handler will need to + * do the 404 thing. + * + * Take a look at the postamble of example/tepee.rb to see how this is handled for + * Camping. + */ +VALUE URIClassifier_init(VALUE self) +{ + VALUE hash; + + // we create an internal hash to protect stuff from the GC + hash = rb_hash_new(); + rb_iv_set(self, "handler_map", hash); +} + + +/** + * call-seq: + * uc.register("/someuri", SampleHandler.new) -> nil + * + * Registers the SampleHandler (one for all requests) with the "/someuri". + * When URIClassifier::resolve is called with "/someuri" it'll return + * SampleHandler immediately. When "/someuri/pathhere" is called it'll + * find SomeHandler after a second search, and setup PATH_INFO="/pathhere". + * + * You actually can reuse this class to register nearly anything and + * quickly resolve it. This could be used for caching, fast mapping, etc. + * The downside is it uses much more memory than a Hash, but it can be + * a lot faster. It's main advantage is that it works on prefixes, which + * is damn hard to get right with a Hash. + */ +VALUE URIClassifier_register(VALUE self, VALUE uri, VALUE handler) +{ + int rc = 0; + void *ptr = NULL; + struct tst *tst = NULL; + DATA_GET(self, struct tst, tst); + + rc = tst_insert((unsigned char *)StringValueCStr(uri), (void *)handler , tst, 0, &ptr); + + if(rc == TST_DUPLICATE_KEY) { + rb_raise(rb_eStandardError, "Handler already registered with that name"); + } else if(rc == TST_ERROR) { + rb_raise(rb_eStandardError, "Memory error registering handler"); + } else if(rc == TST_NULL_KEY) { + rb_raise(rb_eStandardError, "URI was empty"); + } + + rb_hash_aset(rb_iv_get(self, "handler_map"), uri, handler); + + return Qnil; +} + + +/** + * call-seq: + * uc.unregister("/someuri") + * + * Yep, just removes this uri and it's handler from the trie. + */ +VALUE URIClassifier_unregister(VALUE self, VALUE uri) +{ + void *handler = NULL; + struct tst *tst = NULL; + DATA_GET(self, struct tst, tst); + + handler = tst_delete((unsigned char *)StringValueCStr(uri), tst); + + if(handler) { + rb_hash_delete(rb_iv_get(self, "handler_map"), uri); + + return (VALUE)handler; + } else { + return Qnil; + } +} + + +/** + * call-seq: + * uc.resolve("/someuri") -> "/someuri", "", handler + * uc.resolve("/someuri/pathinfo") -> "/someuri", "/pathinfo", handler + * uc.resolve("/notfound/orhere") -> nil, nil, nil + * + * Attempts to resolve either the whole URI or at the longest prefix, returning + * the prefix (as script_info), path (as path_info), and registered handler + * (usually an HttpHandler). + * + * It expects strings. Don't try other string-line stuff yet. + */ +VALUE URIClassifier_resolve(VALUE self, VALUE uri) +{ + void *handler = NULL; + int pref_len = 0; + struct tst *tst = NULL; + VALUE result; + VALUE script_name; + VALUE path_info; + unsigned char *uri_str = NULL; + unsigned char *script_name_str = NULL; + + DATA_GET(self, struct tst, tst); + uri_str = (unsigned char *)StringValueCStr(uri); + + handler = tst_search(uri_str, tst, &pref_len); + + // setup for multiple return values + result = rb_ary_new(); + + + if(handler == NULL) { + script_name = rb_str_substr (uri, 0, pref_len); + script_name_str = (unsigned char *)StringValueCStr(script_name); + + handler = tst_search(script_name_str, tst, NULL); + + if(handler == NULL) { + // didn't find the script name at all + rb_ary_push(result, Qnil); + rb_ary_push(result, Qnil); + rb_ary_push(result, Qnil); + return result; + } else { + // found a handler, setup the path info and we're good + path_info = rb_str_substr(uri, pref_len, RSTRING(uri)->len); + } + } else { + // whole thing was found, so uri is the script name, path info empty + script_name = uri; + path_info = rb_str_new2(""); + } + + rb_ary_push(result, script_name); + rb_ary_push(result, path_info); + rb_ary_push(result, (VALUE)handler); + return result; +} + + + +void Init_http11() +{ + + TRACE(); + + mMongrel = rb_define_module("Mongrel"); + + cHttpParser = rb_define_class_under(mMongrel, "HttpParser", rb_cObject); + rb_define_alloc_func(cHttpParser, HttpParser_alloc); + rb_define_method(cHttpParser, "initialize", HttpParser_init,0); + rb_define_method(cHttpParser, "reset", HttpParser_reset,0); + rb_define_method(cHttpParser, "finish", HttpParser_finish,0); + rb_define_method(cHttpParser, "execute", HttpParser_execute,2); + rb_define_method(cHttpParser, "error?", HttpParser_has_error,0); + rb_define_method(cHttpParser, "finished?", HttpParser_is_finished,0); + rb_define_method(cHttpParser, "nread", HttpParser_nread,0); + + cURIClassifier = rb_define_class_under(mMongrel, "URIClassifier", rb_cObject); + rb_define_alloc_func(cURIClassifier, URIClassifier_alloc); + rb_define_method(cURIClassifier, "initialize", URIClassifier_init, 0); + rb_define_method(cURIClassifier, "register", URIClassifier_register, 2); + rb_define_method(cURIClassifier, "unregister", URIClassifier_unregister, 1); + rb_define_method(cURIClassifier, "resolve", URIClassifier_resolve, 1); +} + + diff --git a/ext/http11/http11_parser.c b/ext/http11/http11_parser.c new file mode 100644 index 0000000..c256037 --- /dev/null +++ b/ext/http11/http11_parser.c @@ -0,0 +1,918 @@ +#line 1 "ext/http11/http11_parser.rl" +#include "http11_parser.h" +#include +#include +#include +#include +#include + +#define MARK(S,F) assert((F) - (S)->mark >= 0); (S)->mark = (F); + +/** machine **/ +#line 100 "ext/http11/http11_parser.rl" + + +/** Data **/ + +#line 18 "ext/http11/http11_parser.c" +static int http_parser_start = 0; + +static int http_parser_first_final = 56; + +static int http_parser_error = 1; + +#line 104 "ext/http11/http11_parser.rl" + +int http_parser_init(http_parser *parser) { + int cs = 0; + +#line 30 "ext/http11/http11_parser.c" + { + cs = http_parser_start; + } +#line 108 "ext/http11/http11_parser.rl" + parser->cs = cs; + parser->body_start = NULL; + parser->content_len = 0; + parser->mark = NULL; + parser->nread = 0; + + return(1); +} + + +/** exec **/ +size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len) { + const char *p, *pe; + int cs = parser->cs; + + p = buffer; + pe = buffer+len; + + +#line 54 "ext/http11/http11_parser.c" + { + p -= 1; + if ( ++p == pe ) + goto _out; + switch ( cs ) + { +case 0: + switch( (*p) ) { + case 68: goto tr13; + case 71: goto tr14; + case 72: goto tr15; + case 79: goto tr16; + case 80: goto tr17; + case 84: goto tr18; + } + goto st1; +st1: + goto _out1; +tr13: +#line 14 "ext/http11/http11_parser.rl" + { MARK(parser, p); } + goto st2; +st2: + if ( ++p == pe ) + goto _out2; +case 2: +#line 81 "ext/http11/http11_parser.c" + if ( (*p) == 69 ) + goto st3; + goto st1; +st3: + if ( ++p == pe ) + goto _out3; +case 3: + if ( (*p) == 76 ) + goto st4; + goto st1; +st4: + if ( ++p == pe ) + goto _out4; +case 4: + if ( (*p) == 69 ) + goto st5; + goto st1; +st5: + if ( ++p == pe ) + goto _out5; +case 5: + if ( (*p) == 84 ) + goto st6; + goto st1; +st6: + if ( ++p == pe ) + goto _out6; +case 6: + if ( (*p) == 69 ) + goto st7; + goto st1; +st7: + if ( ++p == pe ) + goto _out7; +case 7: + if ( (*p) == 32 ) + goto tr33; + goto st1; +tr33: +#line 29 "ext/http11/http11_parser.rl" + { + if(parser->request_method != NULL) + parser->request_method(parser->data, parser->mark, p - parser->mark); + } + goto st8; +st8: + if ( ++p == pe ) + goto _out8; +case 8: +#line 131 "ext/http11/http11_parser.c" + switch( (*p) ) { + case 42: goto tr27; + case 43: goto tr28; + case 47: goto tr29; + case 58: goto tr30; + } + if ( (*p) < 65 ) { + if ( 45 <= (*p) && (*p) <= 57 ) + goto tr28; + } else if ( (*p) > 90 ) { + if ( 97 <= (*p) && (*p) <= 122 ) + goto tr28; + } else + goto tr28; + goto st1; +tr27: +#line 14 "ext/http11/http11_parser.rl" + { MARK(parser, p); } + goto st9; +st9: + if ( ++p == pe ) + goto _out9; +case 9: +#line 155 "ext/http11/http11_parser.c" + if ( (*p) == 32 ) + goto tr34; + goto st1; +tr34: +#line 33 "ext/http11/http11_parser.rl" + { + if(parser->path_info != NULL) + parser->path_info(parser->data, parser->mark, p - parser->mark); + } + goto st10; +tr48: +#line 37 "ext/http11/http11_parser.rl" + { + if(parser->query_string != NULL) + parser->query_string(parser->data, parser->mark, p - parser->mark); + } + goto st10; +st10: + if ( ++p == pe ) + goto _out10; +case 10: +#line 177 "ext/http11/http11_parser.c" + if ( (*p) == 72 ) + goto tr11; + goto st1; +tr11: +#line 14 "ext/http11/http11_parser.rl" + { MARK(parser, p); } + goto st11; +st11: + if ( ++p == pe ) + goto _out11; +case 11: +#line 189 "ext/http11/http11_parser.c" + if ( (*p) == 84 ) + goto st12; + goto st1; +st12: + if ( ++p == pe ) + goto _out12; +case 12: + if ( (*p) == 84 ) + goto st13; + goto st1; +st13: + if ( ++p == pe ) + goto _out13; +case 13: + if ( (*p) == 80 ) + goto st14; + goto st1; +st14: + if ( ++p == pe ) + goto _out14; +case 14: + if ( (*p) == 47 ) + goto st15; + goto st1; +st15: + if ( ++p == pe ) + goto _out15; +case 15: + if ( 48 <= (*p) && (*p) <= 57 ) + goto st16; + goto st1; +st16: + if ( ++p == pe ) + goto _out16; +case 16: + if ( (*p) == 46 ) + goto st17; + if ( 48 <= (*p) && (*p) <= 57 ) + goto st16; + goto st1; +st17: + if ( ++p == pe ) + goto _out17; +case 17: + if ( 48 <= (*p) && (*p) <= 57 ) + goto st18; + goto st1; +st18: + if ( ++p == pe ) + goto _out18; +case 18: + if ( (*p) == 13 ) + goto tr37; + if ( 48 <= (*p) && (*p) <= 57 ) + goto st18; + goto st1; +tr37: +#line 42 "ext/http11/http11_parser.rl" + { + if(parser->http_version != NULL) + parser->http_version(parser->data, parser->mark, p - parser->mark); + } + goto st19; +st19: + if ( ++p == pe ) + goto _out19; +case 19: +#line 257 "ext/http11/http11_parser.c" + if ( (*p) == 10 ) + goto st20; + goto st1; +st20: + if ( ++p == pe ) + goto _out20; +case 20: + switch( (*p) ) { + case 13: goto st21; + case 33: goto tr36; + case 124: goto tr36; + case 126: goto tr36; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto tr36; + } else if ( (*p) >= 35 ) + goto tr36; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr36; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto tr36; + } else + goto tr36; + } else + goto tr36; + goto st1; +st21: + if ( ++p == pe ) + goto _out21; +case 21: + if ( (*p) == 10 ) + goto tr40; + goto st1; +tr40: +#line 46 "ext/http11/http11_parser.rl" + { + parser->body_start = p+1; goto _out56; + } + goto st56; +st56: + if ( ++p == pe ) + goto _out56; +case 56: +#line 306 "ext/http11/http11_parser.c" + goto st1; +tr36: +#line 16 "ext/http11/http11_parser.rl" + { parser->field_start = p; } + goto st22; +st22: + if ( ++p == pe ) + goto _out22; +case 22: +#line 316 "ext/http11/http11_parser.c" + switch( (*p) ) { + case 33: goto st22; + case 58: goto tr32; + case 124: goto st22; + case 126: goto st22; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st22; + } else if ( (*p) >= 35 ) + goto st22; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st22; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st22; + } else + goto st22; + } else + goto st22; + goto st1; +tr32: +#line 17 "ext/http11/http11_parser.rl" + { + parser->field_len = (p - parser->field_start); + } + goto st23; +st23: + if ( ++p == pe ) + goto _out23; +case 23: +#line 351 "ext/http11/http11_parser.c" + if ( (*p) == 13 ) + goto tr56; + goto tr55; +tr55: +#line 21 "ext/http11/http11_parser.rl" + { MARK(parser, p); } + goto st24; +st24: + if ( ++p == pe ) + goto _out24; +case 24: +#line 363 "ext/http11/http11_parser.c" + if ( (*p) == 13 ) + goto tr51; + goto st24; +tr51: +#line 22 "ext/http11/http11_parser.rl" + { + if(parser->http_field != NULL) { + parser->http_field(parser->data, + parser->field_start, parser->field_len, + parser->mark+1, p - (parser->mark +1)); + } + } + goto st25; +tr56: +#line 21 "ext/http11/http11_parser.rl" + { MARK(parser, p); } +#line 22 "ext/http11/http11_parser.rl" + { + if(parser->http_field != NULL) { + parser->http_field(parser->data, + parser->field_start, parser->field_len, + parser->mark+1, p - (parser->mark +1)); + } + } + goto st25; +st25: + if ( ++p == pe ) + goto _out25; +case 25: +#line 393 "ext/http11/http11_parser.c" + switch( (*p) ) { + case 10: goto st26; + case 13: goto tr51; + } + goto st24; +st26: + if ( ++p == pe ) + goto _out26; +case 26: + switch( (*p) ) { + case 13: goto st21; + case 33: goto tr42; + case 124: goto tr42; + case 126: goto tr42; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto tr42; + } else if ( (*p) >= 35 ) + goto tr42; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr42; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto tr42; + } else + goto tr42; + } else + goto tr42; + goto st24; +tr42: +#line 16 "ext/http11/http11_parser.rl" + { parser->field_start = p; } + goto st27; +st27: + if ( ++p == pe ) + goto _out27; +case 27: +#line 435 "ext/http11/http11_parser.c" + switch( (*p) ) { + case 13: goto tr51; + case 33: goto st27; + case 58: goto tr32; + case 124: goto st27; + case 126: goto st27; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st27; + } else if ( (*p) >= 35 ) + goto st27; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st27; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st27; + } else + goto st27; + } else + goto st27; + goto st24; +tr28: +#line 14 "ext/http11/http11_parser.rl" + { MARK(parser, p); } + goto st28; +st28: + if ( ++p == pe ) + goto _out28; +case 28: +#line 469 "ext/http11/http11_parser.c" + switch( (*p) ) { + case 43: goto st28; + case 58: goto st29; + } + if ( (*p) < 48 ) { + if ( 45 <= (*p) && (*p) <= 46 ) + goto st28; + } else if ( (*p) > 57 ) { + if ( (*p) > 90 ) { + if ( 97 <= (*p) && (*p) <= 122 ) + goto st28; + } else if ( (*p) >= 65 ) + goto st28; + } else + goto st28; + goto st1; +tr30: +#line 14 "ext/http11/http11_parser.rl" + { MARK(parser, p); } + goto st29; +st29: + if ( ++p == pe ) + goto _out29; +case 29: +#line 494 "ext/http11/http11_parser.c" + switch( (*p) ) { + case 32: goto tr34; + case 37: goto st30; + case 60: goto st1; + case 62: goto st1; + case 127: goto st1; + } + if ( (*p) > 31 ) { + if ( 34 <= (*p) && (*p) <= 35 ) + goto st1; + } else if ( (*p) >= 0 ) + goto st1; + goto st29; +st30: + if ( ++p == pe ) + goto _out30; +case 30: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st31; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st31; + } else + goto st31; + goto st1; +st31: + if ( ++p == pe ) + goto _out31; +case 31: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st29; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st29; + } else + goto st29; + goto st1; +tr29: +#line 14 "ext/http11/http11_parser.rl" + { MARK(parser, p); } + goto st32; +st32: + if ( ++p == pe ) + goto _out32; +case 32: +#line 542 "ext/http11/http11_parser.c" + switch( (*p) ) { + case 32: goto tr34; + case 37: goto st34; + case 47: goto st1; + case 60: goto st1; + case 62: goto st1; + case 63: goto tr46; + case 127: goto st1; + } + if ( (*p) > 31 ) { + if ( 34 <= (*p) && (*p) <= 35 ) + goto st1; + } else if ( (*p) >= 0 ) + goto st1; + goto st33; +st33: + if ( ++p == pe ) + goto _out33; +case 33: + switch( (*p) ) { + case 32: goto tr34; + case 37: goto st34; + case 60: goto st1; + case 62: goto st1; + case 63: goto tr46; + case 127: goto st1; + } + if ( (*p) > 31 ) { + if ( 34 <= (*p) && (*p) <= 35 ) + goto st1; + } else if ( (*p) >= 0 ) + goto st1; + goto st33; +st34: + if ( ++p == pe ) + goto _out34; +case 34: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st35; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st35; + } else + goto st35; + goto st1; +st35: + if ( ++p == pe ) + goto _out35; +case 35: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st33; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st33; + } else + goto st33; + goto st1; +tr46: +#line 33 "ext/http11/http11_parser.rl" + { + if(parser->path_info != NULL) + parser->path_info(parser->data, parser->mark, p - parser->mark); + } + goto st36; +st36: + if ( ++p == pe ) + goto _out36; +case 36: +#line 613 "ext/http11/http11_parser.c" + switch( (*p) ) { + case 32: goto tr48; + case 37: goto tr54; + case 60: goto st1; + case 62: goto st1; + case 127: goto st1; + } + if ( (*p) > 31 ) { + if ( 34 <= (*p) && (*p) <= 35 ) + goto st1; + } else if ( (*p) >= 0 ) + goto st1; + goto tr53; +tr53: +#line 14 "ext/http11/http11_parser.rl" + { MARK(parser, p); } + goto st37; +st37: + if ( ++p == pe ) + goto _out37; +case 37: +#line 635 "ext/http11/http11_parser.c" + switch( (*p) ) { + case 32: goto tr48; + case 37: goto st38; + case 60: goto st1; + case 62: goto st1; + case 127: goto st1; + } + if ( (*p) > 31 ) { + if ( 34 <= (*p) && (*p) <= 35 ) + goto st1; + } else if ( (*p) >= 0 ) + goto st1; + goto st37; +tr54: +#line 14 "ext/http11/http11_parser.rl" + { MARK(parser, p); } + goto st38; +st38: + if ( ++p == pe ) + goto _out38; +case 38: +#line 657 "ext/http11/http11_parser.c" + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st39; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st39; + } else + goto st39; + goto st1; +st39: + if ( ++p == pe ) + goto _out39; +case 39: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st37; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st37; + } else + goto st37; + goto st1; +tr14: +#line 14 "ext/http11/http11_parser.rl" + { MARK(parser, p); } + goto st40; +st40: + if ( ++p == pe ) + goto _out40; +case 40: +#line 688 "ext/http11/http11_parser.c" + if ( (*p) == 69 ) + goto st41; + goto st1; +st41: + if ( ++p == pe ) + goto _out41; +case 41: + if ( (*p) == 84 ) + goto st7; + goto st1; +tr15: +#line 14 "ext/http11/http11_parser.rl" + { MARK(parser, p); } + goto st42; +st42: + if ( ++p == pe ) + goto _out42; +case 42: +#line 707 "ext/http11/http11_parser.c" + if ( (*p) == 69 ) + goto st43; + goto st1; +st43: + if ( ++p == pe ) + goto _out43; +case 43: + if ( (*p) == 65 ) + goto st44; + goto st1; +st44: + if ( ++p == pe ) + goto _out44; +case 44: + if ( (*p) == 68 ) + goto st7; + goto st1; +tr16: +#line 14 "ext/http11/http11_parser.rl" + { MARK(parser, p); } + goto st45; +st45: + if ( ++p == pe ) + goto _out45; +case 45: +#line 733 "ext/http11/http11_parser.c" + if ( (*p) == 80 ) + goto st46; + goto st1; +st46: + if ( ++p == pe ) + goto _out46; +case 46: + if ( (*p) == 84 ) + goto st47; + goto st1; +st47: + if ( ++p == pe ) + goto _out47; +case 47: + if ( (*p) == 73 ) + goto st48; + goto st1; +st48: + if ( ++p == pe ) + goto _out48; +case 48: + if ( (*p) == 79 ) + goto st49; + goto st1; +st49: + if ( ++p == pe ) + goto _out49; +case 49: + if ( (*p) == 78 ) + goto st50; + goto st1; +st50: + if ( ++p == pe ) + goto _out50; +case 50: + if ( (*p) == 83 ) + goto st7; + goto st1; +tr17: +#line 14 "ext/http11/http11_parser.rl" + { MARK(parser, p); } + goto st51; +st51: + if ( ++p == pe ) + goto _out51; +case 51: +#line 780 "ext/http11/http11_parser.c" + switch( (*p) ) { + case 79: goto st52; + case 85: goto st41; + } + goto st1; +st52: + if ( ++p == pe ) + goto _out52; +case 52: + if ( (*p) == 83 ) + goto st41; + goto st1; +tr18: +#line 14 "ext/http11/http11_parser.rl" + { MARK(parser, p); } + goto st53; +st53: + if ( ++p == pe ) + goto _out53; +case 53: +#line 801 "ext/http11/http11_parser.c" + if ( (*p) == 82 ) + goto st54; + goto st1; +st54: + if ( ++p == pe ) + goto _out54; +case 54: + if ( (*p) == 65 ) + goto st55; + goto st1; +st55: + if ( ++p == pe ) + goto _out55; +case 55: + if ( (*p) == 67 ) + goto st6; + goto st1; + } + _out1: cs = 1; goto _out; + _out2: cs = 2; goto _out; + _out3: cs = 3; goto _out; + _out4: cs = 4; goto _out; + _out5: cs = 5; goto _out; + _out6: cs = 6; goto _out; + _out7: cs = 7; goto _out; + _out8: cs = 8; goto _out; + _out9: cs = 9; goto _out; + _out10: cs = 10; goto _out; + _out11: cs = 11; goto _out; + _out12: cs = 12; goto _out; + _out13: cs = 13; goto _out; + _out14: cs = 14; goto _out; + _out15: cs = 15; goto _out; + _out16: cs = 16; goto _out; + _out17: cs = 17; goto _out; + _out18: cs = 18; goto _out; + _out19: cs = 19; goto _out; + _out20: cs = 20; goto _out; + _out21: cs = 21; goto _out; + _out56: cs = 56; goto _out; + _out22: cs = 22; goto _out; + _out23: cs = 23; goto _out; + _out24: cs = 24; goto _out; + _out25: cs = 25; goto _out; + _out26: cs = 26; goto _out; + _out27: cs = 27; goto _out; + _out28: cs = 28; goto _out; + _out29: cs = 29; goto _out; + _out30: cs = 30; goto _out; + _out31: cs = 31; goto _out; + _out32: cs = 32; goto _out; + _out33: cs = 33; goto _out; + _out34: cs = 34; goto _out; + _out35: cs = 35; goto _out; + _out36: cs = 36; goto _out; + _out37: cs = 37; goto _out; + _out38: cs = 38; goto _out; + _out39: cs = 39; goto _out; + _out40: cs = 40; goto _out; + _out41: cs = 41; goto _out; + _out42: cs = 42; goto _out; + _out43: cs = 43; goto _out; + _out44: cs = 44; goto _out; + _out45: cs = 45; goto _out; + _out46: cs = 46; goto _out; + _out47: cs = 47; goto _out; + _out48: cs = 48; goto _out; + _out49: cs = 49; goto _out; + _out50: cs = 50; goto _out; + _out51: cs = 51; goto _out; + _out52: cs = 52; goto _out; + _out53: cs = 53; goto _out; + _out54: cs = 54; goto _out; + _out55: cs = 55; goto _out; + + _out: {} + } +#line 127 "ext/http11/http11_parser.rl" + + parser->cs = cs; + parser->nread = p - buffer; + if(parser->body_start) { + /* final \r\n combo encountered so stop right here */ + +#line 886 "ext/http11/http11_parser.c" +#line 133 "ext/http11/http11_parser.rl" + parser->nread++; + } + + return(parser->nread); +} + +int http_parser_finish(http_parser *parser) +{ + int cs = parser->cs; + + +#line 899 "ext/http11/http11_parser.c" +#line 144 "ext/http11/http11_parser.rl" + + parser->cs = cs; + + if (http_parser_has_error(parser) ) { + return -1; + } else if (http_parser_is_finished(parser) ) { + return 1; + } else { + return 0; + } +} + +int http_parser_has_error(http_parser *parser) { + return parser->cs == http_parser_error; +} + +int http_parser_is_finished(http_parser *parser) { + return parser->cs == http_parser_first_final; +} diff --git a/ext/http11/http11_parser.h b/ext/http11/http11_parser.h new file mode 100644 index 0000000..f4a205f --- /dev/null +++ b/ext/http11/http11_parser.h @@ -0,0 +1,37 @@ +#ifndef http11_parser_h +#define http11_parser_h + +#include + +typedef void (*element_cb)(void *data, const char *at, size_t length); +typedef void (*field_cb)(void *data, const char *field, size_t flen, const char *value, size_t vlen); + +typedef struct http_parser { + int cs; + const char *body_start; + int content_len; + size_t nread; + const char *mark; + const char *field_start; + size_t field_len; + + void *data; + + field_cb http_field; + element_cb request_method; + element_cb path_info; + element_cb query_string; + element_cb http_version; + +} http_parser; + +int http_parser_init(http_parser *parser); +int http_parser_finish(http_parser *parser); +size_t http_parser_execute(http_parser *parser, const char *data, size_t len ); +int http_parser_has_error(http_parser *parser); +int http_parser_is_finished(http_parser *parser); +void http_parser_destroy(http_parser *parser); + +#define http_parser_nread(parser) (parser)->nread + +#endif diff --git a/ext/http11/http11_parser.rl b/ext/http11/http11_parser.rl new file mode 100644 index 0000000..7642cb1 --- /dev/null +++ b/ext/http11/http11_parser.rl @@ -0,0 +1,162 @@ +#include "http11_parser.h" +#include +#include +#include +#include +#include + +#define MARK(S,F) assert((F) - (S)->mark >= 0); (S)->mark = (F); + +/** machine **/ +%%{ + machine http_parser; + + action mark { MARK(parser, fpc); } + + action start_field { parser->field_start = fpc; } + action write_field { + parser->field_len = (p - parser->field_start); + } + + action start_value { MARK(parser, fpc); } + action write_value { + if(parser->http_field != NULL) { + parser->http_field(parser->data, + parser->field_start, parser->field_len, + parser->mark+1, p - (parser->mark +1)); + } + } + action request_method { + if(parser->request_method != NULL) + parser->request_method(parser->data, parser->mark, p - parser->mark); + } + action path_info { + if(parser->path_info != NULL) + parser->path_info(parser->data, parser->mark, p - parser->mark); + } + action query_string { + if(parser->query_string != NULL) + parser->query_string(parser->data, parser->mark, p - parser->mark); + } + + action http_version { + if(parser->http_version != NULL) + parser->http_version(parser->data, parser->mark, p - parser->mark); + } + action done { + parser->body_start = p+1; fbreak; + } + + + #### HTTP PROTOCOL GRAMMAR + # line endings + CRLF = "\r\n"; + + # character types + CTL = (cntrl | 127); + safe = ("$" | "-" | "_" | "."); + extra = ("!" | "*" | "'" | "(" | ")" | ","); + reserved = (";" | "/" | "?" | ":" | "@" | "&" | "=" | "+"); + unsafe = (CTL | " " | "\"" | "#" | "%" | "<" | ">"); + national = any - (alpha | digit | reserved | extra | safe | unsafe); + unreserved = (alpha | digit | safe | extra | national); + escape = ("%" xdigit xdigit); + uchar = (unreserved | escape); + pchar = (uchar | ":" | "@" | "&" | "=" | "+"); + tspecials = ("(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | "\"" | "/" | "[" | "]" | "?" | "=" | "{" | "}" | " " | "\t"); + + # elements + token = (ascii - (CTL | tspecials)); + + # URI schemes and absolute paths + scheme = ( alpha | digit | "+" | "-" | "." )* ; + absolute_uri = (scheme ":" (uchar | reserved )*) >mark %path_info; + + path = (pchar+ ( "/" pchar* )*) ; + query = ( uchar | reserved )* >mark %query_string ; + param = ( pchar | "/" )* ; + params = (param ( ";" param )*) ; + rel_path = (path? (";" params)?) %path_info ("?" query)? ; + absolute_path = ("/" rel_path) >mark ; + + Request_URI = ("*" >mark %path_info | absolute_uri | absolute_path) ; + Method = ("OPTIONS"| "GET" | "HEAD" | "POST" | "PUT" | "DELETE" | "TRACE") >mark %request_method; + + http_number = (digit+ "." digit+) ; + HTTP_Version = ("HTTP/" http_number) >mark %http_version ; + Request_Line = (Method " " Request_URI " " HTTP_Version CRLF) ; + + + + field_name = (token - ":")+ >start_field %write_field; + + field_value = (any - CRLF)*; + + message_header = field_name ":" field_value >start_value %write_value CRLF; + + Request = Request_Line (message_header)* $0 ( CRLF $1 @done ); + + main := Request; +}%% + +/** Data **/ +%% write data; + +int http_parser_init(http_parser *parser) { + int cs = 0; + %% write init; + parser->cs = cs; + parser->body_start = NULL; + parser->content_len = 0; + parser->mark = NULL; + parser->nread = 0; + + return(1); +} + + +/** exec **/ +size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len) { + const char *p, *pe; + int cs = parser->cs; + + p = buffer; + pe = buffer+len; + + %% write exec; + + parser->cs = cs; + parser->nread = p - buffer; + if(parser->body_start) { + /* final \r\n combo encountered so stop right here */ + %%write eof; + parser->nread++; + } + + return(parser->nread); +} + +int http_parser_finish(http_parser *parser) +{ + int cs = parser->cs; + + %%write eof; + + parser->cs = cs; + + if (http_parser_has_error(parser) ) { + return -1; + } else if (http_parser_is_finished(parser) ) { + return 1; + } else { + return 0; + } +} + +int http_parser_has_error(http_parser *parser) { + return parser->cs == http_parser_error; +} + +int http_parser_is_finished(http_parser *parser) { + return parser->cs == http_parser_first_final; +} diff --git a/ext/http11/tst.h b/ext/http11/tst.h new file mode 100644 index 0000000..8e5ab2c --- /dev/null +++ b/ext/http11/tst.h @@ -0,0 +1,40 @@ + + +struct node +{ + unsigned char value; + struct node *left; + struct node *middle; + struct node *right; +}; + +struct tst +{ + int node_line_width; + struct node_lines *node_lines; + struct node *free_list; + struct node *head[127]; +}; + +struct node_lines +{ + struct node *node_line; + struct node_lines *next; +}; + +enum tst_constants +{ + TST_OK, TST_ERROR, TST_NULL_KEY, TST_DUPLICATE_KEY, TST_REPLACE +}; + +struct tst *tst_init(int node_line_width); + +int tst_insert(unsigned char *key, void *data, struct tst *tst, int option, void **exist_ptr); + +void *tst_search(unsigned char *key, struct tst *tst, int *prefix_len); + +void *tst_delete(unsigned char *key, struct tst *tst); + +void tst_cleanup(struct tst *tst); + + diff --git a/ext/http11/tst_cleanup.c b/ext/http11/tst_cleanup.c new file mode 100644 index 0000000..b574f9f --- /dev/null +++ b/ext/http11/tst_cleanup.c @@ -0,0 +1,24 @@ + +#include "tst.h" +#include +#include + +void tst_cleanup(struct tst *tst) +{ + struct node_lines *current_line; + struct node_lines *next_line; + + next_line = tst->node_lines; + + do + { + current_line = next_line; + next_line = current_line->next; + free(current_line->node_line); + free(current_line); + } + while(next_line != NULL); + + free(tst); +} + diff --git a/ext/http11/tst_delete.c b/ext/http11/tst_delete.c new file mode 100644 index 0000000..cb18f16 --- /dev/null +++ b/ext/http11/tst_delete.c @@ -0,0 +1,146 @@ + +#include "tst.h" +#include +#include + +void *tst_delete(unsigned char *key, struct tst *tst) +{ + struct node *current_node; + struct node *current_node_parent; + struct node *last_branch; + struct node *last_branch_parent; + struct node *next_node; + struct node *last_branch_replacement; + struct node *last_branch_dangling_child; + int key_index; + + + if(key[0] == 0) + return NULL; + if(tst->head[(int)key[0]] == NULL) + return NULL; + + last_branch = NULL; + last_branch_parent = NULL; + current_node = tst->head[(int)key[0]]; + current_node_parent = NULL; + key_index = 1; + while(current_node != NULL) + { + if(key[key_index] == current_node->value) + { + + if( (current_node->left != NULL) || (current_node->right != NULL) ) + { + last_branch = current_node; + last_branch_parent = current_node_parent; + } + if(key[key_index] == 0) + break; + else + { + current_node_parent = current_node; + current_node = current_node->middle; + key_index++; + continue; + } + } + else if( ((current_node->value == 0) && (key[key_index] < 64)) || + ((current_node->value != 0) && (key[key_index] < + current_node->value)) ) + { + last_branch_parent = current_node; + current_node_parent = current_node; + current_node = current_node->left; + last_branch = current_node; + continue; + } + else + { + last_branch_parent = current_node; + current_node_parent = current_node; + current_node = current_node->right; + last_branch = current_node; + continue; + } + + } + if(current_node == NULL) + return NULL; + + if(last_branch == NULL) + { + + next_node = tst->head[(int)key[0]]; + tst->head[(int)key[0]] = NULL; + } + else if( (last_branch->left == NULL) && (last_branch->right == NULL) ) + { + + if(last_branch_parent->left == last_branch) + last_branch_parent->left = NULL; + else + last_branch_parent->right = NULL; + + next_node = last_branch; + } + else + { + + if( (last_branch->left != NULL) && (last_branch->right != NULL) ) + { + last_branch_replacement = last_branch->right; + last_branch_dangling_child = last_branch->left; + } + else if(last_branch->right != NULL) + { + last_branch_replacement = last_branch->right; + last_branch_dangling_child = NULL; + } + else + { + last_branch_replacement = last_branch->left; + last_branch_dangling_child = NULL; + } + + if(last_branch_parent == NULL) + tst->head[(int)key[0]]=last_branch_replacement; + else + { + if (last_branch_parent->left == last_branch) + last_branch_parent->left = last_branch_replacement; + else if (last_branch_parent->right == last_branch) + last_branch_parent->right = last_branch_replacement; + else + last_branch_parent->middle = last_branch_replacement; + } + + if(last_branch_dangling_child != NULL) + { + current_node = last_branch_replacement; + + while (current_node->left != NULL) + current_node = current_node->left; + + current_node->left = last_branch_dangling_child; + } + + next_node = last_branch; + } + + do + { + current_node = next_node; + next_node = current_node->middle; + + current_node->left = NULL; + current_node->right = NULL; + current_node->middle = tst->free_list; + tst->free_list = current_node; + } + while(current_node->value != 0); + + return next_node; + +} + diff --git a/ext/http11/tst_grow_node_free_list.c b/ext/http11/tst_grow_node_free_list.c new file mode 100644 index 0000000..da21333 --- /dev/null +++ b/ext/http11/tst_grow_node_free_list.c @@ -0,0 +1,38 @@ + +#include "tst.h" +#include +#include + +int tst_grow_node_free_list(struct tst *tst) +{ + struct node *current_node; + struct node_lines *new_line; + int i; + + + if((new_line = (struct node_lines *) malloc(sizeof(struct node_lines))) == NULL) + return TST_ERROR; + + if((new_line->node_line = (struct node *) + calloc(tst->node_line_width, sizeof(struct node))) == NULL) + { + free(new_line); + return TST_ERROR; + } + else + { + new_line->next = tst->node_lines; + tst->node_lines = new_line; + } + + current_node = tst->node_lines->node_line; + tst->free_list = current_node; + for (i = 1; i < tst->node_line_width; i++) + { + current_node->middle = &(tst->node_lines->node_line[i]); + current_node = current_node->middle; + } + current_node->middle = NULL; + return 1; +} + diff --git a/ext/http11/tst_init.c b/ext/http11/tst_init.c new file mode 100644 index 0000000..259734a --- /dev/null +++ b/ext/http11/tst_init.c @@ -0,0 +1,41 @@ + +#include "tst.h" +#include +#include + +struct tst *tst_init(int width) +{ + struct tst *tst; + struct node *current_node; + int i; + + +if((tst = (struct tst *) calloc(1, sizeof(struct tst))) == NULL) + return NULL; + +if ((tst->node_lines = (struct node_lines *) calloc(1, sizeof(struct node_lines))) == NULL) +{ + free(tst); + return NULL; +} + +tst->node_line_width = width; +tst->node_lines->next = NULL; +if ((tst->node_lines->node_line = (struct node *) calloc(width, sizeof(struct node))) == NULL) +{ + free(tst->node_lines); + free(tst); + return NULL; +} + +current_node = tst->node_lines->node_line; +tst->free_list = current_node; +for (i = 1; i < width; i++) +{ + current_node->middle = &(tst->node_lines->node_line[i]); + current_node = current_node->middle; +} +current_node->middle = NULL; +return tst; +} + diff --git a/ext/http11/tst_insert.c b/ext/http11/tst_insert.c new file mode 100644 index 0000000..0f83849 --- /dev/null +++ b/ext/http11/tst_insert.c @@ -0,0 +1,192 @@ + +#include "tst.h" +#include +#include + + +int tst_grow_node_free_list(struct tst *tst); +int tst_insert(unsigned char *key, void *data, struct tst *tst, int option, void **exist_ptr) +{ + struct node *current_node; + struct node *new_node_tree_begin = NULL; + int key_index; + int perform_loop = 1; + + + if (key == NULL) + return TST_NULL_KEY; + + if(key[0] == 0) + return TST_NULL_KEY; + + if(tst->head[(int)key[0]] == NULL) + { + + if(tst->free_list == NULL) + { + if(tst_grow_node_free_list(tst) != 1) + return TST_ERROR; + } + tst->head[(int)key[0]] = tst->free_list; + + tst->free_list = tst->free_list->middle; + current_node = tst->head[(int)key[0]]; + current_node->value = key[1]; + if(key[1] == 0) + { + current_node->middle = data; + return TST_OK; + } + else + perform_loop = 0; + } + + current_node = tst->head[(int)key[0]]; + key_index = 1; + while(perform_loop == 1) + { + if(key[key_index] == current_node->value) + { + + if(key[key_index] == 0) + { + if (option == TST_REPLACE) + { + if (exist_ptr != NULL) + *exist_ptr = current_node->middle; + + current_node->middle = data; + return TST_OK; + } + else + { + if (exist_ptr != NULL) + *exist_ptr = current_node->middle; + return TST_DUPLICATE_KEY; + } + } + else + { + if(current_node->middle == NULL) + { + + if(tst->free_list == NULL) + { + if(tst_grow_node_free_list(tst) != 1) + return TST_ERROR; + } + current_node->middle = tst->free_list; + + tst->free_list = tst->free_list->middle; + new_node_tree_begin = current_node; + current_node = current_node->middle; + current_node->value = key[key_index]; + break; + } + else + { + current_node = current_node->middle; + key_index++; + continue; + } + } + } + + if( ((current_node->value == 0) && (key[key_index] < 64)) || + ((current_node->value != 0) && (key[key_index] < + current_node->value)) ) + { + + if (current_node->left == NULL) + { + + if(tst->free_list == NULL) + { + if(tst_grow_node_free_list(tst) != 1) + return TST_ERROR; + } + current_node->left = tst->free_list; + + tst->free_list = tst->free_list->middle; + new_node_tree_begin = current_node; + current_node = current_node->left; + current_node->value = key[key_index]; + if(key[key_index] == 0) + { + current_node->middle = data; + return TST_OK; + } + else + break; + } + else + { + current_node = current_node->left; + continue; + } + } + else + { + + if (current_node->right == NULL) + { + + if(tst->free_list == NULL) + { + if(tst_grow_node_free_list(tst) != 1) + return TST_ERROR; + } + current_node->right = tst->free_list; + + tst->free_list = tst->free_list->middle; + new_node_tree_begin = current_node; + current_node = current_node->right; + current_node->value = key[key_index]; + break; + } + else + { + current_node = current_node->right; + continue; + } + } + } + + do + { + key_index++; + + if(tst->free_list == NULL) + { + if(tst_grow_node_free_list(tst) != 1) + { + current_node = new_node_tree_begin->middle; + + while (current_node->middle != NULL) + current_node = current_node->middle; + + current_node->middle = tst->free_list; + tst->free_list = new_node_tree_begin->middle; + new_node_tree_begin->middle = NULL; + + return TST_ERROR; + } + } + + + if(tst->free_list == NULL) + { + if(tst_grow_node_free_list(tst) != 1) + return TST_ERROR; + } + current_node->middle = tst->free_list; + + tst->free_list = tst->free_list->middle; + current_node = current_node->middle; + current_node->value = key[key_index]; + } while(key[key_index] !=0); + + current_node->middle = data; + return TST_OK; +} + diff --git a/ext/http11/tst_search.c b/ext/http11/tst_search.c new file mode 100644 index 0000000..efa1cfa --- /dev/null +++ b/ext/http11/tst_search.c @@ -0,0 +1,54 @@ + +#include "tst.h" +#include +#include +#include + +void *tst_search(unsigned char *key, struct tst *tst, int *prefix_len) +{ + struct node *current_node; + int key_index; + + assert(key != NULL && "key can't be NULL"); + assert(tst != NULL && "tst can't be NULL"); + + + if(key[0] == 0) + return NULL; + + if(tst->head[(int)key[0]] == NULL) + return NULL; + + current_node = tst->head[(int)key[0]]; + key_index = 1; + + while (current_node != NULL) + { + if(key[key_index] == current_node->value) + { + if(current_node->value == 0) { + if(prefix_len) *prefix_len = key_index; + return current_node->middle; + } else { + current_node = current_node->middle; + key_index++; + continue; + } + } + else if( ((current_node->value == 0) && (key[key_index] < 64)) || + ((current_node->value != 0) && (key[key_index] < + current_node->value)) ) + { + current_node = current_node->left; + continue; + } + else + { + current_node = current_node->right; + continue; + } + } + + if(prefix_len) *prefix_len = key_index; + return NULL; +} diff --git a/lib/mongrel.rb b/lib/mongrel.rb new file mode 100644 index 0000000..c46ccab --- /dev/null +++ b/lib/mongrel.rb @@ -0,0 +1,191 @@ +require 'socket' +require 'http11' +require 'thread' + + +# Mongrel module containing all of the classes (include C extensions) for running +# a Mongrel web server. It contains a minimalist HTTP server with just enough +# functionality to service web application requests fast as possible. +module Mongrel + + # When a handler is found for a registered URI then this class is constructed + # and passed to your HttpHandler::process method. You should assume that + # *one* handler processes all requests. Included in the HttpReqeust is a + # HttpRequest.params Hash that matches common CGI params, and a HttpRequest.body + # which is a string containing the request body (raw for now). + # + # Mongrel really only support small-ish request bodies right now since really + # huge ones have to be completely read off the wire and put into a string. + # Later there will be several options for efficiently handling large file + # uploads. + class HttpRequest + attr_reader :body, :params + + # You don't really call this. It's made for you. + # Main thing it does is hook up the params, and store any remaining + # body data into the HttpRequest.body attribute. + def initialize(params, initial_body, socket) + @body = initial_body || "" + @params = params + @socket = socket + + # fix up the CGI requirements + params['CONTENT_LENGTH'] = params['HTTP_CONTENT_LENGTH'] || 0 + + # now, if the initial_body isn't long enough for the content length we have to fill it + # TODO: adapt for big ass stuff by writing to a temp file + clen = params['HTTP_CONTENT_LENGTH'].to_i + if @body.length < clen + @body << @socket.read(clen - @body.length) + end + end + end + + # Very very simple response object. You basically write your stuff raw + # to the HttpResponse.socket variable. This will be made *much* easier + # in future releases allowing you to set status and request headers prior + # to sending the response. + class HttpResponse + attr_reader :socket + + def initialize(socket) + @socket = socket + end + + end + + # You implement your application handler with this. It's very light giving + # just the minimum necessary for you to handle a request and shoot back + # a response. Look at the HttpRequest and HttpResponse objects for how + # to use them. + class HttpHandler + attr_accessor :script_name + + def process(request, response) + end + end + + # The server normally returns a 404 response if a URI is requested, but it + # also returns a lame empty message. This lets you do a 404 response + # with a custom message for special URIs. + class Error404Handler < HttpHandler + + # Sets the message to return. This is constructed once for the handler + # so it's pretty efficient. + def initialize(msg) + @response = HttpServer::ERROR_404_RESPONSE + msg + end + + # Just kicks back the standard 404 response with your special message. + def process(request, response) + response.socket.write(@response) + end + + end + + + # This is the main driver of Mongrel, while the Mognrel::HttpParser and Mongrel::URIClassifier + # make up the majority of how the server functions. It's a very simple class that just + # has a thread accepting connections and a simple HttpServer.process_client function + # to do the heavy lifting with the IO and Ruby. + # + # *NOTE:* The process_client function used threads at one time but that proved to have + # stability issues on Mac OSX. Actually, Ruby in general has stability issues on Mac OSX. + # + # You use it by doing the following: + # + # server = HttpServer.new("0.0.0.0", 3000) + # server.register("/stuff", MyNifterHandler.new) + # server.run.join + # + # The last line can be just server.run if you don't want to join the thread used. + # If you don't though Ruby will mysteriously just exit on you. + class HttpServer + attr_reader :acceptor + + # The standard empty 404 response for bad requests. Use Error4040Handler for custom stuff. + ERROR_404_RESPONSE="HTTP/1.1 404 Not Found\r\nConnection: close\r\nContent-Type: text/plain\r\nServer: Mongrel/0.1\r\n\r\n" + + # For now we just read 2k chunks. Not optimal at all. + CHUNK_SIZE=2048 + + # Creates a working server on host:port (strange things happen if port isn't a Number). + # Use HttpServer::run to start the server. + def initialize(host, port) + @socket = TCPServer.new(host, port) + @classifier = URIClassifier.new + end + + # Used internally to process an accepted client. It uses HttpParser and URIClassifier + # (in ext/http11/http11.c) to do the heavy work, and mostly just does a hack job + # at some simple IO. Future releases will target this area mostly. + def process_client(client) + begin + parser = HttpParser.new + params = {} + data = "" + + while true + data << client.readpartial(CHUNK_SIZE) + + nread = parser.execute(params, data) + + if parser.error? + STDERR.puts "parser error:" + STDERR.puts data + break + elsif parser.finished? + script_name, path_info, handler = @classifier.resolve(params["PATH_INFO"]) + + if handler + params['PATH_INFO'] = path_info + params['SCRIPT_NAME'] = script_name + + request = HttpRequest.new(params, data[nread ... data.length], client) + response = HttpResponse.new(client) + + handler.process(request, response) + else + client.write(ERROR_404_RESPONSE) + end + + break + else + # gotta stream and read again until we can get the parser to be character safe + # TODO: make this more efficient since this means we're parsing a lot repeatedly + parser.reset + end + end + rescue => details + STDERR.puts "ERROR: #{details}" + STDERR.puts details.backtrace.join("\n") + ensure + client.close + end + end + + # Runs the thing. It returns the thread used so you can "join" it. You can also + # access the HttpServer::acceptor attribute to get the thread later. + def run + @acceptor = Thread.new do + while true + process_client(@socket.accept) + end + end + end + + + # Simply registers a handler with the internal URIClassifier. When the URI is + # found in the prefix of a request then your handler's HttpHandler::process method + # is called. See Mongrel::URIClassifier#register for more information. + def register(uri, handler) + @classifier.register(uri, handler) + end + + # Removes any handler registered at the given URI. See Mongrel::URIClassifier#unregister + # for more information. + def unregister(uri) + @classifier.unregister(uri) + end + end +end diff --git a/setup.rb b/setup.rb new file mode 100644 index 0000000..0807023 --- /dev/null +++ b/setup.rb @@ -0,0 +1,1360 @@ +# +# setup.rb +# +# Copyright (c) 2000-2004 Minero Aoki +# +# This program is free software. +# You can distribute/modify this program under the terms of +# the GNU LGPL, Lesser General Public License version 2.1. +# + +unless Enumerable.method_defined?(:map) # Ruby 1.4.6 + module Enumerable + alias map collect + end +end + +unless File.respond_to?(:read) # Ruby 1.6 + def File.read(fname) + open(fname) {|f| + return f.read + } + end +end + +def File.binread(fname) + open(fname, 'rb') {|f| + return f.read + } +end + +# for corrupted windows stat(2) +def File.dir?(path) + File.directory?((path[-1,1] == '/') ? path : path + '/') +end + + +class SetupError < StandardError; end + +def setup_rb_error(msg) + raise SetupError, msg +end + +# +# Config +# + +if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg } + ARGV.delete(arg) + require arg.split(/=/, 2)[1] + $".push 'rbconfig.rb' +else + require 'rbconfig' +end + +def multipackage_install? + FileTest.directory?(File.dirname($0) + '/packages') +end + + +class ConfigItem + def initialize(name, template, default, desc) + @name = name.freeze + @template = template + @value = default + @default = default.dup.freeze + @description = desc + end + + attr_reader :name + attr_reader :description + + attr_accessor :default + alias help_default default + + def help_opt + "--#{@name}=#{@template}" + end + + def value + @value + end + + def eval(table) + @value.gsub(%r<\$([^/]+)>) { table[$1] } + end + + def set(val) + @value = check(val) + end + + private + + def check(val) + setup_rb_error "config: --#{name} requires argument" unless val + val + end +end + +class BoolItem < ConfigItem + def config_type + 'bool' + end + + def help_opt + "--#{@name}" + end + + private + + def check(val) + return 'yes' unless val + unless /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i =~ val + setup_rb_error "config: --#{@name} accepts only yes/no for argument" + end + (/\Ay(es)?|\At(rue)/i =~ value) ? 'yes' : 'no' + end +end + +class PathItem < ConfigItem + def config_type + 'path' + end + + private + + def check(path) + setup_rb_error "config: --#{@name} requires argument" unless path + path[0,1] == '$' ? path : File.expand_path(path) + end +end + +class ProgramItem < ConfigItem + def config_type + 'program' + end +end + +class SelectItem < ConfigItem + def initialize(name, template, default, desc) + super + @ok = template.split('/') + end + + def config_type + 'select' + end + + private + + def check(val) + unless @ok.include?(val.strip) + setup_rb_error "config: use --#{@name}=#{@template} (#{val})" + end + val.strip + end +end + +class PackageSelectionItem < ConfigItem + def initialize(name, template, default, help_default, desc) + super name, template, default, desc + @help_default = help_default + end + + attr_reader :help_default + + def config_type + 'package' + end + + private + + def check(val) + unless File.dir?("packages/#{val}") + setup_rb_error "config: no such package: #{val}" + end + val + end +end + +class ConfigTable_class + + def initialize(items) + @items = items + @table = {} + items.each do |i| + @table[i.name] = i + end + ALIASES.each do |ali, name| + @table[ali] = @table[name] + end + end + + include Enumerable + + def each(&block) + @items.each(&block) + end + + def key?(name) + @table.key?(name) + end + + def lookup(name) + @table[name] or raise ArgumentError, "no such config item: #{name}" + end + + def add(item) + @items.push item + @table[item.name] = item + end + + def remove(name) + item = lookup(name) + @items.delete_if {|i| i.name == name } + @table.delete_if {|name, i| i.name == name } + item + end + + def new + dup() + end + + def savefile + '.config' + end + + def load + begin + t = dup() + File.foreach(savefile()) do |line| + k, v = *line.split(/=/, 2) + t[k] = v.strip + end + t + rescue Errno::ENOENT + setup_rb_error $!.message + "#{File.basename($0)} config first" + end + end + + def save + @items.each {|i| i.value } + File.open(savefile(), 'w') {|f| + @items.each do |i| + f.printf "%s=%s\n", i.name, i.value if i.value + end + } + end + + def [](key) + lookup(key).eval(self) + end + + def []=(key, val) + lookup(key).set val + end + +end + +c = ::Config::CONFIG + +rubypath = c['bindir'] + '/' + c['ruby_install_name'] + +major = c['MAJOR'].to_i +minor = c['MINOR'].to_i +teeny = c['TEENY'].to_i +version = "#{major}.#{minor}" + +# ruby ver. >= 1.4.4? +newpath_p = ((major >= 2) or + ((major == 1) and + ((minor >= 5) or + ((minor == 4) and (teeny >= 4))))) + +if c['rubylibdir'] + # V < 1.6.3 + _stdruby = c['rubylibdir'] + _siteruby = c['sitedir'] + _siterubyver = c['sitelibdir'] + _siterubyverarch = c['sitearchdir'] +elsif newpath_p + # 1.4.4 <= V <= 1.6.3 + _stdruby = "$prefix/lib/ruby/#{version}" + _siteruby = c['sitedir'] + _siterubyver = "$siteruby/#{version}" + _siterubyverarch = "$siterubyver/#{c['arch']}" +else + # V < 1.4.4 + _stdruby = "$prefix/lib/ruby/#{version}" + _siteruby = "$prefix/lib/ruby/#{version}/site_ruby" + _siterubyver = _siteruby + _siterubyverarch = "$siterubyver/#{c['arch']}" +end +libdir = '-* dummy libdir *-' +stdruby = '-* dummy rubylibdir *-' +siteruby = '-* dummy site_ruby *-' +siterubyver = '-* dummy site_ruby version *-' +parameterize = lambda {|path| + path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')\ + .sub(/\A#{Regexp.quote(libdir)}/, '$libdir')\ + .sub(/\A#{Regexp.quote(stdruby)}/, '$stdruby')\ + .sub(/\A#{Regexp.quote(siteruby)}/, '$siteruby')\ + .sub(/\A#{Regexp.quote(siterubyver)}/, '$siterubyver') +} +libdir = parameterize.call(c['libdir']) +stdruby = parameterize.call(_stdruby) +siteruby = parameterize.call(_siteruby) +siterubyver = parameterize.call(_siterubyver) +siterubyverarch = parameterize.call(_siterubyverarch) + +if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg } + makeprog = arg.sub(/'/, '').split(/=/, 2)[1] +else + makeprog = 'make' +end + +common_conf = [ + PathItem.new('prefix', 'path', c['prefix'], + 'path prefix of target environment'), + PathItem.new('bindir', 'path', parameterize.call(c['bindir']), + 'the directory for commands'), + PathItem.new('libdir', 'path', libdir, + 'the directory for libraries'), + PathItem.new('datadir', 'path', parameterize.call(c['datadir']), + 'the directory for shared data'), + PathItem.new('mandir', 'path', parameterize.call(c['mandir']), + 'the directory for man pages'), + PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']), + 'the directory for man pages'), + PathItem.new('stdruby', 'path', stdruby, + 'the directory for standard ruby libraries'), + PathItem.new('siteruby', 'path', siteruby, + 'the directory for version-independent aux ruby libraries'), + PathItem.new('siterubyver', 'path', siterubyver, + 'the directory for aux ruby libraries'), + PathItem.new('siterubyverarch', 'path', siterubyverarch, + 'the directory for aux ruby binaries'), + PathItem.new('rbdir', 'path', '$siterubyver', + 'the directory for ruby scripts'), + PathItem.new('sodir', 'path', '$siterubyverarch', + 'the directory for ruby extentions'), + PathItem.new('rubypath', 'path', rubypath, + 'the path to set to #! line'), + ProgramItem.new('rubyprog', 'name', rubypath, + 'the ruby program using for installation'), + ProgramItem.new('makeprog', 'name', makeprog, + 'the make program to compile ruby extentions'), + SelectItem.new('shebang', 'all/ruby/never', 'ruby', + 'shebang line (#!) editing mode'), + BoolItem.new('without-ext', 'yes/no', 'no', + 'does not compile/install ruby extentions') +] +class ConfigTable_class # open again + ALIASES = { + 'std-ruby' => 'stdruby', + 'site-ruby-common' => 'siteruby', # For backward compatibility + 'site-ruby' => 'siterubyver', # For backward compatibility + 'bin-dir' => 'bindir', + 'bin-dir' => 'bindir', + 'rb-dir' => 'rbdir', + 'so-dir' => 'sodir', + 'data-dir' => 'datadir', + 'ruby-path' => 'rubypath', + 'ruby-prog' => 'rubyprog', + 'ruby' => 'rubyprog', + 'make-prog' => 'makeprog', + 'make' => 'makeprog' + } +end +multipackage_conf = [ + PackageSelectionItem.new('with', 'name,name...', '', 'ALL', + 'package names that you want to install'), + PackageSelectionItem.new('without', 'name,name...', '', 'NONE', + 'package names that you do not want to install') +] +if multipackage_install? + ConfigTable = ConfigTable_class.new(common_conf + multipackage_conf) +else + ConfigTable = ConfigTable_class.new(common_conf) +end + + +module MetaConfigAPI + + def eval_file_ifexist(fname) + instance_eval File.read(fname), fname, 1 if File.file?(fname) + end + + def config_names + ConfigTable.map {|i| i.name } + end + + def config?(name) + ConfigTable.key?(name) + end + + def bool_config?(name) + ConfigTable.lookup(name).config_type == 'bool' + end + + def path_config?(name) + ConfigTable.lookup(name).config_type == 'path' + end + + def value_config?(name) + case ConfigTable.lookup(name).config_type + when 'bool', 'path' + true + else + false + end + end + + def add_config(item) + ConfigTable.add item + end + + def add_bool_config(name, default, desc) + ConfigTable.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc) + end + + def add_path_config(name, default, desc) + ConfigTable.add PathItem.new(name, 'path', default, desc) + end + + def set_config_default(name, default) + ConfigTable.lookup(name).default = default + end + + def remove_config(name) + ConfigTable.remove(name) + end + +end + + +# +# File Operations +# + +module FileOperations + + def mkdir_p(dirname, prefix = nil) + dirname = prefix + File.expand_path(dirname) if prefix + $stderr.puts "mkdir -p #{dirname}" if verbose? + return if no_harm? + + # does not check '/'... it's too abnormal case + dirs = File.expand_path(dirname).split(%r<(?=/)>) + if /\A[a-z]:\z/i =~ dirs[0] + disk = dirs.shift + dirs[0] = disk + dirs[0] + end + dirs.each_index do |idx| + path = dirs[0..idx].join('') + Dir.mkdir path unless File.dir?(path) + end + end + + def rm_f(fname) + $stderr.puts "rm -f #{fname}" if verbose? + return if no_harm? + + if File.exist?(fname) or File.symlink?(fname) + File.chmod 0777, fname + File.unlink fname + end + end + + def rm_rf(dn) + $stderr.puts "rm -rf #{dn}" if verbose? + return if no_harm? + + Dir.chdir dn + Dir.foreach('.') do |fn| + next if fn == '.' + next if fn == '..' + if File.dir?(fn) + verbose_off { + rm_rf fn + } + else + verbose_off { + rm_f fn + } + end + end + Dir.chdir '..' + Dir.rmdir dn + end + + def move_file(src, dest) + File.unlink dest if File.exist?(dest) + begin + File.rename src, dest + rescue + File.open(dest, 'wb') {|f| f.write File.binread(src) } + File.chmod File.stat(src).mode, dest + File.unlink src + end + end + + def install(from, dest, mode, prefix = nil) + $stderr.puts "install #{from} #{dest}" if verbose? + return if no_harm? + + realdest = prefix ? prefix + File.expand_path(dest) : dest + realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest) + str = File.binread(from) + if diff?(str, realdest) + verbose_off { + rm_f realdest if File.exist?(realdest) + } + File.open(realdest, 'wb') {|f| + f.write str + } + File.chmod mode, realdest + + File.open("#{objdir_root()}/InstalledFiles", 'a') {|f| + if prefix + f.puts realdest.sub(prefix, '') + else + f.puts realdest + end + } + end + end + + def diff?(new_content, path) + return true unless File.exist?(path) + new_content != File.binread(path) + end + + def command(str) + $stderr.puts str if verbose? + system str or raise RuntimeError, "'system #{str}' failed" + end + + def ruby(str) + command config('rubyprog') + ' ' + str + end + + def make(task = '') + command config('makeprog') + ' ' + task + end + + def extdir?(dir) + File.exist?(dir + '/MANIFEST') + end + + def all_files_in(dirname) + Dir.open(dirname) {|d| + return d.select {|ent| File.file?("#{dirname}/#{ent}") } + } + end + + REJECT_DIRS = %w( + CVS SCCS RCS CVS.adm .svn + ) + + def all_dirs_in(dirname) + Dir.open(dirname) {|d| + return d.select {|n| File.dir?("#{dirname}/#{n}") } - %w(. ..) - REJECT_DIRS + } + end + +end + + +# +# Main Installer +# + +module HookUtils + + def run_hook(name) + try_run_hook "#{curr_srcdir()}/#{name}" or + try_run_hook "#{curr_srcdir()}/#{name}.rb" + end + + def try_run_hook(fname) + return false unless File.file?(fname) + begin + instance_eval File.read(fname), fname, 1 + rescue + setup_rb_error "hook #{fname} failed:\n" + $!.message + end + true + end + +end + + +module HookScriptAPI + + def get_config(key) + @config[key] + end + + alias config get_config + + def set_config(key, val) + @config[key] = val + end + + # + # srcdir/objdir (works only in the package directory) + # + + #abstract srcdir_root + #abstract objdir_root + #abstract relpath + + def curr_srcdir + "#{srcdir_root()}/#{relpath()}" + end + + def curr_objdir + "#{objdir_root()}/#{relpath()}" + end + + def srcfile(path) + "#{curr_srcdir()}/#{path}" + end + + def srcexist?(path) + File.exist?(srcfile(path)) + end + + def srcdirectory?(path) + File.dir?(srcfile(path)) + end + + def srcfile?(path) + File.file? srcfile(path) + end + + def srcentries(path = '.') + Dir.open("#{curr_srcdir()}/#{path}") {|d| + return d.to_a - %w(. ..) + } + end + + def srcfiles(path = '.') + srcentries(path).select {|fname| + File.file?(File.join(curr_srcdir(), path, fname)) + } + end + + def srcdirectories(path = '.') + srcentries(path).select {|fname| + File.dir?(File.join(curr_srcdir(), path, fname)) + } + end + +end + + +class ToplevelInstaller + + Version = '3.3.1' + Copyright = 'Copyright (c) 2000-2004 Minero Aoki' + + TASKS = [ + [ 'all', 'do config, setup, then install' ], + [ 'config', 'saves your configurations' ], + [ 'show', 'shows current configuration' ], + [ 'setup', 'compiles ruby extentions and others' ], + [ 'install', 'installs files' ], + [ 'clean', "does `make clean' for each extention" ], + [ 'distclean',"does `make distclean' for each extention" ] + ] + + def ToplevelInstaller.invoke + instance().invoke + end + + @singleton = nil + + def ToplevelInstaller.instance + @singleton ||= new(File.dirname($0)) + @singleton + end + + include MetaConfigAPI + + def initialize(ardir_root) + @config = nil + @options = { 'verbose' => true } + @ardir = File.expand_path(ardir_root) + end + + def inspect + "#<#{self.class} #{__id__()}>" + end + + def invoke + run_metaconfigs + case task = parsearg_global() + when nil, 'all' + @config = load_config('config') + parsearg_config + init_installers + exec_config + exec_setup + exec_install + else + @config = load_config(task) + __send__ "parsearg_#{task}" + init_installers + __send__ "exec_#{task}" + end + end + + def run_metaconfigs + eval_file_ifexist "#{@ardir}/metaconfig" + end + + def load_config(task) + case task + when 'config' + ConfigTable.new + when 'clean', 'distclean' + if File.exist?(ConfigTable.savefile) + then ConfigTable.load + else ConfigTable.new + end + else + ConfigTable.load + end + end + + def init_installers + @installer = Installer.new(@config, @options, @ardir, File.expand_path('.')) + end + + # + # Hook Script API bases + # + + def srcdir_root + @ardir + end + + def objdir_root + '.' + end + + def relpath + '.' + end + + # + # Option Parsing + # + + def parsearg_global + valid_task = /\A(?:#{TASKS.map {|task,desc| task }.join '|'})\z/ + + while arg = ARGV.shift + case arg + when /\A\w+\z/ + setup_rb_error "invalid task: #{arg}" unless valid_task =~ arg + return arg + + when '-q', '--quiet' + @options['verbose'] = false + + when '--verbose' + @options['verbose'] = true + + when '-h', '--help' + print_usage $stdout + exit 0 + + when '-v', '--version' + puts "#{File.basename($0)} version #{Version}" + exit 0 + + when '--copyright' + puts Copyright + exit 0 + + else + setup_rb_error "unknown global option '#{arg}'" + end + end + + nil + end + + + def parsearg_no_options + unless ARGV.empty? + setup_rb_error "#{task}: unknown options: #{ARGV.join ' '}" + end + end + + alias parsearg_show parsearg_no_options + alias parsearg_setup parsearg_no_options + alias parsearg_clean parsearg_no_options + alias parsearg_distclean parsearg_no_options + + def parsearg_config + re = /\A--(#{ConfigTable.map {|i| i.name }.join('|')})(?:=(.*))?\z/ + @options['config-opt'] = [] + + while i = ARGV.shift + if /\A--?\z/ =~ i + @options['config-opt'] = ARGV.dup + break + end + m = re.match(i) or setup_rb_error "config: unknown option #{i}" + name, value = *m.to_a[1,2] + @config[name] = value + end + end + + def parsearg_install + @options['no-harm'] = false + @options['install-prefix'] = '' + while a = ARGV.shift + case a + when /\A--no-harm\z/ + @options['no-harm'] = true + when /\A--prefix=(.*)\z/ + path = $1 + path = File.expand_path(path) unless path[0,1] == '/' + @options['install-prefix'] = path + else + setup_rb_error "install: unknown option #{a}" + end + end + end + + def print_usage(out) + out.puts 'Typical Installation Procedure:' + out.puts " $ ruby #{File.basename $0} config" + out.puts " $ ruby #{File.basename $0} setup" + out.puts " # ruby #{File.basename $0} install (may require root privilege)" + out.puts + out.puts 'Detailed Usage:' + out.puts " ruby #{File.basename $0} " + out.puts " ruby #{File.basename $0} [] []" + + fmt = " %-24s %s\n" + out.puts + out.puts 'Global options:' + out.printf fmt, '-q,--quiet', 'suppress message outputs' + out.printf fmt, ' --verbose', 'output messages verbosely' + out.printf fmt, '-h,--help', 'print this message' + out.printf fmt, '-v,--version', 'print version and quit' + out.printf fmt, ' --copyright', 'print copyright and quit' + out.puts + out.puts 'Tasks:' + TASKS.each do |name, desc| + out.printf fmt, name, desc + end + + fmt = " %-24s %s [%s]\n" + out.puts + out.puts 'Options for CONFIG or ALL:' + ConfigTable.each do |item| + out.printf fmt, item.help_opt, item.description, item.help_default + end + out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's" + out.puts + out.puts 'Options for INSTALL:' + out.printf fmt, '--no-harm', 'only display what to do if given', 'off' + out.printf fmt, '--prefix=path', 'install path prefix', '$prefix' + out.puts + end + + # + # Task Handlers + # + + def exec_config + @installer.exec_config + @config.save # must be final + end + + def exec_setup + @installer.exec_setup + end + + def exec_install + @installer.exec_install + end + + def exec_show + ConfigTable.each do |i| + printf "%-20s %s\n", i.name, i.value + end + end + + def exec_clean + @installer.exec_clean + end + + def exec_distclean + @installer.exec_distclean + end + +end + + +class ToplevelInstallerMulti < ToplevelInstaller + + include HookUtils + include HookScriptAPI + include FileOperations + + def initialize(ardir) + super + @packages = all_dirs_in("#{@ardir}/packages") + raise 'no package exists' if @packages.empty? + end + + def run_metaconfigs + eval_file_ifexist "#{@ardir}/metaconfig" + @packages.each do |name| + eval_file_ifexist "#{@ardir}/packages/#{name}/metaconfig" + end + end + + def init_installers + @installers = {} + @packages.each do |pack| + @installers[pack] = Installer.new(@config, @options, + "#{@ardir}/packages/#{pack}", + "packages/#{pack}") + end + + with = extract_selection(config('with')) + without = extract_selection(config('without')) + @selected = @installers.keys.select {|name| + (with.empty? or with.include?(name)) \ + and not without.include?(name) + } + end + + def extract_selection(list) + a = list.split(/,/) + a.each do |name| + setup_rb_error "no such package: #{name}" unless @installers.key?(name) + end + a + end + + def print_usage(f) + super + f.puts 'Inluded packages:' + f.puts ' ' + @packages.sort.join(' ') + f.puts + end + + # + # multi-package metaconfig API + # + + attr_reader :packages + + def declare_packages(list) + raise 'package list is empty' if list.empty? + list.each do |name| + raise "directory packages/#{name} does not exist"\ + unless File.dir?("#{@ardir}/packages/#{name}") + end + @packages = list + end + + # + # Task Handlers + # + + def exec_config + run_hook 'pre-config' + each_selected_installers {|inst| inst.exec_config } + run_hook 'post-config' + @config.save # must be final + end + + def exec_setup + run_hook 'pre-setup' + each_selected_installers {|inst| inst.exec_setup } + run_hook 'post-setup' + end + + def exec_install + run_hook 'pre-install' + each_selected_installers {|inst| inst.exec_install } + run_hook 'post-install' + end + + def exec_clean + rm_f ConfigTable.savefile + run_hook 'pre-clean' + each_selected_installers {|inst| inst.exec_clean } + run_hook 'post-clean' + end + + def exec_distclean + rm_f ConfigTable.savefile + run_hook 'pre-distclean' + each_selected_installers {|inst| inst.exec_distclean } + run_hook 'post-distclean' + end + + # + # lib + # + + def each_selected_installers + Dir.mkdir 'packages' unless File.dir?('packages') + @selected.each do |pack| + $stderr.puts "Processing the package `#{pack}' ..." if @options['verbose'] + Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}") + Dir.chdir "packages/#{pack}" + yield @installers[pack] + Dir.chdir '../..' + end + end + + def verbose? + @options['verbose'] + end + + def no_harm? + @options['no-harm'] + end + +end + + +class Installer + + FILETYPES = %w( bin lib ext data ) + + include HookScriptAPI + include HookUtils + include FileOperations + + def initialize(config, opt, srcroot, objroot) + @config = config + @options = opt + @srcdir = File.expand_path(srcroot) + @objdir = File.expand_path(objroot) + @currdir = '.' + end + + def inspect + "#<#{self.class} #{File.basename(@srcdir)}>" + end + + # + # Hook Script API base methods + # + + def srcdir_root + @srcdir + end + + def objdir_root + @objdir + end + + def relpath + @currdir + end + + # + # configs/options + # + + def no_harm? + @options['no-harm'] + end + + def verbose? + @options['verbose'] + end + + def verbose_off + begin + save, @options['verbose'] = @options['verbose'], false + yield + ensure + @options['verbose'] = save + end + end + + # + # TASK config + # + + def exec_config + exec_task_traverse 'config' + end + + def config_dir_bin(rel) + end + + def config_dir_lib(rel) + end + + def config_dir_ext(rel) + extconf if extdir?(curr_srcdir()) + end + + def extconf + opt = @options['config-opt'].join(' ') + command "#{config('rubyprog')} #{curr_srcdir()}/extconf.rb #{opt}" + end + + def config_dir_data(rel) + end + + # + # TASK setup + # + + def exec_setup + exec_task_traverse 'setup' + end + + def setup_dir_bin(rel) + all_files_in(curr_srcdir()).each do |fname| + adjust_shebang "#{curr_srcdir()}/#{fname}" + end + end + + def adjust_shebang(path) + return if no_harm? + tmpfile = File.basename(path) + '.tmp' + begin + File.open(path, 'rb') {|r| + first = r.gets + return unless File.basename(config('rubypath')) == 'ruby' + return unless File.basename(first.sub(/\A\#!/, '').split[0]) == 'ruby' + $stderr.puts "adjusting shebang: #{File.basename(path)}" if verbose? + File.open(tmpfile, 'wb') {|w| + w.print first.sub(/\A\#!\s*\S+/, '#! ' + config('rubypath')) + w.write r.read + } + move_file tmpfile, File.basename(path) + } + ensure + File.unlink tmpfile if File.exist?(tmpfile) + end + end + + def setup_dir_lib(rel) + end + + def setup_dir_ext(rel) + make if extdir?(curr_srcdir()) + end + + def setup_dir_data(rel) + end + + # + # TASK install + # + + def exec_install + rm_f 'InstalledFiles' + exec_task_traverse 'install' + end + + def install_dir_bin(rel) + install_files collect_filenames_auto(), "#{config('bindir')}/#{rel}", 0755 + end + + def install_dir_lib(rel) + install_files ruby_scripts(), "#{config('rbdir')}/#{rel}", 0644 + end + + def install_dir_ext(rel) + return unless extdir?(curr_srcdir()) + install_files ruby_extentions('.'), + "#{config('sodir')}/#{File.dirname(rel)}", + 0555 + end + + def install_dir_data(rel) + install_files collect_filenames_auto(), "#{config('datadir')}/#{rel}", 0644 + end + + def install_files(list, dest, mode) + mkdir_p dest, @options['install-prefix'] + list.each do |fname| + install fname, dest, mode, @options['install-prefix'] + end + end + + def ruby_scripts + collect_filenames_auto().select {|n| /\.rb\z/ =~ n } + end + + # picked up many entries from cvs-1.11.1/src/ignore.c + reject_patterns = %w( + core RCSLOG tags TAGS .make.state + .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb + *~ *.old *.bak *.BAK *.orig *.rej _$* *$ + + *.org *.in .* + ) + mapping = { + '.' => '\.', + '$' => '\$', + '#' => '\#', + '*' => '.*' + } + REJECT_PATTERNS = Regexp.new('\A(?:' + + reject_patterns.map {|pat| + pat.gsub(/[\.\$\#\*]/) {|ch| mapping[ch] } + }.join('|') + + ')\z') + + def collect_filenames_auto + mapdir((existfiles() - hookfiles()).reject {|fname| + REJECT_PATTERNS =~ fname + }) + end + + def existfiles + all_files_in(curr_srcdir()) | all_files_in('.') + end + + def hookfiles + %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt| + %w( config setup install clean ).map {|t| sprintf(fmt, t) } + }.flatten + end + + def mapdir(filelist) + filelist.map {|fname| + if File.exist?(fname) # objdir + fname + else # srcdir + File.join(curr_srcdir(), fname) + end + } + end + + def ruby_extentions(dir) + Dir.open(dir) {|d| + ents = d.select {|fname| /\.#{::Config::CONFIG['DLEXT']}\z/ =~ fname } + if ents.empty? + setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first" + end + return ents + } + end + + # + # TASK clean + # + + def exec_clean + exec_task_traverse 'clean' + rm_f ConfigTable.savefile + rm_f 'InstalledFiles' + end + + def clean_dir_bin(rel) + end + + def clean_dir_lib(rel) + end + + def clean_dir_ext(rel) + return unless extdir?(curr_srcdir()) + make 'clean' if File.file?('Makefile') + end + + def clean_dir_data(rel) + end + + # + # TASK distclean + # + + def exec_distclean + exec_task_traverse 'distclean' + rm_f ConfigTable.savefile + rm_f 'InstalledFiles' + end + + def distclean_dir_bin(rel) + end + + def distclean_dir_lib(rel) + end + + def distclean_dir_ext(rel) + return unless extdir?(curr_srcdir()) + make 'distclean' if File.file?('Makefile') + end + + # + # lib + # + + def exec_task_traverse(task) + run_hook "pre-#{task}" + FILETYPES.each do |type| + if config('without-ext') == 'yes' and type == 'ext' + $stderr.puts 'skipping ext/* by user option' if verbose? + next + end + traverse task, type, "#{task}_dir_#{type}" + end + run_hook "post-#{task}" + end + + def traverse(task, rel, mid) + dive_into(rel) { + run_hook "pre-#{task}" + __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '') + all_dirs_in(curr_srcdir()).each do |d| + traverse task, "#{rel}/#{d}", mid + end + run_hook "post-#{task}" + } + end + + def dive_into(rel) + return unless File.dir?("#{@srcdir}/#{rel}") + + dir = File.basename(rel) + Dir.mkdir dir unless File.dir?(dir) + prevdir = Dir.pwd + Dir.chdir dir + $stderr.puts '---> ' + rel if verbose? + @currdir = rel + yield + Dir.chdir prevdir + $stderr.puts '<--- ' + rel if verbose? + @currdir = File.dirname(rel) + end + +end + + +if $0 == __FILE__ + begin + if multipackage_install? + ToplevelInstallerMulti.invoke + else + ToplevelInstaller.invoke + end + rescue SetupError + raise if $DEBUG + $stderr.puts $!.message + $stderr.puts "Try 'ruby #{$0} --help' for detailed usage." + exit 1 + end +end diff --git a/test/.test_ws.rb.swp b/test/.test_ws.rb.swp new file mode 100644 index 0000000..84dbb1d Binary files /dev/null and b/test/.test_ws.rb.swp differ diff --git a/test/test_http11.rb b/test/test_http11.rb new file mode 100644 index 0000000..8f07900 --- /dev/null +++ b/test/test_http11.rb @@ -0,0 +1,31 @@ +require 'test/unit' +require 'http11' + + +class HttpParserTest < Test::Unit::TestCase + + def test_parse_simple + parser = HttpParser.new + req = {} + http = "GET / HTTP/1.1\r\n\r\n" + nread = parser.execute(req, http); + assert nread == http.length, "Failed to parse the full HTTP request" + assert parser.finished?, "Parser didn't finish" + assert !parser.error?, "Parser had error" + assert nread == parser.nread, "Number read returned from execute does not match" + parser.reset + assert parser.nread == 0, "Number read after reset should be 0" + end + + + def test_parse_error + parser = HttpParser.new + req = {} + bad_http = "GET / SsUTF/1.1" + nread = parser.execute(req, bad_http) + assert nread < bad_http.length, "Number read should be less than total on error" + assert !parser.finished?, "Parser shouldn't be finished" + assert parser.error?, "Parser SHOULD have error" + end +end + diff --git a/test/test_uriclassifier.rb b/test/test_uriclassifier.rb new file mode 100644 index 0000000..ae5df1d --- /dev/null +++ b/test/test_uriclassifier.rb @@ -0,0 +1,104 @@ +require 'test/unit' +require 'net/http' +require 'mongrel' +require 'benchmark' + +include Mongrel + +class URIClassifierTest < Test::Unit::TestCase + + def test_uri_finding + u = URIClassifier.new + u.register("/test", 1) + + sn,pi,val = u.resolve("/test") + assert val != nil, "didn't resolve" + assert_equal 1, val, "wrong value" + assert_equal "/test",sn, "wrong SCRIPT_NAME" + end + + + def test_uri_prefix_ops + test = "/pre/fix/test" + prefix = "/pre" + + u = URIClassifier.new + u.register(prefix,1) + + sn,pi,val = u.resolve(test) + assert val != nil, "didn't resolve" + assert_equal prefix,sn, "wrong script name" + assert_equal test[sn.length .. -1],pi, "wrong path info" + end + + def test_not_finding + test = "/cant/find/me" + u = URIClassifier.new + u.register(test, 1) + + sn,pi,val = u.resolve("/nope/not/here") + assert_equal nil,sn, "shouldn't be found" + assert_equal nil,pi, "shouldn't be found" + assert_equal nil,val, "shouldn't be found" + end + + def test_exceptions + u = URIClassifier.new + + u.register("test", 1) + + failed = false + begin + u.register("test", 1) + rescue => e + failed = true + end + + assert failed, "it didn't fail as expected" + + failed = false + begin + u.register("", 1) + rescue => e + failed = true + end + + assert failed, "it didn't fail as expected" + end + + + def test_register_unregister + u = URIClassifier.new + + 100.times do + u.register("stuff", 1) + val = u.unregister("stuff") + assert_equal 1,val, "didn't get the right return value" + end + + u.register("things",1) + sn,pi,val = u.resolve("things") + assert_equal 1, val, "result doesn't match" + + u.unregister("things") + sn,pi,val = u.resolve("things") + assert_equal nil, val, "result should be nil" + + end + + + def test_performance + count = 8500 + u = URIClassifier.new + u.register("stuff",1) + + res = Benchmark.measure { count.times { u.resolve("stuff") } } + + reg_unreg = Benchmark.measure { count.times { u.register("other",1); u.unregister("other"); } } + + puts "\nRESOLVE(#{count}): #{res}" + puts "REG_UNREG(#{count}): #{reg_unreg}" + end + +end + diff --git a/test/test_ws.rb b/test/test_ws.rb new file mode 100644 index 0000000..dd7fa77 --- /dev/null +++ b/test/test_ws.rb @@ -0,0 +1,33 @@ +require 'test/unit' +require 'net/http' +require 'mongrel' +require 'timeout' + +include Mongrel; + +class TestHandler < Mongrel::HttpHandler + attr_reader :ran_test + + def process(request, response) + @ran_test = true + response.socket.write("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nhello!\n") + end +end + + +class WSTest < Test::Unit::TestCase + + def test_simple_server + h = HttpServer.new("0.0.0.0", 9998) + tester = TestHandler.new + h.register("/test", tester) + h.run + + sleep(1) + res = Net::HTTP.get(URI.parse('http://localhost:9998/test')) + assert res != nil, "Didn't get a response" + assert tester.ran_test, "Handler didn't really run" + end + +end + diff --git a/tools/rakehelp.rb b/tools/rakehelp.rb new file mode 100644 index 0000000..6996658 --- /dev/null +++ b/tools/rakehelp.rb @@ -0,0 +1,99 @@ + +def make(makedir) + Dir.chdir(makedir) do + sh 'make' + end +end + + +def extconf(dir) + Dir.chdir(dir) do ruby "extconf.rb" end +end + + +def setup_tests + Rake::TestTask.new do |t| + t.libs << "test" + t.test_files = FileList['test/test*.rb'] + t.verbose = true + end +end + + +def setup_clean otherfiles + files = ['build/*', '**/*.o', '**/*.so', '**/*.a', 'lib/*-*', '**/*.log'] + otherfiles + CLEAN.include(files) +end + + +def setup_rdoc files + Rake::RDocTask.new do |rdoc| + rdoc.rdoc_dir = 'doc/rdoc' + rdoc.options << '--line-numbers' + rdoc.rdoc_files.add(files) + end +end + + +def setup_extension(dir, extension) + ext = "ext/#{dir}" + ext_so = "#{ext}/#{extension}.#{Config::CONFIG['DLEXT']}" + ext_files = FileList[ + "#{ext}/*.c", + "#{ext}/*.h", + "#{ext}/extconf.rb", + "#{ext}/Makefile", + "lib" + ] + + task "lib" do + directory "lib" + end + + desc "Builds just the #{extension} extension" + task extension.to_sym => ["#{ext}/Makefile", ext_so ] + + file "#{ext}/Makefile" => ["#{ext}/extconf.rb"] do + extconf "#{ext}" + end + + file ext_so => ext_files do + make "#{ext}" + cp ext_so, "lib" + end +end + + +def setup_gem(pkg_name, pkg_version, author, summary, executables, test_file) + pkg_version = pkg_version + pkg_name = pkg_name + pkg_file_name = "#{pkg_name}-#{pkg_version}" + + spec = Gem::Specification.new do |s| + s.name = pkg_name + s.version = pkg_version + s.platform = Gem::Platform::RUBY + s.author = author + s.summary = summary + s.test_file = test_file + s.has_rdoc = true + s.extra_rdoc_files = [ "README" ] + + s.files = %w(COPYING LICENSE ext/http11/MANIFEST README Rakefile setup.rb) + + Dir.glob("{bin,doc,test,lib}/**/*") + + Dir.glob("ext/**/*.{h,c,rb}") + + Dir.glob("examples/**/*.rb") + + Dir.glob("tools/*.rb") + + s.require_path = "lib" + s.extensions = FileList["ext/**/extconf.rb"].to_a + + s.executables = executables + s.bindir = "bin" + end + + Rake::GemPackageTask.new(spec) do |p| + p.gem_spec = spec + p.need_tar = true + end +end -- cgit v1.2.3-24-ge0c7