From: (no author) <(no author)@unknown> Date: Mon, 9 Jun 1997 14:17:28 +0000 (+0000) Subject: This commit was manufactured by cvs2svn to create branch 'APACHE_1_2_X'. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0a2cba274761d8223c43fa11da841fe318d0bb53;p=thirdparty%2Fapache%2Fhttpd.git This commit was manufactured by cvs2svn to create branch 'APACHE_1_2_X'. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/1.3@78269 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/APACHE_1_2_X/ABOUT_APACHE b/APACHE_1_2_X/ABOUT_APACHE new file mode 100644 index 00000000000..22db91550cb --- /dev/null +++ b/APACHE_1_2_X/ABOUT_APACHE @@ -0,0 +1,222 @@ + + The Apache HTTP Server Project + + http://www.apache.org/ + + June 1997 + +The Apache Project is a collaborative software development effort aimed +at creating a robust, commercial-grade, featureful, and freely-available +source code implementation of an HTTP (Web) server. The project is +jointly managed by a group of volunteers located around the world, using +the Internet and the Web to communicate, plan, and develop the server and +its related documentation. These volunteers are known as the Apache Group. +In addition, hundreds of users have contributed ideas, code, and +documentation to the project. This file is intended to briefly describe +the history of the Apache Group, recognize the many contributors, and +explain how you can join the fun too. + +In February of 1995, the most popular server software on the Web was the +public domain HTTP daemon developed by Rob McCool at the National Center +for Supercomputing Applications, University of Illinois, Urbana-Champaign. +However, development of that httpd had stalled after Rob left NCSA in +mid-1994, and many webmasters had developed their own extensions and bug +fixes that were in need of a common distribution. A small group of these +webmasters, contacted via private e-mail, gathered together for the purpose +of coordinating their changes (in the form of "patches"). Brian Behlendorf +and Cliff Skolnick put together a mailing list, shared information space, +and logins for the core developers on a machine in the California Bay Area, +with bandwidth and diskspace donated by HotWired and Organic Online. +By the end of February, eight core contributors formed the foundation +of the original Apache Group: + + Brian Behlendorf Roy T. Fielding Rob Hartill + David Robinson Cliff Skolnick Randy Terbush + Robert S. Thau Andrew Wilson + +with additional contributions from + + Eric Hagberg Frank Peters Nicolas Pioch + +Using NCSA httpd 1.3 as a base, we added all of the published bug fixes +and worthwhile enhancements we could find, tested the result on our own +servers, and made the first official public release (0.6.2) of the Apache +server in April 1995. By coincidence, NCSA restarted their own development +during the same period, and Brandon Long and Beth Frank of the NCSA Server +Development Team joined the list in March as honorary members so that the +two projects could share ideas and fixes. + +The early Apache server was a big hit, but we all knew that the codebase +needed a general overhaul and redesign. During May-June 1995, while +Rob Hartill and the rest of the group focused on implementing new features +for 0.7.x (like pre-forked child processes) and supporting the rapidly growing +Apache user community, Robert Thau designed a new server architecture +(code-named Shambhala) which included a modular structure and API for better +extensibility, pool-based memory allocation, and an adaptive pre-forking +process model. The group switched to this new server base in July and added +the features from 0.7.x, resulting in Apache 0.8.8 (and its brethren) +in August. + +After extensive beta testing, many ports to obscure platforms, a new set +of documentation (by David Robinson), and the addition of many features +in the form of our standard modules, Apache 1.0 was released on +December 1, 1995. + +Less than a year after the group was formed, the Apache server passed +NCSA's httpd as the #1 server on the Internet. + + ============================================================================ + +Current Apache Group, 1 June 1997 + + Brian Behlendorf Organic Online, California + Ken Coar Process Software Corporation, New England, USA + Mark J. Cox UKWeb, UK + Roy T. Fielding UC Irvine, California + Dean Gaudet Steam Tunnel Operations, California + Rob Hartill Internet Movie DB, UK + Jim Jagielski jaguNET ISP, Maryland + Alexei Kosut Nueva High School, California + Ben Laurie Freelance Consultant, UK + Chuck Murcko The Topsail Group, Pennsylvania + Aram W. Mirzadeh Qosina Corporation, New York + Sameer Parekh C2Net, California + Paul Sutton UKWeb, UK + Marc Slemko Canada + Randy Terbush Zyzzyva ISP, Nebraska + Dirk-Willem van Gulik Freelance Consultant, Italy + Andrew Wilson Freelance Consultant, UK + +Apache Emeritae (old group members now off doing other things) + + Robert S. Thau MIT, Massachusetts + David Robinson Cambridge University, UK + +Other major contributors + + Rob McCool (original author of the NCSA httpd), + Brandon Long and Beth Frank (NCSA Server Development Team, post-1.3), + Paul Richards (convinced the group to use remote CVS after 1.0), + Kevin Hughes (creator of all those nifty icons), + Henry Spencer (author of the regex library), Garey Smiley (OS/2 port), + Ralf S. Engelschall (mod_rewrite), Howard Fear (mod_include), + Florent Guillaume (language negotiation). + +Many 3rd-party modules, frequently used and recommended, are also +freely-available and linked from the related projects page: +, and their authors frequently +contribute ideas, patches, and testing. In particular, Doug MacEachern +(mod_perl) and Rasmus Lerdorf (mod_php). + +Hundreds of people have made individual contributions to the Apache +project. Patch contributors are listed in the src/CHANGES file. +Frequent contributors have included Petr Lampa, Tom Tromey, +James H. Cloos Jr., Ed Korthof, Nathan Neulinger, Jason S. Clary, +Jason A. Dour, Michael Douglass, Tony Sanders, Martin Kraemer, +Brian Tao, Michael Smith, Adam Sussman, Nathan Schrenk, Matthew Gray, +and John Heidemann. + + ============================================================================ + +How to join the Apache Group + +There are several levels of contributing. If you just want to send +in an occasional suggestion/fix, then you can just use the bug reporting +form at . You can also subscribe to the +announcements mailing list (apache-announce@apache.org) which we use to +broadcast information about new releases, bugfixes, and upcoming events. + +If you'd like to become an active member of the Apache Group (the group +of volunteers who vote on changes to the distributed server), then +you need to start by subscribing to the new-httpd@apache.org mailing list. +One warning though: traffic is high, 1000 to 1500 messages/month. +To subscribe to the list, send "subscribe new-httpd" in the body of +a message to . We recommend reading the list for +a while before trying to jump in to development. + + NOTE: The developer mailing list (new-httpd@apache.org) is not + a user support forum; it is for people actively working on development + of the server code and documentation, and for planning future + directions. If you have user/configuration questions, send them + to the USENET newsgroup "comp.infosystems.www.servers.unix". + +The Apache Group is a meritocracy -- the more work you have done, the more +you are allowed to do. The group founders set the original rules, but +they can be changed by vote of the active members. There is a core group +of people who have logins on our server (hyperreal.com) and access to the +CVS repository. Everyone has access to the CVS snapshots. Changes to +the code are proposed on the mailing list and usually voted on by active +members -- three +1 (yes votes) and no -1 (no votes, or vetoes) are needed +to commit a code change during a release cycle; docs are usually committed +first and then changed as needed, with conflicts resolved by majority vote. + +Our primary method of communication is our mailing list. Approximately 40 +messages a day flow over the list, and are typically very conversational in +tone. We discuss new features to add, bug fixes, user problems, developments +in the web server community, release dates, etc. The actual code development +takes place on the developers' local machines, with proposed changes +communicated using a patch (output of a context "diff -c3 oldfile newfile" +command), and committed to the source repository by one of the core +developers using remote CVS. + +New members of the Apache Group are added when a frequent contributor is +nominated by one member and unanimously approved by the voting members. +In most cases, this "new" member has been actively contributing to the +group's work for over six months, so it's usually an easy decision. +Anyone on the mailing list can vote on a particular issue, but we only +count those made by active members or people who are known to be experts +on that part of the server. Vetoes must be accompanied by a convincing +explanation. + +The above describes our past and current (as of June 1997) guidelines, +which will probably change over time as the membership of the group +changes and our development/coordination tools improve. + + ============================================================================ + +Why Apache Is Free + +Apache exists to provide a robust and commercial-grade reference +implementation of the HTTP protocol. It must remain a platform upon which +individuals and institutions can build reliable systems, both for +experimental purposes and for mission-critical purposes. We believe the +tools of online publishing should be in the hands of everyone, and +software companies should make their money providing value-added services +such as specialized modules and support, amongst other things. We realize +that it is often seen as an economic advantage for one company to "own" a +market - in the software industry that means to control tightly a +particular conduit such that all others must pay. This is typically done +by "owning" the protocols through which companies conduct business, at the +expense of all those other companies. To the extent that the protocols of +the World Wide Web remain "unowned" by a single company, the Web will +remain a level playing field for companies large and small. Thus, +"ownership" of the protocol must be prevented, and the existence of a +robust reference implementation of the protocol, available absolutely for +free to all companies, is a tremendously good thing. + +Furthermore, Apache is an organic entity; those who benefit from it +by using it often contribute back to it by providing feature enhancements, +bug fixes, and support for others in public newsgroups. The amount of +effort expended by any particular individual is usually fairly light, but +the resulting product is made very strong. This kind of community can +only happen with freeware -- when someone pays for software, they usually +aren't willing to fix its bugs. One can argue, then, that Apache's +strength comes from the fact that it's free, and if it were made "not +free" it would suffer tremendously, even if that money were spent on a +real development team. + +We want to see Apache used very widely -- by large companies, small +companies, research institutions, schools, individuals, in the intranet +environment, everywhere -- even though this may mean that companies who +could afford commercial software, and would pay for it without blinking, +might get a "free ride" by using Apache. We would even be happy if some +commercial software companies completely dropped their own HTTP server +development plans and used Apache as a base, with the proper attributions +as described in the LICENSE file. + +Thanks for using Apache! + + ============================================================================ +Roy Fielding, June 1997 + +If you are interested in other WWW history, see diff --git a/APACHE_1_2_X/CHANGES b/APACHE_1_2_X/CHANGES new file mode 100644 index 00000000000..7e762e2fc8d --- /dev/null +++ b/APACHE_1_2_X/CHANGES @@ -0,0 +1,129 @@ + OVERVIEW OF NEW FEATURES IN APACHE 1.2 + +New features with this release, as extensions of the Apache functionality +For more information, see the documentation included with this release +(htdocs/manual/) or http://www.apache.org/docs/ + +In addition to a number of bug fixes and internal performance +enhancements, Apache 1.2 has the following specific new user +features: + + + *) HTTP/1.1 Compliance + Aside from the optional proxy module (which operates as HTTP/1.0), + Apache is conditionally compliant with the HTTP/1.1 proposed standard, + as approved by the IESG and the IETF HTTP working group. + HTTP/1.1 provides a much-improved protocol, and should allow for + greater performance and efficiency when transferring files. Apache + does, however, still work great with HTTP/1.0 browsers. We are very + close to being unconditionally compliant; if you note any deviance + from the proposed standard, please report it as a bug. + + *) eXtended Server Side Includes (XSSI) + A new set of server-side include directives allows the user to + better create WWW pages. This includes number of powerful new + features, such as the ability to set variables and use conditional + HTML. + + *) File-based and Regex-enabled Directive Sections + The new section allows directives to be enabled based on + full filename, not just directory and URL. In addition, + sections can appear in .htaccess files. , along with + and , can also now be based on regular + expressions, not just simple prefix matching. + + *) Browser-based Environment Variables + Environment variables can now be set based on the User-Agent + string of the browser. Combined with XSSI, this allows you to + write browser-based conditional HTML documents. + + *) SetUID CGI Execution + Apache now supports the execution of CGI scripts as users other + than the server user. A number of security checks are built in to + try and make this as safe as possible. + + *) URL Rewriting Module + The optional mod_rewrite module is now included. This module can + provide powerful URL mapping, using regular expressions. There's + nothing this module can't do! + + *) Enhanced, Configurable Logging + The optional mod_log_config included with earlier versions of + Apache is now standard, and has been enhanced to allow logging of + much more detail about the transaction, and can be used to open + more than one log at once (each of which can have a different log + format). + + *) User Tracking (Cookies) Revisions + The mod_cookies included with previous versions of Apache has been + renamed mod_usertrack, to more accurately reflect its function + (some people inadvertently thought it enabled cookie support in + Apache, which is not true - Apache supports the use of cookies + directly). It is also now possible to disable the generation of + cookies, even when the cookie module is compiled in. Also, an + expiry time can be set on the cookies. + + *) Multiple IPs in + The directive can now take more than one IP address + or hostname. This lets a single vhost handles requests for + multiple IPs or hostnames. + + *) CGI Debugging Environment + ScriptLog allows you to now set up a log that records all input + and output to failed CGI scripts. This includes environment + variables, input headers, POST data, output, and more. This makes + CGI scripts much easier to debug. + + *) Resource Limits for CGI Scripts + New directives allow the limiting of resources used by CGI scripts + (e.g. max CPU time). This is helpful in preventing 'runaway' CGI + processes. + + *) Redirect Directive Can Return Alternate Status + The Redirect directive can return permanent or temporary redirects, + "Gone" or "See Other" HTTP status. For NCSA-compatibility, + RedirectTemp and RedirectPermanent are also implemented. + + *) Graceful Restarts + Apache can re-read the config files and re-open log files without + terminating transactions in progress. + + *) Simplified Compilation + The process of configuring Apache for compilation has been + simplified. + + *) Add or Remove Options + The Options directive can now add or remove options from those + currently in force, rather than always replacing them. + + *) Command-line Help + The -h command-line option now lists all the available directives. + + *) Optional Headers Module to Set or Remove HTTP Headers + The optional mod_headers module can be used to set custom headers + in the HTTP response. It can append to existing headers, replace + them, or remove headers from the response. + + *) Conditional Config Directives + A new section allows directives to be enabled only if a + given module is loaded into the server. + + *) Authorization Directives Now Use NCSA-style Syntax + The AuthUserFile, AuthGroupFile and AuthDigestFile commands now + have a syntax compatible with the NCSA server. + + *) Optional Proxy Module + An improved FTP, HTTP, and CONNECT mode SSL proxy is included with + Apache 1.2. Some of the changes visible to users: + + - Improved FTP proxy supporting PASV mode + - NoProxy directive for excluding sites to proxy + - CONNECT mode ports are configurable from a list + - NoCache * directive for disabling proxy caching + - Numerous bug fixes + + *) Optional Example Module + An example module that demonstrates many of the aspects of the + API is now included with Apache as of version 1.2. It can be + used as a base for those who wish to write their own Apache + modules. diff --git a/APACHE_1_2_X/KEYS b/APACHE_1_2_X/KEYS new file mode 100644 index 00000000000..1507ca36df0 --- /dev/null +++ b/APACHE_1_2_X/KEYS @@ -0,0 +1,171 @@ +This file contains the PGP keys of various Apache developers. +Please don't use them for email unless you have to. Their main +purpose is code signing. + +Apache users: pgp < KEYS +Apache developers: pgp -kxa and append it to this file. + + +Type Bits/KeyID Date User ID +pub 1024/2719AF35 1995/05/13 Ben Laurie + Ben Laurie + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.3ia + +mQCNAi+0jQEAAAEEAK7oX0FeNncaHfa1v+V7SMUviAm8qB8orWG0zvja4ZtSrHVg +/PMwppUh44t5ERA9lltRBdHu30+YSh8a1dYt1XOD83nknzj9rhtpFAPqyywlLVhN +VY3PVLyMbULw27aEAGc+StFqrDoUQ0+j9QU/YH/IyVN9rBaJyhsIDEUnGa81AAUR +tB5CZW4gTGF1cmllIDxiZW5AYWxncm91cC5jby51az6JARUDBRAyb2Doc3AsNzyk +Yh0BARa6CACUBnsP9Vb+T/PvNYKVQBIODz+90tz5GozWwCVfPVSaRd8Dz+oF1sFs +YCz/KuxqBhL5PkiCuSMfOVlPA5nirjoktMF/af5saZqhPr5rvr67Z1OzZnVDvWe4 +DhFrn8EoLrY5YNJhUwfINnZqyKaQu8TW6p4caLkTCW0KM+4ztTe74xRG9NeE+K0+ +0RMpAF3jEY36LGRjq6miazt2bVZQDTl6CuWE+gAaFlX2ojV7e1xdxVvpBIEc34MP +g9ORJ0evx1QilMt1VyGcS/pe4IQgjdJqjU/4fzqFZkT2nntQMbV9kQyNe2+qfqP7 +giTryIanmBAfd3oOCTsRz2VKPfdhCqCRiQB1AwUQMRdzEEyr2GZv4ALJAQEuhAL6 +A8I84BR+87uNAHD0ZJkTM73WdyMEGvAKBvrZK/g0VLYj0NtgkSuRJfrXnGkuh27I +ZrjfL952Q/mXgMtHhJHJ9YfenGFWSEDHnolNzKOzTQJpE01IZ3nWv7ezA9N1LZVC +iQCVAgUQMROrdRsIDEUnGa81AQEUNgQAlvyjt534RDQd2AYGoZriaFzjaL7dTCRH +4b1zxuWBNWf3pI4W0iwU02Q5rEWEmY5DLl6/ie+vcQKOWSqXVgnM/s6EARdKEN56 +d6PzkwszgfEybDYrcAxReJcTCcV8ItJer/iqpBLgtaxyUpI77NvKcDGHp6BgYpnv +1lNkH0FISK+JAJUDBRAwtzlWdGx7qH+PTVkBARFWA/99NTCMihlOZS7LmHDVic/q +H1K1DVdMcv0iL39+7Pq4+AA/ET8dWIgcjaIreSqAZTpjwU1pMPaWgecDD1rEMCYX +R+JoofLJ24BLcSlpXJ/gWMifYNxqdDeMRkw/aW/kaXQJWIz+oDYNuOyi5VvB6faF +6Lm7P5cw1mX0I5rYc3woh7QoQmVuIExhdXJpZSA8YmVuQGdvbnpvLmJlbi5hbGdy +b3VwLmNvLnVrPokAlQIFEDEXgCUbCAxFJxmvNQEBiL8D/3MLjfHGvuByqP1VFQrF +QeMNd2aIQuC7ys3lkDvrLkkPJQANua0/MdDaZk6F5pCGcTmmmaJOjcOcCheD7FU5 +w9zxkQGR3Swr3opFHSr/CkEl83jRy3oq1MFydWoGajQjIr/c23X8zr+XntPyO6VX +q5He4RrTiXeAEFBzz+J+R+EQ +=zh1u +-----END PGP PUBLIC KEY BLOCK----- + + +Type bits/keyID Date User ID +pub 1024/A99F75DD 1997/01/24 Ken A L Coar + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.2 + +mQCNAzLpIyUAAAEEAN9KC8CxTeozPYJjsnhFpJ14d4Hhf2M6OTgqPQFRHOswM/3j +B7IW0s+HwVyQ5/SjIlo+8ur9X7yaj1FS2GQmKD1x9LKeHRAoosBIs33okRtoeDRy +ufTaTyQTwLklxClWm3JEef4xZioun1mtWbpz0yVEOCSZcRvtnJrNPMCpn3XdAAUR +tB1LZW4gQSBMIENvYXIgPENvYXJAREVDVVMuT3JnPokAlQMFEDNLrGCazTzAqZ91 +3QEBzwEEAMqamgAftJ8X39dH+slXVZhXAkUDfUNPkDyy7Yd8R+UTCdXXZMRrVSc3 +3nGsd7sycFot+TQ4RWK8g1o/eY0LzgT+hSxsI80BabdnX2hCP8Yq6aqBw9XfHRQU ++zUHA5h150dX9vEUp+Rb8UKPvkqTNz58Cv1HFAHboZ55KMJ+oeTk +=arlJ +-----END PGP PUBLIC KEY BLOCK----- + +Type Bits/KeyID Date User ID +pub 768/A0BB71C1 1997/06/03 Jim Jagielski + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.3 + +mQBtAzOUkNMAAAEDANZdTUJQPwrFI9526Qf+DEWL8dXgfhWW8o6CzewdcCoHYEpu +9CiOMD3f9bgo1VozOPceGzCu/9FF2hMLUvVsTAZkzC3rre5TtPo/vOf5HJ+ac9M7 +aqxW+gRu2/90oLtxwQAFEbQfSmltIEphZ2llbHNraSA8amltQGphZ3VORVQuY29t +PokAdQMFEDOUkNRu2/90oLtxwQEB8iEC/i9Qo55TlT8bRpcqeM3lzNDqzU9cqKRf +9X8pGJIVE5m2JPm99qPLs8RPeepLChi8ZZ+2hSfb7ldQhvVLgNqQqLpsjGtJjJOU +C+MrKDeSk2WAicg6Uo0FWCsEHxrssw139A== +=pwim +-----END PGP PUBLIC KEY BLOCK----- + +Type Bits/KeyID Date User ID +pub 2048/DD919C31 1996/12/24 sameer@c2.net + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.3ia + +mQENAzK/QZIAAAEIALrsEjuGlt6wkHy8fx2wPSkH7paAqJHDCbO1W/GMVs41BsH1 +xpyBi9lOtUXHsDC8Obx/TES4/xVPSsFKPQLa9Q/OsxjXmEPBvQ5PZdOXJ5zmRMI1 +1cfUp2s8w6i+IS68IWRKdPMshGWFGar1YUPM1UpVME7U+uGD3wgdC4DrVJHzS5Eh +gEDyQ9FPb+8CpsRO3AvUPzsZGG8Iy/9GiLzmaJG34zZ5fv5X7sr89xiWJ21ehk+X +ePO9kvq+nzfOCCK6a3GZD4g3KJX/Pm3oKeaXeL8WSCCPzpNbtRJk3ofeN7Zm1K0L +yChPiyui+OO063/WASv52bxUIlmzbX82a92RnDEABRG0DXNhbWVlckBjMi5uZXSJ +ARUDBRAyv0GTbX82a92RnDEBAfqVB/9GSzADIVqY0faFOLN6+E3qqg3hPRLBvjgC +5cvTlwT7W64zI+aiSZuN+xAXq+3lnKtmzn45F3hD7gBxRPJbSKsObn2zU4UcqW/o +qoiYEnO9EhoBomwPUbVy8C00CWvDLfeF4L5r+2oXgilTsCojSaWJX0QoPCwRQao1 +YwZ6CqAA78vdbBNkmA0WrPsVqwd3ijgFapcX671AqiT+pDbvK646I6uGPXJzN3ZU +vFuDim9D2uNk9CfvPhKGscr4qqP40TnNn5fjSsmrFyFxYsdwo7I4TFpnsEPOw226 +GU+TR7zdwnByP72AxPEBJ/F22LwNyreuph+fRpWCnCf+9gVW9Heh +=jS5Z +-----END PGP PUBLIC KEY BLOCK----- + + =========================== +Rob Hartill + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.2 + +mQCNAzG6VfMAAAEEAOvtvphFG/D02vGLENBl5OVPgEJgP9E1xhUgKTZnJstv30kD +h1IqeIBkEAy5bpKapCbvvxukyQErhB0efTi2v5yTAlz5pVjgWM5Sa8CyTXJmXPHH +EuOfy1DqaiQSmZ6KWX0ygw3gKDZMiNMf06UURLLYtRlGKSYY3WVj2u2UCmS9AAUR +tB5Sb2JlcnQgSGFydGlsbCA8cm9iaEBpbWRiLmNvbT6JAJUDBRAx5eIAZWPa7ZQK +ZL0BAU2XBACXfopMzC8kW3KEqq+N9W9fkGNgy//8XqQ77FmfPQPbO4X7Zn3cyO46 +MxvPP+92zSyN3dyj/xWZYoRLwll+ync9d4KUFwKw45DALAvz1CKHMOpQPD7dIWdE +9poJQrcbKeOqLcGZTu/hY90gWBUZ++9umR8X8lyh/WEgcUolfgYHew== +=upYh +-----END PGP PUBLIC KEY BLOCK----- + +Type Bits/KeyID Date User ID +pub 1024/631B5749 1996/06/21 Randy Terbush + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.3 + +mQCNAzHLBS8AAAEEANGFXb9o0NPVfVjSLvQh1j3fN6cMeVNA5BGUJ6HZGP/NDxTE +i8hwejJqakkU4ux/g6Kqckrx3h8WR7OXZZ+R8CsA0bg9Sr42ndEQCUISgArg+lXZ +gRUniARPPA7tamTSq8v1mnxqy9s26Ht2rAG2D6IiK/7v0JlezKirDeBjG1dJAAUR +tCFSYW5keSBUZXJidXNoIDxyYW5keUB6eXp6eXZhLmNvbT6JAJUDBRAxywUwqKsN +4GMbV0kBAegnA/sH63WyfwMFmn3nWe8T/5IXO/QkMYoMGLS1i7IxMY9O8BVvKQM+ +oxEcJdFAG7zPZkpgKzTBxmExz5hMZ9hwJ42XhrslWoP7JVvADJcdthrUAYW9W+jx +GcDYAW3qW5DpKsQchfvXq9QOBDxP+Kbbe2B8xGEyGUhLkacISFTrIhhQSg== +=8P8s +-----END PGP PUBLIC KEY BLOCK----- + +Type Bits/KeyID Date User ID +pub 1024/49A563D9 1997/02/24 Mark Cox + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.3ia + +mQCNAzMRY/IAAAEEAOloTOU0f4w7FDRMM6kA/6XazXxJ/HH8dsmb6E7RuYfVlXsd +kCwxUBOkyW+AYhkHbYUwnB5qBoFUyLrbLGuwKHW1KnAwgbeZLTH5nqQLpA0RLGVZ +v3tzImKUdyyxBphZWC4IeEgUbl9cc+piOsEJ8QzF7gnqwWo/Ku6tTP1JpWPZAAUR +tBlNYXJrIENveCA8bWFya0B1a3dlYi5jb20+iQCVAwUQMxFj8u6tTP1JpWPZAQHz +eQP+N0nQDbPzWeqLssQLyhFkjw5zZByN60j8p25+6JEq7RXgkN1cHtAdH5LMwRAG +fc258f7P9Syp64lH8s4XWYSX5GX8YA8MurOrJmoGFrJs/yxWng8xtxI9tFUnuoIb +HqnD7HCS9Oj1INdyyQuCxZYGHAgxHhpfNTZt+33tMSFIZTQ= +=uIkU +-----END PGP PUBLIC KEY BLOCK----- + +Type Bits/KeyID Date User ID +pub 1024/2F90A69D 1997/02/24 Paul Sutton + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.3ia + +mQCNAzMRsB0AAAEEAKj2XYYEGcZhT69x4gskQ3xz+KMTLn7gKSqqcyyeinJ0ZjLl +6AJjb1/68nGsF+IIY+IJS+5smq8do1qpC3UZcmw423Sg8F71GeqDO4HZXOAOieVy +rpVs6S5TaXlJOcrC7zZCx+iql97+xJFjUGkkS7j/jIkx1AajzMNkSr0vkKadAAUR +tBxQYXVsIFN1dHRvbiA8cGF1bEB1a3dlYi5jb20+iQCVAwUQMxGwHcNkSr0vkKad +AQGrigP9F43zbiOigYel+JCMiB0HK/UdqSrf3xWxHIKWKNhQNjhnyeF+jKQwFld6 +7KQYsqZIpHsWLWmSk0AmKQOUIw+DxclDxBL2dT4p+CjgTgIAcbvPpahWkBAw/E+c +EGTiYbe+Y3sHJhhP+d0TOLmsETG9tpi7gFZ6FfNcWPxFMdxGrf4= +=0jQW +-----END PGP PUBLIC KEY BLOCK----- + +Type bits/keyID Date User ID +pub 1024/BA20321D 1997/06/05 Chuck Murcko + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.2 + +mQCNAzOW7moAAAEEAMYZlNOxWCjLR/PosadbG+xsrB2unid2LiYoakTFiDIBaZjx +bu6hNmVZPYfKOXQcqrCu0EY3uVLP/L89bST5pfIZOzz8GTm33zrETgfzpXYyFdbX +eZ5vc6aa3+7zmI7h/aU567P9ruB2C/RBLl1A59wmPRRVvjEIAkI4bAO6IDIdAAUR +tCBDaHVjayBNdXJja28gPGNodWNrQHRvcHNhaWwub3JnPg== +=vUdL +-----END PGP PUBLIC KEY BLOCK----- + diff --git a/APACHE_1_2_X/LICENSE b/APACHE_1_2_X/LICENSE new file mode 100644 index 00000000000..ec09d302feb --- /dev/null +++ b/APACHE_1_2_X/LICENSE @@ -0,0 +1,54 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + + + diff --git a/APACHE_1_2_X/README b/APACHE_1_2_X/README new file mode 100644 index 00000000000..f8b53dc686a --- /dev/null +++ b/APACHE_1_2_X/README @@ -0,0 +1,86 @@ + Apache + Version 1.2 (and up) + +What is it? +----------- + +Apache is an HTTP server designed as a plug-in replacement for the NCSA +server version 1.3 (or 1.4). It fixes numerous bugs in the NCSA server and +includes many frequently requested new features, and has an API which +allows it to be extended to meet users' needs more easily. + +Documentation +------------- + +The documentation available as of the date of this release is also +included, in HTML format, in the htdocs/manual/ directory. For the +most up-to-date documentation, visit us on the WWW, at +. + +Installation +------------ + +Unless you grabbed a binary distribution of Apache, you must compile +it for your specific platform. In order to compile it, you must set +compile-time options (in particular, system type) for your system by +editing a Configuration file, run a script which generates a Makefile +and a small piece of C code, and then compile it. + +For instructions on compilation, see the file 'INSTALL' in the src/ directory. + +After compilation, you will have a binary called "httpd" in the src/ +directory. If you received a binary distribution of apache, you +should have this file already. + +The next step is to edit the configuration files for the server. In +the subdirectory called "conf" you should find distribution versions +of the three configuration files: srm.conf-dist, access.conf-dist, and +httpd.conf-dist. Copy them to srm.conf, access.conf, httpd.conf +respectively. + +First edit httpd.conf. This sets up general attributes about the +server - the port number, the user it runs as, etc. Next edit the +srm.conf file - this sets up the root of the document tree, special +functions like server-parsed HTML or internal imagemap parsing, etc. +Finally, edit the access.conf file to at least set the base cases of +access. Documentation for all of these is located at +. + +Finally, make a call to httpd, with a -f to the full path to the +httpd.conf file. I.e., the common case: + + /usr/local/etc/apache/src/httpd -f /usr/local/etc/apache/conf/httpd.conf + +And voila! The server should be running. + +By default the srm.conf and access.conf files are located by name - to +specifically call them by other names, use the AccessConfig and +ResourceConfig directives in httpd.conf. + +The Latest Version +------------------ + +Details of the latest version are in the apache project page (above). + +Licencing +--------- + +Please see the file called LICENSE. + +Acknowledgements +---------------- + +We wish to acknowledge the following copyrighted works that make up +portions of the Apache software: + +Portions of this software were developed at the National Center for +Supercomputing Applications at the University of Illinois at +Urbana-Champaign. + +This software contains code derived from the RSA Data Security Inc. MD5 +Message-Diest Algorithm, including various modifications by Spyglass Inc., +Caregie Mellon University, and Bell Communications Research, Inc. +(Bellcore). + +This package contains software written and copyrighted by Henry Spencer. +Please see the file called src/regex/COPYRIGHT. diff --git a/APACHE_1_2_X/RULES.CVS b/APACHE_1_2_X/RULES.CVS new file mode 100644 index 00000000000..7ecbbffd4c6 --- /dev/null +++ b/APACHE_1_2_X/RULES.CVS @@ -0,0 +1,13 @@ +1. Don't commit several unrelated changes in one go. Each change should be +committed separately (that is, it can affect multiple files, but it should all +be part of a single change). + +2. When committing, make sure that the CVS log message explains what the +patches do and why. + +3. Don't edit CHANGES files unless there is a change which is visible to a user +of Apache. CVS logs provide a detailed history of all changes (if people follow +rule 2), so there is no need to duplicate it in CHANGES. + +4. Don't change src/Configuration.tmpl to your local configuration. Copy it to +Configuration (which is _not_ version controlled) and change that. diff --git a/APACHE_1_2_X/cgi-bin/printenv b/APACHE_1_2_X/cgi-bin/printenv new file mode 100644 index 00000000000..7d389e0ac56 --- /dev/null +++ b/APACHE_1_2_X/cgi-bin/printenv @@ -0,0 +1,7 @@ +#!/usr/local/bin/perl + +print "Content-type: text/html\n\n"; +while (($key, $val) = each %ENV) { + print "$key = $val
\n"; +} + diff --git a/APACHE_1_2_X/cgi-bin/test-cgi b/APACHE_1_2_X/cgi-bin/test-cgi new file mode 100644 index 00000000000..a85631e3aa2 --- /dev/null +++ b/APACHE_1_2_X/cgi-bin/test-cgi @@ -0,0 +1,31 @@ +#!/bin/sh + +# disable filename globbing +set -f + +echo Content-type: text/plain +echo + +echo CGI/1.0 test script report: +echo + +echo argc is $#. argv is "$*". +echo + +echo SERVER_SOFTWARE = $SERVER_SOFTWARE +echo SERVER_NAME = $SERVER_NAME +echo GATEWAY_INTERFACE = $GATEWAY_INTERFACE +echo SERVER_PROTOCOL = $SERVER_PROTOCOL +echo SERVER_PORT = $SERVER_PORT +echo REQUEST_METHOD = $REQUEST_METHOD +echo HTTP_ACCEPT = "$HTTP_ACCEPT" +echo PATH_INFO = "$PATH_INFO" +echo PATH_TRANSLATED = "$PATH_TRANSLATED" +echo SCRIPT_NAME = "$SCRIPT_NAME" +echo QUERY_STRING = "$QUERY_STRING" +echo REMOTE_HOST = $REMOTE_HOST +echo REMOTE_ADDR = $REMOTE_ADDR +echo REMOTE_USER = $REMOTE_USER +echo AUTH_TYPE = $AUTH_TYPE +echo CONTENT_TYPE = $CONTENT_TYPE +echo CONTENT_LENGTH = $CONTENT_LENGTH diff --git a/APACHE_1_2_X/conf/access.conf-dist b/APACHE_1_2_X/conf/access.conf-dist new file mode 100644 index 00000000000..8e17b5360f1 --- /dev/null +++ b/APACHE_1_2_X/conf/access.conf-dist @@ -0,0 +1,70 @@ +# access.conf: Global access configuration +# Online docs at http://www.apache.org/ + +# This file defines server settings which affect which types of services +# are allowed, and in what circumstances. + +# Each directory to which Apache has access, can be configured with respect +# to which services and features are allowed and/or disabled in that +# directory (and its subdirectories). + +# Originally by Rob McCool + +# This should be changed to whatever you set DocumentRoot to. + + + +# This may also be "None", "All", or any combination of "Indexes", +# "Includes", "FollowSymLinks", "ExecCGI", or "MultiViews". + +# Note that "MultiViews" must be named *explicitly* --- "Options All" +# doesn't give it to you (or at least, not yet). + +Options Indexes FollowSymLinks + +# This controls which options the .htaccess files in directories can +# override. Can also be "All", or any combination of "Options", "FileInfo", +# "AuthConfig", and "Limit" + +AllowOverride None + +# Controls who can get stuff from this server. + +order allow,deny +allow from all + + + +# /usr/local/etc/httpd/cgi-bin should be changed to whatever your ScriptAliased +# CGI directory exists, if you have that configured. + + +AllowOverride None +Options None + + +# Allow server status reports, with the URL of http://servername/server-status +# Change the ".your_domain.com" to match your domain to enable. + +# +#SetHandler server-status + +#order deny,allow +#deny from all +#allow from .your_domain.com +# + +# There have been reports of people trying to abuse an old bug from pre-1.1 +# days. This bug involved a CGI script distributed as a part of Apache. +# By uncommenting these lines you can redirect these attacks to a logging +# script on phf.apache.org. Or, you can record them yourself, using the script +# support/phf_abuse_log.cgi. + +# +#deny from all +#ErrorDocument 403 http://phf.apache.org/phf_abuse_log.cgi +# + +# You may place any other directories or locations you wish to have +# access information for after this one. + diff --git a/APACHE_1_2_X/conf/httpd.conf-dist b/APACHE_1_2_X/conf/httpd.conf-dist new file mode 100644 index 00000000000..3a783c63c7d --- /dev/null +++ b/APACHE_1_2_X/conf/httpd.conf-dist @@ -0,0 +1,186 @@ +# This is the main server configuration file. See URL http://www.apache.org/ +# for instructions. + +# Do NOT simply read the instructions in here without understanding +# what they do, if you are unsure consult the online docs. You have been +# warned. + +# Originally by Rob McCool + +# ServerType is either inetd, or standalone. + +ServerType standalone + +# If you are running from inetd, go to "ServerAdmin". + +# Port: The port the standalone listens to. For ports < 1023, you will +# need httpd to be run as root initially. + +Port 80 + +# HostnameLookups: Log the names of clients or just their IP numbers +# e.g. www.apache.org (on) or 204.62.129.132 (off) +HostnameLookups on + +# If you wish httpd to run as a different user or group, you must run +# httpd as root initially and it will switch. + +# User/Group: The name (or #number) of the user/group to run httpd as. +# On SCO (ODT 3) use User nouser and Group nogroup +# On HPUX you may not be able to use shared memory as nobody, and the +# suggested workaround is to create a user www and use that user. +User nobody +Group #-1 + +# The following directive disables keepalives and HTTP header flushes for +# Netscape 2.x and browsers which spoof it. There are known problems with +# these + +BrowserMatch Mozilla/2 nokeepalive + +# ServerAdmin: Your address, where problems with the server should be +# e-mailed. + +ServerAdmin you@your.address + +# ServerRoot: The directory the server's config, error, and log files +# are kept in + +ServerRoot /usr/local/etc/httpd + +# BindAddress: You can support virtual hosts with this option. This option +# is used to tell the server which IP address to listen to. It can either +# contain "*", an IP address, or a fully qualified Internet domain name. +# See also the VirtualHost directive. + +#BindAddress * + +# ErrorLog: The location of the error log file. If this does not start +# with /, ServerRoot is prepended to it. + +ErrorLog logs/error_log + +# TransferLog: The location of the transfer log file. If this does not +# start with /, ServerRoot is prepended to it. + +TransferLog logs/access_log + +# PidFile: The file the server should log its pid to +PidFile logs/httpd.pid + +# ScoreBoardFile: File used to store internal server process information. +# Not all architectures require this. But if yours does (you'll know because +# this file is created when you run Apache) then you *must* ensure that +# no two invocations of Apache share the same scoreboard file. +ScoreBoardFile logs/apache_status + +# ServerName allows you to set a host name which is sent back to clients for +# your server if it's different than the one the program would get (i.e. use +# "www" instead of the host's real name). +# +# Note: You cannot just invent host names and hope they work. The name you +# define here must be a valid DNS name for your host. If you don't understand +# this, ask your network administrator. + +#ServerName new.host.name + +# CacheNegotiatedDocs: By default, Apache sends Pragma: no-cache with each +# document that was negotiated on the basis of content. This asks proxy +# servers not to cache the document. Uncommenting the following line disables +# this behavior, and proxies will be allowed to cache the documents. + +#CacheNegotiatedDocs + +# Timeout: The number of seconds before receives and sends time out + +Timeout 300 + +# KeepAlive: Whether or not to allow persistent connections (more than +# one request per connection). Set to "Off" to deactivate. + +KeepAlive On + +# MaxKeepAliveRequests: The maximum number of requests to allow +# during a persistent connection. Set to 0 to allow an unlimited amount. +# We reccomend you leave this number high, for maximum performance. + +MaxKeepAliveRequests 100 + +# KeepAliveTimeout: Number of seconds to wait for the next request + +KeepAliveTimeout 15 + +# Server-pool size regulation. Rather than making you guess how many +# server processes you need, Apache dynamically adapts to the load it +# sees --- that is, it tries to maintain enough server processes to +# handle the current load, plus a few spare servers to handle transient +# load spikes (e.g., multiple simultaneous requests from a single +# Netscape browser). + +# It does this by periodically checking how many servers are waiting +# for a request. If there are fewer than MinSpareServers, it creates +# a new spare. If there are more than MaxSpareServers, some of the +# spares die off. These values are probably OK for most sites --- + +MinSpareServers 5 +MaxSpareServers 10 + +# Number of servers to start --- should be a reasonable ballpark figure. + +StartServers 5 + +# Limit on total number of servers running, i.e., limit on the number +# of clients who can simultaneously connect --- if this limit is ever +# reached, clients will be LOCKED OUT, so it should NOT BE SET TOO LOW. +# It is intended mainly as a brake to keep a runaway server from taking +# Unix with it as it spirals down... + +MaxClients 150 + +# MaxRequestsPerChild: the number of requests each child process is +# allowed to process before the child dies. +# The child will exit so as to avoid problems after prolonged use when +# Apache (and maybe the libraries it uses) leak. On most systems, this +# isn't really needed, but a few (such as Solaris) do have notable leaks +# in the libraries. + +MaxRequestsPerChild 30 + +# Proxy Server directives. Uncomment the following line to +# enable the proxy server: + +#ProxyRequests On + +# To enable the cache as well, edit and uncomment the following lines: + +#CacheRoot /usr/local/etc/httpd/proxy +#CacheSize 5 +#CacheGcInterval 4 +#CacheMaxExpire 24 +#CacheLastModifiedFactor 0.1 +#CacheDefaultExpire 1 +#NoCache a_domain.com another_domain.edu joes.garage_sale.com + +# Listen: Allows you to bind Apache to specific IP addresses and/or +# ports, in addition to the default. See also the VirtualHost command + +#Listen 3000 +#Listen 12.34.56.78:80 + +# VirtualHost: Allows the daemon to respond to requests for more than one +# server address, if your server machine is configured to accept IP packets +# for multiple addresses. This can be accomplished with the ifconfig +# alias flag, or through kernel patches like VIF. + +# Any httpd.conf or srm.conf directive may go into a VirtualHost command. +# See alto the BindAddress entry. + +# +#ServerAdmin webmaster@host.some_domain.com +#DocumentRoot /www/docs/host.some_domain.com +#ServerName host.some_domain.com +#ErrorLog logs/host.some_domain.com-error_log +#TransferLog logs/host.some_domain.com-access_log +# + + diff --git a/APACHE_1_2_X/conf/mime.types b/APACHE_1_2_X/conf/mime.types new file mode 100644 index 00000000000..b662c16b67c --- /dev/null +++ b/APACHE_1_2_X/conf/mime.types @@ -0,0 +1,98 @@ +# This is a comment. I love comments. + +application/activemessage +application/andrew-inset +application/applefile +application/atomicmail +application/dca-rft +application/dec-dx +application/mac-binhex40 hqx +application/mac-compactpro cpt +application/macwriteii +application/msword doc +application/news-message-id +application/news-transmission +application/octet-stream bin dms lha lzh exe class +application/oda oda +application/pdf pdf +application/postscript ai eps ps +application/powerpoint ppt +application/remote-printing +application/rtf rtf +application/slate +application/wita +application/wordperfect5.1 +application/x-bcpio bcpio +application/x-cdlink vcd +application/x-compress +application/x-cpio cpio +application/x-csh csh +application/x-director dcr dir dxr +application/x-dvi dvi +application/x-gtar gtar +application/x-gzip +application/x-hdf hdf +application/x-koan skp skd skt skm +application/x-latex latex +application/x-mif mif +application/x-netcdf nc cdf +application/x-sh sh +application/x-shar shar +application/x-stuffit sit +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-tar tar +application/x-tcl tcl +application/x-tex tex +application/x-texinfo texinfo texi +application/x-troff t tr roff +application/x-troff-man man +application/x-troff-me me +application/x-troff-ms ms +application/x-ustar ustar +application/x-wais-source src +application/zip zip +audio/basic au snd +audio/midi mid midi kar +audio/mpeg mpga mp2 +audio/x-aiff aif aiff aifc +audio/x-pn-realaudio ram +audio/x-pn-realaudio-plugin rpm +audio/x-realaudio ra +audio/x-wav wav +chemical/x-pdb pdb xyz +image/gif gif +image/ief ief +image/jpeg jpeg jpg jpe +image/png png +image/tiff tiff tif +image/x-cmu-raster ras +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-rgb rgb +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd +message/external-body +message/news +message/partial +message/rfc822 +multipart/alternative +multipart/appledouble +multipart/digest +multipart/mixed +multipart/parallel +text/html html htm +text/plain txt +text/richtext rtx +text/tab-separated-values tsv +text/x-setext etx +text/x-sgml sgml sgm +video/mpeg mpeg mpg mpe +video/quicktime qt mov +video/x-msvideo avi +video/x-sgi-movie movie +x-conference/x-cooltalk ice +x-world/x-vrml wrl vrml diff --git a/APACHE_1_2_X/conf/srm.conf-dist b/APACHE_1_2_X/conf/srm.conf-dist new file mode 100644 index 00000000000..40102cd03ce --- /dev/null +++ b/APACHE_1_2_X/conf/srm.conf-dist @@ -0,0 +1,206 @@ +# With this document, you define the name space that users see of your http +# server. This file also defines server settings which affect how requests are +# serviced, and how results should be formatted. + +# See the tutorials at http://www.apache.org/ for +# more information. + +# Originally by Rob McCool; Adapted for Apache + + +# DocumentRoot: The directory out of which you will serve your +# documents. By default, all requests are taken from this directory, but +# symbolic links and aliases may be used to point to other locations. + +DocumentRoot /usr/local/etc/httpd/htdocs + +# UserDir: The name of the directory which is appended onto a user's home +# directory if a ~user request is recieved. + +UserDir public_html + +# DirectoryIndex: Name of the file or files to use as a pre-written HTML +# directory index. Separate multiple entries with spaces. + +DirectoryIndex index.html + +# FancyIndexing is whether you want fancy directory indexing or standard + +FancyIndexing on + +# AddIcon tells the server which icon to show for different files or filename +# extensions + +AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip + +AddIconByType (TXT,/icons/text.gif) text/* +AddIconByType (IMG,/icons/image2.gif) image/* +AddIconByType (SND,/icons/sound2.gif) audio/* +AddIconByType (VID,/icons/movie.gif) video/* + +AddIcon /icons/binary.gif .bin .exe +AddIcon /icons/binhex.gif .hqx +AddIcon /icons/tar.gif .tar +AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv +AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip +AddIcon /icons/a.gif .ps .ai .eps +AddIcon /icons/layout.gif .html .shtml .htm .pdf +AddIcon /icons/text.gif .txt +AddIcon /icons/c.gif .c +AddIcon /icons/p.gif .pl .py +AddIcon /icons/f.gif .for +AddIcon /icons/dvi.gif .dvi +AddIcon /icons/uuencoded.gif .uu +AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl +AddIcon /icons/tex.gif .tex +AddIcon /icons/bomb.gif core + +AddIcon /icons/back.gif .. +AddIcon /icons/hand.right.gif README +AddIcon /icons/folder.gif ^^DIRECTORY^^ +AddIcon /icons/blank.gif ^^BLANKICON^^ + +# DefaultIcon is which icon to show for files which do not have an icon +# explicitly set. + +DefaultIcon /icons/unknown.gif + +# AddDescription allows you to place a short description after a file in +# server-generated indexes. +# Format: AddDescription "description" filename + +# ReadmeName is the name of the README file the server will look for by +# default. Format: ReadmeName name +# +# The server will first look for name.html, include it if found, and it will +# then look for name and include it as plaintext if found. +# +# HeaderName is the name of a file which should be prepended to +# directory indexes. + +ReadmeName README +HeaderName HEADER + +# IndexIgnore is a set of filenames which directory indexing should ignore +# Format: IndexIgnore name1 name2... + +IndexIgnore */.??* *~ *# */HEADER* */README* */RCS + +# AccessFileName: The name of the file to look for in each directory +# for access control information. + +AccessFileName .htaccess + +# DefaultType is the default MIME type for documents which the server +# cannot find the type of from filename extensions. + +DefaultType text/plain + +# AddEncoding allows you to have certain browsers (Mosaic/X 2.1+) uncompress +# information on the fly. Note: Not all browsers support this. + +AddEncoding x-compress Z +AddEncoding x-gzip gz + +# AddLanguage allows you to specify the language of a document. You can +# then use content negotiation to give a browser a file in a language +# it can understand. Note that the suffix does not have to be the same +# as the language keyword --- those with documents in Polish (whose +# net-standard language code is pl) may wish to use "AddLanguage pl .po" +# to avoid the ambiguity with the common suffix for perl scripts. + +AddLanguage en .en +AddLanguage fr .fr +AddLanguage de .de +AddLanguage da .da +AddLanguage el .el +AddLanguage it .it + +# LanguagePriority allows you to give precedence to some languages +# in case of a tie during content negotiation. +# Just list the languages in decreasing order of preference. + +LanguagePriority en fr de + +# Redirect allows you to tell clients about documents which used to exist in +# your server's namespace, but do not anymore. This allows you to tell the +# clients where to look for the relocated document. +# Format: Redirect fakename url + + +# Aliases: Add here as many aliases as you need (with no limit). The format is +# Alias fakename realname + +# Note that if you include a trailing / on fakename then the server will +# require it to be present in the URL. So "/icons" isn't aliased in this +# example. + +#Alias /icons/ /usr/local/etc/httpd/icons/ + +# ScriptAlias: This controls which directories contain server scripts. +# Format: ScriptAlias fakename realname + +#ScriptAlias /cgi-bin/ /usr/local/etc/httpd/cgi-bin/ + +# If you want to use server side includes, or CGI outside +# ScriptAliased directories, uncomment the following lines. + +# AddType allows you to tweak mime.types without actually editing it, or to +# make certain files to be certain types. +# Format: AddType type/subtype ext1 + +# AddHandler allows you to map certain file extensions to "handlers", +# actions unrelated to filetype. These can be either built into the server +# or added with the Action command (see below) +# Format: AddHandler action-name ext1 + +# To use CGI scripts: +#AddHandler cgi-script .cgi + +# To use server-parsed HTML files +#AddType text/html .shtml +#AddHandler server-parsed .shtml + +# Uncomment the following line to enable Apache's send-asis HTTP file +# feature +#AddHandler send-as-is asis + +# If you wish to use server-parsed imagemap files, use +#AddHandler imap-file map + +# To enable type maps, you might want to use +#AddHandler type-map var + +# Action lets you define media types that will execute a script whenever +# a matching file is called. This eliminates the need for repeated URL +# pathnames for oft-used CGI file processors. +# Format: Action media/type /cgi-script/location +# Format: Action handler-name /cgi-script/location + +# MetaDir: specifies the name of the directory in which Apache can find +# meta information files. These files contain additional HTTP headers +# to include when sending the document + +#MetaDir .web + +# MetaSuffix: specifies the file name suffix for the file containing the +# meta information. + +#MetaSuffix .meta + +# Customizable error response (Apache style) +# these come in three flavors +# +# 1) plain text +#ErrorDocument 500 "The server made a boo boo. +# n.b. the (") marks it as text, it does not get output +# +# 2) local redirects +#ErrorDocument 404 /missing.html +# to redirect to local url /missing.html +#ErrorDocument 404 /cgi-bin/missing_handler.pl +# n.b. can redirect to a script or a document using server-side-includes. +# +# 3) external redirects +#ErrorDocument 402 http://some.other_server.com/subscription_info.html +# diff --git a/APACHE_1_2_X/htdocs/apache_pb.gif b/APACHE_1_2_X/htdocs/apache_pb.gif new file mode 100644 index 00000000000..3a1c139fc42 Binary files /dev/null and b/APACHE_1_2_X/htdocs/apache_pb.gif differ diff --git a/APACHE_1_2_X/htdocs/index.html b/APACHE_1_2_X/htdocs/index.html new file mode 100644 index 00000000000..a454ba31623 --- /dev/null +++ b/APACHE_1_2_X/htdocs/index.html @@ -0,0 +1,23 @@ + +Test Page for Apache + + +

It Worked!

+ +If you can see this, then your +Apache installation was +successful. You may now add content to this directory and +replace this page. + +

+The Apache documentation has been +included with this distribution. + +

+You are free to use the image below on an Apache-powered web +server. Thanks for using Apache! + +

+ + + diff --git a/APACHE_1_2_X/htdocs/manual/LICENSE b/APACHE_1_2_X/htdocs/manual/LICENSE new file mode 100644 index 00000000000..ec09d302feb --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/LICENSE @@ -0,0 +1,54 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + + + diff --git a/APACHE_1_2_X/htdocs/manual/TODO b/APACHE_1_2_X/htdocs/manual/TODO new file mode 100644 index 00000000000..975ac8e68ea --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/TODO @@ -0,0 +1,4 @@ +Documentation changes/enhancements needed: + +- Documentation for mod_expires +- Documentation for Satisfy diff --git a/APACHE_1_2_X/htdocs/manual/bind.html b/APACHE_1_2_X/htdocs/manual/bind.html new file mode 100644 index 00000000000..92531681385 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/bind.html @@ -0,0 +1,109 @@ + + +Setting which addresses and ports Apache uses + + + + + +

Setting which addresses and ports Apache uses

+ +
+ +When Apache starts, it connects to some port and address on the +local machine and waits for incoming requests. By default, it +listens to all addresses on the machine, and to the port +as specified by the Port directive in the server configuration. +However, it can be told to listen to more the one port, or to listen +to only selected addresses, or a combination. This is often combined +with the Virtual Host feature which determines how Apache +responds to different IP addresses, hostnames and ports.

+ +There are two directives used to restrict or specify which addresses +and ports Apache listens to. + +

    +
  • BindAddress is used to restrict the server to listening to + a single address, and can be used to permit multiple Apache servers + on the same machine listening to different IP addresses. +
  • Listen can be used to make a single Apache server listen + to more than one address and/or port. +
+ +

BindAddress

+Syntax: BindAddress [ * | IP-address | hostname ]
+Default: BindAddress *
+Context: server config
+Status: Core

+ +Makes the server listen to just the specified address. If the argument +is *, the server listens to all addresses. The port listened to +is set with the Port directive. Only one BindAddress +should be used. + +

Listen

+Syntax: Listen [ port | IP-address:port ]
+Default: none
+Context: server config
+Status: Core

+ +Listen can be used instead of BindAddress and +Port. It tells the server to accept incoming requests on the +specified port or address-and-port combination. If the first format is +used, with a port number only, the server listens to the given port on +all interfaces, instead of the port given by the Port +directive. If an IP address is given as well as a port, the server +will listen on the given port and interface.

Multiple Listen +directives may be used to specify a number of addresses and ports to +listen to. The server will respond to requests from any of the listed +addresses and ports.

+ +For example, to make the server accept connections on both port +80 and port 8000, use: +

+   Listen 80
+   Listen 8000
+
+ +To make the server accept connections on two specified +interfaces and port numbers, use +
+   Listen 192.170.2.1:80
+   Listen 192.170.2.5:8000
+
+ +

How this works with Virtual Hosts

+ +BindAddress and Listen do not implement Virtual Hosts. They tell the +main server what addresses and ports to listen to. If no +<VirtualHost> directives are used, the server will behave the +same for all accepted requests. However, <VirtualHost> can be +used to specify a different behavior for one or more of the addresses +and ports. To implement a VirtualHost, the server must first be told +to listen to the address and port to be used. Then a +<VirtualHost> section should be created for a specified address +and port to set the behavior of this virtual host. Note that if the +<VirtualHost> is set for an address and port that the server is +not listening to, it cannot be accessed. + +

See also

+ +See also the documentation on +Virtual Hosts, +Non-IP virtual hosts, +BindAddress directive, +Port directive, +DNS Issues +and +<VirtualHost> section. + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/cgi_path.html b/APACHE_1_2_X/htdocs/manual/cgi_path.html new file mode 100644 index 00000000000..8ac3bc0dd19 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/cgi_path.html @@ -0,0 +1,93 @@ + + +PATH_INFO Changes in the CGI Environment + + + + + +

PATH_INFO Changes in the CGI Environment

+ +
+ +

Overview

+ +

As implemented in Apache 1.1.1 and earlier versions, the method +Apache used to create PATH_INFO in the CGI environment was +counterintuitive, and could result in crashes in certain cases. In +Apache 1.2 and beyond, this behavior has changed. Although this +results in some compatibility problems with certain legacy CGI +applications, the Apache 1.2 behavior is still compatible with the +CGI/1.1 specification, and CGI scripts can be easily modified (see below). + +

The Problem

+ +

Apache 1.1.1 and earlier implemented the PATH_INFO and SCRIPT_NAME +environment variables by looking at the filename, not the URL. While +this resulted in the correct values in many cases, when the filesystem +path was overloaded to contain path information, it could result in +errant behavior. For example, if the following appeared in a config +file: +

+     Alias /cgi-ralph /usr/local/httpd/cgi-bin/user.cgi/ralph
+
+

In this case, user.cgi is the CGI script, the "/ralph" +is information to be passed onto the CGI. If this configuration was in +place, and a request came for "/cgi-ralph/script/", the +code would set PATH_INFO to "/ralph/script", and +SCRIPT_NAME to "/cgi-". Obviously, the latter is +incorrect. In certain cases, this could even cause the server to +crash.

+ +

The Solution

+ +

Apache 1.2 and later now determine SCRIPT_NAME and PATH_INFO by +looking directly at the URL, and determining how much of the URL is +client-modifiable, and setting PATH_INFO to it. To use the above +example, PATH_INFO would be set to "/script", and +SCRIPT_NAME to "/cgi-ralph". This makes sense and results +in no server behavior problems. It also permits the script to be +guaranteed that +"http://$SERVER_NAME:$SERVER_PORT$SCRIPT_NAME$PATH_INFO" +will always be an accessible URL that points to the current script, +something which was not necessarily true with previous versions of +Apache. + +

However, the "/ralph" +information from the Alias directive is lost. This is +unfortunate, but we feel that using the filesystem to pass along this +sort of information is not a recommended method, and a script making +use of it "deserves" not to work. Apache 1.2b3 and later, however, do +provide a workaround. + +

Compatibility with Previous Servers

+ +

It may be necessary for a script that was designed for earlier +versions of Apache or other servers to need the information that the +old PATH_INFO variable provided. For this purpose, Apache 1.2 (1.2b3 +and later) sets an additional variable, FILEPATH_INFO. This +environment variable contains the value that PATH_INFO would have had +with Apache 1.1.1.

+ +

A script that wishes to work with both Apache 1.2 and earlier +versions can simply test for the existence of FILEPATH_INFO, and use +it if available. Otherwise, it can use PATH_INFO. For example, in +Perl, one might use: +

+    $path_info = $ENV{'FILEPATH_INFO'} || $ENV{'PATH_INFO'};
+
+ +

By doing this, a script can work with all servers supporting the +CGI/1.1 specification, including all versions of Apache.

+ + + + + diff --git a/APACHE_1_2_X/htdocs/manual/content-negotiation.html b/APACHE_1_2_X/htdocs/manual/content-negotiation.html new file mode 100644 index 00000000000..2aa06eb32fb --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/content-negotiation.html @@ -0,0 +1,426 @@ + + + +Apache Content Negotiation + + + + + +

Content Negotiation

+ +Apache's support for content negotiation has been updated to meet the +HTTP/1.1 specification. It can choose the best representation of a +resource based on the browser-supplied preferences for media type, +languages, character set and encoding. It is also implements a +couple of features to give more intelligent handling of requests from +browsers which send incomplete negotiation information.

+ +Content negotiation is provided by the +mod_negotiation module, +which is compiled in by default. + +


+ +

About Content Negotiation

+ +A resource may be available in several different representations. For +example, it might be available in different languages or different +media types, or a combination. One way of selecting the most +appropriate choice is to give the user an index page, and let them +select. However it is often possible for the server to choose +automatically. This works because browsers can send as part of each +request information about what representations they prefer. For +example, a browser could indicate that it would like to see +information in French, if possible, else English will do. Browsers +indicate their preferences by headers in the request. To request only +French representations, the browser would send + +
+  Accept-Language: fr
+
+ +Note that this preference will only be applied when there is a choice +of representations and they vary by language. +

+ +As an example of a more complex request, this browser has been +configured to accept French and English, but prefer French, and to +accept various media types, preferring HTML over plain text or other +text types, and preferring GIF or JPEG over other media types, but also +allowing any other media type as a last resort: + +

+  Accept-Language: fr; q=1.0, en; q=0.5
+  Accept: text/html; q=1.0, text/*; q=0.8, image/gif; q=0.6,
+        image/jpeg; q=0.6, image/*; q=0.5, */*; q=0.1
+
+ +Apache 1.2 supports 'server driven' content negotiation, as defined in +the HTTP/1.1 specification. It fully supports the Accept, +Accept-Language, Accept-Charset and Accept-Encoding request headers. +

+ +The terms used in content negotiation are: a resource is an +item which can be requested of a server, which might be selected as +the result of a content negotiation algorithm. If a resource is +available in several formats, these are called representations +or variants. The ways in which the variants for a particular +resource vary are called the dimensions of negotiation. + +

Negotiation in Apache

+ +In order to negotiate a resource, the server needs to be given +information about each of the variants. This is done in one of two +ways: + +
    +
  • Using a type map (i.e., a *.var file) which + names the files containing the variants explicitly +
  • Or using a 'MultiViews' search, where the server does an implicit + filename pattern match, and chooses from among the results. +
+ +

Using a type-map file

+ +A type map is a document which is associated with the handler +named type-map (or, for backwards-compatibility with +older Apache configurations, the mime type +application/x-type-map). Note that to use this feature, +you've got to have a SetHandler some place which defines a +file suffix as type-map; this is best done with a +
+
+  AddHandler type-map var
+
+
+in srm.conf. See comments in the sample config files for +details.

+ +Type map files have an entry for each available variant; these entries +consist of contiguous RFC822-format header lines. Entries for +different variants are separated by blank lines. Blank lines are +illegal within an entry. It is conventional to begin a map file with +an entry for the combined entity as a whole (although this +is not required, and if present will be ignored). An example +map file is: +

+
+  URI: foo
+
+  URI: foo.en.html
+  Content-type: text/html
+  Content-language: en
+
+  URI: foo.fr.de.html
+  Content-type: text/html; charset=iso-8859-2
+  Content-language: fr, de
+
+ +If the variants have different source qualities, that may be indicated +by the "qs" parameter to the media type, as in this picture (available +as jpeg, gif, or ASCII-art): +
+  URI: foo
+
+  URI: foo.jpeg
+  Content-type: image/jpeg; qs=0.8
+
+  URI: foo.gif
+  Content-type: image/gif; qs=0.5
+
+  URI: foo.txt
+  Content-type: text/plain; qs=0.01
+
+
+

+ +qs values can vary between 0.000 and 1.000. Note that any variant with +a qs value of 0.000 will never be chosen. Variants with no 'qs' +parameter value are given a qs factor of 1.0.

+ +The full list of headers recognized is: + +

+
URI: +
uri of the file containing the variant (of the given media + type, encoded with the given content encoding). These are + interpreted as URLs relative to the map file; they must be on + the same server (!), and they must refer to files to which the + client would be granted access if they were to be requested + directly. +
Content-type: +
media type --- charset, level and "qs" parameters may be given. These + are often referred to as MIME types; typical media types are + image/gif, text/plain, or + text/html; level=3. +
Content-language: +
The languages of the variant, specified as an Internet standard + language code (e.g., en for English, + kr for Korean, etc.). +
Content-encoding: +
If the file is compressed, or otherwise encoded, rather than + containing the actual raw data, this says how that was done. + For compressed files (the only case where this generally comes + up), content encoding should be + x-compress, or x-gzip, as appropriate. +
Content-length: +
The size of the file. Clients can ask to receive a given media + type only if the variant isn't too big; specifying a content + length in the map allows the server to compare against these + thresholds without checking the actual file. +
+ +

Multiviews

+ +This is a per-directory option, meaning it can be set with an +Options directive within a <Directory>, +<Location> or <Files> +section in access.conf, or (if AllowOverride +is properly set) in .htaccess files. Note that +Options All does not set MultiViews; you +have to ask for it by name. (Fixing this is a one-line change to +http_core.h). + +

+ +The effect of MultiViews is as follows: if the server +receives a request for /some/dir/foo, if +/some/dir has MultiViews enabled, and +/some/dir/foo does not exist, then the server reads the +directory looking for files named foo.*, and effectively fakes up a +type map which names all those files, assigning them the same media +types and content-encodings it would have if the client had asked for +one of them by name. It then chooses the best match to the client's +requirements, and forwards them along. + +

+ +This applies to searches for the file named by the +DirectoryIndex directive, if the server is trying to +index a directory; if the configuration files specify +

+
+  DirectoryIndex index
+
+
then the server will arbitrate between index.html +and index.html3 if both are present. If neither are +present, and index.cgi is there, the server will run it. + +

+ +If one of the files found when reading the directive is a CGI script, +it's not obvious what should happen. The code gives that case +special treatment --- if the request was a POST, or a GET with +QUERY_ARGS or PATH_INFO, the script is given an extremely high quality +rating, and generally invoked; otherwise it is given an extremely low +quality rating, which generally causes one of the other views (if any) +to be retrieved. + +

The Negotiation Algorithm

+ +After Apache has obtained a list of the variants for a given resource, +either from a type-map file or from the filenames in the directory, it +applies a algorithm to decide on the 'best' variant to return, if +any. To do this it calculates a quality value for each variant in each +of the dimensions of variance. It is not necessary to know any of the +details of how negotiation actually takes place in order to use Apache's +content negotiation features. However the rest of this document +explains in detail the algorithm used for those interested.

+ +In some circumstances, Apache can 'fiddle' the quality factor of a +particular dimension to achieve a better result. The ways Apache can +fiddle quality factors is explained in more detail below. + +

Dimensions of Negotiation

+ + +
Dimension +Notes +
Media Type +Browser indicates preferences on Accept: header. Each item +can have an associated quality factor. Variant description can also +have a quality factor. +
Language +Browser indicates preferences on Accept-Language: header. Each +item +can have a quality factor. Variants can be associated with none, one +or more languages. +
Encoding +Browser indicates preference with Accept-Encoding: header. +
Charset +Browser indicates preference with Accept-Charset: header. Variants +can indicate a charset as a parameter of the media type. +
+ +

Apache Negotiation Algorithm

+ +Apache uses an algorithm to select the 'best' variant (if any) to +return to the browser. This algorithm is not configurable. It operates +like this: +

+ +

    +
  1. +Firstly, for each dimension of the negotiation, the appropriate +Accept header is checked and a quality assigned to this each +variant. If the Accept header for any dimension means that this +variant is not acceptable, eliminate it. If no variants remain, go +to step 4. + +
  2. Select the 'best' variant by a process of elimination. Each of +the following tests is applied in order. Any variants not selected at +each stage are eliminated. After each test, if only one variant +remains, it is selected as the best match. If more than one variant +remains, move onto the next test. + +
      +
    1. Multiply the quality factor from the Accept header with the + quality-of-source factor for this variant's media type, and select + the variants with the highest value + +
    2. Select the variants with the highest language quality factor + +
    3. Select the variants with the best language match, using either the + order of languages on the LanguagePriority directive (if present), + else the order of languages on the Accept-Language header. + +
    4. Select the variants with the highest 'level' media parameter + (used to give the version of text/html media types). + +
    5. Select only unencoded variants, if there is a mix of encoded + and non-encoded variants. If either all variants are encoded + or all variants are not encoded, select all. + +
    6. Select only variants with acceptable charset media parameters, + as given on the Accept-Charset header line. Charset ISO-8859-1 + is always acceptable. Variants not associated with a particular + charset are assumed to be in ISO-8859-1. + +
    7. Select the variants with the smallest content length + +
    8. Select the first variant of those remaining (this will be either the +first listed in the type-map file, or the first read from the directory) +and go to stage 3. + +
    + +
  3. The algorithm has now selected one 'best' variant, so return + it as the response. The HTTP response header Vary is set to indicate the + dimensions of negotiation (browsers and caches can use this + information when caching the resource). End. + +
  4. To get here means no variant was selected (because non are acceptable + to the browser). Return a 406 status (meaning "No acceptable representation") + with a response body consisting of an HTML document listing the + available variants. Also set the HTTP Vary header to indicate the + dimensions of variance. + +
+

Fiddling with Quality Values

+ +Apache sometimes changes the quality values from what would be +expected by a strict interpretation of the algorithm above. This is to +get a better result from the algorithm for browsers which do not send +full or accurate information. Some of the most popular browsers send +Accept header information which would otherwise result in the +selection of the wrong variant in many cases. If a browser +sends full and correct information these fiddles will not +be applied. +

+ +

Media Types and Wildcards

+ +The Accept: request header indicates preferences for media types. It +can also include 'wildcard' media types, such as "image/*" or "*/*" +where the * matches any string. So a request including: +
+  Accept: image/*, */*
+
+ +would indicate that any type starting "image/" is acceptable, +as is any other type (so the first "image/*" is redundant). Some +browsers routinely send wildcards in addition to explicit types they +can handle. For example: +
+  Accept: text/html, text/plain, image/gif, image/jpeg, */*
+
+ +The intention of this is to indicate that the explicitly +listed types are preferred, but if a different representation is +available, that is ok too. However under the basic algorithm, as given +above, the */* wildcard has exactly equal preference to all the other +types, so they are not being preferred. The browser should really have +sent a request with a lower quality (preference) value for *.*, such +as: +
+  Accept: text/html, text/plain, image/gif, image/jpeg, */*; q=0.01
+
+ +The explicit types have no quality factor, so they default to a +preference of 1.0 (the highest). The wildcard */* is given +a low preference of 0.01, so other types will only be returned if +no variant matches an explicitly listed type. +

+ +If the Accept: header contains no q factors at all, Apache sets +the q value of "*/*", if present, to 0.01 to emulate the desired +behavior. It also sets the q value of wildcards of the format +"type/*" to 0.02 (so these are preferred over matches against +"*/*". If any media type on the Accept: header contains a q factor, +these special values are not applied, so requests from browsers +which send the correct information to start with work as expected. + +

Variants with no Language

+ +If some of the variants for a particular resource have a language +attribute, and some do not, those variants with no language +are given a very low language quality factor of 0.001.

+ +The reason for setting this language quality factor for +variant with no language to a very low value is to allow +for a default variant which can be supplied if none of the +other variants match the browser's language preferences. + +For example, consider the situation with three variants: + +

    +
  • foo.en.html, language en +
  • foo.fr.html, language en +
  • foo.html, no language +
+ +The meaning of a variant with no language is that it is +always acceptable to the browser. If the request Accept-Language +header includes either en or fr (or both) one of foo.en.html +or foo.fr.html will be returned. If the browser does not list +either en or fr as acceptable, foo.html will be returned instead. + +

Note on Caching

+ +When a cache stores a document, it associates it with the request URL. +The next time that URL is requested, the cache can use the stored +document, provided it is still within date. But if the resource is +subject to content negotiation at the server, this would result in +only the first requested variant being cached, and subsequent cache +hits could return the wrong response. To prevent this, +Apache normally marks all responses that are returned after content negotiation +as non-cacheable by HTTP/1.0 clients. Apache also supports the HTTP/1.1 +protocol features to allow caching of negotiated responses.

+ +For requests which come from a HTTP/1.0 compliant client (either a +browser or a cache), the directive CacheNegotiatedDocs can be +used to allow caching of responses which were subject to negotiation. +This directive can be given in the server config or virtual host, and +takes no arguments. It has no effect on requests from HTTP/1.1 +clients. + + + + diff --git a/APACHE_1_2_X/htdocs/manual/custom-error.html b/APACHE_1_2_X/htdocs/manual/custom-error.html new file mode 100644 index 00000000000..3f04af058b0 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/custom-error.html @@ -0,0 +1,153 @@ + + + +Custom error responses + + + + + +

Custom error responses

+ +
+ +
Purpose + +
Additional functionality. Allows webmasters to configure the response of + Apache to some error or problem. + +

Customizable responses can be defined to be activated in the + event of a server detected error or problem. + +

e.g. if a script crashes and produces a "500 Server Error" + response, then this response can be replaced with either some + friendlier text or by a redirection to another URL (local or + external). + +

+ +

Old behavior + +
NCSA httpd 1.3 would return some boring old error/problem message + which would often be meaningless to the user, and would provide no + means of logging the symptoms which caused it.
+ +

+ +

New behavior + +
The server can be asked to; +
    +
  1. Display some other text, instead of the NCSA hard coded messages, or +
  2. redirect to a local URL, or +
  3. redirect to an external URL. +
+ +

Redirecting to another URL can be useful, but only if some information + can be passed which can then be used to explain and/or log the error/problem + more clearly. + +

To achieve this, Apache will define new CGI-like environment + variables, e.g. + +

+REDIRECT_HTTP_ACCEPT=*/*, image/gif, image/x-xbitmap, image/jpeg
+REDIRECT_HTTP_USER_AGENT=Mozilla/1.1b2 (X11; I; HP-UX A.09.05 9000/712)
+REDIRECT_PATH=.:/bin:/usr/local/bin:/etc
+REDIRECT_QUERY_STRING=
+REDIRECT_REMOTE_ADDR=121.345.78.123
+REDIRECT_REMOTE_HOST=ooh.ahhh.com
+REDIRECT_SERVER_NAME=crash.bang.edu
+REDIRECT_SERVER_PORT=80
+REDIRECT_SERVER_SOFTWARE=Apache/0.8.15
+REDIRECT_URL=/cgi-bin/buggy.pl
+
+ +

note the REDIRECT_ prefix. + +

At least REDIRECT_URL and REDIRECT_QUERY_STRING will + be passed to the new URL (assuming it's a cgi-script or a cgi-include). The + other variables will exist only if they existed prior to the error/problem. + None of these will be set if your ErrorDocument is an + external redirect (i.e. anything starting with a protocol name + like http:, even if it refers to the same host as the + server).

+ +

Configuration + +
Use of "ErrorDocument" is enabled for .htaccess files when the + "FileInfo" override is allowed. + +

Here are some examples... + +

+ErrorDocument 500 /cgi-bin/crash-recover
+ErrorDocument 500 "Sorry, our script crashed. Oh dear
+ErrorDocument 500 http://xxx/
+ErrorDocument 404 /Lame_excuses/not_found.html
+ErrorDocument 401 /Subscription/how_to_subscribe.html +
+ +

The syntax is, + +

ErrorDocument +<3-digit-code> action + +

where the action can be, + +

    +
  1. Text to be displayed. Prefix the text with a quote ("). Whatever + follows the quote is displayed. Note: the (") prefix isn't + displayed. + +
  2. An external URL to redirect to. + +
  3. A local URL to redirect to. + +
+
+ +


+ +

Custom error responses and redirects

+ +
+ +
Purpose + +
Apache's behavior to redirected URLs has been modified so that additional + environment variables are available to a script/server-include.

+ +

Old behavior + +
Standard CGI vars were made available to a script which has been + redirected to. No indication of where the redirection came from was provided. + +

+ +

New behavior +
+ +A new batch of environment variables will be initialized for use by a +script which has been redirected to. Each new variable will have the +prefix REDIRECT_. REDIRECT_ environment +variables are created from the CGI environment variables which existed +prior to the redirect, they are renamed with a REDIRECT_ +prefix, i.e. HTTP_USER_AGENT becomes +REDIRECT_HTTP_USER_AGENT. In addition to these new +variables, Apache will define REDIRECT_URL and +REDIRECT_STATUS to help the script trace its origin. +Both the original URL and the URL being redirected to can be logged in +the access log. + +
+ + + + diff --git a/APACHE_1_2_X/htdocs/manual/dns-caveats.html b/APACHE_1_2_X/htdocs/manual/dns-caveats.html new file mode 100644 index 00000000000..50a9bcfe8fe --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/dns-caveats.html @@ -0,0 +1,201 @@ + + +Issues Regarding DNS and Apache + + + + + +

Issues Regarding DNS and Apache

+ +

This page could be summarized with the statement: don't require +Apache to use DNS for any parsing of the configuration files. +If Apache has to use DNS to parse the configuration files then your +server may be subject to reliability problems (it might not boot), or +denial and theft of service attacks (including users able to steal hits +from other users). + +

A Simple Example

+ +Consider this configuration snippet: + +
+    <VirtualHost www.abc.dom>
+    ServerAdmin webgirl@abc.dom
+    DocumentRoot /www/abc
+    </VirtualHost>
+
+ +

In order for Apache to function properly it absolutely needs +to have two pieces of information about each virtual host: the +ServerName +and at least one IP address that the server +responds to. This example does not include the IP address, so Apache +must use DNS to find the address of www.abc.dom. If for +some reason DNS is not available at the time your server is parsing its +config file, then this virtual host will not be configured. It +won't be able to respond to any hits to this virtual host (prior to +Apache version 1.2 the server would not even boot). + +

Suppose that www.abc.dom has address 10.0.0.1. Then +consider this configuration snippet: + +

+    <VirtualHost 10.0.0.1>
+    ServerAdmin webgirl@abc.dom
+    DocumentRoot /www/abc
+    </VirtualHost>
+
+ +

Now Apache needs to use reverse DNS to find the ServerName +for this virtualhost. If that reverse lookup fails then it will partially +disable the virtualhost (prior to Apache version 1.2 the server would not +even boot). If the virtual host is name-based then it will effectively +be totally disabled, but if it is IP-based then it will mostly work. +However if Apache should ever have to generate a full URL for the server +which includes the server name then it will fail to generate a valid URL. + +

Here is a snippet that avoids both of these problems. + +

+    <VirtualHost 10.0.0.1>
+    ServerName www.abc.dom
+    ServerAdmin webgirl@abc.dom
+    DocumentRoot /www/abc
+    </VirtualHost>
+
+ +

Denial of Service

+ +

There are (at least) two forms that denial of service can come in. +If you are running a version of Apache prior to version 1.2 then your +server will not even boot if one of the two DNS lookups mentioned above +fails for any of your virtual hosts. In some cases this DNS lookup may +not even be under your control. For example, if abc.dom +is one of your customers and they control their own DNS then they +can force your (pre-1.2) server to fail while booting simply by deleting the +www.abc.dom record. + +

Another form is far more insidious. Consider this configuration +snippet: + +

+    <VirtualHost www.abc.dom>
+    ServerAdmin webgirl@abc.dom
+    DocumentRoot /www/abc
+    </VirtualHost>
+
+ +
+    <VirtualHost www.def.dom>
+    ServerAdmin webguy@def.dom
+    DocumentRoot /www/def
+    </VirtualHost>
+
+ +

Suppose that you've assigned 10.0.0.1 to www.abc.dom and +10.0.0.2 to www.def.dom. Furthermore, suppose that +def.com has control of their own DNS. With this config +you have put def.com into a position where they can steal +all traffic destined to abc.com. To do so, all they have to +do is set www.def.dom to 10.0.0.1. +Since they control their own DNS you can't stop them from pointing the +www.def.com record wherever they wish. + +

Requests coming in to 10.0.0.1 (including all those where users typed +in URLs of the form http://www.abc.dom/whatever) will all be +served by the def.com virtual host. To better understand why +this happens requires a more in-depth discussion of how Apache matches +up incoming requests with the virtual host that will serve it. A rough +document describing this is available. + +

The "main server" Address

+ +

The addition of non-IP-based virtual host +support in Apache 1.1 requires Apache to know the IP address(es) of +the host that httpd is running on. To get this address it uses either +the global ServerName (if present) or calls the C function +gethostname (which should return the same as typing +"hostname" at the command prompt). Then it performs a DNS lookup on +this address. At present there is no way to avoid this lookup. + +

If you fear that this lookup might fail because your DNS server is down +then you can insert the hostname in /etc/hosts (where you +probably already have it so that the machine can boot properly). Then +ensure that your machine is configured to use /etc/hosts +in the event that DNS fails. Depending on what OS you are using this +might be accomplished by editing /etc/resolv.conf, or maybe +/etc/nsswitch.conf. + +

If your server doesn't have to perform DNS for any other reason +then you might be able to get away with running Apache with the +HOSTRESORDER environment variable set to "local". This all +depends on what OS and resolver libraries you are using. It also affects +CGIs unless you use mod_env +to control the environment. It's best to consult the man pages or FAQs +for your OS. + +

The _default_ Address

+ +

Any address that happens to go to your webserver which doesn't match +the IP address of any of the webservers will be served from the "main" or +"default" server configurations. The "main" server configuration consists +of all those definitions appearing outside of any VirtualHost section. +You may want instead to define a <VirtualHost _default_:*> +which returns 403 or 404 for all hits. (The trailing :* +makes it apply to all ports, which is just a safety measure should you +begin using multiple Listen +directives.) + +

Tips to Avoid these problems

+ +
    +
  • use IP addresses in <VirtualHost> +
  • use IP addresses in Listen +
  • use IP addresses in BindAddress +
  • ensure all virtual hosts have an explicit ServerName +
  • create a <VirtualHost _default_:*> server that + has no pages to serve +
+ +

Appendix: Future Directions

+ +

The situation regarding DNS is highly undesirable. For Apache +1.2 we've attempted to make the server at least continue booting +in the event of failed DNS, but it might not be the best we +can do. In any event requiring the use of explicit IP addresses in +configuration files is highly undesirable in today's Internet where renumbering + is a necessity. + +

A possible work around to the theft of service attack described above +would be to perform a reverse DNS lookup on the ip address returned by +the forward lookup and compare the two names. In the event of a mismatch +the virtualhost would be disabled. This would require reverse DNS to be +configured properly (which is something that most admins are familiar with +because of the common use of "double-reverse" DNS lookups by FTP servers +and TCP wrappers). + +

In any event it doesn't seem possible to reliably boot a virtual-hosted +web server when DNS has failed unless IP addresses are used. Partial +solutions such as disabling portions of the configuration might be worse +than not booting at all depending on what the webserver is supposed +to accomplish. + +

As HTTP/1.1 is deployed and browsers and proxies start issuing the +Host header it will become possible to avoid the use of +IP-based virtual hosts entirely. In this event a webserver has no requirement +to do DNS lookups during configuration. But as of March 1997 these +features have not been deployed widely enough to be put into use on +critical webservers. + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/env.html b/APACHE_1_2_X/htdocs/manual/env.html new file mode 100644 index 00000000000..9ef4f28ff0d --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/env.html @@ -0,0 +1,41 @@ + + + +Special Purpose Environment Variables + + + + + +

Special Purpose Environment Variables

+

Interoperability problems have led to the introduction of +mechanisms to modify the way Apache behaves when talking to particular +clients. To make these mechanisms as flexible as possible, they +are invoked by defining environment variables, typically with +BrowserMatch, though +SetEnv and +PassEnv could also be used, for +example.

+ +

nokeepalive

+This disables KeepAlive when set. Because +of problems with Netscape 2.x and KeepAlive, we recommend the following +directive be used: +
+BrowserMatch Mozilla/2 nokeepalive +
+

force-response-1.0

+This forces an HTTP/1.0 response when set. It was originally implemented as a +result of a problem with AOL's proxies. Some clients may not behave correctly +when given an HTTP/1.1 response, and this can be used to interoperate with +them. + + + + diff --git a/APACHE_1_2_X/htdocs/manual/expand.pl b/APACHE_1_2_X/htdocs/manual/expand.pl new file mode 100755 index 00000000000..37483ad0bda --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/expand.pl @@ -0,0 +1,100 @@ +#!/usr/local/bin/perl5 + +# This is a very simple Perl script to expand server-side includes +# in the directory it is run, and direct subdirectories. It will +# work only on SSI directives of the form +# +# +# +# Filename must be relative to the directory the file appears in. +# +# Nov 30, 1996 - Alexei Kosut + +# ==================================================================== +# Copyright (c) 1996,1997 The Apache Group. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# 3. All advertising materials mentioning features or use of this +# software must display the following acknowledgment: +# "This product includes software developed by the Apache Group +# for use in the Apache HTTP server project (http://www.apache.org/)." +# +# 4. The names "Apache Server" and "Apache Group" must not be used to +# endorse or promote products derived from this software without +# prior written permission. +# +# 5. Redistributions of any form whatsoever must retain the following +# acknowledgment: +# "This product includes software developed by the Apache Group +# for use in the Apache HTTP server project (http://www.apache.org/)." +# +# THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY +# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR +# ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. +# ==================================================================== +# +# This software consists of voluntary contributions made by many +# individuals on behalf of the Apache Group and was originally based +# on public domain software written at the National Center for +# Supercomputing Applications, University of Illinois, Urbana-Champaign. +# For more information on the Apache Group and the Apache HTTP server +# project, please see . + +# Put a list of dirs (except ..) into @dirs + +opendir DIR, "." or die "Could not open directory: $!"; +@dirs = grep !/^\.\.$/, (grep -d, readdir DIR); +closedir DIR; + +foreach $dir (@dirs) { + print "Entering directory $dir\n"; + opendir SUBDIR, "$dir" or die "Could not open subdir $dir: $!"; + foreach $file (grep /\.html$/, readdir SUBDIR) { + print "Expanding file $dir/$file\n"; + rename "$dir/$file", "$dir/${file}.old"; + open READ, "$dir/${file}.old" or die "Couldn't read $dir/$file: $!"; + open WRITE, ">$dir/$file" or die "Couldn't write $dir/$file: $!"; + while ($r = ) { + if ($r =~ //) { + ($pre, $include, $post) = ($`, $1, $'); + print WRITE $pre; + + open INC, "$dir/$include" or + print "Could not include file $dir/$include: $!"; + print WRITE while (); + close INC; + + print WRITE $post; + } + else { + print WRITE $r; + } + } + close READ; + close WRITE; + unlink "$dir/$file.old"; + } + closedir SUBDIR; +} + + diff --git a/APACHE_1_2_X/htdocs/manual/footer.html b/APACHE_1_2_X/htdocs/manual/footer.html new file mode 100644 index 00000000000..d1f330db4bd --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/footer.html @@ -0,0 +1,3 @@ +
+ +Index diff --git a/APACHE_1_2_X/htdocs/manual/handler.html b/APACHE_1_2_X/htdocs/manual/handler.html new file mode 100644 index 00000000000..80592161123 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/handler.html @@ -0,0 +1,141 @@ + + + +Apache's Handler Use + + + + + +

Apache's Handler Use

+ +

What is a Handler

+ +

A "handler" is an internal Apache representation of the action to be +performed when a file is called. Generally, files have implicit +handlers, based on the file type. Normally, all files are simply +served by the server, but certain file typed are "handled" +separately. For example, you may use a type of +"application/x-httpd-cgi" to invoke CGI scripts.

+ +

Apache 1.1 adds the additional ability to use handlers +explicitly. Either based on filename extensions or on location, these +handlers are unrelated to file type. This is advantageous both because +it is a more elegant solution, but it also allows for both a type +and a handler to be associated with a file.

+ +

Handlers can either be built into the server or to a module, or +they can be added with the Action directive. The built-in +handlers in the standard distribution are as follows:

+ +
    +
  • send-as-is: + Send file with HTTP headers as is. + (mod_asis) +
  • cgi-script: + Treat the file as a CGI script. + (mod_cgi) +
  • imap-file: + Imagemap rule file. + (mod_imap) +
  • server-info: + Get the server's configuration information + (mod_info) +
  • server-parsed: + Parse for server-side includes + (mod_include) +
  • server-status: + Get the server's status report + (mod_status) +
  • type-map: + Parse as a type map file for content negotiation + (mod_negotiation) +
+ +

+ +

Directives

+ + +
+ +

AddHandler

+ +Syntax: <AddHandler handler-name extension>
+Context: server config, virtual host, directory, .htaccess
+Status: Base
+Module: mod_mime + +

AddHandler maps the filename extension extension to the +handler handler-name. For example, to activate CGI scripts +with the file extension ".cgi", you might use: +

+    AddHandler cgi-script cgi
+
+ +

Once that has been put into your srm.conf or httpd.conf file, any +file ending with ".cgi" will be treated as a CGI +program.

+ +
+ +

SetHandler

+ +Syntax: <SetHandler handler-name>
+Context: directory, .htaccess
+Status: Base
+Module: mod_mime + +

When placed into an .htaccess file or a +<Directory> or <Location> section, +this directive forces all matching files to be parsed through the +handler given by handler-name. For example, if you had a +directory you wanted to be parsed entirely as imagemap rule files, +regardless of extension, you might put the following into an +.htaccess file in that directory: +

+    SetHandler imap-file
+
+

Another example: if you wanted to have the server display a status +report whenever a URL of http://servername/status was +called, you might put the following into access.conf: +

+    <Location /status>
+    SetHandler server-status
+    </Location>
+
+ +


+ +

Programmer's Note

+ +

In order to implement the handler features, an addition has been +made to the Apache API that you may wish to +make use of. Specifically, a new record has been added to the +request_rec structure:

+
+    char *handler
+
+

If you wish to have your module engage a handler, you need only to +set r->handler to the name of the handler at any time +prior to the invoke_handler stage of the +request. Handlers are implemented as they were before, albeit using +the handler name instead of a content type. While it is not +necessary, the naming convention for handlers is to use a +dash-separated word, with no slashes, so as to not invade the media +type name-space.

+ + + + + diff --git a/APACHE_1_2_X/htdocs/manual/header.html b/APACHE_1_2_X/htdocs/manual/header.html new file mode 100644 index 00000000000..a6e66f69a18 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/header.html @@ -0,0 +1,3 @@ +
+ [APACHE DOCUMENTATION] +
diff --git a/APACHE_1_2_X/htdocs/manual/host.html b/APACHE_1_2_X/htdocs/manual/host.html new file mode 100644 index 00000000000..908cd2d2855 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/host.html @@ -0,0 +1,173 @@ + + +Apache non-IP Virtual Hosts + + + + + +

Apache non-IP Virtual Hosts

+ +See Also: +Virtual Host Support + +
+ +

What is a Virtual Host

+ +

The "Virtual Host" refers to the practice of maintaining more than +one server on one machine, as differentiated by their apparent +hostname. For example, it is often desirable for companies sharing a +web server to have their own domains, with web servers accessible as +www.company1.com and www.company2.com, +without requiring the user to know any extra path information.

+ +

Apache was one of the first servers to support virtual hosts right +out of the box, but since the base HTTP (HyperText +Transport Protocol) standard does not allow any method for the server +to determine the hostname it is being addressed as, Apache's virtual +host support has required a separate IP address for each +server. Documentation on using this approach (which still works very +well) is available. + +

While the approach described above works, with the available IP +address space growing smaller, and the number of domains increasing, +it is not the most elegant solution, and is hard to implement on some +machines. The HTTP/1.1 protocol contains a method for the +server to identify what name it is being addressed as. Apache 1.1 and +later support this approach as well as the traditional +IP-address-per-hostname method.

+ +

The benefits of using the new virtual host support is a practically +unlimited number of servers, ease of configuration and use, and +requires no additional hardware or software. The main disadvantage is +that the user's browser must support this part of the protocol. The +latest versions of many browsers (including Netscape Navigator 2.0 and +later) do, but many browsers, especially older ones, do not. This can +cause problems, although a possible solution is addressed below.

+ +

Using non-IP Virtual Hosts

+ +

Using the new virtual hosts is quite easy, and superficially looks +like the old method. You simply add to one of the Apache configuration +files (most likely httpd.conf or srm.conf) +code similar to the following:

+
+    <VirtualHost www.apache.org>
+    ServerName www.apache.org
+    DocumentRoot /usr/web/apache
+    </VirtualHost>
+
+ +

Of course, any additional directives can (and should) be placed +into the <VirtualHost> section. To make this work, +all that is needed is to make sure that the www.apache.org +DNS entry points to the same IP address as the main +server. Optionally, you could simply use that IP address in the +<VirtualHost> entry.

+ +

Additionally, many servers may wish to be accessible by more than +one name. For example, the Apache server might want to be accessible +as apache.org, or ftp.apache.org, assuming +the IP addresses pointed to the same server. In fact, one might want it +so that all addresses at apache.org were picked up by the +server. This is possible with the ServerAlias +directive, placed inside the <VirtualHost> section. For +example:

+ +
+    ServerAlias apache.org *.apache.org
+
+ +

Note that you can use * and ? as wild-card +characters.

+ +

You also might need ServerAlias if you are serving local users who +do not always include the domain name. For example, if local users are +familiar with typing "www" or "www.physics" then you will need to add +ServerAlias www www.physics. It isn't possible for the +server to know what domain the client uses for their name resolution +because the client doesn't provide that information in the request.

+ +

Security Considerations

+ +Apache allows all virtual hosts to be made accessible via the +Host: header through all IP interfaces, even those which +are configured to use different IP interfaces. For example, if the +configuration for www.foo.com contained a virtual host +section for www.bar.com, and www.bar.com was +a separate IP interface, such that +non-Host:-header-supporting browsers can use it, as +before with Apache 1.0. If a request is made to +www.foo.com and the request includes the header +Host: www.bar.com, a page from www.bar.com +will be sent. + +

+ +This is a security concern if you are controlling access to a +particular server based on IP-layer controls, such as from within a +firewall or router. Let's say www.bar.com in the above +example was instead an intra-net server called +private.foo.com, and the router used by foo.com only let +internal users access private.foo.com. Obviously, +Host: header functionality now allows someone who has +access to www.foo.com to get +private.foo.com, if they send a Host: +private.foo.com header. It is important to note that this +condition exists only if you only implement this policy at the IP +layer - all security controls used by Apache (i.e., allow, deny from, etc.) are consistently +respected. + +

Compatibility with Older Browsers

+ +

As mentioned earlier, a majority of browsers do not send the +required data for the new virtual hosts to work properly. These +browsers will always be sent to the main server's pages. There is a +workaround, albeit a slightly cumbersome one:

+ +

To continue the www.apache.org example (Note: Apache's +web server does not actually function in this manner), we might use the +new ServerPath directive in the www.apache.org virtual host, +for example: + +

+    ServerPath /apache
+
+

What does this mean? It means that a request for any file beginning +with "/apache" will be looked for in the Apache +docs. This means that the pages can be accessed as +http://www.apache.org/apache/ for all browsers, although +new browsers can also access it as +http://www.apache.org/.

+ +

In order to make this work, put a link on your main server's page +to http://www.apache.org/apache/ (Note: Do not use +http://www.apache.org/ - this would create an endless +loop). Then, in the virtual host's pages, be sure to use either purely +relative links (e.g. "file.html" or +"../icons/image.gif" or links containing the prefacing +/apache/ +(e.g. "http://www.apache.org/apache/file.html" or +"/apache/docs/1.1/index.html").

+ +

This requires a bit of +discipline, but adherence to these guidelines will, for the most part, +ensure that your pages will work with all browsers, new and old. When +a new browser contacts http://www.apache.org/, they will +be directly taken to the Apache pages. Older browsers will be able to +click on the link from the main server, go to +http://www.apache.org/apache/, and then access the +pages.

+ + + + + diff --git a/APACHE_1_2_X/htdocs/manual/images/home.gif b/APACHE_1_2_X/htdocs/manual/images/home.gif new file mode 100644 index 00000000000..11299c1cb7e Binary files /dev/null and b/APACHE_1_2_X/htdocs/manual/images/home.gif differ diff --git a/APACHE_1_2_X/htdocs/manual/images/index.gif b/APACHE_1_2_X/htdocs/manual/images/index.gif new file mode 100644 index 00000000000..741c8939d77 Binary files /dev/null and b/APACHE_1_2_X/htdocs/manual/images/index.gif differ diff --git a/APACHE_1_2_X/htdocs/manual/images/sub.gif b/APACHE_1_2_X/htdocs/manual/images/sub.gif new file mode 100644 index 00000000000..93061c5ad7f Binary files /dev/null and b/APACHE_1_2_X/htdocs/manual/images/sub.gif differ diff --git a/APACHE_1_2_X/htdocs/manual/index.html b/APACHE_1_2_X/htdocs/manual/index.html new file mode 100644 index 00000000000..1604b742723 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/index.html @@ -0,0 +1,67 @@ + + + +Apache documentation + + + + + +

Apache User's Guide

+ +
+ +

Release Notes

+ + + +

Apache Reference Manual

+
    +
  • Search + the master manual pages for key words +
  • +
+ + +

Other Notes

+ + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/install.html b/APACHE_1_2_X/htdocs/manual/install.html new file mode 100644 index 00000000000..52e84b0c54a --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/install.html @@ -0,0 +1,249 @@ + + + +Compiling and Installing Apache + + + + + + +

Compiling and Installing Apache 1.2

+ +

If you wish to download and install an earlier version of Apache please +read Compiling and Installing Apache 1.1.

+ +UnixWare users will want to consult build notes +for various UnixWare versions before compiling. + +

Downloading Apache

+ +Information on the latest version of Apache can be found on the Apache +web server at http://www.apache.org/. This will +list the current release, any more recent beta-test release, together +with details of mirror web and anonymous ftp sites. + +

+ +If you downloaded a binary distribution, skip to Installing Apache. Otherwise read the next section +for how to compile the server. + +

Compiling Apache

+ +Compiling Apache consists of three steps: Firstly select which Apache +modules you want to include into the server. Secondly create a +configuration for your operating system. Thirdly compile the +executable. +

+ +All configuration of Apache is performed in the src +directory of the Apache distribution. Change into this directory. + +

    +
  1. + Select modules to compile into Apache in the + Configuration file. Uncomment lines corresponding to + those optional modules you wish to include (among the Module lines + at the bottom of the file), or add new lines corresponding to + additional modules you have downloaded or written. (See API.html for preliminary docs on how to + write Apache modules). Advanced users can comment out some of the + default modules if they are sure they will not need them (be careful + though, since many of the default modules are vital for the correct + operation and security of the server). +

    + + You should also read the instructions in the Configuration + file to see if you need to set any of the Rule lines. + + +

  2. + Configure Apache for your operating system. Normally you can just + type run the Configure script as given below. However + if this fails or you have any special requirements (e.g. to include + an additional library required by an optional module) you might need + to edit one or more of the following options in the + Configuration file: + EXTRA_CFLAGS, LIBS, LFLAGS, INCLUDES. +

    + + Run the Configure script: +

    +
    +    % Configure
    +    Using 'Configuration' as config file
    +     + configured for <whatever> platform
    +     + setting C compiler to <whatever> *
    +     + setting C compiler optimization-level to <whatever> *
    +    %
    +   
    +
    + + (*: Depending on Configuration and your system, Configure + make not print these lines. That's OK).

    + + This generates a Makefile for use in stage 3. It also creates a + Makefile in the support directory, for compilation of the optional + support programs. +

    + + (If you want to maintain multiple configurations, you can give a + option to Configure to tell it to read an alternative + Configuration file, such as Configure -file + Configuration.ai). +

    + +

  3. + Type make. +
+ +The modules we place in the Apache distribution are the ones we have +tested and are used regularly by various members of the Apache +development group. Additional modules contributed by members or third +parties with specific needs or functions are available at <URL:http://www.apache.org/dist/contrib/modules/>. +There are instructions on that page for linking these modules into the +core Apache code. + +

Installing Apache

+ +You will have a binary file called httpd in the +src directory. A binary distribution of Apache will +supply this file.

+ +The next step is to install the program and configure it. Apache is +designed to be configured and run from the same set of directories +where it is compiled. If you want to run it from somewhere else, make +a directory and copy the conf, logs and +icons directories into it.

+ +The next step is to edit the configuration files for the server. This +consists of setting up various directives in up to three +central configuration files. By default, these files are located in +the conf directory and are called srm.conf, +access.conf and httpd.conf. To help you get +started there are same files in the conf directory of the +distribution, called srm.conf-dist, +access.conf-dist and httpd.conf-dist. Copy +or rename these files to the names without the -dist. +Then edit each of the files. Read the comments in each file carefully. +Failure to setup these files correctly could lead to your server not +working or being insecure. You should also have an additional file in +the conf directory called mime.types. This +file usually does not need editing. + +

+ +First edit httpd.conf. This sets up general attributes +about the server: the port number, the user it runs as, etc. Next +edit the srm.conf file; this sets up the root of the +document tree, special functions like server-parsed HTML or internal +imagemap parsing, etc. Finally, edit the access.conf +file to at least set the base cases of access. + +

+ +In addition to these three files, the server behavior can be configured +on a directory-by-directory basis by using .htaccess +files in directories accessed by the server. + +

Starting and Stopping the Server

+ +To start the server, simply run httpd. This will look for +httpd.conf in the location compiled into the code (by +default /usr/locale/etc/httpd/conf/httpd.conf). If +this file is somewhere else, you can give the real +location with the -f argument. For example: + +
+    /usr/local/etc/apache/src/httpd -f /usr/local/etc/apache/conf/httpd.conf
+
+ +If all goes well this will return to the command prompt almost +immediately. This indicates that the server is now up and running. If +anything goes wrong during the initialization of the server you will +see an error message on the screen. + +If the server started ok, you can now use your browser to +connect to the server and read the documentation. If you are running +the browser on the same machine as the server and using the default +port of 80, a suitable URL to enter into your browser is + +
+    http://localhost/
+
+ +

+ +Note that when the server starts it will create a number of +child processes to handle the requests. If you started Apache +as the root user, the parent process will continue to run as root +while the children will change to the user as given in the httpd.conf +file. + +

+ +If when you run httpd it complained about being unable to +"bind" to an address, then either some other process is already using +the port you have configured Apache to use, or you are running httpd +as a normal user but trying to use port below 1024 (such as the +default port 80). + +

+ +If the server is not running, read the error message displayed +when you run httpd. You should also check the server +error_log for additional information (with the default configuration, +this will be located in the file error_log in the +logs directory). + +

+ +If you want your server to continue running after a system reboot, you +should add a call to httpd to your system startup files +(typically rc.local or a file in an +rc.N directory). This will start Apache as root. +Before doing this ensure that your server is properly configured +for security and access restrictions. + +

+ +To stop Apache send the parent process a TERM signal. The PID of this +process is written to the file httpd.pid in the +logs directory (unless configured otherwise). Do not +attempt to kill the child processes because they will be renewed by +the parent. A typical command to stop the server is: + +

+    kill -TERM `cat /usr/local/etc/apache/logs/httpd.pid`
+
+ +

+ +For more information about Apache command line options, configuration +and log files, see Starting Apache. For a +reference guide to all Apache directives supported by the distributed +modules, see the Apache directives. + +

Compiling Support Programs

+ +In addition to the main httpd server which is compiled +and configured as above, Apache includes a number of support programs. +These are not compiled by default. The support programs are in the +support directory of the distribution. To compile +the support programs, change into this directory and type +
+    make
+
+ + + + diff --git a/APACHE_1_2_X/htdocs/manual/install_1_1.html b/APACHE_1_2_X/htdocs/manual/install_1_1.html new file mode 100644 index 00000000000..99fac7f27b1 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/install_1_1.html @@ -0,0 +1,112 @@ + + + +Compiling and Installing Apache + + + + + +

Compiling and Installing Apache

+

Downloading Apache

+

Information on the latest version of Apache can be found on the Apache +web server at http://www.apache.org/. This will list the current release, +any more recent beta-test release, together with details of mirror +web and anonymous ftp sites.

+ +UnixWare users will want to consult build notes +for various UnixWare versions before compiling. + +

Compiling Apache

+This release of Apache supports the notion of `optional modules'. +However, the server has to know which modules are compiled into it, in +order for those modules to be effective; this requires generation of a +short bit of code (`modules.c') which simply has a list of them. +

+If you are satisfied with our standard module set, and expect to +continue to be satisfied with it, then you can just edit the stock +Makefile and compile as you have been doing previously. If you +would +like to select optional modules, however, you need to run the +configuration script. +

+To do this: +

    +
  1. Edit the file `Configuration'. This contains the per-machine +config settings of the Makefile, and also an additional section at +the bottom which lists the modules which have been compiled in, and +also names the files containing them. You will need to: +
      +
    1. Select a compiler and compilation options as appropriate to +your machine. +
    2. Uncomment lines corresponding to those optional modules you wish +to include (among the Module lines at the bottom of the file) +or add new lines corresponding to custom modules you have written. +

      +Note that DBM auth has to be explicitly configured in, if you want +it; just uncomment the corresponding line. +

    +
  2. Run the `Configure' script: +
    +% Configure
    +Using 'Configuration' as config file
    +%
    + +This generates new versions of the Makefile and of modules.c. If +you want to maintain multiple configurations, you can say, e.g., +
    +% Configure -file Configuration.ai
    +Using alternate config file Configuration.ai
    +%
    + +
  3. Type `make'. +

    +The modules we place in the Apache distribution are the ones we have +tested and are used regularly by various members of the Apache +development group. Additional modules contributed by members or third +parties with specific needs or functions are available at +<URL:http://www.apache.org/dist/contrib/modules/>. There are instructions on that page for +linking these modules into the core Apache code. +

+ +

Installing Apache

+After compilation, you will have a binary called `httpd' in the +src/ directory. A binary distribution of Apache will supply this +file. +

+The next step is to edit the configuration files for the server. In +the subdirectory called `conf' you should find distribution versions +of the three configuration files: srm.conf-dist, +access.conf-dist and httpd.conf-dist. Copy them to +srm.conf, access.conf and httpd.conf +respectively. +

+First edit httpd.conf. This sets up general attributes about the +server; the port number, the user it runs as, etc. Next edit the +srm.conf file; this sets up the root of the document tree, +special functions like server-parsed HTML or internal imagemap parsing, etc. +Finally, edit the access.conf file to at least set the base cases +of access. +

+Finally, make a call to httpd, with a -f to the full path to the +httpd.conf file. I.e., the common case: +

+ /usr/local/etc/apache/src/httpd -f /usr/local/etc/apache/conf/httpd.conf +
+The server should be now running. +

+By default the srm.conf and access.conf files are +located by name; to specifically call them by other names, use the +AccessConfig and +ResourceConfig directives in +httpd.conf. + + + + diff --git a/APACHE_1_2_X/htdocs/manual/invoking.html b/APACHE_1_2_X/htdocs/manual/invoking.html new file mode 100644 index 00000000000..62e6a41af9a --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/invoking.html @@ -0,0 +1,124 @@ + + + +Starting Apache + + + + + +

Starting Apache

+ +

Invoking Apache

+The httpd program is usually run as a daemon which executes +continuously, handling requests. It is possible to invoke Apache by +the Internet daemon inetd each time a connection to the HTTP +service is made (use the +ServerType directive) +but this is not recommended. + +

Command line options

+The following options are recognized on the httpd command line: +
+
-d serverroot +
Set the initial value for the +ServerRoot variable to +serverroot. This can be overridden by the ServerRoot command in the +configuration file. The default is /usr/local/etc/httpd. + +
-f config +
Execute the commands in the file config on startup. If +config does not begin with a /, then it is taken to be a +path relative to the ServerRoot. The +default is conf/httpd.conf. + +
-X +
Run in single-process mode, for internal debugging purposes only; the +daemon does not detach from the terminal or fork any children. Do NOT +use this mode to provide ordinary web service. + +
-v +
Print the version of httpd, and then exit. + +
-h +
Give a list of directives together with expected arguments and +places where the directive is valid. (New in Apache 1.2) + +
-l +
Give a list of all modules compiled into the server. + +
-? +
Print a list of the httpd options, and then exit. +
+ +

Configuration files

+The server will read three files for configuration directives. Any directive +may appear in any of these files. The the names of these files are taken +to be relative to the server root; this is set by the +ServerRoot directive, or the +-d command line flag. + +Conventionally, the files are: +
+
conf/httpd.conf +
Contains directives that control the operation of the server daemon. +The filename may be overridden with the -f command line flag. + +
conf/srm.conf +
Contains directives that control the specification of documents that +the server can provide to clients. The filename may be overridden with +the ResourceConfig directive. + +
conf/access.conf +
Contains directives that control access to documents. +The filename may be overridden with the +AccessConfig directive. +
+However, these conventions need not be adhered to. +

+The server also reads a file containing mime document types; the filename +is set by the TypesConfig directive, +and is conf/mime.types by default. + +

Log files

+

security warning

+Anyone who can write to the directory where Apache is writing a +log file can almost certainly gain access to the uid that the server is +started as, which is normally root. Do NOT give people write +access to the directory the logs are stored in without being aware of +the consequences; see the security tips +document for details. +

pid file

+On daemon startup, it saves the process id of the parent httpd process to +the file logs/httpd.pid. This filename can be changed with the +PidFile directive. The process-id is for +use by the administrator in restarting and terminating the daemon; +A HUP or USR1 signal causes the daemon to re-read its configuration files and +a TERM signal causes it to die gracefully. For more information +see the Stopping and Restarting page. +

+If the process dies (or is killed) abnormally, then it will be necessary to +kill the children httpd processes. + +

Error log

+The server will log error messages to a log file, logs/error_log +by default. The filename can be set using the +ErrorLog directive; different error logs can +be set for different virtual hosts. + +

Transfer log

+The server will typically log each request to a transfer file, +logs/access_log by default. The filename can be set using a +TransferLog directive; different +transfer logs can be set for different virtual +hosts. + + + + diff --git a/APACHE_1_2_X/htdocs/manual/keepalive.html b/APACHE_1_2_X/htdocs/manual/keepalive.html new file mode 100644 index 00000000000..60399f3df89 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/keepalive.html @@ -0,0 +1,79 @@ + + +Apache Keep-Alive Support + + + + + +

Apache Keep-Alive Support

+ +
+ +

What is Keep-Alive?

+ +The Keep-Alive extension to HTTP, as defined by the +HTTP/1.1 draft, allows persistent connections. These +long-lived HTTP sessions allow multiple requests to be send over the +same TCP connection, and in some cases have been shown to result in an +almost 50% speedup in latency times for HTML documents with lots of +images. + +

Enabling Keep-Alive Support

+ +Apache 1.1 comes with Keep-Alive support on by default, however there +are some directives you can use to modify Apache's behavior: + +

Note: Apache 1.2 uses a different syntax for the KeepAlive directive.

+ +

KeepAlive

+Syntax: KeepAlive max-requests
+Default: KeepAlive 5
+Context: server config
+Status: Core

+ +This directive enables Keep-Alive support. Set max-requests +to the maximum number of requests you want Apache to entertain per +connection. A limit is imposed to prevent a client from hogging your +server resources. Set this to 0 to disable support. + +

KeepAliveTimeout

+Syntax: KeepAliveTimeout seconds
+Default: KeepAliveTimeout 15
+Context: server config
+Status: Core

+ +The number of seconds Apache will wait for a subsequent request before +closing the connection. Once a request has been received, the timeout +value specified by the Timeout directive +applies. + +

When Keep-Alive Is Used

+ +In order for Keep-Alive support to be used, first the browser must +support it. Many current browsers, including Netscape Navigator 2.0, +and Spyglass Mosaic-based browsers (including Microsoft Internet +Explorer) do. Note, however, that some Windows 95-based browsers misbehave +with Keep-Alive-supporting servers; they may occasionally hang on a +connect. This has been observed with several Windows browsers, and occurs +when connecting to any Keep-Alive server, not just Apache. Netscape 3.0b5 +and later versions are known to work around this problem. + +

However, Keep-Alive support only is active with files where the +length is known beforehand. This means that most CGI scripts, +server-side included files and directory listings will not use +the Keep-Alive protocol. While this should be completely transparent +to the end user, it is something the web-master may want to keep in mind.

+ + + + + diff --git a/APACHE_1_2_X/htdocs/manual/location.html b/APACHE_1_2_X/htdocs/manual/location.html new file mode 100644 index 00000000000..96ab3a85447 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/location.html @@ -0,0 +1,59 @@ + + + +Access Control by URL + + + + + +

Access Control by URL

+ +

The <Location> Directive

+ +Syntax: <Location URL prefix>
+Context: server config, virtual host
+Status: core
+ +

The <Location> directive provides for access control by +URL. It is comparable to the <Directory> directive, and +should be matched with a </Location> directive. Directives that +apply to the URL given should be listen +within. <Location> sections are processed in the +order they appear in the configuration file, after the +<Directory> sections and .htaccess files are +read.

+ +

Note that, due to the way HTTP functions, URL prefix +should, save for proxy requests, be of the form /path/, +and should not include the http://servername. It doesn't +necessarily have to protect a directory (it can be an individual +file, or a number of files), and can include wild-cards. In a wild-card +string, `?' matches any single character, and `*' matches any +sequences of characters. + +

This functionality is especially useful when combined with the +SetHandler +directive. For example, to enable status requests, but allow them only +from browsers at foo.com, you might use: + +

+    <Location /status>
+    SetHandler server-status
+    order deny,allow
+    deny from all
+    allow from .foo.com
+    </Location>
+
+ + + + + diff --git a/APACHE_1_2_X/htdocs/manual/man-template.html b/APACHE_1_2_X/htdocs/manual/man-template.html new file mode 100644 index 00000000000..e62beb51c8b --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/man-template.html @@ -0,0 +1,69 @@ + + + +Apache module mod_foobar + + + + + + + +

Module mod_foobar

+ +
Add this file as a link in modules.html
+ +This module is contained in the mod_foobar.c file, and +is/is not compiled in by default. It provides for +the foobar feature. Any document with the mime type +foo/bar will be processed by this module. + +
Add the magic mime type to the list in +magic_types.html
+ +

Summary

+General module documentation here. + +

Directives

+ + +
Add these directives to the list in +directives.html
+ +
+ +

ADirective

+Syntax: ADirective some args
+Default: ADirective default value
+Context: context-list
+ +
context-list is where this directive can appear; +allowed: server config, virtual host, directory, .htaccess
+ +Override: override
+ +
required if the directive is allowed in .htaccess files; +the AllowOverride option that allows the directive.
+ +Status: status
+ +
Core if in core apache, Base if in one of the standard +modules, Extension if in an extension module (not compiled in by default) +or Experimental
+ +Module: mod_foobar

+ +The ADirective directive does something. + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/misc/API.html b/APACHE_1_2_X/htdocs/manual/misc/API.html new file mode 100644 index 00000000000..ad539e2abbb --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/misc/API.html @@ -0,0 +1,1004 @@ + + +Apache API notes + + + + +

Apache API notes

+ +These are some notes on the Apache API and the data structures you +have to deal with, etc. They are not yet nearly complete, but +hopefully, they will help you get your bearings. Keep in mind that +the API is still subject to change as we gain experience with it. +(See the TODO file for what might be coming). However, +it will be easy to adapt modules to any changes that are made. +(We have more modules to adapt than you do). +

+ +A few notes on general pedagogical style here. In the interest of +conciseness, all structure declarations here are incomplete --- the +real ones have more slots that I'm not telling you about. For the +most part, these are reserved to one component of the server core or +another, and should be altered by modules with caution. However, in +some cases, they really are things I just haven't gotten around to +yet. Welcome to the bleeding edge.

+ +Finally, here's an outline, to give you some bare idea of what's +coming up, and in what order: + +

+ +

Basic concepts.

+ +We begin with an overview of the basic concepts behind the +API, and how they are manifested in the code. + +

Handlers, Modules, and Requests

+ +Apache breaks down request handling into a series of steps, more or +less the same way the Netscape server API does (although this API has +a few more stages than NetSite does, as hooks for stuff I thought +might be useful in the future). These are: + +
    +
  • URI -> Filename translation +
  • Auth ID checking [is the user who they say they are?] +
  • Auth access checking [is the user authorized here?] +
  • Access checking other than auth +
  • Determining MIME type of the object requested +
  • `Fixups' --- there aren't any of these yet, but the phase is + intended as a hook for possible extensions like + SetEnv, which don't really fit well elsewhere. +
  • Actually sending a response back to the client. +
  • Logging the request +
+ +These phases are handled by looking at each of a succession of +modules, looking to see if each of them has a handler for the +phase, and attempting invoking it if so. The handler can typically do +one of three things: + +
    +
  • Handle the request, and indicate that it has done so + by returning the magic constant OK. +
  • Decline to handle the request, by returning the magic + integer constant DECLINED. In this case, the + server behaves in all respects as if the handler simply hadn't + been there. +
  • Signal an error, by returning one of the HTTP error codes. + This terminates normal handling of the request, although an + ErrorDocument may be invoked to try to mop up, and it will be + logged in any case. +
+ +Most phases are terminated by the first module that handles them; +however, for logging, `fixups', and non-access authentication +checking, all handlers always run (barring an error). Also, the +response phase is unique in that modules may declare multiple handlers +for it, via a dispatch table keyed on the MIME type of the requested +object. Modules may declare a response-phase handler which can handle +any request, by giving it the key */* (i.e., a +wildcard MIME type specification). However, wildcard handlers are +only invoked if the server has already tried and failed to find a more +specific response handler for the MIME type of the requested object +(either none existed, or they all declined).

+ +The handlers themselves are functions of one argument (a +request_rec structure. vide infra), which returns an +integer, as above.

+ +

A brief tour of a module

+ +At this point, we need to explain the structure of a module. Our +candidate will be one of the messier ones, the CGI module --- this +handles both CGI scripts and the ScriptAlias config file +command. It's actually a great deal more complicated than most +modules, but if we're going to have only one example, it might as well +be the one with its fingers in every place.

+ +Let's begin with handlers. In order to handle the CGI scripts, the +module declares a response handler for them. Because of +ScriptAlias, it also has handlers for the name +translation phase (to recognize ScriptAliased URIs), the +type-checking phase (any ScriptAliased request is typed +as a CGI script).

+ +The module needs to maintain some per (virtual) +server information, namely, the ScriptAliases in effect; +the module structure therefore contains pointers to a functions which +builds these structures, and to another which combines two of them (in +case the main server and a virtual server both have +ScriptAliases declared).

+ +Finally, this module contains code to handle the +ScriptAlias command itself. This particular module only +declares one command, but there could be more, so modules have +command tables which declare their commands, and describe +where they are permitted, and how they are to be invoked.

+ +A final note on the declared types of the arguments of some of these +commands: a pool is a pointer to a resource pool +structure; these are used by the server to keep track of the memory +which has been allocated, files opened, etc., either to service a +particular request, or to handle the process of configuring itself. +That way, when the request is over (or, for the configuration pool, +when the server is restarting), the memory can be freed, and the files +closed, en masse, without anyone having to write explicit code to +track them all down and dispose of them. Also, a +cmd_parms structure contains various information about +the config file being read, and other status information, which is +sometimes of use to the function which processes a config-file command +(such as ScriptAlias). + +With no further ado, the module itself: + +

+/* Declarations of handlers. */
+
+int translate_scriptalias (request_rec *);
+int type_scriptalias (request_rec *);
+int cgi_handler (request_rec *);
+
+/* Subsidiary dispatch table for response-phase handlers, by MIME type */
+
+handler_rec cgi_handlers[] = {
+{ "application/x-httpd-cgi", cgi_handler },
+{ NULL }
+};
+
+/* Declarations of routines to manipulate the module's configuration
+ * info.  Note that these are returned, and passed in, as void *'s;
+ * the server core keeps track of them, but it doesn't, and can't,
+ * know their internal structure.
+ */
+
+void *make_cgi_server_config (pool *);
+void *merge_cgi_server_config (pool *, void *, void *);
+
+/* Declarations of routines to handle config-file commands */
+
+extern char *script_alias(cmd_parms *, void *per_dir_config, char *fake,
+                          char *real);
+
+command_rec cgi_cmds[] = {
+{ "ScriptAlias", script_alias, NULL, RSRC_CONF, TAKE2,
+    "a fakename and a realname"},
+{ NULL }
+};
+
+module cgi_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                     /* initializer */
+   NULL,                     /* dir config creator */
+   NULL,                     /* dir merger --- default is to override */
+   make_cgi_server_config,   /* server config */
+   merge_cgi_server_config,  /* merge server config */
+   cgi_cmds,                 /* command table */
+   cgi_handlers,             /* handlers */
+   translate_scriptalias,    /* filename translation */
+   NULL,                     /* check_user_id */
+   NULL,                     /* check auth */
+   NULL,                     /* check access */
+   type_scriptalias,         /* type_checker */
+   NULL,                     /* fixups */
+   NULL,                     /* logger */
+   NULL                      /* header parser */
+};
+
+ +

How handlers work

+ +The sole argument to handlers is a request_rec structure. +This structure describes a particular request which has been made to +the server, on behalf of a client. In most cases, each connection to +the client generates only one request_rec structure.

+ +

A brief tour of the request_rec

+ +The request_rec contains pointers to a resource pool +which will be cleared when the server is finished handling the +request; to structures containing per-server and per-connection +information, and most importantly, information on the request itself.

+ +The most important such information is a small set of character +strings describing attributes of the object being requested, including +its URI, filename, content-type and content-encoding (these being filled +in by the translation and type-check handlers which handle the +request, respectively).

+ +Other commonly used data items are tables giving the MIME headers on +the client's original request, MIME headers to be sent back with the +response (which modules can add to at will), and environment variables +for any subprocesses which are spawned off in the course of servicing +the request. These tables are manipulated using the +table_get and table_set routines.

+

+ Note that the Content-type header value cannot be + set by module content-handlers using the table_*() + routines. Rather, it is set by pointing the content_type + field in the request_rec structure to an appropriate + string. E.g., +
+  r->content_type = "text/html";
+ 
+
+Finally, there are pointers to two data structures which, in turn, +point to per-module configuration structures. Specifically, these +hold pointers to the data structures which the module has built to +describe the way it has been configured to operate in a given +directory (via .htaccess files or +<Directory> sections), for private data it has +built in the course of servicing the request (so modules' handlers for +one phase can pass `notes' to their handlers for other phases). There +is another such configuration vector in the server_rec +data structure pointed to by the request_rec, which +contains per (virtual) server configuration data.

+ +Here is an abridged declaration, giving the fields most commonly used:

+ +

+struct request_rec {
+
+  pool *pool;
+  conn_rec *connection;
+  server_rec *server;
+
+  /* What object is being requested */
+  
+  char *uri;
+  char *filename;
+  char *path_info;
+  char *args;           /* QUERY_ARGS, if any */
+  struct stat finfo;    /* Set by server core;
+                         * st_mode set to zero if no such file */
+  
+  char *content_type;
+  char *content_encoding;
+  
+  /* MIME header environments, in and out.  Also, an array containing
+   * environment variables to be passed to subprocesses, so people can
+   * write modules to add to that environment.
+   *
+   * The difference between headers_out and err_headers_out is that
+   * the latter are printed even on error, and persist across internal
+   * redirects (so the headers printed for ErrorDocument handlers will
+   * have them).
+   */
+  
+  table *headers_in;
+  table *headers_out;
+  table *err_headers_out;
+  table *subprocess_env;
+
+  /* Info about the request itself... */
+  
+  int header_only;     /* HEAD request, as opposed to GET */
+  char *protocol;      /* Protocol, as given to us, or HTTP/0.9 */
+  char *method;        /* GET, HEAD, POST, etc. */
+  int method_number;   /* M_GET, M_POST, etc. */
+
+  /* Info for logging */
+
+  char *the_request;
+  int bytes_sent;
+
+  /* A flag which modules can set, to indicate that the data being
+   * returned is volatile, and clients should be told not to cache it.
+   */
+
+  int no_cache;
+
+  /* Various other config info which may change with .htaccess files
+   * These are config vectors, with one void* pointer for each module
+   * (the thing pointed to being the module's business).
+   */
+  
+  void *per_dir_config;   /* Options set in config files, etc. */
+  void *request_config;   /* Notes on *this* request */
+  
+};
+
+
+ +

Where request_rec structures come from

+ +Most request_rec structures are built by reading an HTTP +request from a client, and filling in the fields. However, there are +a few exceptions: + +
    +
  • If the request is to an imagemap, a type map (i.e., a + *.var file), or a CGI script which returned a + local `Location:', then the resource which the user requested + is going to be ultimately located by some URI other than what + the client originally supplied. In this case, the server does + an internal redirect, constructing a new + request_rec for the new URI, and processing it + almost exactly as if the client had requested the new URI + directly.

    + +

  • If some handler signaled an error, and an + ErrorDocument is in scope, the same internal + redirect machinery comes into play.

    + +

  • Finally, a handler occasionally needs to investigate `what + would happen if' some other request were run. For instance, + the directory indexing module needs to know what MIME type + would be assigned to a request for each directory entry, in + order to figure out what icon to use.

    + + Such handlers can construct a sub-request, using the + functions sub_req_lookup_file and + sub_req_lookup_uri; this constructs a new + request_rec structure and processes it as you + would expect, up to but not including the point of actually + sending a response. (These functions skip over the access + checks if the sub-request is for a file in the same directory + as the original request).

    + + (Server-side includes work by building sub-requests and then + actually invoking the response handler for them, via the + function run_sub_request). +

+ +

Handling requests, declining, and returning error codes

+ +As discussed above, each handler, when invoked to handle a particular +request_rec, has to return an int to +indicate what happened. That can either be + +
    +
  • OK --- the request was handled successfully. This may or may + not terminate the phase. +
  • DECLINED --- no erroneous condition exists, but the module + declines to handle the phase; the server tries to find another. +
  • an HTTP error code, which aborts handling of the request. +
+ +Note that if the error code returned is REDIRECT, then +the module should put a Location in the request's +headers_out, to indicate where the client should be +redirected to.

+ +

Special considerations for response handlers

+ +Handlers for most phases do their work by simply setting a few fields +in the request_rec structure (or, in the case of access +checkers, simply by returning the correct error code). However, +response handlers have to actually send a request back to the client.

+ +They should begin by sending an HTTP response header, using the +function send_http_header. (You don't have to do +anything special to skip sending the header for HTTP/0.9 requests; the +function figures out on its own that it shouldn't do anything). If +the request is marked header_only, that's all they should +do; they should return after that, without attempting any further +output.

+ +Otherwise, they should produce a request body which responds to the +client as appropriate. The primitives for this are rputc +and rprintf, for internally generated output, and +send_fd, to copy the contents of some FILE * +straight to the client.

+ +At this point, you should more or less understand the following piece +of code, which is the handler which handles GET requests +which have no more specific handler; it also shows how conditional +GETs can be handled, if it's desirable to do so in a +particular response handler --- set_last_modified checks +against the If-modified-since value supplied by the +client, if any, and returns an appropriate code (which will, if +nonzero, be USE_LOCAL_COPY). No similar considerations apply for +set_content_length, but it returns an error code for +symmetry.

+ +

+int default_handler (request_rec *r)
+{
+    int errstatus;
+    FILE *f;
+    
+    if (r->method_number != M_GET) return DECLINED;
+    if (r->finfo.st_mode == 0) return NOT_FOUND;
+
+    if ((errstatus = set_content_length (r, r->finfo.st_size))
+        || (errstatus = set_last_modified (r, r->finfo.st_mtime)))
+        return errstatus;
+    
+    f = fopen (r->filename, "r");
+
+    if (f == NULL) {
+        log_reason("file permissions deny server access",
+                   r->filename, r);
+        return FORBIDDEN;
+    }
+      
+    register_timeout ("send", r);
+    send_http_header (r);
+
+    if (!r->header_only) send_fd (f, r);
+    pfclose (r->pool, f);
+    return OK;
+}
+
+ +Finally, if all of this is too much of a challenge, there are a few +ways out of it. First off, as shown above, a response handler which +has not yet produced any output can simply return an error code, in +which case the server will automatically produce an error response. +Secondly, it can punt to some other handler by invoking +internal_redirect, which is how the internal redirection +machinery discussed above is invoked. A response handler which has +internally redirected should always return OK.

+ +(Invoking internal_redirect from handlers which are +not response handlers will lead to serious confusion). + +

Special considerations for authentication handlers

+ +Stuff that should be discussed here in detail: + +
    +
  • Authentication-phase handlers not invoked unless auth is + configured for the directory. +
  • Common auth configuration stored in the core per-dir + configuration; it has accessors auth_type, + auth_name, and requires. +
  • Common routines, to handle the protocol end of things, at least + for HTTP basic authentication (get_basic_auth_pw, + which sets the connection->user structure field + automatically, and note_basic_auth_failure, which + arranges for the proper WWW-Authenticate: header + to be sent back). +
+ +

Special considerations for logging handlers

+ +When a request has internally redirected, there is the question of +what to log. Apache handles this by bundling the entire chain of +redirects into a list of request_rec structures which are +threaded through the r->prev and r->next +pointers. The request_rec which is passed to the logging +handlers in such cases is the one which was originally built for the +initial request from the client; note that the bytes_sent field will +only be correct in the last request in the chain (the one for which a +response was actually sent). + +

Resource allocation and resource pools

+ +One of the problems of writing and designing a server-pool server is +that of preventing leakage, that is, allocating resources (memory, +open files, etc.), without subsequently releasing them. The resource +pool machinery is designed to make it easy to prevent this from +happening, by allowing resource to be allocated in such a way that +they are automatically released when the server is done with +them.

+ +The way this works is as follows: the memory which is allocated, file +opened, etc., to deal with a particular request are tied to a +resource pool which is allocated for the request. The pool +is a data structure which itself tracks the resources in question.

+ +When the request has been processed, the pool is cleared. At +that point, all the memory associated with it is released for reuse, +all files associated with it are closed, and any other clean-up +functions which are associated with the pool are run. When this is +over, we can be confident that all the resource tied to the pool have +been released, and that none of them have leaked.

+ +Server restarts, and allocation of memory and resources for per-server +configuration, are handled in a similar way. There is a +configuration pool, which keeps track of resources which were +allocated while reading the server configuration files, and handling +the commands therein (for instance, the memory that was allocated for +per-server module configuration, log files and other files that were +opened, and so forth). When the server restarts, and has to reread +the configuration files, the configuration pool is cleared, and so the +memory and file descriptors which were taken up by reading them the +last time are made available for reuse.

+ +It should be noted that use of the pool machinery isn't generally +obligatory, except for situations like logging handlers, where you +really need to register cleanups to make sure that the log file gets +closed when the server restarts (this is most easily done by using the +function pfopen, which also +arranges for the underlying file descriptor to be closed before any +child processes, such as for CGI scripts, are execed), or +in case you are using the timeout machinery (which isn't yet even +documented here). However, there are two benefits to using it: +resources allocated to a pool never leak (even if you allocate a +scratch string, and just forget about it); also, for memory +allocation, palloc is generally faster than +malloc.

+ +We begin here by describing how memory is allocated to pools, and then +discuss how other resources are tracked by the resource pool +machinery. + +

Allocation of memory in pools

+ +Memory is allocated to pools by calling the function +palloc, which takes two arguments, one being a pointer to +a resource pool structure, and the other being the amount of memory to +allocate (in chars). Within handlers for handling +requests, the most common way of getting a resource pool structure is +by looking at the pool slot of the relevant +request_rec; hence the repeated appearance of the +following idiom in module code: + +
+int my_handler(request_rec *r)
+{
+    struct my_structure *foo;
+    ...
+
+    foo = (foo *)palloc (r->pool, sizeof(my_structure));
+}
+
+ +Note that there is no pfree --- +palloced memory is freed only when the associated +resource pool is cleared. This means that palloc does not +have to do as much accounting as malloc(); all it does in +the typical case is to round up the size, bump a pointer, and do a +range check.

+ +(It also raises the possibility that heavy use of palloc +could cause a server process to grow excessively large. There are +two ways to deal with this, which are dealt with below; briefly, you +can use malloc, and try to be sure that all of the memory +gets explicitly freed, or you can allocate a sub-pool of +the main pool, allocate your memory in the sub-pool, and clear it out +periodically. The latter technique is discussed in the section on +sub-pools below, and is used in the directory-indexing code, in order +to avoid excessive storage allocation when listing directories with +thousands of files). + +

Allocating initialized memory

+ +There are functions which allocate initialized memory, and are +frequently useful. The function pcalloc has the same +interface as palloc, but clears out the memory it +allocates before it returns it. The function pstrdup +takes a resource pool and a char * as arguments, and +allocates memory for a copy of the string the pointer points to, +returning a pointer to the copy. Finally pstrcat is a +varargs-style function, which takes a pointer to a resource pool, and +at least two char * arguments, the last of which must be +NULL. It allocates enough memory to fit copies of each +of the strings, as a unit; for instance: + +
+     pstrcat (r->pool, "foo", "/", "bar", NULL);
+
+ +returns a pointer to 8 bytes worth of memory, initialized to +"foo/bar". + +

Tracking open files, etc.

+ +As indicated above, resource pools are also used to track other sorts +of resources besides memory. The most common are open files. The +routine which is typically used for this is pfopen, which +takes a resource pool and two strings as arguments; the strings are +the same as the typical arguments to fopen, e.g., + +
+     ...
+     FILE *f = pfopen (r->pool, r->filename, "r");
+
+     if (f == NULL) { ... } else { ... }
+
+ +There is also a popenf routine, which parallels the +lower-level open system call. Both of these routines +arrange for the file to be closed when the resource pool in question +is cleared.

+ +Unlike the case for memory, there are functions to close +files allocated with pfopen, and popenf, +namely pfclose and pclosef. (This is +because, on many systems, the number of files which a single process +can have open is quite limited). It is important to use these +functions to close files allocated with pfopen and +popenf, since to do otherwise could cause fatal errors on +systems such as Linux, which react badly if the same +FILE* is closed more than once.

+ +(Using the close functions is not mandatory, since the +file will eventually be closed regardless, but you should consider it +in cases where your module is opening, or could open, a lot of files). + +

Other sorts of resources --- cleanup functions

+ +More text goes here. Describe the the cleanup primitives in terms of +which the file stuff is implemented; also, spawn_process. + +

Fine control --- creating and dealing with sub-pools, with a note +on sub-requests

+ +On rare occasions, too-free use of palloc() and the +associated primitives may result in undesirably profligate resource +allocation. You can deal with such a case by creating a +sub-pool, allocating within the sub-pool rather than the main +pool, and clearing or destroying the sub-pool, which releases the +resources which were associated with it. (This really is a +rare situation; the only case in which it comes up in the standard +module set is in case of listing directories, and then only with +very large directories. Unnecessary use of the primitives +discussed here can hair up your code quite a bit, with very little +gain).

+ +The primitive for creating a sub-pool is make_sub_pool, +which takes another pool (the parent pool) as an argument. When the +main pool is cleared, the sub-pool will be destroyed. The sub-pool +may also be cleared or destroyed at any time, by calling the functions +clear_pool and destroy_pool, respectively. +(The difference is that clear_pool frees resources +associated with the pool, while destroy_pool also +deallocates the pool itself. In the former case, you can allocate new +resources within the pool, and clear it again, and so forth; in the +latter case, it is simply gone).

+ +One final note --- sub-requests have their own resource pools, which +are sub-pools of the resource pool for the main request. The polite +way to reclaim the resources associated with a sub request which you +have allocated (using the sub_req_lookup_... functions) +is destroy_sub_request, which frees the resource pool. +Before calling this function, be sure to copy anything that you care +about which might be allocated in the sub-request's resource pool into +someplace a little less volatile (for instance, the filename in its +request_rec structure).

+ +(Again, under most circumstances, you shouldn't feel obliged to call +this function; only 2K of memory or so are allocated for a typical sub +request, and it will be freed anyway when the main request pool is +cleared. It is only when you are allocating many, many sub-requests +for a single main request that you should seriously consider the +destroy... functions). + +

Configuration, commands and the like

+ +One of the design goals for this server was to maintain external +compatibility with the NCSA 1.3 server --- that is, to read the same +configuration files, to process all the directives therein correctly, +and in general to be a drop-in replacement for NCSA. On the other +hand, another design goal was to move as much of the server's +functionality into modules which have as little as possible to do with +the monolithic server core. The only way to reconcile these goals is +to move the handling of most commands from the central server into the +modules.

+ +However, just giving the modules command tables is not enough to +divorce them completely from the server core. The server has to +remember the commands in order to act on them later. That involves +maintaining data which is private to the modules, and which can be +either per-server, or per-directory. Most things are per-directory, +including in particular access control and authorization information, +but also information on how to determine file types from suffixes, +which can be modified by AddType and +DefaultType directives, and so forth. In general, the +governing philosophy is that anything which can be made +configurable by directory should be; per-server information is +generally used in the standard set of modules for information like +Aliases and Redirects which come into play +before the request is tied to a particular place in the underlying +file system.

+ +Another requirement for emulating the NCSA server is being able to +handle the per-directory configuration files, generally called +.htaccess files, though even in the NCSA server they can +contain directives which have nothing at all to do with access +control. Accordingly, after URI -> filename translation, but before +performing any other phase, the server walks down the directory +hierarchy of the underlying filesystem, following the translated +pathname, to read any .htaccess files which might be +present. The information which is read in then has to be +merged with the applicable information from the server's own +config files (either from the <Directory> sections +in access.conf, or from defaults in +srm.conf, which actually behaves for most purposes almost +exactly like <Directory />).

+ +Finally, after having served a request which involved reading +.htaccess files, we need to discard the storage allocated +for handling them. That is solved the same way it is solved wherever +else similar problems come up, by tying those structures to the +per-transaction resource pool.

+ +

Per-directory configuration structures

+ +Let's look out how all of this plays out in mod_mime.c, +which defines the file typing handler which emulates the NCSA server's +behavior of determining file types from suffixes. What we'll be +looking at, here, is the code which implements the +AddType and AddEncoding commands. These +commands can appear in .htaccess files, so they must be +handled in the module's private per-directory data, which in fact, +consists of two separate tables for MIME types and +encoding information, and is declared as follows: + +
+typedef struct {
+    table *forced_types;      /* Additional AddTyped stuff */
+    table *encoding_types;    /* Added with AddEncoding... */
+} mime_dir_config;
+
+ +When the server is reading a configuration file, or +<Directory> section, which includes one of the MIME +module's commands, it needs to create a mime_dir_config +structure, so those commands have something to act on. It does this +by invoking the function it finds in the module's `create per-dir +config slot', with two arguments: the name of the directory to which +this configuration information applies (or NULL for +srm.conf), and a pointer to a resource pool in which the +allocation should happen.

+ +(If we are reading a .htaccess file, that resource pool +is the per-request resource pool for the request; otherwise it is a +resource pool which is used for configuration data, and cleared on +restarts. Either way, it is important for the structure being created +to vanish when the pool is cleared, by registering a cleanup on the +pool if necessary).

+ +For the MIME module, the per-dir config creation function just +pallocs the structure above, and a creates a couple of +tables to fill it. That looks like this: + +

+void *create_mime_dir_config (pool *p, char *dummy)
+{
+    mime_dir_config *new =
+      (mime_dir_config *) palloc (p, sizeof(mime_dir_config));
+
+    new->forced_types = make_table (p, 4);
+    new->encoding_types = make_table (p, 4);
+    
+    return new;
+}
+
+ +Now, suppose we've just read in a .htaccess file. We +already have the per-directory configuration structure for the next +directory up in the hierarchy. If the .htaccess file we +just read in didn't have any AddType or +AddEncoding commands, its per-directory config structure +for the MIME module is still valid, and we can just use it. +Otherwise, we need to merge the two structures somehow.

+ +To do that, the server invokes the module's per-directory config merge +function, if one is present. That function takes three arguments: +the two structures being merged, and a resource pool in which to +allocate the result. For the MIME module, all that needs to be done +is overlay the tables from the new per-directory config structure with +those from the parent: + +

+void *merge_mime_dir_configs (pool *p, void *parent_dirv, void *subdirv)
+{
+    mime_dir_config *parent_dir = (mime_dir_config *)parent_dirv;
+    mime_dir_config *subdir = (mime_dir_config *)subdirv;
+    mime_dir_config *new =
+      (mime_dir_config *)palloc (p, sizeof(mime_dir_config));
+
+    new->forced_types = overlay_tables (p, subdir->forced_types,
+                                        parent_dir->forced_types);
+    new->encoding_types = overlay_tables (p, subdir->encoding_types,
+                                          parent_dir->encoding_types);
+
+    return new;
+}
+
+ +As a note --- if there is no per-directory merge function present, the +server will just use the subdirectory's configuration info, and ignore +the parent's. For some modules, that works just fine (e.g., for the +includes module, whose per-directory configuration information +consists solely of the state of the XBITHACK), and for +those modules, you can just not declare one, and leave the +corresponding structure slot in the module itself NULL.

+ +

Command handling

+ +Now that we have these structures, we need to be able to figure out +how to fill them. That involves processing the actual +AddType and AddEncoding commands. To find +commands, the server looks in the module's command table. +That table contains information on how many arguments the commands +take, and in what formats, where it is permitted, and so forth. That +information is sufficient to allow the server to invoke most +command-handling functions with pre-parsed arguments. Without further +ado, let's look at the AddType command handler, which +looks like this (the AddEncoding command looks basically +the same, and won't be shown here): + +
+char *add_type(cmd_parms *cmd, mime_dir_config *m, char *ct, char *ext)
+{
+    if (*ext == '.') ++ext;
+    table_set (m->forced_types, ext, ct);
+    return NULL;
+}
+
+ +This command handler is unusually simple. As you can see, it takes +four arguments, two of which are pre-parsed arguments, the third being +the per-directory configuration structure for the module in question, +and the fourth being a pointer to a cmd_parms structure. +That structure contains a bunch of arguments which are frequently of +use to some, but not all, commands, including a resource pool (from +which memory can be allocated, and to which cleanups should be tied), +and the (virtual) server being configured, from which the module's +per-server configuration data can be obtained if required.

+ +Another way in which this particular command handler is unusually +simple is that there are no error conditions which it can encounter. +If there were, it could return an error message instead of +NULL; this causes an error to be printed out on the +server's stderr, followed by a quick exit, if it is in +the main config files; for a .htaccess file, the syntax +error is logged in the server error log (along with an indication of +where it came from), and the request is bounced with a server error +response (HTTP error status, code 500).

+ +The MIME module's command table has entries for these commands, which +look like this: + +

+command_rec mime_cmds[] = {
+{ "AddType", add_type, NULL, OR_FILEINFO, TAKE2, 
+    "a mime type followed by a file extension" },
+{ "AddEncoding", add_encoding, NULL, OR_FILEINFO, TAKE2, 
+    "an encoding (e.g., gzip), followed by a file extension" },
+{ NULL }
+};
+
+ +The entries in these tables are: + +
    +
  • The name of the command +
  • The function which handles it +
  • a (void *) pointer, which is passed in the + cmd_parms structure to the command handler --- + this is useful in case many similar commands are handled by the + same function. +
  • A bit mask indicating where the command may appear. There are + mask bits corresponding to each AllowOverride + option, and an additional mask bit, RSRC_CONF, + indicating that the command may appear in the server's own + config files, but not in any .htaccess + file. +
  • A flag indicating how many arguments the command handler wants + pre-parsed, and how they should be passed in. + TAKE2 indicates two pre-parsed arguments. Other + options are TAKE1, which indicates one pre-parsed + argument, FLAG, which indicates that the argument + should be On or Off, and is passed in + as a boolean flag, RAW_ARGS, which causes the + server to give the command the raw, unparsed arguments + (everything but the command name itself). There is also + ITERATE, which means that the handler looks the + same as TAKE1, but that if multiple arguments are + present, it should be called multiple times, and finally + ITERATE2, which indicates that the command handler + looks like a TAKE2, but if more arguments are + present, then it should be called multiple times, holding the + first argument constant. +
  • Finally, we have a string which describes the arguments that + should be present. If the arguments in the actual config file + are not as required, this string will be used to help give a + more specific error message. (You can safely leave this + NULL). +
+ +Finally, having set this all up, we have to use it. This is +ultimately done in the module's handlers, specifically for its +file-typing handler, which looks more or less like this; note that the +per-directory configuration structure is extracted from the +request_rec's per-directory configuration vector by using +the get_module_config function. + +
+int find_ct(request_rec *r)
+{
+    int i;
+    char *fn = pstrdup (r->pool, r->filename);
+    mime_dir_config *conf = (mime_dir_config *)
+             get_module_config(r->per_dir_config, &mime_module);
+    char *type;
+
+    if (S_ISDIR(r->finfo.st_mode)) {
+        r->content_type = DIR_MAGIC_TYPE;
+        return OK;
+    }
+    
+    if((i=rind(fn,'.')) < 0) return DECLINED;
+    ++i;
+
+    if ((type = table_get (conf->encoding_types, &fn[i])))
+    {
+        r->content_encoding = type;
+
+        /* go back to previous extension to try to use it as a type */
+
+        fn[i-1] = '\0';
+        if((i=rind(fn,'.')) < 0) return OK;
+        ++i;
+    }
+
+    if ((type = table_get (conf->forced_types, &fn[i])))
+    {
+        r->content_type = type;
+    }
+    
+    return OK;
+}
+
+
+ +

Side notes --- per-server configuration, virtual servers, etc.

+ +The basic ideas behind per-server module configuration are basically +the same as those for per-directory configuration; there is a creation +function and a merge function, the latter being invoked where a +virtual server has partially overridden the base server configuration, +and a combined structure must be computed. (As with per-directory +configuration, the default if no merge function is specified, and a +module is configured in some virtual server, is that the base +configuration is simply ignored).

+ +The only substantial difference is that when a command needs to +configure the per-server private module data, it needs to go to the +cmd_parms data to get at it. Here's an example, from the +alias module, which also indicates how a syntax error can be returned +(note that the per-directory configuration argument to the command +handler is declared as a dummy, since the module doesn't actually have +per-directory config data): + +

+char *add_redirect(cmd_parms *cmd, void *dummy, char *f, char *url)
+{
+    server_rec *s = cmd->server;
+    alias_server_conf *conf = (alias_server_conf *)
+            get_module_config(s->module_config,&alias_module);
+    alias_entry *new = push_array (conf->redirects);
+
+    if (!is_url (url)) return "Redirect to non-URL";
+    
+    new->fake = f; new->real = url;
+    return NULL;
+}
+
+ + diff --git a/APACHE_1_2_X/htdocs/manual/misc/FAQ.html b/APACHE_1_2_X/htdocs/manual/misc/FAQ.html new file mode 100644 index 00000000000..94d257d6614 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/misc/FAQ.html @@ -0,0 +1,1397 @@ + + + + Apache Server Frequently Asked Questions + + + + + +

Apache Server Frequently Asked Questions

+

+ $Revision: 1.63 $ ($Date: 1997/06/04 11:42:55 $) +

+

+ The latest version of this FAQ is always available from the main + Apache web site, at + <http://www.apache.org/docs/misc/FAQ>. +

+ + + + + + + + + + + + +

+ If you are reading a text-only version of this FAQ, you may find numbers + enclosed in brackets (such as "[12]"). These refer to the list of + reference URLs to be found at the end of the document. These references + do not appear, and are not needed, for the hypertext version. +

+

The Questions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

The Answers

+

+

+

+ Background +

+
    +
  1. + What is Apache? + +

    + Apache was originally based on code and ideas found in the most + popular HTTP server of the time.. NCSA httpd 1.3 (early 1995). It has + since evolved into a far superior system which can rival (and probably + surpass) almost any other UNIX based HTTP server in terms of functionality, + efficiency and speed. +

    +

    + Since it began, it has been completely rewritten, and includes many new + features. Apache is, as of January 1997, the most popular WWW server on + the Internet, according to the + Netcraft Survey. +

    +
    +
  2. +
  3. + Why was Apache created? + +

    + To address the concerns of a group of WWW providers and part-time httpd + programmers that httpd didn't behave as they wanted it to behave. + Apache is an entirely volunteer effort, completely funded by its + members, not by commercial sales. +


    +

    +
  4. +
  5. + How does The Apache Group's work relate to other + server efforts, such as NCSA's? + +

    + We, of course, owe a great debt to NCSA and their programmers for + making the server Apache was based on. We now, however, have our own + server, and our project is mostly our own. The Apache Project is an + entirely independent venture. +

    +
    +
  6. +
  7. + Why the name "Apache"? + +

    + A cute name which stuck. Apache is "A + PAtCHy server". It was + based on some existing code and a series of "patch files". +

    +
    +
  8. +
  9. + OK, so how does Apache compare to other servers? + +

    + For an independent assessment, see + Web Compare's + comparison chart. +

    +

    + Apache has been shown to be substantially faster than many other + free servers. Although certain commercial servers have claimed to + surpass Apache's speed (it has not been demonstrated that any of these + "benchmarks" are a good way of measuring WWW server speed at any + rate), we feel that it is better to have a mostly-fast free server + than an extremely-fast server that costs thousands of dollars. Apache + is run on sites that get millions of hits per day, and they have + experienced no performance difficulties. +

    +
    +
  10. +
  11. + How thoroughly tested is Apache? + +

    + Apache is run on over 400,000 Internet servers (as of April 1997). It has + been tested thoroughly by both developers and users. The Apache Group + maintains rigorous standards before releasing new versions of their + server, and our server runs without a hitch on over one third of all + WWW servers available on the Internet. When bugs do show up, we + release patches and new versions as soon as they are available. +

    +

    + The Apache project's web site includes a page with a partial list of + sites running Apache. +

    +
    +
  12. +
  13. + What are the future plans for Apache? + +

    +

      +
    • to continue as a public domain HTTP server, +
    • +
    • to keep up with advances in HTTP protocol and web developments in + general, +
    • +
    • to collect suggestions for fixes/improvements from its users, +
    • +
    • to respond to needs of large volume providers as well as + occasional users. +
    • +
    +

    +
    +
  14. +
  15. + Whom do I contact for support? + +

    + There is no official support for Apache. None of the developers want to + be swamped by a flood of trivial questions that can be resolved elsewhere. + Bug reports and suggestions should be sent via + the bug report page. + Other questions should be directed to the + comp.infosystems.www.servers.unix + newsgroup, where some of the Apache team lurk, + in the company of many other httpd gurus who should be able + to help. +

    +

    + Commercial support for Apache is, however, available from a number + of third parties. +

    +
    +
  16. +
  17. + Is there any more information available on + Apache? + +

    + Indeed there is. See the main + Apache web site. + There is also a regular electronic publication called + Apache Week + available. Links to relevant Apache Week articles are + included below where appropriate. +

    +
    +
  18. +
  19. + Where can I get Apache? + +

    + You can find out how to download the source for Apache at the + project's + main web page. +

    +
    +
  20. +
+

+ Technical Questions +

+
    +
  1. + "Why can't I ...? Why won't ... work?" What to + do in case of problems + +

    + If you are having trouble with your Apache server software, you should + take the following steps: +

    +
      +
    1. Check the errorlog! +

      + Apache tries to be helpful when it encounters a problem. In many + cases, it will provide some details by writing one or messages to + the server error log. Sometimes this is enough for you to diagnose + & fix the problem yourself (such as file permissions or the like). + The default location of the error log is + /usr/local/etc/httpd/logs/error_log, but see the + ErrorLog + directive in your config files for the location on your server. +

      +
    2. +
    3. Check the + FAQ! +

      + The latest version of the Apache Frequently-Asked Questions list can + always be found at the main Apache web site. +

      +
    4. +
    5. Check the Apache bug database +

      + Most problems that get reported to The Apache Group are recorded in + the + bug database. + Please check the existing reports, open + and closed, before adding one. If you find + that your issue has already been reported, please don't add + a "me, too" report. If the original report isn't closed + yet, we suggest that you check it periodically. You might also + consider contacting the original submitter, because there may be an + email exchange going on about the issue that isn't getting recorded + in the database. +

      +
    6. +
    7. Ask in the comp.infosystems.www.servers.unix + USENET newsgroup +

      + A lot of common problems never make it to the bug database because + there's already high Q&A traffic about them in the + comp.infosystems.www.servers.unix + newsgroup. Many Apache users, and some of the developers, can be + found roaming its virtual halls, so it is suggested that you seek + wisdom there. The chances are good that you'll get a faster answer + there than from the bug database, even if you don't see + your question already posted. +

      +
    8. +
    9. If all else fails, report the problem in the bug + database +

      + If you've gone through those steps above that are appropriate and + have obtained no relief, then please do let The Apache + Group know about the problem by + logging a bug report. +

      +

      + If your problem involves the server crashing and generating a core + dump, please include a backtrace (if possible). As an example, +

      +

      + +

      +
      # cd ServerRoot +
      +
      # dbx httpd core +
      +
      (dbx) where +
      +
      + +

      +

      + (Substitute the appropriate locations for your + ServerRoot and your httpd and + core files. You may have to use gdb + instead of dbx.) +

      +
    10. +
    +
    +
  2. +
  3. + How compatible is Apache with my existing NCSA 1.3 + setup? + +

    + Apache attempts to offer all the features and configuration options + of NCSA httpd 1.3, as well as many of the additional features found in + NCSA httpd 1.4 and NCSA httpd 1.5. +

    +

    + NCSA httpd appears to be moving toward adding experimental features + which are not generally required at the moment. Some of the experiments + will succeed while others will inevitably be dropped. The Apache + philosophy is to add what's needed as and when it is needed. +

    +

    + Friendly interaction between Apache and NCSA developers should ensure + that fundamental feature enhancements stay consistent between the two + servers for the foreseeable future. +

    +
    +
  4. +
  5. + How do I enable CGI execution in directories other than + the ScriptAlias? + +

    + Apache recognizes all files in a directory named as a + ScriptAlias + as being eligible for execution rather than processing as normal + documents. This applies regardless of the file name, so scripts in a + ScriptAlias directory don't need to be named + "*.cgi" or "*.pl" or + whatever. In other words, all files in a ScriptAlias + directory are scripts, as far as Apache is concerned. +

    +

    + To persuade Apache to execute scripts in other locations, such as in + directories where normal documents may also live, you must tell it how + to recognize them - and also that it's okay to execute them. For + this, you need to use something like the + AddHandler + directive. +

    +
      +
    1. In an appropriate section of your server configuration files, add + a line such as +

      +

      +
      AddHandler cgi-script .cgi +
      +
      +

      + The server will then recognize that all files in that location (and + its logical descendants) that end in ".cgi" + are script files, not documents. +
    2. +
    3. Make sure that the directory location is covered by an + Options + declaration that includes the ExecCGI option. +
    4. +
    +
    +
  6. +
  7. + What does it mean when my CGIs fail with + "Premature end of script headers"? + +

    + It means just what it says: the server was expecting a complete set of + HTTP headers (one or more followed by a blank line), and didn't get + them. The most common cause of this (aside from people not + outputting the required headers at all) a result of an interaction + with perl's output buffering. To make perl flush its buffers + after each output statement, insert the following statements before your + first print or write statement: +

    +

    + +

    +
    $cfh = select (STDOUT); +
    +
    $| = 1; +
    +
    select ($cfh); +
    +
    + +

    +

    + This is generally only necessary when you are calling external + programs from your script that send output to stdout. +

    + If your script isn't written in Perl, do the equivalent thing for + whatever language you are using (e.g., for C, call + fflush() after writing the headers). +

    +
    +
  8. +
  9. + How do I enable SSI (parsed HTML)? + +

    + SSI (an acronym for Server-Side Include) directives allow static HTML + documents to be enhanced at run-time (e.g., when delivered to + a client by Apache). The format of SSI directives is covered + in the mod_include manual; + suffice it to say that Apache supports not only SSI but + xSSI (eXtended SSI) directives. +

    +

    + Processing a document at run-time is called parsing it; hence + the term "parsed HTML" sometimes used for documents that + contain SSI instructions. Parsing tends to be extremely + resource-consumptive, and is not enabled by default. +

    +

    + To enable SSI processing, you need to +

    +
      +
    • Build your server with the + mod_include + module. This is normally compiled in by default. +
    • +
    • Make sure your server configuration files have an + Options + directive which permits Includes. +
    • +
    • Make sure that the directory where you want the SSI documents to + live is covered by the "server-parsed" content handler, + either explicitly or in some ancestral location. That can be done + with the following + AddHandler + directive: +

      +

      +
      AddHandler server-parsed .shtml +
      +
      +

      + This indicates that all files ending in ".shtml" in that + location (or its descendants) should be parsed. Note that using + ".html" will cause all normal HTML files to be parsed, + which may put an inordinate load on your server. +
    • +
    +

    + For additional information, see the Apache Week article + on + Using Server Side Includes. +

    +
    +
  10. +
  11. + Why don't my parsed files get cached? + +

    + Since the server is performing run-time processing of your SSI + directives, which may change the content shipped to the client, it + can't know at the time it starts parsing what the final size of the + result will be, or whether the parsed result will always be the same. + This means that it can't generate Content-Length or + Last-Modified headers. Caches commonly work by comparing + the Last-Modified of what's in the cache with that being + delivered by the server. Since the server isn't sending that header + for a parsed document, whatever's doing the caching can't tell whether + the document has changed or not - and so fetches it again to be on the + safe side. +

    +

    + You can work around this in some cases by causing an + Expires header to be generated. (See the + mod_expires + documentation for more details.) Another possibility is to use the + XBitHack Full + mechanism, which tells Apache to send (under certain circumstances + detailed in the XBitHack directive description) a + Last-Modified header based upon the last modification + time of the file being parsed. Note that this may actually be lying + to the client if the parsed file doesn't change but the SSI-inserted + content does; if the included content changes often, this can result + in stale copies being cached. +

    +
    +
  12. +
  13. + How can I have my script output parsed? + +

    + So you want to include SSI directives in the output from your CGI + script, but can't figure out how to do it? + The short answer is "you can't." This is potentially + a security liability and, more importantly, it can not be cleanly + implemented under the current server API. The best workaround + is for your script itself to do what the SSIs would be doing. + After all, it's generating the rest of the content. +

    +

    + This is a feature The Apache Group hopes to add in the next major + release after 1.2. +

    +
    +
  14. +
  15. + Does or will Apache act as a Proxy server? + +

    + Apache version 1.1 and above comes with a proxy module. If compiled + in, this will make Apache act as a caching-proxy server. +

    +
    +
  16. +
  17. + What are "multiviews"? + +

    + "Multiviews" is the general name given to the Apache + server's ability to provide language-specific document variants in + response to a request. This is documented quite thoroughly in the + content negotiation + description page. In addition, Apache Week carried an + article on this subject entitled + "Content Negotiation Explained". +

    +
    +
  18. +
  19. + Why can't I run more than <n> + virtual hosts? + +

    + You are probably running into resource limitations in your + operating system. The most common limitation is the + per-process limit on file descriptors, + which is almost always the cause of problems seen when adding + virtual hosts. Apache often does not give an intuitive error + message because it is normally some library routine (such as + gethostbyname()) which needs file descriptors and + doesn't complain intelligibly when it can't get them. +

    +

    + Each log file requires a file descriptor, which means that if you are + using separate access and error logs for each virtual host, each + virtual host needs two file descriptors. Each + Listen + directive also needs a file descriptor. +

    +

    + Typical values for <n> that we've seen are in + the neighborhood of 128 or 250. When the server bumps into the file + descriptor limit, it may dump core with a SIGSEGV, it might just + hang, or it may limp along and you'll see (possibly meaningful) errors + in the error log. One common problem that occurs when you run into + a file descriptor limit is that CGI scripts stop being executed + properly. +

    +

    + As to what you can do about this: +

    +
      +
    1. Reduce the number of + Listen + directives. If there are no other servers running on the machine + and all of them are running on the same port, you normally don't + need any Listen directives at all. +
    2. +
    3. Reduce the number of log files. You can use + mod_log_config + to log all requests to a single log file while including the name + of the virtual host in the log file. You can then write a + script to split the logfile into separate files later if + necessary. +
    4. +
    5. Increase the number of file descriptors available to the server + (see your system's documentation on the limit or + ulimit commands). For some systems, information on + how to do this is available in the + performance hints + page. +
    6. +
    7. "Don't do that" - try to run with fewer virtual hosts +
    8. +
    9. Spread your operation across multiple server processes (using + Listen + for example, but see the first point) and/or ports. +
    10. +
    +

    + Since this is an operating-system limitation, there's not much else + available in the way of solutions. +

    +
    +
  20. + Why do I keep getting "access denied" for form POST + requests? + +

    + The most common cause of this is a <Limit> section + that only names the GET method. Look in your + configuration files for something that resembles the following and + would affect the location where the POST-handling script resides: +

    +

    + +

    +
    <Limit GET> +
    +
        : +
    +
    + +

    +

    + Change that to <Limit GET POST> and the problem + will probably go away. +

    +
    +
  21. +
  22. + Can I use my /etc/passwd file + for Web page authentication? + +

    + Yes, you can - but it's a very bad idea. Here are + some of the reasons: +

    +
      +
    • The Web technology provides no governors on how often or how + rapidly password (authentication failure) retries can be made. That + means that someone can hammer away at your system's + root password using the Web, using a dictionary or + similar mass attack, just as fast as the wire and your server can + handle the requests. Most operating systems these days include + attack detection (such as n failed passwords for the same + account within m seconds) and evasion (breaking the + connection, disabling the account under attack, disabling + all logins from that source, et cetera), but the + Web does not. +
    • +
    • An account under attack isn't notified (unless the server is + heavily modified); there's no "You have 19483 login + failures" message when the legitimate owner logs in. +
    • +
    • Without an exhaustive and error-prone examination of the server + logs, you can't tell whether an account has been compromised. + Detecting that an attack has occurred, or is in progress, is fairly + obvious, though - if you look at the logs. +
    • +
    • Web authentication passwords (at least for Basic authentication) + generally fly across the wire, and through intermediate proxy + systems, in what amounts to plaintext. "O'er the net we + go/Caching all the way;/O what fun it is to surf/Giving my password + away!" +
    • +
    • Since HTTP is stateless, information about the authentication is + transmitted each and every time a request is made to the + server. Essentially, the client caches it after the first + successful access, and transmits it without asking for all + subsequent requests to the same server. +
    • +
    • It's relatively trivial for someone on your system to put up a + page that will steal the cached password from a client's cache + without them knowing. Can you say "password grabber"? +
    • +
    +

    + If you still want to do this in light of the above disadvantages, the + method is left as an exercise for the reader. It'll void your Apache + warranty, though, and you'll lose all accumulated UNIX guru points. +

    +
    +
  23. + Why doesn't my ErrorDocument 401 work? + +

    + You need to use it with a URL in the form "/foo/bar" and not one + with a method and hostname such as "http://host/foo/bar". See the + ErrorDocument + documentation for details. This was incorrectly documented in the past. +

    +
    +
  24. +
  25. + Why do I get "setgid: Invalid + argument" at startup? + +

    + Your + Group + directive (probably in conf/httpd.conf) needs to name a + group that actually exists in the /etc/group file (or + your system's equivalent). +

    +
    +
  26. +
  27. + Why does Apache send a cookie on every response? + +

    + Apache does not send automatically send a cookie on every + response, unless you have re-compiled it with the + mod_cookies + module. + This module was distributed with Apache prior to 1.2. + This module may help track users, and uses cookies to do this. If + you are not using the data generated by mod_cookies, do + not compile it into Apache. Note that in 1.2 this module was renamed + to the more correct name + mod_usertrack, + and cookies + have to be specifically enabled with the + CookieTracking + directive. +

    +
    +
  28. +
  29. + Why don't my cookies work, I even compiled in + mod_cookies? + + +

    + Firstly, you do not need to compile in + mod_cookies in order for your scripts to work (see the + previous question + for more about mod_cookies). Apache passes on your + Set-Cookie header fine, with or without this module. If + cookies do not work it will be because your script does not work + properly or your browser does not use cookies or is not set-up to + accept them. +

    +
    +
  30. +
  31. + Why do my Java app[let]s give me plain text when I request + an URL from an Apache server? + +

    + As of version 1.2, Apache is an HTTP/1.1 (HyperText Transfer Protocol + version 1.1) server. This fact is reflected in the protocol version + that's included in the response headers sent to a client when + processing a request. Unfortunately, low-level Web access classes + included in the Java Development Kit (JDK) version 1.0.2 expect to see + the version string "HTTP/1.0" and do not correctly interpret + the "HTTP/1.1" value Apache is sending (this part of the + response is a declaration of what the server can do rather than a + declaration of the dialect of the response). The result + is that the JDK methods do not correctly parse the headers, and + include them with the document content by mistake. +

    +

    + This is definitely a bug in the JDK 1.0.2 foundation classes from Sun, + and it has been fixed in version 1.1. However, the classes in + question are part of the virtual machine environment, which means + they're part of the Web browser (if Java-enabled) or the Java + environment on the client system - so even if you develop + your classes with a recent JDK, the eventual users might + encounter the problem. + The classes involved are replaceable by vendors implementing the + Java virtual machine environment, and so even those that are based + upon the 1.0.2 version may not have this problem. +

    +

    + In the meantime, a workaround is to tell + Apache to "fake" an HTTP/1.0 response to requests that come + from the JDK methods; this can be done by including a line such as the + following in your server configuration files: +

    +

    +

    +
    BrowserMatch Java/1.0 force-response-1.0 +
    +
    +

    +

    + More information about this issue can be found in the + Java and HTTP/1.1 + page at the Apache web site. +

    +
    +
  32. +
  33. + Why can't I publish to my Apache server using PUT on + Netscape Gold and other programs? + +

    + Because you need to install and configure a script to handle + the uploaded files. This script is often called a "PUT" handler. + There are several available, but they may have security problems. + Using FTP uploads may be easier and more secure, at least for now. + For more information, see the Apache Week article + Publishing Pages with PUT. +

    +
    +
  34. +
  35. + Why isn't FastCGI included with Apache any more? + +

    + The simple answer is that it was becoming too difficult to keep the + version being included with Apache synchronized with the master copy + at the + FastCGI web site. When a new version of Apache was released, the + version of the FastCGI module included with it would soon be out of date. +

    +

    + You can still obtain the FastCGI module for Apache from the master + FastCGI web site. +

    +
    +
  36. +
  37. + Why am I getting "httpd: could not set socket + option TCP_NODELAY" in my error log? + +

    + This message almost always indicates that the client disconnected + before Apache reached the point of calling setsockopt() + for the connection. It shouldn't occur for more than about 1% of the + requests your server handles, and it's advisory only in any case. +

    +
    +
  38. +
  39. + How can I get my script's output without Apache buffering + it? + +

    + In order to improve network performance, Apache buffers script output + into relatively large chunks. If you have a script that sends + information in bursts (such as partial-done messages in a multi-commit + database transaction, perhaps), the client will not necessarily get + the output as the script is generating it. +

    +

    + To avoid this, Apache recognizes scripts whose names begin with + "nph-" as non-parsed-header scripts. + That is, Apache won't buffer their output, but connect it directly to + the socket going back to the client. +

    +

    + While this will probably do what you want, there are some + disadvantages to it: +

    +
      +
    • YOU (the script) are responsible for generating + ALL of the HTTP headers, and no longer + just the "Content-type" or + "Location" headers +
    • +
    • Unless your script generates its output carefully, you will see a + performance penalty as excessive numbers of packets go back and forth +
    • +
    +

    + As an example how you might handle the former (in a Perl script): +

    + +
    +
    if ($0 =~ m:/*nph-:) { +
    +      + $HTTP_headers =  + "HTTP/1.1 200 OK\015\012"; +
    +      + $HTTP_headers .=  + "Connection: close\015\012"; +
    +      + printf ($HTTP_headers); +
    + }; +
    +
    +
    +

    + and then follow with your normal non-nph headers. +

    +
    +
  40. +
  41. + Why do I get complaints about redefinition + of `struct iovec' when compiling under Linux? + +

    + This is a conflict between your C library includes and your kernel + includes. You need to make sure that the versions of both are matched + properly. There are two workarounds, either one will solve the problem: +

    +
      +
    • Remove the definition of struct iovec from your C + library includes. It is located in /usr/include/sys/uio.h. + Or, +
    • +
    • Add -DNO_WRITEV to the EXTRA_CFLAGS + line in your Configuration and reconfigure/rebuild. + This hurts performance and should only be used as a last resort. +
    • +
    +
    +
  42. +
  43. + The errorlog says Apache dumped core, but where's the dump + file? + +

    + In Apache version 1.2 (beginning with 1.2b8), the error log message + about dumped core includes the directory where the dump file should be + located. However, many Unixes do not allow a process that has + called setuid() to dump core for security reasons; + the typical Apache setup has the server started as root to bind to + port 80, after which it changes UIDs to a non-privileged user to + serve requests. +

    +

    + Dealing with this is extremely operating system-specific, and may + require rebuilding your system kernel. Consult your operating system + documentation or vendor for more information about whether your system + does this and how to bypass it. If there is a documented way + of bypassing it, it is recommended that you bypass it only for the + httpd server process if possible. +

    +

    + The canonical location for Apache's core-dump files is the + ServerRoot + directory. +

    +
    +
  44. +
  45. + Why isn't restricting access by host or domain name + working correctly? + +

    + Two of the most common causes of this are: +

    +
      +
    1. An error, inconsistency, or unexpected mapping in the DNS + registration +
      + This happens frequently: your configuration restricts access to + Host.FooBar.Com, but you can't get in from that host. + The usual reason for this is that Host.FooBar.Com is + actually an alias for another name, and when Apache performs the + address-to-name lookup it's getting the real name, not + Host.FooBar.Com. You can verify this by checking the + reverse lookup yourself. The easiest way to work around it is to + specify the correct host name in your configuration. +
    2. +
    3. Inadequate checking and verification in your + configuration of Apache +
      + If you intend to perform access checking and restriction based upon + the client's host or domain name, you really need to configure + Apache to double-check the origin information it's supplied. You do + this by adding the -DMAXIMUM_DNS clause to the + EXTRA_CFLAGS definition in your + Configuration file. For example: +
      +
      EXTRA_CFLAGS=-DMAXIMUM_DNS +
      +
      +

      + This will cause Apache to be very paranoid about making sure a + particular host address is really assigned to the name it + claims to be. Note that this can incur a significant + performance penalty, however, because of all the name resolution + requests being sent to a nameserver. +

      +
    4. +
    +
    +
  46. +
  47. + Why doesn't Apache include SSL? + +

    + SSL (Secure Socket Layer) data transport requires encryption, and many + governments have restrictions upon the import, export, and use of + encryption technology. If Apache included SSL in the base package, + its distribution would involve all sorts of legal and bureaucratic + issues, and it would no longer be freely available. Also, some of + the technology required to talk to current clients using SSL is + patented by RSA Data Security, + who restricts its use without a license. +

    +

    + Some SSL implementations of Apache are available, however; see the + "related projects" + page at the main Apache web site. +

    +

    + You can find out more about this topic in the Apache Week + article about + Apache and Secure Transactions. +

    +
    +
  48. +
  49. + Why do I get core dumps under HPUX using HP's ANSI + C compiler? + +

    + We have had numerous reports of Apache dumping core when compiled + with HP's ANSI C compiler using optimization. Disabling the compiler + optimization has fixed these problems. +

    +
    +
  50. +
  51. + How do I get Apache to send a MIDI file so the browser can + play it? + +

    + Even though the registered MIME type for MIDI files is + audio/midi, some browsers are not set up to recognize it + as such; instead, they look for audio/x-midi. There are + two things you can do to address this: +

    +
      +
    1. Configure your browser to treat documents of type + audio/midi correctly. This is the type that Apache + sends by default. This may not be workable, however, if you have + many client installations to change, or if some or many of the + clients are not under your control. +
    2. +
    3. Instruct Apache to send a different Content-type + header for these files by adding the following line to your server's + configuration files: +
      +
      AddType audio/x-midi .mid .midi .kar +
      +
      +

      + Note that this may break browsers that do recognize the + audio/midi MIME type unless they're prepared to also + handle audio/x-midi the same way. +

      +
    4. +
    +
    +
  52. +
  53. + Why won't Apache compile with my system's + cc? + +

    + If the server won't compile on your system, it is probably due to one + of the following causes: +

    +
      +
    • The Configure script doesn't recognize your system + environment. +
      + This might be either because it's completely unknown or because + the specific environment (include files, OS version, et + cetera) isn't explicitly handled. If this happens, you may + need to port the server to your OS yourself. +
    • +
    • Your system's C compiler is garbage. +
      + Some operating systems include a default C compiler that is either + not ANSI C-compliant or suffers from other deficiencies. The usual + recommendation in cases like this is to acquire, install, and use + gcc. +
    • +
    • Your include files may be confused. +
      + In some cases, we have found that a compiler installation or system + upgrade has left the C header files in an inconsistent state. Make + sure that your include directory tree is in sync with the compiler and + the operating system. +
    • +
    • Your operating system or compiler may be out of + revision. +
      + Software vendors (including those that develop operating systems) + issue new releases for a reason; sometimes to add functionality, but + more often to fix bugs that have been discovered. Try upgrading + your compiler and/or your operating system. +
    • +
    +

    + The Apache Group tests the ability to build the server on many + different platforms. Unfortunately, we can't test all of the OS + platforms there are. If you have verified that none of the above + issues is the cause of your problem, and it hasn't been reported + before, please submit a + problem report. + Be sure to include complete details, such as the compiler + & OS versions and exact error messages. +

    +
    +
  54. +
  55. + How do I add browsers and referrers to my logs? + +

    + Apache provides a couple of different ways of doing this. The + recommended method is to compile the + mod_log_config + module into your configuration and use the + CustomLog + directive. +

    +

    + You can either log the additional information in files other than your + normal transfer log, or you can add them to the records already being + written. For example: +

    +

    + + CustomLog logs/access_log "%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\"" + +

    +

    + This will add the values of the User-agent: and + Referer: headers, which indicate the client and the + referring page, respectively, to the end of each line in the access + log. +

    +

    + You may want to check out the Apache Week article + entitled: + "Gathering Visitor Information: Customising Your + Logfiles". +

    +
    +
  56. +
  57. + Why do Java applets and applications not work + with documents on my Apache server? + +

    + The Java Development Kit (JDK) libraries versions 1.0.2 and 1.1 do not + correctly interpret the "HTTP/1.1" response + header that Apache 1.2 sends. Instead, if they don't see an exact + match for "HTTP/1.0", they assume the headers + are part of the document content. +

    +

    + This is a known problem, and it has been reported to Sun's JavaSoft + unit. In the meantime, Apache 1.2 servers can work around this by + adding the following lines to their configuration files: +

    +
    +
    BrowserMatch Java1.0 force-response-1.0 +
    +
    +
    + +
  58. +
+ + + diff --git a/APACHE_1_2_X/htdocs/manual/misc/client_block_api.html b/APACHE_1_2_X/htdocs/manual/misc/client_block_api.html new file mode 100644 index 00000000000..2458e0ec7fe --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/misc/client_block_api.html @@ -0,0 +1,86 @@ + + + +Reading Client Input in Apache 1.2 + + + + + +

Reading Client Input in Apache 1.2

+ +
+ +

Apache 1.1 and earlier let modules handle POST and PUT requests by +themselves. The module would, on its own, determine whether the +request had an entity, how many bytes it was, and then called a +function (read_client_block) to get the data. + +

However, HTTP/1.1 requires several things of POST and PUT request +handlers that did not fit into this module, and all existing modules +have to be rewritten. The API calls for handling this have been +further abstracted, so that future HTTP protocol changes can be +accomplished while remaining backwards-compatible.

+ +
+ +

The New API Functions

+ +
+   int setup_client_block (request_rec *, int read_policy);
+   int should_client_block (request_rec *);
+   long get_client_block (request_rec *, char *buffer, int buffer_size);
+
+ +
    +
  1. Call setup_client_block() near the beginning of the request + handler. This will set up all the necessary properties, and + will return either OK, or an error code. If the latter, + the module should return that error code. The second parameter + selects the policy to apply if the request message indicates a + body, and how a chunked + transfer-coding should be interpreted. Choose one of +
    +    REQUEST_NO_BODY          Send 413 error if message has any body
    +    REQUEST_CHUNKED_ERROR    Send 411 error if body without Content-Length
    +    REQUEST_CHUNKED_DECHUNK  If chunked, remove the chunks for me.
    +    REQUEST_CHUNKED_PASS     Pass the chunks to me without removal.
    +
    + In order to use the last two options, the caller MUST provide a buffer + large enough to hold a chunk-size line, including any extensions. + + + +
  2. When you are ready to possibly accept input, call + should_client_block(). + This will tell the module whether or not to read input. If it is 0, + the module should assume that the input is of a non-entity type + (e.g. a GET request). A nonzero response indicates that the module + should proceed (to step 3). + This step also sends a 100 Continue response + to HTTP/1.1 clients, so should not be called until the module + is *definitely* ready to read content. (otherwise, the point of the + 100 response is defeated). Never call this function more than once. + +
  3. Finally, call get_client_block in a loop. Pass it a + buffer and its + size. It will put data into the buffer (not necessarily the full + buffer, in the case of chunked inputs), and return the length of + the input block. When it is done reading, it will + return 0 if EOF, or -1 if there was an error. + +
+ +

As an example, please look at the code in +mod_cgi.c. This is properly written to the new API +guidelines.

+ + + + diff --git a/APACHE_1_2_X/htdocs/manual/misc/compat_notes.html b/APACHE_1_2_X/htdocs/manual/misc/compat_notes.html new file mode 100644 index 00000000000..56e20bb0806 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/misc/compat_notes.html @@ -0,0 +1,121 @@ + + +Apache HTTP Server: Compatibility Notes with NCSA's Server + + + + +

Compatibility Notes with NCSA's Server

+ +
+ +While Apache 0.8.x and beyond are for the most part a drop-in +replacement for NCSA's httpd and earlier versions of Apache, there are +a couple gotcha's to watch out for. These are mostly due to the fact +that the parser for config and access control files was rewritten from +scratch, so certain liberties the earlier servers took may not be +available here. These are all easily fixable. If you know of other +non-fatal problems that belong here, let us know. + +

Please also check the known bugs page. + + + +

    + +
  1. The basic mod_auth AuthGroupFile-specified group file + format allows commas between user names - Apache does not.
    + - added 12/1/96 + +
  2. AddType only accepts one file extension per line, without +any dots (.) in the extension, and does not take full filenames. +If you need multiple extensions per type, use multiple lines, e.g. +
    +AddType application/foo foo
    +AddType application/foo bar +
    +To map .foo and .bar to application/foo +

    + + + +

  3. If you follow the NCSA guidelines for setting up access restrictions + based on client domain, you may well have added entries for, + AuthType, AuthName, AuthUserFile or AuthGroupFile. + None of these are needed (or appropriate) for restricting access + based on client domain. + +

    When Apache sees AuthType it (reasonably) assumes you + are using some authorization type based on username and password. + +

    Please remove AuthType, it's unnecessary even for NCSA. + +

    + +

  4. AuthUserFile requires a full pathname. In earlier + versions of NCSA httpd and Apache, you could use a filename + relative to the .htaccess file. This could be a major security hole, + as it made it trivially easy to make a ".htpass" file in the a + directory easily accessible by the world. We recommend you store + your passwords outside your document tree. + +

    + +

  5. OldScriptAlias is no longer supported. + +

    + +

  6. exec cgi="" produces reasonable malformed header + responses when used to invoke non-CGI scripts.
    + The NCSA code ignores the missing header. (bad idea)
    + Solution: write CGI to the CGI spec or use exec cmd="" instead. +

    We might add virtual support to exec cmd to + make up for this difference. + +

    + +

  7. <Limit> silliness - in the old Apache 0.6.5, a + directive of <Limit GET> would also restrict POST methods - Apache 0.8.8's new + core is correct in not presuming a limit on a GET is the same limit on a POST, + so if you are relying on that behavior you need to change your access configurations + to reflect that. + +

    + +

  8. Icons for FancyIndexing broken - well, no, they're not broken, we've just upgraded the + icons from flat .xbm files to pretty and much smaller .gif files, courtesy of +Kevin Hughes at +EIT. + If you are using the same srm.conf from an old distribution, make sure you add the new + AddIcon, AddIconByType, and DefaultIcon commands. + +

    + +

  9. Under IRIX, the "Group" directive in httpd.conf needs to be a valid group name + (i.e. "nogroup") not the numeric group ID. The distribution httpd.conf, and earlier + ones, had the default Group be "#-1", which was causing silent exits at startup.

    + +

  10. .asis files: Apache 0.6.5 did not require a Status header; +it added one automatically if the .asis file contained a Location header. +0.8.14 requires a Status header.

    + +

    +

  11. Apache versions before 1.2b1 will ignore the last line of configuration + files if the last line does not have a trailing newline. This affects + configuration files (httpd.conf, access.conf and srm.conf), and + htpasswd and htgroup files. + +
+ +More to come when we notice them.... + + + + diff --git a/APACHE_1_2_X/htdocs/manual/misc/fin_wait_2.html b/APACHE_1_2_X/htdocs/manual/misc/fin_wait_2.html new file mode 100644 index 00000000000..48e10874af7 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/misc/fin_wait_2.html @@ -0,0 +1,321 @@ + + + +Connections in FIN_WAIT_2 and Apache + + + + + + + + +

Connections in the FIN_WAIT_2 state and Apache

+
    +
  1. What is the FIN_WAIT_2 state?

    +Starting with the Apache 1.2 betas, people are reporting many more +connections in the FIN_WAIT_2 state (as reported by +netstat) than they saw using older versions. When the +server closes a TCP connection, it sends a packet with the FIN bit +sent to the client, which then responds with a packet with the ACK bit +set. The client then sends a packet with the FIN bit set to the +server, which responds with an ACK and the connection is closed. The +state that the connection is in during the period between when the +server gets the ACK from the client and the server gets the FIN from +the client is known as FIN_WAIT_2. See the TCP RFC for the +technical details of the state transitions.

    + +The FIN_WAIT_2 state is somewhat unusual in that there is no timeout +defined in the standard for it. This means that on many operating +systems, a connection in the FIN_WAIT_2 state will stay around until +the system is rebooted. If the system does not have a timeout and +too many FIN_WAIT_2 connections build up, it can fill up the space +allocated for storing information about the connections and crash +the kernel. The connections in FIN_WAIT_2 do not tie up an httpd +process.

    + +

  2. But why does it happen?

    + +There are several reasons for it happening, and not all of them are +fully understood by the Apache team yet. What is known follows.

    + +

    Buggy clients and persistent connections

    + +Several clients have a bug which pops up when dealing with +persistent connections (aka keepalives). +When the connection is idle and the server closes the connection +(based on the +KeepAliveTimeout), the client is programmed so that the client does +not send back a FIN and ACK to the server. This means that the +connection stays in the FIN_WAIT_2 state until one of the following +happens:

    +

      +
    • The client opens a new connection to the same or a different + site, which causes it to fully close the older connection on + that socket. +
    • The user exits the client, which on some (most?) clients + causes the OS to fully shutdown the connection. +
    • The FIN_WAIT_2 times out, on servers that have a timeout + for this state. +

    +If you are lucky, this means that the buggy client will fully close the +connection and release the resources on your server. However, there +are some cases where the socket is never fully closed, such as a dialup +client disconnecting from their provider before closing the client. +In addition, a client might sit idle for days without making another +connection, and thus may hold its end of the socket open for days +even though it has no further use for it. +This is a bug in the browser or in its operating system's +TCP implementation.

    + +The clients on which this problem has been verified to exist:

    +

      +
    • Mozilla/3.01 (X11; I; FreeBSD 2.1.5-RELEASE i386) +
    • Mozilla/2.02 (X11; I; FreeBSD 2.1.5-RELEASE i386) +
    • Mozilla/3.01Gold (X11; I; SunOS 5.5 sun4m) +
    • MSIE 3.01 on the Macintosh +
    • MSIE 3.01 on Windows 95 +

    + +This does not appear to be a problem on: +

      +
    • Mozilla/3.01 (Win95; I) +
    +

    + +It is expected that many other clients have the same problem. What a +client should do is periodically check its open +socket(s) to see if they have been closed by the server, and close their +side of the connection if the server has closed. This check need only +occur once every few seconds, and may even be detected by a OS signal +on some systems (e.g., Win95 and NT clients have this capability, but +they seem to be ignoring it).

    + +Apache cannot avoid these FIN_WAIT_2 states unless it +disables persistent connections for the buggy clients, just +like we recommend doing for Navigator 2.x clients due to other bugs. +However, non-persistent connections increase the total number of +connections needed per client and slow retrieval of an image-laden +web page. Since non-persistent connections have their own resource +consumptions and a short waiting period after each closure, a busy server +may need persistence in order to best serve its clients.

    + +As far as we know, the client-caused FIN_WAIT_2 problem is present for +all servers that support persistent connections, including Apache 1.1.x +and 1.2.

    + +

    Something in Apache may be broken

    + +While the above bug is a problem, it is not the whole problem. +Some users have observed no FIN_WAIT_2 problems with Apache 1.1.x, +but with 1.2b enough connections build up in the FIN_WAIT_2 state to +crash their server. We have not yet identified why this would occur +and welcome additional test input.

    + +One possible (and most likely) source for additional FIN_WAIT_2 states +is a function called lingering_close() which was added +between 1.1 and 1.2. This function is necessary for the proper +handling of persistent connections and any request which includes +content in the message body (e.g., PUTs and POSTs). +What it does is read any data sent by the client for +a certain time after the server closes the connection. The exact +reasons for doing this are somewhat complicated, but involve what +happens if the client is making a request at the same time the +server sends a response and closes the connection. Without lingering, +the client might be forced to reset its TCP input buffer before it +has a chance to read the server's response, and thus understand why +the connection has closed. +See the appendix for more details.

    + +We have not yet tracked down the exact reason why +lingering_close() causes problems. Its code has been +thoroughly reviewed and extensively updated in 1.2b6. It is possible +that there is some problem in the BSD TCP stack which is causing the +observed problems. It is also possible that we fixed it in 1.2b6. +Unfortunately, we have not been able to replicate the problem on our +test servers.

    + +

  3. What can I do about it?
  4. + +There are several possible workarounds to the problem, some of +which work better than others.

    + +

    Add a timeout for FIN_WAIT_2

    + +The obvious workaround is to simply have a timeout for the FIN_WAIT_2 state. +This is not specified by the RFC, and could be claimed to be a +violation of the RFC, but it is widely recognized as being necessary. +The following systems are known to have a timeout: +

    +

      +
    • FreeBSD versions starting at 2.0 or possibly earlier. +
    • NetBSD version 1.2(?) +
    • OpenBSD all versions(?) +
    • BSD/OS 2.1, with the + + K210-027 patch installed. +
    • Solaris as of around version + 2.2. The timeout can be tuned by using ndd to + modify tcp_fin_wait_2_flush_interval, but the + default should be appropriate for most servers and improper + tuning can have negative impacts. +
    • SCO TCP/IP Release 1.2.1 + can be modified to have a timeout by following + SCO's instructions. +
    • Linux 2.0.x and + earlier(?) +
    • HP-UX 10.x defaults to + terminating connections in the FIN_WAIT_2 state after the + normal keepalive timeouts. This does not + refer to the persistent connection or HTTP keepalive + timeouts, but the SO_LINGER socket option + which is enabled by Apache. This parameter can be adjusted + by using nettune to modify parameters such as + tcp_keepstart and tcp_keepstop. + In later revisions, there is an explicit timer for + connections in FIN_WAIT_2 that can be modified; contact HP + support for details. +
    • SGI IRIX can be patched to + support a timeout. For IRIX 5.3, 6.2, and 6.3, + use patches 1654, 1703 and 1778 respectively. If you + have trouble locating these patches, please contact your + SGI support channel for help. +
    • NCR's MP RAS Unix 2.xx and + 3.xx both have FIN_WAIT_2 timeouts. In 2.xx it is non-tunable + at 600 seconds, while in 3.xx it defaults to 600 seconds and + is calculated based on the tunable "max keep alive probes" + (default of 8) multiplied by the "keep alive interval" (default + 75 seconds). +
    • Squent's ptx/TCP/IP for + DYNIX/ptx has had a FIN_WAIT_2 timeout since around + release 4.1 in mid-1994. +
    +

    +The following systems are known to not have a timeout: +

    +

      +
    • SunOS 4.x does not and + almost certainly never will have one because it as at the + very end of its development cycle for Sun. If you have kernel + source should be easy to patch. +
    +

    +There is a + +patch available for adding a timeout to the FIN_WAIT_2 state; it +was originally intended for BSD/OS, but should be adaptable to most +systems using BSD networking code. You need kernel source code to be +able to use it. If you do adapt it to work for any other systems, +please drop me a note at marc@apache.org. +

    +

    Compile without using lingering_close()

    + +It is possible to compile Apache 1.2 without using the +lingering_close() function. This will result in that +section of code being similar to that which was in 1.1. If you do +this, be aware that it can cause problems with PUTs, POSTs and +persistent connections, especially if the client uses pipelining. +That said, it is no worse than on 1.1, and we understand that keeping your +server running is quite important.

    + +To compile without the lingering_close() function, add +-DNO_LINGCLOSE to the end of the +EXTRA_CFLAGS line in your Configuration file, +rerun Configure and rebuild the server. +

    +

    Use SO_LINGER as an alternative to +lingering_close()

    + +On most systems, there is an option called SO_LINGER that +can be set with setsockopt(2). It does something very +similar to lingering_close(), except that it is broken +on many systems so that it causes far more problems than +lingering_close. On some systems, it could possibly work +better so it may be worth a try if you have no other alternatives.

    + +To try it, add -DUSE_SO_LINGER -DNO_LINGCLOSE to the end of the +EXTRA_CFLAGS line in your Configuration +file, rerun Configure and rebuild the server.

    + +NOTE: Attempting to use SO_LINGER and +lingering_close() at the same time is very likely to do +very bad things, so don't.

    + +

    Increase the amount of memory used for storing connection state

    +
    +
    BSD based networking code: +
    BSD stores network data, such as connection states, +in something called an mbuf. When you get so many connections +that the kernel does not have enough mbufs to put them all in, your +kernel will likely crash. You can reduce the effects of the problem +by increasing the number of mbufs that are available; this will not +prevent the problem, it will just make the server go longer before +crashing.

    + +The exact way to increase them may depend on your OS; look +for some reference to the number of "mbufs" or "mbuf clusters". On +many systems, this can be done by adding the line +NMBCLUSTERS="n", where n is the number of +mbuf clusters you want to your kernel config file and rebuilding your +kernel.

    +

    +

  5. Feedback
  6. + +If you have any information to add to this page, please contact me at +marc@apache.org.

    + +

  7. Appendix
  8. +

    +Below is a message from Roy Fielding, one of the authors of HTTP/1.1. + +

    Why the lingering close functionality is necessary with HTTP

    + +The need for a server to linger on a socket after a close is noted a couple +times in the HTTP specs, but not explained. This explanation is based on +discussions between myself, Henrik Frystyk, Robert S. Thau, Dave Raggett, +and John C. Mallery in the hallways of MIT while I was at W3C.

    + +If a server closes the input side of the connection while the client +is sending data (or is planning to send data), then the server's TCP +stack will signal an RST (reset) back to the client. Upon +receipt of the RST, the client will flush its own incoming TCP buffer +back to the un-ACKed packet indicated by the RST packet argument. +If the server has sent a message, usually an error response, to the +client just before the close, and the client receives the RST packet +before its application code has read the error message from its incoming +TCP buffer and before the server has received the ACK sent by the client +upon receipt of that buffer, then the RST will flush the error message +before the client application has a chance to see it. The result is +that the client is left thinking that the connection failed for no +apparent reason.

    + +There are two conditions under which this is likely to occur: +

      +
    1. sending POST or PUT data without proper authorization +
    2. sending multiple requests before each response (pipelining) + and one of the middle requests resulting in an error or + other break-the-connection result. +
    +

    +The solution in all cases is to send the response, close only the +write half of the connection (what shutdown is supposed to do), and +continue reading on the socket until it is either closed by the +client (signifying it has finally read the response) or a timeout occurs. +That is what the kernel is supposed to do if SO_LINGER is set. +Unfortunately, SO_LINGER has no effect on some systems; on some other +systems, it does not have its own timeout and thus the TCP memory +segments just pile-up until the next reboot (planned or not).

    + +Please note that simply removing the linger code will not solve the +problem -- it only moves it to a different and much harder one to detect. +

+ + + diff --git a/APACHE_1_2_X/htdocs/manual/misc/footer.html b/APACHE_1_2_X/htdocs/manual/misc/footer.html new file mode 100644 index 00000000000..2c2b4103785 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/misc/footer.html @@ -0,0 +1,4 @@ +
+ +Index +Home diff --git a/APACHE_1_2_X/htdocs/manual/misc/header.html b/APACHE_1_2_X/htdocs/manual/misc/header.html new file mode 100644 index 00000000000..8b23a1ccba0 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/misc/header.html @@ -0,0 +1,3 @@ +
+ [APACHE DOCUMENTATION] +
diff --git a/APACHE_1_2_X/htdocs/manual/misc/howto.html b/APACHE_1_2_X/htdocs/manual/misc/howto.html new file mode 100644 index 00000000000..98a1843e831 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/misc/howto.html @@ -0,0 +1,147 @@ + + + + + +Apache HOWTO documentation + + + + + +

Apache HOWTO documentation

+ +How to: + + +
+

How to redirect an entire server or directory to a single URL

+ +

There are two chief ways to redirect all requests for an entire +server to a single location: one which requires the use of +mod_rewrite, and another which uses a CGI script. + +

First: if all you need to do is migrate a server from one name to +another, simply use the Redirect directive, as supplied +by mod_alias: + +

+  Redirect / http://www.apache.org/
+
+ +

Since Redirect will forward along the complete path, +however, it may not be appropriate - for example, when the directory +structure has changed after the move, and you simply want to direct people +to the home page. + +

The best option is to use the standard Apache module mod_rewrite. +If that module is compiled in, the following lines: + +

RewriteEngine On
+RewriteRule /.* http://www.apache.org/ [R]
+
+ +This will send an HTTP 302 Redirect back to the client, and no matter +what they gave in the original URL, they'll be sent to +"http://www.apache.org". + +The second option is to set up a ScriptAlias pointing to +a cgi script which outputs a 301 or 302 status and the location +of the other server.

+ +

By using a cgi-script you can intercept various requests and +treat them specially, e.g. you might want to intercept POST +requests, so that the client isn't redirected to a script on the other +server which expects POST information (a redirect will lose the POST +information.) You might also want to use a CGI script if you don't +want to compile mod_rewrite into your server. + +

Here's how to redirect all requests to a script... In the server +configuration file, +

ScriptAlias / /usr/local/httpd/cgi-bin/redirect_script
+ +and here's a simple perl script to redirect requests: + +
+#!/usr/local/bin/perl
+
+print "Status: 302 Moved Temporarily\r
+Location: http://www.some.where.else.com/\r\n\r\n";
+
+

+ +
+ +

How to reset your log files

+ +

Sooner or later, you'll want to reset your log files (access_log and +error_log) because they are too big, or full of old information you don't +need.

+ +

access.log typically grows by 1Mb for each 10,000 requests.

+ +

Most people's first attempt at replacing the logfile is to just move the +logfile or remove the logfile. This doesn't work.

+ +

Apache will continue writing to the logfile at the same offset as before the +logfile moved. This results in a new logfile being created which is just +as big as the old one, but it now contains thousands (or millions) of null +characters.

+ +

The correct procedure is to move the logfile, then signal Apache to tell it to reopen the logfiles.

+ +

Apache is signaled using the SIGHUP (-1) signal. e.g. +

+mv access_log access_log.old
+kill -1 `cat httpd.pid` +
+

+ +

Note: httpd.pid is a file containing the process id +of the Apache httpd daemon, Apache saves this in the same directory as the log +files.

+ +

Many people use this method to replace (and backup) their logfiles on a +nightly or weekly basis.

+
+ +

How to stop or restrict robots

+ +

Ever wondered why so many clients are interested in a file called +robots.txt which you don't have, and never did have?

+ +

These clients are called robots (also known as crawlers, +spiders and other cute name) - special automated clients which +wander around the web looking for interesting resources.

+ +

Most robots are used to generate some kind of web index which +is then used by a search engine to help locate information.

+ +

robots.txt provides a means to request that robots limit their +activities at the site, or more often than not, to leave the site alone.

+ +

When the first robots were developed, they had a bad reputation for sending hundreds/thousands of requests to each site, often resulting in the site being overloaded. Things have improved dramatically since then, thanks to Guidelines for Robot Writers, but even so, some robots may exhibit unfriendly behavior which the webmaster isn't willing to tolerate, and will want to stop.

+ +

Another reason some webmasters want to block access to robots, is to +stop them indexing dynamic information. Many search engines will use the +data collected from your pages for months to come - not much use if your +serving stock quotes, news, weather reports or anything else that will be +stale by the time people find it in a search engine.

+ +

If you decide to exclude robots completely, or just limit the areas +in which they can roam, create a robots.txt file; refer +to the robot information pages provided by Martijn Koster for the syntax.

+ + + + diff --git a/APACHE_1_2_X/htdocs/manual/misc/index.html b/APACHE_1_2_X/htdocs/manual/misc/index.html new file mode 100755 index 00000000000..127b1f2f0d3 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/misc/index.html @@ -0,0 +1,119 @@ + + + + Apache Miscellaneous Documentation + + + + + +

Apache Miscellaneous Documentation

+ +

+ Below is a list of additional documentation pages that apply to the + Apache web server development project. +

+
+
API +
+
Description of Apache's Application Programming Interface. +
+
FAQ +
+
Frequently-Asked Questions concerning the Apache project and server +
+
Reading Client Input in Apache 1.2 +
+
Describes differences between Apache 1.1 and 1.2 in how modules + read information from the client +
+
Compatibility with NCSA +
+
Notes about Apache's compatibility with the NCSA server +
+
FIN_WAIT_2 +
+
A description of the causes of Apache processes going into the + FIN_WAIT_2 state, and what you can do about it +
+
"How-To" +
+
Instructions about how to accomplish some commonly-desired server + functionality changes +
+
Known Bugs +
+
Just what it says - a list of known bugs in each of the Apache releases +
+
No PGP +
+
Why we took PEM and PGP support out of the base Apache distribution +
+
Performance Notes (BSD 4.4) +
+
Some notes about ways to improve/optimize Apache performance on + BSD 4.4 systems +
+
Performance Notes (Digital UNIX) +
+
Extracts of USENET postings describing how to optimize Apache + performance on Digital UNIX systems +
+
Performance Notes (General) +
+
Some generic notes about how to improve Apache performance +
+
Security Tips +
+
Some "do"s - and "don't"s - for keeping your + Apache web site secure +
+
Virtual Hosts (IP-based) +
+
Excerpts and notes about configuring and using Apache IP-based virtual + hosts +
+
Windows Bug with Web Keepalive +
+
A brief description of a known problem with Microsoft Windows and + web sites accessed using keepalive connections +
+
+ + + + diff --git a/APACHE_1_2_X/htdocs/manual/misc/known_bugs.html b/APACHE_1_2_X/htdocs/manual/misc/known_bugs.html new file mode 100644 index 00000000000..68054d4a585 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/misc/known_bugs.html @@ -0,0 +1,310 @@ + + + +Apache HTTP Server Project + + + + + +

Known Bugs in Apache

+ +The most up-to-date resource for bug tracking and information is the +Apache bug database. +All existing bugs will be noted there. Below is a synopsis of +significant outstanding bugs at release time. In fact you really +shouldn't trust anything this page says other than maybe the 1.2b8 +information. + +

See Also: Compatibility notes

+
+ +

Version 1.2 (all)

+ +
    +
  1. On some architectures if your configuration uses multiple + Listen directives then it is possible + that the server will starve one of the sockets while serving hits on + another. The work-around is to add + -DUSE_FLOCK_SERIALIZED_ACCEPT to the + EXTRA_CFLAGS line in your Configuration and rebuild. + (If you encounter problems with that, you can also try + -DUSE_FCNTL_SERIALIZED_ACCEPT.) + This affects any architecture that doesn't use one of the + USE_xxxxx_SERIALIZED_ACCEPT definitions, see the + source file conf.h for your architecture. +

    This will be tracked as + PR#467. +

  2. +
+ +

Version 1.2b8

+ +There are several known bugs in 1.2b8. See the +1.2b8 patches +directory for patches for some of the ones that have been fixed since +the release of 1.2b8.

+ +

Version 1.2b1

+ +
    + +
  1. users have reported problems with many connections stuck in the +FIN_WAIT_2 state due to server timeouts. This is a quite complicated +problem; see our FIN_WAIT_2 page for +details. + +
  2. hard_timeout() for request reads uses incorrect logic, and +ends up waiting for an initial request read for the default "timeout" +number of seconds, 1200, yet only the "KeepAliveTimeout" number of +seconds on keepalive connections. + +
  3. mod_info output is not displaying current configuration as +it should. + +
  4. Invalid commands in .htaccess files may cause segmentation faults. + +
+ +

Version 1.1.1

+ +
    + +
  1. Hostnames such as "123.hotwired.com" are valid, yet +find_allowdeny does not properly handle them. This should be put on +Known Bugs. Be careful when fixing this because just removing the +isalpha() check creates a security hole, consider the DNS map +"1.1.1.1.in-addr.arpa IN PTR 2.2.2." if the user has a config line +"allow from 2.2.2" it will allow 1.1.1.1 in (unless -DMAXIMUM_DNS). +-- which is bad because it breaks people who understand double reverse +lookup and are trying to avoid it by using only IP addresses on +allow/deny statements. - reported by Dean Gaudet, fixed in 1.2. + +
+ + +

Version 1.1.0

+ +
    +
  1. mod_auth_msql misbehaviors. Grab a newer version from + the modules distribution + directory. -fixed in 1.1 + +
  2. Hanging on Netscape 2.0-3.0b4 on MSWindows (3.1 and 95) - + we investigated pretty seriously, and as best we can tell + this is a Netscape bug, and was fixed in 3.0b5. Please read our + lab report. + +
+ +

Version 1.1b2 (beta)

+
    +
  1. SunOS has trouble compiling mod_status.c . It'll be fixed + before 1.1 is released.
  2. + +
  3. CGI which spawn background processes may fail to return immediately. + No fix exists yet.
  4. + +
  5. mod_dir appears to have problems when the DocumentRoot has a + trailing slash.
  6. + +
+

Version 1.1b1 (beta)

+
    +
  1. The logfile can sometimes contain only part of a host + address. This occurs if the Cookie module is compiled in + and enabled. +
+ +

Version 0.8.16 (beta)

+
    +
  1. (Feature) You cannot use relative pathnames for the -f or -d flags + to httpd.

    +

  2. .asis files cannot be used for content-negotiation. +
+ +

Version 0.8.13 (beta)

+ +
    +
  1. AddDescription doesn't seem to work (a fix is imminent)
  2. +
+ +

Version 0.8.11 (beta)

+
    +
  1. http_main.c function accept_mutex_init() + horrible bug, lock_fname should be defined larger, e.g. +
    + char lock_fname[30]; +
    +
    Ooops. + +

    + +

  2. There's a bug with NeXT. Restarting the server causes an + infinite loop. A fix has been provided by a user and should be included + in a future update. + +

    + +

+ + +

Version 0.8.10 (beta)

+ +
    +
  1. Server side includes which include CGI output can have unbearable + delays on some platforms. We're looking into a fix. + +

    + +

  2. NCSA 1.3 and beyond allow wildcards in <Directory> tags; e.g. + <Directory /home/*/public_html> - Apache doesn't (yet), + but we have a patch coming real soon now + +

    + +

  3. Buggy scripts can cause server misbehavior on Solaris at least. + +

    + +

  4. Some of the default directives in srm.conf-dist are outdated + +

    + +

  5. Descriptions of args to AddIcon and AddAlt are wrong + in command table. + +

    + +

  6. DirectoryIndex sometimes gets spuriously reset to the default value. + +

    + +

  7. ErrorDocument is a little shaky, " Some text %s doesn't + agree with the documentation. + +

    + +

  8. All Aliases are checked before any ScriptAliases --- the fully + compatible behavior would be to check both in one pass, in the order + in which they occur in srm.conf. + +

    +

+ +

Version 0.8.8 (beta)

+ +
    +
  1. There's a known compilation problem with NeXT. Knock out the + 2nd argument to setjmp when your compiler complains.

    +
  2. + +
  3. exec cgi="" produces reasonable malformed header + responses when used to invoke non-CGI scripts.
    + The NCSA code ignores the missing header. (bad idea)
    + Solution: write CGI to the CGI spec or use exec cmd="" instead. +

    We might add virtual support to exec cmd to + make up for this difference.

    + +
  4. A scoreboard file for process management is currently + created in /tmp. We now find this to be a bad idea, and have plans + to move it into the /logs directory along with other + files created by Apache. +

    If you have any /tmp cleaning scripts (e.g. from crontab), you + should have them ignore the scoreboard file, which is named + /tmp/htstatus.XXXXXXX. If the scoreboard file is damaged, Apache + can become very confused (a SIGHUP repairs the damage). Furthermore, not + having a /tmp at all can cause disastrous results, as there's no error + checking yet.

    + +

  5. Putting authorization information (like AuthName and AuthType) into a + <Directory> directive without a "requires" field in the <Limit> + directive can result in a core dump.

    + +

  6. AddIcon is broken. The fix is to change
    + + { "AddIcon", add_icon, BY_TYPE, DIR_CMD_PERMS, ITERATE2, + +
    to
    + + { "AddIcon", add_icon, BY_PATH, DIR_CMD_PERMS, ITERATE2, + +

    in mod_dir.c

  7. + +
  8. Under IRIX, the "Group" directive in httpd.conf needs to be a valid group name + (i.e. "nogroup") not the numeric group ID. The distribution httpd.conf, and earlier + ones, had the default Group be "#-1", which was causing silent exits at startup. + +

    + + +

  9. Server push as regular CGI's don't work - actually, any normal CGI script + that outputs additional attributes to the Content-type line (separated by a + semicolon) gets that extra information chopped off, which means that the line + Content-type: multipart/x-mixed-replace; boundary=ThisRandomString + gets munged to just Content-type: multipart/x-mixed-replace, which + means it doesn't know what the boundary is, and fails. You can get around this + until 0.8.9 by making the CGI script a "No Parsed Header" script by prefixing the + name of the script with a "nph-", but then you have to be responsible for correct + HTTP headers. If the server-push animation is a constant, unchanging stream that + terminates at some point, you could also put that stream into a whole file and + use the .asis file extension functionality. + +

    + +

  10. ErrorDocument is a little shaky, " Some text %s doesn't + agree with the documentation. + +

    + +

+ +
+ +

Version 0.6.4

+
    +
  1. As with NCSA 1.3 (and 1.4 ?), some HEAD requests on +directories without an index.html fail to be logged... harmless.
  2. +
  3. Typo in Virtual Host #defines (accidentally defined #VIRUAL_HOST"). 0.6.4b fixes this. +
+

Version 0.6.2 (first beta)

+
    + +
  1. Apache error_log might show httpd: caught SIGBUS, dumping core after a successful redirect. We hope to fix this in 0.6.3

  2. + +
  3. If you see a lot of messages such as, +

    access to /something: failed for foo.bar.com, reason: no multi in this directory
    +in your error log, don't panic !. It means "File not found", and we will +fix it sooner or later. + +

    + +
  4. WARNING: Apache logs all URLs redirected from and +to. This isn't bug, it's deliberate, but you should be aware +of it. It's a recognition of the fact that the Common Log File format +doesn't have any place to log the real object that was returned for +the internally redirected request. This will be changed soon. + +

    + +
  5. BSDI problems: One of the test machines (Hyperreal) has noticed "flocks" of +child processes sucking up large amounts of resources when moderately +hit (on a Pentium 90 running 1.1 serving ~2 hits/second). Killing and +restarting the daemon helps this disappear - it's being investigated, +it might be a kernel bug, but then every server developer likes to say +that. Let us know how well it works for you if you are using BSDI and +have a high number of hits.

  6. + +
+ + + + + diff --git a/APACHE_1_2_X/htdocs/manual/misc/nopgp.html b/APACHE_1_2_X/htdocs/manual/misc/nopgp.html new file mode 100644 index 00000000000..8e66fadb388 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/misc/nopgp.html @@ -0,0 +1,88 @@ + + + +Why We Took PEM Out of Apache + + + + + +

Why We Took PEM Out of Apache

+ +On May 17th, 1995, we were asked by a representative of NCSA to remove +any copies of NCSA httpd prior to 1.4.1 from our web site. They +were mandated by the NSA to inform us that redistribution of pre-1.4.1 +code violated the same laws that make distributing Phill Zimmerman's +PGP package to other countries illegal. There was no +encryption in NCSA's httpd, only hooks to publicly available libraries +of PEM code. By the NSA's rules, even hooks to this type of +application is illegal. + +

+ +Because Apache is based on NCSA code, and we had basically not touched +that part of the software, we were informed that Apache was also +illegal to distribute to foreign countries, and advised (not mandated) +by NCSA to remove it. So, we removed both the copies of the NCSA +httpd we had, and all versions of Apache previous to 0.6.5. + +

+ +The Apache members are strong advocates of the right to digital +privacy, so the decision to submit to the NSA and remove the code was +not an easy one. Here are some elements in our rationale: + +

    + +
  • The PEM code in httpd was not widely used. No major site relied +upon its use, so its loss is not a blow to encryption and security on +the world wide web. There are other efforts designed to give much +more flexible security - SSL and SHTTP - so this wasn't a function +whose absence would really be missed on a functional level. + +
  • We didn't feel like being just a couple more martyrs in a fight +being fought very well by many other people. Rather than have the +machine that supports the project confiscated or relocated to South +Africa, etc., we think there are more efficient methods to address the +issue. + +
+ +It kind of sickens us that we had to do it, but so be it. + +

+ +Patches that re-implement the PEM code may be available at a foreign +site soon. If it does show up, we'll point to it - that can't be illegal! + +

+ +Finally, here is a compendium of pointers to sites related to +encryption and export law. We can't promise this list will be up to +date, so send us mail when you see a problem or want a link added. +Thanks. + +

+ + Brian, brian@hyperreal.com + + + + diff --git a/APACHE_1_2_X/htdocs/manual/misc/perf-bsd44.html b/APACHE_1_2_X/htdocs/manual/misc/perf-bsd44.html new file mode 100644 index 00000000000..0a1661b7ca3 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/misc/perf-bsd44.html @@ -0,0 +1,236 @@ + + + +Running a High-Performance Web Server for BSD + + + + + + + +

Running a High-Performance Web Server for BSD

+ +Like other OS's, the listen queue is often the first limit hit. The +following are comments from "Aaron Gifford <agifford@InfoWest.COM>" +on how to fix this on BSDI 1.x, 2.x, and FreeBSD 2.0 (and earlier): + +

+ +Edit the following two files: +

/usr/include/sys/socket.h
+ /usr/src/sys/sys/socket.h
+In each file, look for the following: +
+    /*
+     * Maximum queue length specifiable by listen.
+     */
+    #define SOMAXCONN       5
+
+ +Just change the "5" to whatever appears to work. I bumped the two +machines I was having problems with up to 32 and haven't noticed the +problem since. + +

+ +After the edit, recompile the kernel and recompile the Apache server +then reboot. + +

+ +FreeBSD 2.1 seems to be perfectly happy, with SOMAXCONN +set to 32 already. + +

+ + +Addendum for very heavily loaded BSD servers
+
+from Chuck Murcko <chuck@telebase.com> + +

+ +If you're running a really busy BSD Apache server, the following are useful +things to do if the system is acting sluggish:

+ +

    + +
  • Run vmstat to check memory usage, page/swap rates, etc. + +
  • Run netstat -m to check mbuf usage + +
  • Run fstat to check file descriptor usage + +
+ +These utilities give you an idea what you'll need to tune in your kernel, +and whether it'll help to buy more RAM. + +Here are some BSD kernel config parameters (actually BSDI, but pertinent to +FreeBSD and other 4.4-lite derivatives) from a system getting heavy usage. +The tools mentioned above were used, and the system memory was increased to +48 MB before these tuneups. Other system parameters remained unchanged. + +

+ +

+maxusers        256
+
+ +Maxusers drives a lot of other kernel parameters: + +
    + +
  • Maximum # of processes + +
  • Maximum # of processes per user + +
  • System wide open files limit + +
  • Per-process open files limit + +
  • Maximum # of mbuf clusters + +
  • Proc/pgrp hash table size + +
+ +The actual formulae for these derived parameters are in +/usr/src/sys/conf/param.c. +These calculated parameters can also be overridden (in part) by specifying +your own values in the kernel configuration file: + +
+# Network options. NMBCLUSTERS defines the number of mbuf clusters and
+# defaults to 256. This machine is a server that handles lots of traffic,
+# so we crank that value.
+options         SOMAXCONN=256           # max pending connects
+options         NMBCLUSTERS=4096        # mbuf clusters at 4096
+
+#
+# Misc. options
+#
+options         CHILD_MAX=512           # maximum number of child processes
+options         OPEN_MAX=512            # maximum fds (breaks RPC svcs)
+
+ +SOMAXCONN is not derived from maxusers, so you'll always need to increase +that yourself. We used a value guaranteed to be larger than Apache's +default for the listen() of 128, currently. + +

+ +In many cases, NMBCLUSTERS must be set much larger than would appear +necessary at first glance. The reason for this is that if the browser +disconnects in mid-transfer, the socket fd associated with that particular +connection ends up in the TIME_WAIT state for several minutes, during +which time its mbufs are not yet freed. Another reason is that, on server +timeouts, some connections end up in FIN_WAIT_2 state forever, because +this state doesn't time out on the server, and the browser never sent +a final FIN. For more details see the +FIN_WAIT_2 page. + +

+ +Some more info on mbuf clusters (from sys/mbuf.h): +

+/*
+ * Mbufs are of a single size, MSIZE (machine/machparam.h), which
+ * includes overhead.  An mbuf may add a single "mbuf cluster" of size
+ * MCLBYTES (also in machine/machparam.h), which has no additional overhead
+ * and is used instead of the internal data area; this is done when
+ * at least MINCLSIZE of data must be stored.
+ */
+
+ +

+ +CHILD_MAX and OPEN_MAX are set to allow up to 512 child processes (different +than the maximum value for processes per user ID) and file descriptors. +These values may change for your particular configuration (a higher OPEN_MAX +value if you've got modules or CGI scripts opening lots of connections or +files). If you've got a lot of other activity besides httpd on the same +machine, you'll have to set NPROC higher still. In this example, the NPROC +value derived from maxusers proved sufficient for our load. + +

+ +Caveats + +

+ +Be aware that your system may not boot with a kernel that is configured +to use more resources than you have available system RAM. ALWAYS +have a known bootable kernel available when tuning your system this way, +and use the system tools beforehand to learn if you need to buy more +memory before tuning. + +

+ +RPC services will fail when the value of OPEN_MAX is larger than 256. +This is a function of the original implementations of the RPC library, +which used a byte value for holding file descriptors. BSDI has partially +addressed this limit in its 2.1 release, but a real fix may well await +the redesign of RPC itself. + +

+ +Finally, there's the hard limit of child processes configured in Apache. + +

+ +For versions of Apache later than 1.0.5 you'll need to change the +definition for HARD_SERVER_LIMIT in httpd.h and recompile +if you need to run more than the default 150 instances of httpd. + +

+ +From conf/httpd.conf-dist: + +

+# Limit on total number of servers running, i.e., limit on the number
+# of clients who can simultaneously connect --- if this limit is ever
+# reached, clients will be LOCKED OUT, so it should NOT BE SET TOO LOW.
+# It is intended mainly as a brake to keep a runaway server from taking
+# Unix with it as it spirals down...
+
+MaxClients 150
+
+ +Know what you're doing if you bump this value up, and make sure you've +done your system monitoring, RAM expansion, and kernel tuning beforehand. +Then you're ready to service some serious hits! + +

+ +Thanks to Tony Sanders and Chris Torek at BSDI for their +helpful suggestions and information. + +

+ +"M. Teterin" <mi@ALDAN.ziplink.net> writes:

+

It really does help if your kernel and frequently used utilities +are fully optimized. Rebuilding the FreeBSD kernel on an AMD-133 +(486-class CPU) web-server with
+ -m486 -fexpensive-optimizations -fomit-frame-ponter -O2
+helped reduce the number of "unable" errors, because the CPU was +often maxed out.
+

+ +


+ +

More welcome!

+ +If you have tips to contribute, send mail to brian@organic.com + + + + diff --git a/APACHE_1_2_X/htdocs/manual/misc/perf-dec.html b/APACHE_1_2_X/htdocs/manual/misc/perf-dec.html new file mode 100644 index 00000000000..7cc8bb13081 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/misc/perf-dec.html @@ -0,0 +1,279 @@ + + + +Performance Tuning Tips for Digital Unix + + + + +

Performance Tuning Tips for Digital Unix

+ +Below is a set of newsgroup posts made by an engineer from DEC in +response to queries about how to modify DEC's Digital Unix OS for more +heavily loaded web sites. Copied with permission. + +
+ +

Update

+From: Jeffrey Mogul <mogul@pa.dec.com>
+Date: Fri, 28 Jun 96 16:07:56 MDT
+ +
    +
  1. The advice given in the README file regarding the + "tcbhashsize" variable is incorrect. The largest value + this should be set to is 1024. Setting it any higher + will have the perverse result of disabling the hashing + mechanism. + +
  2. Patch ID OSF350-146 has been superseded by +
    + Patch ID OSF350-195 for V3.2C
    + Patch ID OSF360-350195 for V3.2D +
    + Patch IDs for V3.2E and V3.2F should be available soon. + There is no known reason why the Patch ID OSF360-350195 + won't work on these releases, but such use is not officially + supported by Digital. This patch kit will not be needed for + V3.2G when it is released. +
+
+ + +
+From           mogul@pa.dec.com (Jeffrey Mogul)
+Organization   DEC Western Research
+Date           30 May 1996 00:50:25 GMT
+Newsgroups     comp.unix.osf.osf1
+Message-ID     <4oirch$bc8@usenet.pa.dec.com>
+Subject        Re: Web Site Performance
+References     1
+
+
+
+In article <skoogDs54BH.9pF@netcom.com> skoog@netcom.com (Jim Skoog) writes:
+>Where are the performance bottlenecks for Alpha AXP running the
+>Netscape Commerce Server 1.12 with high volume internet traffic?
+>We are evaluating network performance for a variety of Alpha AXP
+>runing DEC UNIX 3.2C, which run DEC's seal firewall and behind
+>that Alpha 1000 and 2100 webservers.
+
+Our experience (running such Web servers as altavista.digital.com
+and www.digital.com) is that there is one important kernel tuning
+knob to adjust in order to get good performance on V3.2C.  You
+need to patch the kernel global variable "somaxconn" (use dbx -k
+to do this) from its default value of 8 to something much larger.
+
+How much larger?  Well, no larger than 32767 (decimal).  And
+probably no less than about 2048, if you have a really high volume
+(millions of hits per day), like AltaVista does.
+
+This change allows the system to maintain more than 8 TCP
+connections in the SYN_RCVD state for the HTTP server.  (You
+can use "netstat -An |grep SYN_RCVD" to see how many such
+connections exist at any given instant).
+
+If you don't make this change, you might find that as the load gets
+high, some connection attempts take a very long time.  And if a lot
+of your clients disconnect from the Internet during the process of
+TCP connection establishment (this happens a lot with dialup
+users), these "embryonic" connections might tie up your somaxconn
+quota of SYN_RCVD-state connections.  Until the kernel times out
+these embryonic connections, no other connections will be accepted,
+and it will appear as if the server has died.
+
+The default value for somaxconn in Digital UNIX V4.0 will be quite
+a bit larger than it has been in previous versions (we inherited
+this default from 4.3BSD).
+
+Digital UNIX V4.0 includes some other performance-related changes
+that significantly improve its maximum HTTP connection rate.  However,
+we've been using V3.2C systems to front-end for altavista.digital.com
+with no obvious performance bottlenecks at the millions-of-hits-per-day
+level.
+
+We have some Webstone performance results available at
+        http://www.digital.com/info/alphaserver/news/webff.html
+I'm not sure if these were done using V4.0 or an earlier version
+of Digital UNIX, although I suspect they were done using a test
+version of V4.0.
+
+-Jeff
+
+
+ +---------------------------------------------------------------------------- + +From mogul@pa.dec.com (Jeffrey Mogul) +Organization DEC Western Research +Date 31 May 1996 21:01:01 GMT +Newsgroups comp.unix.osf.osf1 +Message-ID <4onmmd$mmd@usenet.pa.dec.com> +Subject Digital UNIX V3.2C Internet tuning patch info + +---------------------------------------------------------------------------- + +Something that probably few people are aware of is that Digital +has a patch kit available for Digital UNIX V3.2C that may improve +Internet performance, especially for busy web servers. + +This patch kit is one way to increase the value of somaxconn, +which I discussed in a message here a day or two ago. + +I've included in this message the revised README file for this +patch kit below. Note that the original README file in the patch +kit itself may be an earlier version; I'm told that the version +below is the right one. + +Sorry, this patch kit is NOT available for other versions of Digital +UNIX. Most (but not quite all) of these changes also made it into V4.0, +so the description of the various tuning parameters in this README +file might be useful to people running V4.0 systems. + +This patch kit does not appear to be available (yet?) from + http://www.service.digital.com/html/patch_service.html +so I guess you'll have to call Digital's Customer Support to get it. + +-Jeff + +DESCRIPTION: Digital UNIX Network tuning patch + + Patch ID: OSF350-146 + + SUPERSEDED PATCHES: OSF350-151, OSF350-158 + + This set of files improves the performance of the network + subsystem on a system being used as a web server. There are + additional tunable parameters included here, to be used + cautiously by an informed system administrator. + +TUNING + + To tune the web server, the number of simultaneous socket + connection requests are limited by: + + somaxconn Sets the maximum number of pending requests + allowed to wait on a listening socket. The + default value in Digital UNIX V3.2 is 8. + This patch kit increases the default to 1024, + which matches the value in Digital UNIX V4.0. + + sominconn Sets the minimum number of pending connections + allowed on a listening socket. When a user + process calls listen with a backlog less + than sominconn, the backlog will be set to + sominconn. sominconn overrides somaxconn. + The default value is 1. + + The effectiveness of tuning these parameters can be monitored by + the sobacklog variables available in the kernel: + + sobacklog_hiwat Tracks the maximum pending requests to any + socket. The initial value is 0. + + sobacklog_drops Tracks the number of drops exceeding the + socket set backlog limit. The initial + value is 0. + + somaxconn_drops Tracks the number of drops exceeding the + somaxconn limit. When sominconn is larger + than somaxconn, tracks the number of drops + exceeding sominconn. The initial value is 0. + + TCP timer parameters also affect performance. Tuning the following + require some knowledge of the characteristics of the network. + + tcp_msl Sets the tcp maximum segment lifetime. + This is the maximum lifetime in half + seconds that a packet can be in transit + on the network. This value, when doubled, + is the length of time a connection remains + in the TIME_WAIT state after a incoming + close request is processed. The unit is + specified in 1/2 seconds, the initial + value is 60. + + tcp_rexmit_interval_min + Sets the minimum TCP retransmit interval. + For some WAN networks the default value may + be too short, causing unnecessary duplicate + packets to be sent. The unit is specified + in 1/2 seconds, the initial value is 1. + + tcp_keepinit This is the amount of time a partially + established connection will sit on the listen + queue before timing out (e.g. if a client + sends a SYN but never answers our SYN/ACK). + Partially established connections tie up slots + on the listen queue. If the queue starts to + fill with connections in SYN_RCVD state, + tcp_keepinit can be decreased to make those + partial connects time out sooner. This should + be used with caution, since there might be + legitimate clients that are taking a while + to respond to SYN/ACK. The unit is specified + in 1/2 seconds, the default value is 150 + (ie. 75 seconds). + + The hashlist size for the TCP inpcb lookup table is regulated by: + + tcbhashsize The number of hash buckets used for the + TCP connection table used in the kernel. + The initial value is 32. For best results, + should be specified as a power of 2. For + busy Web servers, set this to 2048 or more. + + The hashlist size for the interface alias table is regulated by: + + inifaddr_hsize The number of hash buckets used for the + interface alias table used in the kernel. + The initial value is 32. For best results, + should be specified as a power of 2. + + ipport_userreserved The maximum number of concurrent non-reserved, + dynamically allocated ports. Default range + is 1025-5000. The maximum value is 65535. + This limits the numer of times you can + simultaneously telnet or ftp out to connect + to other systems. + + tcpnodelack Don't delay acknowledging TCP data; this + can sometimes improve performance of locally + run CAD packages. Default is value is 0, + the enabled value is 1. + + Digital UNIX version: + + V3.2C +Feature V3.2C patch V4.0 + ======= ===== ===== ==== +somaxconn X X X +sominconn - X X +sobacklog_hiwat - X - +sobacklog_drops - X - +somaxconn_drops - X - +tcpnodelack X X X +tcp_keepidle X X X +tcp_keepintvl X X X +tcp_keepcnt - X X +tcp_keepinit - X X +TCP keepalive per-socket - - X +tcp_msl - X - +tcp_rexmit_interval_min - X - +TCP inpcb hashing - X X +tcbhashsize - X X +interface alias hashing - X X +inifaddr_hsize - X X +ipport_userreserved - X - +sysconfig -q inet - - X +sysconfig -q socket - - X + +
+ + + diff --git a/APACHE_1_2_X/htdocs/manual/misc/perf.html b/APACHE_1_2_X/htdocs/manual/misc/perf.html new file mode 100644 index 00000000000..96c48ea1992 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/misc/perf.html @@ -0,0 +1,146 @@ + + + +Hints on Running a High-Performance Web Server + + + + + +

Hints on Running a High-Performance Web Server

+ +Running Apache on a heavily loaded web server, one often encounters +problems related to the machine and OS configuration. "Heavy" is +relative, of course - but if you are seeing more than a couple hits +per second on a sustained basis you should consult the pointers on +this page. In general the suggestions involve how to tune your kernel +for the heavier TCP load, hardware/software conflicts that arise, etc. + + + +
+ +

+A/UX (Apple's UNIX) +

+ +If you are running Apache on A/UX, a page that gives some helpful +performance hints (concerning the listen() queue and using +virtual hosts) +can be found here + +


+ +

+BSD-based (BSDI, FreeBSD, etc) +

+ +Quick and +detailed +performance tuning hints for BSD-derived systems. + +


+ +

+Digital UNIX +

+ + + +


+ +

+Hewlett-Packard +

+ +Some documentation on tuning HP machines can be found at http://www.software.hp.com/internet/perf/tuning.html. + +


+ +

+Linux +

+ +The most common problem on Linux shows up on heavily-loaded systems +where the whole server will appear to freeze for a couple of minutes +at a time, and then come back to life. This has been traced to a +listen() queue overload - certain Linux implementations have a low +value set for the incoming connection queue which can cause problems. +Please see our Using Apache on +Linux page for more info on how to fix this. + +


+ +

+SGI +

+ + + +


+ +

+Solaris 2.4 +

+ +The Solaris 2.4 TCP implementation has a few inherent limitations that +only became apparent under heavy loads. This has been fixed to some +extent in 2.5 (and completely revamped in 2.6), but for now consult +the following URL for tips on how to expand the capabilities if you +are finding slowdowns and lags are hurting performance. + + + +


+ +

+SunOS 4.x +

+ +More information on tuning SOMAXCONN on SunOS can be found at + +http://www.islandnet.com/~mark/somaxconn.html. + +


+ +

More welcome!

+ +If you have tips to contribute, send mail to brian@organic.com + + + + diff --git a/APACHE_1_2_X/htdocs/manual/misc/security_tips.html b/APACHE_1_2_X/htdocs/manual/misc/security_tips.html new file mode 100644 index 00000000000..cba41ada90f --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/misc/security_tips.html @@ -0,0 +1,186 @@ + + + +Apache HTTP Server: Security Tips + + + + + +

Security Tips for Server Configuration

+ +
+ +

Some hints and tips on security issues in setting up a web server. Some of +the suggestions will be general, others specific to Apache. + +


+ +

Permissions on Log File Directories

+

When Apache starts, it opens the log files as the user who started the +server before switching to the user defined in the +User directive. Anyone who +has write permission for the directory where any log files are +being written to can append pseudo-arbitrary data to any file on the +system which is writable by the user who starts Apache. Since the +server is normally started by root, you should NOT give anyone +write permission to the directory where logs are stored unless you +want them to have root access. +

+


+

Server Side Includes

+

Server side includes (SSI) can be configured so that users can execute +arbitrary programs on the server. That thought alone should send a shiver +down the spine of any sys-admin.

+ +One solution is to disable that part of SSI. To do that you use the +IncludesNOEXEC option to the Options +directive.

+ +


+ +

Non Script Aliased CGI

+

Allowing users to execute CGI scripts in any directory should only +be considered if; +

    +
  1. You trust your users not to write scripts which will deliberately or +accidentally expose your system to an attack. +
  2. You consider security at your site to be so feeble in other areas, as to +make one more potential hole irrelevant. +
  3. You have no users, and nobody ever visits your server. +

+


+ +

Script Alias'ed CGI

+

Limiting CGI to special directories gives the admin control over +what goes into those directories. This is inevitably more secure than +non script aliased CGI, but only if users with write access to the +directories are trusted or the admin is willing to test each new CGI +script/program for potential security holes.

+ +Most sites choose this option over the non script aliased CGI approach.

+ +


+

CGI in general

+

Always remember that you must trust the writers of the CGI script/programs +or your ability to spot potential security holes in CGI, whether they were +deliberate or accidental.

+ +All the CGI scripts will run as the same user, so they have potential to +conflict (accidentally or deliberately) with other scripts e.g. +User A hates User B, so he writes a script to trash User B's CGI +database. One program which can be used to allow scripts to run +as different users is suEXEC which is +included with Apache as of 1.2 and is called from special hooks in +the Apache server code. Another popular way of doing this is with +CGIWrap.

+ +


+ + +

Stopping users overriding system wide settings...

+

To run a really tight ship, you'll want to stop users from setting +up .htaccess files which can override security features +you've configured. Here's one way to do it...

+ +In the server configuration file, put +

+<Directory />
+AllowOverride None
+Options None
+allow from all
+</Directory>
+
+ +Then setup for specific directories

+ +This stops all overrides, Includes and accesses in all directories apart +from those named.

+


+

+ Protect server files by default +

+

+One aspect of Apache which is occasionally misunderstood is the feature +of default access. That is, unless you take steps to change it, if the +server can find its way to a file through normal URL mapping rules, it +can serve it to clients. +

+

+For instance, consider the following example: +

+
    +
  1. # cd /; ln -s / public_html +
  2. +
  3. Accessing http://localhost/~root/ +
  4. +
+

+This would allow clients to walk through the entire filesystem. To work +around this, add the following block to your server's configuration: +

+
+ <Directory />
+     Order deny,allow
+     Deny from all
+ </Directory>
+
+

+This will forbid default access to filesystem locations. Add +appropriate +<Directory> +blocks to allow access only +in those areas you wish. For example, +

+
+ <Directory /usr/users/*/public_html>
+     Order deny,allow
+     Allow from all
+ </Directory>
+ <Directory /usr/local/httpd>
+     Order deny,allow
+     Allow from all
+ </Directory>
+
+

+Pay particular attention to the interactions of +<Location> +and +<Directory> +directives; for instance, even if <Directory /> +denies access, a <Location /> directive might +overturn it. +

+

+Also be wary of playing games with the +UserDir +directive; setting it to something like "./" +would have the same effect, for root, as the first example above. +

+ +
+

Please send any other useful security tips to The Apache Group +by filling out a +problem report, or by +sending mail to +apache-bugs@mail.apache.org +

+


+ + + + diff --git a/APACHE_1_2_X/htdocs/manual/misc/vif-info.html b/APACHE_1_2_X/htdocs/manual/misc/vif-info.html new file mode 100644 index 00000000000..f38f7375d61 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/misc/vif-info.html @@ -0,0 +1,399 @@ + + +Configuring Multiple IP Addresses + + + + +

Configuring Multiple IP Addresses

+ +
+This material is originally from John Ioannidis (ji@polaris.ctr.columbia.edu)
+I have condensed it some and applied some corrections for SunOS 4.1.x
+courtesy of Chuck Smoko (csmoko@relay.nswc.navy.mil).
+
+Bob Baggerman  (bob@bizweb.com)
+12 Jan 94
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+John Ionnidis writes:
+
+This is a topic that comes up once in a while on comp.protocols.tcp-ip
+and other newsgroups. The question is, how to get a machine with one
+network interface to respond to more than one IP addresses. 
+
+I have a solution than might suit you.  For my doctoral work (there's
+a paper about it in this year's ('91) SIGCOMM, also available for
+anonymous FTP from cs.columbia.edu:/pub/ji/sigcomm*.ps.Z), I've
+developed what I call the "Virtual Interface" (VIF). To the networking
+code, it looks like an interface. It gets ifattach()ed when you open
+the /dev/vif* device, and then you can ifconfig it as you like. It
+does not have an if_input procedure; it only has an if_output. Packets
+that it receives (from higher-level protocols) which have its
+IP address, it simply loops back (like any well-behaved if driver).
+Packets that it receives that are destined for some other address, it
+encapsulates in an encapsulation protocol I call IPIP (IP-within-IP,
+protocol number IPPROTO_IPIP == 94), and sends it to another machine
+that groks that encapsulation protocol. This feature you won't need,
+but here's how to have multiple IP addresses on a machine with a
+single real interface:
+
+Let's say your primary interface's IP address is 198.3.2.1, and you
+also want it to respond to addresses 198.4.3.2 and 198.5.4.3 (note
+that these are three distinct class C addresses in three distinct
+class C nets). Here are the ifconfigs:
+
+  ifconfig le0 198.3.2.1 up -trailers	# config primary interface
+
+  ifconfig vif0 198.4.3.2 up 		# config first virtual interface
+  route delete net 198.4.3 198.4.3.2	# delete spurious route 
+  route add host 198.4.3.2 198.4.3.2 0	# add route for this i/f
+
+  ifconfig vif1 198.5.4.3 up		# config second virtual interface
+  route delete net 198.5.4 198.5.4.3	# delete spurious route 
+  route add host 198.5.4.3 198.5.4.3 0	# add route for this i/f
+
+The route deletes are needed because the ifconfig creates a default
+route to the interface's network, which can cause problems; all that's
+needed is the (host) route to the interface's address. 
+
+Now, get le0's ethernet address (say, 8:0:20:3:2:1), and add the
+following static ARP entries:
+
+  arp -s 198.4.3.2 8:0:20:3:2:1 pub
+  arp -s 198.5.4.3 8:0:20:3:2:1 pub
+
+This will cause any ARP requests for the VIF addresses to be replied
+with your machine's ethernet address. 
+
+Now, make sure your default route is to your segment's gateway,
+through the real interface. Finally, make sure your routers and/or
+hosts on the same segment as yours know that 198.4.3.2 and 198.5.4.3
+are on that cable. 
+
+Here's what you've accomplished.
+
+ARP requests for any of your host's addresses will be replied to with
+the host's ethernet address (the real one, because that's what it is,
+the virtual ones because of the public static arp entries). Packets
+reaching your host with any of these addresses will be accepted by the
+ip_input routine because they match the address of one of the host's
+interfaces. Packets leaving your host can have any of its addresses
+(real and virtual). 
+
+The code for vif follows. To use it, put the stuff in netinet/if_vif.c
+and netinet/if_vif.h, configure your kernel with the number of
+virtual interfaces you want using a line like:
+
+pseudo-device	vif4		# Virtual IP interface
+
+in your configuration file, and the line
+
+netinet/if_vif.c	optional vif device-driver
+
+in the "files" file. Also, add the appropriate entries in conf.c, so
+that you can access the if_attach() routine when you open the device:
+
+
+-------------------------- conf.c------------------------------------------
+
+add this in the appropriate place in the headers of conf.c:
+
+--------------------
+#include "vif.h"
+#if NVIF > 0
+int     vifopen(), vifclose(), vifread(), vifwrite(), vifselect(), vifioctl();
+#else
+#define vifopen         nodev
+#define vifclose        nodev
+#define vifread         nodev
+#define vifwrite        nodev
+#define vifselect       nodev
+#define vifioctl        nodev
+#endif
+--------------------
+
+then, way down in the definition for cdevsw[]:
+
+--------------------
+	vifopen,	vifclose,	vifread,	vifwrite,	/*14*/
+	vifioctl,	nodev,		nodev,		0,
+	0,	nodev,
+--------------------
+
+Make sure you remember the correct major device number, 14 in this case!
+
+---------------------------------------------------------------------------
+
+Finally, here's the code. It has the tunneling pieces removed (you
+need more code to use that anyway), and it comes from a Mach 2.6
+kernel; it should compile on any Berkeley-derived unix with minor
+changes (most likely only in the includes). 
+
+---------------------netinet/if_vif.h--------------------------------------
+typedef struct 
+{
+	struct ifnet	vif_if;
+	struct ifnet	*vif_sif;	/* slave interface */
+	int		vif_flags;
+} vif_softc_t;
+
+#define	VIFMTU	(1024+512)
+---------------------------------------------------------------------------
+
+and
+
+---------------------netinet/if_vif.c--------------------------------------
+/*
+ * Virtual IP interface module.
+ */
+
+#include "param.h"
+#include "../sys/systm.h"
+#include "../sys/mbuf.h"
+#include "../sys/socket.h"
+#include "../sys/errno.h"
+#include "../sys/ioctl.h"
+
+#include "../net/if.h"
+#include "../net/netisr.h"
+#include "../net/route.h"
+
+#ifdef	INET
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+#include "../netinet/in_var.h"
+#include "../netinet/ip.h"
+#endif
+
+#include "in_pcb.h"
+#include "vif.h"
+
+typedef struct
+{
+        struct ifnet    vif_if;
+        struct ifnet    *vif_sif;       /* slave interface */
+        int             vif_flags;
+} vif_softc_t;
+
+#define VIFMTU  (1024+512)
+
+vif_softc_t vif_softc[NVIF];
+
+int vifs_inited = 0;
+
+
+vifattach()
+{
+	register int i;
+	register struct ifnet *ifp;
+        int	vifoutput(), vififioctl();
+	
+	for (i=0; i<NVIF; i++)
+	{
+		ifp = &vif_softc[i].vif_if;
+		ifp->if_name = "vif";
+		ifp->if_unit = i;
+		ifp->if_mtu = VIFMTU;
+		ifp->if_flags = IFF_LOOPBACK | IFF_NOARP;
+		ifp->if_ioctl = vififioctl;
+		ifp->if_output = vifoutput;
+		if_attach(ifp);
+	}
+}
+
+vifopen(dev, flag)
+int dev, flag;
+{
+	int unit;
+	
+	if (!vifs_inited)
+	{
+		vifattach();
+		vifs_inited = 1;
+		printf("vif initialized\n");
+	}
+	
+	unit = minor(dev);
+	if ((unit < 0) || (unit >= NVIF))
+	{
+		return ENXIO;
+	}
+	
+	return 0;
+}
+
+vifclose(dev, flag)
+int dev, flag;
+{
+	return 0;
+}
+
+vifread()
+{
+	return ENXIO;
+}
+
+vifwrite()
+{
+	return ENXIO;
+}
+
+vifselect()
+{
+	return ENXIO;
+}
+
+vifoutput(ifp, m0, dst)
+	struct ifnet *ifp;
+	register struct mbuf *m0;
+	struct sockaddr *dst;
+{
+	int s;
+	register struct ifqueue *ifq;
+	struct mbuf *m;
+	struct sockaddr_in *din;
+	
+	if (dst->sa_family != AF_INET)
+	{
+		printf("%s%d: can't handle af%d\n", 
+		       ifp->if_name, ifp->if_unit,
+		       dst->sa_family);
+		m_freem(m0);
+		return (EAFNOSUPPORT);
+	}
+
+	din = (struct sockaddr_in *)dst;
+	
+	if (din->sin_addr.s_addr == IA_SIN(ifp->if_addrlist)->sin_addr.s_addr)
+	{
+		/* printf("%s%d: looping\n", ifp->if_name, ifp->if_unit); */
+		
+		/*
+		 * Place interface pointer before the data
+		 * for the receiving protocol.
+		 */
+		if (m0->m_off <= MMAXOFF &&
+		    m0->m_off >= MMINOFF + sizeof(struct ifnet *)) {
+			m0->m_off -= sizeof(struct ifnet *);
+			m0->m_len += sizeof(struct ifnet *);
+		} else {
+			MGET(m, M_DONTWAIT, MT_HEADER);
+			if (m == (struct mbuf *)0)
+			  return (ENOBUFS);
+			m->m_off = MMINOFF;
+			m->m_len = sizeof(struct ifnet *);
+			m->m_next = m0;
+			m0 = m;
+		}
+		*(mtod(m0, struct ifnet **)) = ifp;
+		s = splimp();
+		ifp->if_opackets++;
+		ifq = &ipintrq;
+		if (IF_QFULL(ifq)) {
+			IF_DROP(ifq);
+			m_freem(m0);
+			splx(s);
+			return (ENOBUFS);
+		}
+		IF_ENQUEUE(ifq, m0);
+		schednetisr(NETISR_IP);
+		ifp->if_ipackets++;
+		splx(s);
+		return (0);
+	}
+
+	return EHOSTUNREACH;
+}
+
+/*
+ * Process an ioctl request.
+ */
+/* ARGSUSED */
+vififioctl(ifp, cmd, data)
+	register struct ifnet *ifp;
+	int cmd;
+	caddr_t data;
+{
+	int error = 0;
+
+	switch (cmd) {
+
+	case SIOCSIFADDR:
+		ifp->if_flags |= IFF_UP;
+		/*
+		 * Everything else is done at a higher level.
+		 */
+		break;
+
+	default:
+		error = EINVAL;
+	}
+	return (error);
+}
+
+vifioctl(dev, cmd, arg, mode)
+dev_t dev;
+int cmd;
+caddr_t arg;
+int mode;
+{
+	int unit;
+	
+	unit = minor(dev);
+	if ((unit < 0) || (unit >= NVIF))
+	  return ENXIO;
+	
+	return EINVAL;
+}
+---------------------------------------------------------------------------- 
+
+To use it, compile your kernel, and reboot. Then create the vif
+device:
+
+# mknod /dev/vif c 14 0
+
+(or whatever major number it ended up being), and echo something into
+it:
+
+# echo > /dev/vif
+
+This will cause the device to be opened, which will if_attach the
+interfaces. If you feel like playing with the code, you may want to
+kmem_alloc() the vif_softc structrure at open time, and use the minor
+number of the device to tell it how many interfaces to create. 
+
+Now you can go ahead and ifconfig etc. 
+
+I'll be happy to answer minor questions, and hear about success and
+failure stories, but I cannot help you if you don't already know how
+to hack kernels.
+
+Good luck! 
+
+/ji
+
+In-Real-Life: John "Heldenprogrammer" Ioannidis
+E-Mail-To: ji@cs.columbia.edu
+V-Mail-To: +1 212 854 8120
+P-Mail-To: 450 Computer Science \n Columbia University \n New York, NY 10027
+
+ +

+ +Note: there is also a commercial-product-turned-freeware +called "Col. Patch" which does this as a loadable kernel module +for SunOS 4.1.3_U1. + +

+ + + + diff --git a/APACHE_1_2_X/htdocs/manual/misc/windoz_keepalive.html b/APACHE_1_2_X/htdocs/manual/misc/windoz_keepalive.html new file mode 100644 index 00000000000..d18fa00ab38 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/misc/windoz_keepalive.html @@ -0,0 +1,50 @@ + + + +MS Windows Netscape 3.0b4 KeepAlive problem solved + + + + +

HTTP/1.1 KeepAlive problems with Netscape 3.0

+ +
+Date: Mon, 1 Jul 1996 16:03:06 -0700 (PDT)
+From: Alexei Kosut <akosut@organic.com>
+To: Apache Group
+Subject: Re: keepalive and windoze
+
+Good news and good news (of a sort)..
+
+I was able to snag a Windows 95 machine here at Organic, and tried out
+some things:
+
+1) On Netscape 3.0b4, I was able to reproduce the bug, each and every
+time. It's really simple: go to the Network Setup panel. Set it to
+"Connect Every Time" and only let it have 1 connection at once (this may
+not be neccessary, but it's helpeful). Then load an image that's
+kept-alive. Then wait until the connection times out (this depends on the
+server - 10-30 seconds, except for MIIS, which never times out, near as I
+can tell). Then hit reload. It will hang. (actually, once it crashed).
+
+2) This happens with all forms of server. Apache 1.1, Netscape 2.0,
+Spyglass 1.2, NCSA 1.5 (although, as stated, I couldn't test MIIS).
+
+3) Netscape 3.0b5 does, indeed, *not* have this bug. At least, I couldn't
+get it to perform such. Yipee.
+
+So, we just put up a note on the web page. Make sure we say that all the
+servers have the bug, it's a Windows bug, and Netscape Navigator 3.0b5
+works around it. That way, no one can yell at us. Yes?
+
+-- Alexei Kosut <akosut@organic.com>            The Apache HTTP Server
+   http://www.nueva.pvt.k12.ca.us/~akosut/      http://www.apache.org/
+
+ + diff --git a/APACHE_1_2_X/htdocs/manual/mod/core.html b/APACHE_1_2_X/htdocs/manual/mod/core.html new file mode 100644 index 00000000000..fde6c351a23 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/core.html @@ -0,0 +1,1429 @@ + + + +Apache Core Features + + + + + + +

Apache Core Features

+ +These configuration parameters control the core Apache features, and are +always available. + + + +
+ +

AccessConfig directive

+ +Syntax: AccessConfig filename
+Default: AccessConfig conf/access.conf
+Context: server config, virtual host
+Status: core

+ +The server will read this file for more directives after reading the +ResourceConfig file. Filename is +relative to the ServerRoot. +This feature can be disabled using: +

AccessConfig /dev/null
+Historically, this file only contained +<Directory> sections; in fact it can now +contain any server directive allowed in the server config context. +


+ +

AccessFileName directive

+ +Syntax: AccessFileName filename
+Default: AccessFileName .htaccess
+Context: server config, virtual host
+Status: core

+ +When returning a document to the client the server looks for an +access control file with this name in every directory of the path to +the document, if access control files are enabled for that directory. + +For example: +

AccessFileName .acl
+before returning the document /usr/local/web/index.html, the +server will read /.acl, /usr/.acl, /usr/local/.acl and /usr/local/web/.acl +for directives, unless they have been disabled with +
+<Directory />
+AllowOverride None
+</Directory>


+ +

AddModule directive

+ +Syntax: AddModule module module ...
+Context: server config
+Status: core
+Compatibility: AddModule is only available in Apache 1.2 and later

+ +The server can have modules compiled in which are not actively in use. +This directive can be used to enable the use of those modules. The +server comes with a pre-loaded list of active modules; this list can +be cleared with the ClearModuleList +directive.


+ +

AllowOverride directive

+ +Syntax: AllowOverride override override ...
+Default: AllowOverride All
+Context: directory
+Status: core

+ +When the server finds an .htaccess file (as specified by +AccessFileName) it needs to know which +directives declared in that file can override earlier access information.

+ +Override can be set to None, in which case the server +will not read the file, All in which case the server will +allow all the directives, or one or more of the following: +

+
AuthConfig +
+ +Allow use of the authorization directives +(AuthDBMGroupFile, +AuthDBMUserFile, +AuthGroupFile, +AuthName, AuthType, +AuthUserFile, +require, etc.). +
FileInfo +
+ +Allow use of the directives controlling document types +(AddEncoding, +AddLanguage, +AddType, +DefaultType, +ErrorDocument, +LanguagePriority, etc.). +
Indexes +
+ +Allow use of the directives controlling directory indexing +(AddDescription, +AddIcon, +AddIconByEncoding, +AddIconByType, +DefaultIcon, +DirectoryIndex, +FancyIndexing, +HeaderName, +IndexIgnore, +IndexOptions, +ReadmeName, etc.). +
Limit +
+ +Allow use of the directives controlling host access (allow, deny and order). +
Options +
+ +Allow use of the directives controlling specific directory features +(Options and +XBitHack). +


+ +

AuthName directive

+ +Syntax: AuthName auth-domain
+Context: directory, .htaccess
+Override: AuthConfig
+Status: core

+ +This directive sets the name of the authorization realm for a directory. +This realm is given to the client so that the user knows which username and +password to send. +It must be accompanied by AuthType and +require directives, and directives such as +AuthUserFile and +AuthGroupFile to work.


+ +

AuthType directive

+ +Syntax: AuthType type
+Context: directory, .htaccess
+Override: AuthConfig
+Status: core

+ +This directive selects the type of user authentication for a directory. +Only Basic is currently implemented. + +It must be accompanied by AuthName and +require directives, and directives such as +AuthUserFile and +AuthGroupFile to work.


+ +

BindAddress directive

+ +Syntax: BindAddress saddr
+Default: BindAddress *
+Context: server config
+Status: core

+ +A Unix® http server can either listen for connections to every +IP address of the server machine, or just one IP address of the server +machine. Saddr can be + +

+
  • * +
  • An IP address +
  • A fully-qualified Internet domain name +
  • +If the value is *, then the server will listen for connections on +every IP address, otherwise it will only listen on the IP address +specified.

    + +This option can be used as an alternative method for supporting +virtual hosts instead of using +<VirtualHost> sections. + +

    See Also: +DNS Issues
    +See Also: +Setting which addresses and ports Apache uses

    + +
    + +

    ClearModuleList directive

    + +Syntax: ClearModuleList
    +Context: server config
    +Status: core
    +Compatibility: ClearModuleList is only available in Apache 1.2 and later

    + +The server comes with a built-in list of active modules. This +directive clears the list. It is assumed that the list will then be +re-populated using the AddModule directive.


    + +

    DefaultType directive

    + +Syntax: DefaultType mime-type
    +Default: DefaultType text/html
    +Context: server config, virtual host, directory, .htaccess
    +Override: FileInfo
    +Status: core

    + +There will be times when the server is asked to provide a document +whose type cannot be determined by its MIME types mappings.

    + +The server must inform the client of the content-type of the document, so in +the event of an unknown type it uses the DefaultType. For +example: +

    DefaultType image/gif
    +would be appropriate for a directory which contained many gif images +with filenames missing the .gif extension.


    + +

    <Directory> directive

    + +Syntax: <Directory directory> ... </Directory>
    +Context: server config, virtual host
    +Status: Core.

    + +<Directory> and </Directory> are used to enclose a group of +directives which will apply only to the named directory and sub-directories +of that directory. Any directive which is allowed in a directory +context may be used. Directory is either the full path to a directory, +or a wild-card string. In a wild-card string, `?' matches any single character, +and `*' matches any sequences of characters. Example: +

    +   <Directory /usr/local/httpd/htdocs>
    +   Options Indexes FollowSymLinks
    +   </Directory>
    +
    + +

    Apache 1.2 and above: +Extended regular expressions can also be used, with the addition of the +~ character. For example:

    + +
    +   <Directory ~ "^/www/.*/[0-9]{3}">
    +
    + +would match directories in /www/ that consisted of three numbers.

    + +

    If multiple directory sections match the directory (or its parents) containing +a document, then the directives are applied in the order of shortest match +first, interspersed with the directives from the +.htaccess files. For example, with +

    +<Directory />
    +AllowOverride None
    +</Directory>

    +<Directory /home/*>
    +AllowOverride FileInfo
    +</Directory>
    +for access to the document /home/web/dir/doc.html the +steps are: + +
  • Apply directive AllowOverride None (disabling +.htaccess files). +
  • Apply directive AllowOverride FileInfo (for directory +/home/web). +
  • Apply any FileInfo directives in /home/web/.htaccess +
  • + +

    + +Note that the default Apache access for <Directory /> is +Allow from All. This means that Apache will serve any file +mapped from an URL. It is recommended that you change this with a block +such as + +

    + <Directory />
    +     Order Deny,Allow
    +     Deny from All
    + </Directory>
    +
    +

    + +and then override this for directories you want accessible. +See the +Security Tips +page for more details. + +

    + +The directory sections typically occur in the access.conf file, but they +may appear in any configuration file. <Directory> directives cannot +nest, and cannot appear in a <Limit> section. +


    + +

    DocumentRoot directive

    + +Syntax: DocumentRoot directory-filename
    +Default: DocumentRoot +/usr/local/etc/httpd/htdocs
    +Context: server config, virtual host
    +Status: core

    + +This directive sets the directory from which httpd will serve files. +Unless matched by a directive like Alias, the server appends the path +from the requested URL to the document root to make the path to the +document. Example: +

    DocumentRoot /usr/web
    +then an access to http://www.my.host.com/index.html refers +to /usr/web/index.html. + +

    There appears to be a bug in mod_dir which causes problems when the +DocumentRoot has a trailing slash (i.e. "DocumentRoot /usr/web/") so +please avoid that. + +


    + +

    ErrorDocument directive

    + +Syntax: ErrorDocument error-code document
    +Context server config, virtual host, directory, .htaccess
    +Status: core
    +Override: FileInfo
    +Compatibility: The directory and .htaccess contexts +are only available in Apache 1.1 and later.

    + +In the event of a problem or error, Apache can be configured to do +one of four things, + +

      +
    1. output a simple hardcoded error message +
    2. output a customized message +
    3. redirect to a local URL to handle the problem/error +
    4. redirect to an external URL to handle the problem/error +
    + +

    The first option is the default, while options 2-4 are configured +using the ErrorDocument directive, which is followed by +the HTTP response code and a message or URL. + +

    Messages in this context begin with a single quote +("), which does not form part of the message itself. +Apache will sometimes offer additional information regarding the +problem/error. + +

    URLs can begin with a slash (/) for local URLs, or be a full +URL which the client can resolve. Examples: +

    +ErrorDocument 500 http://foo.example.com/cgi-bin/tester
    +ErrorDocument 404 /cgi-bin/bad_urls.pl
    +ErrorDocument 401 /subscription_info.html
    +ErrorDocument 403 "Sorry can't allow you access today +
    + +

    Note that when you specify an ErrorDocument that +points to a remote URL (ie. anything with a method such as "http" in +front of it) Apache will send a redirect to the client to tell it +where to find the document, even if the document ends up being +on the same server.. This has several implications, the +most important being that if you use an "ErrorDocument 401" +directive then it must refer to a local document. This results +from the nature of the HTTP basic authentication scheme. + +

    See Also: documentation of customizable +responses.


    + +

    ErrorLog directive

    + +Syntax: ErrorLog filename
    +Default: ErrorLog logs/error_log
    +Context: server config, virtual host
    +Status: core

    + +The error log directive sets the name of the file to which the server will log +any errors it encounters. If the filename does not begin with a slash (/) +then it is assumed to be relative to the ServerRoot. +Example: +

    ErrorLog /dev/null
    +This effectively turns off error logging.

    + +SECURITY: See the security tips +document for details on why your security could be compromised if +the directory where logfiles are stored is writable by anyone other +than the user that starts the server. + +


    + +

    <Files>

    +Syntax: <Files filename> +... </Files>
    +Context: server config, virtual host, htaccess
    +Status: core
    +Compatibility: only available in Apache +1.2 and above.

    + +

    The <Files> directive provides for access control by +filename. It is comparable to the <Directory> directive and +<Location> directives. It +should be matched with a </Files> directive. Directives that +apply to the filename given should be listed +within. <Files> sections are processed in the +order they appear in the configuration file, after the +<Directory> sections and .htaccess files are +read, but before <Location> sections.

    + +

    The filename argument should include a filename, or a +wild-card string, where `?' matches any single character, and `*' matches any +sequences of characters. Extended regular expressions can also be used, with the addition of +the ~ character. For example:

    + +
    +   <Files ~ "\.(gif|jpe?g|png)$">
    +
    + +would match most common Internet graphics formats. + +

    Note that unlike <Directory> and <Location> sections, +<Files> sections can be used inside .htaccess +files. This allows users to control access to their own files, at a +file-by-file level. When used in an .htaccess file, if the +filename does not begin with a / character, +the directory being applied will be prefixed automatically. + +


    + +

    Group directive

    + +Syntax: Group unix-group
    +Default: Group #-1
    +Context: server config, virtual host
    +Status: core

    + +The Group directive sets the group under which the server will answer requests. +In order to use this directive, the stand-alone server must be run initially +as root. Unix-group is one of: +

    +
    A group name +
    Refers to the given group by name. +
    # followed by a group number. +
    Refers to a group by its number. +
    + +It is recommended that you set up a new group specifically for running the +server. Some admins use user nobody, but this is not always +possible or desirable.

    + +Note: if you start the server as a non-root user, it will fail to change +to the specified group, and will instead continue to run as the group of the +original user.

    + +Special note: Use of this directive in <VirtualHost> requires a +properly configured suEXEC wrapper. +When used inside a <VirtualHost> in this manner, only the group +that CGIs are run as is affected. Non-CGI requests are still processed +as the group specified in the main Group directive.

    + +SECURITY: See User for a discussion of the security +considerations.


    + +

    HostNameLookups directive

    + +Syntax: HostNameLookups boolean
    +Default: HostNameLookups on
    +Context: server config, virtual host
    +Status: core

    + +This directive enables DNS lookups so that host names can be logged. +Having this directive set on also enables the use of names +in <Limit> blocks for access control.

    + +Heavily loaded sites should set this directive off, since DNS +lookups can take considerable amounts of time. The utility logresolve, +provided in the /support directory, can be used to look up host names +from logged IP addresses offline.


    + +

    IdentityCheck directive

    + +Syntax: IdentityCheck boolean
    +Default: IdentityCheck off
    +Context: server config, virtual host
    +Status: core

    + +This directive enables RFC1413-compliant logging of the remote user name +for each connection, where the client machine runs identd or something similar. +This information is logged in the access log. Boolean is either +on or off.

    + +The information should not be trusted in any way except for rudimentary usage +tracking.

    + +Note that this can cause serious latency problems accessing your server +since every request requires one of these lookups to be performed. When +firewalls are involved each lookup might possibly fail and add 30 seconds +of latency to each hit. So in general this is not very useful on public +servers accessible from the Internet. +


    + +

    <IfModule>

    +Syntax: <IfModule [!]module-name> ... +</IfModule>
    +Default: None
    +Context: all
    +Status: Core +Compatibility: ScriptLog is only available in 1.2 and +later.

    + +

    + +The <IfModule test>...</IfModule> +section is used to mark directives that are conditional. The +directives within an IfModule section are only +processed if the test is true. If test +is false, everything between the start and end markers +is ignored.

    + +The test in the <IfModule> section directive +can be one of two forms: + +

      +
    • module name +
    • !module name +
    + +

    In the former case, the directives between the start and end markers +are only processed if the module named module name is compiled +in to Apache. The second format reverses the test, and only processes +the directives if module name is not compiled in. + +

    The module name argument is a module name as given as the file +name of the module, at the time it was compiled. For example, +mod_rewrite.c. + +

    <IfModule> sections are nest-able, which can be used to implement +simple multiple-module tests. + +


    + +

    KeepAlive

    +Syntax: (Apache 1.1) KeepAlive max-requests
    +Default: (Apache 1.1) KeepAlive 5
    +Syntax: (Apache 1.2) KeepAlive on/off
    +Default: (Apache 1.2) KeepAlive On
    +Context: server config
    +Status: Core
    +Compatibility: KeepAlive is only available in Apache +1.1 and later.

    + +This directive enables +Keep-Alive +support. + +

    Apache 1.1: Set max-requests +to the maximum number of requests you want Apache to entertain per +request. A limit is imposed to prevent a client from hogging your +server resources. Set this to 0 to disable support. + +

    Apache 1.2 and later: Set to "On" to enable +persistent connections, "Off" to disable. See also the MaxKeepAliveRequests directive.

    + +

    KeepAliveTimeout

    +Syntax: KeepAliveTimeout seconds
    +Default: KeepAliveTimeout 15
    +Context: server config
    +Status: Core
    +Compatibility: KeepAliveTimeout is only available in Apache +1.1 and later.

    + +The number of seconds Apache will wait for a subsequent request before +closing the connection. Once a request has been received, the timeout +value specified by the Timeout directive +applies. +


    + +

    Listen

    +Syntax: +Listen [IP address:]port number
    +Context: server config
    +Status: core
    +Compatibility: Listen is only available in Apache +1.1 and later.

    + +

    The Listen directive instructs Apache to listen to more than one IP +address or port; by default it responds to requests on all IP +interfaces, but only on the port given by the Port +directive.

    + +

    See Also: +DNS Issues
    +See Also: +Setting which addresses and ports Apache uses
    +See Also: +Known Bugs

    +
    + +

    <Limit> directive

    + +Syntax: + <Limit method method ... > ... </Limit>
    +Context: any
    +Status: core

    + +<Limit> and </Limit> are used to enclose a group of +access control directives which will then apply only to the specified +access methods, where method is any valid HTTP method. +Any directive except another <Limit> or +<Directory> may be used; the majority will be +unaffected by the <Limit>. Example: +

    +<Limit GET POST>
    +require valid-user
    +</Limit>
    +If an access control directive appears outside a <Limit> directive, +then it applies to all access methods.


    + +

    <Location>

    + +Syntax: <Location URL> +... </Location>
    +Context: server config, virtual host
    +Status: core
    +Compatibility: Location is only available in Apache +1.1 and later.

    + +

    The <Location> directive provides for access control by +URL. It is comparable to the <Directory> directive, and +should be matched with a </Location> directive. Directives that +apply to the URL given should be listed +within. <Location> sections are processed in the +order they appear in the configuration file, after the +<Directory> sections and .htaccess files are +read.

    + +

    Note that, due to the way HTTP functions, URL prefix +should, save for proxy requests, be of the form /path/, +and should not include the http://servername. It doesn't +necessarily have to protect a directory (it can be an individual +file, or a number of files), and can include wild-cards. In a wild-card +string, `?' matches any single character, and `*' matches any +sequences of characters. + +

    Apache 1.2 and above: +Extended regular expressions can also be used, with the addition of +the +~ character. For example:

    + +
    +   <Location ~ "/(extra|special)/data">
    +
    + +would match URLs that contained the substring "/extra/data" or +"/special/data".

    + +

    The Location functionality is especially useful when +combined with the SetHandler directive. For example, to enable status requests, but allow them only +from browsers at foo.com, you might use: + +

    +    <Location /status>
    +    SetHandler server-status
    +    order deny,allow
    +    deny from all
    +    allow from .foo.com
    +    </Location>
    +
    +
    + +

    MaxClients directive

    + +Syntax: MaxClients number
    +Default: MaxClients 256
    +Context: server config
    +Status: core

    + +The MaxClients directive sets the limit on the number of simultaneous +requests that can be supported; not more than this number of child server +processes will be created.


    + +

    MaxKeepAliveRequests

    +Syntax: MaxKeepAliveRequests number
    +Default: MaxKeepAliveRequests 100
    +Context: server config
    +Status: core
    +Compatibility: Only available in Apache +1.2 and later. + +

    The MaxKeepAliveRequests directive limits the number of requests +allowed per connection when KeepAlive is +on. If it is set to "0", unlimited requests will be +allowed. We recommend that this setting be kept to a high value for +maximum server performance. + +

    MaxRequestsPerChild directive

    + +Syntax: MaxRequestsPerChild number
    +Default: MaxRequestsPerChild 0
    +Context: server config
    +Status: core

    + +The MaxRequestsPerChild directive sets the limit on the number of requests +that an individual child server process will handle. After MaxRequestsPerChild +requests, the child process will die. If MaxRequestsPerChild is 0, then +the process will never expire.

    + +Setting MaxRequestsPerChild to a non-zero limit has two beneficial effects: +

      +
    • it limits the amount of memory that process can consume by (accidental) +memory leakage; +
    • by giving processes a finite lifetime, it helps reduce the +number of processes when the server load reduces. +


    + +

    MaxSpareServers directive

    + +Syntax: MaxSpareServers number
    +Default: MaxSpareServers 10
    +Context: server config
    +Status: core

    + +The MaxSpareServers directive sets the desired maximum number of idle +child server processes. An idle process is one which is not handling +a request. If there are more than MaxSpareServers idle, then the parent +process will kill off the excess processes.

    + +Tuning of this parameter should only be necessary on very busy sites. +Setting this parameter to a large number is almost always a bad idea.

    + +See also MinSpareServers and +StartServers.


    + +

    MinSpareServers directive

    + +Syntax: MinSpareServers number
    +Default: MinSpareServers 5
    +Context: server config
    +Status: core

    + +The MinSpareServers directive sets the desired minimum number of idle +child server processes. An idle process is one which is not handling +a request. If there are fewer than MinSpareServers idle, then the parent +process creates new children at a maximum rate of 1 per second.

    + +Tuning of this parameter should only be necessary on very busy sites. +Setting this parameter to a large number is almost always a bad idea.

    + +See also MaxSpareServers and +StartServers.


    + +

    Options directive

    + +Syntax: Options [+|-]option [+|-]option ...
    +Context: server config, virtual host, directory, .htaccess
    +Override: Options
    +Status: core

    + +The Options directive controls which server features are available in +a particular directory. +

    +option can be set to None, in which case none of +the extra features are enabled, or one or more of the following: +

    +
    All +
    All options except for MultiViews. +
    ExecCGI +
    + +Execution of CGI scripts is permitted. +
    FollowSymLinks +
    + +The server will follow symbolic links in this directory. +
    Includes +
    + +Server-side includes are permitted. +
    IncludesNOEXEC +
    + +Server-side includes are permitted, but the #exec command and +#include of CGI scripts are disabled. +
    Indexes +
    + +If a URL which maps to a directory is requested, and the there is no +DirectoryIndex (e.g. index.html) in that directory, then the server will +return a formatted listing of the directory. +
    MultiViews +
    + +Content negotiated MultiViews are +allowed. +
    SymLinksIfOwnerMatch +
    + +The server will only follow symbolic links for which the target +file or directory is owned by the same user id as the link. +
    + +Normally, if multiple Options could apply to a directory, +then the most specific one is taken complete; the options are not +merged. However if all the options on the Options +directive are preceded by a + or - symbol, the options are +merged. Any options preceded by a + are added to the options +currently in force, and any options preceded by a - are removed from +the options currently in force.

    + +For example, without any + and - symbols: + +

    +<Directory /web/docs>
    +Options Indexes FollowSymLinks
    +</Directory>
    +<Directory /web/docs/spec>
    +Options Includes
    +</Directory> +
    +then only Includes will be set for the /web/docs/spec +directory. However if the second Options directive uses the + +and - symbols:

    + +

    +<Directory /web/docs>
    +Options Indexes FollowSymLinks
    +</Directory>
    +<Directory /web/docs/spec>
    +Options +Includes -Indexes
    +</Directory> +
    +then the options FollowSymLinks and Includes +are set for the /web/docs/spec directory. +
    + +

    PidFile directive

    + +Syntax: PidFile filename
    +Default: PidFile logs/httpd.pid
    +Context: server config
    +Status: core

    + +The PidFile directive sets the file to which the server records the +process id of the daemon. If the filename does not begin with a slash (/) +then it is assumed to be relative to the ServerRoot. +The PidFile is only used in standalone mode.

    + +It is often useful to be able to send the server a signal, so that it closes +and then reopens its ErrorLog and TransferLog, and +re-reads its configuration files. This is done by sending a SIGHUP (kill -1) +signal to the process id listed in the PidFile.

    + +The PidFile is subject to the same warnings about log file placement and +security. + +


    + +

    Port directive

    + +Syntax: Port number
    +Default: Port 80
    +Context: server config
    +Status: core

    + +Number is a number from 0 to 65535; some port numbers (especially below +1024) are reserved for particular protocols. See /etc/services +for a list of some defined ports; the standard port for the http protocol +is 80.

    + +The Port directive has two behaviors, the first of which is necessary for +NCSA backwards compatibility (and which is confusing in the context of +Apache).

    + +

      +
    • +In the absence of any Listen or +BindAddress directives specifying a port number, +the Port directive sets the network port on which the server listens. +If there are any Listen or BindAddress directives specifying +:number then Port has no effect on what address the server +listens at. + +
    • The Port directive +sets the SERVER_PORT environment variable (for +CGI and SSI), +and is used when the server must generate a URL that refers to itself +(for example when creating an external redirect to itself). +
    + +In no event does a Port setting affect +what ports a VirtualHost responds on, the +VirtualHost directive itself is used for that.

    + +The primary behaviour of Port should be considered to be similar to that of +the ServerName directive. The ServerName +and Port together specify what you consider to be the canonical +address of the server.

    + +Port 80 is one of Unix's special ports. All ports numbered +below 1024 are reserved for system use, i.e. regular (non-root) users cannot +make use of them; instead they can only use higher port numbers. +To use port 80, you must start the server from the root account. +After binding to the port and before accepting requests, Apache will change +to a low privileged user as set by the User directive.

    + +If you cannot use port 80, choose any other unused port. Non-root users +will have to choose a port number higher than 1023, such as 8000.

    + +SECURITY: if you do start the server as root, be sure +not to set User to root. If you run the server as +root whilst handling connections, your site may be open to a major security +attack.


    + +

    require directive

    + +Syntax: require entity-name entity entity...
    +Context: directory, .htaccess
    +Override: AuthConfig
    +Status: core

    + +This directive selects which authenticated users can access a directory. +The allowed syntaxes are: +

      +
    • require user userid userid ...

      +Only the named users can access the directory.

      +

    • require group group-name group-name ...

      +Only users in the named groups can access the directory.

      +

    • require valid-user

      +All valid users can access the directory. +

    +

    +If require appears in a <Limit> +section, then it restricts access to the named methods, otherwise +it restricts access for all methods. Example: +

    +AuthType Basic
    +AuthName somedomain
    +AuthUserFile /web/users
    +AuthGroupFile /web/groups
    +<Limit GET POST>
    +require group admin
    +</Limit> +
    + +Require must be accompanied by AuthName and +AuthType directives, and directives such as +AuthUserFile and +AuthGroupFile (to define users and +groups) in order to work correctly.


    + +

    ResourceConfig directive

    + +Syntax: ResourceConfig filename
    +Default: ResourceConfig conf/srm.conf
    +Context: server config, virtual host
    +Status: core

    + +The server will read this file for more directives after reading the +httpd.conf file. Filename is relative to the +ServerRoot. +This feature can be disabled using: +

    ResourceConfig /dev/null
    +Historically, this file contained most directives except for server +configuration directives and <Directory> +sections; in fact it can now contain any server directive allowed in the +server config context.

    + +See also AccessConfig.


    + + +

    RLimitCPU directive

    + +Syntax: RLimitCPU # or 'max' [# or 'max']
    +Default: Unset uses operating system defaults
    +Context: server config, virtual host
    +Status: core
    +Compatibility: RLimitCPU is only available in Apache 1.2 and later

    + +Takes 1 or 2 parameters. The first parameter sets the soft resource limit for all +processes and the second parameter sets the maximum resource limit. Either parameter +can be a number, or max to indicate to the server that the limit should +be set to the maximum allowed by the operating system configuration. Raising the +maximum resource limit requires that the server is running as root, or in the initial +startup phase.

    + +CPU resource limits are expressed in seconds per process.

    + +See also RLimitMEM or RLimitNPROC.


    + +

    RLimitMEM directive

    + +Syntax: RLimitMEM # or 'max' [# or 'max']
    +Default: Unset uses operating system defaults
    +Context: server config, virtual host
    +Status: core
    +Compatibility: RLimitMEM is only available in Apache 1.2 and later

    + +Takes 1 or 2 parameters. The first parameter sets the soft resource limit for all +processes and the second parameter sets the maximum resource limit. Either parameter +can be a number, or max to indicate to the server that the limit should +be set to the maximum allowed by the operating system configuration. Raising the +maximum resource limit requires that the server is running as root, or in the initial +startup phase.

    + +Memory resource limits are expressed in bytes per process.

    + +See also RLimitCPU or RLimitNPROC.


    + +

    RLimitNPROC directive

    + +Syntax: RLimitNPROC # or 'max' [# or 'max']
    +Default: Unset uses operating system defaults
    +Context: server config, virtual host
    +Status: core
    +Compatibility: RLimitNPROC is only available in Apache 1.2 and later

    + +Takes 1 or 2 parameters. The first parameter sets the soft resource limit for all +processes and the second parameter sets the maximum resource limit. Either parameter +can be a number, or max to indicate to the server that the limit should +be set to the maximum allowed by the operating system configuration. Raising the +maximum resource limit requires that the server is running as root, or in the initial +startup phase.

    + +Process limits control the number of processes per user.

    + +Note: If CGI processes are not running under userids other than the +web server userid, this directive will limit the number of processes that the +server itself can create. Evidence of this situation will be indicated by +cannot fork messages in the error_log.

    + +See also RLimitMEM or RLimitCPU. + +


    + +

    Satisfy

    + +Syntax: Satisfy 'any' or 'all'
    +Default: Satisfy all
    +Context: directory, .htaccess
    +Status: core
    +Compatibility: Satisfy is only available in Apache 1.2 and later

    + +Access policy if both allow and require used. The parameter can be +either 'all' or 'any'. This directive is only useful +if access to a particular area is being restricted by both +username/password and client host address. In this case the +default behavior ("all") is to require that the client passes the +address access restriction and enters a valid username and +password. With the "any" option the client will be granted access if +they either pass the host restriction or enter a valid username and +password. This can be used to password restrict an area, but to let +clients from particular addresses in without prompting for a password. + + +


    + +

    ScoreBoardFile directive

    + +Syntax: ScoreBoardFile filename
    +Default: ScoreBoardFile logs/apache_status
    +Context: server config
    +Status: core

    + +The ScoreBoardFile directive is required on some architectures to place +a file that the server will use to communicate between its children and +the parent. The easiest way to find out if your architecture requires +a scoreboard file is to run Apache and see if it creates the file named +by the directive. If your architecture requires it then you must ensure +that this file is not used at the same time by more than one invocation +of Apache.

    + +If you have to use a ScoreBoardFile then you may see improved speed by +placing it on a RAM disk. But be careful that you heed the same warnings +about log file placement and +security.

    + +Apache 1.2 and above:

    + +Linux 1.x users might be able to add -DHAVE_SHMGET to +the EXTRA_CFLAGS in your Configuration. This +might work with some 1.x installations, but won't work with all of +them.

    + +SVR4 users should consider adding -DHAVE_SHMGET to the +EXTRA_CFLAGS in your Configuration. This +is believed to work, but we were unable to test it in time for 1.2 +release.

    + +See Also: +Stopping and Restarting Apache

    + +


    + +

    SendBufferSize directive

    + +Syntax: SendBufferSize bytes
    +Context: server config, virtual host
    +Status: core

    + +The server will set the TCP buffer size to the number of bytes +specified. Very useful to increase past standard OS defaults on high +speed high latency (i.e. 100ms or so, such as transcontinental +fast pipes) +


    + +

    ServerAdmin directive

    + +Syntax: ServerAdmin email-address
    +Context: server config, virtual host
    +Status: core

    + +The ServerAdmin sets the e-mail address that the server includes in any +error messages it returns to the client.

    + +It may be worth setting up a dedicated address for this, e.g. +

    ServerAdmin www-admin@foo.bar.com
    +as users do not always mention that they are talking about the server!


    + +

    ServerAlias directive

    + +Syntax: ServerAlias host1 host2 ...
    +Context: virtual host
    +Status: core
    +Compatibility: ServerAlias is only available in Apache +1.1 and later.

    + +The ServerAlias directive sets the alternate names for a host, for use +with +Host-header based virtual hosts. +

    See Also: +In-depth description of Virtual Host matching

    + +
    + +

    ServerName directive

    + +Syntax: ServerName fully-qualified domain name
    +Context: server config, virtual host
    +Status: core

    + +The ServerName directive sets the hostname of the server; this is only +used when creating redirection URLs. If it is not specified, then the +server attempts to deduce it from its own IP address; however this may +not work reliably, or may not return the preferred hostname. For example: +

    ServerName www.wibble.com
    +would be used if the canonical (main) name of the actual machine +were monster.wibble.com.

    +

    See Also: +DNS Issues

    +
    + +

    ServerPath directive

    + +Syntax: ServerPath pathname
    +Context: virtual host
    +Status: core
    +Compatibility: ServerPath is only available in Apache +1.1 and later.

    + +The ServerPath directive sets the legacy URL pathname for a host, for +use with Host-header based virtual hosts. +

    See Also: +In-depth description of Virtual Host matching

    +
    + +

    ServerRoot directive

    + +Syntax: ServerRoot directory-filename
    +Default: ServerRoot /usr/local/etc/httpd
    +Context: server config
    +Status: core

    + +The ServerRoot directive sets the directory in which the server lives. +Typically it will contain the subdirectories conf/ and +logs/. Relative paths for other configuration files are taken +as relative to this directory.
    +See also the -d option to httpd.


    + +

    ServerType directive

    + +Syntax: ServerType type
    +Default: ServerType standalone
    +Context: server config
    +Status: core

    + +The ServerType directive sets how the server is executed by the system. +Type is one of +

    +
    inetd +
    The server will be run from the system process inetd; the command to start +the server is added to /etc/inetd.conf +
    standalone +
    The server will run as a daemon process; the command to start the server +is added to the system startup scripts. (/etc/rc.local or +/etc/rc3.d/....) +
    + +Inetd is the lesser used of the two options. For each http +connection received, a new copy of the server is started from scratch; +after the connection is complete, this program exits. There is a high price to +pay per connection, but for security reasons, some admins prefer this option. +

    + +Standalone is the most common setting for ServerType since +it is far more efficient. The server is started once, and services all +subsequent connections. If you intend running Apache to serve a busy site, +standalone will probably be your only option.

    + +SECURITY: if you are paranoid about security, run in inetd mode. Security +cannot be guaranteed in either, but whilst most people are happy to use +standalone, inetd is probably least prone to attack.


    + +

    StartServers directive

    + +Syntax: StartServers number
    +Default: StartServers 5
    +Context: server config
    +Status: core

    + +The StartServers directive sets the number of child server processes created +on startup. As the number of processes is dynamically controlled depending +on the load, there is usually little reason to adjust this parameter.

    + +See also MinSpareServers and +MaxSpareServers.


    + +

    TimeOut directive

    + +Syntax: TimeOut number
    +Default: TimeOut 300
    +Context: server config
    +Status: core

    + +The TimeOut directive currently defines the amount of time Apache will +wait for three things: + +

      +
    1. The total amount of time it takes to receive a GET request. +
    2. The amount of time between receipt of TCP packets on a POST or + PUT request. +
    3. The amount of time between ACKs on transmissions of TCP packets + in responses. +
    + +We plan on making these separately configurable at some point down the +road. The timer used to default to 1200 before 1.2, but has been +lowered to 300 which is still far more than necessary in most +situations. It is not set any lower by default because there may +still be odd places in the code where the timer is not reset when +a packet is sent. + +


    + +

    User directive

    + +Syntax: User unix-userid
    +Default: User #-1
    +Context: server config, virtual host
    +Status: core

    + +The User directive sets the userid as which the server will answer requests. +In order to use this directive, the standalone server must be run initially +as root. Unix-userid is one of: +

    +
    A username +
    Refers to the given user by name. +
    # followed by a user number. +
    Refers to a user by their number. +
    + +The user should have no privileges which result in it being able to access +files which are not intended to be visible to the outside world, and +similarly, the user should not be able to execute code which is not +meant for httpd requests. It is recommended that you set up a new user and +group specifically for running the server. Some admins use user +nobody, but this is not always possible or desirable.

    + +Notes: If you start the server as a non-root user, it will fail to change +to the lesser privileged user, and will instead continue to run as +that original user. If you do start the server as root, then it is normal +for the parent process to remain running as root.

    + +Special note: Use of this directive in <VirtualHost> requires a +properly configured suEXEC wrapper. +When used inside a <VirtualHost> in this manner, only the user +that CGIs are run as is affected. Non-CGI requests are still processed +with the user specified in the main User directive.

    + +SECURITY: Don't set User (or Group) to +root unless you know exactly what you are doing, and what the +dangers are.


    + +

    <VirtualHost> directive

    + +Syntax: <VirtualHost addr[:port] ...> ... +</VirtualHost>
    +Context: server config
    +Status: Core.
    +Compatibility: Non-IP address-based Virtual Hosting only +available in Apache 1.1 and later.
    +Compatibility: Multiple address support only available in +Apache 1.2 and later.

    + +<VirtualHost> and </VirtualHost> are used to enclose a group of +directives which will apply only to a particular virtual host. +Any directive which is allowed in a virtual host context may be used. +When the server receives a request for a document on a particular virtual +host, it uses the configuration directives enclosed in the <VirtualHost> +section. Addr can be +

    +
  • The IP address of the virtual host +
  • A fully qualified domain name for the IP address of the virtual host. +
  • Example: +
    + +<VirtualHost 10.1.2.3>
    +ServerAdmin webmaster@host.foo.com
    +DocumentRoot /www/docs/host.foo.com
    +ServerName host.foo.com
    +ErrorLog logs/host.foo.com-error_log
    +TransferLog logs/host.foo.com-access_log
    +</VirtualHost> +
    + +Each VirtualHost must correspond to a different IP address or a +different host name for the server, in the latter case the server +machine must be configured to accept IP packets for multiple +addresses. (If the machine does not have multiple network interfaces, +then this can be accomplished with the ifconfig alias +command (if your OS supports it), or with kernel patches like VIF (for SunOS(TM) 4.1.x)).

    + +The special name _default_ can be specified in which case +this virtual host will match any IP address that is not explicitly listed +in another virtual host. In the absence of any _default_ virtual host +the "main" server config, consisting of all those definitions outside +any VirtualHost section, is used when no match occurs.

    + +You can specify a :port to change the port that is matched. +If unspecified then it defaults to the same port as the most recent +Port statement of the main server. You +may also specify :* to match all ports on that address. +(This is recommended when used with _default_.)

    + +SECURITY: See the +security tips +document for details on why your security could be compromised if +the directory where logfiles are stored is writable by anyone other +than the user that starts the server. + +

    See also: +Warnings about DNS and Apache
    +See also: +Information on Virtual Hosts. +(multihome)
    +See also: +Non-IP address-based Virtual Hosts
    +See also: +In-depth description of Virtual Host matching +

    + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/directives.html b/APACHE_1_2_X/htdocs/manual/mod/directives.html new file mode 100644 index 00000000000..23599099c2b --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/directives.html @@ -0,0 +1,176 @@ + + + +Apache directives + + + + + +

    Apache directives

    + + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/footer.html b/APACHE_1_2_X/htdocs/manual/mod/footer.html new file mode 100644 index 00000000000..2c2b4103785 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/footer.html @@ -0,0 +1,4 @@ +
    + +Index +Home diff --git a/APACHE_1_2_X/htdocs/manual/mod/header.html b/APACHE_1_2_X/htdocs/manual/mod/header.html new file mode 100644 index 00000000000..8b23a1ccba0 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/header.html @@ -0,0 +1,3 @@ +
    + [APACHE DOCUMENTATION] +
    diff --git a/APACHE_1_2_X/htdocs/manual/mod/index.html b/APACHE_1_2_X/htdocs/manual/mod/index.html new file mode 100644 index 00000000000..347393f4744 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/index.html @@ -0,0 +1,103 @@ + + + +Apache modules + + + + + +

    Apache modules

    + +

    +Below is a list of all of the modules that come as part of the +Apache distribution. See also the complete alphabetical list of +all Apache directives. +

    + +
    +
    Core +
    Core Apache features. +
    mod_access +
    Host based access control. +
    mod_actions Apache 1.1 and later. +
    Filetype/method-based script execution +
    mod_alias +
    Aliases and redirects. +
    mod_asis +
    The .asis file handler. +
    mod_auth +
    User authentication using text files. +
    mod_auth_anon +
    Anonymous user authentication, FTP-style. +
    mod_auth_db +
    User authentication using Berkeley DB files. +
    mod_auth_dbm +
    User authentication using DBM files. +
    mod_auth_msql +
    User authentication using mSQL files. +
    mod_browser Apache 1.2 and up +
    Set environment variables based on User-Agent strings +
    mod_cern_meta +
    Support for HTTP header metafiles. +
    mod_cgi +
    Invoking CGI scripts. +
    mod_cookies up to Apache 1.1.1 +
    Support for Netscape-like cookies. Replaced in Apache 1.2 by +mod_usertrack +
    mod_digest +
    MD5 authentication +
    mod_dir +
    Automatic directory listings. +
    mod_dld +
    Start-time linking with the GNU libdld. +
    mod_env +
    Passing of environments to CGI scripts +
    mod_example Apache 1.2 and up +
    Demonstrates Apache API +
    mod_expires Apache 1.2 and up +
    Apply Expires: headers to resources +
    mod_headers Apache 1.2 and up +
    Add arbitrary HTTP headers to resources +
    mod_imap +
    The imagemap file handler. +
    mod_include +
    Server-parsed documents. +
    mod_info +
    Server configuration information +
    mod_log_agent +
    Logging of User Agents. +
    mod_log_common up to Apache 1.1.1 +
    Standard logging in the Common Logfile Format. Replaced by the +mod_log_config module in Apache 1.2 and up +
    mod_log_config +
    User-configurable logging replacement for mod_log_common. +
    mod_log_referer +
    Logging of document references. +
    mod_mime +
    Determining document types. +
    mod_negotiation +
    Content negotiation. +
    mod_rewrite Apache 1.2 and up +
    Powerful URI-to-filename mapping using regular expressions +
    mod_proxy +
    Caching proxy abilities +
    mod_status +
    Server status display +
    mod_userdir +
    User home directories. +
    mod_usertrack Apache 1.2 and up +
    User tracking using Cookies (replacement for mod_cookies.c) +
    + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_access.html b/APACHE_1_2_X/htdocs/manual/mod/mod_access.html new file mode 100644 index 00000000000..80c99831055 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_access.html @@ -0,0 +1,176 @@ + + + +Apache module mod_access + + + + + + +

    Module mod_access

    + +This module is contained in the mod_access.c file, and +is compiled in by default. It provides access control based on client +hostname or IP address. + + + +
  • allow +
  • allow from env= +
  • deny +
  • deny from env= +
  • order +
  • +
    + + +

    allow

    + +Syntax: allow from host host ...
    +Context: directory, .htaccess
    +Override: Limit
    +Status: Base
    +Module: mod_access

    + +The allow directive affects which hosts can access a given directory. +Host is one of the following: +

    +
    all +
    all hosts are allowed access +
    A (partial) domain-name +
    host whose name is, or ends in, this string are allowed access. +
    A full IP address +
    An IP address of a host allowed access +
    A partial IP address +
    The first 1 to 3 bytes of an IP address, for subnet restriction. +
    + +Example:
    allow from .ncsa.uiuc.edu
    +All hosts in the specified domain are allowed access.

    + +Note that this compares whole components; bar.edu +would not match foobar.edu.

    + +See also deny, order, and +BrowserMatch.

    + +Syntax: allow from env=variablename
    +Context: directory, .htaccess
    +Override: Limit
    +Status: Base
    +Module: mod_access
    +Compatibility: Apache 1.2 and above

    + +The allow from env directive controls access to a directory by the +existence (or non-existence) of an environment variable. + +Example:

    +BrowserMatch ^KnockKnock/2.0 let_me_in
    +<Directory /docroot>
    +order allow,deny
    +allow from env=let_me_in
    +deny from all
    +</Directory>
    +
    + +See also deny from env +and order.


    + +

    deny

    + +Syntax: deny from host host ...
    +Context: directory, .htaccess
    +Override: Limit
    +Status: Base
    +Module: mod_access

    + +The deny directive affects which hosts can access a given directory. +Host is one of the following: +

    +
    all +
    all hosts are denied access +
    A (partial) domain-name +
    host whose name is, or ends in, this string are denied access. +
    A full IP address +
    An IP address of a host denied access +
    A partial IP address +
    The first 1 to 3 bytes of an IP address, for subnet restriction. +
    + +Example:
    deny from 16
    +All hosts in the specified network are denied access.

    + +Note that this compares whole components; bar.edu +would not match foobar.edu.

    + +See also allow and order.

    + +Syntax: deny from env=variablename
    +Context: directory, .htaccess
    +Override: Limit
    +Status: Base
    +Module: mod_access
    +Compatibility: Apache 1.2 and above

    + +The deny from env directive controls access to a directory by the +existence (or non-existence) of an environment variable. + +Example:

    +BrowserMatch ^BadRobot/0.9 go_away
    +<Directory /docroot>
    +order deny,allow
    +deny from env=go_away
    +allow from all
    +</Directory>
    +
    + +See also allow from env +and order.


    + +

    order

    + +Syntax: order ordering
    +Default: order deny,allow
    +Context: directory, .htaccess
    +Override: Limit
    +Status: Base
    +Module: mod_access

    + +The order directive controls the order in which allow and +deny directives are evaluated. Ordering is one +of +

    +
    deny,allow +
    the deny directives are evaluated before the allow directives. (The +initial state is OK.) +
    allow,deny +
    the allow directives are evaluated before the deny directives. (The +initial state is FORBIDDEN.) +
    mutual-failure +
    Only those hosts which appear on the allow list and do not appear +on the deny list are granted access. (The initial state is irrelevant.) +
    + +Note that in all cases every allow and deny +statement is evaluated, there is no "short-circuiting". + +

    Example: +

    +order deny,allow
    +deny from all
    +allow from .ncsa.uiuc.edu
    +
    +Hosts in the ncsa.uiuc.edu domain are allowed access; all other hosts are +denied access. + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_actions.html b/APACHE_1_2_X/htdocs/manual/mod/mod_actions.html new file mode 100644 index 00000000000..03709d5a90a --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_actions.html @@ -0,0 +1,85 @@ + + + +Module mod_actions + + + + + +

    Module mod_actions

    + +This module is contained in the mod_actions.c file, and +is compiled in by default. It provides for +executing CGI scripts based on media type or request method. It is not +present in versions prior to Apache 1.1. + +

    Summary

    + +This module lets you run CGI scripts whenever a file of a certain type +is requested. This makes it much easier to execute scripts that +process files. + +

    Directives

    + + +
    + +

    Action

    +Syntax: Action mime-type cgi-script
    +Context: server config, virtual host, directory, .htaccess
    +Override: FileInfo
    +Status: Base
    +Module: mod_actions
    +Compatibility: Action is only available in Apache 1.1 +and later

    + +This directive adds an action, which will activate cgi-script when +a file of content type mime-type is requested. It sends the +URL and file path of the requested document using the standard +CGI PATH_INFO and PATH_TRANSLATED environment variables. + +


    + +

    Script

    +Syntax: Script method cgi-script
    +Context: server config, virtual host, directory
    +Status: Base
    +Module: mod_actions
    +Compatibility: Script is only available in Apache 1.1 +and later

    + +

    This directive adds an action, which will activate cgi-script when +a file is requested using the method of method, which can be +one of GET, POST, PUT or +DELETE. It sends the +URL and file path of the requested document using the standard +CGI PATH_INFO and PATH_TRANSLATED environment variables. + +

    Note that the Script command defines default actions only. If a CGI +script is called, or some other resource that is capable of handling +the requested method internally, it will do so. Also note that script +with a method of GET will only be called if there are +query arguments present (e.g. foo.html?hi). Otherwise, the request +will proceed normally. + +

    Examples: +

    +    Script GET /cgi-bin/search     #e.g. for <ISINDEX>-style searching
    +    Script PUT /~bob/put.cgi
    +
    +
    + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_alias.html b/APACHE_1_2_X/htdocs/manual/mod/mod_alias.html new file mode 100644 index 00000000000..c5c89250e30 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_alias.html @@ -0,0 +1,146 @@ + + + +Apache module mod_alias + + + + + + +

    Module mod_alias

    + +This module is contained in the mod_alias.c file, and +is compiled in by default. It provides for mapping different parts of the +host filesystem in the the document tree, and for URL redirection. + + + +
  • Alias +
  • Redirect +
  • RedirectTemp +
  • RedirectPermanent +
  • ScriptAlias +
  • +
    + + +

    Alias

    + +Syntax: Alias url-path directory-filename
    +Context: server config, virtual host
    +Status: Base
    +Module: mod_alias
    + +The Alias directive allows documents to be stored in the local filesystem +other than under the DocumentRoot. +URLs with a (%-decoded) path beginning with url-path will be +mapped to local files beginning with directory-filename. +Example: +
    Alias /image /ftp/pub/image
    +A request for http://myserver/image/foo.gif would cause the server to +return the file /ftp/pub/image/foo.gif.

    + +Note that if you include a trailing / on the url-path then the +server will require a trailing / in order to expand the alias. That is, +if you use Alias /icons/ /usr/local/etc/httpd/icons/ then +the url /icons will not be aliased.

    + +See also ScriptAlias.


    + +

    Redirect

    + +Syntax: Redirect [ status ] url-path url
    +Context: server config, virtual host, directory, .htaccess
    +Status: Base
    +Module: mod_alias
    +Compatibility: The directory and .htaccess context's +are only available in versions 1.1 and later. The status argument is only available in Apache 1.2 or later.

    + +The Redirect directive maps an old URL into a new one. The new URL is returned +to the client which attempts to fetch it again with the new address. +Url-path a (%-decoded) path; any requests for documents beginning with +this path will be returned a redirect error to a new (%-encoded) url +beginning with url. Example: +

    Redirect /service +http://foo2.bar.com/service
    +If the client requests http://myserver/service/foo.txt, it will be told to +access http://foo2.bar.com/service/foo.txt instead.

    + +Note: Redirect directives take precedence over Alias and ScriptAlias +directives, irrespective of their ordering in the configuration file. Also, +Url-path must be an absolute path, not a relative path, even when used with +.htaccess files or inside of <Directory> sections.

    + +If no status argument is given, the redirect will be +"temporary" (HTTP status 302). This indicates to the client that the +resources is has moved temporarily. The status +argument can be used to return other HTTP status codes: +

    +
    permanent
    Returns a permanent redirect status (301) indicating that +the resource has moved permanently. +
    temp
    Returns a temporary redirect status (302). This is the +default. +
    seeother
    Returns a "See Other" status (303) indicating that +the resource has been replaced. +
    gone
    Returns a "Gone" status (410) indicating that the resource +has been permanently removed. When this status is used the url +argument should be omitted. +
    + +Other status codes can be returned by giving the numeric status code +as the value of status. If the status is between 300 and 399, +the url argument must be present, otherwise it must be +omitted. Note that the status must be known to the Apache code (see +the function send_error_response in http_protocol.c). + +

    RedirectTemp

    + +Syntax: RedirectTemp url-path url
    +Context: server config, virtual host, directory, .htaccess
    +Status: Base
    +Module: mod_alias
    +Compatibility: This directive is only available in 1.2

    + +This directive makes the client know that the Redirect is only +temporary. (Status 302). Exactly equivalent to Redirect temporary

    + +

    RedirectPermanent

    + +Syntax: RedirectPermanent url-path url
    +Context: server config, virtual host, directory, .htaccess
    +Status: Base
    +Module: mod_alias
    +Compatibility: This directive is only available in 1.2

    + +This directive makes the client know that the Redirect is permanent. +(Status 301). Exactly equivalent to Redirect permanent

    + +


    +

    ScriptAlias

    + +Syntax: ScriptAlias url-path directory-filename
    +Context: server config, virtual host
    +Status: Base
    +Module: mod_alias
    + +The ScriptAlias directive has the same behavior as the +Alias directive, except that in addition it +marks the target directory as containing CGI scripts. +URLs with a (%-decoded) path beginning with url-path will be +mapped to scripts beginning with directory-filename. +Example: +
    ScriptAlias /cgi-bin/ /web/cgi-bin/
    +A request for http://myserver/cgi-bin/foo would cause the server to +run the script /web/cgi-bin/foo.

    + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_asis.html b/APACHE_1_2_X/htdocs/manual/mod/mod_asis.html new file mode 100644 index 00000000000..85e628115e1 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_asis.html @@ -0,0 +1,68 @@ + + + +Apache module mod_asis + + + + + + +

    Module mod_asis

    + +This module is contained in the mod_asis.c file, and +is compiled in by default. It provides for .asis files. Any +document with mime type httpd/send-as-is will be processed by +this module. + + +

    Purpose

    +To allow file types to be defined such that Apache sends them without +adding HTTP headers.

    + +This can be used to send any kind of data from the server, including redirects +and other special HTTP responses, without requiring a cgi-script or an nph +script. +

    Usage

    +In the server configuration file, define a new mime type called +httpd/send-as-is e.g. +
    AddType httpd/send-as-is asis
    +this defines the .asis file extension as being of the new +httpd/send-as-is mime type. The contents of any file with a +.asis extension will then be sent by Apache to the client with +almost no changes. Clients will need HTTP headers to be attached, so do not +forget them. A Status: header is also required; the data should be the +3-digit HTTP response code, followed by a textual message.

    + +Here's an example of a file whose contents are sent as is so as to +tell the client that a file has redirected. +

    +Status: 302 Now where did I leave that URL
    +Location: http://xyz.abc.com/foo/bar.html
    +Content-type: text/html
    +
    +<HTML>
    +<HEAD>
    +<TITLE>Lame excuses'R'us</TITLE>
    +</HEAD>
    +<BODY>
    +<H1>Fred's exceptionally wonderful page has moved to
    +<A HREF="http://xyz.abc.com/foo/bar.html">Joe's</A> site.
    +</H1>
    +</BODY>
    +</HTML> +
    +Notes: the server always adds a Date: and Server: header to the data returned +to the client, so these should not be included in the file. +The server does not add a Last-Modified header; it probably should. +

    + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_auth.html b/APACHE_1_2_X/htdocs/manual/mod/mod_auth.html new file mode 100644 index 00000000000..bfb47a795aa --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_auth.html @@ -0,0 +1,145 @@ + + + +Apache module mod_auth + + + + + + +

    Module mod_auth

    + +This module is contained in the mod_auth.c file, and +is compiled in by default. It provides for user authentication using +textual files. + + + +
  • AuthGroupFile +
  • AuthUserFile +
  • AuthAuthoritative +
  • +
    + + +

    AuthGroupFile

    + +Syntax: AuthGroupFile filename
    +Context: directory, .htaccess
    +Override: AuthConfig
    +Status: Base
    +Module: mod_auth

    + +The AuthGroupFile directive sets the name of a textual file containing the list +of user groups for user authentication. Filename is the absolute path +to the group file.

    +Each line of the group file contains a groupname followed by a colon, followed +by the member usernames separated by spaces. Example: +

    mygroup: bob joe anne
    +Note that searching large groups files is very inefficient; +AuthDBMGroupFile should +be used instead.

    + +Security: make sure that the AuthGroupFile is stored outside the +document tree of the web-server; do not put it in the directory that +it protects. Otherwise, clients will be able to download the AuthGroupFile.

    + +See also AuthName, +AuthType and +AuthUserFile.


    + +

    AuthUserFile

    + +Syntax: AuthUserFile filename
    +Context: directory, .htaccess
    +Override: AuthConfig
    +Status: Base
    +Module: mod_auth

    + +The AuthUserFile directive sets the name of a textual file containing +the list of users and passwords for user +authentication. Filename is the absolute path to the user +file.

    Each line of the user file file contains a username followed +by a colon, followed by the crypt() encrypted password. The behavior +of multiple occurrences of the same user is undefined.

    Note that +searching user groups files is inefficient; AuthDBMUserFile should be +used instead.

    + +Security: make sure that the AuthUserFile is stored outside the +document tree of the web-server; do not put it in the directory that +it protects. Otherwise, clients will be able to download the AuthUserFile.

    + +See also AuthName, +AuthType and +AuthGroupFile.

    +


    +

    AuthAuthoritative

    + +Syntax: AuthAuthoritative < on(default) | off >
    +Context: directory, .htaccess
    +Override: AuthConfig
    +Status: Base
    +Module: mod_auth

    + +Setting the AuthAuthoritative directive explicitly to 'off' +allows for both authentication and authorization to be passed on to +lower level modules (as defined in the Configuration and +modules.c files) if there is no userID or +rule matching the supplied userID. If there is a userID and/or +rule specified; the usual password and access checks will be applied +and a failure will give an Authorization Required reply. + +

    + +So if a userID appears in the database of more than one module; or if +a valid require directive applies to more than one module; then the +first module will verify the credentials; and no access is passed on; +regardless of the AuthAuthoritative setting. + +

    + +A common use for this is in conjunction with one of the database +modules; such as mod_auth_db.c, mod_auth_dbm.c, mod_auth_msql.c and mod_auth_anon.c. These modules +supply the bulk of the user credential checking; but a few +(administrator) related accesses fall through to a lower level with a +well protected AuthUserFile. + +

    + +Default: By default; control is not passed on; and an unknown +userID or rule will result in an Authorization Required reply. Not +setting it thus keeps the system secure; and forces an NSCA compliant +behaviour. + +

    + +Security: Do consider the implications of allowing a user to allow +fall-through in his .htaccess file; and verify that this is really +what you want; Generally it is easier to just secure a single +.htpasswd file, than it is to secure a database such as mSQL. Make +sure that the AuthUserFile is stored outside the document tree of the +web-server; do not put it in the directory that it +protects. Otherwise, clients will be able to download the +AuthUserFile. + +

    +See also AuthName, +AuthType and +AuthGroupFile.

    + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_auth_anon.html b/APACHE_1_2_X/htdocs/manual/mod/mod_auth_anon.html new file mode 100644 index 00000000000..c880c34ee10 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_auth_anon.html @@ -0,0 +1,249 @@ + + + +Apache module mod_auth_anon.c + + + + +

    Module mod_auth_anon

    + +This module is contained in the mod_auth_anon.c file and +is not compiled in by default. It is only available in Apache 1.1 and +later. It allows "anonymous" user access to authenticated areas. + +

    Summary

    + +It does access control in a manner similar to anonymous-ftp sites; i.e. +have a 'magic' user id 'anonymous' and the email address as a password. +These email addresses can be logged. +

    +Combined with other (database) access control methods, this allows for +effective user tracking and customization according to a user profile +while still keeping the site open for 'unregistered' users. One advantage +of using Auth-based user tracking is that, unlike magic-cookies and +funny URL pre/postfixes, it is completely browser independent and it +allows users to share URLs. +

    + +Directives / +Example / +Compile time options / +RevisionHistory / +Person to blame / +Sourcecode +

    + +

    Directives

    + + +
    + +

    Anonymous

    + +Syntax: Anonymous user user ...
    +Default: none
    +Context: directory, .htaccess
    +Override: AuthConfig
    +Status: Extension
    +Module: mod_auth_anon

    + + A list of one or more 'magic' userIDs which are allowed access + without password verification. The userIDs are space separated. + It is possible to use the ' and " quotes to allow a space in + a userID as well as the \ escape character. +

    + Please note that the comparison is case-IN-sensitive. +
    + I strongly suggest that the magic username 'anonymous' + is always one of the allowed userIDs. +

    + Example:
    + + Anonymous: anonymous "Not Registered" 'I don\'t know' +

    + This would allow the user to enter without password verification + by using the userId's 'anonymous', 'AnonyMous','Not Registered' and + 'I Don't Know'. +


    + +

    Anonymous_Authoritative

    +Syntax: Anonymous_Authoritative on | off
    +Default: Anonymous_Authoritative off
    +Context: directory, .htaccess
    +Override: AuthConfig
    +Status: Extension
    +Module: mod_auth_anon

    + + When set 'on', there is no + fall-through to other authorization methods. So if a + userID does not match the values specified in the + Anonymous directive, access is denied. +

    + Be sure you know what you are doing when you decide to switch + it on. And remember that it is the linking order of the modules + (in the Configuration / Make file) which details the order + in which the Authorization modules are queried. +


    + +

    Anonymous_LogEmail

    +Syntax: Anonymous_LogEmail on | off
    +Default: off
    +Context: directory, .htaccess
    +Override: AuthConfig
    +Status: Extension
    +Module: mod_auth_anon

    + + When set 'on', the default, the 'password' entered (which hopefully + contains a sensible email address) is logged in the httpd-log file. +


    + +

    Anonymous_MustGiveEmail

    + +Syntax: Anonymous_MustGiveEmail on | off
    +Default: off
    +Context: directory, .htaccess
    +Override: AuthConfig
    +Status: Extension
    +Module: mod_auth_anon

    + + Specifies whether the user must specify an email + address as the password. This prohibits blank passwords. +


    + +

    Anonymous_NoUserID

    +Syntax: Anonymous_NoUserID on | off
    +Default: Anonymous_NoUserID off
    +Context: directory, .htaccess
    +Override: AuthConfig
    +Status: Extension
    +Module: mod_auth_anon

    + + When set 'on', users can leave + the userID (and perhaps the password field) empty. This + can be very convenient for MS-Explorer users who can + just hit return or click directly on the OK button; which + seems a natural reaction. + +


    + +

    Anonymous_VerifyEmail

    +Syntax: Anonymous on | off
    +Default: Anonymous_VerifyEmail off
    +Context: directory, .htaccess
    +Override: AuthConfig
    +Status: Extension
    +Module: mod_auth_anon

    + + When set 'on' the 'password' entered is + checked for at least one '@' and a '.' to encourage users to enter + valid email addresses (see the above Auth_LogEmail). + +


    Example

    + +The example below (when combined with the Auth directives +of a htpasswd-file based (or GDM, mSQL etc) base access +control system allows users in as 'guests' with the +following properties: +
      +
    • +It insists that the user enters a userId. (Anonymous_NoUserId) +
    • +It insists that the user enters a password. (Anonymous_MustGiveEmail) +
    • +The password entered must be a valid email address, ie. contain at least one '@' and a '.'. +(Anonymous_VerifyEmail) +
    • +The userID must be one of anonymous guest www test welcome +and comparison is not case sensitive. +<directory /web/docs/public> +
    • +And the Email addresses entered in the passswd field are logged to +the httpd-log file +(Anonymous_LogEmail) +
    +

    +Excerpt of access.conf: +

    +
    +Anonymous anonymous guest www test welcome

    +Anonymous_MustGiveEmail on
    +Anonymous_VerifyEmail on
    +Anonymous_NoUserId off
    +Anonymous_LogEmail on
    +

    +AuthName Use 'anonymous' & Email address for guest entry
    +AuthType basic

    + +

    +
    + Normal Apache/NCSA tokens for access control +

    + <limit get post head>
    + order deny,allow
    + allow from all
    +

    + require valid-user
    + <limit>
    +

    +
    + + +

    Compile Time Options

    + +Currently there are no Compile options. + +

    Revision History

    + +This version: 23 Nov 1995, 24 Feb 1996, 16 May 1996. + +
    + +
    Version 0.4
    +
    First release +
    +
    Version 0.5
    +
    Added 'VerifyEmail' and 'LogEmail' options. Multiple + 'anonymous' tokens allowed. more docs. Added Authoritative + functionality. +
    +
    + + +

    Contact/person to blame

    + +This module was written for the +European Wide Service Exchange by +<Dirk.vanGulik@jrc.it>. +Feel free to contact me if you have any problems, ice-creams or bugs. This +documentation, courtesy of Nick Himba, +<himba@cs.utwente.nl>. +

    + + +


    Sourcecode

    + +The source code can be found at +http://www.apache.org. A snapshot of a development version +usually resides at +http://me-www.jrc.it/~dirkx/mod_auth_anon.c. Please make sure +that you always quote the version you use when filing a bug report. +

    + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_auth_db.html b/APACHE_1_2_X/htdocs/manual/mod/mod_auth_db.html new file mode 100644 index 00000000000..d97035bf0ff --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_auth_db.html @@ -0,0 +1,160 @@ + + + +Apache module mod_auth_db + + + + + +

    Module mod_auth_db

    + +This module is contained in the mod_auth_db.c file, and +is not compiled in by default. It provides for user authentication using +Berkeley DB files. It is an alternative to DBM +files for those systems which support DB and not DBM. It is only +available in Apache 1.1 and later. + + + +
  • AuthDBGroupFile +
  • AuthDBUserFile +
  • AuthDBAuthoritative +
  • +
    + + +

    AuthDBGroupFile

    + +Syntax: AuthDBGroupFile filename
    +Context: directory, .htaccess
    +Override: AuthConfig
    +Status: Extension
    +Module: mod_auth_db

    + +The AuthDBGroupFile directive sets the name of a DB file containing the list +of user groups for user authentication. Filename is the absolute path +to the group file.

    + +The group file is keyed on the username. The value for a user is a +comma-separated list of the groups to which the users belongs. There must +be no whitespace within the value, and it must never contain any colons.

    + +Security: make sure that the AuthDBGroupFile is stored outside the +document tree of the web-server; do not put it in the directory that +it protects. Otherwise, clients will be able to download the +AuthDBGroupFile unless otherwise protected.

    + +Combining Group and Password DB files: In some cases it is easier to +manage a single database which contains both the password and group +details for each user. This simplifies any support programs that need +to be written: they now only have to deal with writing to and locking +a single DBM file. This can be accomplished by first setting the group +and password files to point to the same DB file:

    + +

    +AuthDBGroupFile /www/userbase
    +AuthDBUserFile /www/userbase +
    + +The key for the single DB record is the username. The value consists of

    + +

    +Unix Crypt-ed Password : List of Groups [ : (ignored) ] +
    + +The password section contains the Unix crypt() password as before. This is +followed by a colon and the comma separated list of groups. Other data may +optionally be left in the DB file after another colon; it is ignored by the +authentication module.

    + +See also AuthName, +AuthType and +AuthDBUserFile.


    + +

    AuthDBUserFile

    + +Syntax: AuthDBUserFile filename
    +Context: directory, .htaccess
    +Override: AuthConfig
    +Status: Extension
    +Module: mod_auth_db

    + +The AuthDBUserFile directive sets the name of a DB file containing the list +of users and passwords for user authentication. Filename is the +absolute path to the user file.

    + +The user file is keyed on the username. The value for a user is the +crypt() encrypted password, optionally followed by a colon and +arbitrary data. The colon and the data following it will be ignored +by the server.

    + +Security: make sure that the AuthDBUserFile is stored outside the +document tree of the web-server; do not put it in the directory that +it protects. Otherwise, clients will be able to download the +AuthDBUserFile.

    + +Important compatibility note: The implementation of "dbmopen" in the +apache modules reads the string length of the hashed values from the +DB data structures, rather than relying upon the string being +NULL-appended. Some applications, such as the Netscape web server, +rely upon the string being NULL-appended, so if you are having trouble +using DB files interchangeably between applications this may be a +part of the problem.

    + +See also AuthName, +AuthType and +AuthDBGroupFile.

    +


    +

    AuthDBAuthoritative

    + +Syntax: AuthDBAuthoritative < on(default) | off >
    +Context: directory, .htaccess
    +Override: AuthConfig
    +Status: Base
    +Module: mod_auth

    + +Setting the AuthDBAuthoritative directive explicitly to 'off' +allows for both authentication and authorization to be passed on +to lower level modules (as defined in the Configuration +and modules.c file if there is no userID or +rule matching the supplied userID. If there is a userID +and/or rule specified; the usual password and access checks will +be applied and a failure will give an Authorization Required reply. +

    +So if a userID appears in the database of more than one module; or +if a valid require directive applies to more than one module; then +the first module will verify the credentials; and no access is +passed on; regardless of the AuthAuthoritative setting.

    + +A common use for this is in conjunction with one of the basic auth +modules; such as mod_auth.c. +Whereas this DB module supplies the bulk of the user credential +checking; a few (administrator) related accesses fall through to +a lower level with a well protected .htpasswd file.

    + +Default: By default; control is not passed on; and an unknown +userID or rule will result in an Authorization Required reply. Not +setting it thus keeps the system secure; and forces an NSCA compliant +behaviour.

    +Security: Do consider the implications of allowing a user to allow +fall-through in his .htaccess file; and verify that this is really +what you want; Generally it is easier to just secure a single +.htpasswd file, than it is to secure a database which might have +more access interfaces. + +

    +See also AuthName, +AuthType and +AuthDBGroupFile.

    + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_auth_dbm.html b/APACHE_1_2_X/htdocs/manual/mod/mod_auth_dbm.html new file mode 100644 index 00000000000..42e0b649853 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_auth_dbm.html @@ -0,0 +1,162 @@ + + + +Apache module mod_auth_dbm + + + + + + +

    Module mod_auth_dbm

    + +This module is contained in the mod_auth_dbm.c file, and +is not compiled in by default. It provides for user authentication using +DBM files. + + + +
  • AuthDBMGroupFile +
  • AuthDBMUserFile +
  • AuthDBMAuthoritative +
  • +
    + + +

    AuthDbmGroupFile

    + +Syntax: AuthDBMGroupFile filename
    +Context: directory, .htaccess
    +Override: AuthConfig
    +Status: Extension
    +Module: mod_auth_dbm

    + +The AuthDBMGroupFile directive sets the name of a DBM file containing the list +of user groups for user authentication. Filename is the absolute path +to the group file.

    + +The group file is keyed on the username. The value for a user is a +comma-separated list of the groups to which the users belongs. There must +be no whitespace within the value, and it must never contain any colons.

    + +Security: make sure that the AuthDBMGroupFile is stored outside the +document tree of the web-server; do not put it in the directory that +it protects. Otherwise, clients will be able to download the +AuthDBMGroupFile unless otherwise protected.

    + +Combining Group and Password DBM files: In some cases it is easier to +manage a single database which contains both the password and group +details for each user. This simplifies any support programs that need +to be written: they now only have to deal with writing to and locking +a single DBM file. This can be accomplished by first setting the group +and password files to point to the same DBM:

    + +

    +AuthDBMGroupFile /www/userbase
    +AuthDBMUserFile /www/userbase +
    + +The key for the single DBM is the username. The value consists of

    + +

    +Unix Crypt-ed Password : List of Groups [ : (ignored) ] +
    + +The password section contains the Unix crypt() password as before. This is +followed by a colon and the comma separated list of groups. Other data may +optionally be left in the DBM file after another colon; it is ignored by the +authentication module. This is what www.telescope.org uses for its combined +password and group database.

    + +See also AuthName, +AuthType and +AuthDBMUserFile.


    + +

    AuthDBMUserFile

    + +Syntax: AuthDBMUserFile filename
    +Context: directory, .htaccess
    +Override: AuthConfig
    +Status: Extension
    +Module: mod_auth_dbm

    + +The AuthDBMUserFile directive sets the name of a DBM file containing the list +of users and passwords for user authentication. Filename is the +absolute path to the user file.

    + +The user file is keyed on the username. The value for a user is the +crypt() encrypted password, optionally followed by a colon and +arbitrary data. The colon and the data following it will be ignored +by the server.

    + +Security: make sure that the AuthDBMUserFile is stored outside the +document tree of the web-server; do not put it in the directory that +it protects. Otherwise, clients will be able to download the +AuthDBMUserFile.

    + +Important compatibility note: The implementation of "dbmopen" in the +apache modules reads the string length of the hashed values from the +DBM data structures, rather than relying upon the string being +NULL-appended. Some applications, such as the Netscape web server, +rely upon the string being NULL-appended, so if you are having trouble +using DBM files interchangeably between applications this may be a +part of the problem.

    + +See also AuthName, +AuthType and +AuthDBMGroupFile.

    + +


    +

    AuthDBMAuthoritative

    + +Syntax: AuthDBMAuthoritative < on(default) | off >
    +Context: directory, .htaccess
    +Override: AuthConfig
    +Status: Base
    +Module: mod_auth

    + +Setting the AuthDBMAuthoritative directive explicitly to 'off' +allows for both authentication and authorization to be passed on +to lower level modules (as defined in the Configuration +and modules.c file if there is no userID or +rule matching the supplied userID. If there is a userID +and/or rule specified; the usual password and access checks will +be applied and a failure will give an Authorization Required reply. +

    +So if a userID appears in the database of more than one module; or +if a valid require directive applies to more than one module; then +the first module will verify the credentials; and no access is +passed on; regardless of the AuthAuthoritative setting.

    + +A common use for this is in conjunction with one of the basic auth +modules; such as mod_auth.c. +Whereas this DBM module supplies the bulk of the user credential +checking; a few (administrator) related accesses fall through to +a lower level with a well protected .htpasswd file.

    + +Default: By default; control is not passed on; and an unknown +userID or rule will result in an Authorization Required reply. Not +setting it thus keeps the system secure; and forces an NSCA compliant +behaviour.

    + +Security: Do consider the implications of allowing a user to allow +fall-through in his .htaccess file; and verify that this is really +what you want; Generally it is easier to just secure a single +.htpasswd file, than it is to secure a database which might have +more access interfaces. + +

    +See also AuthName, +AuthType and +AuthDBMGroupFile.

    + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_auth_msql.html b/APACHE_1_2_X/htdocs/manual/mod/mod_auth_msql.html new file mode 100644 index 00000000000..f1cae193335 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_auth_msql.html @@ -0,0 +1,475 @@ + + + +Module mod_auth_msql + + + + +

    Module mod_auth_msql

    + +This module is contained in the mod_auth_msql.c file and +is compiled in by default. It allows access control using the public +domain mSQL database ftp://ftp.bond.edu.au/pub/Minerva/msql, +a fast but limited SQL engine which can be contacted over an internal +Unix domain protocol as well as over normal TCP/IP socket +communication. It is only available in Apache 1.1 and later.

    + +Full description / +Example / +Compile time options / +RevisionHistory / +Person to blame / +Sourcecode +

    + +


    Full description of all tokens

    +
    + +
    +Auth_MSQLhost < FQHN | IP Address | localhost > +
    + Hostname of the machine running the mSQL demon. The effective uid + of the server should be allowed access. If not given, or if it is + the magic name localhost, it is passed to the mSQL library as a null + pointer. This effectively forces it to use /dev/msql rather than the + (slower) socket communication. +
    + +
    +Auth_MSQLdatabase < mSQL database name > +
    + Name of the database in which the following table(s) are contained (Quick check: use the + mSQL command relshow [<hostname> dbase] to verify the spelling of the + database name). +
    + +
    +Auth_MSQLpwd_table < mSQL table name > +
    + Contains at least the fields with the username + and the (encrypted) password. Each uid should only occur once in this table and + for performance reasons should be a primary key. + Normally this table is compulsory, but it is + possible to use a fall-through to other methods + and use the mSQL module for group control only. + See the Auth_MSQL_Authoritative + directive below. +
    + +
    +Auth_MSQLgrp_table < mSQL table name in the above database > +
    + Contains at least the fields with the + username and the groupname. A user which + is in multiple groups has therefore + multiple entries. There might be some performance + problems associated with this and one + might consider to have separate tables for each + group (rather than all groups in one table) if + your directory structure allows for it. + One only need to specify this table when doing + group control. +
    + +
    +Auth_MSQLuid_field < mSQL field name > +
    + Name of the field containing the username in the + Auth_MSQLpwd_table and optionally in the + Auth_MSQLgrp_table tables. +
    + +
    +Auth_MSQLpwd_field < mSQL field name > +
    + Fieldname for the passwords in the + Auth_MSQLpwd_table table. +
    + +
    +Auth_MSQLgrp_field < mSQL field name > +
    + Fieldname for the groupname
    + Only the fields used need to be specified. When this + module is compiled with the + BACKWARD_VITEK option then + the uid and pwd field names default to 'user' and 'password'. + However you are strongly encouraged to always specify these values + explicitly given the security issues involved. +
    + +
    +Auth_MSQL_nopasswd < on | off > +
    + Skip password comparison if passwd field is + empty, i.e. allow any password. This is 'off' + by default to ensure that an empty field + in the mSQL table does not allow people in by + default with a random password. +
    + +
    +Auth_MSQL_Authoritative < on | off > +
    + Default is 'on'. When set 'on', there is no + fall-through to other authorization methods. So if a + user is not in the mSQL dbase table (and perhaps + not in the right group) or has the password wrong, then + he or she is denied access. When this directive is set to + 'off', control is passed on to any other authorization + modules, such as the basic auth module with the htpasswd + file or the Unix-(g)dbm modules. The default is 'on' + to avoid nasty 'fall-through' surprises. Be sure you + know what you are doing when you decide to switch it off. +
    + +
    +Auth_MSQL_EncryptedPasswords < on | off > +
    + Default is 'on'. When set on, the values in the + pwd_field are assumed to be crypt-ed using *your* + machines 'crypt()' function and the incoming password + is 'crypt'ed before comparison. When this function is + 'off', the comparison is done directly with the plaintext + entered password. (Yes, http-basic-auth does send the + password as plaintext over the wire :-( ). The default + is a sensible 'on', and I personally think that it is + a *very-bad-idea* to change this. However a multi + vendor or international environment (which sometimes + leads to different crypts functions) might force you to. +
    +
    + + +

    Example

    + +An example mSQL table could be created with the following commands: +
    +     % msqladmin create www               
    + % msql www
    + -> create table user_records (
    + -> User_id char(32) primary key,
    + -> Cpasswd char(32),
    + -> Xgroup char(32)
    + -> ) \g
    + query OK
    + -> \q
    + %
    +

    + +The User_id can be as long as desired. However some of the +popular web browsers truncate names at or stop the user from entering +names longer than 32 characters. Furthermore the 'crypt' function +on your platform might impose further limits. Also use of +the require users uid [uid..] directive in the +access.conf file where the uid's are separated by +spaces can possibly prohibit the use of spaces in your usernames. +Also, please note the MAX_FIELD_LEN +directive somewhere below. +

    +To use the above, the following example could be in your +access.conf file. Also there is a more elaborate description +below this example. +

    + +<directory /web/docs/private> +

    + +

    +
    +Auth_MSQLhost localhost
    +
    +
    or
    +
    +Auth_MSQLhost datab.machine.your.org +
    + If this directive is omitted or set to localhost, + it is assumed that Apache and the mSQL + database run on the same (physical) machine and the faster + /dev/msql communication channel will be used. Otherwise, + it is the machine to contact by TCP/IP. Consult the mSQL + documentation for more information. +
    +

    + +

    +Auth_MSQLdatabase www +
    + The name of the database on the above machine, + which contains *both* the tables for group and + for user/passwords. Currently it is not possible + to have these split over two databases. Make + sure that the msql.acl (access control file) of + mSQL does indeed allow the effective uid of the + web server read access to this database. Check the + httpd.conf file for this uid. +
    + +
    +Auth_MSQLpwd_table user_records +
    + This is the table which contain the uid/password combination + is specified. +
    + +
    +Auth_MSQLuid_field User_id
    +Auth_MSQLpwd_field Cpasswd +
    + These two directive specify the field names in the user_record + table. If this module is compiled with the BACKWARD_VITEK + compatibility switch, the defaults user and password are + assumed if you do not specify them. Currently the user_id field + *MUST* be a primary key or one must ensure that each user only + occurs once in the table. If a uid occurs twice access is + denied by default; but see the ONLY_ONCE + compiler directive for more information. +
    + +
    +Auth_MSQLgrp_table user_records
    +Auth_MSQLgrp_field Xgroup
    +
    + Optionally one can also specify a table which contains the + user/group combinations. This can be the same table which + also contains the username/password combinations. However + if a user belongs to two or more groups, one will have to + use a different table with multiple entries. +
    + +
    +Auth_MSQL_nopasswd off
    +Auth_MSQL_Authoritative on
    +Auth_MSQL_EncryptedPasswords on
    +
    + These three optional fields (all set to the sensible defaults, + so you really do not have to enter them) are described in more + detail below. If you choose to set these to any other values then + the above, be very sure you understand the security implications and + do verify that Apache does what you expect it to do. +
    + +
    +AuthName example mSQL realm
    +AuthType basic +
    +
    + Normal Apache/NCSA tokens for access control +

    + <limit get post head>
    + order deny,allow
    + allow from all
    +

    + require valid-user
    +

    • valid-user; allow in any user which has a valid uid/passwd + pair in the above pwd_table. +
    + or
    + require user smith jones
    +
    • Limit access to users who have a valid uid/passwd pair in the + above pwd_table *and* whose uid is 'smith' or 'jones'. Do note that + the uid's are separated by 'spaces' for historic (NCSA) reasons. + So allowing uids with spaces might cause problems. +
    + require group has_paid
    +
    • Optionally also ensure that the uid has the value 'has_paid' in + the group field in the group table. +
    + <limit>
    +
    +
    + + +

    Compile Time Options

    + +
    +
    +#define ONLY_ONCE 1 +
    + If the mSQL table containing the uid/passwd combination does + not have the uid field as a primary key, it is possible for the + uid to occur more than once in the table with possibly different + passwords. When this module is compiled with the ONLY_ONCE + directive set, access is denied if the uid occurs more than once in the + uid/passwd table. If you choose not to set it, the software takes + the first pair returned and ignores any further pairs. The SQL + statement used for this is
    +

    "select password form pwd_table where user='UID'"

    + this might lead to unpredictable results. For this reason as well + as for performance reasons you are strongly advised to make the + uid field a primary key. Use at your own peril :-) +

    + +
    +#define KEEP_MSQL_CONNECTION_OPEN +
    + Normally the (TCP/IP) connection with the database is opened and + closed for each SQL query. When the Apache web-server and the database + are on the same machine, and /dev/msql is used this does not + cause a serious overhead. However when your platform does not + support this (see the mSQL documentation) or when the web server + and the database are on different machines the overhead can be + considerable. When the above directive is set defined the server leaves + the connection open, i.e. no call to msqlClose(). + If an error occurs an attempt is made to reopen the connection for + the next http request. +

    + This has a number of very serious drawbacks +

    • It costs 2 already rare file-descriptors for each child. +
    • It costs msql-connections, typically one per child. The (compiled in) + number of connections mSQL can handle is low, typically 6 or 12. + which might prohibit access to the mSQL database for later + processes. +
    • When a child dies, it might not free that connection properly + or quick enough. +
    • When errors start to occur, connection/file-descriptor resources + might become exhausted very quickly. +
    +

    + In short, use this at your own peril and only in a highly controlled and + monitored environment. +

    + +
    + +#define BACKWARD_VITEK
    +#define VITEK_uid_name "user"
    +#define VITEK_gid_name "passwd" +
    + A second mSQL auth module for Apache has also been developed by Vivek Khera + <khera@kciLink.com> + and was subsequently distributed with some early versions of Apache. It + can be obtained from + ftp://ftp.kcilink.com/pub/mod_auth_msql.c*. + Older 'vitek' versions had the field/table names compiled in. Newer + versions, v.1.11 have more access.conf configuration + options. However these where chosen not to be in line the 'ewse' + version of this module. Also, the 'vitek' module does not give group + control or 'empty' password control. +

    + To get things slightly more in line this version (0.9) should + be backward compatible with the 'vitek' module by: +

    • Adding support for the Auth_MSQL_EncryptedPasswords on/off functionality +
    • Adding support for the different spelling of the 4 configuration + tokens for user-table-name, user/password-field-name and dbase-name. +
    • Setting some field names to a default which used to be hard + coded in in older 'vitek' modules. +
    +

    + If this troubles you, remove the 'BACKWARD_VITEK' define. +

    + +
    + +#define MAX_FIELD_LEN (64)
    +#define MAX_QUERY_LEN (32+24+MAX_FIELD_LEN*2+3*MSQL_FIELD_NAME_LEN+1*MSQL_TABLE_NAME_LEN)
    +
    + In order to avoid using the very large HUGE_STRING_LENGTH, the above two compile + time directives are supplies. The MAX_FIELD_LEN contains the maximum number of + characters in your user, password and group fields. The maximum query length is derived + from those values. +

    + We only do the following two queries: +

    • For the user/passwd combination +

      "select PWDFIELD from PWDTABLE where USERFIELD='UID'"
      +

    • Optionally for the user/group combination: +

      "select GROUPFIELD from GROUPTABLE where USERFIELD='UID' and GROUPFIELD='GID'"
      +

    +

    + This leads to the above limit for the query string. We are ignoring escaping a wee bit here + assuming not more than 24 escapes.) +

    +
    + + +

    Revision History

    + +This version: 23 Nov 1995, 24 Feb 1996, 16 May 1996. + +
    + +
    Version 0.0
    +
    First release +
    +
    Version 0.1
    +
    Update to Apache 1.00 +
    +
    Version 0.2
    +
    Added lines which got missing God knows when + and which did the valid-user authentication no good at all ! +
    +
    Version 0.3
    +
    Added 'Auth_MSQL_nopasswd' option +
    +
    Version 0.4
    +
    Cleaned out the error messages mess. +
    +
    Version 0.6
    +
    Inconsistency with gid/grp in comment/token/source + Make sure you really use 'Auth_MSQLgrp_field' + as indicated above. +
    +
    Version 0.7
    +
    *host to host fixed. Credits + go to Rob Stout, <stout@lava.et.tudelft.nl> for + spotting this one. +
    +
    Version 0.8
    +
    Authoritative directive added. See above. +
    +
    Version 0.9
    +
    palloc return code check(s), should be + backward compatible with 1.11 version of Vivek Khera + <khera@kciLink.com> msql + module, fixed broken err msg in group control, changed + command table messages to make more sense when displayed + in that new module management tool. Added + Auth_MSQL_EncryptedPasswords on/off functionality. + msqlClose() statements added upon error. Support for + persistent connections with the mSQL database (riscy). + Escaping of ' and \. Replaced some + MAX_STRING_LENGTH claims. +
    +
    + + +

    Contact/person to blame

    + +This module was written for the +European Wide Service Exchange by +<Dirk.vanGulik@jrc.it>. +Feel free to contact me if you have any problems, ice-creams or bugs. This +documentation, courtesy of Nick Himba, +<himba@cs.utwente.nl>. +

    + + +


    Sourcecode

    + +The source code can be found at +http://www.apache.org. A snapshot of a development version +usually resides at +http://me-www.jrc.it/~dirkx/mod_auth_msql.c. Please make sure +that you always quote the version you use when filing a bug report. +

    +Furthermore a test/demonstration suite (which assumes that you have +both mSQL and Apache compiled and installed) is available at the contrib +section of +ftp://ftp.apache.org/apache/dist/contrib or + +http://me-www.jrc.it/~dirkx/apache-msql-demo.tar.gz and +its +README file. + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_browser.html b/APACHE_1_2_X/htdocs/manual/mod/mod_browser.html new file mode 100644 index 00000000000..551c38c0faf --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_browser.html @@ -0,0 +1,87 @@ + + + +Apache module mod_browser + + + + + +

    Apache module mod_browser

    + +This module is contained in the mod_browser.c file, and +is compiled in by default with Apache 1.2 and above. It provides for +setting environment variables based on the browser. + +

    Summary

    + +

    This module allows you to set environment variables based on the name of +the browser accessing your document, based on the User-Agent +header field. This is especially useful when combined with a conditional +HTML language such as XSSI or PHP, and +can provide for simple browser-based negotiation of HTML features.

    + +

    Directives

    + + +
    + +

    BrowserMatch

    +Syntax: BrowserMatch regex attr1 attr2...
    +Context: server config
    +Status: base
    +Module: mod_browser
    +Compatibility: Apache 1.2 and above

    + +The BrowserMatch directive defines environment variables based on the +User-Agent +header. The first argument should be a POSIX.2 extended regular +expression (similar to an egrep-style regex). The rest of the arguments +give names of variables to set. These take the form of either +"varname", "!varname" or +"varname=value". In the first form, the value will be set +to "1". The second will remove the given variable if already defined, +and the third will set the variable to the value given by value. If a User-Agent +string matches more than one entry, they will +be merged. Entries are processed in the order they appear, and later +entries can override earlier ones. + +

    For example:

    +
    +    BrowserMatch ^Mozilla forms jpeg=yes browser=netscape
    +    BrowserMatch "^Mozilla/[2-3]" tables agif frames javascript
    +    BrowserMatch MSIE !javascript
    +
    + +

    BrowserMatchNoCase

    +Syntax: BrowserMatchNoCase regex attr1 attr2...
    +Context: server config
    +Status: base
    +Module: mod_browser
    +Compatibility: Apache 1.2 and above + +

    The BrowserMatchNoCase directive is semantically identical to + the BrowserMatch + directive. However, it provides for case-insensitive matching. For + example:

    +
    +    BrowserMatchNoCase mac platform=macintosh
    +    BrowserMatchNoCase win platform=windows
    +
    + + +

    + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_cern_meta.html b/APACHE_1_2_X/htdocs/manual/mod/mod_cern_meta.html new file mode 100644 index 00000000000..98a7410f401 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_cern_meta.html @@ -0,0 +1,81 @@ + + + +Module mod_cern_meta + + + + + +

    Apache module mod_cern_meta

    + +This module is contained in the mod_cern_meta.c file, and +is not compiled in by default. It provides for CERN httpd metafile +semantics. It is only available in Apache 1.1 and later. + +

    Summary

    + +Emulate the CERN HTTPD Meta file semantics. Meta files are HTTP +headers that can be output in addition to the normal range of headers +for each file accessed. They appear rather like the Apache +.asis files, and are able to provide a crude way of influencing +the Expires: header, as well as providing other curiosities. +There are many ways to manage meta information, this one was +chosen because there is already a large number of CERN users +who can exploit this module. + +

    More information on the +CERN metafile semantics is available. + +

    Directives

    + + +
    + +

    MetaDir

    +Syntax: MetaDir directory name
    +Default: MetaDir .web
    +Context: server config
    +Status: Base
    +Module: mod_cern_meta
    +Compatibility: MetaDir is only available in Apache 1.1 +and later.

    + +Specifies the name of the directory in which Apache can find +meta information files. The directory is usually a 'hidden' +subdirectory of the directory that contains the file being +accessed. Set to "." to look in the same directory as the +file. + +

    MetaSuffix

    +Syntax: MetaSuffix suffix
    +Default: MetaSuffix .meta
    +Context: server config
    +Status: Base
    +Module: mod_cern_meta
    +Compatibility: MetaSuffix is only available in Apache 1.1 +and later.

    + +Specifies the file name suffix for the file containing the +meta information. For example, the default values for the two +directives will cause a request to +DOCUMENT_ROOT/somedir/index.html to look in +DOCUMENT_ROOT/somedir/.web/index.html.meta and will use +its contents to generate additional MIME header information. + +

    + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_cgi.html b/APACHE_1_2_X/htdocs/manual/mod/mod_cgi.html new file mode 100644 index 00000000000..fc06cf5c27b --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_cgi.html @@ -0,0 +1,174 @@ + + + +Apache module mod_cgi + + + + + + +

    Module mod_cgi

    + +This module is contained in the mod_cgi.c file, and +is compiled in by default. It provides for execution of CGI scripts. +Any file with mime type application/x-httpd-cgi will be +processed by this module. + + + +

    Summary

    +Any file that has the mime type application/x-httpd-cgi +or handler cgi-script (Apache 1.1 or later) +will be treated as a CGI script, and run by the server, with its output +being returned to the client. Files acquire this type either by +having a name ending in an extension defined by the +AddType directive, or by being in +a ScriptAlias directory.

    + +When the server invokes a CGI script, it will add a variable called +DOCUMENT_ROOT to the environment. This variable will contain the +value of the DocumentRoot +configuration variable. + +

    CGI Environment variables

    +The server will set the CGI environment variables as described in the CGI +specification, with the following provisions: +
    +
    REMOTE_HOST +
    This will only be set if the server has not been compiled with +MINIMAL_DNS. +
    REMOTE_IDENT +
    This will only be set if +IdentityCheck is set to on. +
    REMOTE_USER +
    This will only be set if the CGI script is subject to authentication. +
    +

    + +


    + +

    CGI Debugging

    + +Debugging CGI scripts has traditionally been difficult, mainly because +it has +not +been possible to study the output (standard output and error) for +scripts +which are failing to run properly. These directives, included in +Apache 1.2 and later, provide +more detailed logging of errors when they occur. + +
    + +

    CGI Logfile Format

    + +When configured, the CGI error log logs any CGI which does not execute +properly. Each CGI script which fails to operate causes several lines +of information to be logged. The first two lines are always of the +format: + +
    +  %% [time] request-line
    +  %% HTTP-status CGI-script-filename
    +
    + +If the error is that CGI script cannot be run, the log file will +contain +an extra two lines: + +
    +  %%error
    +  error-message
    +
    + +Alternatively, if the error is the result of the script returning +incorrect header information (often due to a bug in the script), the +following information is logged: + +
    +  %request
    +  All HTTP request headers received
    +  POST or PUT entity (if any)
    +  %response
    +  All headers output by the CGI script
    +  %stdout
    +  CGI standard output
    +  %stderr
    +  CGI standard error
    +
    + +(The %stdout and %stderr parts may be missing if the script did not +output +anything on standard output or standard error). + +
    + +

    Directives

    + +

    ScriptLog

    + +Syntax: ScriptLog filename
    +Default: none
    +Context: resource config
    +Status: mod_cgi +

    + +The ScriptLog directive sets the CGI script error logfile. +If no ScriptLog is given, no error log is created. If given, any +CGI errors are logged into the filename given as argument. If this +is a relative file or path it is taken relative to the server root. + +

    This log will be opened as the user the child processes run as, +ie. the user specified in the main User +directive. This means that either the directory the script log is +in needs to be writable by that user or the file needs to be manually +created and set to be writable by that user. If you place the +script log in your main logs directory, do NOT +change the directory permissions to make it writable by the user +the child processes run as.

    + +

    Note that script logging is meant to be a debugging feature when +writing CGI scripts, and is not meant to be activated continuously on +running servers. It is not optimized for speed or efficiency, and may +have security problems if used in a manner other than that for which +it was designed.

    + +

    ScriptLogLength

    + +Syntax: ScriptLogLength size
    +Default: 10385760
    +Context: resource config
    +Status: mod_cgi +

    + +ScriptLogLength can be used to limit the size of the CGI +script logfile. Since the logfile logs a lot of information per CGI +error (all request headers, all script output) it can grow to be a big +file. To prevent problems due to unbounded growth, this directive can +be used to set an maximum file-size for the CGI logfile. If the file +exceeds this size, no more information will be written to it. + +

    ScriptLogBuffer

    + +Syntax: ScriptLogBuffer size
    +Default: 1024
    +Context: resource config
    +Status: mod_cgi +

    + +The size of any PUT or POST entity body that is logged to the file is +limited, to prevent the log file growing too big too quickly if large +bodies are being received. By default, up to 1024 bytes are logged, +but this can be changed with this directive. + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_cookies.html b/APACHE_1_2_X/htdocs/manual/mod/mod_cookies.html new file mode 100644 index 00000000000..fff4d9da2b0 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_cookies.html @@ -0,0 +1,43 @@ + + + +Apache module mod_cookies + + + + + +

    Module mod_cookies

    + +This module is contained in the mod_cookies.c file, and +is not compiled in by default. It provides for Netscape(TM) cookies. +There is no documentation available for this module. + + + +
  • CookieLog +
  • +
    + + +

    CookieLog

    + +Syntax: CookieLog filename
    +Context: server config, virtual host
    +Status: Experimental
    +Module: mod_cookies

    + +The CookieLog directive sets the filename for logging of cookies. +The filename is relative to the ServerRoot. +

    + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_digest.html b/APACHE_1_2_X/htdocs/manual/mod/mod_digest.html new file mode 100644 index 00000000000..346266cbdc9 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_digest.html @@ -0,0 +1,65 @@ + + + +Apache module mod_digest + + + + + +

    Module mod_digest

    + +This module is contained in the mod_digest.c file, and is +not compiled in by default. It is only available in Apache 1.1 and +later. It provides for user authentication using MD5 Digest +Authentication. + + + +
  • AuthDigestFile +
  • +
    + + +

    AuthDigestFile

    +Syntax: AuthDigestFile filename
    +Context: directory, .htaccess
    +Override: AuthConfig
    +Status: Base
    +Module: mod_digest

    + +

    The AuthDigestFile directive sets the name of a textual file containing +the list +of users and encoded passwords for digest authentication. +Filename +is the absolute path to the user file.

    +

    The digest file uses a special format. Files in this format can be +created using the "htdigest" utility found in the support/ subdirectory of +the Apache distribution.

    + +
    + +

    Using Digest Authentication

    + +

    Using MD5 Digest authentication is very simple. Simply set up +authentication normally. However, use "AuthType Digest" and +"AuthDigestFile" instead of the normal "AuthType Basic" and +"AuthUserFile". Everything else should remain the same.

    + +

    MD5 authentication provides a more secure password system, but only +works with supporting browsers. As of this writing (July 1996), the +majority of browsers do not support digest authentication. Therefore, we +do not recommend using this feature on a large Internet site. However, for +personal and intra-net use, where browser users can be controlled, it is +ideal.

    + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_dir.html b/APACHE_1_2_X/htdocs/manual/mod/mod_dir.html new file mode 100644 index 00000000000..aebd31a5bb8 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_dir.html @@ -0,0 +1,367 @@ + + + +Apache module mod_dir + + + + + +

    Module mod_dir

    + +This module is contained in the mod_dir.c file, and +is compiled in by default. It provides for directory indexing. + +

    Summary

    +This module controls the directory indexing. The index of a directory +can come from one of two sources: +
      +
    • A file written by the user, typically called index.html. +The DirectoryIndex directive sets the name +of this file. +
    • Otherwise, a listing generated by the server. The other directives +control the format of this listing. The AddIcon, +AddIconByEncoding and +AddIconByType are used to set a list of +icons to display for various file types; for each file listed, the +first icon listed that matches the file is displayed. +
    + + +

    Directives

    + + +
  • AddAlt +
  • AddAltByEncoding +
  • AddAltByType +
  • AddDescription +
  • AddIcon +
  • AddIconByEncoding +
  • AddIconByType +
  • DefaultIcon +
  • DirectoryIndex +
  • FancyIndexing +
  • HeaderName +
  • IndexIgnore +
  • IndexOptions +
  • ReadmeName +
  • +
    + +

    AddAlt

    + +Syntax: AddAlt string file file...
    +Context: server config, virtual host, directory, .htaccess
    +Override: Indexes
    +Status: Base
    +Module: mod_dir

    + +This sets the alternate text to display for a file, instead of an icon, for +FancyIndexing. File is a file +extension, partial filename, wild-card expression or full filename for files +to describe. String is enclosed in double quotes +("). This alternate text is displayed if the client is +image-incapable or has image loading disabled. + +


    +

    AddAltByEncoding

    + +Syntax: AddAltByEncoding string MIME-encoding + MIME-encoding...
    +Context: server config, virtual host, directory, .htaccess
    +Override: Indexes
    +Status: Base
    +Module: mod_dir

    + +This sets the alternate text to display for a file, instead of an icon, for +FancyIndexing. MIME-encoding is a +valid content-encoding, such as x-compress. +String is enclosed in double quotes +("). This alternate text is displayed if the client is +image-incapable or has image loading disabled. + +


    +

    AddAltByType

    + +Syntax: AddAltByType string MIME-type MIME-type...
    +Context: server config, virtual host, directory, .htaccess
    +Override: Indexes
    +Status: Base
    +Module: mod_dir

    + +This sets the alternate text to display for a file, instead of an icon, for +FancyIndexing. MIME-type is a +valid content-type, such as text/html. +String is enclosed in double quotes +("). This alternate text is displayed if the client is +image-incapable or has image loading disabled. + +


    + +

    AddDescription

    + +Syntax: AddDescription string file file...
    +Context: server config, virtual host, directory, .htaccess
    +Override: Indexes
    +Status: Base
    +Module: mod_dir

    + +This sets the description to display for a file, for +FancyIndexing. File is a file +extension, partial filename, wild-card expression or full filename for files +to describe. String is enclosed in double quotes +("). Example: +

    AddDescription "The planet Mars" /web/pics/mars.gif +


    + +

    AddIcon

    + +Syntax: AddIcon icon name name ...
    +Context: server config, virtual host, directory, .htaccess
    +Override: Indexes
    +Status: Base
    +Module: mod_dir

    + +This sets the icon to display next to a file ending in name for +FancyIndexing. Icon is either a +(%-escaped) relative URL to the icon, or of the format +(alttext,url) where alttext is the text tag given +for an icon for non-graphical browsers.

    + +Name is either ^^DIRECTORY^^ for directories, ^^BLANKICON^^ for +blank lines (to format the list correctly), a file extension, a wildcard +expression, a partial filename or a complete filename. Examples: +

    +AddIcon (IMG,/icons/image.xbm) .gif .jpg .xbm
    +AddIcon /icons/dir.xbm ^^DIRECTORY^^
    +AddIcon /icons/backup.xbm *~ +
    +AddIconByType should be used in preference to +AddIcon, when possible.


    + +

    AddIconByEncoding

    + +Syntax: AddIconByEncoding icon mime-encoding mime-encoding +...
    +Context: server config, virtual host, directory, .htaccess
    +Override: Indexes
    +Status: Base
    +Module: mod_dir

    + +This sets the icon to display next to files with +mime-encoding for FancyIndexing. +Icon is either a (%-escaped) relative URL to the icon, or of the +format (alttext,url) where alttext is the text tag +given for an icon for non-graphical browsers.

    + +Mime-encoding is a wildcard expression matching required the +content-encoding. Examples: +

    +AddIconByEncoding /icons/compress.xbm x-compress +


    + +

    AddIconByType

    + +Syntax: AddIconByType icon mime-type mime-type ...
    +Context: server config, virtual host, directory, .htaccess
    +Override: Indexes
    +Status: Base
    +Module: mod_dir

    + +This sets the icon to display next to files of type mime-type for +FancyIndexing. Icon is either a +(%-escaped) relative URL to the icon, or of the format +(alttext,url) where alttext is the text tag given +for an icon for non-graphical browsers.

    +Mime-type is a wildcard expression matching required the mime types. +Examples: +

    +AddIconByType (IMG,/icons/image.xbm) image/* +


    + +

    DefaultIcon

    + +Syntax: DefaultIcon url
    +Context: server config, virtual host, directory, .htaccess
    +Override: Indexes
    +Status: Base
    +Module: mod_dir

    + +The DefaultIcon directive sets the icon to display for files when no +specific icon is known, for FancyIndexing. +Url is a (%-escaped) relative URL to the icon. Examples: +

    +DefaultIcon /icon/unknown.xbm +


    + +

    DirectoryIndex

    + +Syntax: DirectoryIndex local-url local-url ...
    +Default: DirectoryIndex index.html
    +Context: server config, virtual host, directory, .htaccess
    +Override: Indexes
    +Status: Base
    +Module: mod_dir

    + +The DirectoryIndex directive sets the list of resources to look for, +when the client requests an index of the directory by specifying a / +at the end of the a directory name. Local-url is the +(%-encoded) URL of a document on the server relative to the requested +directory; it is usually the name of a file in the directory. Several +URLs may be given, in which case the server will return the first one +that it finds. If none of the resources exist and the +Indexes option is set, the server will generate its own +listing of the directory. +

    + +Example: +

    +DirectoryIndex index.html +
    +then a request for http://myserver/docs/ would return +http://myserver/docs/index.html if it exists, or would list +the directory if it did not.

    + +Note that the documents do not need to be relative to the directory; +

    +DirectoryIndex index.html index.txt /cgi-bin/index.pl
    +would cause the CGI script /cgi-bin/index.pl to be executed +if neither index.html or index.txt existed in +a directory.


    + +

    FancyIndexing

    + +Syntax: FancyIndexing boolean
    +Context: server config, virtual host, directory, .htaccess
    +Override: Indexes
    +Status: Base
    +Module: mod_dir

    + +The FancyIndexing directive sets the FancyIndexing option for a directory. +Boolean can be on or off. The +IndexOptions directive should be used in +preference.


    + +

    HeaderName

    + +Syntax: HeaderName filename
    +Context: server config, virtual host, directory, .htaccess
    +Override: Indexes
    +Status: Base
    +Module: mod_dir

    + +The HeaderName directive sets the name of the file that will be inserted +at the top of the index listing. Filename is the name of the file +to include, and is taken to be relative to the directory being indexed. +The server first attempts to include filename.html +as an HTML document, otherwise it will include filename as plain +text. Example: +

    HeaderName HEADER
    +when indexing the directory /web, the server will first look for +the HTML file /web/HEADER.html and include it if found, otherwise +it will include the plain text file /web/HEADER, if it exists. + +

    See also ReadmeName.


    + +

    IndexIgnore

    + +Syntax: IndexIgnore file file ...
    +Context: server config, virtual host, directory, .htaccess
    +Override: Indexes
    +Status: Base
    +Module: mod_dir

    + +The IndexIgnore directive adds to the list of files to hide when listing +a directory. File is a file extension, partial filename, +wildcard expression or full filename for files to ignore. Multiple +IndexIgnore directives add to the list, rather than the replacing the list +of ignored files. By default, the list contains `.'. Example: +

    +IndexIgnore README .htaccess *~ +


    + +

    IndexOptions

    + +Syntax: IndexOptions option option ...
    +Context: server config, virtual host, directory, .htaccess
    +Override: Indexes
    +Status: Base
    +Module: mod_dir

    + +The IndexOptions directive specifies the behavior of the directory indexing. +Option can be one of +

    +
    FancyIndexing +
    +This turns on fancy indexing of directories. +
    IconsAreLinks +
    + +This makes the icons part of the anchor for the filename, for +fancy indexing. +
    ScanHTMLTitles +
    +This enables the extraction of the title from HTML documents for fancy +indexing. If the file does not have a description given by +AddDescription then httpd will read the +document for the value of the TITLE tag. This is CPU and disk intensive. +
    SuppressLastModified +
    + +This will suppress the display of the last modification date, in fancy +indexing listings. +
    SuppressSize +
    + +This will suppress the file size in fancy indexing listings. +
    SuppressDescription +
    + +This will suppress the file description in fancy indexing listings. +
    +This default is that no options are enabled. If multiple IndexOptions +could apply to a directory, then the most specific one is taken complete; +the options are not merged. For example: +
    +<Directory /web/docs>
    +IndexOptions FancyIndexing
    +</Directory>
    +<Directory /web/docs/spec>
    +IndexOptions ScanHTMLTitles
    +</Directory> +
    +then only ScanHTMLTitles will be set for the /web/docs/spec +directory.


    + +

    ReadmeName

    + +Syntax: ReadmeName filename
    +Context: server config, virtual host, directory, .htaccess
    +Override: Indexes
    +Status: Base
    +Module: mod_dir

    + +The ReadmeName directive sets the name of the file that will be appended +to the end of the index listing. Filename is the name of the file +to include, and is taken to be relative to the directory being indexed. +The server first attempts to include filename.html +as an HTML document, otherwise it will include filename as plain +text. Example: +

    ReadmeName README
    +when indexing the directory /web, the server will first look for +the HTML file /web/README.html and include it if found, otherwise +it will include the plain text file /web/README, if it exists. + +

    See also HeaderName.

    + + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_dld.html b/APACHE_1_2_X/htdocs/manual/mod/mod_dld.html new file mode 100644 index 00000000000..d07273a283e --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_dld.html @@ -0,0 +1,80 @@ + + + +Apache module mod_dld + + + + + +

    Module mod_dld

    + +This module is contained in the mod_dld.c file, and is not +compiled in by default. It provides for loading of executable code +and modules into the server at start-up time, using the GNU dld library. + +

    Summary

    + +The optional dld module is a proof-of-concept piece of code which +loads other modules into the server as it is configuring itself (the +first time only; for now, rereading the config files cannot affect the +state of loaded modules), using the GNU dynamic linking library, DLD. +It isn't compiled into the server by default, since not everyone has +DLD, but it works when I try it. (Famous last words.)

    + +Note that for some reason, LoadFile /lib/libc.a seems to be +required for just about everything.

    + +Note: that DLD needs to read the symbol table out of the server binary +when starting up; these commands will fail if the server can't find +its own binary when it starts up, or if that binary is stripped.

    + + +

    Directives

    + +
    + + +

    LoadFile

    + +Syntax: LoadFile filename filename ...
    +Context: server config
    +Status: Experimental
    +Module: mod_dld

    + +The LoadFile directive links in the named object files or libraries when +the server is started; this is used to load additional code which +may be required for some module to work. Filename is relative +to ServerRoot.


    + +

    LoadModule

    + +Syntax: LoadModule module filename
    +Context: server config
    +Status: Experimental
    +Module: mod_dld

    + +The LoadModule directive links in the object file or library filename +and adds the module structure named module to the list of active +modules. Module is the name of the external variable of type +module in the file. Example: +

    +LoadModule ai_backcompat_module modules/mod_ai_backcompat.o
    +LoadFile /lib/libc.a +
    +loads the module in the modules subdirectory of the ServerRoot.

    + + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_env.html b/APACHE_1_2_X/htdocs/manual/mod/mod_env.html new file mode 100644 index 00000000000..0ee71931b39 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_env.html @@ -0,0 +1,92 @@ + + + +Apache module mod_env + + + + + +

    Apache module mod_env

    + +This module is contained in the mod_env.c file, and +is not compiled in by default. It provides for +passing environment variables to CGI/SSI scripts. Is is only available +in Apache 1.1 and later. + +

    Summary

    + +This module allows Apache's CGI and SSI environment to inherit +environment variables from the shell which invoked the httpd process. +CERN web-servers are able to do this, so this module is especially +useful to web-admins who wish to migrate from CERN to Apache without +rewriting all their scripts + +

    Directives

    + + +
    + +

    PassEnv

    +Syntax: PassEnv variable variable ...
    +Context: server config, virtual host
    +Status: Base
    +Module: mod_env
    +Compatibility: PassEnv is only available in +Apache 1.1 and later.

    + +Specifies one or more environment variables to pass to CGI scripts +from the server's own environment. Example: +

    +    PassEnv LD_LIBRARY_PATH
    +
    + +
    + +

    SetEnv

    +Syntax: SetEnv variable value
    +Context: server config, virtual host
    +Status: Base
    +Module: mod_env
    +Compatibility: SetEnv is only available in +Apache 1.1 and later.

    + +Sets an environment variable, which is then passed on to CGI +scripts. Example: +

    +    SetEnv SPECIAL_PATH /foo/bin
    +
    + +
    + +

    UnsetEnv

    +Syntax: UnsetEnv variable variable ...
    +Context: server config, virtual host
    +Status: Base
    +Module: mod_env
    +Compatibility: UnsetEnv is only available in +Apache 1.1 and later.

    + +Removes one or more environment variables from those passed on to +CGI scripts. Example: +

    +    UnsetEnv LD_LIBRARY_PATH
    +
    + + + +

    + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_example.html b/APACHE_1_2_X/htdocs/manual/mod/mod_example.html new file mode 100644 index 00000000000..5ac54af3278 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_example.html @@ -0,0 +1,140 @@ + + + + Apache module mod_example + + + + +

    Module mod_example

    +

    + This module is contained in the modules/mod_example.c file, and + is not compiled in by default. It illustrates many of + the aspects of the + Apache 1.2 API + and, when used, demonstrates the manner in which module callbacks are + triggered by the server. +

    +

    Summary

    +

    + The files in the src/modules/example directory under the + Apache distribution directory tree are provided as an example to those + that wish to write modules that use the Apache API. +

    +

    + The main file is mod_example.c, which illustrates all + the different callback mechanisms and call syntaces. By no means does + an add-on module need to include routines for all of the callbacks - + quite the contrary! +

    +

    + The example module is an actual working module. If you link it into + your server, enable the "example-handler" handler for a location, and + then browse to that location, you will see a display of + some of the tracing the example module did as the various callbacks + were made. +

    +

    + To include the example module in your server, follow the steps below: +

    +
      +
    1. Uncomment the "Module example_module" line near the bottom of + the src/Configuration file. If there isn't one, add + it; it should look like this: +
      +     Module example_module        modules/example/mod_example.o
      +    
      +
    2. +
    3. Run the src/Configure script + ("cd src; ./Configure"). This will + build the Makefile for the server itself, and update the + src/modules/Makefile for any additional modules you + have requested from beneath that subdirectory. +
    4. +
    5. Make the server (run "make" in the src + directory). +
    6. +
    +

    + To add another module of your own: +

    +
      +
    1. mkdir src/modules/mymodule +
    2. +
    3. cp src/modules/example/* src/modules/mymodule +
    4. +
    5. Modify the files in the new directory. +
    6. +
    7. Follow steps [1] through [3] above, with appropriate changes. +
    8. +
    +

    + Using the mod_example Module +

    +

    + To activate the example module, include a block similar to the + following in your srm.conf file: +

    +
    +   <Location /example-info>
    +       SetHandler example-handler
    +   </Location>
    +  
    +

    + As an alternative, you can put the following into a + .htaccess + file and then request the file "test.example" from that + location: +

    +
    +   AddHandler example-handler .example
    +  
    +

    + After reloading/restarting your server, you should be able to browse + to this location and see the brief display mentioned earlier. +

    +

    Directives

    +

    +

    +

    +
    +

    + Example +

    +

    + Syntax: Example +
    + Default: None +
    + Context: server config, virtual host, directory, .htaccess +
    + Override: Options +
    + Status: Extension +
    + Module: mod_example +

    +

    + The Example directive activates the example module's content handler + for a particular location or file type. It takes no arguments. If + you browse to an URL to which the example content-handler applies, you + will get a display of the routines within the module and how and in + what order they were called to service the document request. +

    + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_expires.html b/APACHE_1_2_X/htdocs/manual/mod/mod_expires.html new file mode 100644 index 00000000000..3ec53d1156b --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_expires.html @@ -0,0 +1,185 @@ + + + + Apache module mod_expires + + + + +

    Module mod_expires

    +

    + This module is contained in the mod_expires.c file, and + is not compiled in by default. It provides for the + generation of Expires headers according to user-specified + criteria. +

    +

    Summary

    +

    + This module controls the setting of the Expires HTTP + header in server responses. The expiration date can set to be + relative to either the time the source file was last modified, or to + the time of the client access. +

    +

    + The Expires HTTP header is an instruction to the client + about the document's validity and persistence. If cached, the document + may be fetched from the cache rather than from the source until this + time has passed. After that, the cache copy is considered + "expired" and invalid, and a new copy must be obtained from + the source. +

    +

    Directives

    +

    +

    +
  • ExpiresActive +
  • +
  • ExpiresByType +
  • +
  • ExpiresDefault +
  • +
    +
    +

    + ExpiresActive directive +

    + +

    + Syntax: ExpiresActive boolean +
    + Context: server config, virtual host, directory, .htaccess +
    + Override: Indexes +
    + Status: Extension +
    + Module: mod_expires +

    +

    + This directive enables or disables the generation of the + Expires header for the document realm in question. (That + is, if found in an .htaccess file, for instance, it + applies only to documents generated from that directory.) If set to + Off, no Expires header will be + generated for any document in the realm (unless overridden at a lower + level, such as an .htaccess file overriding a server + config file). If set to On, the header will be + added to served documents according to the criteria defined by the + ExpiresByType + and + ExpiresDefault + directives (q.v.). +

    +

    + Note that this directive does not guarantee that an + Expires header will be generated. If the criteria aren't + met, no header will be sent, and the effect will be as though this + directive wasn't even specified. +

    +
    +

    + ExpiresByType directive +

    + +

    + Syntax: ExpiresByType mime-type <code>seconds +
    + Context: server config, virtual host, directory, .htaccess +
    + Override: Indexes +
    + Status: Extension +
    + Module: mod_expires +

    +

    + This directive defines the value of the Expires header + generated for documents of the specified type (e.g., + text/html). The second argument sets the number of + seconds that will be added to a base time to construct the expiration + date. +

    +

    + The base time is either the last modification time of the file, or the + time of the client's access to the document. Which should be used is + specified by the <code> field; + M means that the file's last modification time should + be used as the base time, and A means the client's + access time should be used. +

    +

    + The difference in effect is subtle. If M is used, all current + copies of the document in all caches will expire at the same time, + which can be good for something like a weekly notice that's always + found at the same URL. If A is used, the date of expiration + is different for each client; this can be good for image files that + don't change very often, particularly for a set of related documents + that all refer to the same images (i.e., the images will be + accessed repeatedly within a relatively short timespan). +

    +

    + Example: +

    +

    +

    +   ExpiresActive On                  # enable expirations
    +   ExpiresByType image/gif A2592000  # expire GIF images after a month
    +                                     #  in the client's cache
    +   ExpiresByType text/html M604800   # HTML documents are good for a
    +                                     #  week from the time they were
    +                                     #  changed, period
    +  
    +

    +

    + Note that this directive only has effect if ExpiresActive + On has been specified. It overrides, for the specified MIME + type only, any expiration date set by the + ExpiresDefault + directive. +

    +
    +

    + ExpiresDefault directive +

    + +

    + Syntax: ExpiresDefault <code>seconds +
    + Context: server config, virtual host, directory, .htaccess +
    + Override: Indexes +
    + Status: Extension +
    + Module: mod_expires +

    +

    + This directive sets the default algorithm for calculating the + expiration time for all documents in the affected realm. It can be + overridden on a type-by-type basis by the + ExpiresByType + directive. See the description of that directive for details about + the syntax of the argument. +

    + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_headers.html b/APACHE_1_2_X/htdocs/manual/mod/mod_headers.html new file mode 100644 index 00000000000..aed34f04db9 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_headers.html @@ -0,0 +1,104 @@ + + + +Apache module mod_headers + + + + + +

    Headers Module

    + +The optional headers module allows for the customization of HTTP +response headers. Headers can be merged, replaced or removed. The +directives described in this document are only available if Apache is +compiled with mod_headers.c. + +
    + +

    Directive

    + + +
    + +

    Header

    +Syntax: Header [ set | append | add ] header value
    +Syntax: Header unset header
    +Context: server config, virtual host, access.conf, .htaccess
    +Status: optional
    +Module: mod_header

    + +This directive can replace, merge or remove HTTP response headers. The +action it performs is determined by the first argument. This can be one +of the following values: + +

      +
    • set
      + The response header is set, replacing any previous header with this name + +
    • append
      + The response header is appended to any existing header of the same + name. When a new value is merged onto an existing header it is + separated from the existing header with a comma. This is the HTTP standard + way of giving a header multiple values. + +
    • add
      + The response header is added to the existing set of headers, even if + this header already exists. This can result in two (or more) headers + having the same name. This can lead to unforeseen consequences, and in + general "append" should be used instead. + +
    • unset
      + The response header of this name is removed, if it exists. If there are + multiple headers of the same name, only the first one set will be removed. +
    + +This argument is followed by a header name, which can include the +final colon, but it is not required. Case is ignored. For +add, append and set a value is given as the third argument. If this +value contains spaces, it should be surrounded by double quotes. +For unset, no value should be given. + +

    Order of Processing

    + +The Header directive can occur almost anywhere within the server +configuration. It is valid in the main server config and virtual host +sections, inside <Directory>, <Location> and <Files> +sections, and within .htaccess files. +

    +The Header directives are processed in the following order: +

      +
    1. main server +
    2. virtual host +
    3. <Directory> sections and .htaccess +
    4. <Location> +
    5. <Files> +
    + +Order is important. These two headers have a different effect if reversed: +
    +Header append Author "John P. Doe"
    +Header unset Author
    +
    + +This way round, the Author header is not set. If reversed, the Author +header is set to "John P. Doe". +

    + +The Header directives are processed just before the response is sent +by its handler. These means that some headers that are added just +before the response is sent cannot be unset or overridden. This +includes headers such as "Date" and "Server". +

    + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_imap.html b/APACHE_1_2_X/htdocs/manual/mod/mod_imap.html new file mode 100644 index 00000000000..718f3fb683b --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_imap.html @@ -0,0 +1,284 @@ + + + +Apache module mod_imap + + + + + +

    Module mod_imap

    + +This module is contained in the mod_imap.c file, and is +compiled in by default. It provides for .map files, +replacing the functionality of the imagemap CGI +program. Any directory or document type configured to use the handler +imap-file (using either AddHandler or SetHandler) will be +processed by this module. + +

    Summary

    + +This module is in the default Apache distribution. The following directive will +activate files ending with .map as imagemap files: + +
    AddHandler imap-file map
    + +Note that the following is still supported: + +
    AddType application/x-httpd-imap map
    + +However, we are trying to phase out "magic MIME types" so we are deprecating +this method. + +

    New Features

    +The imagemap module adds some new features that were not +possible with previously distributed imagemap programs.

    + +

      +
    • URL references relative to the Referer: information. +
    • Default <BASE> assignment through a new map directive +base. +
    • No need for imagemap.conf file. +
    • Point references. +
    • Configurable generation of imagemap menus. +
    +

    + +

    Configuration Directives

    + + + +

    + +

    ImapMenu

    +Syntax: ImapMenu {none, formatted, semi-formatted, + unformatted}
    +Context: server config, virtual host, directory, .htaccess
    +Override: Indexes
    +Module: mod_imap.c
    +Compatibility: ImapMenu is only available in Apache +1.1 and later.

    + +The ImapMenu directive determines the action taken if an imagemap file +is called without valid coordinates. +

    +
    none +
    If ImapMenu is + none, no menu is generated, and the default + action is performed. +
    formatted +
    A formatted menu is the simplest menu. Comments + in the imagemap file are ignored. A level one header is + printed, then an hrule, then the links each on a separate line. + The menu has a consistent, plain look close to that of + a directory listing. +
    semiformatted +
    In the semiformatted menu, comments are printed + where they occur in the imagemap file. Blank lines are turned + into HTML breaks. No header or hrule is printed, but otherwise + the menu is the same as a formatted menu. +
    unformatted +
    Comments are printed, blank lines are ignored. Nothing is + printed that does not appear in the imagemap file. All breaks + and headers must be included as comments in the imagemap file. + This gives you the most flexibility over the appearance of your + menus, but requires you to treat your map files as HTML instead + of plaintext. +
    + +

    + +

    ImapDefault

    +Syntax: ImapDefault {error, nocontent, + map, referer, URL}
    +Context: server config, virtual host, directory, .htaccess
    +Override: Indexes
    +Module: mod_imap.c
    +Compatibility: ImapDefault is only available in Apache +1.1 and later.

    + + +The ImapDefault directive sets the default default used in +the imagemap files. It's value is overridden by a default +directive within the imagemap file. If not present, the +default action is nocontent, which means +that a 204 No Content is sent to the client. In this +case, the client should continue to display the original page. + +

    + +

    ImapBase

    +Syntax: ImapBase {map, referer, URL}
    +Context: server config, virtual host, directory, .htaccess
    +Override: Indexes
    +Module: mod_imap.c
    +Compatibility: ImapBase is only available in Apache +1.1 and later.

    + +The ImapBase directive sets the default base used in +the imagemap files. It's value is overridden by a base +directive within the imagemap file. If not present, the +base defaults to http://servername/. + +


    +

    + +

    Imagemap File

    +The lines in the imagemap files can have one of several formats: +
    +directive value [x,y ...]
    +directive value "Menu text" [x,y ...]
    +directive value x,y ... "Menu text"
    +
    +The directive is one of base, default, +poly, circle, rect, or +point. The value is an absolute or relative URL, or one +of the special values listed below. The coordinates are +x,y pairs separated by whitespace. The quoted text is +used as the text of the link if a imagemap menu is generated. Lines +beginning with '#' are comments. + +

    Imagemap File Directives

    +There are six directives allowed in the imagemap file. The directives +can come in any order, but are processed in the order they are found +in the imagemap file. +
    +
    base Directive +
    Has the effect of <BASE href="value">. The + non-absolute URLs of the map-file are taken relative to this value. + The base directive overrides ImapBase as set in a + .htaccess file or in the server configuration files. In the absence + of an ImapBase configuration directive, base defaults to + http://server_name/.
    + base_uri is synonymous with base. Note that + a trailing slash on the URL is significant. +

    +

    default Directive +
    The action taken if the coordinates given do not fit any of the + poly, circle or rect + directives, and there are no point directives. Defaults + to nocontent in the absence of an ImapDefault + configuration setting, causing a status code of 204 No + Content to be returned. The client should keep the same + page displayed. +

    +

    poly Directive +
    Takes three to one-hundred points, and is obeyed if the user selected + coordinates fall within the polygon defined by these points. +

    +

    circle +
    Takes the center coordinates of a circle and a point on the circle. Is + obeyed if the user selected point is with the circle. +

    +

    rect Directive +
    Takes the coordinates of two opposing corners of a rectangle. Obeyed + if the point selected is within this rectangle. +

    +

    point Directive +
    Takes a single point. The point directive closest to the user + selected point is obeyed if no other directives are satisfied. + Note that default will not be followed if a + point directive is present and valid coordinates are + given. +
    + + + +

    Values

    +The values for each of the directives can any of the following: +
    +
    a URL +
    The URL can be relative or absolute URL. Relative URLs can + contain '..' syntax and will be resolved relative to the + base value.
    + base itself will not resolved according to the current + value. A statement base mailto: will work properly, though. +

    +

    map +
    Equivalent to the URL of the imagemap file itself. No + coordinates are sent with this, so a menu will be generated + unless ImapMenu is set to 'none'. +

    +

    menu +
    Synonymous with map. +

    +

    referer +
    Equivalent to the URL of the referring document. + Defaults to http://servername/ if no Referer: + header was present. +

    +

    nocontent +
    Sends a status code of 204 No Content, + telling the client to keep the same page displayed. Valid for + all but base. +

    +

    error +
    Fails with a 500 Server Error. Valid for all but + base, but sort of silly for anything but + default. +
    + +

    Coordinates

    +
    +
    0,0 200,200 +
    A coordinate consists of an x and a y value + separated by a comma. The coordinates are separated from each other + by whitespace. To accommodate the way Lynx handles imagemaps, should a + user select the coordinate 0,0, it is as if + no coordinate had been selected. +
    + +

    Quoted Text

    +
    +
    "Menu Text" +
    After the value or after the coordinates, the line optionally may + contain text within double quotes. This string is used as the + text for the link if a menu is generated:
    + <a href="http://foo.com/">Menu text</a>
    + If no quoted text is present, the name of the link will be used + as the text:
    + <a href="http://foo.com/">http://foo.com</a>
    + It is impossible to escape double quotes within this text. +
    + +
    + +

    Example Mapfile

    +
    +#Comments are printed in a 'formatted' or 'semiformatted' menu.
    +#And can contain html tags. <hr>
    +base referer
    +poly map "Could I have a menu, please?" 0,0 0,10 10,10 10,0
    +rect .. 0,0 77,27 "the directory of the referer"
    +circle http://www.inetnebr.com/lincoln/feedback/ 195,0 305,27
    +rect another_file "in same directory as referer" 306,0 419,27
    +point http://www.zyzzyva.com/ 100,100
    +point http://www.tripod.com/ 200,200
    +rect mailto:nate@tripod.com 100,150 200,0 "Bugs?"
    +
    +

    + +

    Referencing your mapfile

    +
    +<A HREF="/maps/imagmap1.map">
    +<IMG ISMAP SRC="/images/imagemap1.gif">
    +</A> +

    + + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_include.html b/APACHE_1_2_X/htdocs/manual/mod/mod_include.html new file mode 100644 index 00000000000..6f511309989 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_include.html @@ -0,0 +1,385 @@ + + + +Apache module mod_include + + + + + +

    Module mod_include

    + +This module is contained in the mod_include.c file, and +is compiled in by default. It provides for server-parsed html +documents. Several directives beyond the original NCSA definition have been +included in Apache 1.2 - these are flagged below with the phrase +"Apache 1.2 and above". Of particular significance are the new flow +control directives documented at the bottom. + +

    Enabling Server-Side Includes

    + +Any document with handler of "server-parsed" will be parsed by this +module, if the Includes option is set. If documents +containing server-side include directives are given the extension +.shtml, the following directives will make Apache parse them and +assign the resulting document the mime type of text/html: + +
    +AddType text/html .shtml
    +AddHandler server-parsed .shtml
    +
    + +The following directive must be given for the directories containing +the shtml files (typically in a <Directory> section, +but this directive is also valid .htaccess files if AllowOverride +Options is set): + +
    +Options +Includes
    +
    + +Alternatively the XBitHack +directive can be used to parse normal (text/html) files, +based on file permissions.

    + +For backwards compatibility, documents with mime type +text/x-server-parsed-html or +text/x-server-parsed-html3 will also be parsed +(and the resulting output given the mime type text/html). + +

    Basic Elements

    + +The document is parsed as an HTML document, with special commands embedded +as SGML comments. A command has the syntax: + +
    +<!--#element attribute=value attribute=value ... + --> +
    + +The value will often be enclosed in double quotes; many commands only allow +a single attribute-value pair. Note that the comment terminator +(-->) should be preceded by whitespace to ensure that it +isn't considered part of an SSI token. +

    +The allowed elements are:

    + +

    + +
    config +
    +This command controls various aspects of the parsing. The valid attributes +are: +
    +
    errmsg +
    The value is a message that is sent back to the client if an error occurs +whilst parsing the document. +
    sizefmt +
    The value sets the format to be used which displaying the size of a file. +Valid values are bytes for a count in bytes, or +abbrev for a count in Kb or Mb as appropriate. +
    timefmt +
    The value is a string to be used by the strftime(3) library +routine when printing dates. +
    + +
    echo +
    +This command prints one of the include variables, defined below. +If the variable is unset, it is printed as (none). +Any dates printed are subject to the currently configured timefmt. +Attributes: +
    +
    var +
    The value is the name of the variable to print. +
    + +
    exec +
    +The exec command executes a given shell command or CGI script. +The IncludesNOEXEC Option disables this command +completely. The valid attributes are: +
    +
    cgi +
    +The value specifies a (%-encoded) URL relative path to the CGI script. +If the path does not begin with a (/), then it is taken to be relative to +the current document. The document referenced by this path is invoked +as a CGI script, even if the server would not normally recognize it as +such. However, the directory containing the script must be enabled for +CGI scripts (with ScriptAlias +or the ExecCGI Option).

    +The CGI script is given the PATH_INFO and query string (QUERY_STRING) of the +original request from the client; these cannot be specified in the URL path. +The include variables will be available to the script in addition to the +standard CGI environment.

    +If the script returns a Location: header instead of output, then this +will be translated into an HTML anchor.

    +The include virtual element should be used in preference to +exec cgi. +

    cmd +
    The server will execute the given string using /bin/sh. +The include variables are available to the command. +
    + +
    fsize +
    +This command prints the size of the specified file, subject to the +sizefmt format specification. Attributes: +
    +
    file +
    The value is a path relative to the directory containing the current +document being parsed. +
    virtual +
    The value is a (%-encoded) URL-path relative to the current document being +parsed. If it does not begin with a slash (/) then it is taken to be relative +to the current document. +
    + +
    flastmod +
    +This command prints the last modification date of the specified file, +subject to the timefmt format specification. The attributes are +the same as for the fsize command. + +
    include +
    +This command inserts the text of another document or file into the parsed +file. Any included file is subject to the usual access control. If the +directory containing the parsed file has the +Option +IncludesNOEXEC set, and the including the document would cause a program +to be executed, then it will not be included; this prevents the execution of +CGI scripts. Otherwise CGI scripts are invoked as normal using the complete +URL given in the command, including any query string. + +

    + +An attribute defines the location of the document; the inclusion is done for +each attribute given to the include command. The valid attributes are: +

    +
    file +
    The value is a path relative to the directory containing the current +document being parsed. It cannot contain ../, nor can it be an +absolute path. The virtual attribute should always be used +in preference to this one. +
    virtual +
    The value is a (%-encoded) URL relative to the current document being +parsed. The URL cannot contain a scheme or hostname, only a path and +an optional query string. If it does not begin with a slash (/) then it +is taken to be relative to the current document. +
    +A URL is constructed from the attribute, and the output the server +would return if the URL were accessed by the client is included in the parsed +output. Thus included files can be nested. + +
    printenv +
    This prints out a listing of all existing variables and their values. + No attributes. +
    For example: <!--#printenv --> +
    Apache 1.2 and above. + +
    set +
    This sets the value of a variable. Attributes: +
    +
    var +
    The name of the variable to set. +
    value +
    The value to give a variable. +
    +For example: + <!--#set var="category" value="help" --> +
    Apache 1.2 and above. + +
    + +

    Include Variables

    + +In addition to the variables in the standard CGI environment, these are +available for the echo command, for if and +elif, and to any program invoked by the document. + +
    +
    DATE_GMT +
    The current date in Greenwich Mean Time. +
    DATE_LOCAL +
    The current date in the local time zone. +
    DOCUMENT_NAME +
    The filename (excluding directories) of the document requested by the +user. +
    DOCUMENT_URI +
    The (%-decoded) URL path of the document requested by the user. Note that +in the case of nested include files, this is not then URL for the +current document. +
    LAST_MODIFIED +
    The last modification date of the document requested by the user. +
    +

    + +

    Variable Substitution

    +

    Variable substitution is done within quoted strings in most cases + where they may reasonably occur as an argument to an SSI directive. + This includes the + config, + exec, + flastmod, + fsize, + include, and + set + directives, as well as the arguments to conditional operators. + You can insert a literal dollar sign into the string using backslash + quoting: + +

    +    <!--#if expr="$a = \$test" -->
    +
    + +

    If a variable reference needs to be substituted in the middle of a + character sequence that might otherwise be considered a valid + identifier in its own right, it can be disambiguated by enclosing + the reference in braces, à la shell substitution: + +

    +    <!--#set var="Zed" value="${REMOTE_HOST}_${REQUEST_METHOD}" -->
    +
    + +

    This will result in the Zed variable being set to + "X_Y" if REMOTE_HOST is + "X" and REQUEST_METHOD is + "Y". + +

    EXAMPLE: the below example will print "in foo" if the DOCUMENT_URI is +/foo/file.html, "in bar" if it is /bar/file.html and "in neither" +otherwise: +

    +    <!--#if expr="\"$DOCUMENT_URI\" = \"/foo/file.html\"" -->
    +    in foo
    +    <!--#elif expr="\"$DOCUMENT_URI\" = \"/bar/file.html\"" -->
    +    in bar
    +    <!--#else -->
    +    in neither
    +    <!--#endif -->
    +
    + +

    Flow Control Elements

    + +These are available in Apache 1.2 and above. The basic flow control +elements are: + +
    +    <!--#if expr="test_condition" -->
    +    <!--#elif expr="test_condition" -->
    +    <!--#else -->
    +    <!--#endif -->
    +
    + +

    The if element works like an + if statement in a programming language. The test condition + is evaluated and if the result is true, then the text until + the next elif, else. + or endif element is included in the + output stream. + +

    The elif or else + statements are be used the put text into the output stream + if the original test_condition was false. These elements + are optional. + +

    The endif element ends the + if element and is required. + +

    test_condition is one of the following: + +

    + +
    string
    true if string is not empty + +
    string1 = string2
    + string1 != string2 + +
    Compare string1 with string 2. If string2 has the form /string/ + than it is compared as a regular expression. + Regular expressions have the same syntax as those found in the + Unix egrep command. + +
    ( test_condition ) +
    true if test_condition is true +
    ! test_condition +
    true if test_condition is false +
    test_condition1 && test_condition2 +
    true if both test_condition1 and + test_condition2 are true +
    test_condition1 || test_condition2 +
    true if either test_condition1 or + test_condition2 is true +
    + +

    "=" and "!=" bind more tightly than "&&" and + "||". + "!" binds most tightly. Thus, the following are equivalent: + +

    +    <!--#if expr="$a = test1 && $b = test2" -->
    +    <!--#if expr="($a = test1) && ($b = test2)" -->
    +
    + +

    Anything that's not recognized as a variable or an operator is + treated as a string. Strings can also be quoted: 'string'. + Unquoted strings can't contain whitespace (blanks and tabs) + because it is used to separate tokens such as variables. If + multiple strings are found in a row, they are concatenated using + blanks. So, + +

    +     string1    string2  results in string1 string2
    +    'string1    string2' results in string1    string2
    +
    + +
    +

    Directives

    + +
    + + +

    XBitHack

    + +Syntax: XBitHack status
    +Default: XBitHack off
    +Context: server config, virtual host, directory, .htaccess
    +Override: Options
    +Status: Base
    +Module: mod_include

    + +The XBitHack directives controls the parsing of ordinary html documents. +This directive only affects files associated with the MIME type +text/html. +Status can have the following values: +

    +
    off +
    No special treatment of executable files. +
    on +
    Any file that has the user-execute bit set will be treated as a +server-parsed html document. +
    full +
    As for on but also test the group-execute bit. If it +is set, then set the Last-modified date of the returned file to be the +last modified time of the file. If it is not set, then no last-modified date +is sent. Setting this bit allows clients and proxies to cache the result of +the request. +

    Note: you would not want to use this, for example, when you +#include a CGI that produces different output on each hit +(or potentially depends on the hit). +

    +

    + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_info.html b/APACHE_1_2_X/htdocs/manual/mod/mod_info.html new file mode 100644 index 00000000000..dd753499906 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_info.html @@ -0,0 +1,73 @@ + + + +Apache module mod_info + + + + + +

    Module mod_info

    + +This module is contained in the mod_info.c file. It +provides a comprehensive overview of the server configuration +including all installed modules and directives in the configuration +files. This module is not compiled into the +server by default. It is only available in Apache 1.1 and later. To +enable it, add the following line to the server build Configuration +file, and rebuild the server: + +
    +Module info_module   mod_info.o
    +
    + +
    +

    +To configure it, add the following to your access.conf file. + +

    +<Location /server-info>
    +SetHandler server-info
    +</Location>
    +
    + +You may wish to add a +<Limit> +clause inside the +location +directive to limit access to your server configuration information.

    +Once configured, the server information is obtained by accessing +http://your.host.dom/server-info

    +

    + + Note that the configuration files are read by the module at run-time, + and therefore the display may not reflect the running + server's active configuration if the files have been changed since the + server was last reloaded. Also, the configuration files must be + readable by the user as which the server is running (see the + User + directive), or else the directive settings will not be listed. +

    + It should also be noted that if mod_info is compiled into + the server, its handler capability is available in all + configuration files, including per-directory files + (e.g., .htaccess). This may have + security-related ramifications for your site. +

    +
    +
    + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_log_agent.html b/APACHE_1_2_X/htdocs/manual/mod/mod_log_agent.html new file mode 100644 index 00000000000..9e8fa50855c --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_log_agent.html @@ -0,0 +1,61 @@ + + + +Module mod_log_agent + + + + + +

    Module mod_log_agent

    + +This module is contained in the mod_log_agent.c file, and is not +compiled in by default. It provides for logging of the client user agents. + + + +
    + + +

    AgentLog

    + +Syntax: AgentLog file-pipe
    +Default: AgentLog logs/agent_log
    +Context: server config, virtual host
    +Status: Extension
    +Module: mod_log_agent

    + +The AgentLog directive sets the name of the file to which the server will +log the UserAgent header of incoming requests. File-pipe is one +of +

    A filename +
    A filename relative to the ServerRoot. +
    `|' followed by a command +
    A program to receive the agent log information on its standard input. +Note the a new program will not be started for a VirtualHost if it inherits +the AgentLog from the main server. +
    +Security: if a program is used, then it will be +run under the user who started httpd. This will be root if the server +was started by root; be sure that the program is secure.

    + +Security: See the security tips document for +details on why your security could be compromised if the directory +where logfiles are stored is writable by anyone other than the user +that starts the server.

    + +This directive is provided for compatibility with NCSA 1.4.

    + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_log_common.html b/APACHE_1_2_X/htdocs/manual/mod/mod_log_common.html new file mode 100644 index 00000000000..1a85177cbbd --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_log_common.html @@ -0,0 +1,101 @@ + + + +Apache module mod_log_common + + + + + +

    Module mod_log_common

    + +This module is contained in the mod_log_common.c file, +and is compiled in by default. It provides for logging of the requests +made to the server using the Common Logfile Format. This module has +been replaced by mod_log_config in Apache 1.2 + +

    Log file format

    +The log file contains a separate line for each request. A line is composed +of several tokens separated by spaces: +
    +host ident authuser date request status bytes +
    +If a token does not have a value then it is represented by a hyphen (-). +The meanings and values of these tokens are as follows: +
    +
    host +
    The fully-qualified domain name of the client, or its IP number if the +name is not available. +
    ident +
    If IdentityCheck is enabled and the +client machine runs identd, then this is the identity information reported +by the client. +
    authuser +
    If the request was for an password protected document, then this is +the userid used in the request. +
    date +
    The date and time of the request, in the following format: +
    date = [day/month/year:hour:minute:second zone]
    +day = 2*digit
    +month = 3*letter
    +year = 4*digit
    +hour = 2*digit
    +minute = 2*digit
    +second = 2*digit
    +zone = (`+' | `-') 4*digit
    +
    request +
    The request line from the client, enclosed in double quotes +("). +
    status +
    The three digit status code returned to the client. +
    bytes +
    The number of bytes in the object returned to the client, not including +any headers. +
    + + +

    Directives

    + +
    + + +

    TransferLog

    + +Syntax: TransferLog file-pipe
    +Default: TransferLog logs/transfer_log
    +Context: server config, virtual host
    +Status: Base
    +Module: mod_log_common

    + +The TransferLog directive sets the name of the file to which the server will +log the incoming requests. File-pipe is one +of +

    A filename +
    A filename relative to the ServerRoot. +
    `|' followed by a command +
    A program to receive the agent log information on its standard input. +Note the a new program will not be started for a VirtualHost if it inherits +the TransferLog from the main server. +
    +Security: if a program is used, then it will be +run under the user who started httpd. This will be root if the server +was started by root; be sure that the program is secure.

    + +Security: See the security tips document for +details on why your security could be compromised if the directory +where logfiles are stored is writable by anyone other than the user +that starts the server.

    + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_log_config.html b/APACHE_1_2_X/htdocs/manual/mod/mod_log_config.html new file mode 100644 index 00000000000..8ffc86c5cb9 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_log_config.html @@ -0,0 +1,263 @@ + + + +Apache module mod_log_config + + + + + +

    Module mod_log_config

    + +This module is contained in the mod_log_config.c file, +and is compiled in by default in Apache 1.2. mod_log_config replaces +mod_log_common in Apache 1.2. Prior to version 1.2, mod_log_config was +an optional module. It provides for logging of the requests made to +the server, using the Common Log Format or a user-specified format. + +

    Summary

    + +Three directives are provided by this module: TransferLog +to create a log file, LogFormat to set a custom format, +and CustomLog to define a log file and format in one go. +The TransferLog and CustomLog directives can +be used multiple times in each server to cause each request to be +logged to multiple files. +

    + +

    Compatibility notes

    + +
      +
    • This module is based on mod_log_config distributed with +previous Apache releases, now updated to handle multiple logs. +There is now no need to re-configure Apache to use configuration log +formats. + +
    • The module also implements the CookieLog directive, +used to log user-tracking information created by mod_usertrack. The use of +CookieLog is deprecated, and a CustomLog +should be defined to log user-tracking information instead. + +
    + +

    Log File Formats

    + +Unless told otherwise with LogFormat the log files created by +TransferLog will be in standard "Common Log Format" +(CLF). The contents of each line in a CLF file are explained +below. Alternatively, the log file can be customized (and if multiple +log files are used, each can have a different format). Custom formats +are set with LogFormat and CustomLog. + +

    Common Log Format

    + +The Common Log Format (CLF) file contains a separate line for each +request. A line is composed of several tokens separated by spaces: + +
    +host ident authuser date request status bytes +
    +If a token does not have a value then it is represented by a hyphen (-). +The meanings and values of these tokens are as follows: +
    +
    host +
    The fully-qualified domain name of the client, or its IP number if the +name is not available. +
    ident +
    If IdentityCheck is enabled and the +client machine runs identd, then this is the identity information reported +by the client. +
    authuser +
    If the request was for an password protected document, then this is +the userid used in the request. +
    date +
    The date and time of the request, in the following format: +
    date = [day/month/year:hour:minute:second zone]
    +day = 2*digit
    +month = 3*letter
    +year = 4*digit
    +hour = 2*digit
    +minute = 2*digit
    +second = 2*digit
    +zone = (`+' | `-') 4*digit
    +
    request +
    The request line from the client, enclosed in double quotes +("). +
    status +
    The three digit status code returned to the client. +
    bytes +
    The number of bytes in the object returned to the client, not including +any headers. +
    + +

    Custom Log Formats

    + +The format argument to the LogFormat and +CustomLog is a string. This string is logged to the log +file for each request. It can contain literal characters copied into +the log files, and `%' directives which are replaced in the log file +by the values as follows: + +
    +%...b:          Bytes sent, excluding HTTP headers.
    +%...f:          Filename
    +%...{FOOBAR}e:  The contents of the environment variable FOOBAR
    +%...h:          Remote host
    +%...{Foobar}i:  The contents of Foobar: header line(s) in the request
    +                sent to the server.
    +%...l:          Remote logname (from identd, if supplied)
    +%...{Foobar}n:  The contents of note "Foobar" from another module.
    +%...{Foobar}o:  The contents of Foobar: header line(s) in the reply.
    +%...p:          The port the request was served to
    +%...P:          The process ID of the child that serviced the request.
    +%...r:          First line of request
    +%...s:          Status.  For requests that got internally redirected, this
    +                is status of the *original* request --- %...>s for the last.
    +%...t:          Time, in common log format time format
    +%...{format}t:  The time, in the form given by format, which should
    +                be in strftime(3) format.
    +%...T:          The time taken to serve the request, in seconds.
    +%...u:          Remote user (from auth; may be bogus if return status (%s) is 401)
    +%...U:          The URL path requested.
    +%...v:          The name of the server (i.e. which virtual host?)
    +
    + +The `...' can be nothing at all (e.g. "%h %u %r %s %b"), or it can +indicate conditions for inclusion of the item (which will cause it +to be replaced with `-' if the condition is not met). Note that +there is no escaping performed on the strings from %r, %...i and +%...o; some with long memories may remember that I thought this was +a bad idea, once upon a time, and I'm still not comfortable with +it, but it is difficult to see how to `do the right thing' with all +of `%..i', unless we URL-escape everything and break with CLF. + +

    + +The forms of condition are a list of HTTP status codes, which may +or may not be preceded by `!'. Thus, `%400,501{User-agent}i' logs +User-agent: on 400 errors and 501 errors (Bad Request, Not +Implemented) only; `%!200,304,302{Referer}i' logs Referer: on all +requests which did not return some sort of normal status. + +

    + +Note that the common log format is defined by the string "%h %l +%u %t \"%r\" %s %b", which can be used as the basis for +extending for format if desired (e.g. to add extra fields at the end). +NCSA's extended/combined log format would be "%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\"". + +

    Using Multiple Log Files

    + +The TransferLog and CustomLog directives can +be given more than once to log requests to multiple log files. Each +request will be logged to all the log files defined by either of these +directives. + +

    Use with Virtual Hosts

    + +If a <VirtualHost> section does not contain any +TransferLog or CustomLog directives, the +logs defined for the main server will be used. If it does +contain one or more of these directives, requests serviced by +this virtual host will only be logged in the log files defined +within its definition, not in any of the main server's log files. +See the examples below. +

    + +

    Security Considerations

    + +See the security tips document +for details on why your security could be compromised if the directory +where logfiles are stored is writable by anyone other than the user +that starts the server. +

    +

    Directives

    + + +
    + + +

    CookieLog

    + +Syntax: CookieLog filename
    +Context: server config, virtual host
    +Module: mod_cookies
    +Compatibility: Only available in Apache 1.2 and above

    + +The CookieLog directive sets the filename for logging of cookies. +The filename is relative to the ServerRoot. This directive is included +only for compatibility with mod_cookies, and is deprecated. +

    + +

    CustomLog

    +Syntax: CustomLog file-pipe format
    +Context: server config, virtual host
    +Status: Base
    +Module: mod_log_config

    + +The first argument is the filename to log to. This is used +exactly like the argument to TransferLog, that is, +it is either a full path, or relative to the current +server root.

    + +The format argument specifies a format for each line of the log file. +The options available for the format are exactly the same as for +the argument of the LogFormat directive. If the format +includes any spaces (which it will do in almost all cases) it +should be enclosed in double quotes. + +

    LogFormat

    + +Syntax: LogFormat string
    +Default: LogFormat "%h %l %u %t \"%r\" +%s %b"
    +Context: server config, virtual host
    +Status: Base
    +Module: mod_log_config

    + +This sets the format of the logfile. See +Custom Log Formats for details on the format arguments.


    + + +

    TransferLog

    + +Syntax: TransferLog file-pipe
    +Default: none
    +Context: server config, virtual host
    +Status: Base
    +Module: mod_log_config

    + +The TransferLog directive adds a log file in Common Log Format. +File-pipe is one +of +

    A filename +
    A filename relative to the ServerRoot. +
    `|' followed by a command +
    A program to receive the agent log information on its standard input. +Note the a new program will not be started for a VirtualHost if it inherits +the TransferLog from the main server. +
    +Security: if a program is used, then it will be +run under the user who started httpd. This will be root if the server +was started by root; be sure that the program is secure.

    + + + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_log_referer.html b/APACHE_1_2_X/htdocs/manual/mod/mod_log_referer.html new file mode 100644 index 00000000000..8a5146491a6 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_log_referer.html @@ -0,0 +1,88 @@ + + + +Apache module mod_log_referer + + + + + +

    Module mod_log_referer

    + +This module is contained in the mod_log_referer.c file, and is not +compiled in by default. It provides for logging of the documents which +reference documents on the server. + +

    Log file format

    +The log file contains a separate line for each refer. Each line has the +format +
    uri -> document
    +where uri is the (%-escaped) URI for the document that references +the one requested by the client, and document is the (%-decoded) +local URL to the document being referred to. + + +

    Directives

    + +
    + + +

    RefererIgnore

    + +Syntax: RefererIgnore string string ...
    +Context: server config, virtual host
    +Status: Extension
    +Module: mod_log_referer

    + +The RefererIgnore directive adds to the list of strings to ignore in +Referer headers. If any of the strings in the list is contained in +the Referer header, then no referrer information will be logged for the +request. Example: +

    RefererIgnore www.ncsa.uiuc.edu
    +This avoids logging references from www.ncsa.uiuc.edu. +


    + + +

    RefererLog

    + +Syntax: RefererLog file-pipe
    +Default: RefererLog logs/referer_log
    +Context: server config, virtual host
    +Status: Extension
    +Module: mod_log_referer

    + +The RefererLog directive sets the name of the file to which the server will +log the Referer header of incoming requests. File-pipe is one +of +

    A filename +
    A filename relative to the ServerRoot. +
    `|' followed by a command +
    A program to receive the referrer log information on its standard input. +Note the a new program will not be started for a VirtualHost if it inherits +the RefererLog from the main server. +
    +Security: if a program is used, then it will be +run under the user who started httpd. This will be root if the server +was started by root; be sure that the program is secure.

    + +Security: See the security tips document for +details on why your security could be compromised if the directory +where logfiles are stored is writable by anyone other than the user +that starts the server.

    + +This directive is provided for compatibility with NCSA 1.4.

    + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_mime.html b/APACHE_1_2_X/htdocs/manual/mod/mod_mime.html new file mode 100644 index 00000000000..fa150c88e05 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_mime.html @@ -0,0 +1,212 @@ + + + +Apache module mod_mime + + + + + +

    Module mod_mime

    + +This module is contained in the mod_mime.c file, and is +compiled in by default. It provides for determining the types of files +from the filename. + +

    Summary

    +This module is used to determine the mime types of documents. Some mime +types indicate special processing to be performed by the server, otherwise +the type is returned to the client so that the browser can deal with +the document appropriately.

    + +The filename of a document is treated as being composed of a basename followed +by some extensions, in the following order: +

    base.type.language.enc
    +The type extension sets the type of the document; types are defined +in the TypesConfig file and by the +AddType directive. The language extension +sets the language of the document, as defined by the +AddLanguage directive. Finally, the +enc directive sets the encoding of the document, as defined by +the AddEncoding directive. + + +

    Directives

    + +
    + + +

    AddEncoding

    + +Syntax: AddEncoding mime-enc extension extension...
    +Context: server config, virtual host, directory, .htaccess
    +Override: FileInfo
    +Status: Base
    +Module: mod_mime

    + +The AddEncoding directive adds to the list of filename extensions which +filenames may end in for the specified encoding type. Mime-enc +is the mime encoding to use for documents ending in extension. +Example: +

    +AddEncoding x-gzip gz
    +AddEncoding x-compress Z +
    + +This will cause files ending in .gz to be marked as encoded using the x-gzip +encoding, and .Z files to be marked as encoded with x-compress.


    + +

    AddHandler

    + +Syntax: <AddHandler handler-name extension>
    +Context: server config, virtual host, directory, .htaccess
    +Status: Base
    +Module: mod_mime
    +Compatibility: AddHandler is only available in Apache +1.1 and later

    + +

    AddHandler maps the filename extension extension to the +handler +handler-name. For example, to activate CGI scripts +with the file extension ".cgi", you might use: +

    +    AddHandler cgi-script cgi
    +
    + +

    Once that has been put into your srm.conf or httpd.conf file, any +file ending with ".cgi" will be treated as a CGI +program.

    +
    + +

    AddLanguage

    + +Syntax: AddLanguage mime-lang extension extension...
    +Context: server config, virtual host, directory, .htaccess
    +Override: FileInfo
    +Status: Base
    +Module: mod_mime

    + +The AddLanguage directive adds to the list of filename extensions which +filenames may end in for the specified content language. Mime-lang +is the mime language of files with names ending extension, +after any content encoding extensions have been removed. Example: +

    +AddEncoding x-compress Z
    +AddLanguage en .en
    +AddLanguage fr .fr
    +
    + +Then the document xxxx.en.Z will be treated as being a compressed +English document. Although the content language is reported to the client, +the browser is unlikely to use this information. The AddLanguage directive +is more useful for content negotiation, where the server returns one +from several documents based on the client's language preference.


    + +

    AddType

    + +Syntax: AddType mime-type extension extension...
    +Context: server config, virtual host, directory, .htaccess
    +Override: FileInfo
    +Status: Base
    +Module: mod_mime

    + +The AddType directive adds to the list of filename extensions which +filenames may end in for the specified content type. Mime-enc +is the mime type to use for documents ending in extension. +after content-encoding and language extensions have been removed. Example: +

    +AddType image/gif GIF +
    +It is recommended that new mime types be added using the AddType directive +rather than changing the TypesConfig file.

    +Note that, unlike the NCSA httpd, this directive cannot be used to set the +type of particular files.


    + +

    ForceType

    + +Syntax: <ForceType media type>
    +Context: directory, .htaccess
    +Status: Base
    +Module: mod_mime
    +Compatibility: ForceType is only available in Apache +1.1 and later.

    + +

    When placed into an .htaccess file or a +<Directory> or <Location> section, +this directive forces all matching files to be served +as the content type given by media type. For example, if you +had a directory full of GIF files, but did not want to label them all with +".gif", you might want to use: +

    +    ForceType image/gif
    +
    +

    Note that this will override any filename extensions that might +media type.

    + +

    SetHandler

    + +Syntax: <SetHandler handler-name>
    +Context: directory, .htaccess
    +Status: Base
    +Module: mod_mime
    +Compatibility: SetHandler is only available in Apache +1.1 and later.

    + +

    When placed into an .htaccess file or a +<Directory> or <Location> section, +this directive forces all matching files to be parsed through the +handler +given by handler-name. For example, if you had a +directory you wanted to be parsed entirely as imagemap rule files, +regardless of extension, you might put the following into an +.htaccess file in that directory: +

    +    SetHandler imap-file
    +
    + +

    Another example: if you wanted to have the server display a status +report whenever a URL of http://servername/status was +called, you might put the following into access.conf: +

    +    <Location /status>
    +    SetHandler server-status
    +    </Location>
    +
    +
    + +

    TypesConfig

    + +Syntax: TypesConfig filename
    +Default: TypesConfig conf/mime.types
    +Context: server config
    +Status: Base
    +Module: mod_mime

    + +The TypesConfig directive sets the location of the mime types configuration +file. Filename is relative to the +ServerRoot. This file sets the default list of +mappings from filename extensions to content types; changing this file is not +recommended. Use the AddType directive instead. The +file contains lines in the format of the arguments to an AddType command: +

    mime-type extension extension ...
    +The extensions are lower-cased. Blank lines, and lines beginning with a hash +character (`#') are ignored.

    + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_negotiation.html b/APACHE_1_2_X/htdocs/manual/mod/mod_negotiation.html new file mode 100644 index 00000000000..141b74bfe63 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_negotiation.html @@ -0,0 +1,147 @@ + + + +Apache module mod_negotiation + + + + + +

    Module mod_negotiation

    + +This module is contained in the mod_negotiation.c file, +and is compiled in by default. It provides for content negotiation. + +

    Summary

    +Content negotiation, or more accurately content selection, is the +selection of the document that best matches the clients +capabilities, from one of several available documents. +There are two implementations of this. +
      +
    • A type map (a file with the handler type-map) +which explicitly lists the files containing the variants. +
    • A MultiViews search (enabled by the MultiViews +Option, where the server does an implicit +filename pattern match, and choose from amongst the results. +
    + +

    Type maps

    +A type map has the same format as RFC822 mail headers. It contains document +descriptions separated by blank lines, with lines beginning with a hash +character ('#') treated as comments. A document description consists of +several header records; records may be continued on multiple lines if the +continuation lines start with spaces. The leading space will be deleted +and the lines concatenated. A header record consists of a keyword +name, which always ends in a colon, followed by a value. Whitespace is allowed +between the header name and value, and between the tokens of value. + +The headers allowed are: + +
    +
    Content-Encoding: +
    The encoding of the file. Currently only two encodings are recognized +by http; x-compress for compressed files, and x-gzip +for gzipped files. +
    Content-Language: +
    The language of the variant, as an Internet standard language code, such +as en. +
    Content-Length: +
    The length of the file, in bytes. If this header is not present, then +the actual length of the file is used. +
    Content-Type: +
    The MIME media type of the document, with optional parameters. +parameters are separated from the media type and from one another by +semi-colons. Parameter syntax is name=value; allowed parameters are: +
    +
    level +
    the value is an integer, which specifies the version of the media type. +For text/html this defaults to 2, otherwise 0. +
    qs +
    the value is a floating-point number with value between 0. and 1. +It indications the 'quality' of this variant. +
    +Example: +
    Content-Type: image/jpeg; qs=0.8
    +
    URI: +
    The path to the file containing this variant, relative to the map file. +
    + +

    MultiViews

    +A MultiViews search is enabled by the MultiViews +Option. +If the server receives a request for /some/dir/foo and +/some/dir/foo does not exist, then the server reads the +directory looking for all files named foo.*, and effectively +fakes up a type map which names all those files, assigning them the same media +types and content-encodings it would have if the client had asked for +one of them by name. It then chooses the best match to the client's +requirements, and returns that document.

    + + + +

    Directives

    + +
    + + +

    CacheNegotiatedDocs

    +Syntax: CacheNegotiatedDocs
    +Context: server config
    +Status: Base
    +Module: mod_negotiation
    +Compatibility: CacheNegotiatedDocs is only available +in Apache 1.1 and later.

    + +

    If set, this directive allows content-negotiated documents to be +cached by proxy servers. This could mean that clients behind those +proxys could retrieve versions of the documents that are not the best +match for their abilities, but it will make caching more +efficient. +

    + +This directive only applies to requests which come from HTTP/1.0 browsers. +HTTP/1.1 provides much better control over the caching of negotiated +documents, and this directive has no effect in responses to +HTTP/1.1 requests. + + + +

    LanguagePriority

    + +Syntax: LanguagePriority mime-lang mime-lang...
    +Context: server config, virtual host, directory, .htaccess
    +Override: FileInfo
    +Status: Base
    +Module: mod_negotiation

    + +The LanguagePriority sets the precedence of language variants for the case +where the client does not express a preference, when handling a +MultiViews request. The list of mime-lang are in order of decreasing +preference. Example: + +

    LanguagePriority en fr de
    + +For a request for foo.html, where foo.html.fr +and foo.html.de both existed, but the browser did not express +a language preference, then foo.html.fr would be returned.

    + +

    + +Note that this directive only has an effect if a 'best' language +cannot be determined by other any other means. Correctly implemented +HTTP/1.1 requests will mean this directive has no effect. + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_proxy.html b/APACHE_1_2_X/htdocs/manual/mod/mod_proxy.html new file mode 100644 index 00000000000..e0aef688460 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_proxy.html @@ -0,0 +1,366 @@ + + + +Apache module mod_proxy + + + + + +

    Apache module mod_proxy

    + +This module is contained in the mod_proxy.c file for Apache 1.1.x, +or the modules/proxy subdirectory for Apache 1.2, and +is not compiled in by default. It provides for an HTTP 1.0 caching proxy +server. It is only available in Apache 1.1 and later. Common configuration +questions are addressed here. + +

    Note:

    +

    This module was experimental in Apache 1.1.x. As of Apache 1.2, mod_proxy +stability is greatly improved.

    + +

    Summary

    + +This module implements a proxy/cache for Apache. It implements +proxying capability for +FTP, +CONNECT (for SSL), +HTTP/0.9, and +HTTP/1.0. +The module can be configured to connect to other proxy modules for these +and other protocols. + +

    Directives

    + + +
    + +

    ProxyRequests

    +Syntax: ProxyRequests on/off
    +Default: ProxyRequests Off
    +Context: server config
    +Status: Base
    +Module: mod_proxy
    +Compatibility: ProxyRequest is only available in +Apache 1.1 and later.

    + +This allows or prevents Apache from functioning as a proxy +server. Setting ProxyRequests to 'off' does not disable use of the ProxyPass directive. + +

    ProxyRemote

    +Syntax: ProxyRemote <match> <remote-server>
    +Context: server config
    +Status: Base
    +Module: mod_proxy
    +Compatibility: ProxyRemote is only available in +Apache 1.1 and later.

    + +This defines remote proxies to this proxy. <match> is either the +name of a URL-scheme that the remote server supports, or a partial URL +for which the remote server should be used, or '*' to indicate the +server should be contacted for all requests. <remote-server> is a +partial URL for the remote server. Syntax: + +

    +  <remote-server> = <protocol>://<hostname>[:port]
    +
    + +<protocol> is the protocol that should be used to communicate +with the remote server; only "http" is supported by this module. + +Example: +
    +  ProxyRemote http://goodguys.com/ http://mirrorguys.com:8000
    +  ProxyRemote * http://cleversite.com
    +  ProxyRemote ftp http://ftpproxy.mydomain.com:8080
    +
    + +In the last example, the proxy will forward FTP requests, encapsulated +as yet another HTTP proxy request, to another proxy which can handle +them. + +

    ProxyPass

    +Syntax: ProxyPass <path> <url>
    +Context: server config
    +Status: Base
    +Module: mod_proxy
    +Compatibility: ProxyPass is only available in +Apache 1.1 and later.

    + +This directive allows remote servers to be mapped into the space of the local +server; the local server does not act as a proxy in the conventional sense, +but appears to be a mirror of the remote server. <path> is the name of +a local virtual path; <url> is a partial URL for the remote server. + +Suppose the local server has address http://wibble.org; then +

    +   ProxyPass /mirror/foo http://foo.com
    +
    +Will cause a local request for the http://wibble.org/mirror/foo/bar to be +internally converted into a proxy request to http://foo.com/bar + +

    ProxyBlock

    +Syntax: ProxyBlock <word/host/domain list>
    +Context: server config
    +Status: Base
    +Module: mod_proxy
    +Compatibility: ProxyBlock is only available in +Apache 1.2 and later.

    + +The ProxyBlock directive specifies a list of words, hosts and/or domains, +separated by spaces. HTTP, HTTPS, and FTP document requests to matched words, +hosts or domains are blocked by the proxy server. The proxy module +will also attempt to determine IP addresses of list items which may be +hostnames during startup, and cache them for match test as well. Example: + +

    +  ProxyBlock joes_garage.com some_host.co.uk rocky.wotsamattau.edu
    +
    + +'rocky.wotsamattau.edu' would also be matched if referenced by IP address.

    + +Note that 'wotsamattau' would also be sufficient to match 'wotsamattau.edu'.

    + +Note also that + +

    +ProxyBlock *
    +
    + +blocks connections to all sites. + +

    CacheRoot

    +Syntax: CacheRoot <directory>
    +Context: server config
    +Status: Base
    +Module: mod_proxy
    +Compatibility: CacheRoot is only available in +Apache 1.1 and later.

    + +Sets the name of the directory to contain cache files; this must be +writable +by the httpd server. + +

    CacheSize

    +Syntax: CacheSize <size>
    +Default: CacheSize 5
    +Context: server config
    +Status: Base
    +Module: mod_proxy
    +Compatibility: CacheSize is only available in +Apache 1.1 and later.

    + +Sets the desired space usage of the cache, in Kb (1024 byte units). Although +usage may grow above this setting, the garbage collection will delete files +until the usage is at or below this setting. + +

    CacheGcInterval

    +Syntax: CacheGcInterval <time>
    +Context: server config
    +Status: Base
    +Module: mod_proxy
    +Compatibility: CacheGcinterval is only available in +Apache 1.1 and later.

    + +Check the cache every <time> hours, and delete files if the space +usage is greater than that set by CacheSize. + +

    CacheMaxExpire

    +Syntax: CacheMaxExpire <time>
    +Default: CacheMaxExpire 24
    +Context: server config
    +Status: Base
    +Module: mod_proxy
    +Compatibility: CacheMaxExpire is only available in +Apache 1.1 and later.

    + +Cachable HTTP documents will be retained for at most <time> hours without +checking the origin server. Thus documents can be at most <time> +hours out of date. This restriction is enforced even if an expiry date +was supplied with the document. + +

    CacheLastModifiedFactor

    +Syntax: CacheLastModifiedFactor <factor>
    +Default: CacheLastModifiedFactor 0.1
    +Context: server config
    +Status: Base
    +Module: mod_proxy
    +Compatibility: CacheLastModifiedFactor is only available in +Apache 1.1 and later.

    + +If the origin HTTP server did not supply an expiry date for the +document, then estimate one using the formula +

    +  expiry-period = time-since-last-modification * <factor>
    +
    +For example, if the document was last modified 10 hours ago, and +<factor> is 0.1, then the expiry period will be set to 10*0.1 = 1 hour. + +

    If the expiry-period would be longer than that set by CacheMaxExpire, +then the latter takes precedence. + +

    CacheDirLevels

    +Syntax: CacheDirLevels <levels>
    +Default: CacheDirLevels 3
    +Context: server config
    +Status: Base
    +Module: mod_proxy
    +Compatibility: CacheDirLevels is only available in +Apache 1.1 and later.

    + +CacheDirLevels sets the number of levels of subdirectories in the cache. +Cached data will be saved this many directory levels below CacheRoot. + +

    CacheDirLength

    +Syntax: CacheDirLength <length>
    +Default: CacheDirLength 1
    +Context: server config
    +Status: Base
    +Module: mod_proxy
    +Compatibility: CacheDirLength is only available in +Apache 1.1 and later.

    + +CacheDirLength sets the number of characters in proxy cache subdirectory names. + +

    CacheDefaultExpire

    +Syntax: CacheDefaultExpire <time>
    +Default: CacheDefaultExpire 1
    +Context: server config
    +Status: Base
    +Module: mod_proxy
    +Compatibility: CacheDefaultExpire is only available in +Apache 1.1 and later.

    + +If the document is fetched via a protocol that does not support expiry times, +then use <time> hours as the expiry time. +CacheMaxExpire does not +override. + +

    NoCache

    +Syntax: NoCache <word/host/domain list>
    +Context: server config
    +Status: Base
    +Module: mod_proxy
    +Compatibility: NoCache is only available in +Apache 1.1 and later.

    + +The NoCache directive specifies a list of words, hosts and/or domains, separated +by spaces. HTTP and non-passworded FTP documents from matched words, hosts or +domains are not cached by the proxy server. The proxy module will +also attempt to determine IP addresses of list items which may be hostnames +during startup, and cache them for match test as well. Example: + +

    +  NoCache joes_garage.com some_host.co.uk bullwinkle.wotsamattau.edu
    +
    + +'bullwinkle.wotsamattau.edu' would also be matched if referenced by IP +address.

    + +Note that 'wotsamattau' would also be sufficient to match 'wotsamattau.edu'.

    + +Note also that + +

    +NoCache *
    +
    + +disables caching completely.

    + +


    + +

    Common configuration topics

    + + + +

    Controlling access to your proxy

    + +You can control who can access your proxy via the normal <Directory> +control block using the following example:

    + +

    +<Directory proxy:*>
    +<Limit GET PUT POST DELETE CONNECT OPTIONS>
    +order deny,allow
    +deny from [machines you'd like *not* to allow by IP address or name]
    +allow from [machines you'd like to allow by IP address or name]
    +</Limit>
    +</Directory>
    +

    + +A <Files> block will also work, and is the only method known to work +for all possible URLs in Apache versions earlier than 1.2b10.

    + +

    Using Netscape hostname shortcuts

    + +There is an optional patch to the proxy module to allow Netscape-like +hostname shortcuts to be used. It's available + +here.

    + +

    Why doesn't file type xxx download via FTP?

    + +You probably don't have that particular file type defined as +application/octet-stream in your proxy's mime.types configuration +file. A useful line can be

    + +

    +application/octet-stream        bin dms lha lzh exe class tgz taz
    +
    + +

    Why does Apache start more slowly when using the + proxy module?

    + +If you're using the ProxyBlock or NoCache +directives, hostnames' IP addresses are looked up and cached during +startup for later match test. This may take a few seconds (or more) +depending on the speed with which the hostname lookups occur.

    + +

    Can I use the Apache proxy module with my SOCKS proxy?

    + +Yes. Just build Apache with the rule SOCKS4=yes in your +Configuration file, and follow the instructions there. SOCKS5 +capability can be added in a similar way (there's no SOCKS5 +rule yet), so use the EXTRA_LFLAGS definition, or build Apache +normally and run it with the runsocks wrapper provided with SOCKS5, +if your OS supports dynamically linked libraries.

    + +Some users have reported problems when using SOCKS version 4.2 on Solaris. +The problem was solved by upgrading to SOCKS 4.3.

    + +Remember that you'll also have to grant access to your Apache proxy machine by +permitting connections on the appropriate ports in your SOCKS daemon's +configuration.

    + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_rewrite.html b/APACHE_1_2_X/htdocs/manual/mod/mod_rewrite.html new file mode 100644 index 00000000000..03eaa5801f7 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_rewrite.html @@ -0,0 +1,1161 @@ + + + + + + +Apache module mod_rewrite + + + + + + +

    Module mod_rewrite (Version 3.0)

    + +This module is contained in the mod_rewrite.c file, with Apache +1.2 and later. It provides a rule-based rewriting engine to rewrite requested +URLs on the fly. mod_rewrite is not compiled into the server by +default. To use mod_rewrite you have to enable the following line +in the server build Configuration file: +
    +    Module  rewrite_module   mod_rewrite.o
    +
    + +

    Summary

    + +This module uses a rule-based rewriting engine (based on a +regular-expression parser) to rewrite requested URLs on the fly. + +

    +It supports an unlimited number of additional rule conditions (which can +operate on a lot of variables, including HTTP headers) for granular +matching and external database lookups (either via plain text +tables, DBM hash files or external processes) for advanced URL +substitution. + +

    +It operates on the full URLs (including the PATH_INFO part) both in +per-server context (httpd.conf) and per-dir context (.htaccess) and even +can generate QUERY_STRING parts on result. The rewritten result can lead to internal sub-processing, external request redirection or to internal proxy throughput. + + +

    +The latest version can be found on
    + +http://www.engelschall.com/sw/mod_rewrite/ + +

    +Copyright © 1996,1997 The Apache Group, All rights reserved.
    +Copyright © 1996,1997 Ralf S. Engelschall, All rights reserved. +

    +Written for The Apache Group by +

    + Ralf S. Engelschall
    + rse@engelschall.com
    + www.engelschall.com +
    + + +
    + + +

    +

    Directives

    + + + + +
    + + + +
    + +

    Configuration Directives

    +
    +
    + +

    RewriteEngine

    +Syntax: RewriteEngine {on,off}
    +Default: RewriteEngine off
    +Context: server config, virtual host, per-directory config
    +

    + +The RewriteEngine directive enables or disables the +runtime rewriting engine. If it is set to off this module does +no runtime processing at all. It does not even update the SCRIPT_URx +environment variables. + +

    +Use this directive to disable the module instead of commenting out +all RewriteRule directives! + +

    +


    +

    + +

    RewriteOptions

    +Syntax: RewriteOptions Option ...
    +Default: -None-
    +Context: server config, virtual host, per-directory config
    +

    + +The RewriteOption directive sets some special options for the +current per-server or per-directory configuration. The Option +strings can be one of the following: + +

      +
    • 'inherit'
      + This forces the current configuration to inherit the configuration of the + parent. In per-virtual-server context this means that the maps, + conditions and rules of the main server gets inherited. In per-directory + context this means that conditions and rules of the parent directory's + .htaccess configuration gets inherited. +

      +

    + +

    +


    +

    + +

    RewriteLog

    +Syntax: RewriteLog Filename
    +Default: -None-
    +Context: server config, virtual host
    +

    + +The RewriteLog directive sets the name of the file to which the +server logs any rewriting actions it performs. If the name does not begin +with a slash ('/') then it is assumed to be relative to the +Server Root. The directive should occur only once per server +config. + +

    + + +
    +To disable the logging of rewriting actions it is not recommended +to set Filename +to /dev/null, because although the rewriting engine does +not create output to a logfile it still creates the logfile +output internally. This will slow down the server with no advantage to the +administrator! +To disable logging either remove or comment out the +RewriteLog directive or use RewriteLogLevel 0! +
    + +

    + + +
    +SECURITY: See the Apache Security +Tips document for details on why your security could be compromised if the +directory where logfiles are stored is writable by anyone other than the user +that starts the server. +
    + +

    +Example: +

    +
    +RewriteLog "/usr/local/var/apache/logs/rewrite.log"
    +
    +
    + +

    +


    +

    + +

    RewriteLogLevel

    +Syntax: RewriteLogLevel Level
    +Default: RewriteLogLevel 0
    +Context: server config, virtual host
    +

    + +The RewriteLogLevel directive set the verbosity level of the rewriting +logfile. The default level 0 means no logging, while 9 or more means +that practically all actions are logged. + +

    +To disable the logging of rewriting actions simply set Level to 0. +This disables all rewrite action logs. + +

    + + +
    +Notice: Using a high value for Level will slow down your Apache +server dramatically! Use the rewriting logfile only for debugging or at least +at Level not greater than 2! +
    + + +

    +Example: +

    +
    +RewriteLogLevel 3
    +
    +
    + +

    +


    +

    + +

    RewriteMap

    +Syntax: RewriteMap Mapname {txt,dbm,prg}:Filename
    +Default: not used per default
    +Context: server config, virtual host
    +

    + +The RewriteMap directive defines an external Rewriting Map +which can be used inside rule substitution strings by the mapping-functions +to insert/substitute fields through a key lookup. +

    + +The Mapname is the name of the map and will +be used to specify a mapping-function for the substitution strings of a +rewriting rule via + +

    +${ Mapname : LookupKey +| DefaultValue } +
    + +When such a directive occurs the map Mapname +is consulted and the key LookupKey is looked-up. If the key is +found, the map-function directive is substituted by SubstValue. If +the key is not found then it is substituted by DefaultValue. + +

    +The Filename must be a valid Unix filepath, containing one +of the following formats: + +

      +
    1. Plain Text Format +

      + This is a ASCII file which contains either blank lines, comment lines + (starting with a '#' character) or + +

      + MatchingKey SubstValue +
      + + pairs - one per line. You can create such files either manually, + using your favorite editor, or by using the programs + mapcollect and mapmerge from the support + directory of the mod_rewrite distribution. +

      + To declare such a map prefix, Filename with a txt: + string as in the following example: + +

      + + +
      +#
      +#   map.real-to-user -- maps realnames to usernames
      +#
      +
      +Ralf.S.Engelschall    rse   # Bastard Operator From Hell 
      +Dr.Fred.Klabuster     fred  # Mr. DAU
      +
      + +

      + + +
      +RewriteMap real-to-host txt:/path/to/file/map.real-to-user
      +
      + +

      +

    2. DBM Hashfile Format +

      + This is a binary NDBM format file containing the + same contents as the Plain Text Format files. You can create + such a file with any NDBM tool or with the dbmmanage program + from the support directory of the Apache distribution. +

      + To declare such a map prefix Filename with a dbm: + string. +

      +

    3. Program Format +

      + This is a Unix executable, not a lookup file. To create it you can use + the language of your choice, but the result has to be a run-able Unix + binary (i.e. either object-code or a script with the + magic cookie trick '#!/path/to/interpreter' as the first line). +

      + This program gets started once at startup of the Apache servers and then + communicates with the rewriting engine over its stdin and + stdout file-handles. For each map-function lookup it will + receive the key to lookup as a newline-terminated string on + stdin. It then has to give back the looked-up value as a + newline-terminated string on stdout or the four-character string + ``NULL'' if it fails (i.e. there is no corresponding value + for the given key). A trivial program which will implement a 1:1 map + (i.e. key == value) could be: +

      + + +
      +#!/usr/bin/perl
      +$| = 1;
      +while (<STDIN>) {
      +    # ...here any transformations 
      +    # or lookups should occur...
      +    print $_;
      +}
      +
      +

      + But be very careful:
      +

        +
      1. ``Keep the program simple, stupid'' (KISS), because + if this program hangs it will lead to a hang of the Apache server + when the rule occurs. +
      2. Avoid one common mistake: never do buffered I/O on stdout! + This will cause a deadloop! Hence the ``$|=1'' in the above + example... +
      +

      + To declare such a map prefix Filename with a prg: + string. +

    + +The RewriteMap directive can occur more than once. For each +mapping-function use one RewriteMap directive to declare its +rewriting mapfile. While you cannot declare a map in per-directory +context it is of course possible to use this map in per-directory +context. + +

    + + +
    +For plain text and DBM format files the looked-up keys are cached in-core +until the mtime of the mapfile changes or the server does a +restart. This way you can have map-functions in rules which are used +for every request. This is no problem, because the external lookup +only happens once! +
    + + +

    +


    +

    + +

    RewriteBase

    +Syntax: RewriteBase BaseURL
    +Default: default is the physical directory path
    +Context: per-directory config
    +

    + +The RewriteBase directive explicitly sets the base URL for +per-directory rewrites. As you will see below, RewriteRule can be +used in per-directory config files (.htaccess). There it will act +locally, i.e. the local directory prefix is stripped at this stage of +processing and your rewriting rules act only on the remainder. At the end +it is automatically added. + +

    +When a substitution occurs for a new URL, this module has to +re-inject the URL into the server processing. To be able to do this it needs +to know what the corresponding URL-prefix or URL-base is. By default this +prefix is the corresponding filepath itself. But at most websites URLs are +NOT directly related to physical filename paths, so this assumption +will be usually be wrong! There you have to use the RewriteBase +directive to specify the correct URL-prefix. + +

    + + +
    +So, if your webserver's URLs are not directly +related to physical file paths, you have to use RewriteBase in every +.htaccess files where you want to use RewriteRule +directives. +
    + +

    +Example: + +

    + Assume the following per-directory config file: + +

    + + +
    +#
    +#  /abc/def/.htaccess -- per-dir config file for directory /abc/def
    +#  Remember: /abc/def is the physical path of /xyz, i.e. the server
    +#            has a 'Alias /xyz /abc/def' directive e.g.
    +#
    +
    +RewriteEngine On
    +
    +#  let the server know that we are reached via /xyz and not 
    +#  via the physical path prefix /abc/def
    +RewriteBase   /xyz
    +
    +#  now the rewriting rules
    +RewriteRule   ^oldstuff\.html$  newstuff.html
    +
    + +

    +In the above example, a request to /xyz/oldstuff.html gets correctly +rewritten to the physical file /abc/def/newstuff.html. + +

    + + +
    + +For the Apache hackers:
    +The following list gives detailed information about the internal +processing steps: + +

    +

    +Request:
    +  /xyz/oldstuff.html
    +
    +Internal Processing:
    +  /xyz/oldstuff.html     -> /abc/def/oldstuff.html    (per-server Alias)
    +  /abc/def/oldstuff.html -> /abc/def/newstuff.html    (per-dir    RewriteRule)
    +  /abc/def/newstuff.html -> /xyz/newstuff.html        (per-dir    RewriteBase)
    +  /xyz/newstuff.html     -> /abc/def/newstuff.html    (per-server Alias)
    +
    +Result:
    +  /abc/def/newstuff.html
    +
    + +This seems very complicated but is the correct Apache internal processing, +because the per-directory rewriting comes too late in the process. So, +when it occurs the (rewritten) request has to be re-injected into the Apache +kernel! BUT: While this seems like a serious overhead, it really isn't, because +this re-injection happens fully internal to the Apache server and the same +procedure is used by many other operations inside Apache. So, you can be +sure the design and implementation is correct. +
    +
    + +

    + + +

    +


    +

    + +

    RewriteCond

    +Syntax: RewriteCond TestString CondPattern
    +Default: -None-
    +Context: server config, virtual host, per-directory config
    +

    + +The RewriteCond directive defines a rule condition. Precede a +RewriteRule directive with one or more RewriteCond +directives. + +The following rewriting rule is only used if its pattern matches the current +state of the URI AND if these additional conditions apply, too. + +

    +TestString is a string which contains server-variables of the form + +

    +%{ NAME_OF_VARIABLE } +
    + +where NAME_OF_VARIABLE can be a string +of the following list: + +

    + + + + + + + + + + + + + + + +
    +HTTP headers:

    + +HTTP_USER_AGENT
    +HTTP_REFERER
    +HTTP_COOKIE
    +HTTP_FORWARDED
    +HTTP_HOST
    +HTTP_PROXY_CONNECTION
    +HTTP_ACCEPT
    +
    +

    +connection & request:

    + +REMOTE_ADDR
    +REMOTE_HOST
    +REMOTE_USER
    +REMOTE_IDENT
    +REQUEST_METHOD
    +SCRIPT_FILENAME
    +PATH_INFO
    +QUERY_STRING
    +AUTH_TYPE
    +
    +

    +server internals:

    + +DOCUMENT_ROOT
    +SERVER_ADMIN
    +SERVER_NAME
    +SERVER_PORT
    +SERVER_PROTOCOL
    +SERVER_SOFTWARE
    +SERVER_VERSION
    +
    +

    +system stuff:

    + +TIME_YEAR
    +TIME_MON
    +TIME_DAY
    +TIME_HOUR
    +TIME_MIN
    +TIME_SEC
    +TIME_WDAY
    +
    +

    +specials:

    + +API_VERSION
    +THE_REQUEST
    +REQUEST_URI
    +REQUEST_FILENAME
    +IS_SUBREQ
    +
    +

    + + +

    + + +
    +These variables all correspond to the similar named HTTP MIME-headers, C +variables of the Apache server or struct tm fields of the Unix +system. +
    + +

    +Special Notes: +

      +
    1. The variables SCRIPT_FILENAME and REQUEST_FILENAME contain the same +value, i.e. the value of the filename field of the internal +request_rec structure of the Apache server. The first name is just the +commonly known CGI variable name while the second is the consistent +counterpart to REQUEST_URI (which contains the value of the uri +field of request_rec). + +

      +

    2. There is the special format: %{ENV:variable} where +variable can be any environment variable. This is looked-up via +internal Apache structures and (if not found there) via getenv() from +the Apache server process. + +

      +

    3. There is the special format: %{HTTP:header} where +header can be any HTTP MIME-header name. This is looked-up +from the HTTP request. Example: %{HTTP:Proxy-Connection} +is the value of the HTTP header ``Proxy-Connection:''. + +

      +

    4. There is the special format: %{LA-U:url} +for look-aheads like -U. This performs a internal sub-request to +look-ahead for the final value of url. + +

      +

    5. There is the special format: %{LA-F:file} +for look-aheads like -F. This performs a internal sub-request to +look-ahead for the final value of file. +
    + +

    +CondPattern is the condition pattern, i.e. a regular expression +which gets applied to the current instance of the TestString, i.e. +TestString gets evaluated and then matched against +CondPattern. + +

    +Remember: CondPattern is a standard +Extended Regular Expression with some additions: + +

      +
    1. You can precede the pattern string with a '!' character +(exclamation mark) to specify a non-matching pattern. + +

      +

    2. +There are some special variants of CondPatterns. Instead of real +regular expression strings you can also use one of the following: +

      +

        +
      • '-d' (is directory)
        +Treats the TestString as a pathname and +tests if it exists and is a directory. +

        +

      • '-f' (is regular file)
        +Treats the TestString as a pathname and +tests if it exists and is a regular file. +

        +

      • '-s' (is regular file with size)
        +Treats the TestString as a pathname and +tests if it exists and is a regular file with size greater then zero. +

        +

      • '-l' (is symbolic link)
        +Treats the TestString as a pathname and +tests if it exists and is a symbolic link. +

        +

      • '-F' (is existing file via subrequest)
        +Checks if TestString is a valid file and accessible via all the +server's currently-configured access controls for that path. This uses an +internal subrequest to determine the check, so use it with care because it +decreases your servers performance! +

        +

      • '-U' (is existing URL via subrequest)
        +Checks if TestString is a valid URL and accessible via all the server's +currently-configured access controls for that path. This uses an internal +subrequest to determine the check, so use it with care because it decreases +your servers performance! +
      +

      +Notice: All of these tests can also be prefixed by a not ('!') character +to negate their meaning. +

    + +

    +Additionally you can set special flags for CondPattern by appending + +

    +[flags] +
    + +as the third argument to the RewriteCond directive. Flags +is a comma-separated list of the following flags: + +
      +
    • 'nocase|NC' (no case)
      + This makes the condition test case-insensitive, i.e. there is + no difference between 'A-Z' and 'a-z' both in the expanded + TestString and the CondPattern. +

      +

    • 'ornext|OR' (or next condition)
      + Use this to combine rule conditions with a local OR instead of the + implicit AND. Typical example: +

      +

      +RewriteCond %{REMOTE_HOST}  ^host1.*  [OR]
      +RewriteCond %{REMOTE_HOST}  ^host2.*  [OR]
      +RewriteCond %{REMOTE_HOST}  ^host3.*  
      +RewriteRule ...some special stuff for any of these hosts...
      +
      + Without this flag you had to write down the cond/rule three times. +

      +

    + +

    +Example: +

    + +To rewrite the Homepage of a site according to the ``User-Agent:'' +header of the request, you can use the following: + +
    +RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla.*
    +RewriteRule  ^/$                 /homepage.max.html  [L]
    +
    +RewriteCond  %{HTTP_USER_AGENT}  ^Lynx.*
    +RewriteRule  ^/$                 /homepage.min.html  [L]
    +
    +RewriteRule  ^/$                 /homepage.std.html  [L]
    +
    + +Interpretation: If you use Netscape Navigator as your browser (which identifies +itself as 'Mozilla'), then you get the max homepage, which includes +Frames, etc. If you use the Lynx browser (which is Terminal-based), then you +get the min homepage, which contains no images, no tables, etc. If you +use any other browser you get the standard homepage. +
    +

    + +

    +


    +

    + +

    RewriteRule

    +Syntax: RewriteRule Pattern Substitution
    +Default: -None-
    +Context: server config, virtual host, per-directory config
    + +

    +The RewriteRule directive is the real rewriting workhorse. The +directive can occur more than once. Each directive then defines one single +rewriting rule. The definition order of these rules is +important, because this order is used when applying the rules at +run-time. + +

    +Pattern can be (for Apache 1.1.x a System +V8 and for Apache 1.2.x a POSIX) regular expression +which gets applied to the current URL. Here ``current'' means the value of the +URL when this rule gets applied. This may not be the original requested +URL, because there could be any number of rules before which already matched +and made alterations to it. + +

    +Some hints about the syntax of regular expressions: + +

    + + + + +
    +
    +^           Start of line
    +$           End of line
    +.           Any single character
    +[chars]     One of chars 
    +[^chars]    None of chars 
    +
    +?           0 or 1 of the preceding char
    +*           0 or N of the preceding char
    ++           1 or N of the preceding char
    +
    +\char       escape that specific char 
    +            (e.g. for specifying the chars ".[]()" etc.)
    +
    +(string)    Grouping of chars (the Nth group can be used on the RHS with $N)
    +
    +
    + +

    +Additionally the NOT character ('!') is a possible pattern +prefix. This gives you the ability to negate a pattern; to say, for instance: ``if +the current URL does NOT match to this pattern''. This can be used +for special cases where it is better to match the negative pattern or as a +last default rule. + +

    + + +
    +Notice! When using the NOT character to negate a pattern you cannot +have grouped wildcard parts in the pattern. This is impossible because when +the pattern does NOT match, there are no contents for the groups. In +consequence, if negated patterns are used, you cannot use $N in the +substitution string! +
    + +

    +Substitution of a rewriting rule is the string +which is substituted for (or replaces) the original URL for which +Pattern matched. Beside plain text you can use + +

      +
    1. pattern-group back-references ($N) +
    2. server-variables as in rule condition test-strings (%{VARNAME}) +
    3. mapping-function calls (${mapname:key|default}) +
    + +Back-references are $N (N=1..9) identifiers which +will be replaced by the contents of the Nth group of the matched +Pattern. The server-variables are the same as for the +TestString of a RewriteCond directive. The +mapping-functions come from the RewriteMap directive and are +explained there. These three types of variables are expanded in the order of +the above list. + +

    +As already mentioned above, all the rewriting rules are applied to the +Substitution (in the order of definition in the config file). The +URL is completely replaced by the Substitution and the +rewriting process goes on until there are no more rules (unless explicitly +terminated by a L flag - see below). + +

    +There is a special substitution string named '-' which means: +NO substitution! Sounds silly? No, it is useful to provide rewriting +rules which only match some URLs but do no substitution, e.g. in +conjunction with the C (chain) flag to be able to have more than one +pattern to be applied before a substitution occurs. + +

    + + +
    +Notice: There is a special feature. When you prefix a substitution +field with http://thishost[:thisport] then +mod_rewrite automatically strips it out. This auto-reduction on +implicit external redirect URLs is a useful and important feature when +used in combination with a mapping-function which generates the hostname +part. Have a look at the first example in the example section below to +understand this. +

    +Remember: An unconditional external redirect to your own server will +not work with the prefix http://thishost because of this feature. +To achieve such a self-redirect, you have to use the R-flag (see +below). +

    + +

    +Additionally you can set special flags for Substitution by appending + +

    +[flags] +
    + +as the third argument to the RewriteRule directive. Flags is a +comma-separated list of the following flags: + +
      +
    • 'redirect|R[=code]' (force redirect)
      + Prefix Substitution + with http://thishost[:thisport]/ (which makes the new URL a URI) to + force a external redirection. If no code is given a HTTP response + of 302 (MOVED TEMPORARILY) is used. If you want to use other response + codes in the range 300-400 just specify them as a number or use + one of the following symbolic names: temp (default), permanent, + seeother. + Use it for rules which should + canonicalize the URL and gives it back to the client, e.g. translate + ``/~'' into ``/u/'' or always append a slash to + /u/user, etc.
      +

      + Notice: When you use this flag, make sure that the + substitution field is a valid URL! If not, you are redirecting to an + invalid location! And remember that this flag itself only prefixes the + URL with http://thishost[:thisport]/, but rewriting goes on. + Usually you also want to stop and do the redirection immediately. To stop + the rewriting you also have to provide the 'L' flag. +

      +

    • 'forbidden|F' (force URL to be forbidden)
      + This forces the current URL to be forbidden, i.e. it immediately sends + back a HTTP response of 403 (FORBIDDEN). Use this flag in conjunction with + appropriate RewriteConds to conditionally block some URLs. +

      +

    • 'gone|G' (force URL to be gone)
      + This forces the current URL to be gone, i.e. it immediately sends back a + HTTP response of 410 (GONE). Use this flag to mark no longer existing + pages as gone. +

      +

    • 'proxy|P' (force proxy)
      + This flag forces the substitution part to be internally forced as a proxy + request and immediately (i.e. rewriting rule processing stops here) put + through the proxy module. You have to make sure that the substitution + string is a valid URI (e.g. typically http://) which can + be handled by the Apache proxy module. If not you get an error from + the proxy module. Use this flag to achieve a more powerful implementation + of the mod_proxy directive ProxyPass, to map + some remote stuff into the namespace of the local server. +

      + Notice: You really have to put ProxyRequests On into your + server configuration to prevent proxy requests from leading to core-dumps + inside the Apache kernel. If you have not compiled in the proxy module, + then there is no core-dump problem, because mod_rewrite checks for + existence of the proxy module and if lost forbids proxy URLs. +

      +

    • 'last|L' (last rule)
      + Stop the rewriting process here and + don't apply any more rewriting rules. This corresponds to the Perl + last command or the break command from the C + language. Use this flag to prevent the currently rewritten URL from being + rewritten further by following rules which may be wrong. For + example, use it to rewrite the root-path URL ('/') to a real + one, e.g. '/e/www/'. +

      +

    • 'next|N' (next round)
      + Re-run the rewriting process (starting again with the first rewriting + rule). Here the URL to match is again not the original URL but the URL + from the last rewriting rule. This corresponds to the Perl + next command or the continue command from the C + language. Use this flag to restart the rewriting process, i.e. to + immediately go to the top of the loop.
      + But be careful not to create a deadloop! +

      +

    • 'chain|C' (chained with next rule)
      + This flag chains the current rule with the next rule (which itself can + also be chained with its following rule, etc.). This has the following + effect: if a rule matches, then processing continues as usual, i.e. the + flag has no effect. If the rule does not match, then all following + chained rules are skipped. For instance, use it to remove the + ``.www'' part inside a per-directory rule set when you let an + external redirect happen (where the ``.www'' part should not to + occur!). +

      +

    • 'type|T=mime-type' (force MIME type)
      + Force the MIME-type of the target file to be mime-type. For + instance, this can be used to simulate the old mod_alias + directive ScriptAlias which internally forces all files inside + the mapped directory to have a MIME type of + ``application/x-httpd-cgi''. +

      +

    • 'nosubreq|NS' (used only if no internal sub-request)
      + This flag forces the rewriting engine to skip a rewriting rule if the + current request is an internal sub-request. For instance, sub-requests + occur internally in Apache when mod_include tries to find out + information about possible directory default files (index.xxx). + On sub-requests it is not always useful and even sometimes causes a failure to + if the complete set of rules are applied. Use this flag to exclude some rules.
      +

      + Use the following rule for your decision: whenever you prefix some URLs + with CGI-scripts to force them to be processed by the CGI-script, the + chance is high that you will run into problems (or even overhead) on sub-requests. + In these cases, use this flag. +

      +

    • 'passthrough|PT' (pass through to next handler)
      + This flag forces the rewriting engine to set the uri field + of the internal request_rec structure to the value + of the filename field. This flag is just a hack to be able + to post-process the output of RewriteRule directives by + Alias, ScriptAlias, Redirect, etc. directives + from other URI-to-filename translators. A trivial example to show the + semantics: + If you want to rewrite /abc to /def via the rewriting + engine of mod_rewrite and then /def to /ghi + with mod_alias: +
      +    RewriteRule ^/abc(.*)  /def$1 [PT]
      +    Alias       /def       /ghi   
      +    
      + If you omit the PT flag then mod_rewrite + will do its job fine, i.e. it rewrites uri=/abc/... to + filename=/def/... as a full API-compliant URI-to-filename + translator should do. Then mod_alias comes and tries to do a + URI-to-filename transition which will not work. +

      + Notice: You have to use this flag if you want to intermix directives + of different modules which contain URL-to-filename translators. The + typical example is the use of mod_alias and + mod_rewrite.. +

      + + +
      + + For the Apache hackers:
      + If the current Apache API had a + filename-to-filename hook additionally to the URI-to-filename hook then + we wouldn't need this flag! But without such a hook this flag is the + only solution. The Apache Group has discussed this problem and will + add such hooks into Apache version 2.0. +
      +
      +

      +

    • 'skip|S=num' (skip next rule(s))
      + This flag forces the rewriting engine to skip the next num rules + in sequence when the current rule matches. Use this to make pseudo + if-then-else constructs: The last rule of the then-clause becomes + a skip=N where N is the number of rules in the else-clause. + (This is not the same as the 'chain|C' flag!) +

      +

    • 'env|E=VAR:VAL' (set environment variable)
      + This forces an environment variable named VAR to be set to the value + VAL, where VAL can contain regexp backreferences $N + which will be expanded. You can use this flag more than once to set more + than one variable. The variables can be later dereferenced at a lot of + situations, but the usual location will be from within XSSI (via + <!--#echo var="VAR"-->) or CGI (e.g. $ENV{'VAR'}). + But additionally you can also dereference it in a following RewriteCond + pattern via %{ENV:VAR}. Use this to strip but remember + information from URLs. +
    + +

    + + +
    +Remember: Never forget that Pattern gets applied to a complete URL +in per-server configuration files. But in per-directory configuration +files, the per-directory prefix (which always is the same for a specific +directory!) gets automatically removed for the pattern matching and +automatically added after the substitution has been done. This feature is +essential for many sorts of rewriting, because without this prefix stripping +you have to match the parent directory which is not always possible. +

    +There is one exception: If a substitution string starts with +``http://'' then the directory prefix will be not added and a +external redirect or proxy throughput (if flag P is used!) is forced! +

    + +

    + + +
    +Notice! To enable the rewriting engine for per-directory configuration files +you need to set ``RewriteEngine On'' in these files and +``Option FollowSymLinks'' enabled. If your administrator has +disabled override of FollowSymLinks for a user's directory, then +you cannot use the rewriting engine. This restriction is needed for +security reasons. +
    + +

    +Here are all possible substitution combinations and their meanings: + +

    +Inside per-server configuration (httpd.conf)
    +for request ``GET /somepath/pathinfo'':

    + +

    + + + + +
    +
    +Given Rule                                      Resulting Substitution
    +----------------------------------------------  ----------------------------------
    +^/somepath(.*) otherpath$1                      not supported, because invalid!
    +
    +^/somepath(.*) otherpath$1  [R]                 not supported, because invalid!
    +
    +^/somepath(.*) otherpath$1  [P]                 not supported, because invalid!
    +----------------------------------------------  ----------------------------------
    +^/somepath(.*) /otherpath$1                     /otherpath/pathinfo
    +
    +^/somepath(.*) /otherpath$1 [R]                 http://thishost/otherpath/pathinfo
    +                                                via external redirection
    +
    +^/somepath(.*) /otherpath$1 [P]                 not supported, because silly!
    +----------------------------------------------  ----------------------------------
    +^/somepath(.*) http://thishost/otherpath$1      /otherpath/pathinfo
    +
    +^/somepath(.*) http://thishost/otherpath$1 [R]  http://thishost/otherpath/pathinfo
    +                                                via external redirection
    +
    +^/somepath(.*) http://thishost/otherpath$1 [P]  not supported, because silly!
    +----------------------------------------------  ----------------------------------
    +^/somepath(.*) http://otherhost/otherpath$1     http://otherhost/otherpath/pathinfo
    +                                                via external redirection
    +
    +^/somepath(.*) http://otherhost/otherpath$1 [R] http://otherhost/otherpath/pathinfo
    +                                                via external redirection
    +                                                (the [R] flag is redundant)
    +
    +^/somepath(.*) http://otherhost/otherpath$1 [P] http://otherhost/otherpath/pathinfo
    +                                                via internal proxy
    +
    +
    + +

    +Inside per-directory configuration for /somepath
    +(i.e. file .htaccess in dir /physical/path/to/somepath containing +RewriteBase /somepath)
    for +request ``GET /somepath/localpath/pathinfo'':

    + +

    + + + + +
    +
    +Given Rule                                      Resulting Substitution
    +----------------------------------------------  ----------------------------------
    +^localpath(.*) otherpath$1                      /somepath/otherpath/pathinfo
    +
    +^localpath(.*) otherpath$1  [R]                 http://thishost/somepath/otherpath/pathinfo
    +                                                via external redirection
    +
    +^localpath(.*) otherpath$1  [P]                 not supported, because silly!
    +----------------------------------------------  ----------------------------------
    +^localpath(.*) /otherpath$1                     /otherpath/pathinfo
    +
    +^localpath(.*) /otherpath$1 [R]                 http://thishost/otherpath/pathinfo
    +                                                via external redirection
    +
    +^localpath(.*) /otherpath$1 [P]                 not supported, because silly!
    +----------------------------------------------  ----------------------------------
    +^localpath(.*) http://thishost/otherpath$1      /otherpath/pathinfo
    +
    +^localpath(.*) http://thishost/otherpath$1 [R]  http://thishost/otherpath/pathinfo
    +                                                via external redirection
    +
    +^localpath(.*) http://thishost/otherpath$1 [P]  not supported, because silly!
    +----------------------------------------------  ----------------------------------
    +^localpath(.*) http://otherhost/otherpath$1     http://otherhost/otherpath/pathinfo
    +                                                via external redirection
    +
    +^localpath(.*) http://otherhost/otherpath$1 [R] http://otherhost/otherpath/pathinfo
    +                                                via external redirection
    +                                                (the [R] flag is redundant)
    +
    +^localpath(.*) http://otherhost/otherpath$1 [P] http://otherhost/otherpath/pathinfo
    +                                                via internal proxy
    +
    +
    + + + + + + +

    +Example: +

    +

    +We want to rewrite URLs of the form +
    +/ Language +/~ Realname +/.../ File +
    +into +
    +/u/ Username +/.../ File +. Language +
    +

    +We take the rewrite mapfile from above and save it under +/anywhere/map.real-to-user. Then we only have to add the +following lines to the Apache server configuration file: + +

    +
    +RewriteLog   /anywhere/rewrite.log
    +RewriteMap   real-to-user               txt:/anywhere/map.real-to-host
    +RewriteRule  ^/([^/]+)/~([^/]+)/(.*)$   /u/${real-to-user:$2|nobody}/$3.$1
    +
    +
    +
    + + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_status.html b/APACHE_1_2_X/htdocs/manual/mod/mod_status.html new file mode 100644 index 00000000000..f5a55fa397c --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_status.html @@ -0,0 +1,107 @@ + + +Apache module mod_status + + + + +

    Module mod_status

    + +The Status Module is only available in Apache 1.1 and later.

    + +

    Function

    + +The Status module allows a server administrator to find out how well +their server is performing. A HTML page is presented that gives +the current server statistics in an easily readable form. If required +this page can be made to automatically refresh (given a compatible +browser). Another page gives a simple machine-readable list of the current +server state. +

    +The details given are: +

      +
    • The number of children serving requests +
    • The number of idle children +
    • The status of each child, the number of requests that child has +performed and the total number of bytes served by the child (*) +
    • A total number of accesses and byte count served (*) +
    • The time the server was started/restarted and the +time it has been running for +
    • Averages giving the number of requests per second, +the number of bytes served per second and the average number +of bytes per request (*) +
    • The current percentage CPU used by each child and in total by +Apache (*) +
    • The current hosts and requests being processed (*) +
    + +A compile-time option must be used to display the details marked "(*)" as +the instrumentation required for obtaining these statistics does not +exist within standard Apache. + +

    Enabling Status Support

    + +To enable status reports only for browsers from the foo.com +domain add this code to your access.conf configuration file +
    +    <Location /server-status>
    +    SetHandler server-status
    +    
    +    order deny,allow
    +    deny from all
    +    allow from .foo.com
    +    </Location>
    +
    +

    +You can now access server statistics by using a Web browser to access the +page http://your.server.name/server-status +

    +Note that mod_status will only work when you are running Apache in +standalone mode and not +inetd mode. + +

    Automatic Updates

    +You can get the status page to update itself automatically if you have +a browser that supports "refresh". Access the page +http://your.server.name/server-status?refresh=N to refresh the page +every N seconds. +

    Machine Readable Status File

    +A machine-readable version of the status file is available by accessing the +page http://your.server.name/server-status?auto. This is useful +when automatically run, see the Perl program in the /support +directory of Apache, log_server_status. + +

    Full Instrumentation

    + +To obtain full statistics you must compile Apache with a special +directive. On some machines there may be a small performance loss +if you do this. Try full statistics and see if you notice any +difference. If you do please contact +mark@ukweb.com and tell me your configuration. + +

    + +Do this by adding the following to the AUX_CFLAGS line in the +"Configuration" file and then recompiling as usual. +

    +	AUX_CFLAGS= (something) -DSTATUS
    +
    + +
    + + It should be noted that if mod_status is compiled into + the server, its handler capability is available in all + configuration files, including per-directory files + (e.g., .htaccess). This may have + security-related ramifications for your site. + +
    + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_userdir.html b/APACHE_1_2_X/htdocs/manual/mod/mod_userdir.html new file mode 100644 index 00000000000..cca87f5020e --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_userdir.html @@ -0,0 +1,76 @@ + + + +Apache module mod_userdir + + + + + +

    Module mod_userdir

    + +This module is contained in the mod_userdir.c file, and +is compiled in by default. It provides for user-specific directories. + + + +
    + + +

    UserDir

    + +Syntax: UserDir directory/filename
    +Default: UserDir public_html
    +Context: server config, virtual host
    +Status: Base
    +Module: mod_userdir
    +Compatibility: All forms except the UserDir +public_html form are only available in Apache 1.1 or above.

    + +The UserDir directive sets the real directory in a user's home directory +to use when a request for a document for a user is received. +Directory is either disabled, to disable this feature, + or the name of a directory, following one of the following +patterns. If not disabled, then a request for +http://www.foo.com/~bob/one/two.html will be translated to: +

    +UserDir public_html     -> ~bob/public_html/one/two.html
    +UserDir /usr/web        -> /usr/web/bob/one/two.html
    +UserDir /home/*/www     -> /home/bob/www/one/two.html
    +
    +The following directives will send redirects to the client: +
    +UserDir http://www.foo.com/users   -> http//www.foo.com/users/bob/one/two.html
    +UserDir http://www.foo.com/*/usr   -> http://www.foo.com/bob/usr/one/two.html
    +UserDir http://www.foo.com/~*/     -> http://www.foo.com/~bob/one/two.html
    +
    + +

    + +Be careful when using this directive; for instance, "UserDir +./" would map "/~root" to +"/" - which is probably undesirable. See also +the +<Directory> +directive and the +Security Tips +page for more information. + +

    + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_usertrack.html b/APACHE_1_2_X/htdocs/manual/mod/mod_usertrack.html new file mode 100644 index 00000000000..585e45d64d6 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/mod/mod_usertrack.html @@ -0,0 +1,87 @@ + + + +Apache module mod_usertrack + + + + + +

    Module mod_usertrack

    + +Previous releases of Apache have included a module which generates a +'clickstream' log of user activity on a site using cookies. This was +called the "cookies" module, mod_cookies. In Apache 1.2 and later this +module has been renamed the "user tracking" module, +mod_usertrack. This module has been simplified and new directives +added. + +
    + +

    Logging

    + +Previously, the cookies module (now the user tracking module) did its +own logging, using the CookieLog directive. In this release, +this module does no logging at all. Instead, a configurable log +format file should be used to log user click-streams. This is possible +because the logging module now allows multiple log files. The cookie itself is +logged by using the text %{cookie}n + +in the log file format. For example: +
    +CustomLog logs/clickstream "%{cookie}n %r %t"
    +
    + +For backward compatibility the configurable log module implements the +old CookieLog directive, but this should be upgraded to the +above CustomLog directive. + +

    Directives

    + + + +
    + +

    CookieExpires

    +Syntax: CookieExpires expiry-period
    +Context: server config, virtual host
    +Status: optional
    +Module: mod_usertrack

    + +When used, this directive sets an expiry time on the cookie generated +by the usertrack module. The expiry-period can be given either +as a number of seconds, or in the format such as "2 weeks 3 days 7 +hours". Valid denominations are: years, months, weeks, hours, minutes +and seconds. + +

    If this directive is not used, cookies last only for the current +browser session.

    + +

    CookieTracking

    +Syntax: CookieTracking on | off
    +Context: server config, virtual host, directory, +.htaccess
    +Override: FileInfo
    +Status: optional
    +Module: mod_usertrack

    + +When the user track module is compiled in, and "CookieTracking on" is +set, Apache will start sending a user-tracking cookie for all new +requests. This directive can be used to turn this behavior on or off +on a per-server or per-directory basis. By default, compiling +mod_usertrack will not activate cookies. + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/multilogs.html b/APACHE_1_2_X/htdocs/manual/multilogs.html new file mode 100644 index 00000000000..08ddd2612d3 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/multilogs.html @@ -0,0 +1,122 @@ + + + +Apache Multiple Log Files + + + + + +

    Multiple Log Files

    + +It is now possible to specify multiple log files, each with a fully +customizable format. This is compatible with existing +configurations. Multiple log files are implemented as part of the mod_log_config module which as of +Apache 1.2 is the default log module. + +
    + +

    Using Multiple Log Files

    + +Multiple log files be created with either the TransferLog +or CustomLog directive. These directives can be +repeated to create more than one log file (in previous releases, +only one logfile could be given per server configuration). +The TransferLog directive creates a log file +in the standard "common log format", although this can be customized +with LogFormat. The syntax of these two +directives is the same as for the config log module in previous +Apache releases. +

    + +The real power of multiple log files come from the ability to +create log files in different formats. For example, as well +as a CLF transfer log, the server could log the user agent of +each client, or the referrer information, or any other aspect of +the request, such as the language preferences of the user. +

    + +The new CustomLog directive takes both a filename to log +to, and a log file format. + +


    + +Syntax: CustomLog filename "format"
    +Context: server config, virtual host
    +Status: base
    +Module: mod_log_config

    + +The first argument is the filename to log to. This is used +exactly like the argument to TransferLog, that is, +it is either a file as a full path or relative to the current +server root, or |programname. Be aware that anyone who can write to +the directory where a log file is written can gain access to the uid +that starts the server. See the +security tips document for details.

    + +The format argument specifies a format for each line of the log file. +The options available for the format are exactly the same as for +the argument of the LogFormat directive. If the format +includes any spaces (which it will do in almost all cases) it +should be enclosed in double quotes. +

    + +

    Use with Virtual Hosts

    + +If a <VirtualHost> section does not contain any +TransferLog or CustomLog directives, the +logs defined for the main server will be used. If it does +contain one or more of these directives, requests serviced by +this virtual host will only be logged in the log files defined +within its definition, not in any of the main server's log files. +See the examples below. +

    + +


    + +

    Examples

    + +To create a normal (CLF) format log file in logs/access_log, and a +log of user agents: + +
    +TransferLog logs/access_log
    +CustomLog   logs/agents     "%{user-agent}i"
    +
    + +To define a CLF transfer log and a referrer log which log +all accesses to both the main server and a virtual host: + +
    +TransferLog logs/access_log
    +CustomLog   logs/referer    "%{referer}i"
    +
    +<VirtualHost>
    +  DocumentRoot   /whatever
    +  ServerName     my.virtual.host
    +</VirtualHost>
    +
    + +Since no TransferLog or CustomLog directives appear inside the +<VirtualHost> section, any requests for this virtual host +will be logged in the main server's log files. If however the +directive + +
    +TransferLog logs/vhost_access_log
    +
    + +was added inside the virtual host definition, then accesses to this +virtual host will be logged in vhost_access_log file (in common +log format), and not in logs/access_log or logs/referer. + + + + diff --git a/APACHE_1_2_X/htdocs/manual/new_features_1_0.html b/APACHE_1_2_X/htdocs/manual/new_features_1_0.html new file mode 100644 index 00000000000..cd5a73cf08b --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/new_features_1_0.html @@ -0,0 +1,125 @@ + + + +Apache extra features + + + + + +

    Overview of new features

    + +

    New Features with Apache 1.0

    + +

    New features with this release, as extensions of the Apache +functionality (see also more detailed CHANGES file) in +the source directory. Because the core code has changed so +significantly, there are certain liberties that earlier versions of +Apache (and the NCSA daemon) took that Apache 1.0 is pickier about - +please check the compatibility notes if you have any problems. + +

      + +
    • API for server extensions --- see below for a brief sermon on +philosophy, or see src/API.html for an actual +overview. Most server functionality (including includes, CGI, and +most forms of access control) are actually implemented as +API-conformant modules; you can also do other neat stuff (we've +included a sample module, for instance, which one of us is using to +track click-trails using the Netscape +cookie mechanism, for visitors who come in through Netscape +clients). Modules can also be loaded dynamically using GNU DLD. + +

      +The API is not yet quite stable (see src/TODO for some possible +changes), but anything done now will be easily adapted for future +versions --- after all, we have more modules to adapt than you do. + +

      + +

    • New Process Model - much less forking, no fixed number of children. + +We found that many people were using values for "MaxServers" either +too high or too low, and were hanging themselves on it. The model we +adopted is still based on long-lived minimal-forking processes, but +instead of specifying one number of persistent processes, the +web-master specifies a maximum and minimum number of processes to be +"spare" - every couple of seconds the parent checks the actual number +of spare servers and adjusts accordingly. This should keep the number +of servers concurrently running relatively low while still ensuring +minimal forking. + +

      + +

    • <VirtualHost> (the configuration directive for +multiple-homed servers) is more general now. Just about any srm.conf or +httpd.conf command can go in a <Virtualhost> section, with the +following specific exceptions: ServerType, UserId, GroupId, +StartServers, MaxRequestsPerChild, BindAddress, PidFile, TypesConfig, +ServerRoot. + +

      + +

    • Support for content negotiation of languages through MultiViews +(*.fr, *.de, *.en suffixes), via the new AddLanguage and LanguagePriority +commands (code written by Florent Guillaume, guillaum@clipper.ens.fr). + +

      + +

    • Significant internal cleanups and rearrangements. The two externally + visible consequences of this are that just about all of the unchecked + fixed limits are gone, and that the server is somewhat pickier about + config file syntax (noting and complaining about extraneous command + arguments or other stuff at the end of command lines). + +

      + +

    • XBITHACK is a run-time option, and can be selectively enabled per + directory --- the -DXBITHACK compile-time option just changes the + default. The command which configures it is "XBitHack", which is + allowed everywhere "Options" is; this takes an argument --- + "XBitHack Off" turns it off; "XBitHack On" gets you the NCSA + -DXBITHACK behavior; and "XBitHack Full" gets you the Apache GXBIT + stuff on top of that. (-DXBITHACK makes "Full" the default; + otherwise, it defaults "Off"). + +

      + +

    • TransferLog can specify a program which gets the log entries piped to it, + a la 'TransferLog "| /var/www/my-perl-script -arg valu"' --- this should + give the same SIGTERM/pause/SIGKILL treatment to the logging process on + server restarts that a CGI script gets on an aborted request. NB the + server is counting on the logging process to work, and will probably hang + or worse if it dies. + +

      + +

    • Configurable logging module --- this + is a replacement for the standard plane-jane Common Log Format code, which + supports a LogFormat directive which allows you to control the formatting of + entries in the TransferLog, and add some new items if you like (in + particular, Referer and User-Agent). EXPERIMENTAL. +
    +


    + + +

    Other features of Apache

    + + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/new_features_1_1.html b/APACHE_1_2_X/htdocs/manual/new_features_1_1.html new file mode 100644 index 00000000000..8ab27051686 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/new_features_1_1.html @@ -0,0 +1,213 @@ + + +New features with Apache 1.1 + + + + + +

    Overview of new features

    + +

    API Changes

    + +A few changes to the Apache API were made for 1.1. It is possible +that some third-party modules will no longer work with 1.1, though +we have made every effort to provide backwards-compatibility. If you +encounter a module that does not work with 1.1, please let us know. + + +

    New Features with Apache 1.1

    +

    New features with this release, as extensions of the Apache +functionality (see also more detailed CHANGES file in +the source directory.) Because the core code has changed so +significantly, there are certain liberties that earlier versions of +Apache (and the NCSA daemon) took that recent Apache versions are +pickier about - please check the compatibility notes if you have any +problems.

    +
    + +

    In addition to a number of bug fixes and internal performance +enhancements, Apache +1.1 has the following specific new user features:

    + +
      + +
    • Support for Keep-Alive Persistent +Connections
      Apache now has (optional) support for persistent +connections, as defined by the HTTP/1.1 draft. This protocol, +supported by a number of current HTTP servers and browsers (including +Netscape Navigator 2.0) has been shown to increase speed of document +transfer by up to 50% in certain cases. + +
    • New non-IP Intensive VirtualHost +Support
      +Apache's support for virtual hosts has been enhanced to be able to +use information sent by some new Web browsers to determine the server +being accessed, without requiring an additional IP address for each +host. + +
    • Listen to Multiple Addresses and +Ports
      +Using the new Listen directive, Apache can listen to more +than one port and IP address, using the same configuration set. + +
    • Status +Module
      +Apache now contains a module that gives the web-master accurate, +up-to-date information about the server's status and its resource +consumption. It also gives the current state of each server process +including the current URL being processed. For an example, check out +the status of the +www.apache.org server. + +
    • Server Information Module
      +This module gives a plethora of information about the other modules +installed, their directives, and their configurations. It is +extremely helpful in debugging configuration problems. For an +example, check out information about the +www.apache.org server. + +
    • Experimental Caching Proxy Server
      +Apache can now act as +an HTTP proxy server, allowing clients behind firewalls to use the +server to access the outside world. In addition, it can cache +documents it proxies, speeding up access to frequently requested +documents. + +
    • URL-based Access Protection
      +In addition to access checking and authorization by filename (with +<Directory>), +the new <Location> directive allows protection by +URL. + +
    • Filetype-based Script "Actions"
      +You can now run CGI scripts whenever a file of a certain type is +requested. This makes it much easier to execute scripts that process +files. In addition, you can use the new Script directive to enable scripts +for files called with HTTP methods Apache does not natively support. + +
    • New "Handler" Directives
      +The new AddHandler and SetHandler directive +allows "handlers" to be defined for filename extensions or +directories. These handlers, which can either be built into Apache or +added with the Action directive, extend +Apache's range of usability, and almost entirely remove the "magic" +media types. + +
    • Customizable CGI Environment +Variables
      +New PassEnv and SetEnv directives allow you to +modify the environment variables passed to CGI scripts. + +
    • CERN Metafile Support
      +Now emulates the CERN httpd's support for metafiles containing additional +HTTP headers to be supplied with a document. + +
    • Improved Imagemap Support
      +The internal imagemap handling code has been rewritten and +reorganized, adding new handling of default, base and relative URLs, +and support for creating non-graphical menus for use with clients that +do not support imagemaps. + +
    • Improved UserDir Directive
      +Now supports the ability to point user's files (as specified by URLs +beginning with the "~" character) at directories other +than those specified by the Unix password file. + +
    • Minimal DNS Now Runtime Option
      +New HostnameLookups +server configuration directive can be used to turn On or +Off DNS lookups. This supersedes the -DMINIMAL_DNS +compile-time configuration option. This option can be set per-directory. + +
    • IdentityCheck Now Per-Directory Option
      +The IdentityCheck directive, which controls the use of +ident to check the remote user name, can now be set per directory. The +ident support is also RFC 1413-compliant. + +
    • Redirect Now Usable in .htaccess Files
      +The Redirect +directive can now be used in .htaccess files when the +FileInfo directive has been set on. This allows users to +redirect parts of their directories without requiring CGI scripts + +
    • ErrorDocument Now Usable in .htaccess Files
      +The ErrorDocument +directive can now be used in .htaccess files when the +FileInfo directive has been set on. This allows users to +have different error messages for different sections of a site. + +
    • ForceType Directive
      +This new directive, in <Directory> sections or +.htaccess files, allows you to override the filename extensions and +force a single content type. (e.g. ForceType +application/octet-stream) + +
    • File Owner Available to Included CGI Scripts
      +Server-side includes that call CGI scripts will now set a +USER_NAME environment variable that contains the owner of +the file which included it. + +
    • Improved Icons
      +Thanks to Kevin +Hughes, Apache's nifty color GIF icons for directory listings have +been updated. In addition, the Powered by Apache +(apache_pb.gif) logo has been included. + +
    + +
    + +

    New Authentication Modules

    + +

    Note: These modules are not +compiled into the server by default, as they require special support +on the host system. They must be enabled specifically in the +Configuration file.

    + +
      + +
    • Anonymous HTTP Logins
      +New options allow you to allow, using Basic HTTP Authentication, +anonymous logins, like those of FTP. This allows you to collect email +addresses of people accessing your site. + +
    • Support for Digest +Authentication
      +Apache now supports digest authentication using RSA MD5 +encryption. When used with a supporting web browser, this provides a +more secure alternative to Basic authentication. + +
    • Support for Unix DB +Authentication - mod_auth_db.c
      In +addition to DBM support, Apache now +contains optional support for Berkeley DB databases. + +
    • mSQL Database +Authentication - mod_auth_msql.html
      +Support for the use of mSQL databases for user authentication via HTTP +is now supported. + +
    + +
    + +

    OS/2 Support

    + +

    Apache now includes support for OS/2, thanks to Softlink Services.

    + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/new_features_1_2.html b/APACHE_1_2_X/htdocs/manual/new_features_1_2.html new file mode 100644 index 00000000000..1b0bda3021b --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/new_features_1_2.html @@ -0,0 +1,208 @@ + + +New features with Apache 1.2 + + + + + +

    Overview of new features

    + +

    API Changes

    + +

    Some non-compatible changes were made to the Apache API in order to +deal with HTTP/1.1 compatibility. It is possible that some modules +will no longer work (specifically, those that process input using the +POST or PUT methods). If you encounter a module that does not work, +please contact the author. A programmer's note on the subject is +available.

    + +

    Additionally, some changes were made to the CGI environment that +may cause some CGI scripts to work incorrectly. If you are +experiencing trouble with a CGI that worked fine under Apache 1.1.1, +please see our explanation of the changes.

    + +

    New Features with Apache 1.2

    +

    New features with this release, as extensions of the Apache +functionality. Because the core code has changed so +significantly, there are certain liberties that earlier versions of +Apache (and the NCSA daemon) took that recent Apache versions are +pickier about - please check the compatibility notes if you have any +problems.

    +
    + +

    In addition to a number of bug fixes and internal performance +enhancements, Apache +1.2 has the following specific new user features:

    + +
      + +
    • HTTP/1.1 Compliance +[Documentation to be written]
      +Aside from the optional proxy module (which operates as HTTP/1.0), +Apache is conditionally compliant with the HTTP/1.1 proposed standard, +as approved by the IESG and the +IETF HTTP working group. +HTTP/1.1 provides a much-improved protocol, and +should allow for greater performance and efficiency when transferring +files. Apache does, however, still work great with HTTP/1.0 browsers. +We are very close to being unconditionally compliant; if you note any +deviance from the proposed standard, please report it as a bug. + +
    • eXtended Server Side Includes +(XSSI)
      +A new set of server-side include +directives allows the user to better create WWW pages. This includes +number of powerful new features, such as the ability to set variables +and use conditional HTML. + +
    • File-based and Regex-enabled +Directive Sections
      +The new +<Files> +section allows directives to be enabled based on full filename, not just directory and URL. In +addition, <Files> sections can appear in +.htaccess files. <Files>, along with +<Directory> + and <Location>, can +also now be based on regular expressions, not just simple prefix +matching. + +
    • Browser-based Environment +Variables
      +Environment variables can now be set based on the +User-Agent string of the browser. Combined with XSSI, this allows you to write browser-based +conditional HTML documents. + +
    • SetUID CGI Execution
      + Apache now + supports the execution of CGI scripts as users other + than the server user. A number of security checks are built in + to try and make this as safe as possible. + +
    • URL Rewriting Module
      +The optional mod_rewrite module is now included. This +module can provide powerful URL mapping, using regular +expressions. There's nothing this module can't do! + +
    • Enhanced, Configurable +Logging
      +The optional mod_log_config included with earlier +versions of Apache is now standard, and has been enhanced to allow +logging of much more detail about the transaction, and can be used to +open more than one log file at once +(each of which can have a different log format). If you have Apache +write any logs to a directory which is writable by anyone other than +the user that starts the server, see the +security tips document to be sure you aren't putting the security +of your server at risk. + + +
    • User Tracking (Cookies) +Revisions
      +The mod_cookies included with previous versions of Apache +has been renamed mod_usertrack, to more accurately +reflect its function (some people inadvertently thought it enabled +cookie support in Apache, which is not true - Apache supports the use +of cookies directly). It is also now possible to disable the +generation of cookies, even when + the cookie module is compiled in. Also, an expiry time can be set + on the cookies. + +
    • <VirtualHost> Enhancements
      + The <VirtualHost> directive can now take more than one IP + address or hostname. This lets a single vhost handles requests + for multiple IPs or hostnames. Also the special section + <VirtualHost _default_> can be used to handle requests normally + left for the main server configuration. + +
    • CGI Debugging Environment
      +ScriptLog allows you to now set up a log that records +all input and output to failed CGI scripts. This includes environment +variables, input headers, POST data, output, and more. This makes CGI +scripts much easier to debug. + +
    • Resource Limits for CGI Scripts
      +New directives allow the limiting of resources used by CGI scripts +(e.g. max CPU time). This is helpful in preventing 'runaway' CGI +processes. + +
    • Redirect Directive Can Return Alternate Status
      + The Redirect directive can return permanent or temporary redirects, + "Gone" or "See Other" HTTP status. For NCSA-compatibility, + RedirectTemp and RedirectPermanent are also implemented. + +
    • Simplified Compilation
      + The process of configuring Apache for compilation has been + simplified. + +
    • Add or Remove Options
      + The Options directive can now add or remove options from + those currently in force, rather than always replacing them. + +
    • Command-line Help
      +The -h command-line option now lists all the available +directives. + +
    • Optional Headers Module to Set or Remove HTTP Headers
      +The optional mod_headers module can be used to set custom +headers in the HTTP response. It can append to existing headers, +replace them, or remove headers from the response. + +
    • Conditional Config Directives
      +A new <IfModule> section allows directives to be +enabled only if a given module is loaded into the server. + +
    • Authorization Directives Now Use +NCSA-style Syntax
      + +The AuthUserFile, AuthGroupFile and AuthDigestFile commands +now have a syntax compatible with the NCSA server. + +
    • NCSA Satisfy authentication +directive now implemented
      +Satisfy allows for more flexible access control +configurations. + +
    • Better NCSA Compatibility
      +Apache directives are now more compatible with NCSA 1.5 to make +moving between servers easier. In particular, Apache now implements the +Satisfy, +MaxKeepAliveRequests, +RedirectPermanent and +RedirectTemp, +directives, and the following directives are now syntax-compatible with +NCSA: +AuthUserFile, +AuthGroupFile, +AuthDigestFile, +KeepAlive and +KeepAliveTimeout. + +
    • Optional proxy module
      +An improved FTP, HTTP, and CONNECT mode SSL proxy is included with +Apache 1.2. Some of the changes visible to users: +
      +
      - Improved FTP proxy supporting PASV mode +
      - ProxyBlock directive for excluding sites to proxy +
      - NoCache * directive for disabling proxy caching +
      - Numerous bug fixes +
      + +
    + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/process-model.html b/APACHE_1_2_X/htdocs/manual/process-model.html new file mode 100644 index 00000000000..c130decffa7 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/process-model.html @@ -0,0 +1,68 @@ + + +Server Pool Management + + + + + +

    Server Pool Management

    + +
    +

    +We found that many people were using values for "MaxServers" either +too high or too low, and were hanging themselves on it. The model we +adopted is still based on long-lived minimal-forking processes, but +instead of specifying one number of persistent processes, the +web-master specifies a maximum and minimum number of processes to be +"spare" - every couple of seconds the parent checks the actual number +of spare servers and adjusts accordingly. This should keep the number +of servers concurrently running relatively low while still ensuring +minimal forking. + +

    + +We renamed the current StartServers to MinSpareServers, created +separate StartServers parameter which means what it says, and renamed +MaxServers to MaxSpareServers (though the old name still works, for +NCSA 1.4 back-compatibility). The old names were generally regarded +as too confusing. + +

    + +The defaults for each variable are: + +

    +MinSpareServers		5
    +MaxSpareServers		10
    +StartServers		5
    +
    + +There is an absolute maximum number of simultaneous children defined +by a compile-time limit which defaults to 256 and a "MaxClients" +directive which specifies the number of simultaneous children that +will be allowed. MaxClients can be adjusted up to the compile-time +limit (HARD_SERVER_LIMIT, defined in httpd.h). If you need more +than 256 simultaneous children, you need to modify both HARD_SERVER_LIMIT +and MaxClients.

    + +In versions before 1.2, HARD_SERVER_LIMIT defaulted to 150.

    + +We do not recommend changing either of these values unless: + +

      +
    1. You know you have the server resources to handle more +
    2. You use the machine for other purposes and must limit the amount of memory +Apache uses +
    + + + + + diff --git a/APACHE_1_2_X/htdocs/manual/stopping.html b/APACHE_1_2_X/htdocs/manual/stopping.html new file mode 100644 index 00000000000..373590a3119 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/stopping.html @@ -0,0 +1,166 @@ + + + +Stopping and Restarting Apache + + + + + +

    Stopping and Restarting Apache

    + +

    You will notice many httpd executables running on your system, +but you should not send signals to any of them except the parent, whose +pid is in the PidFile. That is to +say you shouldn't ever need to send signals to any process except the +parent. There are three signals that you can send the parent: +TERM, HUP, and USR1, which will +be described in a moment. + +

    To send a signal to the parent you should issue a command such as: +

    +    kill -TERM `cat /usr/local/etc/httpd/logs/httpd.pid`
    +
    + +You can read about its progress by issuing: + +
    +    tail -f /usr/local/etc/httpd/logs/error_log
    +
    + +Modify those examples to match your +ServerRoot and +PidFile settings. + +

    TERM Signal: stop now

    + +

    Sending the TERM signal to the parent causes it to +immediately attempt to kill off all of its children. It may take it +several seconds to complete killing off its children. Then the +parent itself exits. Any requests in progress are terminated, and no +further requests are served. + +

    HUP Signal: restart now

    + +

    Sending the HUP signal to the parent causes it to kill off +its children like in TERM but the parent doesn't exit. It +re-reads its configuration files, and re-opens any log files. +Then it spawns a new set of children and continues +serving hits. + +

    Users of the +status module +will notice that the server statistics are +set to zero when a HUP is sent. + +

    Note: If your configuration file has errors in it when you issue a +restart then your parent will not restart, it will exit with an error. +See below for a method of avoiding this. + +

    USR1 Signal: graceful restart

    + +

    Note: prior to release 1.2b9 this code is quite unstable and +shouldn't be used at all. + +

    The USR1 signal causes the parent process to advise +the children to exit after their current request (or to exit immediately +if they're not serving anything). The parent re-reads its configuration +files and re-opens its log files. As each child dies off the parent +replaces it with a child from the new generation of the +configuration, which begins serving new requests immediately. + +

    This code is designed to always respect the +MaxClients, +MinSpareServers, +and MaxSpareServers settings. +Furthermore, it respects StartServers +in the following manner: if after one second at least StartServers new +children have not been created, then create enough to pick up the slack. +This is to say that the code tries to maintain both the number of children +appropriate for the current load on the server, and respect your wishes +with the StartServers parameter. + +

    Users of the +status module +will notice that the server statistics +are not set to zero when a USR1 is sent. The code +was written to both minimize the time in which the server is unable to serve +new requests (they will be queued up by the operating system, so they're +not lost in any event) and to respect your tuning parameters. In order +to do this it has to keep the scoreboard used to keep track +of all children across generations. + +

    The status module will also use a G to indicate those +children which are still serving requests started before the graceful +restart was given. + +

    At present there is no way for a log rotation script using +USR1 to know for certain that all children writing the +pre-restart log have finished. We suggest that you use a suitable delay +after sending the USR1 signal before you do anything with the +old log. For example if most of your hits take less than 10 minutes to +complete for users on low bandwidth links then you could wait 15 minutes +before doing anything with the old log. + +

    Note: If your configuration file has errors in it when you issue a +restart then your parent will not restart, it will exit with an error. +In the case of graceful +restarts it will also leave children running when it exits. (These are +the children which are "gracefully exiting" by handling their last request.) +This will cause problems if you attempt to restart the server -- it will +not be able to bind to its listening ports. At present the only work +around is to check the syntax of your files before doing a restart. The +easiest way is to just run httpd as a non-root user. If there are no +errors it will attempt to open its sockets and logs and fail because it's +not root (or because the currently running httpd already has those ports +bound). If it fails for any other reason then it's probably a config file +error and the error should be fixed before issuing the graceful restart. + +

    Appendix: signals and race conditions

    + +

    Prior to Apache 1.2b9 there were several race conditions +involving the restart and die signals (a simple description of race +condition is: a time-sensitive problem, as in if something happens at just +the wrong time it won't behave as expected). For those architectures that +have the "right" feature set we have eliminated as many as we can. +But it should be noted that there still do exist race conditions on +certain architectures. + +

    Architectures that use an on disk +ScoreBoardFile +have the potential to corrupt their scoreboards. This can result in +the "bind: Address already in use" (after HUP) or +"long lost child came home!" (after USR1). The former is +a fatal error, while the latter just causes the server to lose a scoreboard +slot. So it might be advisable to use graceful restarts, with +an occasional hard restart. These problems are very difficult to work +around, but fortunately most architectures do not require a scoreboard file. +See the ScoreBoardFile documentation for a method to determine if your +architecture uses it. + +

    NEXT and MACHTEN (68k only) have small race +conditions +which can cause a restart/die signal to be lost, but should not cause the +server to do anything otherwise problematic. + + +

    All architectures have a small race condition in each child involving +the second and subsequent requests on a persistent HTTP connection +(KeepAlive). It may exit after reading the request line but before +reading any of the request headers. There is a fix that was discovered +too late to make 1.2. In theory this isn't an issue because the KeepAlive +client has to expect these events because of network latencies and +server timeouts. In practice it doesn't seem to affect anything either +-- in a test case the server was restarted twenty times per second and +clients successfully browsed the site without getting broken images or +empty documents. + + + + diff --git a/APACHE_1_2_X/htdocs/manual/suexec.html b/APACHE_1_2_X/htdocs/manual/suexec.html new file mode 100644 index 00000000000..7806bc8f55c --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/suexec.html @@ -0,0 +1,505 @@ + + + +Apache suEXEC Support + + + + + +

    Apache suEXEC Support

    + +

    +

      + CONTENTS +
    1. What is suEXEC?
    2. +
    3. Before we begin.
    4. +
    5. suEXEC Security Model.
    6. +
    7. Configuring & Installing suEXEC
    8. +
    9. Enabling & Disabling suEXEC
    10. +
    11. Debugging suEXEC
    12. +
    13. Beware the Jabberwock: Warnings & Examples
    14. +
    +

    + +

    What is suEXEC?

    +

    +The suEXEC feature -- introduced in Apache 1.2 -- provides +Apache users the ability to run CGI and SSI +programs under user IDs different from the user ID of the calling web-server. +Normally, when a CGI or SSI program executes, it runs as the same user who is +running the web server. +

    + +

    +Used properly, this feature can reduce considerably the security risks involved +with allowing users to develop and run private CGI or SSI programs. However, +if suEXEC is improperly configured, it can cause any number of problems and +possibly create new holes in your computer's security. If you aren't familiar +with managing setuid root programs and the security issues they present, we +highly recommend that you not consider using suEXEC. +

    + +

    +BACK TO CONTENTS +

    + +

    Before we begin.

    +

    +Before jumping head-first into this document, you should be aware of the +assumptions made on the part of the Apache Group and this document. +

    + +

    +First, it is assumed that you are using a UNIX derivate operating system that +is capable of setuid and setgid operations. +All command examples are given in this regard. Other platforms, if they are +capable of supporting suEXEC, may differ in their configuration. +

    + +

    +Second, it is assumed you are familiar with some basic concepts of your +computer's security and its administration. This involves an understanding +of setuid/setgid operations and the various effects they +may have on your system and its level of security. +

    + +

    +Third, it is assumed that you are using an unmodified +version of suEXEC code. All code for suEXEC has been carefully scrutinized and +tested by the developers as well as numerous beta testers. Every precaution has +been taken to ensure a simple yet solidly safe base of code. Altering this +code can cause unexpected problems and new security risks. It is +highly recommended you not alter the suEXEC code unless you +are well versed in the particulars of security programming and are willing to +share your work with the Apache Group for consideration. +

    + +

    +Fourth, and last, it has been the decision of the Apache Group to +NOT make suEXEC part of the default installation of Apache. +To this end, suEXEC configuration is a manual process requiring of the +administrator careful attention to details. It is through this process +that the Apache Group hopes to limit suEXEC installation only to those +who are determined to use it. +

    + +

    +Still with us? Yes? Good. Let's move on! +

    + +

    +BACK TO CONTENTS +

    + +

    suEXEC Security Model

    +

    +Before we begin configuring and installing suEXEC, we will first discuss +the security model you are about to implement. By doing so, you may +better understand what exactly is going on inside suEXEC and what precautions +are taken to ensure your system's security. +

    + +

    +suEXEC is based on a setuid "wrapper" program that is +called by the main Apache web server. This wrapper is called when an HTTP +request is made for a CGI or SSI program that the administrator has designated +to run as a userid other than that of the main server. When such a request +is made, Apache provides the suEXEC wrapper with the program's name and the +user and group IDs under which the program is to execute. +

    + +

    +The wrapper then employs the following process to determine success or +failure -- if any one of these conditions fail, the program logs the failure +and exits with an error, otherwise it will continue: +

      +
    1. Was the wrapper called with the proper number of arguments? +
      + The wrapper will only execute if it is given the proper number of arguments. + The proper argument format is known to the Apache web server. If the wrapper + is not receiving the proper number of arguments, it is either being hacked, or + there is something wrong with the suEXEC portion of your Apache binary. +
      +
    2. +
    3. Is the user executing this wrapper a valid user of this system? +
      + This is to ensure that the user executing the wrapper is truly a user of the system. +
      +
    4. +
    5. Is this valid user allowed to run the wrapper? +
      + Is this user the user allowed to run this wrapper? Only one user (the Apache + user) is allowed to execute this program. +
      +
    6. +
    7. Does the target program have an unsafe hierarchical reference? +
      + Does the target program contain a leading '/' or have a '..' backreference? These + are not allowed; the target program must reside within the Apache webspace. +
      +
    8. +
    9. Is the target user name valid? +
      + Does the target user exist? +
      +
    10. +
    11. Is the target group name valid? +
      + Does the target group exist? +
      +
    12. +
    13. Is the target user NOT superuser? +
      + Presently, suEXEC does not allow 'root' to execute CGI/SSI programs. +
      +
    14. +
    15. Is the target userid ABOVE the minimum ID number? +
      + The minimum user ID number is specified during configuration. This allows you + to set the lowest possible userid that will be allowed to execute CGI/SSI programs. + This is useful to block out "system" accounts. +
      +
    16. +
    17. Is the target group NOT the superuser group? +
      + Presently, suEXEC does not allow the 'root' group to execute CGI/SSI programs. +
      +
    18. +
    19. Is the target groupid ABOVE the minimum ID number? +
      + The minimum group ID number is specified during configuration. This allows you + to set the lowest possible groupid that will be allowed to execute CGI/SSI programs. + This is useful to block out "system" groups. +
      +
    20. +
    21. Can the wrapper successfully become the target user and group? +
      + Here is where the program becomes the target user and group via setuid and setgid + calls. The group access list is also initialized with all of the groups of which + the user is a member. +
      +
    22. +
    23. Does the directory in which the program resides exist? +
      + If it doesn't exist, it can't very well contain files. +
      +
    24. +
    25. Is the directory within the Apache webspace? +
      + If the request is for a regular portion of the server, is the requested directory + within the server's document root? If the request is for a UserDir, is the requested + directory within the user's document root? +
      +
    26. +
    27. Is the directory NOT writable by anyone else? +
      + We don't want to open up the directory to others; only the owner user may be able + to alter this directories contents. +
      +
    28. +
    29. Does the target program exist? +
      + If it doesn't exists, it can't very well be executed. +
      +
    30. +
    31. Is the target program NOT writable by anyone else? +
      + We don't want to give anyone other than the owner the ability to change the program. +
      +
    32. +
    33. Is the target program NOT setuid or setgid? +
      + We do not want to execute programs that will then change our UID/GID again. +
      +
    34. +
    35. Is the target user/group the same as the program's user/group? +
      + Is the user the owner of the file? +
      +
    36. +
    37. Can we successfully clean the process environment to ensure safe operations? +
      + suEXEC cleans the process' environment by establishing a safe execution PATH (defined + during configuration), as well as only passing through those variables whose names + are listed in the safe environment list (also created during configuration). +
      +
    38. +
    39. Can we successfully become the target program and execute? +
      + Here is where suEXEC ends and the target program begins. +
      +
    40. +
    +

    + +

    +This is the standard operation of the the suEXEC wrapper's security model. +It is somewhat stringent and can impose new limitations and guidelines for +CGI/SSI design, but it was developed carefully step-by-step with security +in mind. +

    + +

    +For more information as to how this security model can limit your possibilities +in regards to server configuration, as well as what security risks can be avoided +with a proper suEXEC setup, see the "Beware the Jabberwock" +section of this document. +

    + +

    +BACK TO CONTENTS +

    + +

    Configuring & Installing suEXEC

    +

    +Here's where we begin the fun. The configuration and installation of suEXEC is +a four step process: edit the suEXEC header file, compile suEXEC, place the +suEXEC binary in its proper location, and configure Apache for use with suEXEC. +

    + +

    +EDITING THE SUEXEC HEADER FILE
    +- From the top-level of the Apache source tree, type:   +cd support [ENTER] +

    + +

    +Edit the suexec.h file and change the following macros to +match your local Apache installation. +

    + +

    +From support/suexec.h +

    +     /*
    +      * HTTPD_USER -- Define as the username under which Apache normally
    +      *               runs.  This is the only user allowed to execute
    +      *               this program.
    +      */
    +     #define HTTPD_USER "www"
    +
    +     /*
    +      * UID_MIN -- Define this as the lowest UID allowed to be a target user
    +      *            for suEXEC.  For most systems, 500 or 100 is common.
    +      */
    +     #define UID_MIN 100
    +
    +     /*
    +      * GID_MIN -- Define this as the lowest GID allowed to be a target group
    +      *            for suEXEC.  For most systems, 100 is common.
    +      */
    +     #define GID_MIN 100
    +
    +     /*
    +      * USERDIR_SUFFIX -- Define to be the subdirectory under users' 
    +      *                   home directories where suEXEC access should
    +      *                   be allowed.  All executables under this directory
    +      *                   will be executable by suEXEC as the user so 
    +      *                   they should be "safe" programs.  If you are 
    +      *                   using a "simple" UserDir directive (ie. one 
    +      *                   without a "*" in it) this should be set to 
    +      *                   the same value.  suEXEC will not work properly
    +      *                   in cases where the UserDir directive points to 
    +      *                   a location that is not the same as the user's
    +      *                   home directory as referenced in the passwd file.
    +      *
    +      *                   If you have VirtualHosts with a different
    +      *                   UserDir for each, you will need to define them to
    +      *                   all reside in one parent directory; then name that
    +      *                   parent directory here.  IF THIS IS NOT DEFINED
    +      *                   PROPERLY, ~USERDIR CGI REQUESTS WILL NOT WORK!
    +      *                   See the suEXEC documentation for more detailed
    +      *                   information.
    +      */
    +     #define USERDIR_SUFFIX "public_html"
    +
    +     /*
    +      * LOG_EXEC -- Define this as a filename if you want all suEXEC
    +      *             transactions and errors logged for auditing and
    +      *             debugging purposes.
    +      */
    +     #define LOG_EXEC "/usr/local/etc/httpd/logs/cgi.log" /* Need me? */
    +
    +     /*
    +      * DOC_ROOT -- Define as the DocumentRoot set for Apache.  This
    +      *             will be the only hierarchy (aside from UserDirs)
    +      *             that can be used for suEXEC behavior.
    +      */
    +     #define DOC_ROOT "/usr/local/etc/httpd/htdocs"
    +
    +     /*
    +      * SAFE_PATH -- Define a safe PATH environment to pass to CGI executables.
    +      *
    +      */
    +     #define SAFE_PATH "/usr/local/bin:/usr/bin:/bin"
    +
    +

    + +

    +COMPILING THE SUEXEC WRAPPER
    +You now need to compile the suEXEC wrapper. At the shell command prompt, +type:  cc suexec.c -o suexec [ENTER]. +This should create the suexec wrapper executable. +

    + +

    +COMPILING APACHE FOR USE WITH SUEXEC
    +By default, Apache is compiled to look for the suEXEC wrapper in the following +location. +

    + +

    +From src/httpd.h +

    +     /* The path to the suEXEC wrapper */
    +     #define SUEXEC_BIN "/usr/local/etc/httpd/sbin/suexec"
    +
    +

    + +

    +If your installation requires location of the wrapper program in a different +directory, edit src/httpd.h and recompile your Apache server. +See Compiling and Installing Apache for more +info on this process. +

    + +

    +COPYING THE SUEXEC BINARY TO ITS PROPER LOCATION
    +Copy the suexec executable created in the +exercise above to the defined location for SUEXEC_BIN. +

    + +

    +cp suexec /usr/local/etc/httpd/sbin/suexec [ENTER] +

    + +

    +In order for the wrapper to set the user ID, it must me installed as owner +root and must have the setuserid execution bit +set for file modes. If you are not running a root +user shell, do so now and execute the following commands. +

    + +

    +chown root /usr/local/etc/httpd/sbin/suexec [ENTER]
    +chmod 4711 /usr/local/etc/httpd/sbin/suexec [ENTER] +

    + +

    +BACK TO CONTENTS +

    + +

    Enabling & Disabling suEXEC

    +

    +After properly installing the suexec wrapper +executable, you must kill and restart the Apache server. A simple +kill -1 `cat httpd.pid` will not be enough. +Upon startup of the web-server, if Apache finds a properly configured +suexec wrapper, it will print the following message to +the console: +

    + +

    +Configuring Apache for use with suexec wrapper. +

    + +

    +If you don't see this message at server startup, the server is most +likely not finding the wrapper program where it expects it, or the +executable is not installed setuid root. Check +your installation and try again. +

    + +

    +One way to use suEXEC is through the +User and +Group directives in +VirtualHost +definitions. By setting these directives to values different from the +main server user ID, all requests for CGI resources will be executed as +the User and Group defined for that +<VirtualHost>. If only one or +neither of these directives are specified for a +<VirtualHost> then the main +server userid is assumed.

    + +suEXEC can also be used to to execute CGI programs as +the user to which the request is being directed. This is accomplished by +using the ~ character prefixing the user ID for whom +execution is desired. +The only requirement needed for this feature to work is for CGI +execution to be enabled for the user and that the script must meet the +scrutiny of the security checks above. + +

    +BACK TO CONTENTS +

    + +

    Debugging suEXEC

    +

    +The suEXEC wrapper will write log information to the location defined in +the suexec.h as indicated above. If you feel you have +configured and installed the wrapper properly, have a look at this log +and the error_log for the server to see where you may have gone astray. +

    + +

    +BACK TO CONTENTS +

    + +

    Beware the Jabberwock: Warnings & Examples

    +

    +NOTE! This section may not be complete. For the latest +revision of this section of the documentation, see the Apache Group's +Online Documentation +version. +

    + +

    +There are a few points of interest regarding the wrapper that can cause +limitations on server setup. Please review these before submitting any +"bugs" regarding suEXEC. +

      + suEXEC Points Of Interest +
    • Hierarchy limitations +
      + For security and efficiency reasons, all suexec requests must + remain within either a top-level document root for virtual + host requests, or one top-level personal document root for + userdir requests. For example, if you have four VirtualHosts + configured, you would need to structure all of your VHosts' + document roots off of one main Apache document hierarchy to + take advantage of suEXEC for VirtualHosts. (Example forthcoming.) +
      +
    • +
    • suEXEC's PATH environment variable +
      + This can be a dangerous thing to change. Make certain every + path you include in this define is a trusted + directory. You don't want to open people up to having someone + from across the world running a trojan horse on them. +
      +
    • +
    • Altering the suEXEC code +
      + Again, this can cause Big Trouble if you try + this without knowing what you are doing. Stay away from it + if at all possible. +
      +
    • +
    + +

    +BACK TO CONTENTS +

    + + + + diff --git a/APACHE_1_2_X/htdocs/manual/unixware.html b/APACHE_1_2_X/htdocs/manual/unixware.html new file mode 100644 index 00000000000..eb8adbe2fe8 --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/unixware.html @@ -0,0 +1,61 @@ + + + +Compiling Apache under UnixWare + + + + + + +

    Compiling Apache under UnixWare

    + +To compile a working copy of Apache under UnixWare, there are several other +steps you may need to take. These prevent such problems as zombie processes, +bind errors, and accept errors, to name a few. + +

    UnixWare 1.x

    + +Make sure that USE_FCNTL_SERIALIZE_ACCEPT is defined (if not +defined by Apache autoconfiguration). If using the UnixWare cc +compiler, and you still see accept() errors, don't use compiler optimization, +or get gcc. + +

    UnixWare 2.0.x

    + +SCO patch tf2163 is required +in order for Apache to work correctly on UnixWare 2.0.x. See +http://www.sco.com +for UnixWare patch information.

    + +In addition, make sure that USE_FCNTL_SERIALIZE_ACCEPT is defined (if not +defined by Apache autoconfiguration). To reduce instances of connections +in FIN_WAIT_2 state, you may also want to define NO_LINGCLOSE (Apache 1.2 +only). + +

    UnixWare 2.1.x

    + +SCO patch ptf3123 is required +in order for Apache to work correctly on UnixWare 2.1.x. See +http://www.sco.com +for UnixWare patch information.

    + +NOTE: Unixware 2.1.2 and later already have patch ptf3123 included

    + +In addition, make sure that USE_FCNTL_SERIALIZE_ACCEPT is defined (if not +defined by Apache autoconfiguration). To reduce instances of connections +in FIN_WAIT_2 state, you may also want to define NO_LINGCLOSE (Apache 1.2 +only).

    + +Thanks to Joe Doupnik <JRD@cc.usu.edu> and Rich Vaughn +<rvaughn@aad.com> for additional info for UnixWare builds.

    + + + + diff --git a/APACHE_1_2_X/htdocs/manual/vhosts-in-depth.html b/APACHE_1_2_X/htdocs/manual/vhosts-in-depth.html new file mode 100644 index 00000000000..4e078128a0f --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/vhosts-in-depth.html @@ -0,0 +1,382 @@ + + +An In-Depth Discussion of VirtualHost Matching + + + + + +

    An In-Depth Discussion of VirtualHost Matching

    + +

    This is a very rough document that was probably out of date the moment +it was written. It attempts to explain exactly what the code does when +deciding what virtual host to serve a hit from. It's provided on the +assumption that something is better than nothing. The server version +under discussion is Apache 1.2. + +

    If you just want to "make it work" without understanding +how, there's a What Works section at the bottom. + +

    Config File Parsing

    + +

    There is a main_server which consists of all the definitions appearing +outside of VirtualHost sections. There are virtual servers, +called vhosts, which are defined by +VirtualHost +sections. + +

    The directives +Port, +ServerName, +ServerPath, +and +ServerAlias +can appear anywhere within the definition of +a server. However, each appearance overrides the previous appearance +(within that server). + +

    The default value of the Port field for main_server +is 80. The main_server has no default ServerName, +ServerPath, or ServerAlias. + +

    In the absence of any +Listen +directives, the (final if there +are multiple) Port directive in the main_server indicates +which port httpd will listen on. + +

    The Port and ServerName directives for +any server main or virtual are used when generating URLs such as during +redirects. + +

    Each address appearing in the VirtualHost directive +can have an optional port. If the port is unspecified it defaults to +the value of the main_server's most recent Port statement. +The special port * indicates a wildcard that matches any port. +Collectively the entire set of addresses (including multiple +A record +results from DNS lookups) are called the vhost's address set. + +

    The magic _default_ address has significance during +the matching algorithm. It essentially matches any unspecified address. + +

    After parsing the VirtualHost directive, the vhost server +is given a default Port equal to the port assigned to the +first name in its VirtualHost directive. The complete +list of names in the VirtualHost directive are treated +just like a ServerAlias (but are not overridden by any +ServerAlias statement). Note that subsequent Port +statements for this vhost will not affect the ports assigned in the +address set. + +

    +All vhosts are stored in a list which is in the reverse order that +they appeared in the config file. For example, if the config file is: + +

    +    <VirtualHost A>
    +    ...
    +    </VirtualHost>
    +
    +    <VirtualHost B>
    +    ...
    +    </VirtualHost>
    +
    +    <VirtualHost C>
    +    ...
    +    </VirtualHost>
    +
    + +Then the list will be ordered: main_server, C, B, A. Keep this in mind. + +

    +After parsing has completed, the list of servers is scanned, and various +merges and default values are set. In particular: + +

      +
    1. If a vhost has no + ServerAdmin, + ResourceConfig, + AccessConfig, + Timeout, + KeepAliveTimeout, + KeepAlive, + MaxKeepAliveRequests, + or + SendBufferSize + directive then the respective value is + inherited from the main_server. (That is, inherited from whatever + the final setting of that value is in the main_server.) + +
    2. The "lookup defaults" that define the default directory + permissions + for a vhost are merged with those of the main server. This includes + any per-directory configuration information for any module. + +
    3. The per-server configs for each module from the main_server are + merged into the vhost server. +
    + +Essentially, the main_server is treated as "defaults" or a +"base" on +which to build each vhost. But the positioning of these main_server +definitions in the config file is largely irrelevant -- the entire +config of the main_server has been parsed when this final merging occurs. +So even if a main_server definition appears after a vhost definition +it might affect the vhost definition. + +

    If the main_server has no ServerName at this point, +then the hostname of the machine that httpd is running on is used +instead. We will call the main_server address set those IP +addresses returned by a DNS lookup on the ServerName of +the main_server. + +

    Now a pass is made through the vhosts to fill in any missing +ServerName fields and to classify the vhost as either +an IP-based vhost or a name-based vhost. A vhost is +considered a name-based vhost if any of its address set overlaps the +main_server (the port associated with each address must match the +main_server's Port). Otherwise it is considered an IP-based +vhost. + +

    For any undefined ServerName fields, a name-based vhost +defaults to the address given first in the VirtualHost +statement defining the vhost. Any vhost that includes the magic +_default_ wildcard is given the same ServerName as +the main_server. Otherwise the vhost (which is necessarily an IP-based +vhost) is given a ServerName based on the result of a reverse +DNS lookup on the first address given in the VirtualHost +statement. + +

    + +

    Vhost Matching

    + +

    +The server determines which vhost to use for a request as follows: + +

    find_virtual_server: When the connection is first made +by the client, the local IP address (the IP address to which the client +connected) is looked up in the server list. A vhost is matched if it +is an IP-based vhost, the IP address matches and the port matches +(taking into account wildcards). + +

    If no vhosts are matched then the last occurrence, if it appears, +of a _default_ address (which if you recall the ordering of the +server list mentioned above means that this would be the first occurrence +of _default_ in the config file) is matched. + +

    In any event, if nothing above has matched, then the main_server is +matched. + +

    The vhost resulting from the above search is stored with data +about the connection. We'll call this the connection vhost. +The connection vhost is constant over all requests in a particular TCP/IP +session -- that is, over all requests in a KeepAlive/persistent session. + +

    For each request made on the connection the following sequence of +events further determines the actual vhost that will be used to serve +the request. + +

    check_fulluri: If the requestURI is an absoluteURI, that +is it includes http://hostname/, then an attempt is made to +determine if the hostname's address (and optional port) match that of +the connection vhost. If it does then the hostname portion of the URI +is saved as the request_hostname. If it does not match, then the +URI remains untouched. Note: to achieve this address +comparison, +the hostname supplied goes through a DNS lookup unless it matches the +ServerName or the local IP address of the client's socket. + +

    parse_uri: If the URI begins with a protocol +(i.e., http:, ftp:) then the request is +considered a proxy request. Note that even though we may have stripped +an http://hostname/ in the previous step, this could still +be a proxy request. + +

    read_request: If the request does not have a hostname +from the earlier step, then any Host: header sent by the +client is used as the request hostname. + +

    check_hostalias: If the request now has a hostname, +then an attempt is made to match for this hostname. The first step +of this match is to compare any port, if one was given in the request, +against the Port field of the connection vhost. If there's +a mismatch then the vhost used for the request is the connection vhost. +(This is a bug, see observations.) + +

    +If the port matches, then httpd scans the list of vhosts starting with +the next server after the connection vhost. This scan does not +stop if there are any matches, it goes through all possible vhosts, +and in the end uses the last match it found. The comparisons performed +are as follows: + +

      +
    • Compare the request hostname:port with the vhost + ServerName and Port. + +
    • Compare the request hostname against any and all addresses given in + the VirtualHost directive for this vhost. + +
    • Compare the request hostname against the ServerAlias + given for the vhost. +
    + +

    +check_serverpath: If the request has no hostname +(back up a few paragraphs) then a scan similar to the one +in check_hostalias is performed to match any +ServerPath directives given in the vhosts. Note that the +last match is used regardless (again consider the ordering of +the virtual hosts). + +

    Observations

    + +
      + +
    • It is difficult to define an IP-based vhost for the machine's + "main IP address". You essentially have to create a bogus + ServerName for the main_server that does not match the + machine's IPs. + +
    • During the scans in both check_hostalias and + check_serverpath no check is made that the vhost being + scanned is actually a name-based vhost. This means, for example, that + it's possible to match an IP-based vhost through another address. But + because the scan starts in the vhost list at the first vhost that + matched the local IP address of the connection, not all IP-based vhosts + can be matched. + +

      Consider the config file above with three vhosts A, B, C. Suppose + that B is a named-based vhost, and A and C are IP-based vhosts. If + a request comes in on B or C's address containing a header + "Host: A" then + it will be served from A's config. If a request comes in on A's + address then it will always be served from A's config regardless of + any Host: header. +

      + +
    • Unless you have a _default_ vhost, + it doesn't matter if you mix name-based vhosts in amongst IP-based + vhosts. During the find_virtual_server phase above no + named-based vhost will be matched, so the main_server will remain the + connection vhost. Then scans will cover all vhosts in the vhost list. + +

      If you do have a _default_ vhost, then you cannot place + named-based vhosts after it in the config. This is because on any + connection to the main server IPs the connection vhost will always be + the _default_ vhost since none of the name-based are + considered during find_virtual_server. +

      + +
    • You should never specify DNS names in VirtualHost + directives because it will force your server to rely on DNS to boot. + Furthermore it poses a security threat if you do not control the + DNS for all the domains listed. + + There's more information + available on this and the next two topics.

      + +
    • ServerName should always be set for each vhost. Otherwise + A DNS lookup is required for each vhost.

      + +
    • A DNS lookup is always required for the main_server's + ServerName (or to generate that if it isn't specified + in the config).

      + +
    • If a ServerPath directive exists which is a prefix of + another ServerPath directive that appears later in + the configuration file, then the former will always be matched + and the latter will never be matched. (That is assuming that no + Host header was available to disambiguate the two.)

      + +
    • If a vhost that would otherwise be a name-vhost includes a + Port statement that doesn't match the main_server + Port then it will be considered an IP-based vhost. + Then find_virtual_server will match it (because + the ports associated with each address in the address set default + to the port of the main_server) as the connection vhost. Then + check_hostalias will refuse to check any other name-based + vhost because of the port mismatch. The result is that the vhost + will steal all hits going to the main_server address.

      + +
    • If two IP-based vhosts have an address in common, the vhost appearing + later in the file is always matched. Such a thing might happen + inadvertently. If the config has name-based vhosts and for some reason + the main_server ServerName resolves to the wrong address + then all the name-based vhosts will be parsed as ip-based vhosts. + Then the last of them will steal all the hits.

      + +
    • The last name-based vhost in the config is always matched for any hit + which doesn't match one of the other name-based vhosts.

      + +
    + +

    What Works

    + +

    In addition to the tips on the DNS +Issues page, here are some further tips: + +

      + +
    • Place all main_server definitions before any VirtualHost definitions. +(This is to aid the readability of the configuration -- the post-config +merging process makes it non-obvious that definitions mixed in around +virtualhosts might affect all virtualhosts.)

      + +
    • Arrange your VirtualHosts such +that all name-based virtual hosts come first, followed by IP-based +virtual hosts, followed by any _default_ virtual host

      + +
    • Avoid ServerPaths which are prefixes of other +ServerPaths. If you cannot avoid this then you have to +ensure that the longer (more specific) prefix vhost appears earlier in +the configuration file than the shorter (less specific) prefix +(i.e., "ServerPath /abc" should appear after +"ServerPath /abcdef").

      + +
    • Do not use port-based vhosts in the same server as +name-based vhosts. A loose definition for port-based is a vhost which +is determined by the port on the server (i.e. one server with +ports 8000, 8080, and 80 all of which have different configurations).

      + +
    + + + + diff --git a/APACHE_1_2_X/htdocs/manual/virtual-host.html b/APACHE_1_2_X/htdocs/manual/virtual-host.html new file mode 100644 index 00000000000..6bfa8fb626c --- /dev/null +++ b/APACHE_1_2_X/htdocs/manual/virtual-host.html @@ -0,0 +1,204 @@ + + + +Apache Server Virtual Host Support + + + + + +

    Virtual Host Support

    + +See Also: +Non-IP based virtual hosts + +

    What are virtual hosts?

    +This is the ability of a single machine to be a web server for multiple +domains. For example, an Internet service provider might have a machine +called www.serve.com which provides Web space for several +organizations including, say, smallco and baygroup. +Ordinarily, these groups would be given parts of the Web tree on www.serve.com. +So smallco's home page would have the URL +
    +http://www.serve.com/smallco/ +
    +and baygroup's home page would have the URL +
    +http://www.serve.com/baygroup/ +
    +

    +For esthetic reasons, however, both organizations would rather their home +pages appeared under their own names rather than that of the service +provider's; but they do not want to set up their own Internet links and +servers. +

    +Virtual hosts are the solution to this problem. smallco and baygroup would +have their own Internet name registrations, www.smallco.com and +www.baygroup.org respectively. These hostnames would both +correspond to the service provider's machine (www.serve.com). Thus +smallco's home page would now have the URL +

    +http://www.smallco.com/ +
    +and baygroup's home page would would have the URL +
    +http://www.baygroup.org/ +
    + +

    System requirements

    +Due to limitations in the HTTP/1.0 protocol, the web server must have a +different IP address for each virtual host. This can be achieved +by the machine having several physical network connections, or by use +of a virtual interface on some operating systems. + +

    How to set up Apache

    +There are two ways of configuring apache to support multiple hosts. +Either by running a separate httpd daemon for each hostname, or by running a +single daemon which supports all the virtual hosts. +

    +Use multiple daemons when: +

      +
    • The different virtual hosts need very different httpd configurations, such + as different values for: ServerType, + User, + Group, + TypesConfig or + ServerRoot. +
    • The machine does not process a very high request rate. +
    +Use a single daemon when: +
      +
    • Sharing of the httpd configuration between virtual hosts is acceptable. +
    • The machine services a large number of requests, and so the performance + loss in running separate daemons may be significant. +
    + +

    Setting up multiple daemons

    +Create a separate httpd installation for each virtual host. +For each installation, use the +BindAddress directive in the configuration +file to select which IP address (or virtual host) that daemon services. +e.g. +
    BindAddress www.smallco.com
    +This hostname can also be given as an IP address. + +

    Setting up a single daemon

    +For this case, a single httpd will service requests for all the virtual hosts. +The VirtualHost directive in the + configuration file is used to set the values of +ServerAdmin, +ServerName, +DocumentRoot, +ErrorLog and +TransferLog configuration +directives to different values for each virtual host. +e.g. +
    +<VirtualHost www.smallco.com>
    +ServerAdmin webmaster@mail.smallco.com
    +DocumentRoot /groups/smallco/www
    +ServerName www.smallco.com
    +ErrorLog /groups/smallco/logs/error_log
    +TransferLog /groups/smallco/logs/access_log
    +</VirtualHost>
    +
    +<VirtualHost www.baygroup.org>
    +ServerAdmin webmaster@mail.baygroup.org
    +DocumentRoot /groups/baygroup/www
    +ServerName www.baygroup.org
    +ErrorLog /groups/baygroup/logs/error_log
    +TransferLog /groups/baygroup/logs/access_log
    +</VirtualHost>
    +
    + +This VirtualHost hostnames can also be given as IP addresses. + +

    + +Almost ANY configuration directive can be put +in the VirtualHost directive, with the exception of +ServerType, +User, +Group, +StartServers, +MaxSpareServers, +MinSpareServers, +MaxRequestsPerChild, +BindAddress, +PidFile, +TypesConfig, and +ServerRoot. + +

    + +SECURITY: When specifying where to write log files, be aware +of some security risks which are present if anyone other than the +user that starts Apache has write access to the directory where they +are written. See the security +tips document for details. + +

    + +

    File Handle/Resource Limits:

    +When using a large number of Virtual Hosts, Apache may run out of available +file descriptors if each Virtual Host specifies different log files. +The total number of file descriptors used by Apache is one for each distinct +error log file, one for every other log file directive, plus 10-20 for +internal use. Unix operating systems limit the number of file descriptors that +may be used by a process; the limit is typically 64, and may usually be +increased up to a large hard-limit. +

    +Although Apache attempts to increase the limit as required, this +may not work if: +

      +
    1. Your system does not provide the setrlimit() system call. +
    2. The setrlimit(RLIMIT_NOFILE) call does not function on your system + (such as Solaris 2.3) +
    3. The number of file descriptors required exceeds the hard limit. +
    4. Your system imposes other limits on file descriptors, such as a limit +on stdio streams only using file descriptors below 256. (Solaris 2) +
    + +In the event of problems you can: +
      +
    • Reduce the number of log files; don't specify log files in the VirtualHost +sections, but only log to the main log files. +
    • If you system falls into 1 or 2 (above), then increase the file descriptor +limit before starting Apache, using a script like +
      +#!/bin/sh
      +ulimit -S -n 100
      +exec httpd
      +
    + +The have been reports that Apache may start running out of resources allocated +for the root process. This will exhibit itself as errors in the error log like +"unable to fork". There are two ways you can bump this up: + +
      +
    1. Have a csh script wrapper around httpd which sets the +"rlimit" to some large number, like 512. +
    2. Edit http_main.c to add calls to setrlimit() from main(), along the lines of +
      +	struct rlimit rlp;
      +
      +	rlp.rlim_cur = rlp.rlim_max = 512;
      +        if (setrlimit(RLIMIT_NPROC, &rlp)) {
      +            fprintf(stderr, "setrlimit(RLIMIT_NPROC) failed.\n");
      +            exit(1);
      +        }
      +
      +(thanks to "Aaron Gifford <agifford@InfoWest.COM>" for the patch) +
    + +The latter will probably manifest itself in a later version of Apache. + + + + diff --git a/APACHE_1_2_X/icons/README b/APACHE_1_2_X/icons/README new file mode 100644 index 00000000000..a1fc5a5a9c7 --- /dev/null +++ b/APACHE_1_2_X/icons/README @@ -0,0 +1,161 @@ +Public Domain Icons + + These icons were originally made for Mosaic for X and have been + included in the NCSA httpd and Apache server distributions in the + past. They are in the public domain and may be freely included in any + application. The originals were done by Kevin Hughes (kevinh@eit.com). + + Many thanks to Andy Polyakov for tuning the icon colors and adding a + few new images. If you'd like to contribute additions or ideas to + this set, please let me know. + + The distribution site for these icons is at: + + http://www.eit.com/goodies/www.icons/ + + Kevin Hughes + September 11, 1995 + + +Suggested Uses + +The following are a few suggestions, to serve as a starting point for ideas. +Please feel free to tweak and rename the icons as you like. + + a.gif + This might be used to represent PostScript or text layout + languages. + + alert.black.gif, alert.red.gif + These can be used to highlight any important items, such as a + README file in a directory. + + back.gif, forward.gif + These can be used as links to go to previous and next areas. + + ball.gray.gif, ball.red.gif + These might be used as bullets. + + binary.gif + This can be used to represent binary files. + + binhex.gif + This can represent BinHex-encoded data. + + blank.gif + This can be used as a placeholder or a spacing element. + + bomb.gif + This can be used to repreesnt core files. + + box1.gif, box2.gif + These icons can be used to represent generic 3D applications and + related files. + + broken.gif + This can represent corrupted data. + + burst.gif + This can call attention to new and important items. + + c.gif + This might represent C source code. + + comp.blue.gif, comp.red.gif + These little computer icons can stand for telnet or FTP + sessions. + + compressed.gif + This may represent compressed data. + + continued.gif + This can be a link to a continued listing of a directory. + + down.gif, up.gif, left.gif, right.gif + These can be used to scroll up, down, left and right in a + listing or may be used to denote items in an outline. + + dvi.gif + This can represent DVI files. + + f.gif + This might represent FORTRAN or Forth source code. + + folder.gif, folder.open.gif, folder.sec.gif + The folder can represent directories. There is also a version + that can represent secure directories or directories that cannot + be viewed. + + generic.gif, generic.sec.gif, generic.red.gif + These can represent generic files, secure files, and important + files, respectively. + + hand.right.gif, hand.up.gif + These can point out important items (pun intended). + + image1.gif, image2.gif, image3.gif + These can represent image formats of various types. + + index.gif + This might represent a WAIS index or search facility. + + layout.gif + This might represent files and formats that contain graphics as + well as text layout, such as HTML and PDF files. + + link.gif + This might represent files that are symbolic links. + + movie.gif + This can represent various movie formats. + + p.gif + This may stand for Perl or Python source code. + + pie0.gif ... pie8.gif + These icons can be used in applications where a list of + documents is returned from a search. The little pie chart images + can denote how relevant the documents may be to your search + query. + + patch.gif + This may stand for patches and diff files. + + portal.gif + This might be a link to an online service or a 3D world. + + ps.gif, quill.gif + These may represent PostScript files. + + screw1.gif, screw2.gif + These may represent CAD or engineering data and formats. + + script.gif + This can represent any of various interpreted languages, such as + Perl, python, TCL, and shell scripts, as well as server + configuration files. + + sound1.gif, sound2.gif + These can represent sound files. + + sphere1.gif, sphere2.gif + These can represent 3D worlds or rendering applications and + formats. + + tex.gif + This can represent TeX files. + + text.gif + This can represent generic (plain) text files. + + transfer.gif + This can represent FTP transfers or uploads/downloads. + + unknown.gif + This may represent a file of an unknown type. + + uuencoded.gif + This can stand for uuencoded data. + + world1.gif, world2.gif + These can represent 3D worlds or other 3D formats. diff --git a/APACHE_1_2_X/icons/a.gif b/APACHE_1_2_X/icons/a.gif new file mode 100644 index 00000000000..bb23d971f4c Binary files /dev/null and b/APACHE_1_2_X/icons/a.gif differ diff --git a/APACHE_1_2_X/icons/alert.black.gif b/APACHE_1_2_X/icons/alert.black.gif new file mode 100644 index 00000000000..eaecd2172a0 Binary files /dev/null and b/APACHE_1_2_X/icons/alert.black.gif differ diff --git a/APACHE_1_2_X/icons/alert.red.gif b/APACHE_1_2_X/icons/alert.red.gif new file mode 100644 index 00000000000..a4238940433 Binary files /dev/null and b/APACHE_1_2_X/icons/alert.red.gif differ diff --git a/APACHE_1_2_X/icons/apache_pb.gif b/APACHE_1_2_X/icons/apache_pb.gif new file mode 100644 index 00000000000..3a1c139fc42 Binary files /dev/null and b/APACHE_1_2_X/icons/apache_pb.gif differ diff --git a/APACHE_1_2_X/icons/back.gif b/APACHE_1_2_X/icons/back.gif new file mode 100644 index 00000000000..a694ae1ec3f Binary files /dev/null and b/APACHE_1_2_X/icons/back.gif differ diff --git a/APACHE_1_2_X/icons/ball.gray.gif b/APACHE_1_2_X/icons/ball.gray.gif new file mode 100644 index 00000000000..eb84268c4cc Binary files /dev/null and b/APACHE_1_2_X/icons/ball.gray.gif differ diff --git a/APACHE_1_2_X/icons/ball.red.gif b/APACHE_1_2_X/icons/ball.red.gif new file mode 100644 index 00000000000..a8425cb574b Binary files /dev/null and b/APACHE_1_2_X/icons/ball.red.gif differ diff --git a/APACHE_1_2_X/icons/binary.gif b/APACHE_1_2_X/icons/binary.gif new file mode 100644 index 00000000000..9a15cbae04c Binary files /dev/null and b/APACHE_1_2_X/icons/binary.gif differ diff --git a/APACHE_1_2_X/icons/binhex.gif b/APACHE_1_2_X/icons/binhex.gif new file mode 100644 index 00000000000..62d0363108d Binary files /dev/null and b/APACHE_1_2_X/icons/binhex.gif differ diff --git a/APACHE_1_2_X/icons/blank.gif b/APACHE_1_2_X/icons/blank.gif new file mode 100644 index 00000000000..0ccf01e1983 Binary files /dev/null and b/APACHE_1_2_X/icons/blank.gif differ diff --git a/APACHE_1_2_X/icons/bomb.gif b/APACHE_1_2_X/icons/bomb.gif new file mode 100644 index 00000000000..270fdb1c064 Binary files /dev/null and b/APACHE_1_2_X/icons/bomb.gif differ diff --git a/APACHE_1_2_X/icons/box1.gif b/APACHE_1_2_X/icons/box1.gif new file mode 100644 index 00000000000..65dcd002eaf Binary files /dev/null and b/APACHE_1_2_X/icons/box1.gif differ diff --git a/APACHE_1_2_X/icons/box2.gif b/APACHE_1_2_X/icons/box2.gif new file mode 100644 index 00000000000..c43bc4faecf Binary files /dev/null and b/APACHE_1_2_X/icons/box2.gif differ diff --git a/APACHE_1_2_X/icons/broken.gif b/APACHE_1_2_X/icons/broken.gif new file mode 100644 index 00000000000..9f8cbe9f760 Binary files /dev/null and b/APACHE_1_2_X/icons/broken.gif differ diff --git a/APACHE_1_2_X/icons/burst.gif b/APACHE_1_2_X/icons/burst.gif new file mode 100644 index 00000000000..fbdcf575f78 Binary files /dev/null and b/APACHE_1_2_X/icons/burst.gif differ diff --git a/APACHE_1_2_X/icons/c.gif b/APACHE_1_2_X/icons/c.gif new file mode 100644 index 00000000000..7555b6c164f Binary files /dev/null and b/APACHE_1_2_X/icons/c.gif differ diff --git a/APACHE_1_2_X/icons/comp.blue.gif b/APACHE_1_2_X/icons/comp.blue.gif new file mode 100644 index 00000000000..f8d76a8c23f Binary files /dev/null and b/APACHE_1_2_X/icons/comp.blue.gif differ diff --git a/APACHE_1_2_X/icons/comp.gray.gif b/APACHE_1_2_X/icons/comp.gray.gif new file mode 100644 index 00000000000..7664cd03649 Binary files /dev/null and b/APACHE_1_2_X/icons/comp.gray.gif differ diff --git a/APACHE_1_2_X/icons/compressed.gif b/APACHE_1_2_X/icons/compressed.gif new file mode 100644 index 00000000000..39e732739f5 Binary files /dev/null and b/APACHE_1_2_X/icons/compressed.gif differ diff --git a/APACHE_1_2_X/icons/continued.gif b/APACHE_1_2_X/icons/continued.gif new file mode 100644 index 00000000000..b0ffb7e0cc0 Binary files /dev/null and b/APACHE_1_2_X/icons/continued.gif differ diff --git a/APACHE_1_2_X/icons/dir.gif b/APACHE_1_2_X/icons/dir.gif new file mode 100644 index 00000000000..48264601ae0 Binary files /dev/null and b/APACHE_1_2_X/icons/dir.gif differ diff --git a/APACHE_1_2_X/icons/down.gif b/APACHE_1_2_X/icons/down.gif new file mode 100644 index 00000000000..a354c871cd0 Binary files /dev/null and b/APACHE_1_2_X/icons/down.gif differ diff --git a/APACHE_1_2_X/icons/dvi.gif b/APACHE_1_2_X/icons/dvi.gif new file mode 100644 index 00000000000..791be33105d Binary files /dev/null and b/APACHE_1_2_X/icons/dvi.gif differ diff --git a/APACHE_1_2_X/icons/f.gif b/APACHE_1_2_X/icons/f.gif new file mode 100644 index 00000000000..fbe353c2822 Binary files /dev/null and b/APACHE_1_2_X/icons/f.gif differ diff --git a/APACHE_1_2_X/icons/folder.gif b/APACHE_1_2_X/icons/folder.gif new file mode 100644 index 00000000000..48264601ae0 Binary files /dev/null and b/APACHE_1_2_X/icons/folder.gif differ diff --git a/APACHE_1_2_X/icons/folder.open.gif b/APACHE_1_2_X/icons/folder.open.gif new file mode 100644 index 00000000000..30979cb5285 Binary files /dev/null and b/APACHE_1_2_X/icons/folder.open.gif differ diff --git a/APACHE_1_2_X/icons/folder.sec.gif b/APACHE_1_2_X/icons/folder.sec.gif new file mode 100644 index 00000000000..75332d9e59b Binary files /dev/null and b/APACHE_1_2_X/icons/folder.sec.gif differ diff --git a/APACHE_1_2_X/icons/forward.gif b/APACHE_1_2_X/icons/forward.gif new file mode 100644 index 00000000000..b2959b4c85c Binary files /dev/null and b/APACHE_1_2_X/icons/forward.gif differ diff --git a/APACHE_1_2_X/icons/generic.gif b/APACHE_1_2_X/icons/generic.gif new file mode 100644 index 00000000000..de60b2940f9 Binary files /dev/null and b/APACHE_1_2_X/icons/generic.gif differ diff --git a/APACHE_1_2_X/icons/generic.red.gif b/APACHE_1_2_X/icons/generic.red.gif new file mode 100644 index 00000000000..94743981d93 Binary files /dev/null and b/APACHE_1_2_X/icons/generic.red.gif differ diff --git a/APACHE_1_2_X/icons/generic.sec.gif b/APACHE_1_2_X/icons/generic.sec.gif new file mode 100644 index 00000000000..88d5240c3c3 Binary files /dev/null and b/APACHE_1_2_X/icons/generic.sec.gif differ diff --git a/APACHE_1_2_X/icons/hand.right.gif b/APACHE_1_2_X/icons/hand.right.gif new file mode 100644 index 00000000000..5cdbc7206da Binary files /dev/null and b/APACHE_1_2_X/icons/hand.right.gif differ diff --git a/APACHE_1_2_X/icons/hand.up.gif b/APACHE_1_2_X/icons/hand.up.gif new file mode 100644 index 00000000000..85a5d683177 Binary files /dev/null and b/APACHE_1_2_X/icons/hand.up.gif differ diff --git a/APACHE_1_2_X/icons/icon.sheet.gif b/APACHE_1_2_X/icons/icon.sheet.gif new file mode 100644 index 00000000000..ad1686e4480 Binary files /dev/null and b/APACHE_1_2_X/icons/icon.sheet.gif differ diff --git a/APACHE_1_2_X/icons/image1.gif b/APACHE_1_2_X/icons/image1.gif new file mode 100644 index 00000000000..01e442bfa92 Binary files /dev/null and b/APACHE_1_2_X/icons/image1.gif differ diff --git a/APACHE_1_2_X/icons/image2.gif b/APACHE_1_2_X/icons/image2.gif new file mode 100644 index 00000000000..751faeea364 Binary files /dev/null and b/APACHE_1_2_X/icons/image2.gif differ diff --git a/APACHE_1_2_X/icons/image3.gif b/APACHE_1_2_X/icons/image3.gif new file mode 100644 index 00000000000..4f30484ff64 Binary files /dev/null and b/APACHE_1_2_X/icons/image3.gif differ diff --git a/APACHE_1_2_X/icons/index.gif b/APACHE_1_2_X/icons/index.gif new file mode 100644 index 00000000000..162478fb3a7 Binary files /dev/null and b/APACHE_1_2_X/icons/index.gif differ diff --git a/APACHE_1_2_X/icons/layout.gif b/APACHE_1_2_X/icons/layout.gif new file mode 100644 index 00000000000..c96338a1522 Binary files /dev/null and b/APACHE_1_2_X/icons/layout.gif differ diff --git a/APACHE_1_2_X/icons/left.gif b/APACHE_1_2_X/icons/left.gif new file mode 100644 index 00000000000..279e6710d49 Binary files /dev/null and b/APACHE_1_2_X/icons/left.gif differ diff --git a/APACHE_1_2_X/icons/link.gif b/APACHE_1_2_X/icons/link.gif new file mode 100644 index 00000000000..c5b6889a76d Binary files /dev/null and b/APACHE_1_2_X/icons/link.gif differ diff --git a/APACHE_1_2_X/icons/movie.gif b/APACHE_1_2_X/icons/movie.gif new file mode 100644 index 00000000000..00351837741 Binary files /dev/null and b/APACHE_1_2_X/icons/movie.gif differ diff --git a/APACHE_1_2_X/icons/p.gif b/APACHE_1_2_X/icons/p.gif new file mode 100644 index 00000000000..7b917b4e91e Binary files /dev/null and b/APACHE_1_2_X/icons/p.gif differ diff --git a/APACHE_1_2_X/icons/patch.gif b/APACHE_1_2_X/icons/patch.gif new file mode 100644 index 00000000000..39bc90e7953 Binary files /dev/null and b/APACHE_1_2_X/icons/patch.gif differ diff --git a/APACHE_1_2_X/icons/pdf.gif b/APACHE_1_2_X/icons/pdf.gif new file mode 100644 index 00000000000..c88fd777c4b Binary files /dev/null and b/APACHE_1_2_X/icons/pdf.gif differ diff --git a/APACHE_1_2_X/icons/pie0.gif b/APACHE_1_2_X/icons/pie0.gif new file mode 100644 index 00000000000..6f7a0ae7a70 Binary files /dev/null and b/APACHE_1_2_X/icons/pie0.gif differ diff --git a/APACHE_1_2_X/icons/pie1.gif b/APACHE_1_2_X/icons/pie1.gif new file mode 100644 index 00000000000..03aa6be71eb Binary files /dev/null and b/APACHE_1_2_X/icons/pie1.gif differ diff --git a/APACHE_1_2_X/icons/pie2.gif b/APACHE_1_2_X/icons/pie2.gif new file mode 100644 index 00000000000..b04c5e09086 Binary files /dev/null and b/APACHE_1_2_X/icons/pie2.gif differ diff --git a/APACHE_1_2_X/icons/pie3.gif b/APACHE_1_2_X/icons/pie3.gif new file mode 100644 index 00000000000..4db9d023eda Binary files /dev/null and b/APACHE_1_2_X/icons/pie3.gif differ diff --git a/APACHE_1_2_X/icons/pie4.gif b/APACHE_1_2_X/icons/pie4.gif new file mode 100644 index 00000000000..93471fdd885 Binary files /dev/null and b/APACHE_1_2_X/icons/pie4.gif differ diff --git a/APACHE_1_2_X/icons/pie5.gif b/APACHE_1_2_X/icons/pie5.gif new file mode 100644 index 00000000000..57aee93f070 Binary files /dev/null and b/APACHE_1_2_X/icons/pie5.gif differ diff --git a/APACHE_1_2_X/icons/pie6.gif b/APACHE_1_2_X/icons/pie6.gif new file mode 100644 index 00000000000..0dc327b5697 Binary files /dev/null and b/APACHE_1_2_X/icons/pie6.gif differ diff --git a/APACHE_1_2_X/icons/pie7.gif b/APACHE_1_2_X/icons/pie7.gif new file mode 100644 index 00000000000..8661337f067 Binary files /dev/null and b/APACHE_1_2_X/icons/pie7.gif differ diff --git a/APACHE_1_2_X/icons/pie8.gif b/APACHE_1_2_X/icons/pie8.gif new file mode 100644 index 00000000000..59ddb34ce0f Binary files /dev/null and b/APACHE_1_2_X/icons/pie8.gif differ diff --git a/APACHE_1_2_X/icons/portal.gif b/APACHE_1_2_X/icons/portal.gif new file mode 100644 index 00000000000..0e6e506e004 Binary files /dev/null and b/APACHE_1_2_X/icons/portal.gif differ diff --git a/APACHE_1_2_X/icons/ps.gif b/APACHE_1_2_X/icons/ps.gif new file mode 100644 index 00000000000..0f565bc1db7 Binary files /dev/null and b/APACHE_1_2_X/icons/ps.gif differ diff --git a/APACHE_1_2_X/icons/quill.gif b/APACHE_1_2_X/icons/quill.gif new file mode 100644 index 00000000000..818a5cdc7e0 Binary files /dev/null and b/APACHE_1_2_X/icons/quill.gif differ diff --git a/APACHE_1_2_X/icons/right.gif b/APACHE_1_2_X/icons/right.gif new file mode 100644 index 00000000000..b256e5f75fb Binary files /dev/null and b/APACHE_1_2_X/icons/right.gif differ diff --git a/APACHE_1_2_X/icons/screw1.gif b/APACHE_1_2_X/icons/screw1.gif new file mode 100644 index 00000000000..af6ba2b097b Binary files /dev/null and b/APACHE_1_2_X/icons/screw1.gif differ diff --git a/APACHE_1_2_X/icons/screw2.gif b/APACHE_1_2_X/icons/screw2.gif new file mode 100644 index 00000000000..06dccb3e44c Binary files /dev/null and b/APACHE_1_2_X/icons/screw2.gif differ diff --git a/APACHE_1_2_X/icons/script.gif b/APACHE_1_2_X/icons/script.gif new file mode 100644 index 00000000000..d8a853bc582 Binary files /dev/null and b/APACHE_1_2_X/icons/script.gif differ diff --git a/APACHE_1_2_X/icons/sound1.gif b/APACHE_1_2_X/icons/sound1.gif new file mode 100644 index 00000000000..8efb49f55d6 Binary files /dev/null and b/APACHE_1_2_X/icons/sound1.gif differ diff --git a/APACHE_1_2_X/icons/sound2.gif b/APACHE_1_2_X/icons/sound2.gif new file mode 100644 index 00000000000..48e6a7fb2fa Binary files /dev/null and b/APACHE_1_2_X/icons/sound2.gif differ diff --git a/APACHE_1_2_X/icons/sphere1.gif b/APACHE_1_2_X/icons/sphere1.gif new file mode 100644 index 00000000000..7067070da27 Binary files /dev/null and b/APACHE_1_2_X/icons/sphere1.gif differ diff --git a/APACHE_1_2_X/icons/sphere2.gif b/APACHE_1_2_X/icons/sphere2.gif new file mode 100644 index 00000000000..a9e462a377c Binary files /dev/null and b/APACHE_1_2_X/icons/sphere2.gif differ diff --git a/APACHE_1_2_X/icons/tar.gif b/APACHE_1_2_X/icons/tar.gif new file mode 100644 index 00000000000..4032c1bd3d4 Binary files /dev/null and b/APACHE_1_2_X/icons/tar.gif differ diff --git a/APACHE_1_2_X/icons/tex.gif b/APACHE_1_2_X/icons/tex.gif new file mode 100644 index 00000000000..45e43233b84 Binary files /dev/null and b/APACHE_1_2_X/icons/tex.gif differ diff --git a/APACHE_1_2_X/icons/text.gif b/APACHE_1_2_X/icons/text.gif new file mode 100644 index 00000000000..4c623909fbf Binary files /dev/null and b/APACHE_1_2_X/icons/text.gif differ diff --git a/APACHE_1_2_X/icons/transfer.gif b/APACHE_1_2_X/icons/transfer.gif new file mode 100644 index 00000000000..33697dbb667 Binary files /dev/null and b/APACHE_1_2_X/icons/transfer.gif differ diff --git a/APACHE_1_2_X/icons/unknown.gif b/APACHE_1_2_X/icons/unknown.gif new file mode 100644 index 00000000000..32b1ea23fb6 Binary files /dev/null and b/APACHE_1_2_X/icons/unknown.gif differ diff --git a/APACHE_1_2_X/icons/up.gif b/APACHE_1_2_X/icons/up.gif new file mode 100644 index 00000000000..6d6d6d1ebf8 Binary files /dev/null and b/APACHE_1_2_X/icons/up.gif differ diff --git a/APACHE_1_2_X/icons/uu.gif b/APACHE_1_2_X/icons/uu.gif new file mode 100644 index 00000000000..4387d529f69 Binary files /dev/null and b/APACHE_1_2_X/icons/uu.gif differ diff --git a/APACHE_1_2_X/icons/uuencoded.gif b/APACHE_1_2_X/icons/uuencoded.gif new file mode 100644 index 00000000000..4387d529f69 Binary files /dev/null and b/APACHE_1_2_X/icons/uuencoded.gif differ diff --git a/APACHE_1_2_X/icons/world1.gif b/APACHE_1_2_X/icons/world1.gif new file mode 100644 index 00000000000..05b4ec20588 Binary files /dev/null and b/APACHE_1_2_X/icons/world1.gif differ diff --git a/APACHE_1_2_X/icons/world2.gif b/APACHE_1_2_X/icons/world2.gif new file mode 100644 index 00000000000..e3203f7a881 Binary files /dev/null and b/APACHE_1_2_X/icons/world2.gif differ diff --git a/APACHE_1_2_X/src/.cvsignore b/APACHE_1_2_X/src/.cvsignore new file mode 100644 index 00000000000..1cc54bc747c --- /dev/null +++ b/APACHE_1_2_X/src/.cvsignore @@ -0,0 +1,5 @@ +Configuration +Makefile +modules.c +httpd +Makefile.config diff --git a/APACHE_1_2_X/src/.indent.pro b/APACHE_1_2_X/src/.indent.pro new file mode 100644 index 00000000000..77b65f3d6a7 --- /dev/null +++ b/APACHE_1_2_X/src/.indent.pro @@ -0,0 +1 @@ +-i4 -npsl -di0 -br -nce -d0 -cli0 -npcs diff --git a/APACHE_1_2_X/src/CHANGES b/APACHE_1_2_X/src/CHANGES new file mode 100644 index 00000000000..5bddf6ab07d --- /dev/null +++ b/APACHE_1_2_X/src/CHANGES @@ -0,0 +1,1794 @@ +Changes with Apache 1.2 + +Changes with Apache 1.2b11 + + *) Fixed open timestamp fd in proxy_cache.c [Chuck Murcko] + + *) Added undocumented perl SSI mechanism for -DUSE_PERL_SSI and mod_perl. + [Rob Hartill] + + *) Proxy needs to use hard_timeout instead of soft_timeout when it is + reading from one buffer and writing to another, at least until it has + a custom timeout handler. [Roy Fielding and Petr Lampa] + + *) Fixed problem on Irix with servers hanging in IdentityCheck, + apparently due to a mismatch between sigaction and setjmp. + [Roy Fielding] PR#502 + + *) Log correct status code if we timeout before receiving a request (408) + or if we received a request-line that was too long to process (414). + [Ed Korthof and Roy Fielding] PR#601 + + *) Virtual hosts with the same ServerName, but on different ports, were + not being selected properly. [Ed Korthof] + + *) Added code to return the requested IP address from proxy_host2addr() + if gethostbyaddr() fails due to reverse DNS lookup problems. Original + change submitted by Jozsef Hollosi . + [Chuck Murcko] PR#614 + + *) If multiple requests on a single connection are used to retrieve + data from different virtual hosts, the virtual host list would be + scanned starting with the most recently used VH instead of the first, + causing most virtual hosts to be ignored. + [Paul Sutton and Martin Mares] PR#610 + + *) The OS/2 handling of process group was broken by a porting patch for + MPE, so restored prior code for OS/2. [Roy Fielding and Garey Smiley] + + *) Inherit virtual server port from main server if none (or "*") is + given for VirtualHost. [Dean Gaudet] PR#576 + + *) If the lookup for a DirectoryIndex name with content negotiation + has found matching variants, but none are acceptable, return the + negotiation result if there are no more DirectoryIndex names to lookup. + [Petr Lampa and Roy Fielding] + + *) If a soft_timeout occurs after keepalive is set, then the main child + loop would try to read another request even though the connection + has been aborted. [Roy Fielding] + + *) Configure changes: Allow for whitespace at the start of a + Module declaration. Also, be more understanding about the + CC=/OPTIM= format in Configuration. Finally, fix compiler + flags if using HP-UX's cc compiler. [Jim Jagielski] + + *) Subrequests and internal redirects now inherit the_request from the + original request-line. [Roy Fielding] + + *) Test for error conditions before creating output header fields, since + we don't want the error message to include those fields. Likewise, + reset the content_language(s) and content_encoding of the response + before generating or redirecting to an error message, since the new + message will have its own Content-* definitions. [Dean Gaudet] + + *) Restored the semantics of headers_out (headers sent only with 200..299 + and 304 responses) and err_headers_out (headers sent with all responses). + Avoid the overhead of copying tables if err_headers_out is empty + (the usual case). [Roy Fielding] + + *) Fixed a couple places where a check for the default Content-Type was + not properly checking both the value configured by the DefaultType + directive and the DEFAULT_TYPE symbol in httpd.h. Changed the value + of DEFAULT_TYPE to match the documented default (text/plain). + [Dean Gaudet] PR#506 + + *) Escape the HTML-sensitive characters in the Request-URI that is + output for each child by mod_status. [Dean Gaudet and Ken Coar] PR#501 + + *) Properly initialize the flock structures used by the mutex locking + around accept() when USE_FCNTL_SERIALIZED_ACCEPT is defined. + [Marc Slemko] + + *) The method for determining PATH_INFO has been restored to the pre-1.2b + (and NCSA httpd) definition wherein it was the extra path info beyond + the CGI script filename. The environment variable FILEPATH_INFO has + been removed, and instead we supply the original REQUEST_URI to any + script that wants to be Apache-specific and needs the real URI path. + This solves a problem with existing scripts that use extra path info + in the ScriptAlias directive to pass options to the CGI script. + [Roy Fielding] + + *) The _default_ change in 1.2b10 will change the behaviour on configs + that use multiple Listen statements for listening on multiple ports. + But that change is necessary to make _default_ consistent with other + forms of . It requires such configs to be modified + to use . The documentation has been + updated. [Dean Gaudet] PR#530 + + *) If an ErrorDocument CGI script is used to respond to an error + generated by another CGI script which has already read the message + body of the request, the server would block trying to read the + message body again. [Rob Hartill] + + *) signal() replacement conflicted with a define on QNX (and potentially + other platforms). Fixed. [Ben Laurie] PR#512 + +Changes with Apache 1.2b10 + + *) Allow HTTPD_ROOT, SERVER_CONFIG_FILE, DEFAULT_PATH, and SHELL_PATH + to be configured via -D in Configuration. [Dean Gaudet] PR#449 + + *) didn't work properly. [Dean Gaudet] + + *) Added prototype for mktemp() for SUNOS4 [Marc Slemko] + + *) In mod_proxy.c, check return values for proxy_host2addr() when reading + config, in case the hostent struct returned is trash. + [Chuck Murcko] PR #491 + + *) Fixed the fix in 1.2b9 for parsing URL query info into args for CGI + scripts. [Dean Gaudet, Roy Fielding, Marc Slemko] + +Changes with Apache 1.2b9 [never announced] + + *) Reset the MODULE_MAGIC_NUMBER to account for the unsigned port + changes and in anticipation of 1.2 final release. [Roy Fielding] + + *) Fix problem with scripts not receiving a SIGPIPE when client drops + the connection (e.g., when user presses Stop). Apache will now stop + trying to send a message body immediately after an error from write. + [Roy Fielding and Nathan Kurz] PR#335 + + *) Rearrange Configuration.tmpl so that mod_rewrite has higher priority + than mod_alias, and mod_alias has higher priority than mod_proxy; + rearranged other modules to enhance understanding of their purpose + and relative order (and maybe even reduce some overhead). + [Roy Fielding and Sameer Parekh] + + *) Fix graceful restart. Eliminate many signal-related race + conditions in both forms of restart, and in SIGTERM. See + htdocs/manual/stopping.html for details on stopping and + restarting the parent. [Dean Gaudet] + + *) Fix memory leaks in mod_rewrite, mod_browser, mod_include. Tune + memory allocator to avoid a behaviour that required extra blocks to + be allocated. [Dean Gaudet] + + *) Allow suexec to access files relative to current directory but not + above. (Excluding leading / or any .. directory.) [Ken Coar] + PR#269, 319, 395 + + *) Fix suexec segfault when group doesn't exist. [Gregory Neil Shapiro] + PR#367, 368, 354, 453 + + *) Fix the above fix: if suexec is enabled, avoid destroying r->url + while obtaining the /~user and save the username in a separate data + area so that it won't be overwritten by the call to getgrgid(), and + fix some misuse of the pool string allocation functions. Also fixes + a general problem with parsing URL query info into args for CGI scripts. + [Roy Fielding] PR#339, 367, 354, 453 + + *) Fix IRIX warning about bzero undefined. [Marc Slemko] + + *) Fix problem with . [Martin Kraemer] PR#271 + + *) Corrected spelling of "authoritative". AuthDBAuthoratative became + AuthDBAuthoritative. [Marc Slemko] PR#420 + + *) MaxClients should be at least 1. [Lars Eilebrecht] PR#375 + + *) The default handler now logs invalid methods or URIs (i.e. PUT on an + object that can't be PUT, or FOOBAR for some method FOOBAR that + apache doesn't know about at all). Log 404s that occur in mod_include. + [Paul Sutton, John Van Essen] + + *) If a soft timeout (or lingerout) occurs while trying to flush a + buffer or write inside buff.c or fread'ing from a CGI's output, + then the timeout would be ignored. [Roy Fielding] PR#373 + + *) Work around a bug in Netscape Navigator versions 2.x, 3.x and 4.0b2's + parsing of headers. If the terminating empty-line CRLF occurs starting + at the 256th or 257th byte of output, then Navigator will think a normal + image is invalid. We are guessing that this is because their initial + read of a new request uses a 256 byte buffer. We check the bytes written + so far and, if we are about to tickle the bug, we instead insert a + padding header of eminent bogosity. [Roy Fielding and Dean Gaudet] PR#232 + + *) Fixed SIGSEGV problem when a DirectoryIndex file is also the source + of an external redirection. [Roy Fielding and Paul Sutton] + + *) Configure would create a broken Makefile if the configuration file + contained a commented-out Rule. [Roy Fielding] + + *) Promote per_dir_config and subprocess_env from the subrequest to the + main request in mod_negotiation. In particular this fixes a bug + where sections wouldn't properly apply to negotiated content. + [Dean Gaudet] + + *) Fix a potential deadlock in mod_cgi script_err handling. + [Ralf S. Engelschall] + + *) rotatelogs zero-pads the logfile names to improve alphabetic sorting. + [Mitchell Blank Jr] + + *) Updated mod_rewrite to 3.0.4: Fixes HTTP redirects from within + .htaccess files because the RewriteBase was not replaced correctly. + Updated mod_rewrite to 3.0.5: Fixes problem with rewriting inside + sections missing a trailing /. [Ralf S. Engelschall] + + *) Clean up Linux settings in conf.h by detecting 2.x versus 1.x. For + 1.x the settings are those of pre-1.2b8. For 2.x we include + HAVE_SHMGET (scoreboard in shared memory rather than file) and + HAVE_SYS_RESOURCE_H (enable the RLimit commands). + [Dean Gaudet] PR#336, PR#340 + + *) Redirect did not preserve ?query_strings when present in the client's + request. [Dean Gaudet] + + *) Configure was finding non-modules on EXTRA_LIBS. [Frank Cringle] PR#380 + + *) Use /bin/sh5 on ultrix. [P. Alejandro Lopez-Valencia] PR#369 + + *) Add UnixWare compile/install instructions. [Chuck Murcko] + + *) Add mod_example (illustration of API techniques). [Ken Coar] + + *) Add macro for memmove to conf.h for SUNOS4. [Marc Slemko] + + *) Improve handling of directories when filenames have spaces in them. + [Chuck Murcko] + + *) For hosts with multiple IP addresses, try all additional addresses if + necessary to get a connect. Fail only if hostent address list is + exhausted. [Chuck Murcko] + + *) More signed/unsigned port fixes. [Dean Gaudet] + + *) HARD_SERVER_LIMIT can be defined in the Configuration file now. + [Dean Gaudet] + +Changes with Apache 1.2b8 + + *) suexec.c doesn't close the log file, allowing CGIs to continue writing + to it. [Marc Slemko] + + *) The addition of and directives made the + sub_req_lookup_simple() function bogus, so we now handle + the special cases directly. [Dean Gaudet] + + *) We now try to log where the server is dumping core when a fatal + signal is received. [Ken Coar] + + *) Improved lingering_close by adding a special timeout, removing the + spurious log messages, removing the nonblocking settings (they + are not needed with the better timeout), and adding commentary + about the NO_LINGCLOSE and USE_SO_LINGER issues. NO_LINGCLOSE is + now the default for SunOS4, Unixware, NeXT, and Irix. [Roy Fielding] + + *) Send error messages about setsockopt failures to the server error + log instead of stderr. [Roy Fielding] + + *) Fix loopholes in proxy cache expiry vis a vis alarms. [Brian Moore] + + *) Stopgap solution for CGI 3-second delay with server-side includes: if + processing a subrequest, allocate memory from r->main->pool instead + of r->pool so that we can avoid waiting for free_proc_chain to cleanup + in the middle of an SSI request. [Dean Gaudet] PR #122 + + *) Fixed status of response when POST is received for a nonexistant URL + (was sending 405, now 404) and when any method is sent with a + full-URI that doesn't match the server and the server is not acting + as a proxy (was sending 501, now 403). [Roy Fielding] + + *) Host port changed to unsigned short. [Ken Coar] PR #276 + + *) Fix typo in command definition of AuthAuthoritative. [Ken Coar] PR #246 + + *) Defined HAVE_SHMGET for shared memory on Linux. [Dean Gaudet] + + *) Report extra info from errno with many errors that cause httpd to exit. + spawn_child, popenf, and pclosef now have valid errno returns in the + event of an error. Correct problems where errno was stomped on + before being reported. [Dean Gaudet] + + *) In the proxy, if the cache filesystem was full, garbage_coll() was + never called, and thus the filesystem would remain full indefinitely. + We now also remove incomplete cache files left if the origin server + didn't send a Content-Length header and either the client has aborted + transfer or bwrite() to client has failed. [Petr Lampa] + + *) Fixed the handling of module and script-added header fields. + Improved the interface for sending header fields and reduced + the duplication of code between sending okay responses and errors. + We now always send both headers_out and err_headers_out, and + ensure that the server-reserved fields are not being overridden, + while not overriding those that are not reserved. [Roy Fielding] + + *) Moved transparent content negotiation fields to err_headers_out + to reflect above changes. [Petr Lampa] + + *) Fixed the determination of whether or not we should make the + connection persistent for all of the cases where some other part + of the server has already indicated that we should not. Also + improved the ordering of the test so that chunked encoding will + be set whenever it is desired instead of only when KeepAlive + is enabled. Added persistent connection capability for most error + responses (those that do not indicate a bad input stream) when + accessed by an HTTP/1.1 client. [Roy Fielding] + + *) Added missing timeouts for sending header fields, error responses, + and the last chunk of chunked encoding, each of which could have + resulted in a process being stuck in write forever. Using soft_timeout + requires that the sender check for an aborted connection rather than + continuing after an EINTR. Timeouts that used to be initiated before + send_http_header (and never killed) are now initiated only within or + around the routines that actually do the sending, and not allowed to + propagate above the caller. [Roy Fielding] + + *) mod_auth_anon required an @ or a . in the email address, not both. + [Dirk vanGulik] + + *) per_dir_defaults weren't set correctly until directory_walk for + name-based vhosts. This fixes an obscure bug with the wrong config + info being used for vhosts that share the same ip as the server. + [Dean Gaudet] + + *) Improved generation of modules/Makefile to be more generic for + new module directories. [Ken Coar, Chuck Murcko, Roy Fielding] + + *) Generate makefile dependency for Configuration based on the actual + name given when running the Configure process. [Dean Gaudet] + + *) Fixed problem with vhost error log not being set prior to + initializing virtual hosts. [Dean Gaudet] + + *) Fixed infinite loop when a trailing slash is included after a type map + file URL (extra path info). [Petr Lampa] + + *) Fixed server status updating of per-connection counters. [Roy Fielding] + + *) Add documentation for DNS issues (reliability and security), and try + to explain the virtual host matching process. [Dean Gaudet] + + *) Try to continue gracefully by disabling the vhost if a DNS lookup + fails while parsing the configuration file. [Dean Gaudet] + + *) Improved calls to setsockopt. [Roy Fielding] + + *) Negotiation changes: Don't output empty content-type in variant list; + Output charset in variant list; Return sooner from handle_multi() if + no variants found; Add handling of '*' wildcard in Accept-Charset. + [Petr Lampa and Paul Sutton] + + *) Fixed overlaying of request/sub-request notes and headers in + mod_negotiation. [Dean Gaudet] + + *) If two variants' charset quality are equal and one is the default + charset (iso-8859-1), then prefer the variant that was specifically + listed in Accept-Charset instead of the default. [Petr Lampa] + + *) Memory allocation problem in push_array() -- it would corrupt memory + when nalloc==0. [Kai Risku and Roy Fielding] + + *) invoke_handler() doesn't handle mime arguments in content-type + [Petr Lampa] PR#160 + + *) Reduced IdentityCheck timeout to 30 seconds, as per RFC 1413 minimum. + [Ken Coar] + + *) Fixed problem with ErrorDocument not working for virtual hosts + due to one of the performance changes in 1.2b7. [Dean Gaudet] + + *) Log an error message if we get a request header that is too long, + since it may indicate a buffer overflow attack. [Marc Slemko] + + *) Made is_url() allow "[-.+a-zA-Z0-9]+:" as a valid scheme and + not reject URLs without a double-slash, as per RFC2068 section 3.2. + [Ken Coar] PR #146, #187 + + *) Added table entry placeholder for new header_parser callback + in all of the distributed modules. [Ken Coar] PR #191 + + *) Allow for cgi files without the .EXE extension on them under OS/2. + [Garey Smiley] PR #59 + + *) Fixed error message when resource is not found and URL contains + path info. [Petr Lampa and Dean Gaudet] PR #40 + + *) Fixed user and server confusion over what should be a virtual host + and what is the main server, resulting in access to something + other than the name defined in the virtualhost directive (but + with the same IP address) failing. [Dean Gaudet] + + *) Updated mod_rewrite to version 3.0.2, which: fixes compile error on + AIX; improves the redirection stuff to enable the users to generally + redirect to http, https, gopher and ftp; added TIME variable for + RewriteCond which expands to YYYYMMDDHHMMSS strings and added the + special patterns >STRING, ] + + *) unset Content-Length if chunked (RFC-2068) [Petr Lampa] + + *) mod_negotiation fixes [Petr Lampa] PR#157, PR#158, PR#159 + - replace protocol response numbers with symbols + - save variant-list into main request notes + - free allocated memory from subrequests + - merge notes, headers_out and err_headers_out + + *) changed status check mask in proxy_http.c from "HTTP/#.# ### *" to + "HTTP/#.# ###*" to be more lenient about what we accept. + [Chuck Murcko] + + *) more proxy FTP bug fixes: + - Changed send_dir() to remove user/passwd from displayed URL. + - Changed login error messages to be more descriptive. + - remove setting of SO_DEBUG socket option + - Make ftp_getrc() more lenient about multiline responses, + specifically, 230 responses which don't have continuation 230- + on each line). These seem to be all NT FTP servers, and while + perhaps questionable, they appear to be legal by RFC 959. + - Add missing kill_timeout() after transfer to user completes. + [Chuck Murcko] + + *) Fixed problem where a busy server could hang when restarting + after being sent a SIGHUP due to child processes not exiting. + [Marc Slemko] + + *) Modify mod_include escaping so a '\' only signifies an escaped + character if the next character is one that needs + escaping. [Ben Laurie] + + *) Eliminated possible infinite loop in mod_imap when relative URLs are + used with a 'base' directive that does not have a '/' in it. + [Marc Slemko, reported by Onno Witvliet ] + + *) Reduced the default timeout from 1200 seconds to 300, and the + one in the sample configfile from 400 to 300. [Marc Slemko] + + *) Stop vbprintf from crashing if given a NULL string pointer; + print (null) instead. [Ken Coar] + + *) Don't disable Nagle algorithm if system doesn't have TCP_NODELAY. + [Marc Slemko and Roy Fielding] + + *) Fixed problem with mod_cgi-generated internal redirects trying to + read the request message-body twice. [Archie Cobbs and Roy Fielding] + + *) Reduced timeout on lingering close, removed possibility of a blocked + read causing the child to hang, and stopped logging of errors if + the socket is not connected (reset by client). [Roy Fielding] + + *) Rearranged main child loop to remove duplication of code in + select/accept and keep-alive requests, fixed several bugs regarding + checking scoreboard_image for exit indication and failure to + account for all success conditions and trap all error conditions, + prevented multiple flushes before closing the socket; close the entire + socket buffer instead of just one descriptor, prevent logging of + EPROTO and ECONNABORTED on platforms where supported, and generally + improved readability. [Roy Fielding] + + *) Extensive performance improvements. Cleaned up inefficient use of + auto initializers, multiple is_matchexp calls on a static string, + and excessive merging of response_code_strings. [Dean Gaudet] + + *) Added double-buffering to mod_include to improve performance on + server-side includes. [Marc Slemko] + + *) Several fixes for suexec wrapper. [Randy Terbush] + - Make wrapper work for files on NFS filesystem. + - Fix portability problem of MAXPATHLEN. + - Fix array overrun problem in clean_env(). + - Fix allocation of PATH environment variable + + *) Removed extraneous blank line is description of mod_status chars. + [Kurt Kohler] + + *) Logging of errors from the call_exec routine simply went nowhere, + since the logfile fd has been closed, so now we send them to stderr. + [Harald T. Alvestrand] + + *) Fixed core dump when DocumentRoot is a CGI. + [Ben Laurie, reported by geddis@tesserae.com] + + *) Fixed potential file descriptor leak in mod_asis; updated it and + http_core to use pfopen/pfclose instead of fopen/fclose. + [Randy Terbush and Roy Fielding] + + *) Fixed handling of unsigned ints in ap_snprintf() on some chips such + as the DEC Alpha which is 64-bit but uses 32-bit ints. + [Dean Gaudet and Ken Coar] + + *) Return a 302 response code to the client when sending a redirect + due to a missing trailing '/' on a directory instead of a 301; now + it is cacheable. [Markus Gyger] + + *) Fix condition where, if a bad directive occurs in .htaccess, and + sub_request() goes first to this directory, then log_reason() will + SIGSEGV because it doesn't have initialized r->per_dir_config. + [PR#162 from Petr Lampa, fix by Marc Slemko and Dean Gaudet] + + *) Fix handling of lang_index in is_variant_better(). This was + causing problems which resulted in the server sending the + wrong language document in some cases. [Petr Lampa] + + *) Remove free() from clean_env() in suexec wrapper. This was nuking + the clean environment on some systems. + + *) Tweak byteserving code (e.g. serving PDF files) to work around + bugs in Netscape Navigator and Microsoft Internet Explorer. + Emit Content-Length header when sending multipart/byteranges. + [Alexei Kosut] + + *) Port to HI-UX/WE2. [Nick Maclaren] + + *) Port to HP MPE operating system for HP 3000 machines + [Mark Bixby ] + + *) Fixed bug which caused a segmentation fault if only one argument + given to RLimit* directives. [Ed Korthof] + + *) Continue persistent connection after 204 or 304 response. [Dean Gaudet] + + *) Improved buffered output to the client by delaying the flush decision + until the BUFF code is actually about to read the next request. + This fixes a problem introduced in 1.2b5 with clients that send + an extra CRLF after a POST request. Also improved chunked output + performance by combining writes using writev() and removing as + many bflush() calls as possible. NOTE: Platforms without writev() + must add -DNO_WRITEV to the compiler CFLAGS, either in Configuration + or Configure, unless we have already done so. [Dean Gaudet] + + *) Fixed mod_rewrite bug which truncated the rewritten URL [Marc Slemko] + + *) Fixed mod_info output corruption bug introduced by buffer overflow + fixes. [Dean Gaudet] + + *) Fixed http_protocol to correctly output all HTTP/1.1 headers, including + for the special case of a 304 response. [Paul Sutton] + + *) Improved handling of TRACE method by bypassing normal method handling + and header parsing routines; fixed Allow response to always allow TRACE. + [Dean Gaudet] + + *) Fixed compiler warnings in the regex library. [Dean Gaudet] + + *) Cleaned-up some of the generated HTML. [Ken Coar] + +Changes with Apache 1.2b6 + + *) Allow whitespace in imagemap mapfile coordinates. [Marc Slemko] + + *) Fix typo introduced in fix for potential infinite loop around + accept() in child_main(). This change caused the rev to 1.2b6. + 1.2b5 was never a public beta. + +Changes with Apache 1.2b5 + + *) Change KeepAlive semantics (On|Off instead of a number), add + MaxKeepAliveRequests directive. [Alexei Kosut] + + *) Various NeXT compilation patches, as well as a change in + regex/regcomp.c since that file also used a NEXT define. + [Andreas Koenig] + + *) Allow * to terminate the end of a directory match in mod_dir. + Allows /~* to match for both /~joe and /~joe/. [David Bronder] + + *) Don't call can_exec() if suexec_enabled. Calling this requires + scripts executed by the suexec wrapper to be world executable, which + defeats one of the advantages of running the wrapper. [Randy Terbush] + + *) Portability Fix: IRIX complained with 'make clean' about *pure* (removed) + [Jim Jagielski] + + *) Migration from sprintf() to snprintf() to avoid buffer + overflows. [Marc Slemko] + + *) Provide portable snprintf() implementation (ap_snprintf) + as well as *cvt family. [Jim Jagielski] + + *) Portability Fix: NeXT lacks unistd.h so we wrap it's inclusion + [Jim Jagielski] + + *) Remove mod_fastcgi.c from the distribution. This module appears + to be maintained more through the Open Market channels and should + continue to be easily available at http://www.fastcgi.com/ + + *) Fixed bug in modules/Makefile that wouldn't allow building in more + than one subdirectory (or cleaning, either). [Jeremy Laidman] + + *) mod_info assumed that the config files were relative to ServerRoot. + [Ken the Rodent] + + *) CGI scripts called as an error document resulting from failed + CGI execution would hang waiting for POST'ed data. [Rob Hartill] + + *) Log reason when mod_dir returns access HTTP_FORBIDDEN + [Ken the Rodent] + + *) Properly check errno to prevent display of a directory index + when server receives a long enough URL to confuse stat(). + [Marc Slemko] + + *) Several security enhancements to suexec wrapper. It is _highly_ + recommended that previously installed versions of the wrapper + be replaced with this version. [Randy Terbush, Jason Dour] + + - ~user execution now properly restricted to ~user's home + directory and below. + - execution restricted to UID/GID > 100 + - restrict passed environment to known variables + - call setgid() before initgroups() (portability fix) + - remove use of setenv() (portability fix) + + *) Add HTTP/1.0 response forcing. [Ben Laurie] + + *) Add access control via environment variables. [Ben Laurie] + + *) Add rflush() function. [Alexei Kosut] + + *) remove duplicate pcalloc() call in new_connection(). + + *) Fix incorrect comparison which could allow number of children = + MaxClients + 1 if less than HARD_SERVER_LIMIT. Also fix potential + problem if StartServers > HARD_SERVER_LIMIT. [Ed Korthof] + + *) Updated support for OSes (MachTen, ULTRIX, Paragon, ISC, OpenBSD + AIX PS/2, CONVEXOS. [Jim Jagielski] + + *) Replace instances of inet_ntoa() with inet_addr() for ProxyBlock. + It's more portable. [Martin Kraemer] + + *) Replace references to make in Makefile.tmpl with $(MAKE). + [Chuck Murcko] + + *) Add ProxyBlock directive w/IP address caching. Add IP address + caching to NoCache directive as well. ProxyBlock works with all + handlers; NoCache now also works with FTP for anonymous logins. + Still more code cleanup. [Chuck Murcko] + + *) Add "header parse" API hook [Ben Laurie] + + *) Fix byte ordering problems for REMOTE_PORT [Chuck Murcko] + + *) suEXEC wrapper was freeing memory that had not been malloc'ed. + + *) Correctly allow access and auth directives in sections in + server config files. [Alexei Kosut] + + *) Fix bug with ServerPath that could cause certain files to be not + found by the server. [Alexei Kosut] + + *) Fix handling of ErrorDocument so that it doesn't remove a trailing + double-quote from text and so that it properly checks for unsupported + status codes using the new index_of_response interface. [Roy Fielding] + + *) Multiple fixes to the lingering_close code in order to avoid being + interrupted by a stray timeout, to avoid lingering on a connection + that has already been aborted or never really existed, to ensure that + we stop lingering as soon as any error condition is received, and to + prevent being stuck indefinitely if the read blocks. Also improves + reporting of error conditions. [Marc Slemko and Roy Fielding] + + *) Fixed initialization of parameter structure for sigaction. + [mgyger@itr.ch, Adrian Filipi-Martin] + + *) Fixed reinitializing the parameters before each call to accept and + select, and removed potential for infinite loop in accept. + [Roy Fielding, after useful PR from adrian@virginia.edu] + + *) Fixed condition where, if a child fails to fork, the scoreboard would + continue to say SERVER_STARTING forever. Eventually, the main process + would refuse to start new children because count_idle_servers() will + count those SERVER_STARTING entries and will always report that there + are enough idle servers. [Phillip Vandry] + + *) Fixed bug in bcwrite regarding failure to account for partial writes. + Avoided calling bflush() when the client is pipelining requests. + Removed unnecessary flushes from http_protocol. [Dean Gaudet] + + *) Added description of "." mode in server-status [Jim Jagielski] + + +Changes with Apache 1.2b4: + + *) Fix possible race condition in accept_mutex_init() that + could leave a small security hole open allowing files to be + overwritten in cases where the server UID has write permissions. + [Marc Slemko] + + *) Fix awk compatibilty problem in Configure. [Jim Jagielski] + + *) Fix portablity problem in util_script where ARG_MAX may not be + defined for some systems. + + *) Add changes to allow compilation on Machten 4.0.3 for PowerPC. + [Randal Schwartz] + + *) OS/2 changes to support an MMAP style scoreboard file and UNIX + style magic #! token for better script portability. [Garey Smiley] + + *) Fix bug in suexec wrapper introduced in b3 that would cause failed + execution for ~userdir CGI. [Jason Dour] + + *) Fix initgroups() business in suexec wrapper. [Jason Dour] + + *) Fix month off by one in suexec wrapper logging. + +Changes with Apache 1.2b3: + + *) Fix error in mod_cgi which could cause resources not to be properly + freed, or worse. [Dean Gaudet] + + *) Fix find_string() NULL pointer dereference. [Howard Fear] + + *) Add set_flag_slot() at the request of Dirk and others. + [Dirk vanGulik] + + *) Sync mod_rewrite with patch level 10. [Ralf Engelschall] + + *) Add changes to improve the error message given for invalid + ServerName parameters. [Dirk vanGulik] + + *) Add "Authoritative" directive for Auth modules that don't + currently have it. This gives admin control to assign authoritative + control to an authentication scheme and allow "fall through" for + those authentication modules that aren't "Authoritative" thereby + allowing multiple authentication mechanisms to be chained. + [Dirk vanGulik] + + *) Remove requirement for ResourceConfig/AccessConfig if not using + the three config file layout. [Randy Terbush] + + *) Add PASV mode to mod_proxy FTP handler. [Chuck Murcko] + + *) Changes to suexec wrapper to fix the following problems: + 1. symlinked homedirs will kill ~userdirs. + 2. initgroups() on Linux 2.0.x clobbers gr->grid. + 3. CGI command lines paramters problems + 4. pw-pwdir for "docroot check" still the httpd user's pw record. + [Randy Terbush, Jason Dour] + + *) Change create_argv() to accept variable arguments. This fixes + a problem where arguments were not getting passed to the CGI via + argv[] when the suexec wrapper was active. [Randy Terbush, Jake Buchholz] + + *) Collapse multiple slashes in path URLs to properly apply + handlers defined by . [Alexei Kosut] + + *) Define a sane set of DEFAULT_USER and DEFAULT_GROUP values for AIX. + + *) Improve the accuracy of request duration timings by setting + r->request_time in read_request_line() instead of read_request(). + [Dean Gaudet] + + *) Reset timeout while reading via get_client_block() in mod_cgi.c + Fixes problem with timed out transfers of large files. [Rasmus Lerdorf] + + *) Add the ability to pass different Makefile.tmpl files to Configure + using the -make flag. [Rob Hartill] + + *) Fix coredump triggered when sending a SIGHUP to the server caused + by an assertion failure, in turn caused by an uninitialised field in a + listen_rec. + [Ben Laurie] + + *) Add FILEPATH_INFO variable to CGI environment, which is equal to + PATH_INFO from previous versions of Apache (in certain situations, + Apache 1.2's PATH_INFO will be different than 1.1's). [Alexei Kosut] + [later removed in 1.2b11] + + *) Add rwrite() function to API to allow for sending strings of + arbitrary length. [Doug MacEachern] + + *) Remove rlim_t typedef for NetBSD. Do older versions need this? + + *) Defined rlim_t and WANTHSREGEX=yes and fixed waitpid() substitute for + NeXT. [Jim Jagielski] + + *) Removed recent modification to promote the status code on internal + redirects, since the correct fix was to change the default log format + in mod_log_config so that it outputs the original status. [Rob Hartill] + +Changes with Apache 1.2b2: + + *) Update set_signals() to use sigaction() for setting handlers. + This appears to fix a re-entrant problem in the seg_fault() + bus_error() handlers. [Randy Terbush] + + *) Changes to allow mod_status compile for OS/2 [Garey Smiley] + + *) changes for DEC AXP running OSF/1 v3.0. [Marc Evans] + + *) proxy_http.c bugfixes: [Chuck Murcko] + 1) fixes possible NULL pointer reference w/NoCache + 2) fixes NoCache behavior when using ProxyRemote (ProxyRemote + host would cache nothing if it was in the local domain, + and the local domain was in the NoCache list) + 3) Adds Host: header when not available + 4) Some code cleanup and clarification + + *) mod_include.c bugfixes: + 1) Fixed an ommission that caused include variables to not + be parsed in config errmsg directives [Howard Fear] + 2) Remove HAVE_POSIX_REGEX cruft [Alexei Kosut] + 3) Patch to fix compiler warnings [perrot@lal.in2p3.fr] + 4) Allow backslash-escaping to all quoted text + [Ben Yoshino ] + 5) Pass variable to command line if not set in XSSI's env + [Howard Fear] + + *) Fix infinite loop when processing Content-language lines in + type-map files. [Alexei Kosut] + + *) Closed file-globbing hole in test-cgi script. [Brian Behlendorf] + + *) Fixed problem in set_[user|group] that prevented CGI execution + for non-virtualhosts when suEXEC was enabled. [Randy Terbush] + + *) Added PORTING information file. [Jim Jagielski] + + *) Added definitions for S_IWGRP and S_IWOTH to conf.h [Ben Laurie] + + *) Changed default group to "nogroup" instead of "nobody" [Randy Terbush] + + *) Fixed define typo of FCNTL_SERIALIZED_ACCEPT where + USE_FCNTL_SERIALIZED_ACCEPT was intended. + + *) Fixed additional uses of 0xffffffff where INADDR_NONE was intended, + which caused problems of systems where socket s_addr is >32bits. + + *) Added comment to explain (r->chunked = 1) side-effect in + http_protocol.c [Roy Fielding] + + *) Replaced use of index() in mod_expires.c with more appropriate + and portable isdigit() test. [Ben Laurie] + + *) Updated Configure for ... + OS/2 (DEF_WANTHSREGEX=yes, other code changes) + *-dg-dgux* (bad pattern match) + QNX (DEF_WANTHSREGEX=yes) + *-sunos4* (DEF_WANTHSREGEX=yes, -DUSEBCOPY) + *-ultrix (new) + *-unixware211 (new) + and added some user diagnostic info. [Ben Laurie] + + *) In helpers/CutRule, replaced "cut" invocation with "awk" invocation + for better portability. [Jim Jagielski] + + *) Updated helpers/GuessOS for ... + SCO 5 (recognize minor releases) + SCO Unixware (braindamaged uname, whatever-whatever-unixware2) + SCO UnixWare 2.1.1 (requires a separate set of #defines in conf.h) + IRIX64 (-sgi-irix64) + ULTRIX (-unknown-ultrix) + SINIX (-whatever-sysv4) + NCR Unix (-ncr-sysv4) + and fixed something in helpers/PrintPath [Ben Laurie] + +Changes with Apache 1.2b1: + + *) Not listed. See + +Changes with Apache 1.1.1: + + *) Fixed bug where Cookie module would make two entries in the + logfile for each access [Mark Cox] + + *) Fixed bug where Redirect in .htaccess files would cause memory + leak. [Nathan Neulinger] + + *) MultiViews now works correctly with AddHandler [Alexei Kosut] + + *) Problems with mod_auth_msql fixed [Dirk vanGulik] + + *) Fix misspelling of "Anonymous_Authorative" directive in mod_auth_anon. + +Changes with Apache 1.1.0: + + *) Bring NeXT support up to date. [Takaaki Matsumoto] + + *) Bring QNX support up to date. [Ben Laurie] + + *) Make virtual hosts default to main server keepalive parameters. + [Alexei Kosut, Ben Laurie] + + *) Allow ScanHTMLTitles to work with lowercase tags. [Alexei Kosut] + + *) Fix missing address family for connect, also remove unreachable statement + in mod_proxy. [Ben Laurie] + + *) mod_env now turned on by default in Configuration.tmpl. + + *) Bugs which were fixed: + a) yet more mod_proxy bugs [Ben Laurie] + b) CGI works again with inetd [Alexei Kosut] + c) Leading colons were stripped from passwords [osm@interguide.com] + d) Another fix to multi-method Limit problem [jk@tools.de] + +Changes with Apache 1.1b4: + + *) r->bytes_sent variable restored. [Robert Thau] + + *) Previously broken multi-method <Limit> parsing fixed. [Robert Thau] + + *) More possibly unsecure programs removed from the support directory. + + *) More mod_auth_msql authentication improvements. + + *) VirtualHosts based on Host: headers no longer conflict with the + Listen directive. + + *) OS/2 compatibility enhancements. [Gary Smiley] + + *) POST now allowed to directory index CGI scripts. + + *) Actions now work with files of the default type. + + *) Bugs which were fixed: + a) more mod_proxy bugs + b) early termination of inetd requests + c) compile warnings on several systems + d) problems when scripts stop reading output early + +Changes with Apache 1.1b3: + + *) Much of cgi-bin and all of cgi-src has been removed, due to + various security holes found and that we could no longer support + them. + + *) The "Set-Cookie" header is now special-cased to not merge multiple + instances, since certain popular browsers can not handle multiple + Set-Cookie instructions in a single header. [Paul Sutton] + + *) rprintf() added to buffer code, occurrences of sprintf removed. + [Ben Laurie] + + *) CONNECT method for proxy module, which means tunneling SSL should work. + (No crypto needed) Also a NoCache config directive. + + *) Several API additions: pstrndup(), table_unset() and get_token() + functions now available to modules. + + *) mod_imap fixups, in particular Location: headers are now complete + URL's. + + *) New "info" module which reports on installed module set through a + special URL, a la mod_status. + + *) "ServerPath" directive added - allows for graceful transition + for Host:-header-based virtual hosts. + + *) Anonymous authentication module improvements. + + *) MSQL authentication module improvements. + + *) Status module design improved - output now table-based. [Ben Laurie] + + *) htdigest utility included for use with digest authentication + module. + + *) mod_negotiation: Accept values with wildcards to be treated with + less priority than those without wildcards at the same quality + value. [Alexei Kosut] + + *) Bugs which were fixed: + a) numerous mod_proxy bugs + b) CGI early-termination bug [Ben Laurie] + c) Keepalives not working with virtual hosts + d) RefererIgnore problems + e) closing fd's twice in mod_include (causing core dumps on + Linux and elsewhere). + +Changes with Apache 1.1b2: + + *) Bugfixes: + a) core dumps in mod_digest + b) truncated hostnames/ip address in the logs + c) relative URL's in mod_imap map files + +Changes with Apache 1.1b1: + + *) Not listed. See <http://www.apache.org/docs/new_features_1_1.html> + +Changes with Apache 1.0.3: + + *) Internal redirects which occur in mod_dir.c now preserve the + query portion of a request (the bit after the question mark). + [Adam Sussman] + + *) Escape active characters '<', '>' and '&' in html output in + directory listings, error messages and redirection links. + [David Robinson] + + *) Apache will now work with LynxOS 2.3 and later [Steven Watt] + + *) Fix for POSIX compliance in waiting for processes in alloc.c. + [Nick Williams] + + *) setsockopt no longer takes a const declared argument [Martijn Koster] + + *) Reset timeout timer after each successful fwrite() to the network. + This patch adds a reset_timeout() procedure that is called by + send_fd() to reset the timeout ever time data is written to the net. + [Nathan Schrenk] + + *) timeout() signal handler now checks for SIGPIPE and reports + lost connections in a more user friendly way. [Rob Hartill] + + *) Location of the "scoreboard" file which used to live in /tmp is + now configurable (for OSes that can't use mmap) via ScoreBoardFile + which works similar to PidFile (in httpd.conf) [Rob Hartill] + + *) Include sys/resource.h in the correct place for SunOS4 [Sameer Parekh] + + *) the pstrcat call in mod_cookies.c didn't have an ending NULL, + which caused a SEGV with cookies enabled + + *) Output warning when MinSpareServers is set to <= 0 and change it to 1 + [Rob Hartill] + + *) Log the UNIX textual error returned by some system calls, in + particular errors from accept() [David Robinson] + + *) Add strerror function to util.c for SunOS4 [Randy Terbush] + +Changes with Apache 1.0.2 + + *) patch to get Apache compiled on UnixWare 2.x, recommended as + a temporary measure, pending rewrite of rfc931.c. [Chuck Murcko] + + *) Fix get_basic_auth_pw() to set the auth_type of the request. + [David Robinson] + + *) past changes to http_config.c to only use the + setrlimit function on systems defining RLIMIT_NOFILE + broke the feature on SUNOS4. Now defines HAVE_RESOURCE + for SUNOS and prototypes the needed functions. + + *) Remove uses of MAX_STRING_LEN/HUGE_STRING_LEN from several routines. + [David Robinson] + + *) Fix use of pointer to scratch memory. [Cliff Skolnick] + + *) Merge multiple headers from CGI scripts instead of taking last + one. [David Robinson] + + *) Add support for SCO 5. [Ben Laurie] + +Changes with Apache 1.0.1 + + *) Silence mod_log_referer and mod_log_agent if not configured + [Randy Terbush] + + *) Recursive includes can occur if the client supplies PATH_INFO data + and the server provider uses relative links; as file.html + relative to /doc.shtml/pathinfo is /doc.shtml/file.html. [David Robinson] + + *) The replacement for initgroups() did not call {set,end}grent(). This + had two implications: if anything else used getgrent(), then + initgroups() would fail, and it was consuming a file descriptor. + [Ben Laurie] + + *) On heavily loaded servers it was possible for the scoreboard to get + out of sync with reality, as a result of a race condition. + The observed symptoms are far more Apaches running than should + be, and heavy system loads, generally followed by catastrophic + system failure. [Ben Laurie] + + *) Fix typo in license. [David Robinson] + +Changes with Apache 1.0.0 + + *) Not listed. See <http://www.apache.org/docs/new_features_1_0.html> + +Changes with Apache 0.8.16 + + *) New man page for 'httpd' added to support directory [David Robinson] + + *) .htgroup files can have more than one line giving members for a + given group (each must have the group name in front), for NCSA + back-compatibility [Robert Thau] + + *) Mutual exclusion around accept() is on by default for SVR4 systems + generally, since they generally can't handle multiple processes in + accept() on the same socket. This should cure flaky behavior on + a lot of those systems. [David Robinson] + + *) AddType, AddEncoding, and AddLanguage directives take multiple + extensions on a single command line [David Robinson] + + *) UserDir can be disabled for a given virtual host by saying + "UserDir disabled" in the <VirtualHost> section --- it was a bug + that this didn't work. [David Robinson] + + *) Compiles on QNX [Ben Laurie] + + *) Corrected parsing of ctime time format [David Robinson] + + *) httpd does a perror() before exiting if it can't log its pid + to the PidFile, to make diagnosing the error a bit easier. + [David Robinson] + + *) <!--#include file="..."--> can no longer include files in the + parent directory, for NCSA back-compatibility. [David Robinson] + + *) '~' is *not* escaped in URIs generated for directory listings + [Roy Fielding] + + *) Eliminated compiler warning in the imagemap module [Randy Terbush] + + *) Fixed bug involving handling URIs with escaped %-characters + in redirects [David Robinson] + +Changes with Apache 0.8.15 + + *) Switched to new, simpler license + + *) Eliminated core dumps with improperly formatted DBM group files [Mark Cox] + + *) Don't allow requests for ordinary files to have PATH_INFO [Ben Laurie] + + *) Reject paths containing %-escaped '%' or null characters [David Robinson] + + *) Correctly handles internal redirects to files with names containing '%' + [David Robinson] + + *) Repunctuated some error messages [Aram Mirzadeh, Andrew Wilson] + + *) Use geteuid() rather than getuid() to see if we have root privilege, + so that server correctly resets privilege if run setuid root. [Andrew + Wilson] + + *) Handle ftp: and telnet: URLs correctly in imagemaps (built-in module) + [Randy Terbush] + + *) Fix relative URLs in imagemap files [Randy Terbush] + + *) Somewhat better fix for the old "Alias /foo/ /bar/" business + [David Robinson] + + *) Don't repeatedly open the ErrorLog if a bunch of <VirtualHost> + entries all name the same one. [David Robinson] + + *) Fix directory listings with filenames containing unusual characters + [David Robinson] + + *) Better URI-escaping for generated URIs in directories with filenames + containing unusual characters [Ben Laurie] + + *) Fixed potential FILE* leak in http_main.c [Ben Laurie] + + *) Unblock alarms on error return from spawn_child() [David Robinson] + + *) Sample Config files have extra note for SCO users [Ben Laurie] + + *) Configuration has note for HP-UX users [Rob Hartill] + + *) Eliminated some bogus Linux-only #defines in conf.h [Aram Mirzadeh] + + *) Nuked bogus #define in httpd.h [David Robinson] + + *) Better test for whether a system has setrlimit() [David Robinson] + + *) Calls update_child_status() after reopen_scoreboard() [David Robinson] + + *) Doesn't send itself SIGHUP on startup when run in the -X debug-only mode + [Ben Laurie] + +Changes with Apache 0.8.14 + + *) Compiles on SCO ODT 3.0 [Ben Laurie] + + *) AddDescription works (better) [Ben Laurie] + + *) Leaves an intelligible error diagnostic when it can't set group + privileges on standalone startup [Andrew Wilson] + + *) Compiles on NeXT again --- the 0.8.13 RLIMIT patch was failing on + that machine, which claims to be BSD but does not support RLIMIT. + [Randy Terbush] + + *) gcc -Wall no longer complains about an unused variable when util.c + is compiled with -DMINIMAL_DNS [Andrew Wilson] + + *) Nuked another compiler warning for -Wall on Linux [Aram Mirzadeh] + +Changes with Apache 0.8.13 + + *) Make IndexIgnore *work* (ooops) [Jarkko Torppa] + + *) Have built-in imagemap code recognize & honor Point directive [James + Cloos] + + *) Generate cleaner directory listings in directories with a mix of + long and short filenames [Rob Hartill] + + *) Properly initialize dynamically loaded modules [Royston Shufflebotham] + + *) Properly default ServerName for virtual servers [Robert Thau] + + *) Rationalize handling of BSD in conf.h and elsewhere [Randy Terbush, + Paul Richards and a cast of thousands...] + + *) On self-identified BSD systems (we don't try to guess any more), + allocate a few extra file descriptors per virtual host with setrlimit, + if we can, to avoid running out. [Randy Terbush] + + *) Write 22-character lock file name into buffer with enough space + on startup [Konstantin Olchanski] + + *) Use archaic setpgrp() interface on NeXT, which requires it [Brian + Pinkerton] + + *) Suppress -Wall warning by casting const away in util.c [Aram Mirzadeh] + + *) Suppress -Wall warning by initializing variable in negotiation code + [Tobias Weingartner] + +Changes with Apache 0.8.12 + + *) Doesn't pause three seconds after including a CGI script which is + too slow to die off (this is done by not even trying to kill off + subprocesses, including the SIGTERM/pause/SIGKILL routine, until + after the entire document has been processed). [Robert Thau] + + *) Doesn't do SSI if Options Includes is off. (Ooops). [David Robinson] + + *) Options IncludesNoExec allows inclusion of at least text/* [Roy Fielding] + + *) Allows .htaccess files to override <Directory> sections naming the + same directory [David Robinson] + + *) Removed an efficiency hack in sub_req_lookup_uri which was + causing certain extremely marginal cases (e.g., ScriptAlias of a + *particular* index.html file) to fail. [David Robinson] + + *) Doesn't log an error when the requested URI requires + authentication, but no auth header line was supplied by the + client; this is a normal condition (the client doesn't no auth is + needed here yet). [Robert Thau] + + *) Behaves more sanely when the name server loses its mind [Sean Welch] + + *) RFC931 code compiles cleanly on old BSDI releases [Randy Terbush] + + *) RFC931 code no longer passes out name of prior clients on current + requests if the current request came from a server that doesn't + do RFC931. [David Robinson] + + *) Configuration script accepts "Module" lines with trailing whitespace. + [Robert Thau] + + *) Cleaned up compiler warning from mod_access.c [Robert Thau] + + *) Cleaned up comments in mod_cgi.c [Robert Thau] + +Changes with Apache 0.8.11 + + *) Wildcard <Directory> specifications work. [Robert Thau] + + *) Doesn't loop for buggy CGI on Solaris [Cliff Skolnick] + + *) Symlink checks (FollowSymLinks off, or SymLinkIfOwnerMatch) always check + the file being requested itself, in addition to the directories leading + up to it. [Robert Thau] + + *) Logs access failures due to symlink checks or invalid client address + in the error log [Roy Fielding, Robert Thau] + + *) Symlink checks deal correctly with systems where lstat of + "/path/to/some/link/" follows the link. [Thau, Fielding] + + *) Doesn't reset DirectoryIndex to 'index.html' when + other directory options are set in a .htaccess file. [Robert Thau] + + *) Clarified init code and nuked bogus warning in mod_access.c + [Florent Guillaume] + + *) Corrected several directives in sample srm.conf + --- includes corrections to directory indexing icon-related directives + (using unknown.gif rather than unknown.xbm as the DefaultIcon, doing + icons for encodings right, and turning on AddEncoding by default). + [Roy Fielding] + + *) Corrected descriptions of args to AddIcon and AddAlt in command table + [James Cloos] + + *) INSTALL & README mention "contributed modules" directory [Brian + Behlendorf] + + *) Fixed English in the license language... "for for" --> "for". + [Roy Fielding] + + *) Fixed ScriptAlias/Alias interaction by moving ScriptAlias handling to + mod_alias.c, merging it almost completely with handling of Alias, and + adding a 'notes' field to the request_rec which allows the CGI module + to discover whether the Alias module has put this request through + ScriptAlias (which it needs to know for back-compatibility, as the old + NCSA code did not check Options ExecCGI in ScriptAlias directories). + [Robert Thau] + + +Changes with Apache 0.8.10 + + *) AllowOverride applies to the named directory, and not just + subdirectories. [David Robinson] + + *) Do locking for accept() exclusion (on systems that need it) + using a special file created for the purpose in /usr/tmp, and + not the error log; using the error log causes real problems + if it's NFS-mounted; this is known to be the cause of a whole + lot of "server hang" problems with Solaris. [David Robinson; + thanks to Merten Schumann for help diagnosing the problem]. + +Changes with Apache 0.8.9 + + *) Compiles with -DMAXIMUM_DNS ---- ooops! [Henrik Mortensen] + + *) Nested includes see environment variables of the including document, + for NCSA bug-compatibility (some sites have standard footer includes + which try to print out the last-modified date). [Eric Hagberg/Robert + Thau] + + *) <!--exec cgi="/some/uri/here"--> always treats the item named by the + URI as a CGI script, even if it would have been treated as something + else if requested directly, for NCSA back-compatibility. (Note that + this means that people who know the name of the script can see the + code just by asking for it). [Robert Thau] + + *) New version of dbmmanage script included in support directory as + dbmmanage.new. + + *) Check if scoreboard file couldn't be opened, and say so, rather + then going insane [David Robinson] + + *) POST to CGI works on A/UX [Jim Jaglieski] + + *) AddIcon and AddAlt commands work properly [Rob Hartill] + + *) NCSA server push works properly --- the Arena bug compatibility + workaround, which broke it, is gone (use -DARENA_BUG_WORKAROUND + if you still want the workaround). [Rob Hartill] + + *) If client didn't submit any Accept-encodings, ignore encodings in + content negotiation. (NB this will all have to be reworked anyway + for the new HTTP draft). [Florent Guillaume] + + *) Don't dump core when trying to log timed-out requests [Jim Jaglieski] + + *) Really honor CacheNegotiatedDocs [Florent Guillaume] + + *) Give Redirect priority over Alias, for NCSA bug compatibility + [David Robinson] + + *) Correctly set PATH_TRANSLATED in all cases from <!--#exec cmd=""-->, + paralleling earlier bug fix for CGI [David Robinson] + + *) If DBM auth is improperly configured, report a server error and don't + dump core. + + *) Deleted FCNTL_SERIALIZED_ACCEPTS from conf.h entry for A/UX; + it seems to work well enough without it (even in a 10 hits/sec + workout), and the overhead for the locking under A/UX is + alarmingly high (though it is very low on other systems). + [Eric Hagberg] + + *) Fixed portability problems with mod_cookies.c [Cliff Skolnick] + + *) Further de-Berklize mod_cookies.c; change the bogus #include. [Brian + Behlendorf/Eric Hagberg] + + *) More improvements to default Configuration for A/UX [Jim Jaglieski] + + *) Compiles clean on NEXT [Rob Hartill] + + *) Compiles clean on SGI [Robert Thau] + +Changes with Apache 0.8.8 + + *) SunOS library prototypes now never included unless explicitly + requested in the configuration (via -DSUNOS_LIB_PROTOTYPES); + people using GNU libc on SunOS are screwed by prototypes for the + standard library. + + (Those who wish to compile clean with gcc -Wall on a standard + SunOS setup need the prototypes, and may obtain them using + -DSUNOS_LIB_PROTOTYPES. Those wishing to use -Wall on a system + with nonstandard libraries are presumably competent to make their + own arrangements). + + *) Strips trailing '/' characters off both args to the Alias command, + to make 'Alias /foo/ /bar/' work. + +Changes with Apache 0.8.7 + + *) Don't hang when restarting with a child from 'TransferLog "|..."' running + [reported by David Robinson] + + *) Compiles clean on OSF/1 [David Robinson] + + *) Added some of the more recent significant changes (AddLanguage stuff, + experimental LogFormat support) to CHANGES file in distribution root + directory + +Changes with Apache 0.8.6 + + *) Deleted Netscape reload workaround --- it's in violation of HTTP specs. + (If you actually wanted a conditional GET which bypassed the cache, you + couldn't get it). [Reported by Roy Fielding] + + *) Properly terminate headers on '304 Not Modified' replies to conditional + GETs --- no browser we can find cares much, but the CERN proxy chokes. + [Reported by Cliff Skolnick; fix discovered independently by Rob Hartill] + + *) httpd -v doesn't call itself "Shambhala". [Reported by Chuck Murcko] + + *) SunOS lib-function prototypes in conf.h conditionalized on __GNUC__, + not __SUNPRO_C (they're needed to quiet gcc -Wall, but acc chokes on 'em, + and older versions don't set the __SUNPRO_C preprocessor variable). On + all other systems, these are never used anyway. [Reported by Mark Cox]. + + *) Scoreboard file (/tmp/htstatus.*) no longer publically writable. + +Changes with Apache 0.8.5 + + *) Added last-minute configurable log experiment, as optional module + + *) Correctly set r->bytes_sent for HTTP/0.9 requests, so they get logged + properly. (One-line fix to http_protocol.c). + + *) Work around bogus behavior when reloading from Netscape. + It's Netscape's bug --- for some reason they expect a request with + If-modified-since: to not function as a conditional GET if it also + comes with Pragma: no-cache, which is way out of line with the HTTP + spec (according to Roy Fielding, the redactor). + + *) Added parameter to set maximum number of server processes. + + *) Added patches to make it work on A/UX. A/UX is *weird*. [Eric Hagberg] + + *) IdentityCheck bugfix [Chuck Murcko]. + + *) Corrected cgi-src/Makefile entry for new imagemap script. [Alexei Kosut] + + *) More sample config file corrections; add extension to AddType for + *.asis, move AddType generic description to its proper place, and + fix miscellaneous typos. [ Alexei Kosut ] + + *) Deleted the *other* reference to the regents from the Berkeley + legal disclaimer (everyplace). + + *) Nuked Shambhala name from src/README; had already cleaned it out + of everywhere else. + +Changes with Apache 0.8.4 + + *) Changes to server-pool management parms --- renamed current + StartServers to MinSpareServers, created separate StartServers + parameter which means what it says, and renamed MaxServers to + MaxSpareServers (though the old name still works, for NCSA 1.4 + back-compatibility). The old names were generally regarded as + too confusing. Also altered "docs" in sample config files. + + *) More improvements to default config files --- + sample directives (commented out) for XBitHack, BindAddress, + CacheNegotiatedDocs, VirtualHost; decent set of AddLanguage + defaults, AddTypes for send-as-is and imagemap magic types, and + improvements to samples for DirectoryIndex [Alexei Kosut] + + *) Yet more improvements to default config files --- changes to + Alexei's sample AddLanguage directives, and sample LanguagePriority + [ Florent Guillaume ] + + *) Set config file locations properly if not set in httpd.conf + [ David Robinson ] + + *) Don't escape URIs in internal redirects multiple times; don't + do that when translating PATH_INFO to PATH_TRANSLATED either. + [ David Robinson ] + + *) Corrected spelling of "Required" in 401 error reports [Andrew Wilson] + +Changes with Apache 0.8.3 + + *) Edited distribution README to *briefly* summarize installation + procedures, and give a pointer to the INSTALL file in the src/ + directory. + + *) Upgraded imagemap script in cgi-bin to 1.8 version from more + recent NCSA distributions. + + *) Bug fix to previous bug fix --- if .htaccess file and <Directory> + exist for the same directory, use both and don't segfault. [Reported + by David Robinson] + + *) Proper makefile dependencies [David Robinson] + + *) Note (re)starts in error log --- reported by Rob Hartill. + + *) Only call no2slash() after get_path_info() has been done, to + preserve multiple slashes in the PATH_INFO [NCSA compatibility, + reported by Andrew Wilson, though this one is probably a real bug] + + *) Fixed mod_imap.c --- relative paths with base_uri referer don't + dump core when Referer is not supplied. [Randy Terbush] + + *) Lightly edited sample config files to refer people to our documentation + instead of NCSA's, and to list Rob McCool as *original* author (also + deleted his old, and no doubt non-functional email address). Would be + nice to have examples of new features... + +Changes with Apache 0.8.2 + + *) Added AddLanuage code [Florent Guillaume] + + *) Don't say "access forbidden" when a CGI script is not found. [Mark Cox] + + *) All sorts of problems when MultiViews finds a directory. It would + be nice if mod_dir.c was robust enough to handle that, but for now, + just punt. [reported by Brian Behlendorf] + + *) Wait for all children on restart, to make sure that the old socket + is gone and we can reopen it. [reported by Randy Terbush] + + *) Imagemap module is enabled in default Configuration + + *) RefererLog and UserAgentLog modules properly default the logfile + [Randy Terbush] + + *) Mark Cox's mod_cookies added to the distribution as an optional + module (commented out in the default Configuration, and noted as + an experiment, along with mod_dld). [Mark Cox] + + *) Compiles on Ultrix (a continuing battle...). [Robert Thau] + + *) Fixed nasty bug in SIGTERM handling [reported by Randy Terbush] + + *) Changed "Shambhala" to "Apache" in API docs. [Robert Thau] + + *) Added new, toothier legal disclaimer. [Robert Thau; copied from BSD + license] + +Changes with Apache 0.8.1 + + *) New imagemap module [Randy Terbush] + + *) Replacement referer log module with NCSA-compatible RefererIgnore + [Matthew Gray again] + + *) Don't mung directory listings with very long filenames. + [Florent Guillaume] + +Changes with Apache 0.8.0 (nee Shambhala 0.6.2): + + *) New config script. See INSTALL for info. [Robert Thau] + + *) Scoreboard mechanism for regulating the number of extant server + processes. MaxServers and StartServers defaults are the same as + for NCSA, but the meanings are slightly different. (Actually, + I should probably lower the MaxServers default to 10). + + Before asking for a new connection, each server process checks + the number of other servers which are also waiting for a + connection. If there are more than MaxServers, it quietly dies + off. Conversely, every second, the root, or caretaker, process + looks to see how many servers are waiting for a new connection; + if there are fewer than StartServers, it starts a new one. This + does not depend on the number of server processes already extant. + The accounting is arranged through a "scoreboard" file, named + /tmp/htstatus.*, on which each process has an independent file + descriptor (they need to seek without interference). + + The end effect is that MaxServers is the maximum number of + servers on an *inactive* server machine, but more will be forked + off to handle unusually heavy loads (or unusually slow clients); + these will die off when they are no longer needed --- without + reverting to the overhead of full forking operation. There is a + hard maximum of 150 server processes compiled in, largely to + avoid forking out of control and dragging the machine down. + (This is arguably too high). + + In my server endurance tests, this mechanism did not appear to + impose any significant overhead, even after I forced it to put the + scoreboard file on a normal filesystem (which might have more + overhead than tmpfs). [Robert Thau] + + *) Set HTTP_FOO variables for SSI <!--#exec cmd-->s, not just CGI scripts. + [Cliff Skolnick] + + *) Read .htaccess files even in directory with <Directory> section. + (Former incompatibility noted on mailing list, now fixed). [Robert + Thau] + + *) "HEAD /" gives the client a "Bad Request" error message, rather + than trying to send no body *and* no headers. [Cliff Skolnick]. + + *) Don't produce double error reports for some very obscure cases + mainly involving auth configuration (the "all modules decline to + handle" case which is a sure sign of a server bug in most cases, + but also happens when authentication is badly misconfigured). + [Robert Thau] + + *) Moved FCNTL_SERIALIZED_ACCEPT defines into conf.h (that's what + it's *for*, and this sort of thing really shouldn't be cluttering + up the Makefile). [Robert Thau] + + *) Incidental code cleanups in http_main.c --- stop dragging + sa_client around; just declare it where used. [Robert Thau] + + *) Another acc-related fix. (It doesn't like const char + in some places...). [Mark Cox] + +Changes with 0.6.1 + + *) Fixed auth_name-related typos in http_core.c [Brian Behlendorf] + Also, fixed auth typo in http_protocol.c unmasked by this fix. + + *) Compiles clean with acc on SunOS [Paul Sutton] + + *) Reordered modules in modules.c so that Redirect takes priority + over ScriptAlias, for NCSA bug-compatibility [Rob Hartill] --- + believe it or not, he has an actual site with a ScriptAlias and + a Redirect declared for the *exact same directory*. Even *my* + compatibility fetish wouldn't motivate me to fix this if the fix + required any effort, but it doesn't, so what the hey. + + *) Fixed to properly default several server_rec fields for virtual + servers from the corresponding fields in the main server_rec. + [Cliff Skolnick --- 'port' was a particular irritant]. + + *) No longer kills off nph- child processes before they are + finished sending output. [Matthew Gray] + +Changes with 0.6.0 + + *) Two styles of timeout --- hard and soft. soft_timeout()s just put + the connection to the client in an "aborted" state, but otherwise + allow whatever handlers are running to clean up. hard_timeout()s + abort the request in progress completely; anything not tied to some + resource pool cleanup will leak. They're still around because I + haven't yet come up with a more elegant way of handling + timeouts when talking to something that isn't the client. The + default_handler and the dir_handler now use soft timeouts, largely + so I can test the feature. [Robert Thau] + + *) TransferLog "| my_postprocessor ..." seems to be there. Note that + the case of log handlers dying prematurely is probably handled VERY + gracelessly at this point, and if the logger stops reading input, + the server will hang. (It is known to correctly restart the + logging process on server restart; this is (should be!) going through + the same SIGTERM/pause/SIGKILL routine used to ding an errant CGI + script). [Robert Thau] + + *) asis files supported (new module). [Robert Thau] + + *) IdentityCheck code is compiled in, but has not been tested. (I + don't know anyone who runs identd). [Robert Thau] + + *) PATH_INFO and PATH_TRANSLATED are not set unless some real PATH_INFO + came in with the request, for NCSA bug-compatibility. [Robert Thau] + + *) Don't leak the DIR * on HEAD request for a directory. [Robert Thau] + + *) Deleted the block_alarms() stuff from dbm_auth; no longer necessary, + as timeouts are not in scope. [Robert Thau] + + *) quoted-string args in config files now handled correctly (doesn't drop + the last character). [Robert Thau; reported by Randy Terbush] + + *) Fixed silly typo in http_main.c which was suddenly fatal in HP-UX. + How the hell did it ever work? [Robert Thau; reported by Rob Hartill] + + *) mod_core.c --- default_type returns DEFAULT_TYPE (the compile-time + default default type); the former default default behavior when all + type-checkers defaulted had been a core dump. [Paul Sutton] + + *) Copy filenames out of the struct dirent when indexing + directories. (On Linux, readdir() returns a pointer to the same + memory area every time). Fix is in mod_dir.c. [Paul Sutton] + +Changes with 0.5.3 [not released] + + *) Default response handler notes "file not found" in the error log, + if the file was not found. [Cliff Skolnick]. + + *) Another Cliff bug --- "GET /~user" now properly redirects (the userdir + code no longer sets up bogus PATH_INFO which fakes out the directory + handler). [Cliff Skolnick] + +Changes with 0.5.2 + + *) Changes to http_main.c --- root server no longer plays silly + games with SIGCHLD, and so now detects and replaces dying + children. Child processes just die on SIGTERM, without taking + the whole process group with them. Potential problem --- if any + child process refuses to die, we hang in restart. + MaxRequestsPerChild may still not work, but it certainly works + better than it did before this! [Robert Thau] + + *) mod_dir.c bug fixes: ReadmeName and HeaderName + work (or work better, at least); over-long description lines + properly terminated. [Mark Cox] + + *) http_request.c now calls unescape_url() more places where it + should [Paul Sutton]. + + *) More directory handling bugs (reported by Cox) + Parent Directory link is now set correctly. [Robert Thau] + +Changes with 0.5.1: [Hopefully complete] 10 Apr 1995 + + *) Generalized cleanup interface in alloc.c --- any function can be + registered with alloc.c as a cleanup for a resource pool; + tracking of files and file descriptors has been reimplemented in + terms of this interface, so I can give it some sort of a test. + [Robert Thau] + + *) More changes in alloc.c --- new cleanup_for_exec() function, + which tracks down and closes all file descriptors which have been + registered with the alloc.c machinery before the server exec()s a + child process for CGI or <!--#exec-->. CGI children now get + started with exactly three file descriptors open. Hopefully, + this cures the problem Rob H. was having with overly persistent + CGI connections. [Robert Thau] + + *) Mutual exclusion around the accept() in child_main() --- this is + required on at least SGI, Solaris and Linux, and is #ifdef'ed in + by default on those systems only (-DFCNTL_SERIALIZED_ACCEPT). + This uses fcntl(F_SETLK,...) on the error log descriptor because + flock() on that descriptor won't work on systems which have BSD + flock() semantics, including (I think) Linux 1.3 and Solaris. + + This does work on SunOS (when the server is idle, only one + process in the pool is waiting on accept()); it *ought* to work + on the other systems. [Robert Thau] + + *) FreeBSD and BSDI portability tweaks [Chuck Murcko] + + *) sizeof(*sa_client) bugfix from [Rob Hartill] + + *) pstrdup(..., NULL) returns NULL, [Randy Terbush] + + *) block_alarms() to avoid leaking the DBM* in dbm auth (this should + be unnecessary if I go to the revised timeout-handling scheme). + [Robert Thau] + + *) For NCSA bug-compatibility, set QUERY_STRING env var (to a null + string) even if none came in with the request. [Robert Thau] + + *) CHANGES file added to distribution ;-). + +Changes with 0.4 02 Apr 1995 + + *) Patches by Brian Behlendorf, Andrew Wilson, Robert Thau, + and Rob Hartill. + +Changes with 0.3 24 Mar 1995 + + *) Patches by Robert Thau, David Robinson, Rob Hartill, and + Carlos Varela + +Changes with 0.2 18 Mar 1995 + + *) Based on NCSA httpd 1.3 by Rob McCool and patches by CERT, + Roy Fielding, Robert Thau, Nicolas Pioch, David Robinson, + Brian Behlendorf, Rob Hartill, and Cliff Skolnick diff --git a/APACHE_1_2_X/src/Configuration.tmpl b/APACHE_1_2_X/src/Configuration.tmpl new file mode 100644 index 00000000000..06446d7fc9a --- /dev/null +++ b/APACHE_1_2_X/src/Configuration.tmpl @@ -0,0 +1,289 @@ +# Config file for the Apache httpd. + +# Configuration.tmpl is the template for Configuration. Configuration should +# be edited to select the modules to be included as well as various flags +# for Makefile. + +# The template should only be changed when a new system or module is added, +# or an existing one modified. This will also most likely require some minor +# changes to Configure to recognize those changes. + +# There are 5 types of lines here: + +# '#' comments, distinguished by having a '#' as the first non-blank character +# +# Makefile options, such as CC=gcc, etc... +# +# Rules, distinquished by having "Rule" at the front. These are used to +# control Configure's behavior as far as how to create Makefile. +# +# Module selection lines, distinguished by having 'Module' at the front. +# These list the configured modules, in priority order (highest priority +# first). They're down at the bottom. +# +# Optional module selection lines, distinguished by having `%Module' +# at the front. These specify a module that is to be compiled in (but +# not enabled). The AddModule directive can be used to enable such a +# module. By default no such modules are defined. + + +################################################################ +# Makefile configuration +# +# These are added to the general flags determined by Configure. +# Edit these to work around Configure if needed. The EXTRA_* family +# will be added to the regular Makefile flags. For example, if you +# want to compile with -Wall, then add that to EXTRA_CFLAGS. These +# will be added to whatever flags Configure determines as appropriate +# and needed for your platform. +# +# You can also set the compiler and Optimization used here as well. +# Settings here have priority; If not set, Configure will attempt to guess +# the C compiler, and set OPTIM to '-O2' +# +EXTRA_CFLAGS= +EXTRA_LFLAGS= +EXTRA_LIBS= +EXTRA_INCLUDES= + +#CC= +#OPTIM=-O2 +#RANLIB= + +################################################################ +# Rules configuration +# +# These are used to let Configure know that we want certain +# functions. The format is: Rule RULE=value +# +# At present, only the following RULES are known: WANTHSREGEX, SOCKS4, +# STATUS, and IRIXNIS. +# +# For all Rules, if set to "yes", then Configure knows we want that +# capability and does what is required to add it in. If set to "default" +# then Configure makes a "best guess"; if set to anything else, or not +# present, then nothing is done. +# +# SOCKS4: +# If SOCKS4 is set to 'yes', be sure that you add the sock library +# location to EXTRA_LIBS, otherwise Configure will assume +# "-L/usr/local/lib -lsocks" +# +# STATUS: +# If Configure determines that you are using the status_module, +# it will automatically enable full status information if set +# to 'yes'. If the status module is not included, having STATUS +# set to 'yes' has no impact. +# +# IRIXNIS: +# Only takes effect if Configure determines that you are running +# SGI IRIX. If you are, and you are using NIS, you should set this +# to 'yes' +# + +Rule STATUS=yes +Rule SOCKS4=no +Rule IRIXNIS=no + +# The following rules should be set automatically by Configure. However, if +# they are not set by Configure (because we don't know the correct value for +# your platform), or are set incorrectly, you may override them here. +# If you have to do this, please let us know what you set and what your +# platform is, by filling out a problem report form at the Apache web site: +# <http://www.apache.org/bugdb.cgi>. If your browser is forms-incapable, +# you can get the information to us by sending mail to apache-bugs@apache.org. +# +# WANTHSREGEX: +# Apache requires a POSIX regex implementation. Henry Spencer's +# excellent regex package is included with Apache and can be used +# if desired. If your OS has a decent regex, you can elect to +# not use this one by setting WANTHSREGEX to 'no' or commenting +# out the Rule. The "default" action is "no" unless overruled +# by OS specifics + +Rule WANTHSREGEX=default + +################################################################ +# Module configuration +# +# Modules are listed in reverse priority order --- the ones that come +# later can override the behavior of those that come earlier. This +# can have visible effects; for instance, if UserDir followed Alias, +# you couldn't alias out a particular user's home directory. + +# The configuration below is what we consider a decent default +# configuration. If you want the functionality provided by a particular +# module, remove the "#" sign at the beginning of the line. But remember, +# the more modules you compile into the server, the larger the executable +# is and the more memory it will take, so if you are unlikely to use the +# functionality of a particular module you might wish to leave it out. + +## +## Config manipulation modules +## +## mod_env sets up additional or restricted environment variables to be +## passed to CGI/SSI scripts. It is listed first (lowest priority) since +## it does not do per-request stuff. + +Module env_module mod_env.o + +## mod_dld defines commands that allow other modules to be loaded +## dynamically (at runtime). This module is for experimental use only. + +# Module dld_module mod_dld.o + +## +## Request logging modules +## + +Module config_log_module mod_log_config.o + +## Optional modules for NCSA user-agent/referer logging compatibility +## We recommend, however, that you just use the configurable access_log. + +# Module agent_log_module mod_log_agent.o +# Module referer_log_module mod_log_referer.o + +## +## Type checking modules +## +## mod_mime maps filename extensions to content types, encodings, and +## magic type handlers (the latter is obsoleted by mod_actions). +## mod_negotiation allows content selection based on the Accept* headers. + +Module mime_module mod_mime.o +Module negotiation_module mod_negotiation.o + +## +## Content delivery modules +## +## The status module allows the server to display current details about +## how well it is performing and what it is doing. Consider also enabling +## STATUS=yes (see the Rules section near the start of this file) to allow +## full status information. Check conf/access.conf on how to enable this. + +# Module status_module mod_status.o + +## The Info module displays configuration information for the server and +## all included modules. It's very useful for debugging. + +# Module info_module mod_info.o + +## mod_include translates server-side include (SSI) statements in text files. +## mod_dir handles requests on directories and directory indexes. +## mod_cgi handles CGI scripts. + +Module includes_module mod_include.o +Module dir_module mod_dir.o +Module cgi_module mod_cgi.o + +## The asis module implemented ".asis" file types, which allow the embedding +## of HTTP headers at the beginning of the document. mod_imap handles internal +## imagemaps (no more cgi-bin/imagemap/!). mod_actions is used to specify +## CGI scripts which act as "handlers" for particular files, for example to +## automatically convert every GIF to another file type. + +Module asis_module mod_asis.o +Module imap_module mod_imap.o +Module action_module mod_actions.o + +## +## URL translation modules. +## +## The UserDir module for selecting resource directories by user name +## and a common prefix, e.g., /~<user> , /usr/web/<user> , etc. + +Module userdir_module mod_userdir.o + +## The proxy module enables the server to act as a proxy for outside +## http and ftp services. It's not as complete as it could be yet. +## NOTE: You do not want this module UNLESS you are running a proxy; +## it is not needed for normal (origin server) operation. + +# Module proxy_module modules/proxy/libproxy.a + +## The Alias module provides simple URL translation and redirection. + +Module alias_module mod_alias.o + +## mod_rewrite allows for powerful URI-to-URI and URI-to-filename mapping, +## using regular expressions. + +# Module rewrite_module mod_rewrite.o + +## +## Access control and authentication modules. +## +Module access_module mod_access.o +Module auth_module mod_auth.o + +## The anon_auth module allows for anonymous-FTP-style username/ +## password authentication. + +# Module anon_auth_module mod_auth_anon.o + +## db_auth and dbm_auth work with Berkeley DB files - make sure there +## is support for DBM files on your system. You may need to grab the GNU +## "gdbm" package if not and possibly adjust EXTRA_LIBS. (This may be +## done by Configure at a later date) + +# Module db_auth_module mod_auth_db.o +# Module dbm_auth_module mod_auth_dbm.o + +## msql_auth checks against an mSQL database. You must have mSQL installed +## and an "msql.h" available for this to even compile. Additionally, +## you may need to add a couple entries to the EXTRA_LIBS line, like +## +## -lmsql -L/usr/local/lib -L/usr/local/Minerva/lib +## +## This depends on your installation of mSQL. (This may be done by Configure +## at a later date) + +# Module msql_auth_module mod_auth_msql.o + +## "digest" implements HTTP Digest Authentication rather than the less +## secure Basic Auth used by the other modules. + +# Module digest_module mod_digest.o + +## Optional response header manipulation modules. +## +## cern_meta mimics the behavior of the CERN web server with regards to +## metainformation files. + +# Module cern_meta_module mod_cern_meta.o + +## The expires module can apply Expires: headers to resources, +## as a function of access time or modification time. + +# Module expires_module mod_expires.o + +## The headers module can set arbitrary HTTP response headers, +## as configured in server, vhost, access.conf or .htaccess configs + +# Module headers_module mod_headers.o + +## Miscellaneous modules +## +## mod_usertrack.c is the new name for mod_cookies.c. This module +## uses Netscape cookies to automatically construct and log +## click-trails from Netscape cookies, or compatible clients who +## aren't coming in via proxy. +## +## You do not need this, or any other module to allow your site +## to use Cookies. This module is for user tracking only + +# Module usertrack_module mod_usertrack.o + +## The example module, which demonstrates the use of the API. See +## the file modules/example/README for details. This module should +## only be used for testing -- DO NOT ENABLE IT on a production server. + +# Module example_module modules/example/mod_example.o + +## mod_browser lets you set environment variables based on the User-Agent +## string in the request; this is useful for conditional HTML, for example. +## Since it is also used to detect buggy browsers for workarounds, it +## should be the last (highest priority) module. + +Module browser_module mod_browser.o diff --git a/APACHE_1_2_X/src/Configure b/APACHE_1_2_X/src/Configure new file mode 100755 index 00000000000..dc526abe3e3 --- /dev/null +++ b/APACHE_1_2_X/src/Configure @@ -0,0 +1,645 @@ +#!/bin/sh +trap 'rm -f $tmpfile; exit' 0 1 2 3 15 + +# Apache configuration script, first cut --- rst. +# Dont like it? Inspired to do something better? Go for it. + +# second cut --- jmj +# At this point we change what Configuration contains. It maintain +# contains comments, specific compiler flags, a list of included +# modules and "rules". These rules are used to allow Configure to +# be totally configured from Configuration +# +# Uses 3 supplemental scripts located in ./helpers: CutRule, +# GuessOS and PrintPath +# + +file=Configuration +tmpfile=htconf.$$ +makefile_tmpl=Makefile.tmpl + +while [ "x$1" != "x" ]; do + if [ "x$1" = "x-file" ] ; then + shift 1; file=$1; shift 1 + if [ ! -r $file ]; then + echo "$file does not exist or is not readable." + exit 1 + fi + elif [ "x$1" = "x-make" ] ; then + shift 1; makefile_tmpl=$1; shift 1 + if [ ! -r $makefile_tmpl ]; then + echo "$makefile_tmpl does not exist or is not readable." + exit 1 + fi + else + echo "Ignoring command line option '$1'" + shift 1 + fi +done +echo "Using config file: $file" +echo "Using Makefile template file: $makefile_tmpl" + +if [ ! -r $file ]; then + echo "Can't see or read \"$file\"" + exit 1 +fi + +# First, strip comments and blank lines and then change Rules to comments +# and then remove whitespace before Module declarations + +sed 's/#.*//' $file | \ + sed '/^[ ]*$/d' | \ + sed 's/[ ]*$//' | \ + sed 's/^Rule[ ]*/##Rule:/' | \ + sed 's/^[ ]*Module/Module/' | \ + sed 's/^[ ]*%Module/%Module/' > $tmpfile + +# Check for syntax errors... + +if egrep -v '^%?Module[ ]+[A-Za-z0-9_]+[ ]+[^ ]+$' $tmpfile \ + | grep -v = > /dev/null +then + echo "Syntax error --- The configuration file is used only to" + echo "define the list of included modules or to set Makefile" + echo "options or Configure rules, and I don't see that at all:" + egrep -v '^Module[ ]+[A-Za-z0-9_]+[ ]+[^ ]+$' $tmpfile | \ + grep -v = + exit 1 +fi + +# File is OK --- make backup copies of things and then get the new ones: + +if [ -f Makefile ] ; then mv Makefile Makefile.bak; fi +if [ -f modules.c ] ; then mv modules.c modules.c.bak; fi + +sed -e 's/_module//' $tmpfile | awk >modules.c '\ + BEGIN { modules[n++] = "core" ; pmodules[pn++] = "core"} \ + /^Module/ { modules[n++] = $2 ; pmodules[pn++] = $2 } \ + /^%Module/ { pmodules[pn++] = $2 } \ + END { print "/* modules.c --- automatically generated by Apache"; \ + print " * configuration script. DO NOT HAND EDIT!!!!!"; \ + print " */"; \ + print ""; \ + print "#include \"httpd.h\""; \ + print "#include \"http_config.h\""; \ + print ""; \ + for (i = 0; i < pn; ++i) { \ + printf ("extern module %s_module;\n", pmodules[i]); \ + } \ + print ""; \ + print "module *prelinked_modules[] = {"; \ + for (i = 0; i < n; ++i) { \ + printf " &%s_module,\n", modules[i]; \ + } \ + print " NULL"; \ + print "};"; \ + print "module *preloaded_modules[] = {"; \ + for (i = 0; i < pn; ++i) { \ + printf " &%s_module,\n", pmodules[i]; \ + } \ + print " NULL"; \ + print "};"; \ + }' + +# +# Add module set only +# +echo "#" > Makefile +echo "# Makefile automatically generated from $makefile_tmpl" >> Makefile +echo "# and configuration file by Apache config script." >> Makefile +echo "# Hand-edited changes will be lost if the config script" >> Makefile +echo "# is re-run" >> Makefile +echo "#" >> Makefile + +awk >>Makefile <$tmpfile '\ + /^Module/ { modules[n++] = $3 } \ + /^%Module/ { modules[n++] = $3 } \ + END { print "MODULES=\\"; \ + for (i = 0; i < n; ++i) { \ + if (i < n-1) printf (" %s \\\n", modules[i]); \ + else printf (" %s\n", modules[i]); \ + } \ + print "" \ + }' +# +# Now add Makefile additions and Rules +# +awk >>Makefile <$tmpfile '\ + BEGIN { print "# Makefile options inherited from Configure"; \ + print "###############"; \ + } \ + /\=/ { print } \ + END { print "###############"; }' + +# +# Extract the rules. +# +RULE_WANTHSREGEX=`./helpers/CutRule WANTHSREGEX $file` +RULE_STATUS=`./helpers/CutRule STATUS $file` +RULE_SOCKS4=`./helpers/CutRule SOCKS4 $file` +RULE_IRIXNIS=`./helpers/CutRule IRIXNIS $file` + +# +# Now we determine the OS/Platform automagically, thanks to +# GuessOS, a home-brewed OS-determiner ala config.guess +# +# We adjust CFLAGS, LIBS, LFLAGS and INCLUDES (and other Makefile +# options) as required. Setting CC and OPTIM here has no effect +# if they were set in Configure. +# +# Also, we set DEF_WANTHSREGEX and to the appropriate +# value for each platform. +# +# As more PLATFORMs are added to Configuration.tmpl, be sure to +# add the required lines below. +# + +PLAT=`./helpers/GuessOS` + +# Preset DBM_LIB. Can be overridden on a per-platform basis. + +DBM_LIB="-ldbm" + +# +# Look for ranlib. Do it early in case we want to override it below +# +if ./helpers/PrintPath -s ranlib; then + RANLIB="ranlib" +else + RANLIB="true" +fi + +# +# We now look for popular compilers. As with ranlib, we +# do this early because some options may depend +# on which compiler we use/find +# +for compilers in "gcc" "cc" "acc" "c89" +do + lookedfor="$lookedfor $compilers" + if ./helpers/PrintPath -s $compilers; then + COMPILER="$compilers" + break + fi +done + +# +SHELL="/bin/sh" + +case "$PLAT" in + *MPE/iX*) + OS='MPE/iX' + CFLAGS="$CFLAGS -DMPE -D_POSIX_SOURCE -D_SOCKET_SOURCE" + LIBS="$LIBS -lsocket" + LFLAGS="$LFLAGS -Xlinker \"-WL,cap=ia,ba,ph,pm;nmstack=1024000\"" + ;; + *-apple-aux3*) + OS='A/UX 3.1.x' + CFLAGS="$CFLAGS -DAUX -D_POSIX_SOURCE" + LIBS="$LIBS -lposix -lbsd" + LFLAGS="$LFLAGS -s" + DEF_WANTHSREGEX=no + ;; + i386-ibm-aix*) + OS='IBM AIX PS/2' + CFLAGS="$CFLAGS -DAIX -U__STR__ -DUSEBCOPY" + DEF_WANTHSREGEX=no + ;; + *-ibm-aix*) + OS='IBM AIX' + CFLAGS="$CFLAGS -DAIX -U__STR__" + ;; + *-apollo-*) + OS='Apollo Domain' + CFLAGS="$CFLAGS -DAPOLLO" + ;; + *-dg-dgux*) + OS='DG/UX 5.4' + CFLAGS="$CFLAGS -DDGUX" + DEF_WANTHSREGEX=yes + ;; + *OS/2*) + DEF_WANTHSREGEX=yes + OS='EMX OS/2' + CFLAGS="$CFLAGS -Zbsd-signals -Zbin-files -DTCPIPV4 -g" + LIBS="$LIBS -lsocket -llibufc -lbsd" + DBM_LIB="-lgdbm" + ;; + *-hi-hiux) + OS='HI-UX' + CFLAGS="$CFLAGS -DHIUX" + # if we're using the HIUX compiler, add a few flags. + if [ "$CC" = "cc" ] || [ "$COMPILER" = "cc" ]; then + CFLAGS="$CFLAGS -Aa -D_HIUX_SOURCE" + OPTIM=" " + fi + ;; + *-hp-hpux10.*) + OS='HP-UX 10' + CFLAGS="$CFLAGS -DHPUX10" + # if we're using the HPUX compiler, add a few flags. + if [ "$CC" = "cc" ] || [ "$COMPILER" = "cc" ]; then + CFLAGS="$CFLAGS -Aa -D_HPUX_SOURCE" + OPTIM=" " + fi + ;; + *-hp-hpux*) + OS='HP-UX' + CFLAGS="$CFLAGS -DHPUX" + if [ "$CC" = "cc" ] || [ "$COMPILER" = "cc" ]; then + CFLAGS="$CFLAGS -Aa -D_HPUX_SOURCE" + OPTIM=" " + fi + ;; + *-sgi-irix64) +# Note: We'd like to see patches to compile 64-bit, but for now... + echo "You are running 64-bit Irix. For now, we will compile 32-bit" + echo "but if you would care to port to 64-bit, send us the patches." + CFLAGS="$CFLAGS -n32" + LFLAGS="$LFLAGS -n32" + DEF_WANTHSREGEX=yes + DBM_LIB="" + if [ "$RULE_IRIXNIS" = "yes" ]; then + OS='SGI IRIX w/NIS' + CFLAGS="$CFLAGS -DIRIX" + LIBS="$LIBS -lsun" + else + OS='SGI IRIX' + CFLAGS="$CFLAGS -DIRIX" + fi + ;; + *-sgi-irix) + DEF_WANTHSREGEX=yes + DBM_LIB="" + if [ "$RULE_IRIXNIS" = "yes" ]; then + OS='SGI IRIX w/NIS' + CFLAGS="$CFLAGS -DIRIX" + LIBS="$LIBS -lsun" + else + OS='SGI IRIX' + CFLAGS="$CFLAGS -DIRIX" + fi + ;; + *-linux2) + DEF_WANTHSREGEX=yes + OS='Linux' + CFLAGS="$CFLAGS -DLINUX=2" + ;; + *-linux1) + DEF_WANTHSREGEX=yes + OS='Linux' + CFLAGS="$CFLAGS -DLINUX=1" + ;; + *-lynx-lynxos*) + OS='LynxOS' + CFLAGS="$CFLAGS -DLYNXOS" + LIBS="$LIBS -lbsd -ldes -lc_p" + ;; + *486-*-bsdi*) + OS='BSDI w/486' + CFLAGS="$CFLAGS -m486" + DBM_LIB="" + ;; + *-bsdi*) + OS='BSDI' + DBM_LIB="" + ;; + *486-*-freebsd*|*486-*-netbsd*) + OS='FreeBSD/NETBSD on 486' + LIBS="$LIBS -lcrypt" + DBM_LIB="" + ;; + *-freebsd*|*-netbsd*) + OS='FreeBSD/NetBSD' + LIBS="$LIBS -lcrypt" + DBM_LIB="" + ;; + *-openbsd*) + OS='OpenBSD' + ;; + *-next-nextstep*) + OS='NeXT' + CFLAGS="$CFLAGS -DNEXT" + DEF_WANTHSREGEX=yes + RANLIB="sleep 5; /bin/ranlib" + # ranlib on most NeXTs sets the time wrong. 5 secs wait does much good + ;; + *-dec-osf*) + OS='DEC OSF/1' + CFLAGS="$CFLAGS -DOSF1" + LIBS="$LIBS -lm" + ;; + *-qnx) + OS='QNX' + CFLAGS="$CFLAGS -DQNX" + LIBS="$LIBS -N128k -lsocket" + DEF_WANTHSREGEX=yes + ;; + *-qnx32) + OS='QNX32' + CFLAGS="$CFLAGS -DQNX -mf -3" + LIBS="$LIBS -N128k -lsocket" + DEF_WANTHSREGEX=yes + ;; + *-isc4*) + OS='ISC 4' + CC='gcc' + CFLAGS="$CFLAGS -posix -DISC" + LFLAGS="$LFLAGS -posix" + LIBS="$LIBS -linet" + DEF_WANTHSREGEX=yes + ;; + *-sco3*) + OS='SCO 3' + CFLAGS="$CFLAGS -DSCO -Oacgiltz" + LIBS="$LIBS -lPW -lsocket -lmalloc -lcrypt_i" + DEF_WANTHSREGEX=yes + ;; + *-sco5*) + OS='SCO 5' + CFLAGS="$CFLAGS -DSCO5" + LIBS="$LIBS -lsocket -lmalloc -lprot" + OSBPRINTF="-K noinline" + DEF_WANTHSREGEX=no + ;; + *-solaris2*) + OS='Solaris 2' + CFLAGS="$CFLAGS -DSOLARIS2" + LIBS="$LIBS -lsocket -lnsl" + DBM_LIB="" + DEF_WANTHSREGEX=yes + ;; + *-sunos4*) + OS='SunOS 4' + CFLAGS="$CFLAGS -DSUNOS4 -DUSEBCOPY" + DEF_WANTHSREGEX=yes + ;; + *-unixware1) + DEF_WANTHSREGEX=yes + OS='Unixware' + CFLAGS="$CFLAGS -DSVR4 -DNO_LINGCLOSE" + LIBS="$LIBS -lsocket -lnsl -lcrypt" + ;; + *-unixware2) + DEF_WANTHSREGEX=yes + OS='Unixware' + CFLAGS="$CFLAGS -DSVR4 -DNO_LINGCLOSE" + LIBS="$LIBS -lsocket -lnsl -lcrypt" + ;; + *-unixware211) + OS='Unixware 2.1.1' + CFLAGS="$CFLAGS -DUW" + LIBS="$LIBS -lsocket -lnsl -lcrypt" + ;; + *-sni-sysv4*) + OS='SVR4' + CFLAGS="$CFLAGS -DSVR4" + DEF_WANTHSREGEX=yes + LIBS="$LIBS -lsocket -lnsl -lc" + ;; + DS/90\ 7000-*-sysv4*) + OS='UXP/DS' + CFLAGS="$CFLAGS -DUXPDS" + LIBS="$LIBS -lsocket -lnsl" + DEF_WANTHSREGEX=yes + ;; + *-sysv4*) + OS='SVR4' + CFLAGS="$CFLAGS -DSVR4" + LIBS="$LIBS -lsocket -lnsl -lc" + ;; + *-uts*) + OS='Amdahl UTS' + CFLAGS="$CFLAGS -Xa -eft -DUTS21" + LIBS="$LIBS -lsocket -lbsd -la" + ;; + *-ultrix) + OS='ULTRIX' + CFLAGS="-DULTRIX" + DEF_WANTHSREGEX=yes + SHELL="/bin/sh5" + ;; + *powerpc-tenon-machten*) + OS='MachTen PPC' + LFLAGS="$LFLAGS -Xlstack=0x14000 -Xldelcsect" + ;; + *-machten*) + OS='MachTen 68K' + LFLAGS="$LFLAGS -stack 0x14000" + DEF_WANTHSREGEX=yes + ;; + *convex-v11*) + OS='CONVEXOS11' + CFLAGS="$CFLAGS -DCONVEXOS11" + CC='cc' + DEF_WANTHSREGEX=yes + ;; + i860-intel-osf1) + DEF_WANTHSREGEX=yes + OS='Paragon OSF/1' + CFLAGS="$CFLAGS -DPARAGON" + ;; + *) # default: Catch systems we don't know about + echo Sorry, but we cannot grok \"$PLAT\" + echo uname -m + uname -m + echo uname -r + uname -r + echo uname -s + uname -s + echo uname -v + uname -v + echo uname -X + uname -X + echo Ideally, read the file PORTING, do what it says, and send the + echo resulting patches to The Apache Group by filling out a report + echo form at http://www.apache.org/bugdb.cgi - or, if your browser + echo isn\'t forms-capable, you can send them via email to + echo apache-bugs@apache.org. If you don\'t wish to do the port + echo yourself, please submit this output rather than the patches. + echo Thank you + exit 1 + ;; +esac + +# +# See if we need to override WANTHSREGEX +# +if [ "$RULE_WANTHSREGEX" = "default" ]; then + if [ "x$DEF_WANTHSREGEX" = "x" ]; then + RULE_WANTHSREGEX=no + else + RULE_WANTHSREGEX=$DEF_WANTHSREGEX + fi +fi + +# Show the final values of the rules + +echo "###############" > Makefile.config +echo "# Platform: $OS" >> Makefile.config +echo "# Final Rules:" >> Makefile.config +echo "# Rule WANTHSREGEX=$RULE_WANTHSREGEX" >> Makefile.config +echo "###############" >> Makefile.config + +# +# Now that _that's_ done, get on with it +# + +echo " + configured for $OS platform" + +# +# Now we determine the C-compiler and optimization level +# to use. Settings of CC and OPTIM in Configuration have +# the highest precedence; next comes any settings from +# the above "OS-specific" section. If still unset, +# then we use the "found" location of COMPILERS above +# and set a "safe" optimization level +# + +if egrep "^CC[ ]*=" Makefile > /dev/null; then + CC="" # clear it just in case +else + if [ "x$CC" = "x" ]; then + if [ "x$COMPILER" = "x" ]; then + echo "Error: could not find any of these C compilers" + echo " anywhere in your PATH: $lookedfor" + echo "Configure terminated" + exit 1 + fi + CC=$COMPILER + fi + echo " + setting C compiler to $CC" +fi + +# +# Ditto for optimization +# +if egrep "^OPTIM[ ]*=" Makefile > /dev/null; then + OPTIM="" # ditto +else + if [ "x$OPTIM" = "x" ]; then + OPTIM="-O2" + fi + echo " + setting C compiler optimization-level to $OPTIM" +fi + +# +# Are they using the status monitor module? If so, check +# for STATUS rule... +# +STAT_MOD="mod_status" +if grep "$STAT_MOD" Makefile > /dev/null; then + if [ "$RULE_STATUS" = "yes" ]; then + CFLAGS="$CFLAGS -DSTATUS" + fi +fi + +# +# Are they using dbm auth? If so, add DBM library. +# +if grep mod_auth_dbm Makefile > /dev/null; then + LIBS="$LIBS $DBM_LIB" +fi + +# +# Now HS's POSIX regex implementation if needed/wanted +# +if [ "$RULE_WANTHSREGEX" = "yes" ]; then + REGLIB="regex/libregex.a" + INCLUDES="$INCLUDES -Iregex" +fi + +# +# Now SOCKS4. +# NOTE: We assume that if they are using SOCKS4, then they've +# adjusted EXTRA_LIBS and/or EXTRA_LFLAGS as required, +# otherwise we assume "-L/usr/local/lib -lsocks" +# +if [ "$RULE_SOCKS4" = "yes" ]; then + # Set flag and check Makefile for -lsocks line + CFLAGS="$CFLAGS -Dconnect=Rconnect -Dselect=Rselect" + CFLAGS="$CFLAGS -Dgethostbyname=Rgethostbyname" + if [ "$OS" = "Solaris 2" ]; then + LIBS="$LIBS -lresolv" + fi + if grep "EXTRA_" Makefile | grep "\-lsocks" > /dev/null; then : ; + else + LIBS="$LIBS -L/usr/local/lib -lsocks" + fi +fi + +# +# Good enough +# +echo >> Makefile +if [ "x$CC" != "x" ]; then + echo "CC=$CC" >> Makefile.config +fi +if [ "x$OPTIM" != "x" ]; then + echo "OPTIM=$OPTIM" >> Makefile.config +fi +echo "CFLAGS1=$CFLAGS">> Makefile.config +echo "INCLUDES1=$INCLUDES">> Makefile.config +echo "LIBS1=$LIBS">> Makefile.config +echo "LFLAGS1=$LFLAGS">> Makefile.config +echo "BROKEN_BPRINTF_FLAGS=$OSBPRINTF">> Makefile.config +echo "REGLIB=$REGLIB">> Makefile.config +echo "RANLIB=$RANLIB">> Makefile.config +echo "SHELL=$SHELL">> Makefile.config +echo >> Makefile.config +echo "#### End of Configure created section ####">> Makefile.config + + +# Now (finish) creating the makefiles +cat Makefile.config >> Makefile +sed -e "s#@@Configuration@@#$file#" "$makefile_tmpl" >>Makefile +awk >>Makefile <$tmpfile \ + '($1 == "Module" && $3 ~ /modules\//) { printf "%s: modules/last-built ; @cat /dev/null\n\n", $3, $3}' +cat Makefile.config ../support/Makefile.tmpl > ../support/Makefile + +cat << EOF > modules/Makefile +# +# Simple Makefile for modules in src/modules. +# Generated by src/Configure according to rules in src/Configuration; +# hand-edit at your own risk! +# + +SHELL=$SHELL +EOF + +if [ "$RULE_WANTHSREGEX" = "yes" ]; then + INCLUDES2="-I../../regex" +fi + +echo "INCLUDES2=$INCLUDES2">> modules/Makefile +echo "MOD_CFLAGS=\$(INCLUDES2) \$(AUX_CFLAGS)">> modules/Makefile + +awk >> modules/Makefile < $tmpfile '\ + BEGIN {printf "MODULES="} \ + ($1 == "Module" && $3 ~ /modules\//) {split ($3, pp, "/"); printf "%s ", pp[2]} \ + END {printf "\n"}' + +awk >> modules/Makefile < $tmpfile '\ + BEGIN {printf "CLEANERS="} \ + ($1 == "Module" && $3 ~ /modules\//) {split ($3, pp, "/"); printf "%s_clean ", pp[2]} \ + END {printf "\n"}' + +cat << EOF >> modules/Makefile + +default: \$(MODULES) + @echo "Done building module subdirectories" + +clean: \$(CLEANERS) + @echo "Done cleaning module subdirectories" + +\$(MODULES): ForceMe + (cd \$@; \$(MAKE) CC=\$(CC) AUX_CFLAGS='\$(MOD_CFLAGS)' RANLIB='\$(RANLIB)') + +ForceMe: + +EOF + +awk >>modules/Makefile <$tmpfile \ + '($1 == "Module" && $3 ~ /modules\//) { split ($3, pp, "/"); \ + printf "%s_clean:\n\t(cd %s; $(MAKE) clean)\n\n", pp[2], pp[2]}' + diff --git a/APACHE_1_2_X/src/INSTALL b/APACHE_1_2_X/src/INSTALL new file mode 100644 index 00000000000..e5dcfa54407 --- /dev/null +++ b/APACHE_1_2_X/src/INSTALL @@ -0,0 +1,71 @@ +This release of Apache supports the notion of "optional modules". +However, the server has to know which modules are compiled into it, in +order for those modules to be effective; this requires generation of a +short bit of code ("modules.c") which simply has a list of them. + +It is also necessary to choose the correct options for your platform. + +To do this: + +1) Copy the file "Configuration.tmpl" to "Configuration" and then edit + "Configuration". This contains the list and settings of various + "Rules" and an additional section at the bottom which + lists the modules which have been compiled in, and also names the + files containing them. You will need to: + + a) Adjust the Rules and EXTRA_CFLAGS|LIBS|LFLAGS|INCLUDES if + you feel so inclined. + + b) Uncomment lines corresponding to those optional modules you wish + to include (among the Module lines at the bottom of the file), + or add new lines corresponding to custom modules you have written. + (See API.html for preliminary docs on how to do that). + + Note that DBM auth has to be explicitly configured in, if you want + it --- just uncomment the corresponding line. + +2) Run the "Configure" script: + + % ./Configure + Using config file: Configuration + Using Makefile template file: Makefile.tmpl + + configured for <whatever> platform + + setting C compiler to <whatever> * + + setting C compiler optimization-level to <whatever> * + % + + This generates new versions of the Makefile and of modules.c. (If + you want to maintain multiple configurations, you can say, e.g., + + % ./Configure -file Configuration.ai + Using config file: Configuration.ai + Using Makefile template file: Makefile.tmpl + + configured for <whatever> platform + + setting C compiler to <whatever> * + + setting C compiler optimization-level to <whatever> * + % + + (*: Depending on Configuration and your system, Configure + make not print these lines. That's OK) + +3) Type "make". + +The modules we place in the Apache distribution are the ones we have +tested and are used regularly by various members of the Apache +development group. Additional modules contributed by members or third +parties with specific needs or functions are available at +<URL:http://www.apache.org/dist/contrib/modules/>. There are +instructions on that page for linking these modules into the +core Apache code. + +If during compilation you get a warning about a missing 'regex.h', set +WANTHSREGEX=yes in the 'Configuration', and let The Apache Group know +you needed to do this for your OS by filling out a problem report form +at <http://www.apache.org/bugdb.cgi>, or by sending a mail message to +apache-bugs@apache.org. Include the output of the command "uname -a". + + +-------------------------------------------------------------------- + +Now that you have compiled Apache, go back to the README file in the +top-level directory of this distribution to continue the installation. diff --git a/APACHE_1_2_X/src/Makefile.tmpl b/APACHE_1_2_X/src/Makefile.tmpl new file mode 100644 index 00000000000..54352ace964 --- /dev/null +++ b/APACHE_1_2_X/src/Makefile.tmpl @@ -0,0 +1,126 @@ +# Apache makefile template (well, suffix). + +# This is combined with the information in the "Configuration" file +# by the configure script to make the actual Makefile. + +CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) +LIBS=$(EXTRA_LIBS) $(LIBS1) +INCLUDES=$(INCLUDES1) $(EXTRA_INCLUDES) +LFLAGS=$(LFLAGS1) $(EXTRA_LFLAGS) + +OBJS= alloc.o http_main.o http_core.o http_config.o http_request.o \ + http_log.o http_protocol.o rfc1413.o util.o util_script.o modules.o buff.o\ + md5c.o util_md5.o explain.o http_bprintf.o util_date.o util_snprintf.o\ + $(MODULES) + +.c.o: + $(CC) -c $(INCLUDES) $(CFLAGS) $(SPACER) $< + +all: @@Configuration@@ httpd + +@@Configuration@@: Configuration.tmpl + @echo "@@Configuration@@ older than Configuration.tmpl, or doesn't exist." + @echo "Consider copying Configuration.tmpl to @@Configuration@@, editing and rerunning" + @echo "Configure." + @echo "If not, you will at least have to touch @@Configuration@@." + @false + +httpd: $(REGLIB) $(OBJS) + $(CC) $(LFLAGS) -o httpd $(OBJS) $(REGLIB) $(LIBS) + +regex/libregex.a: + (cd regex; $(MAKE) lib CC=$(CC) AUX_CFLAGS='$(CFLAGS)' RANLIB='$(RANLIB)') + +modules/last-built: + (cd modules; \ + $(MAKE) CC=$(CC) AUX_CFLAGS='$(CFLAGS)' RANLIB='$(RANLIB)') + +clean: + rm -f httpd $(OBJS) + cd regex; $(MAKE) clean + cd modules; $(MAKE) clean + +dist.tar: + # Assure a semi-sensible configuration going out... + cp Makefile.orig Makefile + cp modules.c.orig modules.c + tar cvf dist.tar README INSTALL CHANGES TODO API.html \ + Configuration Configure Makefile.tmpl Makefile *.h *.c + +# Work around broken compilers +http_bprintf.o: http_bprintf.c + $(CC) -c $(INCLUDES) $(CFLAGS) $(BROKEN_BPRINTF_FLAGS) http_bprintf.c + +#Dependencies + +$(OBJS): Makefile + +alloc.o: conf.h alloc.h +buff.o: conf.h alloc.h buff.h +explain.o: explain.h +http_bprintf.o: conf.h alloc.h buff.h +http_config.o: httpd.h http_config.h http_core.h http_log.h http_request.h \ + http_conf_globals.h explain.h +http_core.o: httpd.h http_config.h http_core.h http_protocol.h scoreboard.h \ + http_conf_globals.h http_main.h http_log.h rfc1413.h util_md5.h +http_log.o: httpd.h http_config.h http_core.h http_log.h +http_main.o: httpd.h http_config.h http_core.h http_log.h http_request.h \ + http_conf_globals.h http_protocol.h http_main.h scoreboard.h \ + explain.h +http_protocol.o: httpd.h http_config.h http_core.h http_protocol.h \ + http_main.h http_log.h util_date.h +http_request.o: httpd.h http_config.h http_request.h http_core.h \ + http_protocol.h http_log.h http_main.h scoreboard.h +md5c.o: md5.h +mod_access.o: httpd.h http_core.h http_config.h http_log.h +mod_actions.o: httpd.h http_config.h http_request.h http_core.h \ + http_protocol.h http_main.h http_log.h util_script.h +mod_alias.o: httpd.h http_config.h +mod_asis.o: httpd.h http_config.h http_protocol.h http_log.h util_script.h \ + http_main.h http_request.h +mod_auth.o: httpd.h http_config.h http_core.h http_log.h http_protocol.h +mod_auth_anon.o: httpd.h http_config.h http_core.h http_log.h http_protocol.h +mod_auth_db.o: httpd.h http_config.h http_core.h http_log.h http_protocol.h +mod_auth_dbm.o: httpd.h http_config.h http_core.h http_log.h http_protocol.h +mod_auth_msql.o: httpd.h http_config.h http_core.h http_log.h http_protocol.h +mod_browser.o: httpd.h http_config.h +mod_cern_meta.o: httpd.h http_config.h util_script.h http_log.h +mod_cgi.o: httpd.h http_config.h http_request.h http_core.h http_protocol.h \ + http_main.h http_log.h util_script.h +mod_digest.o: httpd.h http_config.h http_core.h http_log.h http_protocol.h \ + util_md5.h +mod_dir.o: httpd.h http_config.h http_core.h http_request.h http_protocol.h \ + http_log.h http_main.h util_script.h +mod_dld.o: httpd.h http_config.h http_conf_globals.h +mod_env.o: httpd.h http_config.h +mod_expires.o: httpd.h http_config.h http_log.h +mod_headers.o: httpd.h http_config.h +mod_imap.o: httpd.h http_config.h http_request.h http_core.h http_protocol.h \ + http_main.h http_log.h util_script.h +mod_include.o: httpd.h http_config.h http_request.h http_core.h http_log.h \ + http_protocol.h http_main.h util_script.h +mod_info.o: httpd.h http_config.h http_core.h http_log.h http_main.h \ + http_protocol.h util_script.h +mod_log_agent.o: httpd.h http_config.h +mod_log_config.o: httpd.h http_config.h http_core.h +mod_log_referer.o: httpd.h http_config.h +mod_mime.o: httpd.h http_config.h +mod_negotiation.o: httpd.h http_config.h http_request.h http_core.h http_log.h +mod_rewrite.o: httpd.h http_config.h http_request.h http_core.h http_log.h \ + mod_rewrite.h +mod_status.o: httpd.h http_config.h http_core.h http_protocol.h http_main.h \ + util_script.h scoreboard.h +mod_userdir.o: httpd.h http_config.h +mod_usertrack.o: httpd.h http_config.h http_core.h +modules.o: httpd.h http_config.h +rfc1413.o: httpd.h http_log.h rfc1413.h +util.o: httpd.h http_conf_globals.h +util_date.o: util_date.h +util_md5.o: httpd.h util_md5.h +util_script.o: httpd.h http_config.h http_conf_globals.h http_main.h \ + http_log.h http_protocol.h http_core.h http_request.h \ + util_script.h +util_snprintf.o: httpd.h + +httpd.h: conf.h alloc.h buff.h +util_md5.h: md5.h diff --git a/APACHE_1_2_X/src/PORTING b/APACHE_1_2_X/src/PORTING new file mode 100644 index 00000000000..97fccdb8521 --- /dev/null +++ b/APACHE_1_2_X/src/PORTING @@ -0,0 +1,254 @@ +The Semi-Official Guide to Porting Apache + +------------- +Introduction: +------------- +Apache has been ported to a wide variety of platforms, from multiple +UNIX varients to OS/2. Nonetheless, there are most likely a few +platforms out there that currently are not "officially" supported +under Apache. Porting Apache to these platforms can be quite simple +depending on the "genericness" of the OS. This doc will provide +some basic guidelines to help the potential porter. + +------------- +Requirements: +------------- +One of the basic requirements for a potential Apache platform is +a robust TCP/IP implementation. Just about any UNIX out there +nowadays, even some ancient ones, have a TCP/IP stack that will +work. In particular, the UNIX should provide for sockets and the +basic controlling functions for them (like accept(), bind(), etc). + +The source for Apache is written in ANSI-C, so an ANSI-C compiler +is required. However, Apache does not use or require ANSI-only +functions or options (eg: the "%n" parameter in the scanf() +family); the source basically uses ANSI function prototyping but +no other specific ANSIisms. Thus, an ANSI-to-K&R filter _may_ +work, although as far as I know it has not yet been tried. If you +attempt this, let the Apache team know (mailto: new-httpd@hyperreal.com). + +------------------- +The Starting Point: +------------------- +The first thing to look at is the output of the ./helpers/GuessOS +script. This is a simple script that attempts to determine the +platform and OS you are running on. The output of this script +is used by Configure to set some basic compilation parameters. + +The output of ./helpers/GuessOS was designed to be GNUconfig.guess +compatible (from GNU/autoconf). The format of the output string +is: + + machine-vendor-OS + +This string is returned to the main Configure script as the +shell variable $PLAT. If Configure is not "aware" of that platform +(or cannot correctly parse it), it will complain and die. + +---------------------- +Configure cannot Grok: +---------------------- +If this happens to you, then it means that Configure doesn't +know how to configure and compile Apache for your OS. The first +course of action is the easiest: Look in Configure and see if +there are any OSs which is similar to yours. + +For example, let's say that your OS is similar to HP-UX, but that +GuessOS returns "foobar-intel-hubble". You would then edit +Configure as follows: + + *-hp-hpux*|*-*-hubble) + OS='HP-UX' + CFLAGS="$CFLAGS -DHPUX" + ;; + +The '|*-*-hubble' was added to the switch statement for HP-UX. + +Another fix may involve editing the GuessOS helper script. Let's +say, for example, that your system is SysV4-based, but that +GuessOS does not return that info. You could then add a switch +to the script that does something like: + + *WeirdSystem*) + echo "${MACHINE}-whatever-sysv4"; exit 0 + ;; + +In this case, we force GuessOS to return a string that includes +the "sysv4" cookie for Configure to recognize. + +Unfortunately, unless you are running a very generic BSD or SysV +system, no "supported" OS will be close enough in all aspects to +allow for a clear (and possibly workable) build of Apache. If this +is the case, you will need to port Apache to your OS. + +------------------- +Porting for Apache: +------------------- +When all else fails, it's time to hack some code. The source itself +is generic enough that most ports are incredibly easy. No matter +what, however, there are 2 source files that need to be updated +for the port: + + Configure + conf.h + +Configure: + ========== +Configure concerns itself with determining the OS-type for the +build and setting up a few Makefile variables for the build. The +most important is 'OS' and 'CFLAGS'. For example, when Configure +determines a build for A/UX, it runs the following lines: + + case "$PLAT" in + *-apple-aux3*) + OS='A/UX 3.1.x' + CFLAGS="$CFLAGS -DAUX -D_POSIX_SOURCE" + LIBS="$LIBS -lposix -lbsd" + LFLAGS="$LFLAGS -s" + DEF_WANTHSREGEX=no + ;; + +The 'OS' variable is used to define the system Apache is being built +for. You will also note that 'CFLAGS' defines "-DAUX". In this case, +'AUX' is a magic cookie used by the Apache code (mainly conf.h [see +below]) to handle OS-specific code. Each code that has and requires +such OS-specific code will require a unique "system cookie" defined +in 'CFLAGS'. You will also note that Configure also goes ahead and +predefines the LIBS and LFLAGS Makefile variables (DEF_WANTHSREGEX is +explained below). + +conf.h: + ======= +The Apache code, specifically in conf.h, uses a variety of #defines to +control how the code is compiled and what options are available for each +supported OS. One of the hardest parts about the porting process is +determining which of the following are applicable for your system and +setup. This time using the example of AIX, we see: + + #elif defined(AIX) + #undef HAVE_GMTOFF + #undef NO_KILLPG + #undef NO_SETSID + #define HAVE_SYS_SELECT_H + #define JMP_BUF sigjmp_buf + #define HAVE_MMAP + typedef int rlim_t; + +The above lines describe which functions, capabilities and specifics +are required for Apache to build and run under IBM AIX (the #undefs +are not strictly required, but are a Good Idea anyway). + +The following several lines provide a list and short description +of these #defines. By correcting #defining the ones you need in conf.h +(wrapped by the above mentioned "system cookie"), you can fine tune the +build for your OS. + +-- + + NEED_*: + If the particular OS doesn't supply the specified function, we use the + Apache-supplied version (in util.c). + + NEED_STRERROR: + NEED_STRDUP: + NEED_STRCASECMP: + NEED_STRNCASECMP: + NEED_INITGROUPS: + NEED_WAITPID: + NEED_STRERROR: +-- + + HAVE_*: + Does this OS have/support this capability? + + HAVE_GMTOFF: + Define if the OS's tm struct has the tm_gmtoff element + + HAVE_RESOURCE: + Define if the OS supports the getrlimit()/setrlimit() functions + + HAVE_MMAP: + Define if the OS supports the BSD mmap() call. This is used by various + OSs to allow the scoreboard file to be held in shared mmapped-memory + instead of a real file. + + HAVE_SHMGET: + Define if the OS has the SysV-based shmget() family of shared-memory + functions. Used to allow the scoreboard to live in a shared-memory + slot instead of a real file. + + HAVE_CRYPT_H: + Define if the OS has the <crypt.h> header file. + + HAVE_SYS_SELECT_H: + Define if the OS has the <sys/select.h> header file. + + HAVE_SYS_RESOURCE_H: + Define if the OS has and supports the getrlimit/setrlimit + family. Apache uses this to determine if RLIMIT_CPU|VMEM|DATA|RLIMIT + is found and used. + + HAVE_SNPRINTF: + Apache makes extensive use of the snprintf() function. many + platforms do not provide this function. If your platform + does provide it _and_ it's reliable (most are not) then + define this to use the OS version. Otherwise, Apache will + use it's own. +-- + + USE_*: + These #defines are used for functions and ability that aren't exactly + required but should be used. + + USE_FCNTL_SERIALIZED_ACCEPT: + Define if the OS requires a mutex "lock" around the socket accept() + call. Use fcntl() locking. + + USE_FLOCK_SERIALIZED_ACCEPT: + Define if the OS requires a mutex "lock" around the socket accept() + call. Use flock() locking (fcntl() is expensive on some OSs, esp. + when using NFS). + + USE_LONGJMP: + use the longjmp() call instead of siglongjmp() + (as well as setjmp() instead of sigsetjmp()) + +-- + + NO_*: + These are defined if the OS does NOT have the specified function or if + we should not use it. + + NO_UNISTD_H: + NO_KILLPG: + NO_SETSID: + NO_USE_SIGACTION: + Do not use the sigaction() call, even if we have it. + NO_LINGCLOSE: + Do not use Apache's soft, "lingering" close feature to + terminate connections. +-- + + MISC #DEFINES: + Various other #defines used in the code. + + JMP_BUF: + The variable-type for siglongjmp() or longjmp() call. + + MOVEBREAK: + Amount to move sbrk() breakpoint, if required, before attaching + shared-memory segment. + +----------- +Conclusion: +----------- +The above hints, and a good understanding of your OS and Apache, will +go a LONG way in helping you get Apache built and running on your +OS. If you have a port, PLEASE send Email to 'new-httpd@hyperreal.com' +with the patches so that we may add them to the official version. +If you hit a rough spot in the porting process, you can also try +sending Email to that address as well and, if you are lucky, someone +will respond. Another good source is the 'comp.infosystems.www.servers.unix' +Usenet group as well. + +Good luck and happy porting! diff --git a/APACHE_1_2_X/src/README b/APACHE_1_2_X/src/README new file mode 100644 index 00000000000..9aefdcac470 --- /dev/null +++ b/APACHE_1_2_X/src/README @@ -0,0 +1,147 @@ +The following document was written by Robert S. Thau (rst@ai.mit.edu) on the +release of Apache 1.0. Some details may have changed since then regarding the +functions and names of modules, but the basic ideas are still intact. + ================================================= + +The basic idea of the new Apache release is to make a modular +"tinkertoy" server, to which people can easily add code which is +valuable to them (even if it isn't universally useful) without hairing +up a monolithic server. Applications for this idea include database +integration, support for experimental search and scripting extensions, +new authentication modes (digest authentication, for instance, could +be done entirely as a module), and so forth. All modules have the +same interface to the server core, and through it, to each other. + +In particular, the following are modules in the current code base: +common log format (other loggers can easily coexist with it), auth and +dbm auth (although both use common code in http_protocol.c to parse +the Authorization: line), directory handling (which can be added or +replaced), handling of aliases and access control, content +negotiation, CGI, includes, aliases, and so forth. (What's left in +the basic server? Not a whole lot). The configuration file commands +which configure these things are defined, for the most part, by the +modules themselves, and not by the server core (each module has, or +can have, a command dispatch table). + +Besides carving up the base code into modules, this release makes a +few other fairly pervasive changes. Most of the global variables are +gone; most of the MAX_STRING_LENGTH char arrays are gone (the few that +are left being sprintf() targets, or I/O buffers of various sorts), +and unmunge_name has vanished. The most drastic change is the use of +a "compool" strategy to manage resources allocated for a request --- +the code in alloc.c keeps track of it all and allows it to be freed en +bloc at the end of the request. This strategy seems to be effective +in stanching memory and descriptor leaks. + +Additional third-party modules can be found at +<URL:http://www.apache.org/dist/contrib/modules/>. + + +A brief code review: + +The code here can be divided into the server core (the http_* files, +along with alloc.c and the various utility files), and several modules +(the mod_* files). + +The core interfaces to modules through the "module" structure which +describes each one. There's a linked list of these things rooted at +top_module, through which http_config.c dispatches when necessary. The +module structures themselves are defined at the bottom of the mod_foo +files. (Loading new modules dynamically at runtime should be simple; +just push them onto the linked list. The only complication is what to +do with AddModule commands when the config files are reread, +particularly if you find a module has been taken out). + +In addition to the core itself (which does have a module structure to +hold its command tables, and the handlers for various phases of +request handling which make it *barely* a web server on its own), +the modules included here are the following: + +mod_mime.c --- deduction of MIME types and content-encodings from + filename extensions. This module defines the AddType, AddEncoding, + and TypesConfig config-file directives. This code is off in a + module by itself so that people who want to experiment with other + meta-information schemes can replace it, and still have content + negotiation work. + +mod_log_config.c --- logging in configurable or common log format. + +mod_auth.c --- HTTP authentication. Defines the AuthUserFile and + AuthGroupFile directives (other auth-related commands are handled by + the core itself, so it knows which requests require it to poll the + modules for authentication handlers). + +mod_auth_dbm.c --- DBM auth. Untested, and left out of the modules + list in modules.c because of that, but it does at least compile. + Grump. + +mod_access.c --- access checking by DNS name or IP address; defines + the "order", "allow" and "deny" config-file commands. (If this + module is compiled out, the server fails safe --- any attempt to + configure access control will die on a config file syntax error when + the relevant commands go unrecognized). + +mod_negotiation.c --- Content negotiation. Defines the + CacheNegotiatedDocs config-file command. Making this a module is + perhaps going overboard, but I wanted to see how far I could push + it. + +mod_alias.c --- Alias command and file translation. + +mod_userdir.c --- ditto for Userdir. + +mod_cgi.c --- Common Gateway Interface. Also defines ScriptAlias, + because scripts are treated slightly differently depending on + whether they are ScriptAliased or not (in particular, ExecCGI is not + required in the former case). + +mod_includes.c --- server-side includes. + +mod_dir.c --- defines a whole *raft* of commands; handles directories. + +mod_asis.c --- ASIS file handling. + +mod_dld.c --- the experimental runtime-code-loader described above. + You'll have to alter the makefile and modules.c to make this active + if you want it. + + + +As to the core, here's a brief review of what's where: + +http_protocol.c --- functions for dealing directly with the client. + Reading requests, writing replies of various sorts. I've tried to + route all data transfer between server and client through here, so + there's a single piece of code to change if we want to add, say, + HTTP-NG packetization. The major glaring exception is NPH- CGI + scripts; what *will* we do with those for HTTP-NG? + +http_request.c --- functions which direct the processing of requests, + including error handling. Generally responsible for making sure + that the right module handlers get invoked, in the right order. + (This includes the "sub-request" mechanism, which is used by + includes and other stuff to ask about the status of particular + subfiles). + +http_core.c --- + Contains the core module structure, its command table, and the + command handlers, also the filename translation routine, and the + like for the core. (Basically, this is all of the core module stuff + which looks more or less like the boilerplate from the other modules). + +http_config.c --- Functions to read config files and dispatch to the + command handlers; also, routines to manage configuration vectors, + and to dispatch to modules' handlers for the various phases of + handling a request. + +http_log.c --- just the error log. Error handling is split between + http_protocol.c (for generating the default error responses) and + http_request.c (for executive handling, including ErrorDocument + invocation); transaction logging is in the modules. + +http_main.c --- System startup, restart, and accepting connections; + also timeout handling (which is pretty grotesque right now; ideas?) + +alloc.c --- allocation of all resources which might have to be reclaimed + eventually, including memory, files, and child processes. + diff --git a/APACHE_1_2_X/src/ap/ap_md5c.c b/APACHE_1_2_X/src/ap/ap_md5c.c new file mode 100644 index 00000000000..fd42bcb456e --- /dev/null +++ b/APACHE_1_2_X/src/ap/ap_md5c.c @@ -0,0 +1,354 @@ +/* + * This is work is derived from material Copyright RSA Data Security, Inc. + * + * The RSA copyright statement and Licence for that original material is + * included below. This is followed by the Apache copyright statement and + * licence for the modifications made to that material. + */ + +/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +/* ==================================================================== + * Copyright (c) 1996,1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +#include <string.h> + +#include "md5.h" + +/* Constants for MD5Transform routine. + */ + +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static void MD5Transform(UINT4 state[4], const unsigned char block[64]); +static void Encode(unsigned char *output, const UINT4 *input, + unsigned int len); +static void Decode(UINT4 *output, const unsigned char *input, + unsigned int len); + +static unsigned char PADDING[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/* MD5 initialization. Begins an MD5 operation, writing a new context. + */ +void +MD5Init(MD5_CTX *context) +{ + context->count[0] = context->count[1] = 0; + /* Load magic initialization constants. */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. + */ +void +MD5Update(MD5_CTX *context, const unsigned char *input, unsigned int inputLen) +{ + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((UINT4)inputLen << 3)) < ((UINT4)inputLen << 3)) + context->count[1]++; + context->count[1] += (UINT4)inputLen >> 29; + + partLen = 64 - index; + + /* Transform as many times as possible. */ + if (inputLen >= partLen) + { + memcpy(&context->buffer[index], input, partLen); + MD5Transform(context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform(context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + memcpy(&context->buffer[index], &input[i], inputLen-i); +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. + */ +void +MD5Final(unsigned char digest[16], MD5_CTX *context) +{ + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* Pad out to 56 mod 64. */ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update(context, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update(context, bits, 8); + + /* Store state in digest */ + Encode(digest, context->state, 16); + + /* Zeroize sensitive information. */ + memset(context, 0, sizeof (*context)); +} + +/* MD5 basic transformation. Transforms state based on block. */ +static void +MD5Transform(UINT4 state[4], const unsigned char block[64]) +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. */ + memset(x, 0, sizeof (x)); +} + +/* Encodes input (UINT4) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void +Encode(unsigned char *output, const UINT4 *input, unsigned int len) +{ + unsigned int i, j; + UINT4 k; + + for (i = 0, j = 0; j < len; i++, j += 4) + { + k = input[i]; + output[j] = (unsigned char)(k & 0xff); + output[j+1] = (unsigned char)((k >> 8) & 0xff); + output[j+2] = (unsigned char)((k >> 16) & 0xff); + output[j+3] = (unsigned char)((k >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (UINT4). Assumes len is + a multiple of 4. + */ +static void +Decode(UINT4 *output, const unsigned char *input, unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | + (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); +} diff --git a/APACHE_1_2_X/src/ap/ap_snprintf.c b/APACHE_1_2_X/src/ap/ap_snprintf.c new file mode 100644 index 00000000000..d37c634f753 --- /dev/null +++ b/APACHE_1_2_X/src/ap/ap_snprintf.c @@ -0,0 +1,949 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + * This code is based on, and used with the permission of, the + * SIO stdio-replacement strx_* functions by Panos Tsirigotis + * <panos@alumni.cs.colorado.edu> for xinetd. + */ + +#include "conf.h" + +#ifndef HAVE_SNPRINTF + +#include <stdio.h> +#include <ctype.h> +#include <sys/types.h> +#include <stdarg.h> +#include <string.h> +#include <stdlib.h> +#include <math.h> + +#ifdef HAVE_CVT + +# define ap_ecvt ecvt +# define ap_fcvt fcvt +# define ap_gcvt gcvt + +#else + +/* + * cvt.c - IEEE floating point formatting routines for FreeBSD + * from GNU libc-4.6.27 + */ + +/* + * ap_ecvt converts to decimal + * the number of digits is specified by ndigit + * decpt is set to the position of the decimal point + * sign is set to 0 for positive, 1 for negative + */ + +#define NDIG 80 + +static char * + ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag) +{ + register int r2; + double fi, fj; + register char *p, *p1; + static char buf[NDIG]; + + if (ndigits >= NDIG - 1) + ndigits = NDIG - 2; + r2 = 0; + *sign = 0; + p = &buf[0]; + if (arg < 0) { + *sign = 1; + arg = -arg; + } + arg = modf(arg, &fi); + p1 = &buf[NDIG]; + /* + * Do integer part + */ + if (fi != 0) { + p1 = &buf[NDIG]; + while (fi != 0) { + fj = modf(fi / 10, &fi); + *--p1 = (int) ((fj + .03) * 10) + '0'; + r2++; + } + while (p1 < &buf[NDIG]) + *p++ = *p1++; + } + else if (arg > 0) { + while ((fj = arg * 10) < 1) { + arg = fj; + r2--; + } + } + p1 = &buf[ndigits]; + if (eflag == 0) + p1 += r2; + *decpt = r2; + if (p1 < &buf[0]) { + buf[0] = '\0'; + return (buf); + } + while (p <= p1 && p < &buf[NDIG]) { + arg *= 10; + arg = modf(arg, &fj); + *p++ = (int) fj + '0'; + } + if (p1 >= &buf[NDIG]) { + buf[NDIG - 1] = '\0'; + return (buf); + } + p = p1; + *p1 += 5; + while (*p1 > '9') { + *p1 = '0'; + if (p1 > buf) + ++ * --p1; + else { + *p1 = '1'; + (*decpt)++; + if (eflag == 0) { + if (p > buf) + *p = '0'; + p++; + } + } + } + *p = '\0'; + return (buf); +} + +static char * + ap_ecvt(double arg, int ndigits, int *decpt, int *sign) +{ + return (ap_cvt(arg, ndigits, decpt, sign, 1)); +} + +static char * + ap_fcvt(double arg, int ndigits, int *decpt, int *sign) +{ + return (ap_cvt(arg, ndigits, decpt, sign, 0)); +} + +/* + * ap_gcvt - Floating output conversion to + * minimal length string + */ + +static char * + ap_gcvt(double number, int ndigit, char *buf) +{ + int sign, decpt; + register char *p1, *p2; + register i; + + p1 = ap_ecvt(number, ndigit, &decpt, &sign); + p2 = buf; + if (sign) + *p2++ = '-'; + for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--) + ndigit--; + if ((decpt >= 0 && decpt - ndigit > 4) + || (decpt < 0 && decpt < -3)) { /* use E-style */ + decpt--; + *p2++ = *p1++; + *p2++ = '.'; + for (i = 1; i < ndigit; i++) + *p2++ = *p1++; + *p2++ = 'e'; + if (decpt < 0) { + decpt = -decpt; + *p2++ = '-'; + } + else + *p2++ = '+'; + if (decpt / 100 > 0) + *p2++ = decpt / 100 + '0'; + if (decpt / 10 > 0) + *p2++ = (decpt % 100) / 10 + '0'; + *p2++ = decpt % 10 + '0'; + } + else { + if (decpt <= 0) { + if (*p1 != '0') + *p2++ = '.'; + while (decpt < 0) { + decpt++; + *p2++ = '0'; + } + } + for (i = 1; i <= ndigit; i++) { + *p2++ = *p1++; + if (i == decpt) + *p2++ = '.'; + } + if (ndigit < decpt) { + while (ndigit++ < decpt) + *p2++ = '0'; + *p2++ = '.'; + } + } + if (p2[-1] == '.') + p2--; + *p2 = '\0'; + return (buf); +} + +#endif /* HAVE_CVT */ + +typedef enum { + NO = 0, YES = 1 +} boolean_e; + +#define FALSE 0 +#define TRUE 1 +#define NUL '\0' +#define INT_NULL ((int *)0) +#define WIDE_INT long + +typedef WIDE_INT wide_int; +typedef unsigned WIDE_INT u_wide_int; +typedef int bool_int; + +#define S_NULL "(null)" +#define S_NULL_LEN 6 + +#define FLOAT_DIGITS 6 +#define EXPONENT_LENGTH 10 + +/* + * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions + * + * XXX: this is a magic number; do not decrease it + */ +#define NUM_BUF_SIZE 512 + + +/* + * Descriptor for buffer area + */ +struct buf_area { + char *buf_end; + char *nextb; /* pointer to next byte to read/write */ +}; + +typedef struct buf_area buffy; + +/* + * The INS_CHAR macro inserts a character in the buffer and writes + * the buffer back to disk if necessary + * It uses the char pointers sp and bep: + * sp points to the next available character in the buffer + * bep points to the end-of-buffer+1 + * While using this macro, note that the nextb pointer is NOT updated. + * + * NOTE: Evaluation of the c argument should not have any side-effects + */ +#define INS_CHAR( c, sp, bep, cc ) \ + { \ + if ( sp < bep ) \ + { \ + *sp++ = c ; \ + cc++ ; \ + } \ + } + +#define NUM( c ) ( c - '0' ) + +#define STR_TO_DEC( str, num ) \ + num = NUM( *str++ ) ; \ + while ( isdigit( *str ) ) \ + { \ + num *= 10 ; \ + num += NUM( *str++ ) ; \ + } + +/* + * This macro does zero padding so that the precision + * requirement is satisfied. The padding is done by + * adding '0's to the left of the string that is going + * to be printed. + */ +#define FIX_PRECISION( adjust, precision, s, s_len ) \ + if ( adjust ) \ + while ( s_len < precision ) \ + { \ + *--s = '0' ; \ + s_len++ ; \ + } + +/* + * Macro that does padding. The padding is done by printing + * the character ch. + */ +#define PAD( width, len, ch ) do \ + { \ + INS_CHAR( ch, sp, bep, cc ) ; \ + width-- ; \ + } \ + while ( width > len ) + +/* + * Prefix the character ch to the string str + * Increase length + * Set the has_prefix flag + */ +#define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YES + + +/* + * Convert num to its decimal format. + * Return value: + * - a pointer to a string containing the number (no sign) + * - len contains the length of the string + * - is_negative is set to TRUE or FALSE depending on the sign + * of the number (always set to FALSE if is_unsigned is TRUE) + * + * The caller provides a buffer for the string: that is the buf_end argument + * which is a pointer to the END of the buffer + 1 (i.e. if the buffer + * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) + */ +static char * + conv_10(register wide_int num, register bool_int is_unsigned, + register bool_int * is_negative, char *buf_end, register int *len) +{ + register char *p = buf_end; + register u_wide_int magnitude; + + if (is_unsigned) { + magnitude = (u_wide_int) num; + *is_negative = FALSE; + } + else { + *is_negative = (num < 0); + + /* + * On a 2's complement machine, negating the most negative integer + * results in a number that cannot be represented as a signed integer. + * Here is what we do to obtain the number's magnitude: + * a. add 1 to the number + * b. negate it (becomes positive) + * c. convert it to unsigned + * d. add 1 + */ + if (*is_negative) { + wide_int t = num + 1; + + magnitude = ((u_wide_int) - t) + 1; + } + else + magnitude = (u_wide_int) num; + } + + /* + * We use a do-while loop so that we write at least 1 digit + */ + do { + register u_wide_int new_magnitude = magnitude / 10; + + *--p = magnitude - new_magnitude * 10 + '0'; + magnitude = new_magnitude; + } + while (magnitude); + + *len = buf_end - p; + return (p); +} + + + +/* + * Convert a floating point number to a string formats 'f', 'e' or 'E'. + * The result is placed in buf, and len denotes the length of the string + * The sign is returned in the is_negative argument (and is not placed + * in buf). + */ +static char * + conv_fp(register char format, register double num, +boolean_e add_dp, int precision, bool_int * is_negative, char *buf, int *len) +{ + register char *s = buf; + register char *p; + int decimal_point; + + if (format == 'f') + p = ap_fcvt(num, precision, &decimal_point, is_negative); + else /* either e or E format */ + p = ap_ecvt(num, precision + 1, &decimal_point, is_negative); + + /* + * Check for Infinity and NaN + */ + if (isalpha(*p)) { + *len = strlen(strcpy(buf, p)); + *is_negative = FALSE; + return (buf); + } + + if (format == 'f') + if (decimal_point <= 0) { + *s++ = '0'; + if (precision > 0) { + *s++ = '.'; + while (decimal_point++ < 0) + *s++ = '0'; + } + else if (add_dp) + *s++ = '.'; + } + else { + while (decimal_point-- > 0) + *s++ = *p++; + if (precision > 0 || add_dp) + *s++ = '.'; + } + else { + *s++ = *p++; + if (precision > 0 || add_dp) + *s++ = '.'; + } + + /* + * copy the rest of p, the NUL is NOT copied + */ + while (*p) + *s++ = *p++; + + if (format != 'f') { + char temp[EXPONENT_LENGTH]; /* for exponent conversion */ + int t_len; + bool_int exponent_is_negative; + + *s++ = format; /* either e or E */ + decimal_point--; + if (decimal_point != 0) { + p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative, + &temp[EXPONENT_LENGTH], &t_len); + *s++ = exponent_is_negative ? '-' : '+'; + + /* + * Make sure the exponent has at least 2 digits + */ + if (t_len == 1) + *s++ = '0'; + while (t_len--) + *s++ = *p++; + } + else { + *s++ = '+'; + *s++ = '0'; + *s++ = '0'; + } + } + + *len = s - buf; + return (buf); +} + + +/* + * Convert num to a base X number where X is a power of 2. nbits determines X. + * For example, if nbits is 3, we do base 8 conversion + * Return value: + * a pointer to a string containing the number + * + * The caller provides a buffer for the string: that is the buf_end argument + * which is a pointer to the END of the buffer + 1 (i.e. if the buffer + * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) + */ +static char * + conv_p2(register u_wide_int num, register int nbits, + char format, char *buf_end, register int *len) +{ + register int mask = (1 << nbits) - 1; + register char *p = buf_end; + static char low_digits[] = "0123456789abcdef"; + static char upper_digits[] = "0123456789ABCDEF"; + register char *digits = (format == 'X') ? upper_digits : low_digits; + + do { + *--p = digits[num & mask]; + num >>= nbits; + } + while (num); + + *len = buf_end - p; + return (p); +} + + +/* + * Do format conversion placing the output in buffer + */ +static int format_converter(register buffy * odp, const char *fmt, + va_list ap) +{ + register char *sp; + register char *bep; + register int cc = 0; + register int i; + + register char *s = NULL; + char *q; + int s_len; + + register int min_width = 0; + int precision = 0; + enum { + LEFT, RIGHT + } adjust; + char pad_char; + char prefix_char; + + double fp_num; + wide_int i_num = (wide_int) 0; + u_wide_int ui_num; + + char num_buf[NUM_BUF_SIZE]; + char char_buf[2]; /* for printing %% and %<unknown> */ + + /* + * Flag variables + */ + boolean_e is_long; + boolean_e alternate_form; + boolean_e print_sign; + boolean_e print_blank; + boolean_e adjust_precision; + boolean_e adjust_width; + bool_int is_negative; + + sp = odp->nextb; + bep = odp->buf_end; + + while (*fmt) { + if (*fmt != '%') { + INS_CHAR(*fmt, sp, bep, cc); + } + else { + /* + * Default variable settings + */ + adjust = RIGHT; + alternate_form = print_sign = print_blank = NO; + pad_char = ' '; + prefix_char = NUL; + + fmt++; + + /* + * Try to avoid checking for flags, width or precision + */ + if (isascii(*fmt) && !islower(*fmt)) { + /* + * Recognize flags: -, #, BLANK, + + */ + for (;; fmt++) { + if (*fmt == '-') + adjust = LEFT; + else if (*fmt == '+') + print_sign = YES; + else if (*fmt == '#') + alternate_form = YES; + else if (*fmt == ' ') + print_blank = YES; + else if (*fmt == '0') + pad_char = '0'; + else + break; + } + + /* + * Check if a width was specified + */ + if (isdigit(*fmt)) { + STR_TO_DEC(fmt, min_width); + adjust_width = YES; + } + else if (*fmt == '*') { + min_width = va_arg(ap, int); + fmt++; + adjust_width = YES; + if (min_width < 0) { + adjust = LEFT; + min_width = -min_width; + } + } + else + adjust_width = NO; + + /* + * Check if a precision was specified + * + * XXX: an unreasonable amount of precision may be specified + * resulting in overflow of num_buf. Currently we + * ignore this possibility. + */ + if (*fmt == '.') { + adjust_precision = YES; + fmt++; + if (isdigit(*fmt)) { + STR_TO_DEC(fmt, precision); + } + else if (*fmt == '*') { + precision = va_arg(ap, int); + fmt++; + if (precision < 0) + precision = 0; + } + else + precision = 0; + } + else + adjust_precision = NO; + } + else + adjust_precision = adjust_width = NO; + + /* + * Modifier check + */ + if (*fmt == 'l') { + is_long = YES; + fmt++; + } + else + is_long = NO; + + /* + * Argument extraction and printing. + * First we determine the argument type. + * Then, we convert the argument to a string. + * On exit from the switch, s points to the string that + * must be printed, s_len has the length of the string + * The precision requirements, if any, are reflected in s_len. + * + * NOTE: pad_char may be set to '0' because of the 0 flag. + * It is reset to ' ' by non-numeric formats + */ + switch (*fmt) { + case 'u': + if (is_long) + i_num = va_arg(ap, u_wide_int); + else + i_num = (wide_int) va_arg(ap, unsigned int); + /* + * The rest also applies to other integer formats, so fall + * into that case. + */ + case 'd': + case 'i': + /* + * Get the arg if we haven't already. + */ + if ((*fmt) != 'u') { + if (is_long) + i_num = va_arg(ap, wide_int); + else + i_num = (wide_int) va_arg(ap, int); + }; + s = conv_10(i_num, (*fmt) == 'u', &is_negative, + &num_buf[NUM_BUF_SIZE], &s_len); + FIX_PRECISION(adjust_precision, precision, s, s_len); + + if (*fmt != 'u') { + if (is_negative) + prefix_char = '-'; + else if (print_sign) + prefix_char = '+'; + else if (print_blank) + prefix_char = ' '; + } + break; + + + case 'o': + if (is_long) + ui_num = va_arg(ap, u_wide_int); + else + ui_num = (u_wide_int) va_arg(ap, unsigned int); + s = conv_p2(ui_num, 3, *fmt, + &num_buf[NUM_BUF_SIZE], &s_len); + FIX_PRECISION(adjust_precision, precision, s, s_len); + if (alternate_form && *s != '0') { + *--s = '0'; + s_len++; + } + break; + + + case 'x': + case 'X': + if (is_long) + ui_num = (u_wide_int) va_arg(ap, u_wide_int); + else + ui_num = (u_wide_int) va_arg(ap, unsigned int); + s = conv_p2(ui_num, 4, *fmt, + &num_buf[NUM_BUF_SIZE], &s_len); + FIX_PRECISION(adjust_precision, precision, s, s_len); + if (alternate_form && i_num != 0) { + *--s = *fmt; /* 'x' or 'X' */ + *--s = '0'; + s_len += 2; + } + break; + + + case 's': + s = va_arg(ap, char *); + if (s != NULL) { + s_len = strlen(s); + if (adjust_precision && precision < s_len) + s_len = precision; + } + else { + s = S_NULL; + s_len = S_NULL_LEN; + } + pad_char = ' '; + break; + + + case 'f': + case 'e': + case 'E': + fp_num = va_arg(ap, double); + + s = conv_fp(*fmt, fp_num, alternate_form, + (adjust_precision == NO) ? FLOAT_DIGITS : precision, + &is_negative, &num_buf[1], &s_len); + if (is_negative) + prefix_char = '-'; + else if (print_sign) + prefix_char = '+'; + else if (print_blank) + prefix_char = ' '; + break; + + + case 'g': + case 'G': + if (adjust_precision == NO) + precision = FLOAT_DIGITS; + else if (precision == 0) + precision = 1; + /* + * * We use &num_buf[ 1 ], so that we have room for the sign + */ + s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1]); + if (*s == '-') + prefix_char = *s++; + else if (print_sign) + prefix_char = '+'; + else if (print_blank) + prefix_char = ' '; + + s_len = strlen(s); + + if (alternate_form && (q = strchr(s, '.')) == NULL) + s[s_len++] = '.'; + if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL) + *q = 'E'; + break; + + + case 'c': + char_buf[0] = (char) (va_arg(ap, int)); + s = &char_buf[0]; + s_len = 1; + pad_char = ' '; + break; + + + case '%': + char_buf[0] = '%'; + s = &char_buf[0]; + s_len = 1; + pad_char = ' '; + break; + + + case 'n': + *(va_arg(ap, int *)) = cc; + break; + + /* + * Always extract the argument as a "char *" pointer. We + * should be using "void *" but there are still machines + * that don't understand it. + * If the pointer size is equal to the size of an unsigned + * integer we convert the pointer to a hex number, otherwise + * we print "%p" to indicate that we don't handle "%p". + */ + case 'p': + ui_num = (u_wide_int) va_arg(ap, char *); + + if (sizeof(char *) <= sizeof(u_wide_int)) + s = conv_p2(ui_num, 4, 'x', + &num_buf[NUM_BUF_SIZE], &s_len); + else { + s = "%p"; + s_len = 2; + } + pad_char = ' '; + break; + + + case NUL: + /* + * The last character of the format string was %. + * We ignore it. + */ + continue; + + + /* + * The default case is for unrecognized %'s. + * We print %<char> to help the user identify what + * option is not understood. + * This is also useful in case the user wants to pass + * the output of format_converter to another function + * that understands some other %<char> (like syslog). + * Note that we can't point s inside fmt because the + * unknown <char> could be preceded by width etc. + */ + default: + char_buf[0] = '%'; + char_buf[1] = *fmt; + s = char_buf; + s_len = 2; + pad_char = ' '; + break; + } + + if (prefix_char != NUL) { + *--s = prefix_char; + s_len++; + } + + if (adjust_width && adjust == RIGHT && min_width > s_len) { + if (pad_char == '0' && prefix_char != NUL) { + INS_CHAR(*s, sp, bep, cc) + s++; + s_len--; + min_width--; + } + PAD(min_width, s_len, pad_char); + } + + /* + * Print the string s. + */ + for (i = s_len; i != 0; i--) { + INS_CHAR(*s, sp, bep, cc); + s++; + } + + if (adjust_width && adjust == LEFT && min_width > s_len) + PAD(min_width, s_len, pad_char); + } + fmt++; + } + odp->nextb = sp; + return (cc); +} + + +/* + * This is the general purpose conversion function. + */ +static void strx_printv(int *ccp, char *buf, size_t len, const char *format, + va_list ap) +{ + buffy od; + int cc; + + /* + * First initialize the descriptor + * Notice that if no length is given, we initialize buf_end to the + * highest possible address. + */ + od.buf_end = len ? &buf[len] : (char *) ~0; + od.nextb = buf; + + /* + * Do the conversion + */ + cc = format_converter(&od, format, ap); + if (len == 0 || od.nextb <= od.buf_end) + *(od.nextb) = '\0'; + if (ccp) + *ccp = cc; +} + + +int ap_snprintf(char *buf, size_t len, const char *format,...) +{ + int cc; + va_list ap; + + va_start(ap, format); + strx_printv(&cc, buf, (len - 1), format, ap); + va_end(ap); + return (cc); +} + + +int ap_vsnprintf(char *buf, size_t len, const char *format, va_list ap) +{ + int cc; + + strx_printv(&cc, buf, (len - 1), format, ap); + return (cc); +} + +#endif /* HAVE_SNPRINTF */ diff --git a/APACHE_1_2_X/src/helpers/CutRule b/APACHE_1_2_X/src/helpers/CutRule new file mode 100755 index 00000000000..740a3362c1b --- /dev/null +++ b/APACHE_1_2_X/src/helpers/CutRule @@ -0,0 +1,7 @@ +# Helper script for Configure - cut a rule from Configuration. +# note that there is a tab and a space in the character groups. +# Map to lowercase to make tests easier + +egrep "^[ ]*Rule[ ]+$1[ ]*=" $2 | \ +awk 'BEGIN {FS="="}{print $2}' | \ +sed 's/[ ]//g' | tr "A-Z" "a-z" diff --git a/APACHE_1_2_X/src/helpers/GuessOS b/APACHE_1_2_X/src/helpers/GuessOS new file mode 100755 index 00000000000..0890b81f1c3 --- /dev/null +++ b/APACHE_1_2_X/src/helpers/GuessOS @@ -0,0 +1,224 @@ +#!/bin/sh +# +# Simple OS/Platform guesser. Similar to config.guess but +# much, much smaller. Since it was developed for use with +# Apache, it follows under Apache's regular licensing +# with one specific addition: Any changes or additions +# to this script should be Emailed to the Apache +# group (apache@apache.org) in general and to +# Jim Jagielski (jim@jaguNET.com) in specific. +# +# Be as similar to the output of config.guess/config.sub +# as possible. + +# First get uname entries that we use below + +MACHINE=`(uname -m) 2>/dev/null` || MACHINE="unknown" +RELEASE=`(uname -r) 2>/dev/null` || RELEASE="unknown" +SYSTEM=`(uname -s) 2>/dev/null` || SYSTEM="unknown" +VERSION=`(uname -v) 2>/dev/null` || VERSION="unknown" + + +# Now test for ISC and SCO, since it is has a braindamaged uname. +# +# We need to work around FreeBSD 1.1.5.1 +XREL=`uname -X 2>/dev/null | grep "^Release" | awk '{print $3}'` +if [ "x$XREL" != "x" ]; then + if [ -f /etc/kconfig ]; then + case "$XREL" in + 4.0|4.1) + echo "${MACHINE}-whatever-isc4"; exit 0 + ;; + esac + else + case "$XREL" in + 3.2v4.2) + echo "whatever-whatever-sco3"; exit 0 + ;; + 3.2v5.0*) + echo "whatever-whatever-sco5"; exit 0 + ;; + 4.2MP) + if [ "x$VERSION" = "x2.1.1" ]; then + echo "${MACHINE}-whatever-unixware211"; exit 0 + else + echo "${MACHINE}-whatever-unixware2"; exit 0 + fi + ;; + 4.2) + echo "whatever-whatever-unixware1"; exit 0 + ;; + esac + fi +fi +# Now we simply scan though... In most cases, the SYSTEM info is enough +# +case "${SYSTEM}:${RELEASE}:${VERSION}:${MACHINE}" in + A/UX:*) + echo "m68k-apple-aux3"; exit 0 + ;; + + AIX:*) + echo "${MACHINE}-ibm-aix"; exit 0 + ;; + + dgux:*) + echo "${MACHINE}-dg-dgux"; exit 0 + ;; + + HI-UX:*) + echo "${MACHINE}-hi-hiux"; exit 0 + ;; + + HP-UX:*) + HPUXVER=`echo ${RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "$HPUXVER" in + 10.*) + echo "${MACHINE}-hp-hpux10."; exit 0 + ;; + *) + echo "${MACHINE}-hp-hpux"; exit 0 + ;; + esac + ;; + + IRIX:*) + echo "${MACHINE}-sgi-irix"; exit 0 + ;; + + IRIX64:*) + echo "${MACHINE}-sgi-irix64"; exit 0 + ;; + + Linux:[2-9].*) + echo "${MACHINE}-whatever-linux2"; exit 0 + ;; + + Linux:1.*) + echo "${MACHINE}-whatever-linux1"; exit 0 + ;; + + LynxOS:*) + echo "${MACHINE}-lynx-lynxos"; exit 0 + ;; + + BSD/386:*:*:*486*|BSD/OS:*:*:*:*486*) + echo "i486-whatever-bsdi"; exit 0 + ;; + + BSD/386:*|BSD/OS:*) + echo "${MACHINE}-whatever-bsdi"; exit 0 + ;; + + FreeBSD:*:*:*486*) + echo "i486-whatever-freebsd"; exit 0 + ;; + + FreeBSD:*) + echo "${MACHINE}-whatever-freebsd"; exit 0 + ;; + + NetBSD:*:*:*486*) + echo "i486-whatever-netbsd"; exit 0 + ;; + + NetBSD:*) + echo "${MACHINE}-whatever-netbsd"; exit 0 + ;; + + OpenBSD:*) + echo "${MACHINE}-whatever-openbsd"; exit 0 + ;; + + OSF1:*:*:*alpha*) + echo "${MACHINE}-dec-osf"; exit 0 + ;; + + QNX:*) + case "$VERSION" in + 423) + echo "${MACHINE}-qssl-qnx32" + ;; + *) + echo "${MACHINE}-qssl-qnx" + ;; + esac + exit 0 + ;; + + Paragon*:*:*:*) + echo "i860-intel-osf1"; exit 0 + ;; + + SunOS:5.*) + echo "${MACHINE}-sun-solaris2"; exit 0 + ;; + + SunOS:*) + echo "${MACHINE}-sun-sunos4"; exit 0 + ;; + + UNIX_System_V:4.*:*) + echo "${MACHINE}-whatever-sysv4"; exit 0 + ;; + + *:4*:R4*:m88k) + echo "${MACHINE}-whatever-sysv4"; exit 0 + ;; + + DYNIX/ptx:4*:*) + echo "${MACHINE}-whatever-sysv4"; exit 0 + ;; + + *:4.0:3.0:3[34]?? | *:4.0:3.0:3[34]??,*) + echo "i486-ncr-sysv4"; exit 0 + ;; + + ULTRIX:*) + echo "${MACHINE}-unknown-ultrix"; exit 0 + ;; + + SINIX*) + echo "${MACHINE}-sni-sysv4"; exit 0 + ;; + + machten:*) + echo "${MACHINE}-tenon-${SYSTEM}"; exit 0; + ;; + + library:*) + echo "${MACHINE}-ncr-sysv4"; exit 0 + ;; + + ConvexOS:*:11.0:*) + echo "${MACHINE}-v11-${SYSTEM}"; exit 0; + ;; + +esac + +# +# Ugg. These are all we can determine by what we know about +# the output of uname. Be more creative: +# + +# Do the Apollo stuff first. Here, we just simply assume +# that the existance of the /usr/apollo directory is proof +# enough +if [ -d /usr/apollo ]; then + echo "whatever-apollo-whatever" + exit 0 +fi + +# Now NeXT +ISNEXT=`hostinfo 2>/dev/null` +case "$ISNEXT" in + *NeXT*) + echo "whatever-next-nextstep"; exit 0 + ;; +esac + +# At this point we gone through all the one's +# we know of: Punt + +echo "${MACHINE}-whatever-${SYSTEM}|${RELEASE}|${VERSION}" +exit 0 diff --git a/APACHE_1_2_X/src/helpers/PrintPath b/APACHE_1_2_X/src/helpers/PrintPath new file mode 100755 index 00000000000..9ec0e0c37f0 --- /dev/null +++ b/APACHE_1_2_X/src/helpers/PrintPath @@ -0,0 +1,46 @@ +#!/bin/sh +# Look for $1 somewhere in $PATH +# will print out the full pathname unless +# called with the '-s' option +# +# We do some funny stuff to check to see +# if test/[] knows about -x +# +testfile="pp.t.$$" + +cat > $testfile <<ENDTEST +#!/bin/sh +if [ -x / ] || [ -x /bin ] || [ -x /bin/ls ]; then + exit 0 +fi +exit 1 +ENDTEST + +if `/bin/sh $testfile 2>/dev/null`; then + test_exec_flag="-x" +else + test_exec_flag="-r" +fi +rm -f $testfile + +if [ "x$1" = "x-s" ]; then + shift +else + echo="yes" +fi + +for path in `echo $PATH | + sed 's/^:/.:/ + s/::/:.:/g + s/:$/:./ + s/:/ /g' ` +do + if [ $test_exec_flag $path/$1 ] && [ ! -d $path/$1 ]; then + if [ "$echo" = "yes" ]; then + echo $path/$1 + fi + exit 0 + fi +done +exit 1 + diff --git a/APACHE_1_2_X/src/include/alloc.h b/APACHE_1_2_X/src/include/alloc.h new file mode 100644 index 00000000000..858bf2cb549 --- /dev/null +++ b/APACHE_1_2_X/src/include/alloc.h @@ -0,0 +1,252 @@ + +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +/* + * Resource allocation routines... + * + * designed so that we don't have to keep track of EVERYTHING so that + * it can be explicitly freed later (a fundamentally unsound strategy --- + * particularly in the presence of die()). + * + * Instead, we maintain pools, and allocate items (both memory and I/O + * handlers) from the pools --- currently there are two, one for per + * transaction info, and one for config info. When a transaction is over, + * we can delete everything in the per-transaction pool without fear, and + * without thinking too hard about it either. + * + * rst + */ + +/* Arenas for configuration info and transaction info + * --- actual layout of the pool structure is private to + * alloc.c. + */ + +typedef struct pool pool; + +extern pool *permanent_pool; +void init_alloc(); /* Set up everything */ +pool *make_sub_pool (pool *); /* All pools are subpools of permanent_pool */ +void destroy_pool (pool *); + +/* Clearing out EVERYTHING in an pool... destroys any sub-pools */ + +void clear_pool (struct pool *); + +/* Preparing for exec() --- close files, etc., but *don't* flush I/O + * buffers, *don't* wait for subprocesses, and *don't* free any memory. + */ + +void cleanup_for_exec (); + +/* routines to allocate memory from an pool... */ + +void *palloc(struct pool *, int nbytes); +void *pcalloc(struct pool *, int nbytes); +extern char *pstrdup(struct pool *, const char *s); +extern char *pstrndup(struct pool *, const char *s, int n); +char *pstrcat(struct pool *, ...); /* all '...' must be char* */ + +/* array and alist management... keeping lists of things. + * Common enough to want common support code ... + */ + +typedef struct { + pool *pool; + int elt_size; + int nelts; + int nalloc; + char *elts; +} array_header; + +array_header *make_array (pool *p, int nelts, int elt_size); +void *push_array (array_header *); +void array_cat (array_header *dst, const array_header *src); +array_header *append_arrays (pool *, const array_header *, + const array_header *); + +/* copy_array copies the *entire* array. copy_array_hdr just copies + * the header, and arranges for the elements to be copied if (and only + * if) the code subsequently does a push or arraycat. + */ + +array_header *copy_array (pool *p, const array_header *src); +array_header *copy_array_hdr (pool *p, const array_header *src); + + +/* Tables. Implemented alist style, for now, though we try to keep + * it so that imposing a hash table structure on top in the future + * wouldn't be *too* hard... + * + * Note that key comparisons for these are case-insensitive, largely + * because that's what's appropriate and convenient everywhere they're + * currently being used... + */ + +typedef array_header table; + +typedef struct { + char *key; /* maybe NULL in future; + * check when iterating thru table_elts + */ + char *val; +} table_entry; + +table *make_table (pool *p, int nelts); +table *copy_table (pool *p, const table *); +void clear_table (table *); +char *table_get (const table *, const char *); +void table_set (table *, const char *name, const char *val); +void table_merge (table *, const char *name, const char *more_val); +void table_unset (table *, const char *key); +void table_add (table *, const char *name, const char *val); +void table_do (int (*comp)(void *, const char *, const char *), void *rec, + const table *t, ...); + +table *overlay_tables (pool *p, const table *overlay, const table *base); + +array_header *table_elts (table *); + +#define is_empty_table(t) (((t) == NULL)||((t)->nelts == 0)) + +/* routines to remember allocation of other sorts of things... + * generic interface first. Note that we want to have two separate + * cleanup functions in the general case, one for exec() preparation, + * to keep CGI scripts and the like from inheriting access to things + * they shouldn't be able to touch, and one for actually cleaning up, + * when the actual server process wants to get rid of the thing, + * whatever it is. + * + * kill_cleanup disarms a cleanup, presumably because the resource in + * question has been closed, freed, or whatever, and it's scarce + * enough to want to reclaim (e.g., descriptors). It arranges for the + * resource not to be cleaned up a second time (it might have been + * reallocated). run_cleanup does the same, but runs it first. + * + * Cleanups are identified for purposes of finding & running them off by the + * plain_cleanup and data, which should presumably be unique. + * + * NB any code which invokes register_cleanup or kill_cleanup directly + * is a critical section which should be guarded by block_alarms() and + * unblock_alarms() below... + */ + +void register_cleanup (pool *p, void *data, + void (*plain_cleanup)(void *), + void (*child_cleanup)(void *)); + +void kill_cleanup (pool *p, void *data, void (*plain_cleanup)(void *)); +void run_cleanup (pool *p, void *data, void (*cleanup)(void *)); + +/* The time between when a resource is actually allocated, and when it + * its cleanup is registered is a critical section, during which the + * resource could leak if we got interrupted or timed out. So, anything + * which registers cleanups should bracket resource allocation and the + * cleanup registry with these. (This is done internally by run_cleanup). + * + * NB they are actually implemented in http_main.c, since they are bound + * up with timeout handling in general... + */ + +extern void block_alarms(); +extern void unblock_alarms(); + +/* Common cases which want utility support.. + * the note_cleanups_for_foo routines are for + */ + +FILE *pfopen(struct pool *, const char *name, const char *fmode); +FILE *pfdopen(struct pool *, int fd, const char *fmode); +int popenf(struct pool *, const char *name, int flg, int mode); + +void note_cleanups_for_file (pool *, FILE *); +void note_cleanups_for_fd (pool *, int); +void kill_cleanups_for_fd (pool *p, int fd); + +regex_t *pregcomp (pool *p, const char *pattern, int cflags); +void pregfree (pool *p, regex_t *reg); + +/* routines to note closes... file descriptors are constrained enough + * on some systems that we want to support this. + */ + +int pfclose(struct pool *, FILE *); +int pclosef(struct pool *, int fd); + +/* ... even child processes (which we may want to wait for, + * or to kill outright, on unexpected termination). + * + * spawn_child is a utility routine which handles an awful lot of + * the rigamarole associated with spawning a child --- it arranges + * for pipes to the child's stdin and stdout, if desired (if not, + * set the associated args to NULL). It takes as args a function + * to call in the child, and an argument to be passed to the function. + */ + +enum kill_conditions { kill_never, kill_always, kill_after_timeout, just_wait}; + +int spawn_child_err (pool *, void (*)(void *), void *, + enum kill_conditions, FILE **pipe_in, FILE **pipe_out, + FILE **pipe_err); +#define spawn_child(p,f,v,k,in,out) spawn_child_err(p,f,v,k,in,out,NULL) + +/* magic numbers --- min free bytes to consider a free pool block useable, + * and the min amount to allocate if we have to go to malloc() */ + +#define BLOCK_MINFREE 4096 +#define BLOCK_MINALLOC 8192 + +/* Finally, some accounting */ + +long bytes_in_pool(pool *p); +long bytes_in_free_blocks(); diff --git a/APACHE_1_2_X/src/include/ap_config.h b/APACHE_1_2_X/src/include/ap_config.h new file mode 100644 index 00000000000..fd7869c069c --- /dev/null +++ b/APACHE_1_2_X/src/include/ap_config.h @@ -0,0 +1,752 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +/* + * conf.h: system-dependant #defines and includes... + * See README for a listing of what they mean + */ + +#if !defined(QNX) && !defined(MPE) +#include <sys/param.h> +#endif + +/* Define one of these according to your system. */ +#if defined(MPE) +#include <sys/times.h> +#define JMP_BUF sigjmp_buf +#define NO_SETSID +#define NO_KILLPG +#define NO_WRITEV +#define NEED_INITGROUPS +#define NEED_STRCASECMP +#define NEED_STRDUP +#define NEED_STRNCASECMP +extern void GETPRIVMODE(); +extern void GETUSERMODE(); +extern char *inet_ntoa(); + +#elif defined(SUNOS4) +#define HAVE_GMTOFF +#define HAVE_SYS_RESOURCE_H +#undef NO_KILLPG +#undef NO_SETSID +char *crypt(const char *pw, const char *salt); +char *mktemp(char *template); +#define JMP_BUF sigjmp_buf +#define HAVE_MMAP +#include <sys/time.h> +#define NEED_STRERROR +typedef int rlim_t; +#define memmove(a,b,c) bcopy(b,a,c) +#define NO_LINGCLOSE + +#elif defined(SOLARIS2) +#undef HAVE_GMTOFF +#define NO_KILLPG +#undef NO_SETSID +#define HAVE_SYS_RESOURCE_H +#define bzero(a,b) memset(a,0,b) +#define JMP_BUF sigjmp_buf +#define USE_FCNTL_SERIALIZED_ACCEPT +#define HAVE_MMAP +#define HAVE_CRYPT_H +int gethostname(char *name, int namelen); + +#elif defined(IRIX) +#undef HAVE_GMTOFF +/* IRIX has killpg, but it's only in _BSD_COMPAT, so don't use it in case + * there's some weird conflict with non-BSD signals */ +#define NO_KILLPG +#undef NO_SETSID +#define JMP_BUF sigjmp_buf +#define USE_FCNTL_SERIALIZED_ACCEPT +#define HAVE_SHMGET +#define HAVE_CRYPT_H +#define NO_LONG_DOUBLE +#define HAVE_BSTRING_H +#define NO_LINGCLOSE + +#elif defined(HIUX) +#define HAVE_SYS_RESOURCE_H +#undef HAVE_GMTOFF +#define NO_KILLPG +#undef NO_SETSID +#ifndef _HIUX_SOURCE +#define _HIUX_SOURCE +#endif +#define JMP_BUF sigjmp_buf +#define HAVE_SHMGET +#define SELECT_NEEDS_CAST + +#elif defined(HPUX) || defined(HPUX10) +#define HAVE_SYS_RESOURCE_H +#undef HAVE_GMTOFF +#define NO_KILLPG +#undef NO_SETSID +#ifndef _HPUX_SOURCE +#define _HPUX_SOURCE +#endif +#define JMP_BUF sigjmp_buf +#define HAVE_SHMGET +#ifndef HPUX10 +#define SELECT_NEEDS_CAST +typedef int rlim_t; +#endif + +#elif defined(AIX) +#undef HAVE_GMTOFF +#undef NO_KILLPG +#undef NO_SETSID +#define HAVE_SYS_SELECT_H +#define JMP_BUF sigjmp_buf +#ifndef __ps2__ +#define HAVE_MMAP +#define DEFAULT_GROUP "nobody" +#endif +#define DEFAULT_USER "nobody" +typedef int rlim_t; + +#elif defined(ULTRIX) +#define HAVE_GMTOFF +#undef NO_KILLPG +#undef NO_SETSID +#define ULTRIX_BRAIN_DEATH +#define NEED_STRDUP +/* If you have Ultrix 4.3, and are using cc, const is broken */ +#ifndef __ultrix__ /* Hack to check for pre-Ultrix 4.4 cc */ +#define const /* Not implemented */ +#endif +#define JMP_BUF sigjmp_buf + +#elif defined(OSF1) +#define HAVE_GMTOFF +#undef NO_KILLPG +#undef NO_SETSID +#define JMP_BUF sigjmp_buf +#define HAVE_MMAP +#define HAVE_CRYPT_H +#define NO_LONG_DOUBLE + +#elif defined(PARAGON) +#define HAVE_GMTOFF +#undef NO_KILLPG +#undef NO_SETSID +#define JMP_BUF sigjmp_buf +#define HAVE_MMAP +#define HAVE_CRYPT_H +#define NO_LONG_DOUBLE +typedef int rlim_t; + +#elif defined(SEQUENT) +#define HAVE_GMTOFF +#undef NO_KILLPG +#define NO_SETSID +#define NEED_STRDUP +#define tolower(c) (isupper(c) ? tolower(c) : c) + +#elif defined(NEXT) +typedef unsigned short mode_t; +#define HAVE_GMTOFF +#undef NO_KILLPG +#define NO_SETSID +#define NEED_STRDUP +#define NO_LINGCLOSE +#define NO_UNISTD_H +#undef _POSIX_SOURCE +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif +#ifndef S_ISDIR +#define S_ISDIR(m) (((m)&(S_IFMT)) == (S_IFDIR)) +#endif +#ifndef S_ISREG +#define S_ISREG(m) (((m)&(S_IFMT)) == (S_IFREG)) +#endif +#ifndef S_IXUSR +#define S_IXUSR 00100 +#endif +#ifndef S_IRGRP +#define S_IRGRP 00040 +#endif +#ifndef S_IXGRP +#define S_IXGRP 00010 +#endif +#ifndef S_IROTH +#define S_IROTH 00004 +#endif +#ifndef S_IXOTH +#define S_IXOTH 00001 +#endif +#ifndef S_IRUSR +#define S_IRUSR S_IREAD +#endif +#ifndef S_IWUSR +#define S_IWUSR S_IWRITE +#endif +#ifndef S_IWGRP +#define S_IWGRP 000020 +#endif +#ifndef S_IWOTH +#define S_IWOTH 000002 +#ifndef rlim_t +typedef int rlim_t; +#endif +typedef u_long n_long; +#endif + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 +#define waitpid(a,b,c) wait4((a) == -1 ? 0 : (a),(union wait *)(b),c,NULL) +typedef int pid_t; +#define JMP_BUF jmp_buf +#define USE_LONGJMP +#define NO_USE_SIGACTION + +#elif defined(LINUX) +#if LINUX > 1 +#define HAVE_SHMGET +#define HAVE_SYS_RESOURCE_H +typedef int rlim_t; +#endif +#define USE_FCNTL_SERIALIZED_ACCEPT +#undef HAVE_GMTOFF +#undef NO_KILLPG +#undef NO_SETSID +#undef NEED_STRDUP +#define JMP_BUF sigjmp_buf +#include <sys/time.h> + +#elif defined(SCO) +#undef HAVE_GMTOFF +#undef NO_KILLPG +#undef NO_SETSID +#define NEED_INITGROUPS +#define NO_WRITEV +#define JMP_BUF sigjmp_buf +#define SIGURG SIGUSR1 /* but note, this signal will be sent to a process group if enabled (for OOB data). It is not currently enabled. */ +#include <sys/time.h> + +#elif defined(SCO5) + +#define JMP_BUF sigjmp_buf +#define SIGURG SIGUSR1 +#define HAVE_SYS_SELECT_H +#define USE_FCNTL_SERIALIZED_ACCEPT +#define HAVE_MMAP +#define HAVE_SYS_RESOURCE_H +#define SecureWare + +/* Although SCO 5 defines these in <strings.h> (note the "s") they don't have +consts. Sigh. */ +extern int strcasecmp(const char *,const char *); +extern int strncasecmp(const char *,const char *,unsigned); + +#elif defined(CONVEXOS) +#define HAVE_GMTOFF +#define NEED_STRDUP + +#elif defined(AUX) +/* These are to let -Wall compile more cleanly */ +extern int strcasecmp(const char *, const char *); +extern int strncasecmp(const char *,const char *,unsigned); +extern int set42sig(), getopt(), getpeername(), bzero(); +extern int listen(), bind(), socket(), getsockname(); +extern int accept(), gethostname(), connect(), lstat(); +extern int select(), killpg(), shutdown(); +extern int initgroups(), setsockopt(); +extern char *shmat(); +extern int shmctl(); +extern int shmget(); +extern char *sbrk(); +extern char *crypt(); +#include <sys/time.h> +#undef HAVE_GMTOFF +#undef NO_KILLPG +#undef NO_SETSID +#define NEED_STRDUP +#define JMP_BUF sigjmp_buf +/* fcntl() locking is expensive with NFS */ +#undef USE_FLOCK_SERIALIZED_ACCEPT +#define HAVE_SHMGET +#define MOVEBREAK 0x4000000 +/* + * NOTE: If when you run Apache under A/UX and you get a warning + * that httpd couldn't move break, then the above value for + * MOVEBREAK (64megs) is too large for your setup. Try reducing + * to 0x2000000 which is still PLENTY of space. I doubt if + * even on heavy systems sbrk() would be called at all... + */ +#define NO_LINGCLOSE + +#elif defined(SVR4) +#define NO_KILLPG +#undef NO_SETSID +#undef NEED_STRDUP +#define NEED_STRCASECMP +#define NEED_STRNCASECMP +#define bzero(a,b) memset(a,0,b) +#define JMP_BUF sigjmp_buf +/* A lot of SVR4 systems need this */ +#define USE_FCNTL_SERIALIZED_ACCEPT + +#elif defined(UW) +#define NO_LINGCLOSE +#define NO_KILLPG +#undef NO_SETSID +#undef NEED_STRDUP +#define NEED_STRCASECMP +#define NEED_STRNCASECMP +#define bzero(a,b) memset(a,0,b) +#define JMP_BUF sigjmp_buf +#define HAVE_RESOURCE +#define HAVE_MMAP +#define HAVE_SHMGET +#define HAVE_CRYPT_H +#define HAVE_SYS_SELECT_H +#define HAVE_SYS_RESOURCE_H +#include <sys/time.h> +#define _POSIX_SOURCE + +#elif defined(DGUX) +#define NO_KILLPG +#undef NO_SETSID +#undef NEED_STRDUP +#define NEED_STRCASECMP +#define NEED_STRNCASECMP +#define bzero(a,b) memset(a,0,b) +#define JMP_BUF sigjmp_buf +/* A lot of SVR4 systems need this */ +#define USE_FCNTL_SERIALIZED_ACCEPT + +#elif defined(__NetBSD__) || defined(__OpenBSD__) +#define HAVE_SYS_RESOURCE_H +#define HAVE_GMTOFF +#undef NO_KILLPG +#undef NO_SETSID +#define JMP_BUF sigjmp_buf +#define DEFAULT_USER "nobody" +#define DEFAULT_GROUP "nogroup" + +#elif defined(UTS21) +#undef HAVE_GMTOFF +#undef NO_KILLPG +#define NO_SETSID +#define NEED_WAITPID +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 +#define strftime(buf,bufsize,fmt,tm) ascftime(buf,fmt,tm) +#include <sys/types.h> + +#elif defined(APOLLO) +#undef HAVE_GMTOFF +#undef NO_KILLPG +#undef NO_SETSID + +#elif defined(__FreeBSD__) || defined(__bsdi__) +#if defined(__FreeBSD__) +#include <osreldate.h> +#endif +#define HAVE_SYS_RESOURCE_H +#define HAVE_GMTOFF +#undef NO_KILLPG +#undef NO_SETSID +#define JMP_BUF sigjmp_buf +#define HAVE_MMAP +#define DEFAULT_USER "nobody" +#define DEFAULT_GROUP "nogroup" +#if defined(__bsdi__) || \ +(defined(__FreeBSD_version) && (__FreeBSD_version < 220000)) +typedef quad_t rlim_t; +#endif + +#elif defined(QNX) +#ifndef crypt +char *crypt(const char *pw, const char *salt); +#endif +#ifndef initgroups +int initgroups (char *, int); +#endif +#ifndef strncasecmp +#define strncasecmp strnicmp +#endif +#undef NO_KILLPG +#undef NO_SETSID +#define NEED_INITGROUPS +#define NEED_SELECT_H +#define NEED_PROCESS_H +#define HAVE_SYS_SELECT_H +#include <unix.h> +#define JMP_BUF sigjmp_buf + +#elif defined(LYNXOS) +#undef NO_KILLPG +#undef NO_SETSID +#define NEED_STRCASECMP +#define NEED_STRNCASECMP +#define NEED_INITGROUPS +#define JMP_BUF jmp_buf + +#elif defined(UXPDS) +#undef NEED_STRCASECMP +#undef NEED_STRNCASECMP +#undef NEED_STRDUP +#undef HAVE_GMTOFF +#define NO_KILLPG +#undef NO_SETSID +#define HAVE_RESOURCE 1 +#define bzero(a,b) memset(a,0,b) +#define JMP_BUF sigjmp_buf +#define USE_FCNTL_SERIALIZED_ACCEPT +#define HAVE_MMAP +#define HAVE_CRYPT_H + +#elif defined(__EMX__) +/* Defines required for EMX OS/2 port. */ +#define JMP_BUF sigjmp_buf +#define NO_KILLPG +#define NEED_STRCASECMP +#define NEED_STRNCASECMP +#define NO_SETSID +/* Add some drive name support */ +#define chdir _chdir2 +#include <sys/time.h> +#define MAXSOCKETS 4096 +#define HAVE_MMAP + +#elif defined(__MACHTEN__) +typedef int rlim_t; +#define JMP_BUF sigjmp_buf +#undef NO_KILLPG +#define NO_SETSID +#define HAVE_GMTOFF +#ifndef __MACHTEN_PPC__ +#ifndef __MACHTEN_68K__ +#define __MACHTEN_68K__ +#endif +#define USE_FLOCK_SERIALIZED_ACCEPT +#define NO_USE_SIGACTION +#define USE_LONGJMP +#undef NEED_STRDUP +#else +#define HAVE_SHMGET +#define USE_FCNTL_SERIALIZED_ACCEPT +#endif + +/* Convex OS v11 */ +#elif defined(CONVEXOS11) +#define NO_TIMEZONE +#include <stdio.h> +#include <sys/types.h> +#define JMP_BUF jmp_buf +typedef int rlim_t; + +#elif defined(ISC) +#include <net/errno.h> +#define NO_KILLPG +#undef NO_SETSID +#define HAVE_SHMGET +#define SIGURG SIGUSR1 +#define JMP_BUF sigjmp_buf +#define USE_FCNTL_SERIALIZED_ACCEPT + +/* Unknown system - Edit these to match */ +#else +#ifdef BSD +#define HAVE_GMTOFF +#else +#undef HAVE_GMTOFF +#endif +/* NO_KILLPG is set on systems that don't have killpg */ +#undef NO_KILLPG +/* NO_SETSID is set on systems that don't have setsid */ +#undef NO_SETSID +/* NEED_STRDUP is set on stupid systems that don't have strdup. */ +#undef NEED_STRDUP +#endif + +/* Do we have sys/resource.h; assume that BSD does. */ +#ifndef HAVE_SYS_RESOURCE_H +#ifdef BSD +#define HAVE_SYS_RESOURCE_H +#endif +#endif /* HAVE_SYS_RESOURCE_H */ + +/* + * The particular directory style your system supports. If you have dirent.h + * in /usr/include (POSIX) or /usr/include/sys (SYSV), #include + * that file and define DIR_TYPE to be dirent. Otherwise, if you have + * /usr/include/sys/dir.h, define DIR_TYPE to be direct and include that + * file. If you have neither, I'm confused. + */ + +#include <sys/types.h> +#include <stdarg.h> +/* + * We use snprintf() to avoid overflows, but we include + * our own version (ap_snprintf). Allow for people to use their + * snprintf() if they want + */ +#ifdef HAVE_SNPRINTF +#define ap_snprintf snprintf +#define ap_vsnprintf vsnprintf +#else +int ap_snprintf(char *buf, size_t len, const char *format,...); +int ap_vsnprintf(char *buf, size_t len, const char *format, va_list ap); +#endif + +#if !defined(NEXT) && !defined(CONVEXOS) +#include <dirent.h> +#define DIR_TYPE dirent +#else +#include <sys/dir.h> +#define DIR_TYPE direct +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#ifndef MPE +#include <sys/file.h> +#endif +#include <sys/socket.h> +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif +#include <ctype.h> +#include <netinet/in.h> +#include <netdb.h> +#include <sys/ioctl.h> +#ifndef MPE +#include <arpa/inet.h> /* for inet_ntoa */ +#endif +#include <time.h> /* for ctime */ +#include <signal.h> +#include <errno.h> +#include <sys/wait.h> +#include <pwd.h> +#include <grp.h> +#include <fcntl.h> +#include <limits.h> +#if !defined(QNX) && !defined(CONVEXOS11) && !defined(NEXT) +#include <memory.h> +#endif +#ifdef NEED_PROCESS_H +#include <process.h> +#endif + +#include <regex.h> + +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#ifdef SUNOS4 +int getrlimit( int, struct rlimit *); +int setrlimit( int, struct rlimit *); +#endif +#endif +#ifdef HAVE_MMAP +#ifndef __EMX__ +/* This file is not needed for OS/2 */ +#include <sys/mman.h> +#endif +#endif +#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS) +#define MAP_ANON MAP_ANONYMOUS +#endif + +#if defined(HAVE_MMAP) && defined(NO_MMAP) +#undef HAVE_MMAP +#endif + +#ifndef LOGNAME_MAX +#define LOGNAME_MAX 25 +#endif + +#ifndef NEXT +#include <unistd.h> +#endif + +#ifdef ultrix +#define ULTRIX_BRAIN_DEATH +#endif + +#ifndef S_ISLNK +#ifndef __EMX__ +/* Don't define this for OS/2 */ +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#endif +#endif + +#ifndef INADDR_NONE +#define INADDR_NONE ((unsigned long) -1) +#endif + +/* + * Replace signal function with sigaction equivalent + */ +#ifndef NO_USE_SIGACTION +typedef void Sigfunc(int); + +#if defined(SIG_IGN) && !defined(SIG_ERR) +#define SIG_ERR ((Sigfunc *)-1) +#endif + +/* + * For some strange reason, QNX defines signal to signal. Eliminate it. + */ +#ifdef signal +#undef signal +#endif +#define signal(s,f) ap_signal(s,f) +Sigfunc *signal(int signo, Sigfunc *func); +#endif + +#include <setjmp.h> + +#if defined(USE_LONGJMP) +#define ap_longjmp(x, y) longjmp((x), (y)) +#define ap_setjmp(x) setjmp(x) +#else +#define ap_longjmp(x, y) siglongjmp((x), (y)) +#define ap_setjmp(x) sigsetjmp((x), 1) +#endif + +/* Finding offsets of elements within structures. + * Taken from the X code... they've sweated portability of this stuff + * so we don't have to. Sigh... + */ + +#if defined(CRAY) || defined(__arm) +#if __STDC__ +#define XtOffset(p_type,field) _Offsetof(p_type,field) +#else +#ifdef CRAY2 +#define XtOffset(p_type,field) \ + (sizeof(int)*((unsigned int)&(((p_type)NULL)->field))) + +#else /* !CRAY2 */ + +#define XtOffset(p_type,field) ((unsigned int)&(((p_type)NULL)->field)) + +#endif /* !CRAY2 */ +#endif /* __STDC__ */ +#else /* ! (CRAY || __arm) */ + +#define XtOffset(p_type,field) \ + ((long) (((char *) (&(((p_type)NULL)->field))) - ((char *) NULL))) + +#endif /* !CRAY */ + +#ifdef offsetof +#define XtOffsetOf(s_type,field) offsetof(s_type,field) +#else +#define XtOffsetOf(s_type,field) XtOffset(s_type*,field) +#endif + +#ifdef SUNOS_LIB_PROTOTYPES +/* Prototypes needed to get a clean compile with gcc -Wall. + * Believe it or not, these do have to be declared, at least on SunOS, + * because they aren't mentioned in the relevant system headers. + * Sun Quality Software. Gotta love it. + */ + +int getopt (int, char **, char *); + +int strcasecmp (char *, char *); +int strncasecmp (char *, char *, int); +int toupper(int); +int tolower(int); + +int printf (char *, ...); +int fprintf (FILE *, char *, ...); +int fputs (char *, FILE *); +int fread (char *, int, int, FILE *); +int fwrite (char *, int, int, FILE *); +int fflush (FILE *); +int fclose (FILE *); +int ungetc (int, FILE *); +int _filbuf (FILE *); /* !!! */ +int _flsbuf (unsigned char, FILE *); /* !!! */ +int sscanf (char *, char *, ...); +void setbuf (FILE *, char *); +void perror (char *); + +time_t time (time_t *); +int strftime (char *, int, char *, struct tm *); + +int initgroups (char *, int); +int wait3 (int *, int, void*); /* Close enough for us... */ +int lstat (const char *, struct stat *); +int stat (const char *, struct stat *); +int flock (int, int); +#ifndef NO_KILLPG +int killpg(int, int); +#endif +int socket (int, int, int); +int setsockopt (int, int, int, const char*, int); +int listen (int, int); +int bind (int, struct sockaddr *, int); +int connect (int, struct sockaddr *, int); +int accept (int, struct sockaddr *, int *); +int shutdown (int, int); + +int getsockname (int s, struct sockaddr *name, int *namelen); +int getpeername (int s, struct sockaddr *name, int *namelen); +int gethostname (char *name, int namelen); +void syslog (int, char *, ...); +char *mktemp (char *); + +long vfprintf (FILE *, char *, va_list); + +#endif diff --git a/APACHE_1_2_X/src/include/buff.h b/APACHE_1_2_X/src/include/buff.h new file mode 100644 index 00000000000..593b68b34f2 --- /dev/null +++ b/APACHE_1_2_X/src/include/buff.h @@ -0,0 +1,137 @@ +/* ==================================================================== + * Copyright (c) 1996,1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +#include <stdarg.h> + +/* Reading is buffered */ +#define B_RD (1) +/* Writing is buffered */ +#define B_WR (2) +#define B_RDWR (3) +/* At end of file, or closed stream; no further input allowed */ +#define B_EOF (4) +/* No further output possible */ +#define B_EOUT (8) +/* A read error has occurred */ +#define B_RDERR (16) +/* A write error has occurred */ +#define B_WRERR (32) +#define B_ERROR (48) +/* Use chunked writing */ +#define B_CHUNK (64) +/* bflush() if a read would block */ +#define B_SAFEREAD (128) + +typedef struct buff_struct BUFF; + +struct buff_struct +{ + int flags; /* flags */ + unsigned char *inptr; /* pointer to next location to read */ + int incnt; /* number of bytes left to read from input buffer; + * always 0 if had a read error */ + int outchunk; /* location of chunk header when chunking */ + int outchunk_header_size; /* how long the header is */ + int outcnt; /* number of byte put in output buffer */ + unsigned char *inbase; + unsigned char *outbase; + int bufsiz; + void (*error)(BUFF *fb, int op, void *data); + void *error_data; + long int bytes_sent; /* number of bytes actually written */ + + pool *pool; + +/* could also put pointers to the basic I/O routines here */ + int fd; /* the file descriptor */ + int fd_in; /* input file descriptor, if different */ +}; + +/* Options to bset/getopt */ +#define BO_BYTECT (1) + +/* Stream creation and modification */ +extern BUFF *bcreate(pool *p, int flags); +extern void bpushfd(BUFF *fb, int fd_in, int fd_out); +extern int bsetopt(BUFF *fb, int optname, const void *optval); +extern int bgetopt(BUFF *fb, int optname, void *optval); +extern int bsetflag(BUFF *fb, int flag, int value); +extern int bclose(BUFF *fb); + +#define bgetflag(fb, flag) ((fb)->flags & (flag)) + +/* Error handling */ +extern void bonerror(BUFF *fb, void (*error)(BUFF *, int, void *), + void *data); + +/* I/O */ +extern int bread(BUFF *fb, void *buf, int nbyte); +extern int bgets(char *s, int n, BUFF *fb); +extern int blookc(char *buff, BUFF *fb); +extern int bskiplf(BUFF *fb); +extern int bwrite(BUFF *fb, const void *buf, int nbyte); +extern int bflush(BUFF *fb); +extern int bputs(const char *x, BUFF *fb); +extern int bvputs(BUFF *fb, ...); +extern int bprintf(BUFF *fb,const char *fmt,...); +extern int vbprintf(BUFF *fb,const char *fmt,va_list vlist); + +/* Internal routines */ +extern int bflsbuf(int c, BUFF *fb); +extern int bfilbuf(BUFF *fb); + +#define bgetc(fb) ( ((fb)->incnt == 0) ? bfilbuf(fb) : \ + ((fb)->incnt--, *((fb)->inptr++)) ) + +#define bputc(c, fb) ((((fb)->flags & (B_EOUT|B_WRERR|B_WR)) != B_WR || \ + (fb)->outcnt == (fb)->bufsiz) ? bflsbuf(c, (fb)) : \ + ((fb)->outbase[(fb)->outcnt++] = (c), 0)) diff --git a/APACHE_1_2_X/src/include/conf.h b/APACHE_1_2_X/src/include/conf.h new file mode 100644 index 00000000000..fd7869c069c --- /dev/null +++ b/APACHE_1_2_X/src/include/conf.h @@ -0,0 +1,752 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +/* + * conf.h: system-dependant #defines and includes... + * See README for a listing of what they mean + */ + +#if !defined(QNX) && !defined(MPE) +#include <sys/param.h> +#endif + +/* Define one of these according to your system. */ +#if defined(MPE) +#include <sys/times.h> +#define JMP_BUF sigjmp_buf +#define NO_SETSID +#define NO_KILLPG +#define NO_WRITEV +#define NEED_INITGROUPS +#define NEED_STRCASECMP +#define NEED_STRDUP +#define NEED_STRNCASECMP +extern void GETPRIVMODE(); +extern void GETUSERMODE(); +extern char *inet_ntoa(); + +#elif defined(SUNOS4) +#define HAVE_GMTOFF +#define HAVE_SYS_RESOURCE_H +#undef NO_KILLPG +#undef NO_SETSID +char *crypt(const char *pw, const char *salt); +char *mktemp(char *template); +#define JMP_BUF sigjmp_buf +#define HAVE_MMAP +#include <sys/time.h> +#define NEED_STRERROR +typedef int rlim_t; +#define memmove(a,b,c) bcopy(b,a,c) +#define NO_LINGCLOSE + +#elif defined(SOLARIS2) +#undef HAVE_GMTOFF +#define NO_KILLPG +#undef NO_SETSID +#define HAVE_SYS_RESOURCE_H +#define bzero(a,b) memset(a,0,b) +#define JMP_BUF sigjmp_buf +#define USE_FCNTL_SERIALIZED_ACCEPT +#define HAVE_MMAP +#define HAVE_CRYPT_H +int gethostname(char *name, int namelen); + +#elif defined(IRIX) +#undef HAVE_GMTOFF +/* IRIX has killpg, but it's only in _BSD_COMPAT, so don't use it in case + * there's some weird conflict with non-BSD signals */ +#define NO_KILLPG +#undef NO_SETSID +#define JMP_BUF sigjmp_buf +#define USE_FCNTL_SERIALIZED_ACCEPT +#define HAVE_SHMGET +#define HAVE_CRYPT_H +#define NO_LONG_DOUBLE +#define HAVE_BSTRING_H +#define NO_LINGCLOSE + +#elif defined(HIUX) +#define HAVE_SYS_RESOURCE_H +#undef HAVE_GMTOFF +#define NO_KILLPG +#undef NO_SETSID +#ifndef _HIUX_SOURCE +#define _HIUX_SOURCE +#endif +#define JMP_BUF sigjmp_buf +#define HAVE_SHMGET +#define SELECT_NEEDS_CAST + +#elif defined(HPUX) || defined(HPUX10) +#define HAVE_SYS_RESOURCE_H +#undef HAVE_GMTOFF +#define NO_KILLPG +#undef NO_SETSID +#ifndef _HPUX_SOURCE +#define _HPUX_SOURCE +#endif +#define JMP_BUF sigjmp_buf +#define HAVE_SHMGET +#ifndef HPUX10 +#define SELECT_NEEDS_CAST +typedef int rlim_t; +#endif + +#elif defined(AIX) +#undef HAVE_GMTOFF +#undef NO_KILLPG +#undef NO_SETSID +#define HAVE_SYS_SELECT_H +#define JMP_BUF sigjmp_buf +#ifndef __ps2__ +#define HAVE_MMAP +#define DEFAULT_GROUP "nobody" +#endif +#define DEFAULT_USER "nobody" +typedef int rlim_t; + +#elif defined(ULTRIX) +#define HAVE_GMTOFF +#undef NO_KILLPG +#undef NO_SETSID +#define ULTRIX_BRAIN_DEATH +#define NEED_STRDUP +/* If you have Ultrix 4.3, and are using cc, const is broken */ +#ifndef __ultrix__ /* Hack to check for pre-Ultrix 4.4 cc */ +#define const /* Not implemented */ +#endif +#define JMP_BUF sigjmp_buf + +#elif defined(OSF1) +#define HAVE_GMTOFF +#undef NO_KILLPG +#undef NO_SETSID +#define JMP_BUF sigjmp_buf +#define HAVE_MMAP +#define HAVE_CRYPT_H +#define NO_LONG_DOUBLE + +#elif defined(PARAGON) +#define HAVE_GMTOFF +#undef NO_KILLPG +#undef NO_SETSID +#define JMP_BUF sigjmp_buf +#define HAVE_MMAP +#define HAVE_CRYPT_H +#define NO_LONG_DOUBLE +typedef int rlim_t; + +#elif defined(SEQUENT) +#define HAVE_GMTOFF +#undef NO_KILLPG +#define NO_SETSID +#define NEED_STRDUP +#define tolower(c) (isupper(c) ? tolower(c) : c) + +#elif defined(NEXT) +typedef unsigned short mode_t; +#define HAVE_GMTOFF +#undef NO_KILLPG +#define NO_SETSID +#define NEED_STRDUP +#define NO_LINGCLOSE +#define NO_UNISTD_H +#undef _POSIX_SOURCE +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif +#ifndef S_ISDIR +#define S_ISDIR(m) (((m)&(S_IFMT)) == (S_IFDIR)) +#endif +#ifndef S_ISREG +#define S_ISREG(m) (((m)&(S_IFMT)) == (S_IFREG)) +#endif +#ifndef S_IXUSR +#define S_IXUSR 00100 +#endif +#ifndef S_IRGRP +#define S_IRGRP 00040 +#endif +#ifndef S_IXGRP +#define S_IXGRP 00010 +#endif +#ifndef S_IROTH +#define S_IROTH 00004 +#endif +#ifndef S_IXOTH +#define S_IXOTH 00001 +#endif +#ifndef S_IRUSR +#define S_IRUSR S_IREAD +#endif +#ifndef S_IWUSR +#define S_IWUSR S_IWRITE +#endif +#ifndef S_IWGRP +#define S_IWGRP 000020 +#endif +#ifndef S_IWOTH +#define S_IWOTH 000002 +#ifndef rlim_t +typedef int rlim_t; +#endif +typedef u_long n_long; +#endif + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 +#define waitpid(a,b,c) wait4((a) == -1 ? 0 : (a),(union wait *)(b),c,NULL) +typedef int pid_t; +#define JMP_BUF jmp_buf +#define USE_LONGJMP +#define NO_USE_SIGACTION + +#elif defined(LINUX) +#if LINUX > 1 +#define HAVE_SHMGET +#define HAVE_SYS_RESOURCE_H +typedef int rlim_t; +#endif +#define USE_FCNTL_SERIALIZED_ACCEPT +#undef HAVE_GMTOFF +#undef NO_KILLPG +#undef NO_SETSID +#undef NEED_STRDUP +#define JMP_BUF sigjmp_buf +#include <sys/time.h> + +#elif defined(SCO) +#undef HAVE_GMTOFF +#undef NO_KILLPG +#undef NO_SETSID +#define NEED_INITGROUPS +#define NO_WRITEV +#define JMP_BUF sigjmp_buf +#define SIGURG SIGUSR1 /* but note, this signal will be sent to a process group if enabled (for OOB data). It is not currently enabled. */ +#include <sys/time.h> + +#elif defined(SCO5) + +#define JMP_BUF sigjmp_buf +#define SIGURG SIGUSR1 +#define HAVE_SYS_SELECT_H +#define USE_FCNTL_SERIALIZED_ACCEPT +#define HAVE_MMAP +#define HAVE_SYS_RESOURCE_H +#define SecureWare + +/* Although SCO 5 defines these in <strings.h> (note the "s") they don't have +consts. Sigh. */ +extern int strcasecmp(const char *,const char *); +extern int strncasecmp(const char *,const char *,unsigned); + +#elif defined(CONVEXOS) +#define HAVE_GMTOFF +#define NEED_STRDUP + +#elif defined(AUX) +/* These are to let -Wall compile more cleanly */ +extern int strcasecmp(const char *, const char *); +extern int strncasecmp(const char *,const char *,unsigned); +extern int set42sig(), getopt(), getpeername(), bzero(); +extern int listen(), bind(), socket(), getsockname(); +extern int accept(), gethostname(), connect(), lstat(); +extern int select(), killpg(), shutdown(); +extern int initgroups(), setsockopt(); +extern char *shmat(); +extern int shmctl(); +extern int shmget(); +extern char *sbrk(); +extern char *crypt(); +#include <sys/time.h> +#undef HAVE_GMTOFF +#undef NO_KILLPG +#undef NO_SETSID +#define NEED_STRDUP +#define JMP_BUF sigjmp_buf +/* fcntl() locking is expensive with NFS */ +#undef USE_FLOCK_SERIALIZED_ACCEPT +#define HAVE_SHMGET +#define MOVEBREAK 0x4000000 +/* + * NOTE: If when you run Apache under A/UX and you get a warning + * that httpd couldn't move break, then the above value for + * MOVEBREAK (64megs) is too large for your setup. Try reducing + * to 0x2000000 which is still PLENTY of space. I doubt if + * even on heavy systems sbrk() would be called at all... + */ +#define NO_LINGCLOSE + +#elif defined(SVR4) +#define NO_KILLPG +#undef NO_SETSID +#undef NEED_STRDUP +#define NEED_STRCASECMP +#define NEED_STRNCASECMP +#define bzero(a,b) memset(a,0,b) +#define JMP_BUF sigjmp_buf +/* A lot of SVR4 systems need this */ +#define USE_FCNTL_SERIALIZED_ACCEPT + +#elif defined(UW) +#define NO_LINGCLOSE +#define NO_KILLPG +#undef NO_SETSID +#undef NEED_STRDUP +#define NEED_STRCASECMP +#define NEED_STRNCASECMP +#define bzero(a,b) memset(a,0,b) +#define JMP_BUF sigjmp_buf +#define HAVE_RESOURCE +#define HAVE_MMAP +#define HAVE_SHMGET +#define HAVE_CRYPT_H +#define HAVE_SYS_SELECT_H +#define HAVE_SYS_RESOURCE_H +#include <sys/time.h> +#define _POSIX_SOURCE + +#elif defined(DGUX) +#define NO_KILLPG +#undef NO_SETSID +#undef NEED_STRDUP +#define NEED_STRCASECMP +#define NEED_STRNCASECMP +#define bzero(a,b) memset(a,0,b) +#define JMP_BUF sigjmp_buf +/* A lot of SVR4 systems need this */ +#define USE_FCNTL_SERIALIZED_ACCEPT + +#elif defined(__NetBSD__) || defined(__OpenBSD__) +#define HAVE_SYS_RESOURCE_H +#define HAVE_GMTOFF +#undef NO_KILLPG +#undef NO_SETSID +#define JMP_BUF sigjmp_buf +#define DEFAULT_USER "nobody" +#define DEFAULT_GROUP "nogroup" + +#elif defined(UTS21) +#undef HAVE_GMTOFF +#undef NO_KILLPG +#define NO_SETSID +#define NEED_WAITPID +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 +#define strftime(buf,bufsize,fmt,tm) ascftime(buf,fmt,tm) +#include <sys/types.h> + +#elif defined(APOLLO) +#undef HAVE_GMTOFF +#undef NO_KILLPG +#undef NO_SETSID + +#elif defined(__FreeBSD__) || defined(__bsdi__) +#if defined(__FreeBSD__) +#include <osreldate.h> +#endif +#define HAVE_SYS_RESOURCE_H +#define HAVE_GMTOFF +#undef NO_KILLPG +#undef NO_SETSID +#define JMP_BUF sigjmp_buf +#define HAVE_MMAP +#define DEFAULT_USER "nobody" +#define DEFAULT_GROUP "nogroup" +#if defined(__bsdi__) || \ +(defined(__FreeBSD_version) && (__FreeBSD_version < 220000)) +typedef quad_t rlim_t; +#endif + +#elif defined(QNX) +#ifndef crypt +char *crypt(const char *pw, const char *salt); +#endif +#ifndef initgroups +int initgroups (char *, int); +#endif +#ifndef strncasecmp +#define strncasecmp strnicmp +#endif +#undef NO_KILLPG +#undef NO_SETSID +#define NEED_INITGROUPS +#define NEED_SELECT_H +#define NEED_PROCESS_H +#define HAVE_SYS_SELECT_H +#include <unix.h> +#define JMP_BUF sigjmp_buf + +#elif defined(LYNXOS) +#undef NO_KILLPG +#undef NO_SETSID +#define NEED_STRCASECMP +#define NEED_STRNCASECMP +#define NEED_INITGROUPS +#define JMP_BUF jmp_buf + +#elif defined(UXPDS) +#undef NEED_STRCASECMP +#undef NEED_STRNCASECMP +#undef NEED_STRDUP +#undef HAVE_GMTOFF +#define NO_KILLPG +#undef NO_SETSID +#define HAVE_RESOURCE 1 +#define bzero(a,b) memset(a,0,b) +#define JMP_BUF sigjmp_buf +#define USE_FCNTL_SERIALIZED_ACCEPT +#define HAVE_MMAP +#define HAVE_CRYPT_H + +#elif defined(__EMX__) +/* Defines required for EMX OS/2 port. */ +#define JMP_BUF sigjmp_buf +#define NO_KILLPG +#define NEED_STRCASECMP +#define NEED_STRNCASECMP +#define NO_SETSID +/* Add some drive name support */ +#define chdir _chdir2 +#include <sys/time.h> +#define MAXSOCKETS 4096 +#define HAVE_MMAP + +#elif defined(__MACHTEN__) +typedef int rlim_t; +#define JMP_BUF sigjmp_buf +#undef NO_KILLPG +#define NO_SETSID +#define HAVE_GMTOFF +#ifndef __MACHTEN_PPC__ +#ifndef __MACHTEN_68K__ +#define __MACHTEN_68K__ +#endif +#define USE_FLOCK_SERIALIZED_ACCEPT +#define NO_USE_SIGACTION +#define USE_LONGJMP +#undef NEED_STRDUP +#else +#define HAVE_SHMGET +#define USE_FCNTL_SERIALIZED_ACCEPT +#endif + +/* Convex OS v11 */ +#elif defined(CONVEXOS11) +#define NO_TIMEZONE +#include <stdio.h> +#include <sys/types.h> +#define JMP_BUF jmp_buf +typedef int rlim_t; + +#elif defined(ISC) +#include <net/errno.h> +#define NO_KILLPG +#undef NO_SETSID +#define HAVE_SHMGET +#define SIGURG SIGUSR1 +#define JMP_BUF sigjmp_buf +#define USE_FCNTL_SERIALIZED_ACCEPT + +/* Unknown system - Edit these to match */ +#else +#ifdef BSD +#define HAVE_GMTOFF +#else +#undef HAVE_GMTOFF +#endif +/* NO_KILLPG is set on systems that don't have killpg */ +#undef NO_KILLPG +/* NO_SETSID is set on systems that don't have setsid */ +#undef NO_SETSID +/* NEED_STRDUP is set on stupid systems that don't have strdup. */ +#undef NEED_STRDUP +#endif + +/* Do we have sys/resource.h; assume that BSD does. */ +#ifndef HAVE_SYS_RESOURCE_H +#ifdef BSD +#define HAVE_SYS_RESOURCE_H +#endif +#endif /* HAVE_SYS_RESOURCE_H */ + +/* + * The particular directory style your system supports. If you have dirent.h + * in /usr/include (POSIX) or /usr/include/sys (SYSV), #include + * that file and define DIR_TYPE to be dirent. Otherwise, if you have + * /usr/include/sys/dir.h, define DIR_TYPE to be direct and include that + * file. If you have neither, I'm confused. + */ + +#include <sys/types.h> +#include <stdarg.h> +/* + * We use snprintf() to avoid overflows, but we include + * our own version (ap_snprintf). Allow for people to use their + * snprintf() if they want + */ +#ifdef HAVE_SNPRINTF +#define ap_snprintf snprintf +#define ap_vsnprintf vsnprintf +#else +int ap_snprintf(char *buf, size_t len, const char *format,...); +int ap_vsnprintf(char *buf, size_t len, const char *format, va_list ap); +#endif + +#if !defined(NEXT) && !defined(CONVEXOS) +#include <dirent.h> +#define DIR_TYPE dirent +#else +#include <sys/dir.h> +#define DIR_TYPE direct +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#ifndef MPE +#include <sys/file.h> +#endif +#include <sys/socket.h> +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif +#include <ctype.h> +#include <netinet/in.h> +#include <netdb.h> +#include <sys/ioctl.h> +#ifndef MPE +#include <arpa/inet.h> /* for inet_ntoa */ +#endif +#include <time.h> /* for ctime */ +#include <signal.h> +#include <errno.h> +#include <sys/wait.h> +#include <pwd.h> +#include <grp.h> +#include <fcntl.h> +#include <limits.h> +#if !defined(QNX) && !defined(CONVEXOS11) && !defined(NEXT) +#include <memory.h> +#endif +#ifdef NEED_PROCESS_H +#include <process.h> +#endif + +#include <regex.h> + +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#ifdef SUNOS4 +int getrlimit( int, struct rlimit *); +int setrlimit( int, struct rlimit *); +#endif +#endif +#ifdef HAVE_MMAP +#ifndef __EMX__ +/* This file is not needed for OS/2 */ +#include <sys/mman.h> +#endif +#endif +#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS) +#define MAP_ANON MAP_ANONYMOUS +#endif + +#if defined(HAVE_MMAP) && defined(NO_MMAP) +#undef HAVE_MMAP +#endif + +#ifndef LOGNAME_MAX +#define LOGNAME_MAX 25 +#endif + +#ifndef NEXT +#include <unistd.h> +#endif + +#ifdef ultrix +#define ULTRIX_BRAIN_DEATH +#endif + +#ifndef S_ISLNK +#ifndef __EMX__ +/* Don't define this for OS/2 */ +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#endif +#endif + +#ifndef INADDR_NONE +#define INADDR_NONE ((unsigned long) -1) +#endif + +/* + * Replace signal function with sigaction equivalent + */ +#ifndef NO_USE_SIGACTION +typedef void Sigfunc(int); + +#if defined(SIG_IGN) && !defined(SIG_ERR) +#define SIG_ERR ((Sigfunc *)-1) +#endif + +/* + * For some strange reason, QNX defines signal to signal. Eliminate it. + */ +#ifdef signal +#undef signal +#endif +#define signal(s,f) ap_signal(s,f) +Sigfunc *signal(int signo, Sigfunc *func); +#endif + +#include <setjmp.h> + +#if defined(USE_LONGJMP) +#define ap_longjmp(x, y) longjmp((x), (y)) +#define ap_setjmp(x) setjmp(x) +#else +#define ap_longjmp(x, y) siglongjmp((x), (y)) +#define ap_setjmp(x) sigsetjmp((x), 1) +#endif + +/* Finding offsets of elements within structures. + * Taken from the X code... they've sweated portability of this stuff + * so we don't have to. Sigh... + */ + +#if defined(CRAY) || defined(__arm) +#if __STDC__ +#define XtOffset(p_type,field) _Offsetof(p_type,field) +#else +#ifdef CRAY2 +#define XtOffset(p_type,field) \ + (sizeof(int)*((unsigned int)&(((p_type)NULL)->field))) + +#else /* !CRAY2 */ + +#define XtOffset(p_type,field) ((unsigned int)&(((p_type)NULL)->field)) + +#endif /* !CRAY2 */ +#endif /* __STDC__ */ +#else /* ! (CRAY || __arm) */ + +#define XtOffset(p_type,field) \ + ((long) (((char *) (&(((p_type)NULL)->field))) - ((char *) NULL))) + +#endif /* !CRAY */ + +#ifdef offsetof +#define XtOffsetOf(s_type,field) offsetof(s_type,field) +#else +#define XtOffsetOf(s_type,field) XtOffset(s_type*,field) +#endif + +#ifdef SUNOS_LIB_PROTOTYPES +/* Prototypes needed to get a clean compile with gcc -Wall. + * Believe it or not, these do have to be declared, at least on SunOS, + * because they aren't mentioned in the relevant system headers. + * Sun Quality Software. Gotta love it. + */ + +int getopt (int, char **, char *); + +int strcasecmp (char *, char *); +int strncasecmp (char *, char *, int); +int toupper(int); +int tolower(int); + +int printf (char *, ...); +int fprintf (FILE *, char *, ...); +int fputs (char *, FILE *); +int fread (char *, int, int, FILE *); +int fwrite (char *, int, int, FILE *); +int fflush (FILE *); +int fclose (FILE *); +int ungetc (int, FILE *); +int _filbuf (FILE *); /* !!! */ +int _flsbuf (unsigned char, FILE *); /* !!! */ +int sscanf (char *, char *, ...); +void setbuf (FILE *, char *); +void perror (char *); + +time_t time (time_t *); +int strftime (char *, int, char *, struct tm *); + +int initgroups (char *, int); +int wait3 (int *, int, void*); /* Close enough for us... */ +int lstat (const char *, struct stat *); +int stat (const char *, struct stat *); +int flock (int, int); +#ifndef NO_KILLPG +int killpg(int, int); +#endif +int socket (int, int, int); +int setsockopt (int, int, int, const char*, int); +int listen (int, int); +int bind (int, struct sockaddr *, int); +int connect (int, struct sockaddr *, int); +int accept (int, struct sockaddr *, int *); +int shutdown (int, int); + +int getsockname (int s, struct sockaddr *name, int *namelen); +int getpeername (int s, struct sockaddr *name, int *namelen); +int gethostname (char *name, int namelen); +void syslog (int, char *, ...); +char *mktemp (char *); + +long vfprintf (FILE *, char *, va_list); + +#endif diff --git a/APACHE_1_2_X/src/include/explain.h b/APACHE_1_2_X/src/include/explain.h new file mode 100644 index 00000000000..5912502585e --- /dev/null +++ b/APACHE_1_2_X/src/include/explain.h @@ -0,0 +1,23 @@ +#ifndef EXPLAIN +#define DEF_Explain +#define Explain0(f) +#define Explain1(f,a1) +#define Explain2(f,a1,a2) +#define Explain3(f,a1,a2,a3) +#define Explain4(f,a1,a2,a3,a4) +#define Explain5(f,a1,a2,a3,a4,a5) +#define Explain6(f,a1,a2,a3,a4,a5,a6) +#else +#define DEF_Explain static const char *__ExplainFile=__FILE__; +void _Explain(const char *szFile,int nLine,const char *szFmt,...); +#define Explain0(f) _Explain(__ExplainFile,__LINE__,f) +#define Explain1(f,a1) _Explain(__ExplainFile,__LINE__,f,a1) +#define Explain2(f,a1,a2) _Explain(__ExplainFile,__LINE__,f,a1,a2) +#define Explain3(f,a1,a2,a3) _Explain(__ExplainFile,__LINE__,f,a1,a2,a3) +#define Explain4(f,a1,a2,a3,a4) _Explain(__ExplainFile,__LINE__,f,a1,a2,a3,a4) +#define Explain5(f,a1,a2,a3,a4,a5) \ + _Explain(__ExplainFile,__LINE__,f,a1,a2,a3,a4,a5) +#define Explain6(f,a1,a2,a3,a4,a5,a6) \ + _Explain(__ExplainFile,__LINE__,f,a1,a2,a3,a4,a5,a6) + +#endif diff --git a/APACHE_1_2_X/src/include/hsregex.h b/APACHE_1_2_X/src/include/hsregex.h new file mode 100644 index 00000000000..dde954d8332 --- /dev/null +++ b/APACHE_1_2_X/src/include/hsregex.h @@ -0,0 +1,73 @@ +#ifndef _REGEX_H_ +#define _REGEX_H_ /* never again */ +/* ========= begin header generated by ./mkh ========= */ +#ifdef __cplusplus +extern "C" { +#endif + +/* === regex2.h === */ +typedef off_t regoff_t; +typedef struct { + int re_magic; + size_t re_nsub; /* number of parenthesized subexpressions */ + const char *re_endp; /* end pointer for REG_PEND */ + struct re_guts *re_g; /* none of your business :-) */ +} regex_t; +typedef struct { + regoff_t rm_so; /* start of match */ + regoff_t rm_eo; /* end of match */ +} regmatch_t; + + +/* === regcomp.c === */ +extern int regcomp(regex_t *, const char *, int); +#define REG_BASIC 0000 +#define REG_EXTENDED 0001 +#define REG_ICASE 0002 +#define REG_NOSUB 0004 +#define REG_NEWLINE 0010 +#define REG_NOSPEC 0020 +#define REG_PEND 0040 +#define REG_DUMP 0200 + + +/* === regerror.c === */ +#define REG_NOMATCH 1 +#define REG_BADPAT 2 +#define REG_ECOLLATE 3 +#define REG_ECTYPE 4 +#define REG_EESCAPE 5 +#define REG_ESUBREG 6 +#define REG_EBRACK 7 +#define REG_EPAREN 8 +#define REG_EBRACE 9 +#define REG_BADBR 10 +#define REG_ERANGE 11 +#define REG_ESPACE 12 +#define REG_BADRPT 13 +#define REG_EMPTY 14 +#define REG_ASSERT 15 +#define REG_INVARG 16 +#define REG_ATOI 255 /* convert name to number (!) */ +#define REG_ITOA 0400 /* convert number to name (!) */ +extern size_t regerror(int, const regex_t *, char *, size_t); + + +/* === regexec.c === */ +extern int regexec(const regex_t *, const char *, size_t, regmatch_t [], int); +#define REG_NOTBOL 00001 +#define REG_NOTEOL 00002 +#define REG_STARTEND 00004 +#define REG_TRACE 00400 /* tracing of execution */ +#define REG_LARGE 01000 /* force large representation */ +#define REG_BACKR 02000 /* force use of backref code */ + + +/* === regfree.c === */ +extern void regfree(regex_t *); + +#ifdef __cplusplus +} +#endif +/* ========= end header generated by ./mkh ========= */ +#endif diff --git a/APACHE_1_2_X/src/include/http_conf_globals.h b/APACHE_1_2_X/src/include/http_conf_globals.h new file mode 100644 index 00000000000..0596ab4460b --- /dev/null +++ b/APACHE_1_2_X/src/include/http_conf_globals.h @@ -0,0 +1,85 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +/* + * Process config --- what the process ITSELF is doing + */ + +extern int standalone; +extern uid_t user_id; +extern char *user_name; +extern gid_t group_id; +#ifdef MULTIPLE_GROUPS +extern gid_t group_id_list[NGROUPS_MAX]; +#endif +extern int max_requests_per_child; +extern struct in_addr bind_address; +extern listen_rec *listeners; +extern int daemons_to_start; +extern int daemons_min_free; +extern int daemons_max_free; +extern int daemons_limit; +extern int suexec_enabled; + +extern char *pid_fname; +extern char *scoreboard_fname; +extern char *server_argv0; + +/* Trying to allocate these in the config pool gets us into some *nasty* + * chicken-and-egg problems in http_main.c --- where do you stick them + * when pconf gets cleared? Better to just allocate a little space + * statically... + */ + +extern char server_root[MAX_STRING_LEN]; +extern char server_confname[MAX_STRING_LEN]; + diff --git a/APACHE_1_2_X/src/include/http_config.h b/APACHE_1_2_X/src/include/http_config.h new file mode 100644 index 00000000000..148ab6958f7 --- /dev/null +++ b/APACHE_1_2_X/src/include/http_config.h @@ -0,0 +1,297 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +/* + * The central data structures around here... + */ + +/* Command dispatch structures... */ + +enum cmd_how { + RAW_ARGS, /* cmd_func parses command line itself */ + TAKE1, /* one argument only */ + TAKE2, /* two arguments only */ + ITERATE, /* one argument, occuring multiple times + * (e.g., IndexIgnore) + */ + ITERATE2, /* two arguments, 2nd occurs multiple times + * (e.g., AddIcon) + */ + FLAG, /* One of 'On' or 'Off' */ + NO_ARGS, /* No args at all, e.g. </Directory> */ + TAKE12, /* one or two arguments */ + TAKE3, /* three arguments only */ + TAKE23, /* two or three arguments */ + TAKE123, /* one, two or three arguments */ + TAKE13 /* one or three arguments */ +}; + +typedef struct command_struct { + char *name; /* Name of this command */ + const char *(*func)(); /* Function invoked */ + void *cmd_data; /* Extra data, for functions which + * implement multiple commands... + */ + int req_override; /* What overrides need to be allowed to + * enable this command. + */ + enum cmd_how args_how; /* What the command expects as arguments */ + + char *errmsg; /* 'usage' message, in case of syntax errors */ +} command_rec; + +/* The allowed locations for a configuration directive are the union of + * those indicated by each set bit in the req_override mask. + * + * (req_override & RSRC_CONF) => *.conf outside <Directory> or <Location> + * (req_override & ACCESS_CONF) => *.conf inside <Directory> or <Location> + * (req_override & OR_AUTHCFG) => *.conf inside <Directory> or <Location> + * and .htaccess when AllowOverride AuthConfig + * (req_override & OR_LIMIT) => *.conf inside <Directory> or <Location> + * and .htaccess when AllowOverride Limit + * (req_override & OR_OPTIONS) => *.conf anywhere + * and .htaccess when AllowOverride Options + * (req_override & OR_FILEINFO) => *.conf anywhere + * and .htaccess when AllowOverride FileInfo + * (req_override & OR_INDEXES) => *.conf anywhere + * and .htaccess when AllowOverride Indexes + */ +#define OR_NONE 0 +#define OR_LIMIT 1 +#define OR_OPTIONS 2 +#define OR_FILEINFO 4 +#define OR_AUTHCFG 8 +#define OR_INDEXES 16 +#define OR_UNSET 32 +#define ACCESS_CONF 64 +#define RSRC_CONF 128 +#define OR_ALL (OR_LIMIT|OR_OPTIONS|OR_FILEINFO|OR_AUTHCFG|OR_INDEXES) + +/* This can be returned by a function if they don't wish to handle + * a command. Make it something not likely someone will actually use + * as an error code. + */ + +#define DECLINE_CMD "\a\b" + +/* + * This structure is passed to a command which is being invoked, + * to carry a large variety of miscellaneous data which is all of + * use to *somebody*... + */ + +typedef struct { + void *info; /* Argument to command from cmd_table */ + int override; /* Which allow-override bits are set */ + int limited; /* Which methods are <Limit>ed */ + + char *config_file; /* Filename cmd read from */ + int config_line; /* Line cmd read from */ + FILE *infile; /* fd for more lines (not currently used) */ + + pool *pool; /* Pool to allocate new storage in */ + pool *temp_pool; /* Pool for scratch memory; persists during + * configuration, but wiped before the first + * request is served... + */ + server_rec *server; /* Server_rec being configured for */ + char *path; /* If configuring for a directory, + * pathname of that directory. + */ + const command_rec *cmd; /* configuration command */ +} cmd_parms; + +/* This structure records the existence of handlers in a module... */ + +typedef struct { + char *content_type; + int (*handler) (request_rec *); +} handler_rec; + +/* + * Module structures. Just about everything is dispatched through + * these, directly or indirectly (through the command and handler + * tables). + */ + +typedef struct module_struct { + int version; /* API version, *not* module version; + * check that module is compatible with this + * version of the server. + */ + int module_index; /* Index to this modules structures in + * config vectors. + */ + + const char *name; + + struct module_struct *next; + +#ifdef ULTRIX_BRAIN_DEATH + void (*init)(); + void *(*create_dir_config)(); + void *(*merge_dir_config)(); + void *(*create_server_config)(); + void *(*merge_server_config)(); +#else + void (*init)(server_rec *, pool *); + void *(*create_dir_config)(pool *p, char *dir); + void *(*merge_dir_config)(pool *p, void *base_conf, void *new_conf); + void *(*create_server_config)(pool *p, server_rec *s); + void *(*merge_server_config)(pool *p, void *base_conf, void *new_conf); +#endif + + command_rec *cmds; + handler_rec *handlers; + + /* Hooks for getting into the middle of server ops... + * + * translate_handler --- translate URI to filename + * access_checker --- check access by host address, etc. All of these + * run; if all decline, that's still OK. + * check_user_id --- get and validate user id from the HTTP request + * auth_checker --- see if the user (from check_user_id) is OK *here*. + * If all of *these* decline, the request is rejected + * (as a SERVER_ERROR, since the module which was + * supposed to handle this was configured wrong). + * type_checker --- Determine MIME type of the requested entity; + * sets content_type, _encoding and _language fields. + * logger --- log a transaction. Not supported yet out of sheer + * laziness on my part. + */ + + int (*translate_handler)(request_rec *); + int (*check_user_id)(request_rec *); + int (*auth_checker)(request_rec *); + int (*access_checker)(request_rec *); + int (*type_checker)(request_rec *); + int (*fixer_upper)(request_rec *); + int (*logger)(request_rec *); + int (*header_parser)(request_rec *); +} module; + +/* Initializer for the first few module slots, which are only + * really set up once we start running. Note that the first word + * is a version check; this should allow us to deal with changes to + * the API (the server can detect an old-format module, and either + * handle it back-compatibly, or at least signal an error). + */ + +#define MODULE_MAGIC_NUMBER 19970526 +#define STANDARD_MODULE_STUFF MODULE_MAGIC_NUMBER, -1, __FILE__, NULL + +/* Generic accessors for other modules to get at their own module-specific + * data + */ + +void *get_module_config (void *conf_vector, module *m); +void set_module_config (void *conf_vector, module *m, void *val); + +/* Generic command handling function... */ + +const char *set_string_slot (cmd_parms *, char *, char *); +const char *set_flag_slot (cmd_parms *, char *, int); + +/* For modules which need to read config files, open logs, etc. ... + * this returns the fname argument if it begins with '/'; otherwise + * it relativizes it wrt server_root. + */ + +char *server_root_relative (pool *p, char *fname); + +/* Finally, the hook for dynamically loading modules in... */ + +void add_module (module *m); +int add_named_module (const char *name); +void clear_module_list (); +const char *find_module_name (module *m); +module *find_linked_module (const char *name); + +#ifdef CORE_PRIVATE + +/* For http_main.c... */ + +server_rec *read_config (pool *conf_pool, pool *temp_pool, char *config_name); +void setup_prelinked_modules(); +void show_directives(); +void show_modules(); + +/* For http_request.c... */ + +void *create_request_config (pool *p); +void *create_per_dir_config (pool *p); +void *merge_per_dir_configs (pool *p, void *base, void *new); + +/* For http_core.c... (<Directory> command and virtual hosts) */ + +int parse_htaccess(void **result, request_rec *r, int override, + char *path, char *file); +const char *srm_command_loop (cmd_parms *parms, void *config); + +server_rec *init_virtual_host (pool *p, const char *hostname, server_rec *main_server); +int is_virtual_server (server_rec *); +void process_resource_config(server_rec *s, char *fname, pool *p, pool *ptemp); + +/* Module-method dispatchers, also for http_request.c */ + +int translate_name (request_rec *); +int directory_walk (request_rec *); /* check symlinks, get per-dir config */ +int check_access (request_rec *); /* check access on non-auth basis */ +int check_user_id (request_rec *); /* obtain valid username from client auth */ +int check_auth (request_rec *); /* check (validated) user is authorized here */ +int find_types (request_rec *); /* identify MIME type */ +int run_fixups (request_rec *); /* poke around for other metainfo, etc.... */ +int invoke_handler (request_rec *); +int log_transaction (request_rec *r); +int header_parse (request_rec *); + +#endif diff --git a/APACHE_1_2_X/src/include/http_core.h b/APACHE_1_2_X/src/include/http_core.h new file mode 100644 index 00000000000..8454b81ad11 --- /dev/null +++ b/APACHE_1_2_X/src/include/http_core.h @@ -0,0 +1,205 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +/***************************************************************** + * + * The most basic server code is encapsulated in a single module + * known as the core, which is just *barely* functional enough to + * serve documents, though not terribly well. + * + * Largely for NCSA back-compatibility reasons, the core needs to + * make pieces of its config structures available to other modules. + * The accessors are declared here, along with the interpretation + * of one of them (allow_options). + */ + +#define OPT_NONE 0 +#define OPT_INDEXES 1 +#define OPT_INCLUDES 2 +#define OPT_SYM_LINKS 4 +#define OPT_EXECCGI 8 +#define OPT_UNSET 16 +#define OPT_INCNOEXEC 32 +#define OPT_SYM_OWNER 64 +#define OPT_MULTI 128 +#define OPT_ALL (OPT_INDEXES|OPT_INCLUDES|OPT_SYM_LINKS|OPT_EXECCGI) + +/* options for get_remote_host() */ +#define REMOTE_HOST (0) +#define REMOTE_NAME (1) +#define REMOTE_NOLOOKUP (2) + +#define SATISFY_ALL 0 +#define SATISFY_ANY 1 +#define SATISFY_NOSPEC 2 + +int allow_options (request_rec *); +int allow_overrides (request_rec *); +char *default_type (request_rec *); +char *document_root (request_rec *); /* Don't use this! If your request went + * through a Userdir, or something like + * that, it'll screw you. But it's + * back-compatible... + */ +extern const char *get_remote_host(conn_rec *conn, void *dir_config, int type); +extern const char *get_remote_logname(request_rec *r); + +/* Authentication stuff. This is one of the places where compatibility + * with the old config files *really* hurts; they don't discriminate at + * all between different authentication schemes, meaning that we need + * to maintain common state for all of them in the core, and make it + * available to the other modules through interfaces. + */ + +typedef struct { + int method_mask; + char *requirement; +} require_line; + +char *auth_type (request_rec *); +char *auth_name (request_rec *); +int satisfies (request_rec *r); +array_header *requires (request_rec *); + +#ifdef CORE_PRIVATE + +/* + * Core is also unlike other modules in being implemented in more than + * one file... so, data structures are declared here, even though most of + * the code that cares really is in http_core.c. Also, anothre accessor. + */ + +char *response_code_string (request_rec *r, int error_index); + +extern module core_module; + +/* Per-directory configuration */ + +typedef char allow_options_t; +typedef char overrides_t; + +typedef struct { + char *d; + /* since is_matchexp(conf->d) was being called so frequently in + * directory_walk() and its relatives, this field was created and + * is set to the result of that call. + */ + int d_is_matchexp; + + allow_options_t opts; + allow_options_t opts_add; + allow_options_t opts_remove; + overrides_t override; + + /* MIME typing --- the core doesn't do anything at all with this, + * but it does know what to slap on a request for a document which + * goes untyped by other mechanisms before it slips out the door... + */ + + char *default_type; + + /* Authentication stuff. Groan... */ + + int satisfy; + char *auth_type; + char *auth_name; + array_header *requires; + + int content_md5; + + /* Custom response config. These can contain text or a URL to redirect to. + * if response_code_strings is NULL then there are none in the config, + * if it's not null then it's allocated to sizeof(char*)*RESPONSE_CODES. + * This lets us do quick merges in merge_core_dir_configs(). + */ + + char **response_code_strings; + + /* Hostname resolution etc */ + int hostname_lookups; + int do_rfc1413; /* See if client is advertising a username? */ + + /* System Resource Control */ +#ifdef RLIMIT_CPU + struct rlimit *limit_cpu; +#endif +#if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) + struct rlimit *limit_mem; +#endif +#ifdef RLIMIT_NPROC + struct rlimit *limit_nproc; +#endif + + /* Access control */ + array_header *sec; + regex_t *r; + +} core_dir_config; + +/* Per-server core configuration */ + +typedef struct { + + /* Name translations --- we want the core to be able to do *something* + * so it's at least a minimally functional web server on its own (and + * can be tested that way). But let's keep it to the bare minimum: + */ + char *document_root; + + /* Access control */ + + char *access_name; + array_header *sec; + array_header *sec_url; +} core_server_config; + +#endif diff --git a/APACHE_1_2_X/src/include/http_log.h b/APACHE_1_2_X/src/include/http_log.h new file mode 100644 index 00000000000..e30324db61d --- /dev/null +++ b/APACHE_1_2_X/src/include/http_log.h @@ -0,0 +1,62 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +void open_logs (server_rec *, pool *p); +void error_log2stderr (server_rec *); + +void log_pid (pool *p, char *pid_fname); +void log_error(char *err, server_rec *s); +extern void log_unixerr(const char *routine, const char *file, + const char *msg, server_rec *s); +void log_printf(const server_rec *s, const char *fmt, ...); +void log_reason(const char *reason, const char *fname, request_rec *r); + diff --git a/APACHE_1_2_X/src/include/http_main.h b/APACHE_1_2_X/src/include/http_main.h new file mode 100644 index 00000000000..7d3c2f5a789 --- /dev/null +++ b/APACHE_1_2_X/src/include/http_main.h @@ -0,0 +1,99 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +/* + * Routines in http_main.c which other code --- in particular modules --- + * may want to call. Right now, that's limited to timeout handling. + * There are two functions which modules can call to trigger a timeout + * (with the per-virtual-server timeout duration); these are hard_timeout + * and soft_timeout. + * + * The difference between the two is what happens when the timeout + * expires (or earlier than that, if the client connection aborts) --- + * a soft_timeout just puts the connection to the client in an + * "aborted" state, which will cause http_protocol.c to stop trying to + * talk to the client, but otherwise allows the code to continue normally. + * hard_timeout(), by contrast, logs the request, and then aborts it + * completely --- longjmp()ing out to the accept() loop in http_main. + * Any resources tied into the request's resource pool will be cleaned up; + * everything that isn't will leak. + * + * soft_timeout() is recommended as a general rule, because it gives your + * code a chance to clean up. However, hard_timeout() may be the most + * convenient way of dealing with timeouts waiting for some external + * resource other than the client, if you can live with the restrictions. + * + * (When a hard timeout is in scope, critical sections can be guarded + * with block_alarms() and unblock_alarms() --- these are declared in + * alloc.c because they are most often used in conjunction with + * routines to allocate something or other, to make sure that the + * cleanup does get registered before any alarm is allowed to happen + * which might require it to be cleaned up; they * are, however, + * implemented in http_main.c). + * + * kill_timeout() will disarm either variety of timeout. + * + * reset_timeout() resets the timeout in progress. + */ + +void hard_timeout (char *, request_rec *); +void keepalive_timeout (char *, request_rec *); +void soft_timeout (char *, request_rec *); +void kill_timeout (request_rec *); +void reset_timeout (request_rec *); + +void sync_scoreboard_image (); +int update_child_status (int child_num, int status, request_rec *r); +int get_child_status (int child_num); +int count_busy_servers (); +int count_idle_servers (); + diff --git a/APACHE_1_2_X/src/include/http_protocol.h b/APACHE_1_2_X/src/include/http_protocol.h new file mode 100644 index 00000000000..85687b48a3e --- /dev/null +++ b/APACHE_1_2_X/src/include/http_protocol.h @@ -0,0 +1,190 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +/* + * Prototypes for routines which either talk directly back to the user, + * or control the ones that eventually do. + */ + +/* Read a request and fill in the fields. */ + +request_rec *read_request (conn_rec *c); + +/* Send a single HTTP header field */ + +int send_header_field (request_rec *r, const char *fieldname, + const char *fieldval); + +/* Send the Status-Line and header fields for HTTP response */ + +void send_http_header (request_rec *l); + +/* Send the response to special method requests */ + +int send_http_trace (request_rec *r); +int send_http_options (request_rec *r); + +/* Finish up stuff after a request */ + +void finalize_request_protocol (request_rec *r); + +/* Send error back to client... last arg indicates error status in case + * we get an error in the process of trying to deal with an ErrorDocument + * to handle some other error. In that case, we print the default report + * for the first thing that went wrong, and more briefly report on the + * problem with the ErrorDocument. + */ + +void send_error_response (request_rec *r, int recursive_error); + +/* Set last modified header line from the lastmod date of the associated file. + * Also, set content length. + * + * May return an error status, typically USE_LOCAL_COPY (that when the + * permit_cache argument is set to one). + */ + +int set_content_length (request_rec *r, long length); +int set_keepalive (request_rec *r); +int set_last_modified (request_rec *r, time_t mtime); + +/* Other ways to send stuff at the client. All of these keep track + * of bytes_sent automatically. This indirection is intended to make + * it a little more painless to slide things like HTTP-NG packetization + * underneath the main body of the code later. In the meantime, it lets + * us centralize a bit of accounting (bytes_sent). + * + * These also return the number of bytes written by the call. + * They should only be called with a timeout registered, for obvious reaasons. + * (Ditto the send_header stuff). + */ + +long send_fd(FILE *f, request_rec *r); +long send_fd_length(FILE *f, request_rec *r, long length); + +/* Hmmm... could macrofy these for now, and maybe forever, though the + * definitions of the macros would get a whole lot hairier. + */ + +int rputc (int c, request_rec *r); +int rputs(const char *str, request_rec *r); +int rwrite(const void *buf, int nbyte, request_rec *r); +int rvputs(request_rec *r, ...); +int rprintf(request_rec *r,const char *fmt,...); +int rflush(request_rec *r); + +/* + * Index used in custom_responses array for a specific error code + * (only use outside protocol.c is in getting them configured). + */ + +int index_of_response (int status); + +/* Reading a block of data from the client connection (e.g., POST arg) */ + +int setup_client_block (request_rec *r, int read_policy); +int should_client_block (request_rec *r); +long get_client_block (request_rec *r, char *buffer, int bufsiz); + +/* Sending a byterange */ + +int set_byterange (request_rec *r); +int each_byterange (request_rec *r, long *offset, long *length); + +/* Finally, this charming little number is here to encapsulate the + * degree to which nph- scripts completely escape from any discipline + * the protocol code might care to impose (this as opposed to other + * scripts, which *partially* escape to the extent that they may try + * to explicitly set the status line). + */ + +void client_to_stdout (conn_rec *c); + + +/* Support for the Basic authentication protocol. Note that there's + * nothing that prevents these from being in mod_auth.c, except that other + * modules which wanted to provide their own variants on finding users and + * passwords for Basic auth (a fairly common request) would then require + * mod_auth to be loaded or they wouldn't work. + * + * get_basic_auth_pw returns 0 (OK) if it set the 'pw' argument (and assured + * a correct value in r->connection->user); otherwise it returns an error + * code, either SERVER_ERROR if things are really confused, AUTH_REQUIRED + * if no authentication at all seemed to be in use, or DECLINED if there + * was authentication but it wasn't Basic (in which case, the caller should + * presumably decline as well). + * + * note_basic_auth_failure arranges for the right stuff to be scribbled on + * the HTTP return so that the client knows how to authenticate itself the + * next time. As does note_digest_auth_failure for Digest auth. + * + * note_auth_failure does the same thing, but will call the correct one + * based on the authentication type in use. + * + */ + +void note_auth_failure(request_rec *r); +void note_basic_auth_failure(request_rec *r); +void note_digest_auth_failure(request_rec *r); +int get_basic_auth_pw (request_rec *r, char **pw); + +/* + * Setting up the protocol fields for subsidiary requests... + * Also, a wrapup function to keep the internal accounting straight. + */ + +void set_sub_req_protocol (request_rec *rnew, const request_rec *r); +void finalize_sub_req_protocol (request_rec *sub_r); + +/* This is also useful for putting sub_reqs and internal_redirects together */ + +void parse_uri (request_rec *r, const char *uri); diff --git a/APACHE_1_2_X/src/include/http_request.h b/APACHE_1_2_X/src/include/http_request.h new file mode 100644 index 00000000000..f20d494cad9 --- /dev/null +++ b/APACHE_1_2_X/src/include/http_request.h @@ -0,0 +1,92 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +/* http_request.c is the code which handles the main line of request + * processing, once a request has been read in (finding the right per- + * directory configuration, building it if necessary, and calling all + * the module dispatch functions in the right order). + * + * The pieces here which are public to the modules, allow them to learn + * how the server would handle some other file or URI, or perhaps even + * direct the server to serve that other file instead of the one the + * client requested directly. + * + * There are two ways to do that. The first is the sub_request mechanism, + * which handles looking up files and URIs as adjuncts to some other + * request (e.g., directory entries for multiviews and directory listings); + * the lookup functions stop short of actually running the request, but + * (e.g., for includes), a module may call for the request to be run + * by calling run_sub_req. The space allocated to create sub_reqs can be + * reclaimed by calling destroy_sub_req --- be sure to copy anything you care + * about which was allocated in its pool elsewhere before doing this. + */ + +request_rec *sub_req_lookup_uri (const char *new_file, const request_rec *r); +request_rec *sub_req_lookup_file (const char *new_file, const request_rec *r); +int run_sub_req (request_rec *r); +void destroy_sub_req (request_rec *r); + +/* + * Then there's the case that you want some other request to be served + * as the top-level request INSTEAD of what the client requested directly. + * If so, call this from a handler, and then immediately return OK. + */ + +void internal_redirect (const char *new_uri, request_rec *); +void internal_redirect_handler (const char *new_uri, request_rec *); +int some_auth_required (request_rec *r); + +#ifdef CORE_PRIVATE +/* Function called by main.c to handle first-level request */ +void process_request (request_rec *); +int default_handler (request_rec *); +#endif diff --git a/APACHE_1_2_X/src/include/httpd.h b/APACHE_1_2_X/src/include/httpd.h new file mode 100644 index 00000000000..3f15afdb350 --- /dev/null +++ b/APACHE_1_2_X/src/include/httpd.h @@ -0,0 +1,713 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +/* + * httpd.h: header for simple (ha! not anymore) http daemon + */ + +/* Headers in which EVERYONE has an interest... */ + +#include "conf.h" +#include "alloc.h" +#include "buff.h" + +/* ----------------------------- config dir ------------------------------ */ + +/* Define this to be the default server home dir. Anything later in this + * file with a relative pathname will have this added. + */ +#ifndef HTTPD_ROOT +#ifdef __EMX__ +/* Set default for OS/2 file system */ +#define HTTPD_ROOT "/os2httpd" +#else +#define HTTPD_ROOT "/usr/local/etc/httpd" +#endif +#endif + +/* Root of server */ +#ifdef __EMX__ +/* Set default for OS/2 file system */ +#define DOCUMENT_LOCATION "/os2httpd/docs" +#else +#define DOCUMENT_LOCATION "/usr/local/etc/httpd/htdocs" +#endif + +/* Max. number of dynamically loaded modules */ +#define DYNAMIC_MODULE_LIMIT 64 + +/* Default administrator's address */ +#define DEFAULT_ADMIN "[no address given]" + +/* + * --------- You shouldn't have to edit anything below this line ---------- + * + * Any modifications to any defaults not defined above should be done in the + * respective config. file. + * + */ + + +/* -------------- Port number for server running standalone --------------- */ + +#define DEFAULT_PORT 80 + +/* --------- Default user name and group name running standalone ---------- */ +/* --- These may be specified as numbers by placing a # before a number --- */ + +#ifndef DEFAULT_USER +#define DEFAULT_USER "#-1" +#endif +#ifndef DEFAULT_GROUP +#define DEFAULT_GROUP "#-1" +#endif + +/* The name of the log files */ +#ifdef __EMX__ +/* Set default for OS/2 file system */ +#define DEFAULT_XFERLOG "logs/access.log" +#else +#define DEFAULT_XFERLOG "logs/access_log" +#endif +#ifdef __EMX__ +/* Set default for OS/2 file system */ +#define DEFAULT_ERRORLOG "logs/error.log" +#else +#define DEFAULT_ERRORLOG "logs/error_log" +#endif +#define DEFAULT_PIDLOG "logs/httpd.pid" +#define DEFAULT_SCOREBOARD "logs/apache_runtime_status" + +/* Define this to be what your HTML directory content files are called */ +#define DEFAULT_INDEX "index.html" + +/* Define this to 1 if you want fancy indexing, 0 otherwise */ +#define DEFAULT_INDEXING 0 + +/* Define this to be what type you'd like returned for files with unknown */ +/* suffixes */ +#define DEFAULT_TYPE "text/plain" + +/* Define this to be what your per-directory security files are called */ +#ifdef __EMX__ +/* Set default for OS/2 file system */ +#define DEFAULT_ACCESS_FNAME "htaccess" +#else +#define DEFAULT_ACCESS_FNAME ".htaccess" +#endif + +/* The name of the server config file */ +#ifndef SERVER_CONFIG_FILE +#define SERVER_CONFIG_FILE "conf/httpd.conf" +#endif + +/* The name of the document config file */ +#define RESOURCE_CONFIG_FILE "conf/srm.conf" + +/* The name of the MIME types file */ +#define TYPES_CONFIG_FILE "conf/mime.types" + +/* The name of the access file */ +#define ACCESS_CONFIG_FILE "conf/access.conf" + +/* Whether we should enable rfc1413 identity checking */ +#define DEFAULT_RFC1413 0 +/* The default directory in user's home dir */ +#define DEFAULT_USER_DIR "public_html" + +/* The default path for CGI scripts if none is currently set */ +#ifndef DEFAULT_PATH +#define DEFAULT_PATH "/bin:/usr/bin:/usr/ucb:/usr/bsd:/usr/local/bin" +#endif + +/* The path to the Bourne shell, for parsed docs */ +#ifndef SHELL_PATH +#ifdef __EMX__ +/* Set default for OS/2 file system */ +#define SHELL_PATH "CMD.EXE" +#else +#define SHELL_PATH "/bin/sh" +#endif +#endif + +/* The path to the suExec wrapper, can be overridden in Configuration */ +#ifndef SUEXEC_BIN +#define SUEXEC_BIN "/usr/local/etc/httpd/sbin/suexec" +#endif + +/* The default string lengths */ +#define MAX_STRING_LEN HUGE_STRING_LEN +#define HUGE_STRING_LEN 8192 + +/* The timeout for waiting for messages */ +#define DEFAULT_TIMEOUT 300 + +/* The timeout for waiting for keepalive timeout until next request */ +#define DEFAULT_KEEPALIVE_TIMEOUT 15 + +/* The number of requests to entertain per connection */ +#define DEFAULT_KEEPALIVE 100 + +/* The size of the server's internal read-write buffers */ +#define IOBUFSIZE 8192 + +/* Number of servers to spawn off by default --- also, if fewer than + * this free when the caretaker checks, it will spawn more. + */ +#define DEFAULT_START_DAEMON 5 + +/* Maximum number of *free* server processes --- more than this, and + * they will die off. + */ + +#define DEFAULT_MAX_FREE_DAEMON 10 + +/* Minimum --- fewer than this, and more will be created */ + +#define DEFAULT_MIN_FREE_DAEMON 5 + +/* Limit on the total --- clients will be locked out if more servers than + * this are needed. It is intended solely to keep the server from crashing + * when things get out of hand. + * + * We keep a hard maximum number of servers, for two reasons --- first off, + * in case something goes seriously wrong, we want to stop the fork bomb + * short of actually crashing the machine we're running on by filling some + * kernel table. Secondly, it keeps the size of the scoreboard file small + * enough that we can read the whole thing without worrying too much about + * the overhead. + */ +#ifndef HARD_SERVER_LIMIT +#define HARD_SERVER_LIMIT 256 +#endif + +/* Number of requests to try to handle in a single process. If <= 0, + * the children don't die off. That's the default here, since I'm still + * interested in finding and stanching leaks. + */ + +#define DEFAULT_MAX_REQUESTS_PER_CHILD 0 + +/* If you have altered Apache and wish to change the SERVER_VERSION + * identifier below, please keep to the HTTP specification. This states that + * the identification string should consist of product tokens with an optional + * slash and version designator. Sub-products which form a significant part + * of the application can be listed, separated by whitespace, by adding + * their product tokens to EXTRA_CFLAGS in the Configuration file like so. + * + * EXTRA_CFLAGS="-DSERVER_SUBVERSION="MrWidget/0.1-alpha" + * + * The tokens are listed in order of their significance for identifying the + * application. + * + * "Product tokens should be short and to the point -- use of them for + * advertizing or other non-essential information is explicitly forbidden." + * + * Example: "Apache/1.1.0 MrWidget/0.1-alpha" + */ + +#define SERVER_BASEVERSION "Apache/1.2.1-dev" /* SEE COMMENTS ABOVE */ +#ifdef SERVER_SUBVERSION +#define SERVER_VERSION SERVER_BASEVERSION " " SERVER_SUBVERSION +#else +#define SERVER_VERSION SERVER_BASEVERSION +#endif + +#define SERVER_PROTOCOL "HTTP/1.1" +#define SERVER_SUPPORT "http://www.apache.org/" + +#define DECLINED -1 /* Module declines to handle */ +#define OK 0 /* Module has handled this stage. */ + +/* ----------------------- HTTP Status Codes ------------------------- */ + +#define RESPONSE_CODES 38 + +#define HTTP_CONTINUE 100 +#define HTTP_SWITCHING_PROTOCOLS 101 +#define HTTP_OK 200 +#define HTTP_CREATED 201 +#define HTTP_ACCEPTED 202 +#define HTTP_NON_AUTHORITATIVE 203 +#define HTTP_NO_CONTENT 204 +#define HTTP_RESET_CONTENT 205 +#define HTTP_PARTIAL_CONTENT 206 +#define HTTP_MULTIPLE_CHOICES 300 +#define HTTP_MOVED_PERMANENTLY 301 +#define HTTP_MOVED_TEMPORARILY 302 +#define HTTP_SEE_OTHER 303 +#define HTTP_NOT_MODIFIED 304 +#define HTTP_USE_PROXY 305 +#define HTTP_BAD_REQUEST 400 +#define HTTP_UNAUTHORIZED 401 +#define HTTP_PAYMENT_REQUIRED 402 +#define HTTP_FORBIDDEN 403 +#define HTTP_NOT_FOUND 404 +#define HTTP_METHOD_NOT_ALLOWED 405 +#define HTTP_NOT_ACCEPTABLE 406 +#define HTTP_PROXY_AUTHENTICATION_REQUIRED 407 +#define HTTP_REQUEST_TIME_OUT 408 +#define HTTP_CONFLICT 409 +#define HTTP_GONE 410 +#define HTTP_LENGTH_REQUIRED 411 +#define HTTP_PRECONDITION_FAILED 412 +#define HTTP_REQUEST_ENTITY_TOO_LARGE 413 +#define HTTP_REQUEST_URI_TOO_LARGE 414 +#define HTTP_UNSUPPORTED_MEDIA_TYPE 415 +#define HTTP_INTERNAL_SERVER_ERROR 500 +#define HTTP_NOT_IMPLEMENTED 501 +#define HTTP_BAD_GATEWAY 502 +#define HTTP_SERVICE_UNAVAILABLE 503 +#define HTTP_GATEWAY_TIME_OUT 504 +#define HTTP_VERSION_NOT_SUPPORTED 505 +#define HTTP_VARIANT_ALSO_VARIES 506 + +#define DOCUMENT_FOLLOWS HTTP_OK +#define PARTIAL_CONTENT HTTP_PARTIAL_CONTENT +#define MULTIPLE_CHOICES HTTP_MULTIPLE_CHOICES +#define MOVED HTTP_MOVED_PERMANENTLY +#define REDIRECT HTTP_MOVED_TEMPORARILY +#define USE_LOCAL_COPY HTTP_NOT_MODIFIED +#define BAD_REQUEST HTTP_BAD_REQUEST +#define AUTH_REQUIRED HTTP_UNAUTHORIZED +#define FORBIDDEN HTTP_FORBIDDEN +#define NOT_FOUND HTTP_NOT_FOUND +#define METHOD_NOT_ALLOWED HTTP_METHOD_NOT_ALLOWED +#define NOT_ACCEPTABLE HTTP_NOT_ACCEPTABLE +#define LENGTH_REQUIRED HTTP_LENGTH_REQUIRED +#define PRECONDITION_FAILED HTTP_PRECONDITION_FAILED +#define SERVER_ERROR HTTP_INTERNAL_SERVER_ERROR +#define NOT_IMPLEMENTED HTTP_NOT_IMPLEMENTED +#define BAD_GATEWAY HTTP_BAD_GATEWAY +#define VARIANT_ALSO_VARIES HTTP_VARIANT_ALSO_VARIES + +#define is_HTTP_INFO(x) (((x) >= 100)&&((x) < 200)) +#define is_HTTP_SUCCESS(x) (((x) >= 200)&&((x) < 300)) +#define is_HTTP_REDIRECT(x) (((x) >= 300)&&((x) < 400)) +#define is_HTTP_ERROR(x) (((x) >= 400)&&((x) < 600)) +#define is_HTTP_CLIENT_ERROR(x) (((x) >= 400)&&((x) < 500)) +#define is_HTTP_SERVER_ERROR(x) (((x) >= 500)&&((x) < 600)) + +#define status_drops_connection(x) (((x) == HTTP_BAD_REQUEST) || \ + ((x) == HTTP_REQUEST_TIME_OUT) || \ + ((x) == HTTP_LENGTH_REQUIRED) || \ + ((x) == HTTP_REQUEST_ENTITY_TOO_LARGE) || \ + ((x) == HTTP_REQUEST_URI_TOO_LARGE) || \ + ((x) == HTTP_INTERNAL_SERVER_ERROR) || \ + ((x) == HTTP_SERVICE_UNAVAILABLE)) + + +#define METHODS 8 +#define M_GET 0 +#define M_PUT 1 +#define M_POST 2 +#define M_DELETE 3 +#define M_CONNECT 4 +#define M_OPTIONS 5 +#define M_TRACE 6 +#define M_INVALID 7 + +#define CGI_MAGIC_TYPE "application/x-httpd-cgi" +#define INCLUDES_MAGIC_TYPE "text/x-server-parsed-html" +#define INCLUDES_MAGIC_TYPE3 "text/x-server-parsed-html3" +#define MAP_FILE_MAGIC_TYPE "application/x-type-map" +#define ASIS_MAGIC_TYPE "httpd/send-as-is" +#define DIR_MAGIC_TYPE "httpd/unix-directory" +#define STATUS_MAGIC_TYPE "application/x-httpd-status" + +/* Just in case your linefeed isn't the one the other end is expecting. */ +#define LF 10 +#define CR 13 + +/* Possible values for request_rec.read_body (set by handling module): + * REQUEST_NO_BODY Send 413 error if message has any body + * REQUEST_CHUNKED_ERROR Send 411 error if body without Content-Length + * REQUEST_CHUNKED_DECHUNK If chunked, remove the chunks for me. + * REQUEST_CHUNKED_PASS Pass the chunks to me without removal. + */ +#define REQUEST_NO_BODY 0 +#define REQUEST_CHUNKED_ERROR 1 +#define REQUEST_CHUNKED_DECHUNK 2 +#define REQUEST_CHUNKED_PASS 3 + +/* Things which may vary per file-lookup WITHIN a request --- + * e.g., state of MIME config. Basically, the name of an object, info + * about the object, and any other info we may ahve which may need to + * change as we go poking around looking for it (e.g., overridden by + * .htaccess files). + * + * Note how the default state of almost all these things is properly + * zero, so that allocating it with pcalloc does the right thing without + * a whole lot of hairy initialization... so long as we are willing to + * make the (fairly) portable assumption that the bit pattern of a NULL + * pointer is, in fact, zero. + */ + +/* This represents the result of calling htaccess; these are cached for + * each request. + */ +struct htaccess_result +{ + char *dir; /* the directory to which this applies */ + int override; /* the overrides allowed for the .htaccess file */ + void *htaccess; /* the configuration directives */ +/* the next one, or NULL if no more; N.B. never change this */ + const struct htaccess_result *next; +}; + + +typedef struct conn_rec conn_rec; +typedef struct server_rec server_rec; +typedef struct request_rec request_rec; +typedef struct listen_rec listen_rec; + +struct request_rec { + + pool *pool; + conn_rec *connection; + server_rec *server; + + request_rec *next; /* If we wind up getting redirected, + * pointer to the request we redirected to. + */ + request_rec *prev; /* If this is an internal redirect, + * pointer to where we redirected *from*. + */ + + request_rec *main; /* If this is a sub_request (see request.h) + * pointer back to the main request. + */ + + /* Info about the request itself... we begin with stuff that only + * protocol.c should ever touch... + */ + + char *the_request; /* First line of request, so we can log it */ + int assbackwards; /* HTTP/0.9, "simple" request */ + int proxyreq; /* A proxy request */ + int header_only; /* HEAD request, as opposed to GET */ + char *protocol; /* Protocol, as given to us, or HTTP/0.9 */ + int proto_num; /* Number version of protocol; 1.1 = 1001 */ + char *hostname; /* Host, as set by full URI or Host: */ + int hostlen; /* Length of http://host:port in full URI */ + + time_t request_time; /* When the request started */ + + char *status_line; /* Status line, if set by script */ + int status; /* In any case */ + + /* Request method, two ways; also, protocol, etc.. Outside of protocol.c, + * look, but don't touch. + */ + + char *method; /* GET, HEAD, POST, etc. */ + int method_number; /* M_GET, M_POST, etc. */ + int allowed; /* Allowed methods - for 405, OPTIONS, etc */ + + int sent_bodyct; /* byte count in stream is for body */ + long bytes_sent; /* body byte count, for easy access */ + + /* HTTP/1.1 connection-level features */ + + int chunked; /* sending chunked transfer-coding */ + int byterange; /* number of byte ranges */ + char *boundary; /* multipart/byteranges boundary */ + char *range; /* The Range: header */ + long clength; /* The "real" content length */ + + long remaining; /* bytes left to read */ + long read_length; /* bytes that have been read */ + int read_body; /* how the request body should be read */ + int read_chunked; /* reading chunked transfer-coding */ + + /* MIME header environments, in and out. Also, an array containing + * environment variables to be passed to subprocesses, so people can + * write modules to add to that environment. + * + * The difference between headers_out and err_headers_out is that the + * latter are printed even on error, and persist across internal redirects + * (so the headers printed for ErrorDocument handlers will have them). + * + * The 'notes' table is for notes from one module to another, with no + * other set purpose in mind... + */ + + table *headers_in; + table *headers_out; + table *err_headers_out; + table *subprocess_env; + table *notes; + + char *content_type; /* Break these out --- we dispatch on 'em */ + char *handler; /* What we *really* dispatch on */ + + char *content_encoding; + char *content_language; /* for back-compat. only -- do not use */ + array_header *content_languages; /* array of (char*) */ + + int no_cache; + int no_local_copy; + + /* What object is being requested (either directly, or via include + * or content-negotiation mapping). + */ + + char *uri; /* complete URI for a proxy req, or + URL path for a non-proxy req */ + char *filename; + char *path_info; + char *args; /* QUERY_ARGS, if any */ + struct stat finfo; /* ST_MODE set to zero if no such file */ + + /* Various other config info which may change with .htaccess files + * These are config vectors, with one void* pointer for each module + * (the thing pointed to being the module's business). + */ + + void *per_dir_config; /* Options set in config files, etc. */ + void *request_config; /* Notes on *this* request */ + +/* + * a linked list of the configuration directives in the .htaccess files + * accessed by this request. + * N.B. always add to the head of the list, _never_ to the end. + * that way, a sub request's list can (temporarily) point to a parent's list + */ + const struct htaccess_result *htaccess; +}; + + +/* Things which are per connection + */ + +struct conn_rec { + + pool *pool; + server_rec *server; + server_rec *base_server; /* Physical vhost this conn come in on */ + + /* Information about the connection itself */ + + int child_num; /* The number of the child handling conn_rec */ + BUFF *client; /* Connetion to the guy */ + int aborted; /* Are we still talking? */ + + /* Who is the client? */ + + struct sockaddr_in local_addr; /* local address */ + struct sockaddr_in remote_addr;/* remote address */ + char *remote_ip; /* Client's IP address */ + char *remote_host; /* Client's DNS name, if known. + * NULL if DNS hasn't been checked, + * "" if it has and no address was found. + * N.B. Only access this though + * get_remote_host() */ + char *remote_logname; /* Only ever set if doing rfc1413 lookups. + * N.B. Only access this through + * get_remote_logname() */ + char *user; /* If an authentication check was made, + * this gets set to the user name. We assume + * that there's only one user per connection(!) + */ + char *auth_type; /* Ditto. */ + + int keepalive; /* Are we using HTTP Keep-Alive? */ + int keptalive; /* Did we use HTTP Keep-Alive? */ + int keepalives; /* How many times have we used it? */ +}; + +/* Per-vhost config... */ + +/* The address 255.255.255.255, when used as a virtualhost address, + * will become the "default" server when the ip doesn't match other vhosts. + */ +#define DEFAULT_VHOST_ADDR 0xfffffffful + +typedef struct server_addr_rec server_addr_rec; +struct server_addr_rec { + server_addr_rec *next; + struct in_addr host_addr; /* The bound address, for this server */ + unsigned short host_port; /* The bound port, for this server */ + char *virthost; /* The name given in <VirtualHost> */ +}; + + +struct server_rec { + + server_rec *next; + + /* Full locations of server config info */ + + char *srm_confname; + char *access_confname; + + /* Contact information */ + + char *server_admin; + char *server_hostname; + unsigned short port; /* for redirects, etc. */ + + /* Log files --- note that transfer log is now in the modules... */ + + char *error_fname; + FILE *error_log; + + /* Module-specific configuration for server, and defaults... */ + + int is_virtual; /* true if this is the virtual server */ + void *module_config; /* Config vector containing pointers to + * modules' per-server config structures. + */ + void *lookup_defaults; /* MIME type info, etc., before we start + * checking per-directory info. + */ + /* Transaction handling */ + + server_addr_rec *addrs; + int timeout; /* Timeout, in seconds, before we give up */ + int keep_alive_timeout; /* Seconds we'll wait for another request */ + int keep_alive_max; /* Maximum requests per connection */ + int keep_alive; /* Use persistent connections? */ + int send_buffer_size; /* size of TCP send buffer (in bytes) */ + + char *path; /* Pathname for ServerPath */ + int pathlen; /* Length of path */ + + char *names; /* Wildcarded names for ServerAlias servers */ + + uid_t server_uid; /* effective user id when calling exec wrapper */ + gid_t server_gid; /* effective group id when calling exec wrapper */ +}; + +/* These are more like real hosts than virtual hosts */ +struct listen_rec { + listen_rec *next; + struct sockaddr_in local_addr; /* local IP address and port */ + int fd; + int used; /* Only used during restart */ +/* more stuff here, like which protocol is bound to the port */ +}; + +/* Prototypes for utilities... util.c. + */ + +/* Time */ +extern const char month_snames[12][4]; + +struct tm *get_gmtoff(int *tz); +char *get_time(); +char *ht_time (pool *p, time_t t, const char *fmt, int gmt); +char *gm_timestr_822(pool *p, time_t t); + +/* String handling. The *_nc variants allow you to use non-const char **s as +arguments (unfortunately C won't automatically convert a char ** to a const +char **) */ + +char *getword(pool *p, const char **line, char stop); +char *getword_nc(pool *p, char **line, char stop); +char *getword_white(pool *p, const char **line); +char *getword_white_nc(pool *p, char **line); +char *getword_nulls (pool *p, const char **line, char stop); +char *getword_nulls_nc (pool *p, char **line, char stop); +char *getword_conf (pool *p, const char **line); +char *getword_conf_nc (pool *p, char **line); + +char *get_token (pool *p, char **accept_line, int accept_white); +int find_token (pool *p, const char *line, const char *tok); +int find_last_token (pool *p, const char *line, const char *tok); + +int is_url(const char *u); +extern int unescape_url(char *url); +void no2slash(char *name); +void getparents(char *name); +char *escape_path_segment(pool *p, const char *s); +char *os_escape_path(pool *p,const char *path,int partial); +#define escape_uri(ppool,path) os_escape_path(ppool,path,1) +extern char *escape_html(pool *p, const char *s); +char *construct_server(pool *p, const char *hostname, unsigned port); +char *construct_url (pool *p, const char *path, const server_rec *s); +char *escape_shell_cmd (pool *p, const char *s); + +int count_dirs(const char *path); +char *make_dirstr(pool *a, const char *s, int n); +char *make_full_path(pool *a, const char *dir, const char *f); + +int is_matchexp(const char *str); +int strcmp_match(const char *str, const char *exp); +int strcasecmp_match(const char *str, const char *exp); +char *uudecode (pool *, const char *); + +char *pregsub(pool *p, const char *input, const char *source, + size_t nmatch, regmatch_t pmatch[]); + +void str_tolower (char *); +int ind (const char *, char); /* Sigh... */ +int rind (const char *, char); + +int cfg_getline(char *s, int n, FILE *f); + +#ifdef NEED_STRERROR +char *strerror (int err); +#endif + +/* Misc system hackery */ + +uid_t uname2id(const char *name); +gid_t gname2id(const char *name); +int is_directory(const char *name); +int can_exec(const struct stat *); +void chdir_file(const char *file); + +char *get_local_host(pool *); +unsigned long get_virthost_addr (const char *hostname, unsigned short *port); + +extern time_t restart_time; diff --git a/APACHE_1_2_X/src/include/md5.h b/APACHE_1_2_X/src/include/md5.h new file mode 100644 index 00000000000..a8ff86c4bd0 --- /dev/null +++ b/APACHE_1_2_X/src/include/md5.h @@ -0,0 +1,99 @@ +/* + * This is work is derived from material Copyright RSA Data Security, Inc. + * + * The RSA copyright statement and Licence for that original material is + * included below. This is followed by the Apache copyright statement and + * licence for the modifications made to that material. + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +/* ==================================================================== + * Copyright (c) 1996,1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + + +/* MD5.H - header file for MD5C.C */ + +/* UINT4 defines a four byte word */ +typedef unsigned int UINT4; + +/* MD5 context. */ +typedef struct { + UINT4 state[4]; /* state (ABCD) */ + UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; + +extern void MD5Init(MD5_CTX *context); +extern void MD5Update(MD5_CTX *context, const unsigned char *input, + unsigned int inputLen); +extern void MD5Final(unsigned char digest[16], MD5_CTX *context); diff --git a/APACHE_1_2_X/src/include/regex.h b/APACHE_1_2_X/src/include/regex.h new file mode 100644 index 00000000000..dde954d8332 --- /dev/null +++ b/APACHE_1_2_X/src/include/regex.h @@ -0,0 +1,73 @@ +#ifndef _REGEX_H_ +#define _REGEX_H_ /* never again */ +/* ========= begin header generated by ./mkh ========= */ +#ifdef __cplusplus +extern "C" { +#endif + +/* === regex2.h === */ +typedef off_t regoff_t; +typedef struct { + int re_magic; + size_t re_nsub; /* number of parenthesized subexpressions */ + const char *re_endp; /* end pointer for REG_PEND */ + struct re_guts *re_g; /* none of your business :-) */ +} regex_t; +typedef struct { + regoff_t rm_so; /* start of match */ + regoff_t rm_eo; /* end of match */ +} regmatch_t; + + +/* === regcomp.c === */ +extern int regcomp(regex_t *, const char *, int); +#define REG_BASIC 0000 +#define REG_EXTENDED 0001 +#define REG_ICASE 0002 +#define REG_NOSUB 0004 +#define REG_NEWLINE 0010 +#define REG_NOSPEC 0020 +#define REG_PEND 0040 +#define REG_DUMP 0200 + + +/* === regerror.c === */ +#define REG_NOMATCH 1 +#define REG_BADPAT 2 +#define REG_ECOLLATE 3 +#define REG_ECTYPE 4 +#define REG_EESCAPE 5 +#define REG_ESUBREG 6 +#define REG_EBRACK 7 +#define REG_EPAREN 8 +#define REG_EBRACE 9 +#define REG_BADBR 10 +#define REG_ERANGE 11 +#define REG_ESPACE 12 +#define REG_BADRPT 13 +#define REG_EMPTY 14 +#define REG_ASSERT 15 +#define REG_INVARG 16 +#define REG_ATOI 255 /* convert name to number (!) */ +#define REG_ITOA 0400 /* convert number to name (!) */ +extern size_t regerror(int, const regex_t *, char *, size_t); + + +/* === regexec.c === */ +extern int regexec(const regex_t *, const char *, size_t, regmatch_t [], int); +#define REG_NOTBOL 00001 +#define REG_NOTEOL 00002 +#define REG_STARTEND 00004 +#define REG_TRACE 00400 /* tracing of execution */ +#define REG_LARGE 01000 /* force large representation */ +#define REG_BACKR 02000 /* force use of backref code */ + + +/* === regfree.c === */ +extern void regfree(regex_t *); + +#ifdef __cplusplus +} +#endif +/* ========= end header generated by ./mkh ========= */ +#endif diff --git a/APACHE_1_2_X/src/include/rfc1413.h b/APACHE_1_2_X/src/include/rfc1413.h new file mode 100644 index 00000000000..91bf42e4aef --- /dev/null +++ b/APACHE_1_2_X/src/include/rfc1413.h @@ -0,0 +1,53 @@ +/* ==================================================================== + * Copyright (c) 1996,1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +extern char *rfc1413(conn_rec *conn, server_rec *srv); diff --git a/APACHE_1_2_X/src/include/scoreboard.h b/APACHE_1_2_X/src/include/scoreboard.h new file mode 100644 index 00000000000..1485a45a9a5 --- /dev/null +++ b/APACHE_1_2_X/src/include/scoreboard.h @@ -0,0 +1,110 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +#include <sys/times.h> + +/* Scoreboard info on a process is, for now, kept very brief --- + * just status value and pid (the latter so that the caretaker process + * can properly update the scoreboard when a process dies). We may want + * to eventually add a separate set of long_score structures which would + * give, for each process, the number of requests serviced, and info on + * the current, or most recent, request. + * + * Status values: + */ + +#define SERVER_UNKNOWN (-1) /* should never be in this state */ +#define SERVER_DEAD 0 +#define SERVER_READY 1 /* Waiting for connection (or accept() lock) */ +#define SERVER_STARTING 3 /* Server Starting up */ +#define SERVER_BUSY_READ 2 /* Reading a client request */ +#define SERVER_BUSY_WRITE 4 /* Processing a client request */ +#define SERVER_BUSY_KEEPALIVE 5 /* Waiting for more requests via keepalive */ +#define SERVER_BUSY_LOG 6 /* Logging the request */ +#define SERVER_BUSY_DNS 7 /* Looking up a hostname */ +#define SERVER_GRACEFUL 8 /* server is gracefully finishing request */ + +typedef struct { + pid_t pid; + char status; +#if defined(STATUS) + unsigned long access_count; + unsigned long bytes_served; + unsigned long my_access_count; + unsigned long my_bytes_served; + unsigned long conn_bytes; + unsigned short conn_count; + struct tms times; + time_t last_used; + char client[32]; /* Keep 'em small... */ + char request[64]; /* We just want an idea... */ + char vhost[32]; /* What virtual host is being accessed? */ +#endif +} short_score; + +typedef struct + { + int exit_generation; /* Set by the main process if a graceful + restart is required */ + } global_score; + +typedef struct + { + short_score servers[HARD_SERVER_LIMIT]; + global_score global; + } scoreboard; + +#define SCOREBOARD_SIZE sizeof(scoreboard) + +extern void sync_scoreboard_image(void); +short_score get_scoreboard_info(int x); + diff --git a/APACHE_1_2_X/src/include/util_date.h b/APACHE_1_2_X/src/include/util_date.h new file mode 100644 index 00000000000..edfd34ad431 --- /dev/null +++ b/APACHE_1_2_X/src/include/util_date.h @@ -0,0 +1,63 @@ +/* ==================================================================== + * Copyright (c) 1996,1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +/* + * util_date.h: prototypes for date parsing utility routines + */ + +#include <time.h> + +#define BAD_DATE (time_t)0 + +int checkmask (const char *data, const char *mask); +time_t tm2sec (const struct tm *t); +time_t parseHTTPdate (const char *date); diff --git a/APACHE_1_2_X/src/include/util_md5.h b/APACHE_1_2_X/src/include/util_md5.h new file mode 100644 index 00000000000..63e2c37cd2b --- /dev/null +++ b/APACHE_1_2_X/src/include/util_md5.h @@ -0,0 +1,58 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +#include "md5.h" + +char *md5(pool *a, unsigned char *string); +char *md5contextTo64(pool *p, MD5_CTX *context); +char *md5digest(pool *p, FILE *infile); + diff --git a/APACHE_1_2_X/src/include/util_script.h b/APACHE_1_2_X/src/include/util_script.h new file mode 100644 index 00000000000..28258767781 --- /dev/null +++ b/APACHE_1_2_X/src/include/util_script.h @@ -0,0 +1,69 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +#ifndef APACHE_ARG_MAX +#ifdef _POSIX_ARG_MAX +#define APACHE_ARG_MAX _POSIX_ARG_MAX +#else +#define APACHE_ARG_MAX 512 +#endif +#endif + +char **create_environment(pool *p, table *t); +int find_path_info(char *uri, char *path_info); +void add_cgi_vars(request_rec *r); +void add_common_vars(request_rec *r); +#define scan_script_header(a1,a2) scan_script_header_err(a1,a2,NULL) +int scan_script_header_err(request_rec *r, FILE *f, char *buffer); +void send_size(size_t size, request_rec *r); +void call_exec (request_rec *r, char *argv0, char **env, int shellcmd); + diff --git a/APACHE_1_2_X/src/main/alloc.c b/APACHE_1_2_X/src/main/alloc.c new file mode 100644 index 00000000000..2557c079caf --- /dev/null +++ b/APACHE_1_2_X/src/main/alloc.c @@ -0,0 +1,1130 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + + +/* + * Resource allocation code... the code here is responsible for making + * sure that nothing leaks. + * + * rst --- 4/95 --- 6/95 + */ + +#include "conf.h" +#include "alloc.h" + +#include <stdarg.h> + +/***************************************************************** + * + * Managing free storage blocks... + */ + +union align +{ + /* Types which are likely to have the longest RELEVANT alignment + * restrictions... + */ + + char *cp; + void (*f)(); + long l; + FILE *fp; + double d; +}; + +#define CLICK_SZ (sizeof(union align)) + +union block_hdr +{ + union align a; + + /* Actual header... */ + + struct { + char *endp; + union block_hdr *next; + char *first_avail; + } h; +}; + +union block_hdr *block_freelist = NULL; + + + +/* Get a completely new block from the system pool. Note that we rely on +malloc() to provide aligned memory. */ + +union block_hdr *malloc_block (int size) +{ + union block_hdr *blok = + (union block_hdr *)malloc(size + sizeof(union block_hdr)); + + if (blok == NULL) { + fprintf (stderr, "Ouch! malloc failed in malloc_block()\n"); + exit (1); + } + blok->h.next = NULL; + blok->h.first_avail = (char *)(blok + 1); + blok->h.endp = size + blok->h.first_avail; + + return blok; +} + + + +void chk_on_blk_list (union block_hdr *blok, union block_hdr *free_blk) +{ + /* Debugging code. Left in for the moment. */ + + while (free_blk) { + if (free_blk == blok) { + fprintf (stderr, "Ouch! Freeing free block\n"); + exit (1); + } + free_blk = free_blk->h.next; + } +} + +/* Free a chain of blocks --- must be called with alarms blocked. */ + +void free_blocks (union block_hdr *blok) +{ + /* First, put new blocks at the head of the free list --- + * we'll eventually bash the 'next' pointer of the last block + * in the chain to point to the free blocks we already had. + */ + + union block_hdr *old_free_list = block_freelist; + + if (blok == NULL) return; /* Sanity check --- freeing empty pool? */ + + block_freelist = blok; + + /* + * Next, adjust first_avail pointers of each block --- have to do it + * sooner or later, and it simplifies the search in new_block to do it + * now. + */ + + while (blok->h.next != NULL) { + chk_on_blk_list (blok, old_free_list); + blok->h.first_avail = (char *)(blok + 1); + blok = blok->h.next; + } + + chk_on_blk_list (blok, old_free_list); + blok->h.first_avail = (char *)(blok + 1); + + /* Finally, reset next pointer to get the old free blocks back */ + + blok->h.next = old_free_list; +} + + + + +/* Get a new block, from our own free list if possible, from the system + * if necessary. Must be called with alarms blocked. + */ + +union block_hdr *new_block (int min_size) +{ + union block_hdr **lastptr = &block_freelist; + union block_hdr *blok = block_freelist; + + /* First, see if we have anything of the required size + * on the free list... + */ + + while (blok != NULL) { + if (min_size + BLOCK_MINFREE <= blok->h.endp - blok->h.first_avail) { + *lastptr = blok->h.next; + blok->h.next = NULL; + return blok; + } + else { + lastptr = &blok->h.next; + blok = blok->h.next; + } + } + + /* Nope. */ + + min_size += BLOCK_MINFREE; + return malloc_block((min_size > BLOCK_MINALLOC) ? min_size : BLOCK_MINALLOC); +} + + + +/* Accounting */ + +long bytes_in_block_list (union block_hdr *blok) +{ + long size = 0; + + while (blok) { + size += blok->h.endp - (char *)(blok + 1); + blok = blok->h.next; + } + + return size; +} + + +/***************************************************************** + * + * Pool internals and management... + * NB that subprocesses are not handled by the generic cleanup code, + * basically because we don't want cleanups for multiple subprocesses + * to result in multiple three-second pauses. + */ + +struct process_chain; +struct cleanup; + +static void run_cleanups (struct cleanup *); +static void free_proc_chain (struct process_chain *); + +struct pool { + union block_hdr *first; + union block_hdr *last; + struct cleanup *cleanups; + struct process_chain *subprocesses; + struct pool *sub_pools; + struct pool *sub_next; + struct pool *sub_prev; + struct pool *parent; + char *free_first_avail; +}; + +pool *permanent_pool; + +/* Each pool structure is allocated in the start of its own first block, + * so we need to know how many bytes that is (once properly aligned...). + * This also means that when a pool's sub-pool is destroyed, the storage + * associated with it is *completely* gone, so we have to make sure it + * gets taken off the parent's sub-pool list... + */ + +#define POOL_HDR_CLICKS (1 + ((sizeof(struct pool) - 1) / CLICK_SZ)) +#define POOL_HDR_BYTES (POOL_HDR_CLICKS * CLICK_SZ) + +struct pool *make_sub_pool (struct pool *p) +{ + union block_hdr *blok; + pool *new_pool; + + block_alarms(); + + blok = new_block (0); + new_pool = (pool *)blok->h.first_avail; + blok->h.first_avail += POOL_HDR_BYTES; + + memset ((char *)new_pool, '\0', sizeof (struct pool)); + new_pool->free_first_avail = blok->h.first_avail; + new_pool->first = new_pool->last = blok; + + if (p) { + new_pool->parent = p; + new_pool->sub_next = p->sub_pools; + if (new_pool->sub_next) new_pool->sub_next->sub_prev = new_pool; + p->sub_pools = new_pool; + } + + unblock_alarms(); + + return new_pool; +} + +void init_alloc() { permanent_pool = make_sub_pool (NULL); } + +void clear_pool (struct pool *a) +{ + block_alarms(); + + while (a->sub_pools) + destroy_pool (a->sub_pools); + + a->sub_pools = NULL; + + run_cleanups (a->cleanups); a->cleanups = NULL; + free_proc_chain (a->subprocesses); a->subprocesses = NULL; + free_blocks (a->first->h.next); a->first->h.next = NULL; + + a->last = a->first; + a->first->h.first_avail = a->free_first_avail; + + unblock_alarms(); +} + +void destroy_pool (pool *a) +{ + block_alarms(); + clear_pool (a); + + if (a->parent) { + if (a->parent->sub_pools == a) a->parent->sub_pools = a->sub_next; + if (a->sub_prev) a->sub_prev->sub_next = a->sub_next; + if (a->sub_next) a->sub_next->sub_prev = a->sub_prev; + } + + free_blocks (a->first); + unblock_alarms(); +} + +long bytes_in_pool (pool *p) { return bytes_in_block_list (p->first); } +long bytes_in_free_blocks () { return bytes_in_block_list (block_freelist); } + +/***************************************************************** + * + * Allocating stuff... + */ + + +void *palloc (struct pool *a, int reqsize) +{ + /* Round up requested size to an even number of alignment units (core clicks) + */ + + int nclicks = 1 + ((reqsize - 1) / CLICK_SZ); + int size = nclicks * CLICK_SZ; + + /* First, see if we have space in the block most recently + * allocated to this pool + */ + + union block_hdr *blok = a->last; + char *first_avail = blok->h.first_avail; + char *new_first_avail; + + if(reqsize <= 0) + return NULL; + + new_first_avail = first_avail + size; + + if (new_first_avail <= blok->h.endp) { + blok->h.first_avail = new_first_avail; + return (void *)first_avail; + } + + /* Nope --- get a new one that's guaranteed to be big enough */ + + block_alarms(); + blok = new_block (size); + a->last->h.next = blok; + a->last = blok; + unblock_alarms(); + + first_avail = blok->h.first_avail; + blok->h.first_avail += size; + + return (void *)first_avail; +} + +void *pcalloc(struct pool *a, int size) +{ + void *res = palloc (a, size); + memset (res, '\0', size); + return res; +} + +char *pstrdup(struct pool *a, const char *s) +{ + char *res; + if (s == NULL) return NULL; + res = palloc (a, strlen(s) + 1); + strcpy (res, s); + return res; +} + +char *pstrndup(struct pool *a, const char *s, int n) +{ + char *res; + if (s == NULL) return NULL; + res = palloc (a, n + 1); + strncpy (res, s, n); + res[n] = '\0'; + return res; +} + +char *pstrcat(pool *a, ...) +{ + char *cp, *argp, *res; + + /* Pass one --- find length of required string */ + + int len = 0; + va_list adummy; + + va_start (adummy, a); + + while ((cp = va_arg (adummy, char *)) != NULL) + len += strlen(cp); + + va_end (adummy); + + /* Allocate the required string */ + + res = (char *)palloc(a, len + 1); + cp = res; + + /* Pass two --- copy the argument strings into the result space */ + + va_start (adummy, a); + + while ((argp = va_arg (adummy, char *)) != NULL) { + strcpy (cp, argp); + cp += strlen(argp); + } + + va_end (adummy); + + /* Return the result string */ + + return res; +} + + +/***************************************************************** + * + * The 'array' functions... + */ + +array_header *make_array (pool *p, int nelts, int elt_size) +{ + array_header *res = (array_header *)palloc(p, sizeof(array_header)); + + if (nelts < 1) nelts = 1; /* Assure sanity if someone asks for + * array of zero elts. + */ + + res->elts = pcalloc (p, nelts * elt_size); + + res->pool = p; + res->elt_size = elt_size; + res->nelts = 0; /* No active elements yet... */ + res->nalloc = nelts; /* ...but this many allocated */ + + return res; +} + +void *push_array (array_header *arr) +{ + if (arr->nelts == arr->nalloc) { + int new_size = (arr->nalloc <= 0) ? 1 : arr->nalloc * 2; + char *new_data; + + new_data = pcalloc (arr->pool, arr->elt_size * new_size); + + memcpy (new_data, arr->elts, arr->nalloc * arr->elt_size); + arr->elts = new_data; + arr->nalloc = new_size; + } + + ++arr->nelts; + return arr->elts + (arr->elt_size * (arr->nelts - 1)); +} + +void array_cat (array_header *dst, const array_header *src) +{ + int elt_size = dst->elt_size; + + if (dst->nelts + src->nelts > dst->nalloc) { + int new_size = (dst->nalloc <= 0) ? 1 : dst->nalloc * 2; + char *new_data; + + while (dst->nelts + src->nelts > new_size) + new_size *= 2; + + new_data = pcalloc (dst->pool, elt_size * new_size); + memcpy (new_data, dst->elts, dst->nalloc * elt_size); + + dst->elts = new_data; + dst->nalloc = new_size; + } + + memcpy (dst->elts + dst->nelts * elt_size, src->elts, elt_size * src->nelts); + dst->nelts += src->nelts; +} + +array_header *copy_array (pool *p, const array_header *arr) +{ + array_header *res = make_array (p, arr->nalloc, arr->elt_size); + + memcpy (res->elts, arr->elts, arr->elt_size * arr->nelts); + res->nelts = arr->nelts; + return res; +} + +/* This cute function copies the array header *only*, but arranges + * for the data section to be copied on the first push or arraycat. + * It's useful when the elements of the array being copied are + * read only, but new stuff *might* get added on the end; we have the + * overhead of the full copy only where it is really needed. + */ + +array_header *copy_array_hdr (pool *p, const array_header *arr) +{ + array_header *res = (array_header *)palloc(p, sizeof(array_header)); + + res->elts = arr->elts; + + res->pool = p; + res->elt_size = arr->elt_size; + res->nelts = arr->nelts; + res->nalloc = arr->nelts; /* Force overflow on push */ + + return res; +} + +/* The above is used here to avoid consing multiple new array bodies... */ + +array_header *append_arrays (pool *p, + const array_header *first, + const array_header *second) +{ + array_header *res = copy_array_hdr (p, first); + + array_cat (res, second); + return res; +} + + +/***************************************************************** + * + * The "table" functions. + */ + +table *make_table (pool *p, int nelts) { + return make_array (p, nelts, sizeof (table_entry)); +} + +table *copy_table (pool *p, const table *t) { + return copy_array (p, t); +} + +void clear_table (table *t) +{ + t->nelts = 0; +} + +array_header *table_elts (table *t) { return t; } + +char *table_get (const table *t, const char *key) +{ + table_entry *elts = (table_entry *)t->elts; + int i; + + if (key == NULL) return NULL; + + for (i = 0; i < t->nelts; ++i) + if (!strcasecmp (elts[i].key, key)) + return elts[i].val; + + return NULL; +} + +void table_set (table *t, const char *key, const char *val) +{ + register int i, j, k; + table_entry *elts = (table_entry *)t->elts; + int done = 0; + + for (i = 0; i < t->nelts; ++i) + if (!strcasecmp (elts[i].key, key)) { + if (!done) { + elts[i].val = pstrdup(t->pool, val); + done = 1; + } + else { /* delete an extraneous element */ + for (j = i, k = i + 1; k < t->nelts; ++j, ++k) { + elts[j].key = elts[k].key; + elts[j].val = elts[k].val; + } + --t->nelts; + } + } + + if (!done) { + elts = (table_entry *)push_array(t); + elts->key = pstrdup (t->pool, key); + elts->val = pstrdup (t->pool, val); + } +} + +void table_unset( table *t, const char *key ) +{ + register int i, j, k; + table_entry *elts = (table_entry *)t->elts; + + for (i = 0; i < t->nelts; ++i) + if (!strcasecmp (elts[i].key, key)) { + + /* found an element to skip over + * there are any number of ways to remove an element from + * a contiguous block of memory. I've chosen one that + * doesn't do a memcpy/bcopy/array_delete, *shrug*... + */ + for (j = i, k = i + 1; k < t->nelts; ++j, ++k) { + elts[j].key = elts[k].key; + elts[j].val = elts[k].val; + } + --t->nelts; + } +} + +void table_merge (table *t, const char *key, const char *val) +{ + table_entry *elts = (table_entry *)t->elts; + int i; + + for (i = 0; i < t->nelts; ++i) + if (!strcasecmp (elts[i].key, key)) { + elts[i].val = pstrcat (t->pool, elts[i].val, ", ", val, NULL); + return; + } + + elts = (table_entry *)push_array(t); + elts->key = pstrdup (t->pool, key); + elts->val = pstrdup (t->pool, val); +} + +void table_add (table *t, const char *key, const char *val) +{ + table_entry *elts = (table_entry *)t->elts; + + elts = (table_entry *)push_array(t); + elts->key = pstrdup (t->pool, key); + elts->val = pstrdup (t->pool, val); +} + +table* overlay_tables (pool *p, const table *overlay, const table *base) +{ + return append_arrays (p, overlay, base); +} + +/* And now for something completely abstract ... + * + * For each key value given as a vararg: + * run the function pointed to as + * int comp(void *r, char *key, char *value); + * on each valid key-value pair in the table t that matches the vararg key, + * or once for every valid key-value pair if the vararg list is empty, + * until the function returns false (0) or we finish the table. + * + * Note that we restart the traversal for each vararg, which means that + * duplicate varargs will result in multiple executions of the function + * for each matching key. Note also that if the vararg list is empty, + * only one traversal will be made and will cut short if comp returns 0. + * + * Note that the table_get and table_merge functions assume that each key in + * the table is unique (i.e., no multiple entries with the same key). This + * function does not make that assumption, since it (unfortunately) isn't + * true for some of Apache's tables. + * + * Note that rec is simply passed-on to the comp function, so that the + * caller can pass additional info for the task. + */ +void table_do (int (*comp)(void *, const char *, const char *), void *rec, + const table *t, ...) +{ + va_list vp; + char *argp; + table_entry *elts = (table_entry *)t->elts; + int rv, i; + + va_start(vp, t); + + argp = va_arg(vp, char *); + + do { + for (rv = 1, i = 0; rv && (i < t->nelts); ++i) { + if (elts[i].key && (!argp || !strcasecmp(elts[i].key, argp))) { + rv = (*comp)(rec, elts[i].key, elts[i].val); + } + } + } while (argp && ((argp = va_arg(vp, char *)) != NULL)); + + va_end(vp); +} + +/***************************************************************** + * + * Managing generic cleanups. + */ + +struct cleanup { + void *data; + void (*plain_cleanup)(void *); + void (*child_cleanup)(void *); + struct cleanup *next; +}; + +void register_cleanup (pool *p, void *data, void (*plain_cleanup)(void *), + void (*child_cleanup)(void *)) +{ + struct cleanup *c = (struct cleanup *)palloc(p, sizeof (struct cleanup)); + c->data = data; + c->plain_cleanup = plain_cleanup; + c->child_cleanup = child_cleanup; + c->next = p->cleanups; + p->cleanups = c; +} + +void kill_cleanup (pool *p, void *data, void (*cleanup)(void *)) +{ + struct cleanup *c = p->cleanups; + struct cleanup **lastp = &p->cleanups; + + while (c) { + if (c->data == data && c->plain_cleanup == cleanup) { + *lastp = c->next; + break; + } + + lastp = &c->next; + c = c->next; + } +} + +void run_cleanup (pool *p, void *data, void (*cleanup)(void *)) +{ + block_alarms(); /* Run cleanup only once! */ + (*cleanup)(data); + kill_cleanup (p, data, cleanup); + unblock_alarms(); +} + +static void run_cleanups (struct cleanup *c) +{ + while (c) { + (*c->plain_cleanup)(c->data); + c = c->next; + } +} + +static void run_child_cleanups (struct cleanup *c) +{ + while (c) { + (*c->child_cleanup)(c->data); + c = c->next; + } +} + +static void cleanup_pool_for_exec (pool *p) +{ + run_child_cleanups (p->cleanups); + p->cleanups = NULL; + + for (p = p->sub_pools; p; p = p->sub_next) + cleanup_pool_for_exec (p); +} + +void cleanup_for_exec() +{ + block_alarms(); + cleanup_pool_for_exec (permanent_pool); + unblock_alarms(); +} + +/***************************************************************** + * + * Files and file descriptors; these are just an application of the + * generic cleanup interface. + */ + +static void fd_cleanup (void *fdv) { close ((int)fdv); } + +void note_cleanups_for_fd (pool *p, int fd) { + register_cleanup (p, (void *)fd, fd_cleanup, fd_cleanup); +} + +void kill_cleanups_for_fd(pool *p,int fd) + { + kill_cleanup(p,(void *)fd,fd_cleanup); + } + +int popenf(pool *a, const char *name, int flg, int mode) +{ + int fd; + int save_errno; + + block_alarms(); + fd = open(name, flg, mode); + save_errno = errno; + if (fd >= 0) note_cleanups_for_fd (a, fd); + unblock_alarms(); + errno = save_errno; + return fd; +} + +int pclosef(pool *a, int fd) +{ + int res; + int save_errno; + + block_alarms(); + res = close(fd); + save_errno = errno; + kill_cleanup(a, (void *)fd, fd_cleanup); + unblock_alarms(); + errno = save_errno; + return res; +} + +/* Note that we have separate plain_ and child_ cleanups for FILE *s, + * since fclose() would flush I/O buffers, which is extremely undesirable; + * we just close the descriptor. + */ + +static void file_cleanup (void *fpv) { fclose ((FILE *)fpv); } +static void file_child_cleanup (void *fpv) { close (fileno ((FILE *)fpv)); } + +void note_cleanups_for_file (pool *p, FILE *fp) { + register_cleanup (p, (void *)fp, file_cleanup, file_child_cleanup); +} + +FILE *pfopen(pool *a, const char *name, const char *mode) +{ + FILE *fd = NULL; + int baseFlag, desc; + + block_alarms(); + + if (*mode == 'a') { + /* Work around faulty implementations of fopen */ + baseFlag = (*(mode+1) == '+') ? O_RDWR : O_WRONLY; + desc = open(name, baseFlag | O_APPEND | O_CREAT, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + if (desc >= 0) { + fd = fdopen(desc, mode); + } + } else { + fd = fopen(name, mode); + } + + if (fd != NULL) note_cleanups_for_file (a, fd); + unblock_alarms(); + return fd; +} + +FILE *pfdopen(pool *a,int fd, const char *mode) +{ + FILE *f; + + block_alarms(); + f=fdopen(fd,mode); + if(f != NULL) + note_cleanups_for_file(a,f); + unblock_alarms(); + return f; +} + + +int pfclose(pool *a, FILE *fd) +{ + int res; + + block_alarms(); + res = fclose(fd); + kill_cleanup(a, (void *)fd, file_cleanup); + unblock_alarms(); + return res; +} + +/* + * Here's a pool-based interface to POSIX regex's regcomp(). + * Note that we return regex_t instead of being passed one. + * The reason is that if you use an already-used regex_t structure, + * the memory that you've already allocated gets forgotten, and + * regfree() doesn't clear it. So we don't allow it. + */ + +static void regex_cleanup (void *preg) { regfree ((regex_t *)preg); } + +regex_t *pregcomp(pool *p, const char *pattern, int cflags) { + regex_t *preg = palloc(p, sizeof(regex_t)); + + if (regcomp(preg, pattern, cflags)) + return NULL; + + register_cleanup (p, (void *)preg, regex_cleanup, regex_cleanup); + + return preg; +} + + +void pregfree(pool *p, regex_t *reg) +{ + block_alarms(); + regfree (reg); + kill_cleanup (p, (void *)reg, regex_cleanup); + unblock_alarms(); +} + +/***************************************************************** + * + * More grotty system stuff... subprocesses. Frump. These don't use + * the generic cleanup interface because I don't want multiple + * subprocesses to result in multiple three-second pauses; the + * subprocesses have to be "freed" all at once. If someone comes + * along with another resource they want to allocate which has the + * same property, we might want to fold support for that into the + * generic interface, but for now, it's a special case + */ + +struct process_chain { + pid_t pid; + enum kill_conditions kill_how; + struct process_chain *next; +}; + +void note_subprocess (pool *a, int pid, enum kill_conditions how) +{ + struct process_chain *new = + (struct process_chain *)palloc(a, sizeof(struct process_chain)); + + new->pid = pid; + new->kill_how = how; + new->next = a->subprocesses; + a->subprocesses = new; +} + +int spawn_child_err (pool *p, void (*func)(void *), void *data, + enum kill_conditions kill_how, + FILE **pipe_in, FILE **pipe_out, FILE **pipe_err) +{ + int pid; + int in_fds[2]; + int out_fds[2]; + int err_fds[2]; + int save_errno; + + block_alarms(); + + if (pipe_in && pipe (in_fds) < 0) + { + save_errno = errno; + unblock_alarms(); + errno = save_errno; + return 0; + } + + if (pipe_out && pipe (out_fds) < 0) { + save_errno = errno; + if (pipe_in) { + close (in_fds[0]); close (in_fds[1]); + } + unblock_alarms(); + errno = save_errno; + return 0; + } + + if (pipe_err && pipe (err_fds) < 0) { + save_errno = errno; + if (pipe_in) { + close (in_fds[0]); close (in_fds[1]); + } + if (pipe_out) { + close (out_fds[0]); close (out_fds[1]); + } + unblock_alarms(); + errno = save_errno; + return 0; + } + + if ((pid = fork()) < 0) { + save_errno = errno; + if (pipe_in) { + close (in_fds[0]); close (in_fds[1]); + } + if (pipe_out) { + close (out_fds[0]); close (out_fds[1]); + } + if (pipe_err) { + close (err_fds[0]); close (err_fds[1]); + } + unblock_alarms(); + errno = save_errno; + return 0; + } + + if (!pid) { + /* Child process */ + + if (pipe_out) { + close (out_fds[0]); + dup2 (out_fds[1], STDOUT_FILENO); + close (out_fds[1]); + } + + if (pipe_in) { + close (in_fds[1]); + dup2 (in_fds[0], STDIN_FILENO); + close (in_fds[0]); + } + + if (pipe_err) { + close (err_fds[0]); + dup2 (err_fds[1], STDERR_FILENO); + close (err_fds[1]); + } + + /* HP-UX SIGCHLD fix goes here, if someone will remind me what it is... */ + signal (SIGCHLD, SIG_DFL); /* Was that it? */ + + func (data); + exit (0); /* Should never get here... */ + } + + /* Parent process */ + + note_subprocess (p, pid, kill_how); + + if (pipe_out) { + close (out_fds[1]); +#ifdef __EMX__ + /* Need binary mode set for OS/2. */ + *pipe_out = fdopen (out_fds[0], "rb"); +#else + *pipe_out = fdopen (out_fds[0], "r"); +#endif + + if (*pipe_out) note_cleanups_for_file (p, *pipe_out); + } + + if (pipe_in) { + close (in_fds[0]); +#ifdef __EMX__ + /* Need binary mode set for OS/2 */ + *pipe_in = fdopen (in_fds[1], "wb"); +#else + *pipe_in = fdopen (in_fds[1], "w"); +#endif + + if (*pipe_in) note_cleanups_for_file (p, *pipe_in); + } + + if (pipe_err) { + close (err_fds[1]); +#ifdef __EMX__ + /* Need binary mode set for OS/2. */ + *pipe_err = fdopen (err_fds[0], "rb"); +#else + *pipe_err = fdopen (err_fds[0], "r"); +#endif + + if (*pipe_err) note_cleanups_for_file (p, *pipe_err); + } + + unblock_alarms(); + return pid; +} + +static void free_proc_chain (struct process_chain *procs) +{ + /* Dispose of the subprocesses we've spawned off in the course of + * whatever it was we're cleaning up now. This may involve killing + * some of them off... + */ + + struct process_chain *p; + int need_timeout = 0; + int status; + + if (procs == NULL) return; /* No work. Whew! */ + + /* First, check to see if we need to do the SIGTERM, sleep, SIGKILL + * dance with any of the processes we're cleaning up. If we've got + * any kill-on-sight subprocesses, ditch them now as well, so they + * don't waste any more cycles doing whatever it is that they shouldn't + * be doing anymore. + */ + +#ifndef NEED_WAITPID + /* Pick up all defunct processes */ + for (p = procs; p; p = p->next) { + if (waitpid (p->pid, (int *) 0, WNOHANG) > 0) { + p->kill_how = kill_never; + } + } +#endif + + for (p = procs; p; p = p->next) { + if (p->kill_how == kill_after_timeout) { + /* Subprocess may be dead already. Only need the timeout if not. */ + if (kill (p->pid, SIGTERM) != -1) + need_timeout = 1; + } else if (p->kill_how == kill_always) { + kill (p->pid, SIGKILL); + } + } + + /* Sleep only if we have to... */ + + if (need_timeout) sleep (3); + + /* OK, the scripts we just timed out for have had a chance to clean up + * --- now, just get rid of them, and also clean up the system accounting + * goop... + */ + + for (p = procs; p; p = p->next){ + + if (p->kill_how == kill_after_timeout) + kill (p->pid, SIGKILL); + + if (p->kill_how != kill_never) + waitpid (p->pid, &status, 0); + } +} + diff --git a/APACHE_1_2_X/src/main/buff.c b/APACHE_1_2_X/src/main/buff.c new file mode 100644 index 00000000000..97c000272d6 --- /dev/null +++ b/APACHE_1_2_X/src/main/buff.c @@ -0,0 +1,975 @@ +/* ==================================================================== + * Copyright (c) 1996,1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +#include "conf.h" +#include "alloc.h" +#include "buff.h" + +#include <errno.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#ifndef NO_UNISTD_H +#include <unistd.h> +#endif +#ifndef NO_WRITEV +#include <sys/types.h> +#include <sys/uio.h> +#endif + +#ifdef HAVE_BSTRING_H +#include <bstring.h> /* for IRIX, FD_SET calls bzero() */ +#endif + +#define DEFAULT_BUFSIZE (4096) + +/* + * Buffered I/O routines. + * These are a replacement for the stdio routines. + * Advantages: + * Known semantics for handling of file-descriptors (on close etc.) + * No problems reading and writing simultanously to the same descriptor + * No limits on the number of open file handles. + * Only uses memory resources; no need to ensure the close routine + * is called. + * Extra code could be inserted between the buffered and un-buffered routines. + * Timeouts could be handled by using select or poll before read or write. + * Extra error handling could be introduced; e.g. + * keep an address to which we should longjump(), or + * keep a stack of routines to call on error. + */ + +/* Notes: + * On reading EOF, EOF will set in the flags and no further Input will + * be done. + * + * On an error except for EAGAIN, ERROR will be set in the flags and no + * futher I/O will be done + */ + +static void +doerror(BUFF *fb, int err) +{ + int errsave = errno; /* Save errno to prevent overwriting it below */ + + if (err == B_RD) + fb->flags |= B_RDERR; + else + fb->flags |= B_WRERR; + if (fb->error != NULL) (*fb->error)(fb, err, fb->error_data); + + errno = errsave; +} + +/* Buffering routines */ +/* + * Create a new buffered stream + */ +BUFF * +bcreate(pool *p, int flags) +{ + BUFF *fb; + + fb = palloc(p, sizeof(BUFF)); + fb->pool=p; + fb->bufsiz = DEFAULT_BUFSIZE; + fb->flags = flags & B_RDWR; + + if (flags & B_RD) fb->inbase = palloc(p, fb->bufsiz); + else fb->inbase = NULL; + + /* overallocate so that we can put a chunk trailer of CRLF into this + * buffer */ + if (flags & B_WR) fb->outbase = palloc(p, fb->bufsiz + 2); + else fb->outbase = NULL; + + fb->inptr = fb->inbase; + + fb->incnt = 0; + fb->outcnt = 0; + fb->outchunk = -1; + fb->error = NULL; + fb->bytes_sent = 0L; + + fb->fd = -1; + fb->fd_in = -1; + + return fb; +} + +/* + * Push some I/O file descriptors onto the stream + */ +void +bpushfd(BUFF *fb, int fd_in, int fd_out) +{ + fb->fd = fd_out; + fb->fd_in = fd_in; +} + +int +bsetopt(BUFF *fb, int optname, const void *optval) +{ + if (optname == BO_BYTECT) + { + fb->bytes_sent = *(const long int *)optval - (long int)fb->outcnt;; + return 0; + } else + { + errno = EINVAL; + return -1; + } +} + +int +bgetopt(BUFF *fb, int optname, void *optval) +{ + if (optname == BO_BYTECT) + { + long int bs=fb->bytes_sent + fb->outcnt; + if (bs < 0L) bs = 0L; + *(long int *)optval = bs; + return 0; + } else + { + errno = EINVAL; + return -1; + } +} + +/* + * start chunked encoding + */ +static void +start_chunk( BUFF *fb ) +{ + char chunksize[16]; /* Big enough for practically anything */ + int chunk_header_size; + + if (fb->outchunk != -1) { + /* already chunking */ + return; + } + if (!(fb->flags & B_WR) || (fb->flags & (B_WRERR|B_EOUT))) { + /* unbuffered writes */ + return; + } + + /* we know that the chunk header is going to take at least 3 bytes... */ + chunk_header_size = ap_snprintf( chunksize, sizeof(chunksize), + "%x\015\012", fb->bufsiz - fb->outcnt - 3 ); + /* we need at least the header_len + at least 1 data byte + * remember that we've overallocated fb->outbase so that we can always + * fit the two byte CRLF trailer + */ + if( fb->bufsiz - fb->outcnt < chunk_header_size + 1 ) { + bflush(fb); + } + /* assume there's enough space now */ + memcpy( &fb->outbase[fb->outcnt], chunksize, chunk_header_size ); + fb->outchunk = fb->outcnt; + fb->outcnt += chunk_header_size; + fb->outchunk_header_size = chunk_header_size; +} + + +/* + * end a chunk -- tweak the chunk_header from start_chunk, and add a trailer + */ +static void +end_chunk( BUFF *fb ) +{ + int i; + + if( fb->outchunk == -1 ) { + /* not chunking */ + return; + } + + if( fb->outchunk + fb->outchunk_header_size == fb->outcnt ) { + /* nothing was written into this chunk, and we can't write a 0 size + * chunk because that signifies EOF, so just erase it + */ + fb->outcnt = fb->outchunk; + fb->outchunk = -1; + return; + } + + /* we know this will fit because of how we wrote it in start_chunk() */ + i = ap_snprintf( (char *)&fb->outbase[fb->outchunk], + fb->outchunk_header_size, + "%x", fb->outcnt - fb->outchunk - fb->outchunk_header_size ); + + /* we may have to tack some trailing spaces onto the number we just wrote + * in case it was smaller than our estimated size. We've also written + * a \0 into the buffer with ap_snprintf so we might have to put a + * \r back in. + */ + i += fb->outchunk; + while( fb->outbase[i] != '\015' && fb->outbase[i] != '\012' ) { + fb->outbase[i++] = ' '; + } + if( fb->outbase[i] == '\012' ) { + /* we overwrote the \r, so put it back */ + fb->outbase[i-1] = '\015'; + } + + /* tack on the trailing CRLF, we've reserved room for this */ + fb->outbase[fb->outcnt++] = '\015'; + fb->outbase[fb->outcnt++] = '\012'; + + fb->outchunk = -1; +} + + +/* + * Set a flag on (1) or off (0). + */ +int bsetflag(BUFF *fb, int flag, int value) +{ + if (value) { + fb->flags |= flag; + if( flag & B_CHUNK ) { + start_chunk(fb); + } + } else { + fb->flags &= ~flag; + if( flag & B_CHUNK ) { + end_chunk(fb); + } + } + return value; +} + + +/* + * This is called instead of read() everywhere in here. It implements + * the B_SAFEREAD functionality -- which is to force a flush() if a read() + * would block. It also deals with the EINTR errno result from read(). + * return code is like read() except EINTR is eliminated. + */ +static int +saferead( BUFF *fb, void *buf, int nbyte ) +{ + int rv; + + if( fb->flags & B_SAFEREAD ) { + fd_set fds; + struct timeval tv; + + /* test for a block */ + do { + FD_ZERO( &fds ); + FD_SET( fb->fd_in, &fds ); + tv.tv_sec = 0; + tv.tv_usec = 0; +#ifdef SELECT_NEEDS_CAST + rv = select( fb->fd_in + 1, (int *)&fds, NULL, NULL, &tv ); +#else + rv = select( fb->fd_in + 1, &fds, NULL, NULL, &tv ); +#endif + } while( rv < 0 && errno == EINTR ); + /* treat any error as if it would block as well */ + if( rv != 1 ) { + bflush(fb); + } + } + do { + rv = read( fb->fd_in, buf, nbyte ); + } while (rv == -1 && errno == EINTR && !(fb->flags & B_EOUT)); + return( rv ); +} + + +/* + * Read up to nbyte bytes into buf. + * If fewer than byte bytes are currently available, then return those. + * Returns 0 for EOF, -1 for error. + */ +int +bread(BUFF *fb, void *buf, int nbyte) +{ + int i, nrd; + + if (fb->flags & B_RDERR) return -1; + if (nbyte == 0) return 0; + + if (!(fb->flags & B_RD)) + { +/* Unbuffered reading */ + i = saferead( fb, buf, nbyte ); + if (i == -1 && errno != EAGAIN) doerror(fb, B_RD); + return i; + } + + nrd = fb->incnt; +/* can we fill the buffer */ + if (nrd >= nbyte) + { + memcpy(buf, fb->inptr, nbyte); + fb->incnt = nrd - nbyte; + fb->inptr += nbyte; + return nbyte; + } + + if (nrd > 0) + { + memcpy(buf, fb->inptr, nrd); + nbyte -= nrd; + buf = nrd + (char *)buf; + fb->incnt = 0; + } + if (fb->flags & B_EOF) return nrd; + +/* do a single read */ + if (nbyte >= fb->bufsiz) + { +/* read directly into buffer */ + i = saferead( fb, buf, nbyte ); + if (i == -1) + { + if (nrd == 0) + { + if (errno != EAGAIN) doerror(fb, B_RD); + return -1; + } + else return nrd; + } else if (i == 0) fb->flags |= B_EOF; + } else + { +/* read into hold buffer, then memcpy */ + fb->inptr = fb->inbase; + i = saferead( fb, fb->inptr, fb->bufsiz ); + if (i == -1) + { + if (nrd == 0) + { + if (errno != EAGAIN) doerror(fb, B_RD); + return -1; + } + else return nrd; + } else if (i == 0) fb->flags |= B_EOF; + fb->incnt = i; + if (i > nbyte) i = nbyte; + memcpy(buf, fb->inptr, i); + fb->incnt -= i; + fb->inptr += i; + } + return nrd + i; +} + + +/* + * Reads from the stream into the array pointed to by buff, until + * a (CR)LF sequence is read, or end-of-file condition is encountered + * or until n-1 bytes have been stored in buff. If a CRLF sequence is + * read, it is replaced by a newline character. The string is then + * terminated with a null character. + * + * Returns the number of bytes stored in buff, or zero on end of + * transmission, or -1 on an error. + * + * Notes: + * If null characters are exepected in the data stream, then + * buff should not be treated as a null terminated C string; instead + * the returned count should be used to determine the length of the + * string. + * CR characters in the byte stream not immediately followed by a LF + * will be preserved. + */ +int +bgets(char *buff, int n, BUFF *fb) +{ + int i, ch, ct; + +/* Can't do bgets on an unbuffered stream */ + if (!(fb->flags & B_RD)) + { + errno = EINVAL; + return -1; + } + if (fb->flags & B_RDERR) return -1; + + ct = 0; + i = 0; + for (;;) + { + if (i == fb->incnt) + { +/* no characters left */ + fb->inptr = fb->inbase; + fb->incnt = 0; + if (fb->flags & B_EOF) break; + i = saferead( fb, fb->inptr, fb->bufsiz ); + if (i == -1) + { + buff[ct] = '\0'; + if (ct == 0) + { + if (errno != EAGAIN) doerror(fb, B_RD); + return -1; + } + else return ct; + } + fb->incnt = i; + if (i == 0) + { + fb->flags |= B_EOF; + break; /* EOF */ + } + i = 0; + continue; /* restart with the new data */ + } + + ch = fb->inptr[i++]; + if (ch == '\012') /* got LF */ + { + if (ct == 0) buff[ct++] = '\n'; +/* if just preceeded by CR, replace CR with LF */ + else if (buff[ct-1] == '\015') buff[ct-1] = '\n'; + else if (ct < n-1) buff[ct++] = '\n'; + else i--; /* no room for LF */ + break; + } + if (ct == n-1) + { + i--; /* push back ch */ + break; + } + + buff[ct++] = ch; + } + fb->incnt -= i; + fb->inptr += i; + + buff[ct] = '\0'; + return ct; +} + +/* + * Looks at the stream fb and places the first character into buff + * without removing it from the stream buffer. + * + * Returns 1 on success, zero on end of transmission, or -1 on an error. + * + */ +int blookc(char *buff, BUFF *fb) +{ + int i; + + *buff = '\0'; + + if (!(fb->flags & B_RD)) { /* Can't do blookc on an unbuffered stream */ + errno = EINVAL; + return -1; + } + if (fb->flags & B_RDERR) return -1; + + if (fb->incnt == 0) { /* no characters left in stream buffer */ + fb->inptr = fb->inbase; + if (fb->flags & B_EOF) + return 0; + + i = saferead( fb, fb->inptr, fb->bufsiz ); + + if (i == -1) { + if (errno != EAGAIN) + doerror(fb, B_RD); + return -1; + } + if (i == 0) { + fb->flags |= B_EOF; + return 0; /* EOF */ + } + else fb->incnt = i; + } + + *buff = fb->inptr[0]; + return 1; +} + +/* + * Skip data until a linefeed character is read + * Returns 1 on success, 0 if no LF found, or -1 on error + */ +int +bskiplf(BUFF *fb) +{ + unsigned char *x; + int i; + +/* Can't do bskiplf on an unbuffered stream */ + if (!(fb->flags & B_RD)) + { + errno = EINVAL; + return -1; + } + if (fb->flags & B_RDERR) return -1; + + for (;;) + { + x = (unsigned char *)memchr(fb->inptr, '\012', fb->incnt); + if (x != NULL) + { + x++; + fb->incnt -= x - fb->inptr; + fb->inptr = x; + return 1; + } + + fb->inptr = fb->inbase; + fb->incnt = 0; + if (fb->flags & B_EOF) return 0; + i = saferead( fb, fb->inptr, fb->bufsiz ); + if (i == 0) fb->flags |= B_EOF; + if (i == -1 && errno != EAGAIN) doerror(fb, B_RD); + if (i == 0 || i == -1) return i; + fb->incnt = i; + } +} + +/* + * Emtpy the buffer after putting a single character in it + */ +int +bflsbuf(int c, BUFF *fb) +{ + char ss[1]; + + ss[0] = c; + return bwrite(fb, ss, 1); +} + +/* + * Fill the buffer and read a character from it + */ +int +bfilbuf(BUFF *fb) +{ + int i; + char buf[1]; + + i = bread(fb, buf, 1); + if (i == 0) errno = 0; /* no error; EOF */ + if (i != 1) return EOF; + else return buf[0]; +} + + +/* + * When doing chunked encodings we really have to write everything in the + * chunk before proceeding onto anything else. This routine either writes + * nbytes and returns 0 or returns -1 indicating a failure. + * + * This is *seriously broken* if used on a non-blocking fd. It will poll. + */ +static int +write_it_all(BUFF *fb, const void *buf, int nbyte) +{ + int i; + + if (fb->flags & (B_WRERR|B_EOUT)) + return -1; + + while (nbyte > 0) { + i = write(fb->fd, buf, nbyte); + if (i < 0) { + if (errno != EAGAIN && errno != EINTR) { + return -1; + } + } + else { + nbyte -= i; + buf = i + (const char *)buf; + } + if (fb->flags & B_EOUT) + return -1; + } + return 0; +} + + +/* + * A hook to write() that deals with chunking. This is really a protocol- + * level issue, but we deal with it here because it's simpler; this is + * an interim solution pending a complete rewrite of all this stuff in + * 2.0, using something like sfio stacked disciplines or BSD's funopen(). + */ +static int +bcwrite(BUFF *fb, const void *buf, int nbyte) +{ + char chunksize[16]; /* Big enough for practically anything */ +#ifndef NO_WRITEV + struct iovec vec[3]; + int i, rv; +#endif + + if (fb->flags & (B_WRERR|B_EOUT)) + return -1; + + if (!(fb->flags & B_CHUNK)) + return write(fb->fd, buf, nbyte); + +#ifdef NO_WRITEV + /* without writev() this has poor performance, too bad */ + + ap_snprintf(chunksize, sizeof(chunksize), "%x\015\012", nbyte); + if (write_it_all(fb, chunksize, strlen(chunksize)) == -1) + return -1; + if (write_it_all(fb, buf, nbyte) == -1) + return -1; + if (write_it_all(fb, "\015\012", 2) == -1) + return -1; + return nbyte; +#else + +#define NVEC (sizeof(vec)/sizeof(vec[0])) + + vec[0].iov_base = chunksize; + vec[0].iov_len = ap_snprintf(chunksize, sizeof(chunksize), "%x\015\012", + nbyte); + vec[1].iov_base = (void *)buf; /* cast is to avoid const warning */ + vec[1].iov_len = nbyte; + vec[2].iov_base = "\r\n"; + vec[2].iov_len = 2; + /* while it's nice an easy to build the vector and crud, it's painful + * to deal with a partial writev() + */ + for( i = 0; i < NVEC; ) { + do rv = writev( fb->fd, &vec[i], NVEC - i ); + while (rv == -1 && errno == EINTR && !(fb->flags & B_EOUT)); + if (rv == -1) + return -1; + /* recalculate vec to deal with partial writes */ + while (rv > 0) { + if( rv <= vec[i].iov_len ) { + vec[i].iov_base = (char *)vec[i].iov_base + rv; + vec[i].iov_len -= rv; + rv = 0; + if( vec[i].iov_len == 0 ) { + ++i; + } + } else { + rv -= vec[i].iov_len; + ++i; + } + } + if (fb->flags & B_EOUT) + return -1; + } + /* if we got here, we wrote it all */ + return nbyte; +#undef NVEC +#endif +} + + +/* + * Write nbyte bytes. + * Only returns fewer than nbyte if an error ocurred. + * Returns -1 if no bytes were written before the error ocurred. + * It is worth noting that if an error occurs, the buffer is in an unknown + * state. + */ +int +bwrite(BUFF *fb, const void *buf, int nbyte) +{ + int i, nwr; + + if (fb->flags & (B_WRERR|B_EOUT)) return -1; + if (nbyte == 0) return 0; + + if (!(fb->flags & B_WR)) + { +/* unbuffered write -- have to use bcwrite since we aren't taking care + * of chunking any other way */ + do i = bcwrite(fb, buf, nbyte); + while (i == -1 && errno == EINTR && !(fb->flags & B_EOUT)); + if (i == 0) { /* return of 0 means non-blocking */ + errno = EAGAIN; + return -1; + } + else if (i < 0) { + if (errno != EAGAIN) + doerror(fb, B_WR); + return -1; + } + fb->bytes_sent += i; + if (fb->flags & B_EOUT) + return -1; + else + return i; + } + +/* + * Whilst there is data in the buffer, keep on adding to it and writing it + * out + */ + nwr = 0; + while (fb->outcnt > 0) + { +/* can we accept some data? */ + i = fb->bufsiz - fb->outcnt; + if (i > 0) + { + if (i > nbyte) i = nbyte; + memcpy(fb->outbase + fb->outcnt, buf, i); + fb->outcnt += i; + nbyte -= i; + buf = i + (const char *)buf; + nwr += i; + if (nbyte == 0) return nwr; /* return if none left */ + } + +/* the buffer must be full */ + if (fb->flags & B_CHUNK) { + end_chunk(fb); + /* it is just too painful to try to re-cram the buffer while + * chunking + */ + i = (write_it_all(fb, fb->outbase, fb->outcnt) == -1) ? + -1 : fb->outcnt; + } + else { + do i = write(fb->fd, fb->outbase, fb->outcnt); + while (i == -1 && errno == EINTR && !(fb->flags & B_EOUT)); + } + if (i <= 0) { + if (i == 0) /* return of 0 means non-blocking */ + errno = EAGAIN; + if (nwr == 0) { + if (errno != EAGAIN) doerror(fb, B_WR); + return -1; + } + else return nwr; + } + fb->bytes_sent += i; + + /* deal with a partial write */ + if (i < fb->outcnt) + { + int j, n=fb->outcnt; + unsigned char *x=fb->outbase; + for (j=i; j < n; j++) x[j-i] = x[j]; + fb->outcnt -= i; + } + else + fb->outcnt = 0; + + if (fb->flags & B_EOUT) + return -1; + } +/* we have emptied the file buffer. Now try to write the data from the + * original buffer until there is less than bufsiz left. Note that we + * use bcwrite() to do this for us, it will do the chunking so that + * we don't have to dink around building a chunk in our own buffer. + */ + while (nbyte >= fb->bufsiz) + { + do i = bcwrite(fb, buf, nbyte); + while (i == -1 && errno == EINTR && !(fb->flags & B_EOUT)); + if (i <= 0) { + if (i == 0) /* return of 0 means non-blocking */ + errno = EAGAIN; + if (nwr == 0) { + if (errno != EAGAIN) doerror(fb, B_WR); + return -1; + } + else return nwr; + } + fb->bytes_sent += i; + + buf = i + (const char *)buf; + nwr += i; + nbyte -= i; + + if (fb->flags & B_EOUT) + return -1; + } +/* copy what's left to the file buffer */ + fb->outcnt = 0; + if( fb->flags & B_CHUNK ) start_chunk( fb ); + if (nbyte > 0) memcpy(fb->outbase + fb->outcnt, buf, nbyte); + fb->outcnt += nbyte; + nwr += nbyte; + return nwr; +} + +/* + * Flushes the buffered stream. + * Returns 0 on success or -1 on error + */ +int +bflush(BUFF *fb) +{ + int i; + + if (!(fb->flags & B_WR) || (fb->flags & B_EOUT)) return 0; + + if (fb->flags & B_WRERR) return -1; + + if (fb->flags & B_CHUNK) end_chunk(fb); + + while (fb->outcnt > 0) + { + /* the buffer must be full */ + do i = write(fb->fd, fb->outbase, fb->outcnt); + while (i == -1 && errno == EINTR && !(fb->flags & B_EOUT)); + if (i == 0) { + errno = EAGAIN; + return -1; /* return of 0 means non-blocking */ + } + else if (i < 0) { + if (errno != EAGAIN) doerror(fb, B_WR); + return -1; + } + fb->bytes_sent += i; + + /* + * We should have written all the data, but if the fd was in a + * strange (non-blocking) mode, then we might not have done so. + */ + if (i < fb->outcnt) + { + int j, n=fb->outcnt; + unsigned char *x=fb->outbase; + for (j=i; j < n; j++) x[j-i] = x[j]; + } + fb->outcnt -= i; + + /* If a soft timeout occurs while flushing, the handler should + * have set the buffer flag B_EOUT. + */ + if (fb->flags & B_EOUT) + return -1; + } + return 0; +} + +/* + * Flushes and closes the file, even if an error occurred. + * Discards an data that was not read, or not written by bflush() + * Sets the EOF flag to indicate no futher data can be read, + * and the EOUT flag to indicate no further data can be written. + */ +int +bclose(BUFF *fb) +{ + int rc1, rc2, rc3; + + if (fb->flags & B_WR) rc1 = bflush(fb); + else rc1 = 0; + rc2 = close(fb->fd); + if (fb->fd_in != fb->fd) rc3 = close(fb->fd_in); + else rc3 = 0; + + fb->inptr = fb->inbase; + fb->incnt = 0; + fb->outcnt = 0; + + fb->flags |= B_EOF | B_EOUT; + fb->fd = -1; + fb->fd_in = -1; + + if (rc1 != 0) return rc1; + else if (rc2 != 0) return rc2; + else return rc3; +} + +/* + * returns the number of bytes written or -1 on error + */ +int +bputs(const char *x, BUFF *fb) +{ + int i, j=strlen(x); + i = bwrite(fb, x, j); + if (i != j) return -1; + else return j; +} + +/* + * returns the number of bytes written or -1 on error + */ +int +bvputs(BUFF *fb, ...) +{ + int i, j, k; + va_list v; + const char *x; + + va_start(v, fb); + for (k=0;;) + { + x = va_arg(v, const char *); + if (x == NULL) break; + j = strlen(x); + i = bwrite(fb, x, j); + if (i != j) + { + va_end(v); + return -1; + } + k += i; + } + + va_end(v); + + return k; +} + +void +bonerror(BUFF *fb, void (*error)(BUFF *, int, void *), void *data) +{ + fb->error = error; + fb->error_data = data; +} diff --git a/APACHE_1_2_X/src/main/explain.c b/APACHE_1_2_X/src/main/explain.c new file mode 100644 index 00000000000..6490c940522 --- /dev/null +++ b/APACHE_1_2_X/src/main/explain.c @@ -0,0 +1,14 @@ +#include <stdio.h> +#include <stdarg.h> +#include "explain.h" + +void _Explain(const char *szFile,int nLine,const char *szFmt,...) + { + va_list vlist; + + fprintf(stderr,"%s(%d): ",szFile,nLine); + va_start(vlist,szFmt); + vfprintf(stderr,szFmt,vlist); + va_end(vlist); + fputc('\n',stderr); + } diff --git a/APACHE_1_2_X/src/main/http_bprintf.c b/APACHE_1_2_X/src/main/http_bprintf.c new file mode 100644 index 00000000000..712af066883 --- /dev/null +++ b/APACHE_1_2_X/src/main/http_bprintf.c @@ -0,0 +1,599 @@ +/* + * printf() style routines stolen from FastCGI + * Copyright (c) 1996 Open Market, Inc. + */ + +/* + * Modified to work with Apache buffering routines by Ben Laurie + * <ben@algroup.co.uk>. + * + * Modifications Copyright (C) 1996 Ben Laurie. + * + * History: + * 18 May 1996 Initial revision [Ben Laurie] + * + */ + +#include <assert.h> +#include <math.h> +#include "conf.h" +#include "alloc.h" +#include "buff.h" + +#if !defined(max) +#define max(a,b) (a > b ? a : b) +#endif + +#ifdef NO_LONG_DOUBLE +#define LONG_DOUBLE double +#else +#define LONG_DOUBLE long double +#endif + +#define FALSE 0 +#define TRUE 1 + +#define PRINTF_BUFFLEN 100 + /* + * More than sufficient space for all unmodified conversions + * except %s and %f. + */ +#define FMT_BUFFLEN 25 + /* + * Max size of a format specifier is 1 + 5 + 7 + 7 + 2 + 1 + slop + */ +#define NULL_STRING "(null)" + /* + * String displayed if given a NULL pointer. + */ + +/* + * Copy n characters from *srcPtr to *destPtr, then increment + * both *srcPtr and *destPtr by n. + */ +static void CopyAndAdvance(char **destPtr, const char **srcPtr, int n) + { + char *dest = *destPtr; + const char *src = *srcPtr; + int i; + + for (i = 0; i < n; i++) + *dest++ = *src++; + *destPtr = dest; + *srcPtr = src; + } + +int vbprintf(BUFF *bp, const char *format, va_list arg) + { + const char *f,*fStop,*percentPtr,*p; + char *fmtBuffPtr, *buffPtr; + int op, performedOp, sizeModifier, buffLen, specifierLength; + int fastPath, n, buffReqd, minWidth, precision, exp; + int buffCount = 0; + int auxBuffLen = 0; + char *auxBuffPtr = NULL; + int streamCount = 0; + char fmtBuff[FMT_BUFFLEN]; + char buff[PRINTF_BUFFLEN]; + + int intArg; + short shortArg; + long longArg; + unsigned unsignedArg; + unsigned long uLongArg; + unsigned short uShortArg; + char *charPtrArg = NULL; + void *voidPtrArg; + int *intPtrArg; + long *longPtrArg; + short *shortPtrArg; + double doubleArg = 0.0; + LONG_DOUBLE lDoubleArg = 0.0; + + fmtBuff[0] = '%'; + f=format; + fStop = f + strlen(f); + while (f != fStop) + { + percentPtr = memchr(f, '%', fStop - f); + if(percentPtr == NULL) percentPtr = fStop; + if(percentPtr != f) + { + if(bwrite(bp,f,percentPtr - f) < 0) + goto ErrorReturn; + streamCount += percentPtr - f; + f = percentPtr; + if(f == fStop) + break; + } + fastPath = TRUE; + /* + * The following loop always executes either once or twice. + */ + for (;;) + { + if(fastPath) + { + /* + * Fast path: Scan optimistically, hoping that no flags, + * minimum field width, or precision are specified. + * Use the preallocated buffer, which is large enough + * for all fast path cases. If the conversion specifier + * is really more complex, run the loop a second time + * using the slow path. + * Note that fast path execution of %s bypasses the buffer + * and %f is not attempted on the fast path due to + * its large buffering requirements. + */ + op = percentPtr[1]; + switch(op) + { + case 'l': + case 'L': + case 'h': + sizeModifier = op; + op = percentPtr[2]; + fmtBuff[1] = sizeModifier; + fmtBuff[2] = op; + fmtBuff[3] = '\0'; + specifierLength = 3; + break; + default: + sizeModifier = ' '; + fmtBuff[1] = op; + fmtBuff[2] = '\0'; + specifierLength = 2; + break; + } + buffPtr = buff; + buffLen = PRINTF_BUFFLEN; + } + else + { + /* + * Slow path: Scan the conversion specifier and construct + * a new format string, compute an upper bound on the + * amount of buffering that sprintf will require, + * and allocate a larger buffer if necessary. + */ + p = percentPtr + 1; + fmtBuffPtr = &fmtBuff[1]; + /* + * Scan flags + */ + n = strspn(p, "-0+ #"); + if(n > 5) + goto ErrorReturn; + CopyAndAdvance(&fmtBuffPtr, &p, n); + + /* Optimiser bug in SCO 5 - p is not advanced here under -O2. + * -K noinline fixes it. Ben. + */ + + /* + * Scan minimum field width + */ + n = strspn(p, "0123456789"); + if(n == 0) + { + if(*p == '*') + { + minWidth = va_arg(arg, int); + if(abs(minWidth) > 999999) goto ErrorReturn; + /* + * The following use of strlen rather than the + * value returned from sprintf is because SUNOS4 + * returns a char * instead of an int count. + */ + sprintf(fmtBuffPtr, "%d", minWidth); + fmtBuffPtr += strlen(fmtBuffPtr); + p++; + } + else + minWidth = 0; + } + else if(n <= 6) + { + minWidth = strtol(p, NULL, 10); + CopyAndAdvance(&fmtBuffPtr, &p, n); + } + else + goto ErrorReturn; + /* + * Scan precision + */ + if(*p == '.') + { + p++; + n = strspn(p, "0123456789"); + if(n == 0) + { + if(*p == '*') + { + precision = va_arg(arg, int); + if(precision < 0) precision = 0; + if(precision > 999999) goto ErrorReturn; + /* + * The following use of strlen rather than the + * value returned from sprintf is because SUNOS4 + * returns a char * instead of an int count. + */ + sprintf(fmtBuffPtr, ".%d", precision); + fmtBuffPtr += strlen(fmtBuffPtr); + p++; + } + else + precision = 0; + } + else if(n <= 6) + { + precision = strtol(p, NULL, 10); + *fmtBuffPtr++='.'; + CopyAndAdvance(&fmtBuffPtr, &p, n); + } + else + goto ErrorReturn; + } + else + precision = -1; + /* + * Scan size modifier and conversion operation + */ + switch(*p) + { + case 'l': + case 'L': + case 'h': + sizeModifier = *p; + CopyAndAdvance(&fmtBuffPtr, &p, 1); + break; + + default: + sizeModifier = ' '; + break; + } + op = *p; + CopyAndAdvance(&fmtBuffPtr, &p, 1); + assert(fmtBuffPtr - fmtBuff < FMT_BUFFLEN); + *fmtBuffPtr = '\0'; + /* + bwrite(bp,"[",1); + bwrite(bp,fmtBuff,strlen(fmtBuff)); + bwrite(bp,"]",1); + */ + specifierLength = p - percentPtr; + /* + * Bound the required buffer size. For s and f + * conversions this requires examining the argument. + */ + switch(op) + { + case 'd': + case 'i': + case 'u': + case 'o': + case 'x': + case 'X': + case 'c': + case 'p': + buffReqd = max(precision, 46); + break; + + case 's': + charPtrArg = va_arg(arg, char *); + if (charPtrArg == NULL) { + charPtrArg = NULL_STRING; + }; + if(precision == -1) + buffReqd = strlen(charPtrArg); + else + { + p = memchr(charPtrArg, '\0', precision); + buffReqd=(p == NULL) ? precision : p - charPtrArg; + } + break; + + case 'f': + switch(sizeModifier) + { + case ' ': + doubleArg = va_arg(arg, double); + frexp(doubleArg, &exp); + break; + + case 'L': + lDoubleArg = va_arg(arg, LONG_DOUBLE); + frexp(lDoubleArg, &exp); + break; + + default: + goto ErrorReturn; + } + if(precision == -1) + precision = 6; + buffReqd = precision + 3 + ((exp > 0) ? exp/3 : 0); + break; + + case 'e': + case 'E': + case 'g': + case 'G': + if(precision == -1) + precision = 6; + buffReqd = precision + 8; + break; + + case 'n': + case '%': + default: + goto ErrorReturn; + } + buffReqd = max(buffReqd + 10, minWidth); + /* + * Allocate the buffer + */ + if(buffReqd <= PRINTF_BUFFLEN) + { + buffPtr = buff; + buffLen = PRINTF_BUFFLEN; + } + else + { + if(auxBuffPtr == NULL || buffReqd > auxBuffLen) + { + if(auxBuffPtr != NULL) free(auxBuffPtr); + auxBuffPtr = malloc(buffReqd); + auxBuffLen = buffReqd; + if(auxBuffPtr == NULL) + goto ErrorReturn; + } + buffPtr = auxBuffPtr; + buffLen = auxBuffLen; + } + } + /* + * This giant switch statement requires the following variables + * to be set up: op, sizeModifier, arg, buffPtr, fmtBuff. + * When fastPath == FALSE and op == 's' or 'f', the argument + * has been read into charPtrArg, doubleArg, or lDoubleArg. + * The statement produces the boolean performedOp, TRUE iff + * the op/sizeModifier were executed and argument consumed; + * if performedOp, the characters written into buffPtr[] + * and the character count buffCount (== EOF meaning error). + * + * The switch cases are arranged in the same order as in the + * description of fprintf in section 15.11 of Harbison and Steele. + */ + performedOp = TRUE; + switch(op) + { + case 'd': + case 'i': + switch(sizeModifier) + { + case ' ': + intArg = va_arg(arg, int); + sprintf(buffPtr, fmtBuff, intArg); + buffCount = strlen(buffPtr); + break; + + case 'l': + longArg = va_arg(arg, long); + sprintf(buffPtr, fmtBuff, longArg); + buffCount = strlen(buffPtr); + break; + + case 'h': + shortArg = va_arg(arg, short); + sprintf(buffPtr, fmtBuff, shortArg); + buffCount = strlen(buffPtr); + break; + + default: + goto ErrorReturn; + } + break; + + case 'u': + case 'o': + case 'x': + case 'X': + switch(sizeModifier) + { + case ' ': + unsignedArg = va_arg(arg, unsigned); + sprintf(buffPtr, fmtBuff, unsignedArg); + buffCount = strlen(buffPtr); + break; + + case 'l': + uLongArg = va_arg(arg, unsigned long); + sprintf(buffPtr, fmtBuff, uLongArg); + buffCount = strlen(buffPtr); + break; + + case 'h': + uShortArg = va_arg(arg, unsigned short); + sprintf(buffPtr, fmtBuff, uShortArg); + buffCount = strlen(buffPtr); + break; + + default: + goto ErrorReturn; + } + break; + + case 'c': + switch(sizeModifier) + { + case ' ': + intArg = va_arg(arg, int); + sprintf(buffPtr, fmtBuff, intArg); + buffCount = strlen(buffPtr); + break; + + case 'l': + /* + * XXX: Allowed by ISO C Amendment 1, but + * many platforms don't yet support wint_t + */ + goto ErrorReturn; + + default: + goto ErrorReturn; + } + break; + + case 's': + switch(sizeModifier) + { + case ' ': + if(fastPath) + { + buffPtr = va_arg(arg, char *); + if (buffPtr == NULL) { + buffPtr = NULL_STRING; + }; + buffCount = strlen(buffPtr); + buffLen = buffCount + 1; + } + else + { + sprintf(buffPtr, fmtBuff, charPtrArg); + buffCount = strlen(buffPtr); + } + break; + + case 'l': + /* + * XXX: Don't know how to convert a sequence + * of wide characters into a byte stream, or + * even how to predict the buffering required. + */ + goto ErrorReturn; + + default: + goto ErrorReturn; + } + break; + + case 'p': + if(sizeModifier != ' ') + goto ErrorReturn; + voidPtrArg = va_arg(arg, void *); + sprintf(buffPtr, fmtBuff, voidPtrArg); + buffCount = strlen(buffPtr); + break; + + case 'n': + switch(sizeModifier) + { + case ' ': + intPtrArg = va_arg(arg, int *); + *intPtrArg = streamCount; + break; + + case 'l': + longPtrArg = va_arg(arg, long *); + *longPtrArg = streamCount; + break; + + case 'h': + shortPtrArg = va_arg(arg, short *); + *shortPtrArg = streamCount; + break; + + default: + goto ErrorReturn; + } + buffCount = 0; + break; + + case 'f': + if(fastPath) + { + performedOp = FALSE; + break; + } + + switch(sizeModifier) + { + case ' ': + sprintf(buffPtr, fmtBuff, doubleArg); + buffCount = strlen(buffPtr); + break; + + case 'L': + sprintf(buffPtr, fmtBuff, lDoubleArg); + buffCount = strlen(buffPtr); + break; + + default: + goto ErrorReturn; + } + break; + /* FIXME: Used to flow through here? Should it? Ben */ + + case 'e': + case 'E': + case 'g': + case 'G': + switch(sizeModifier) + { + case ' ': + doubleArg = va_arg(arg, double); + sprintf(buffPtr, fmtBuff, doubleArg); + buffCount = strlen(buffPtr); + break; + + case 'L': + lDoubleArg = va_arg(arg, LONG_DOUBLE); + sprintf(buffPtr, fmtBuff, lDoubleArg); + buffCount = strlen(buffPtr); + break; + + default: + goto ErrorReturn; + } + break; + + case '%': + if(sizeModifier != ' ') + goto ErrorReturn; + buff[0] = '%'; + buffCount = 1; + break; + + case '\0': + goto ErrorReturn; + + default: + performedOp = FALSE; + break; + } /* switch(op) */ + + if(performedOp) + break; + if(!fastPath) + goto ErrorReturn; + fastPath = FALSE; + } /* for (;;) */ + assert(buffCount < buffLen); + if(buffCount > 0) + { + if(bwrite(bp,buffPtr,buffCount) < 0) + goto ErrorReturn; + streamCount += buffCount; + } + else if(buffCount < 0) + goto ErrorReturn; + f += specifierLength; + } /* while(f != fStop) */ + goto NormalReturn; +ErrorReturn: + streamCount = -1; +NormalReturn: + if(auxBuffPtr != NULL) + free(auxBuffPtr); + return streamCount; + } diff --git a/APACHE_1_2_X/src/main/http_config.c b/APACHE_1_2_X/src/main/http_config.c new file mode 100644 index 00000000000..51c0ec6580b --- /dev/null +++ b/APACHE_1_2_X/src/main/http_config.c @@ -0,0 +1,1198 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +/* + * http_config.c: once was auxillary functions for reading httpd's config + * file and converting filenames into a namespace + * + * Rob McCool + * + * Wall-to-wall rewrite for Apache... commands which are part of the + * server core can now be found next door in "http_core.c". Now contains + * general command loop, and functions which do bookkeeping for the new + * Apache config stuff (modules and configuration vectors). + * + * rst + * + */ + +#define CORE_PRIVATE + +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_log.h" /* for errors in parse_htaccess */ +#include "http_request.h" /* for default_handler (see invoke_handler) */ +#include "http_conf_globals.h" /* Sigh... */ +#include "explain.h" + +DEF_Explain + +/**************************************************************** + * + * We begin with the functions which deal with the linked list + * of modules which control just about all of the server operation. + */ + +/* num_modules is the number of currently active modules. */ +static int num_modules = 0; +/* total_modules is the number of modules linked in. */ +static int total_modules = 0; +module *top_module = NULL; + +typedef int (*handler)(request_rec *); +typedef void *(*maker)(pool *); +typedef void *(*dir_maker)(pool *, char *); +typedef void *(*merger)(pool *, void *, void *); + +/* Dealing with config vectors. These are associated with per-directory, + * per-server, and per-request configuration, and have a void* pointer for + * each modules. The nature of the structure pointed to is private to the + * module in question... the core doesn't (and can't) know. However, there + * are defined interfaces which allow it to create instances of its private + * per-directory and per-server structures, and to merge the per-directory + * structures of a directory and its subdirectory (producing a new one in + * which the defaults applying to the base directory have been properly + * overridden). + */ + +void * +get_module_config (void *conf_vector, module *m) +{ + void **confv = (void**)conf_vector; + return confv[m->module_index]; +} + +void +set_module_config (void *conf_vector, module *m, void *val) +{ + void **confv = (void**)conf_vector; + confv[m->module_index] = val; +} + +void * +create_empty_config (pool *p) +{ + void **conf_vector = (void **)pcalloc(p, sizeof(void*) * total_modules); + return (void *)conf_vector; +} + +void * +create_default_per_dir_config (pool *p) +{ + void **conf_vector = (void **)pcalloc(p, sizeof(void*) * (total_modules+DYNAMIC_MODULE_LIMIT)); + module *modp; + + for (modp = top_module; modp; modp = modp->next) { + dir_maker df = modp->create_dir_config; + + if (df) conf_vector[modp->module_index] = (*df)(p, NULL); + } + + return (void*)conf_vector; +} + +void * +merge_per_dir_configs (pool *p, void *base, void *new) +{ + void **conf_vector = (void **)pcalloc(p, sizeof(void*) * total_modules); + void **base_vector = (void **) base; + void **new_vector = (void **) new; + module *modp; + + for (modp = top_module; modp; modp = modp->next) { + merger df = modp->merge_dir_config; + int i = modp->module_index; + + if (df && new_vector[i]) + conf_vector[i] = (*df)(p, base_vector[i], new_vector[i]); + else + conf_vector[i] = new_vector[i]? new_vector[i] : base_vector[i]; + } + + return (void*)conf_vector; +} + +void * +create_server_config (pool *p, server_rec *s) +{ + void **conf_vector = (void **)pcalloc(p, sizeof(void*) * (total_modules+DYNAMIC_MODULE_LIMIT)); + module *modp; + + for (modp = top_module; modp; modp = modp->next) { + if (modp->create_server_config) + conf_vector[modp->module_index]=(*modp->create_server_config)(p,s); + } + + return (void*)conf_vector; +} + +void merge_server_configs (pool *p, void *base, void *virt) +{ + /* Can reuse the 'virt' vector for the spine of it, since we don't + * have to deal with the moral equivalent of .htaccess files here... + */ + + void **base_vector = (void **)base; + void **virt_vector = (void **)virt; + module *modp; + + for (modp = top_module; modp; modp = modp->next) { + merger df = modp->merge_server_config; + int i = modp->module_index; + + if (!virt_vector[i]) + virt_vector[i] = base_vector[i]; + else if (df) + virt_vector[i] = (*df)(p, base_vector[i], virt_vector[i]); + } +} + +void *create_connection_config (pool *p) { + return create_empty_config (p); +} + +void *create_request_config (pool *p) { + return create_empty_config (p); +} + +void *create_per_dir_config (pool *p) { + return create_empty_config (p); +} + +#ifdef EXPLAIN + +struct + { + int offset; + char *method; + } aMethods[]= + { +#define m(meth) { XtOffsetOf(module,meth),#meth } + m(translate_handler), + m(check_user_id), + m(auth_checker), + m(type_checker), + m(fixer_upper), + m(logger), + { -1,"?" }, +#undef m + }; + +char *ShowMethod(module *modp,int offset) + { + int n; + static char buf[200]; + + for(n=0 ; aMethods[n].offset >= 0 ; ++n) + if(aMethods[n].offset == offset) + break; + ap_snprintf(buf, sizeof(buf), "%s:%s",modp->name,aMethods[n].method); + return buf; + } +#else +#define ShowMethod(modp,offset) +#endif + +/**************************************************************** + * + * Dispatch through the modules to find handlers for various phases + * of request handling. These are invoked by http_request.c to actually + * do the dirty work of slogging through the module structures. + */ + +int +run_method (request_rec *r, int offset, int run_all) +{ + module *modp; + for (modp = top_module; modp; modp = modp->next) { + handler mod_handler = *(handler *)(offset + (char *)(modp)); + + if (mod_handler) { + int result; + + Explain1("Run %s",ShowMethod(modp,offset)); + result = (*mod_handler)(r); + + Explain2("%s returned %d",ShowMethod(modp,offset),result); + if (result != DECLINED && (!run_all || result != OK)) + return result; + } + } + + return run_all ? OK : DECLINED; +} + +int translate_name(request_rec *r) { + return run_method (r, XtOffsetOf (module, translate_handler), 0); +} + +int check_access(request_rec *r) { + return run_method (r, XtOffsetOf (module, access_checker), 1); +} + +int find_types (request_rec *r) { + return run_method (r, XtOffsetOf (module, type_checker), 0); +} + +int run_fixups (request_rec *r) { + return run_method (r, XtOffsetOf (module, fixer_upper), 1); +} + +int log_transaction (request_rec *r) { + return run_method (r, XtOffsetOf (module, logger), 1); +} + +int header_parse (request_rec *r) { + return run_method (r, XtOffsetOf (module, header_parser), 1); +} + +/* Auth stuff --- anything that defines one of these will presumably + * want to define something for the other. Note that check_auth is + * separate from check_access to make catching some config errors easier. + */ + +int check_user_id (request_rec *r) { + return run_method (r, XtOffsetOf (module, check_user_id), 0); +} + +int check_auth (request_rec *r) { + return run_method (r, XtOffsetOf (module, auth_checker), 0); +} + +int invoke_handler (request_rec *r) +{ + module *modp; + handler_rec *handp; + char *content_type = r->content_type ? r->content_type : default_type (r); + char *handler, *p; + + if ((p = strchr(content_type, ';')) != NULL) { /* MIME type arguments */ + while (p > content_type && p[-1] == ' ') --p; /* strip trailing spaces */ + content_type = pstrndup(r->pool, content_type, p - content_type); + } + handler = r->handler ? r->handler : content_type; + + /* Pass one --- direct matches */ + + for (modp = top_module; modp; modp = modp->next) + { + if (!modp->handlers) continue; + + for (handp = modp->handlers; handp->content_type; ++handp) { + if (!strcasecmp (handler, handp->content_type)) { + int result = (*handp->handler)(r); + + if (result != DECLINED) return result; + } + } + } + + /* Pass two --- wildcard matches */ + + for (modp = top_module; modp; modp = modp->next) + { + if (!modp->handlers) continue; + + for (handp = modp->handlers; handp->content_type; ++handp) { + char *starp = strchr (handp->content_type, '*'); + int len; + + if (!starp) continue; + + len = starp - handp->content_type; + + if (!len || !strncasecmp (handler, handp->content_type, len)) + { + int result = (*handp->handler)(r); + + if (result != DECLINED) return result; + } + } + } + + return NOT_IMPLEMENTED; +} + +/* One-time setup for precompiled modules --- NOT to be done on restart */ + +void add_module (module *m) +{ + /* This could be called from an AddModule httpd.conf command, + * after the file has been linked and the module structure within it + * teased out... + */ + + /* At some point, we may want to offer back-compatibility for + * loading modules that are for older versions of Apache. For now, + * though, we don't. + */ + + if (m->version != MODULE_MAGIC_NUMBER) { + fprintf(stderr, "httpd: module \"%s\" is not compatible with this " + "version of Apache.\n", m->name); + fprintf(stderr, "Please contact the author for the correct version.\n"); + exit(1); + } + + if (m->next == NULL) { + m->next = top_module; + top_module = m; + } + if (m->module_index == -1) { + m->module_index = num_modules++; + } +} + +void setup_prelinked_modules () +{ + extern module *prelinked_modules[], *preloaded_modules[]; + module **m; + + /* First, set all module indices, and init total_modules. */ + total_modules = 0; + for (m = preloaded_modules; *m; ++m, ++total_modules) { + (*m)->module_index = total_modules; + } + + for (m = prelinked_modules; *m; ++m) { + add_module (*m); + } +} + +const char *find_module_name (module *m) +{ + return m->name; +} + +module *find_linked_module (const char *name) +{ + module *modp; + + for (modp = top_module; modp; modp = modp->next) { + if (strcmp(modp->name, name) == 0) + return modp; + } + return NULL; +} + +/* Add a named module. Returns 1 if module found, 0 otherwise. */ +int add_named_module (const char *name) +{ + extern module *preloaded_modules[]; + module *modp; + int i = 0; + + for (modp = preloaded_modules[i]; modp; modp = preloaded_modules[++i]) { + if (strcmp(modp->name, name) == 0) { + /* Only add modules that are not already enabled. */ + if (modp->next == NULL) { + add_module(modp); + } + return 1; + } + } + + return 0; +} + +/* Clear the internal list of modules, in preparation for starting over. */ +void clear_module_list () +{ + module **m = &top_module; + module **next_m; + + while (*m) { + next_m = &((*m)->next); + *m = NULL; + m = next_m; + } + + num_modules = 0; + + /* This is required; so we add it always. */ + add_named_module ("http_core.c"); +} + +/***************************************************************** + * + * Resource, access, and .htaccess config files now parsed by a common + * command loop. + * + * Let's begin with the basics; parsing the line and + * invoking the function... + */ + +const char *invoke_cmd(const command_rec *cmd, cmd_parms *parms, void *mconfig, + const char *args) +{ + char *w, *w2, *w3; + const char *errmsg; + + if ((parms->override & cmd->req_override) == 0) + return pstrcat (parms->pool, cmd->name, " not allowed here", NULL); + + parms->info = cmd->cmd_data; + parms->cmd = cmd; + + switch (cmd->args_how) { + case RAW_ARGS: + return (*cmd->func) (parms, mconfig, args); + + case NO_ARGS: + if (*args != 0) + return pstrcat (parms->pool, cmd->name, " takes no arguments", + NULL); + + return (*cmd->func) (parms, mconfig); + + case TAKE1: + w = getword_conf (parms->pool, &args); + + if (*w == '\0' || *args != 0) + return pstrcat (parms->pool, cmd->name, " takes one argument", + cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); + + return (*cmd->func) (parms, mconfig, w); + + case TAKE2: + + w = getword_conf (parms->pool, &args); + w2 = getword_conf (parms->pool, &args); + + if (*w == '\0' || *w2 == '\0' || *args != 0) + return pstrcat (parms->pool, cmd->name, " takes two arguments", + cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); + + return (*cmd->func) (parms, mconfig, w, w2); + + case TAKE12: + + w = getword_conf (parms->pool, &args); + w2 = getword_conf (parms->pool, &args); + + if (*w == '\0' || *args != 0) + return pstrcat (parms->pool, cmd->name, " takes 1-2 arguments", + cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); + + return (*cmd->func) (parms, mconfig, w, *w2 ? w2 : NULL); + + case TAKE3: + + w = getword_conf (parms->pool, &args); + w2 = getword_conf (parms->pool, &args); + w3 = getword_conf (parms->pool, &args); + + if (*w == '\0' || *w2 == '\0' || *w3 == '\0' || *args != 0) + return pstrcat (parms->pool, cmd->name, " takes three arguments", + cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); + + return (*cmd->func) (parms, mconfig, w, w2, w3); + + case TAKE23: + + w = getword_conf (parms->pool, &args); + w2 = getword_conf (parms->pool, &args); + w3 = *args ? getword_conf (parms->pool, &args) : NULL; + + if (*w == '\0' || *w2 == '\0' || *args != 0) + return pstrcat (parms->pool, cmd->name, " takes two or three arguments", + cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); + + return (*cmd->func) (parms, mconfig, w, w2, w3); + + case TAKE123: + + w = getword_conf (parms->pool, &args); + w2 = *args ? getword_conf (parms->pool, &args) : NULL; + w3 = *args ? getword_conf (parms->pool, &args) : NULL; + + if (*w == '\0' || *args != 0) + return pstrcat (parms->pool, cmd->name, " takes one, two or three arguments", + cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); + + return (*cmd->func) (parms, mconfig, w, w2, w3); + + case TAKE13: + + w = getword_conf (parms->pool, &args); + w2 = *args ? getword_conf (parms->pool, &args) : NULL; + w3 = *args ? getword_conf (parms->pool, &args) : NULL; + + if (*w == '\0' || (*w2 && !w3) || *args != 0) + return pstrcat (parms->pool, cmd->name, " takes one or three arguments", + cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); + + return (*cmd->func) (parms, mconfig, w, w2, w3); + + case ITERATE: + + while (*(w = getword_conf (parms->pool, &args)) != '\0') + if ((errmsg = (*cmd->func) (parms, mconfig, w))) + return errmsg; + + return NULL; + + case ITERATE2: + + w = getword_conf (parms->pool, &args); + + if (*w == '\0' || *args == 0) + return pstrcat(parms->pool, cmd->name, + " requires at least two arguments", + cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); + + + while (*(w2 = getword_conf (parms->pool, &args)) != '\0') + if ((errmsg = (*cmd->func) (parms, mconfig, w, w2))) + return errmsg; + + return NULL; + + case FLAG: + + w = getword_conf (parms->pool, &args); + + if (*w == '\0' || (strcasecmp(w, "on") && strcasecmp (w, "off"))) + return pstrcat (parms->pool, cmd->name, " must be On or Off", + NULL); + + return (*cmd->func) (parms, mconfig, strcasecmp (w, "off") != 0); + + default: + + return pstrcat (parms->pool, cmd->name, + " is improperly configured internally (server bug)", + NULL); + } +} + +const command_rec *find_command (const char *name, const command_rec *cmds) +{ + while (cmds->name) + if (!strcasecmp (name, cmds->name)) + return cmds; + else + ++cmds; + + return NULL; +} + +const command_rec *find_command_in_modules (const char *cmd_name, module **mod) +{ + const command_rec *cmdp; + module *modp; + + for (modp = *mod; modp; modp = modp->next) + if (modp->cmds && (cmdp = find_command (cmd_name, modp->cmds))) { + *mod = modp; + return cmdp; + } + + return NULL; +} + +const char *handle_command (cmd_parms *parms, void *config, const char *l) +{ + const char *args, *cmd_name, *retval; + const command_rec *cmd; + module *mod = top_module; + + ++parms->config_line; + if((l[0] == '#') || (!l[0])) return NULL; + + args = l; + cmd_name = getword_conf (parms->temp_pool, &args); + if (*cmd_name == '\0') return NULL; + + do { + if (!(cmd = find_command_in_modules (cmd_name, &mod))) { + return pstrcat (parms->pool, "Invalid command ", cmd_name, NULL); + } + else { + void *mconfig = get_module_config (config, mod); + void *sconfig = + get_module_config (parms->server->module_config, mod); + + if (!mconfig && mod->create_dir_config) { + mconfig = (*mod->create_dir_config) (parms->pool, parms->path); + set_module_config (config, mod, mconfig); + } + + if (!sconfig && mod->create_server_config) { + sconfig = + (*mod->create_server_config)(parms->pool, parms->server); + set_module_config (parms->server->module_config, mod, sconfig); + } + + retval = invoke_cmd (cmd, parms, mconfig, args); + mod = mod->next; /* Next time around, skip this one */ + } + } while (retval && !strcmp(retval, DECLINE_CMD)); + + return retval; +} + +const char *srm_command_loop (cmd_parms *parms, void *config) +{ + char l[MAX_STRING_LEN]; + + while (!(cfg_getline (l, MAX_STRING_LEN, parms->infile))) { + const char *errmsg = handle_command (parms, config, l); + if (errmsg) return errmsg; + } + + return NULL; +} + +/* + * Generic command functions... + */ + +const char *set_string_slot (cmd_parms *cmd, char *struct_ptr, char *arg) +{ + /* This one's pretty generic... */ + + int offset = (int)cmd->info; + *(char **)(struct_ptr + offset) = pstrdup (cmd->pool, arg); + return NULL; +} + +const char *set_flag_slot (cmd_parms *cmd, char *struct_ptr, int arg) +{ + /* This one's pretty generic too... */ + + int offset = (int)cmd->info; + *(int *)(struct_ptr + offset) = arg ? 1 : 0; + return NULL; +} + +/***************************************************************** + * + * Reading whole config files... + */ + +cmd_parms default_parms = { NULL, 0, -1, NULL, 0, NULL, NULL, NULL, NULL }; + +char *server_root_relative (pool *p, char *file) +{ +#ifdef __EMX__ + /* Add support for OS/2 drive names */ + if ((file[0] == '/') || (file[1] == ':')) return file; +#else + if (file[0] == '/') return file; +#endif + return make_full_path (p, server_root, file); +} + +void process_resource_config(server_rec *s, char *fname, pool *p, pool *ptemp) +{ + FILE *cfg; + const char *errmsg; + cmd_parms parms; + struct stat finfo; + + fname = server_root_relative (p, fname); + + if (!(strcmp(fname, server_root_relative(p, RESOURCE_CONFIG_FILE))) || + !(strcmp(fname, server_root_relative(p, ACCESS_CONFIG_FILE)))) { + if (stat(fname, &finfo) == -1) + return; + } + + /* GCC's initialization extensions are soooo nice here... */ + + parms = default_parms; + parms.config_file = fname; + parms.pool = p; + parms.temp_pool = ptemp; + parms.server = s; + parms.override = (RSRC_CONF|OR_ALL)&~(OR_AUTHCFG|OR_LIMIT); + + if(!(cfg = fopen(fname, "r"))) { + perror("fopen"); + fprintf(stderr,"httpd: could not open document config file %s\n", + fname); + exit(1); + } + + parms.infile = cfg; + + errmsg = srm_command_loop (&parms, s->lookup_defaults); + + if (errmsg) { + fprintf (stderr, "Syntax error on line %d of %s:\n", + parms.config_line, fname); + fprintf (stderr, "%s\n", errmsg); + exit(1); + } + + fclose(cfg); +} + + +int parse_htaccess(void **result, request_rec *r, int override, + char *d, char *filename) +{ + FILE *f; + cmd_parms parms; + const char *errmsg; + const struct htaccess_result *cache; + struct htaccess_result *new; + void *dc; + +/* firstly, search cache */ + for (cache=r->htaccess; cache != NULL; cache=cache->next) + if (cache->override == override && strcmp(cache->dir, d) == 0) + { + if (cache->htaccess != NULL) *result = cache->htaccess; + return OK; + } + + parms = default_parms; + parms.override = override; + parms.pool = r->pool; + parms.temp_pool = r->pool; + parms.server = r->server; + parms.path = d; + + if((f=pfopen(r->pool, filename, "r"))) { + dc = create_per_dir_config (r->pool); + + parms.infile = f; + parms.config_file = filename; + + errmsg = srm_command_loop (&parms, dc); + + pfclose(r->pool, f); + + if (errmsg) { + log_reason (errmsg, filename, r); + return SERVER_ERROR; + } + + *result = dc; + } else + dc = NULL; + +/* cache it */ + new = palloc(r->pool, sizeof(struct htaccess_result)); + new->dir = pstrdup(r->pool, d); + new->override = override; + new->htaccess = dc; +/* add to head of list */ + new->next = r->htaccess; + r->htaccess = new; + + return OK; +} + +/***************************************************************** + * + * Virtual host stuff; note that the commands that invoke this stuff + * are with the command table in http_core.c. + */ + +/* + * Parses a host of the form <address>[:port] + * paddr is used to create a list in the order of input + * **paddr is the ->next pointer of the last entry (or s->addrs) + * *paddr is the variable used to keep track of **paddr between calls + * port is the default port to assume + */ +static void get_addresses (pool *p, char *w, server_addr_rec ***paddr, unsigned port) +{ + struct hostent *hep; + unsigned long my_addr; + server_addr_rec *sar; + char *t; + int i, is_an_ip_addr; + + if( *w == 0 ) return; + + t = strchr(w, ':'); + if (t) { + if( strcmp(t+1,"*") == 0 ) { + port = 0; + } else if( (i = atoi(t+1)) ) { + port = i; + } else { + fprintf( stderr, "Port must be numeric\n" ); + } + *t = 0; + } + + is_an_ip_addr = 0; + if (strcmp(w, "*") == 0) { + my_addr = htonl(INADDR_ANY); + is_an_ip_addr = 1; + } else if( strcmp(w, "_default_") == 0 + || strcmp(w, "255.255.255.255") == 0 ) { + my_addr = DEFAULT_VHOST_ADDR; + is_an_ip_addr = 1; + } else if( +#ifdef DGUX + ( my_addr = inet_network(w) ) +#else + ( my_addr = inet_addr(w) ) +#endif + != INADDR_NONE ) { + is_an_ip_addr = 1; + } + if( is_an_ip_addr ) { + sar = pcalloc( p, sizeof( server_addr_rec ) ); + **paddr = sar; + *paddr = &sar->next; + sar->host_addr.s_addr = my_addr; + sar->host_port = port; + sar->virthost = pstrdup(p, w); + if (t != NULL) *t = ':'; + return; + } + + hep = gethostbyname(w); + + if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) { + fprintf (stderr, "Cannot resolve host name %s --- ignoring!\n", w); + if (t != NULL) *t = ':'; + return; + } + + for( i = 0; hep->h_addr_list[i]; ++i ) { + sar = pcalloc( p, sizeof( server_addr_rec ) ); + **paddr = sar; + *paddr = &sar->next; + sar->host_addr = *(struct in_addr *)hep->h_addr_list[i]; + sar->host_port = port; + sar->virthost = pstrdup(p, w); + } + + if (t != NULL) *t = ':'; +} + +server_rec *init_virtual_host (pool *p, const char *hostname, + server_rec *main_server) +{ + server_rec *s = (server_rec *)pcalloc (p, sizeof (server_rec)); + server_addr_rec **addrs; + +#ifdef RLIMIT_NOFILE + struct rlimit limits; + + getrlimit ( RLIMIT_NOFILE, &limits ); + if ( limits.rlim_cur < limits.rlim_max ) { + limits.rlim_cur += 2; + if ( setrlimit ( RLIMIT_NOFILE, &limits ) < 0 ) { + perror ("setrlimit(RLIMIT_NOFILE)"); + fprintf (stderr, "Cannot exceed hard limit for open files"); + } + } +#endif + + s->server_admin = NULL; + s->server_hostname = NULL; + s->error_fname = NULL; + s->srm_confname = NULL; + s->access_confname = NULL; + s->timeout = 0; + s->keep_alive_timeout = 0; + s->keep_alive = -1; + s->keep_alive_max = -1; + s->error_log = main_server->error_log; + /* start the list of addreses */ + addrs = &s->addrs; + while( hostname[0] ) { + get_addresses( p, getword_conf( p, &hostname ), &addrs, + main_server->port ); + } + /* terminate the list */ + *addrs = NULL; + if( s->addrs ) { + if (s->addrs->host_port) { + s->port = s->addrs->host_port; /* set them the same, by default */ + } else { + /* otherwise we get a port of 0 on redirects */ + s->port = main_server->port; + } + } + s->next = NULL; + + s->is_virtual = 1; + s->names = NULL; + + s->module_config = create_empty_config (p); + s->lookup_defaults = create_per_dir_config (p); + + s->server_uid = user_id; + s->server_gid = group_id; + + return s; +} + +int is_virtual_server (server_rec *s) +{ + return s->is_virtual; +} + +void fixup_virtual_hosts (pool *p, server_rec *main_server) +{ + server_rec *virt; + + for (virt = main_server->next; virt; virt = virt->next) { + merge_server_configs (p, main_server->module_config, + virt->module_config); + + virt->lookup_defaults = + merge_per_dir_configs (p, main_server->lookup_defaults, + virt->lookup_defaults); + + if (virt->server_admin == NULL) + virt->server_admin = main_server->server_admin; + + if (virt->srm_confname == NULL) + virt->srm_confname = main_server->srm_confname; + + if (virt->access_confname == NULL) + virt->access_confname = main_server->access_confname; + + if (virt->timeout == 0) + virt->timeout = main_server->timeout; + + if (virt->keep_alive_timeout == 0) + virt->keep_alive_timeout = main_server->keep_alive_timeout; + + if (virt->keep_alive == -1) + virt->keep_alive = main_server->keep_alive; + + if (virt->keep_alive_max == -1) + virt->keep_alive_max = main_server->keep_alive_max; + + if (virt->send_buffer_size == 0) + virt->send_buffer_size = main_server->send_buffer_size; + } +} + +/***************************************************************** + * + * Getting *everything* configured... + */ + +void init_config_globals (pool *p) +{ + /* ServerRoot, server_confname set in httpd.c */ + + standalone = 1; + user_name = DEFAULT_USER; + user_id = uname2id(DEFAULT_USER); + group_id = gname2id(DEFAULT_GROUP); + daemons_to_start = DEFAULT_START_DAEMON; + daemons_min_free = DEFAULT_MIN_FREE_DAEMON; + daemons_max_free = DEFAULT_MAX_FREE_DAEMON; + daemons_limit = HARD_SERVER_LIMIT; + pid_fname = DEFAULT_PIDLOG; + scoreboard_fname = DEFAULT_SCOREBOARD; + max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; + bind_address.s_addr = htonl(INADDR_ANY); + listeners = NULL; +} + +server_rec *init_server_config(pool *p) +{ + server_rec *s = (server_rec *)pcalloc (p, sizeof (server_rec)); + + s->port = DEFAULT_PORT; + s->server_admin = DEFAULT_ADMIN; + s->server_hostname = NULL; + s->error_fname = DEFAULT_ERRORLOG; + s->error_log = stderr; + s->srm_confname = RESOURCE_CONFIG_FILE; + s->access_confname = ACCESS_CONFIG_FILE; + s->timeout = DEFAULT_TIMEOUT; + s->keep_alive_timeout = DEFAULT_KEEPALIVE_TIMEOUT; + s->keep_alive_max = DEFAULT_KEEPALIVE; + s->keep_alive = 1; + s->next = NULL; + s->addrs = pcalloc(p, sizeof (server_addr_rec)); + s->addrs->host_addr.s_addr = htonl (INADDR_ANY); /* NOT virtual host; + * don't match any real network + * interface. + */ + s->addrs->host_port = 0; /* matches any port */ + + s->module_config = create_server_config (p, s); + s->lookup_defaults = create_default_per_dir_config (p); + + return s; +} + +server_rec *read_config(pool *p, pool *ptemp, char *confname) +{ + server_rec *s = init_server_config(p); + module *m; + + init_config_globals(p); + + /* All server-wide config files now have the SAME syntax... */ + + process_resource_config (s, confname, p, ptemp); + process_resource_config (s, s->srm_confname, p, ptemp); + process_resource_config (s, s->access_confname, p, ptemp); + + fixup_virtual_hosts (p, s); + + for (m = top_module; m; m = m->next) + if (m->init) + (*m->init) (s, p); + + return s; +} + +/******************************************************************** + * Configuration directives are restricted in terms of where they may + * appear in the main configuration files and/or .htaccess files according + * to the bitmask req_override in the command_rec structure. + * If any of the overrides set in req_override are also allowed in the + * context in which the command is read, then the command is allowed. + * The context is determined as follows: + * + * inside *.conf --> override = (RSRC_CONF|OR_ALL)&~(OR_AUTHCFG|OR_LIMIT); + * within <Directory> or <Location> --> override = OR_ALL|ACCESS_CONF; + * within .htaccess --> override = AllowOverride for current directory; + * + * the result is, well, a rather confusing set of possibilities for when + * a particular directive is allowed to be used. This procedure prints + * in English where the given (pc) directive can be used. + */ +void show_overrides(command_rec *pc, module *pm) +{ + int n = 0; + + printf("\tAllowed in *.conf "); + if ((pc->req_override & (OR_OPTIONS|OR_FILEINFO|OR_INDEXES)) || + ((pc->req_override & RSRC_CONF) && + ((pc->req_override & (ACCESS_CONF|OR_AUTHCFG|OR_LIMIT))))) + printf("anywhere"); + else if (pc->req_override & RSRC_CONF) + printf("only outside <Directory> or <Location>"); + else + printf("only inside <Directory> or <Location>"); + + /* Warn if the directive is allowed inside <Directory> or .htaccess + * but module doesn't support per-dir configuration */ + + if ((pc->req_override & (OR_ALL|ACCESS_CONF)) && !pm->create_dir_config) + printf(" [no per-dir config]"); + + if (pc->req_override & OR_ALL) { + printf(" and in .htaccess\n\twhen AllowOverride"); + + if ((pc->req_override & OR_ALL) == OR_ALL) + printf(" isn't None"); + else { + printf(" includes "); + + if (pc->req_override & OR_AUTHCFG) { + if (n++) printf(" or "); + printf("AuthConfig"); + } + if (pc->req_override & OR_LIMIT) { + if (n++) printf(" or "); + printf("Limit"); + } + if (pc->req_override & OR_OPTIONS) { + if (n++) printf(" or "); + printf("Options"); + } + if (pc->req_override & OR_FILEINFO) { + if (n++) printf(" or "); + printf("FileInfo"); + } + if (pc->req_override & OR_INDEXES) { + if (n++) printf(" or "); + printf("Indexes"); + } + } + } + printf("\n"); +} + +/* Show the preloaded configuration directives, the help string explaining + * the directive arguments, in what module they are handled, and in + * what parts of the configuration they are allowed. Used for httpd -h. + */ +void show_directives() +{ + extern module *preloaded_modules[]; + command_rec *pc; + int n; + + for (n = 0; preloaded_modules[n]; ++n) + for (pc = preloaded_modules[n]->cmds; pc && pc->name; ++pc) { + printf("%s\n", pc->name); + if (pc->errmsg) + printf("\t%s\n", pc->errmsg); + printf("\t%s\n", preloaded_modules[n]->name); + show_overrides(pc, preloaded_modules[n]); + } +} + +/* Show the preloaded module names. Used for httpd -l. */ +void show_modules() +{ + extern module *preloaded_modules[]; + int n; + + printf ("Compiled-in modules:\n"); + for (n = 0; preloaded_modules[n]; ++n) + printf (" %s\n", preloaded_modules[n]->name); +} + diff --git a/APACHE_1_2_X/src/main/http_core.c b/APACHE_1_2_X/src/main/http_core.c new file mode 100644 index 00000000000..0bc6ece1f75 --- /dev/null +++ b/APACHE_1_2_X/src/main/http_core.c @@ -0,0 +1,1387 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +#define CORE_PRIVATE +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_protocol.h" /* For index_of_response(). Grump. */ +#include "http_conf_globals.h" + +#include "http_main.h" /* For the default_handler below... */ +#include "http_log.h" +#include "rfc1413.h" +#include "util_md5.h" +#include "scoreboard.h" + +/* Server core module... This module provides support for really basic + * server operations, including options and commands which control the + * operation of other modules. Consider this the bureaucracy module. + * + * The core module also defines handlers, etc., do handle just enough + * to allow a server with the core module ONLY to actually serve documents + * (though it slaps DefaultType on all of 'em); this was useful in testing, + * but may not be worth preserving. + * + * This file could almost be mod_core.c, except for the stuff which affects + * the http_conf_globals. + */ + +void *create_core_dir_config (pool *a, char *dir) +{ + core_dir_config *conf = + (core_dir_config *)pcalloc(a, sizeof(core_dir_config)); + + if (!dir || dir[strlen(dir) - 1] == '/') conf->d = dir; + else if (strncmp(dir,"proxy:",6)==0) conf->d = pstrdup (a, dir); + else conf->d = pstrcat (a, dir, "/", NULL); + conf->d_is_matchexp = conf->d ? is_matchexp( conf->d ) : 0; + + + conf->opts = dir ? OPT_UNSET : OPT_ALL; + conf->opts_add = conf->opts_remove = OPT_NONE; + conf->override = dir ? OR_UNSET : OR_ALL; + + conf->content_md5 = 2; + + conf->hostname_lookups = 2;/* binary, but will use 2 as an "unset = on" */ + conf->do_rfc1413 = DEFAULT_RFC1413 | 2; /* set bit 1 to indicate default */ + conf->satisfy = SATISFY_NOSPEC; + +#ifdef RLIMIT_CPU + conf->limit_cpu = NULL; +#endif +#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) + conf->limit_mem = NULL; +#endif +#ifdef RLIMIT_NPROC + conf->limit_nproc = NULL; +#endif + + conf->sec = make_array (a, 2, sizeof(void *)); + + return (void *)conf; +} + +void *merge_core_dir_configs (pool *a, void *basev, void *newv) +{ + core_dir_config *base = (core_dir_config *)basev; + core_dir_config *new = (core_dir_config *)newv; + core_dir_config *conf = + (core_dir_config *)pcalloc (a, sizeof(core_dir_config)); + int i; + + memcpy ((char *)conf, (const char *)base, sizeof(core_dir_config)); + if( base->response_code_strings ) { + conf->response_code_strings = palloc(a, + sizeof(*conf->response_code_strings) * RESPONSE_CODES ); + memcpy( conf->response_code_strings, base->response_code_strings, + sizeof(*conf->response_code_strings) * RESPONSE_CODES ); + } + + conf->d = new->d; + conf->d_is_matchexp = new->d_is_matchexp; + conf->r = new->r; + + if (new->opts != OPT_UNSET) conf->opts = new->opts; + if (new->opts_add) conf->opts |= new->opts_add; + if (new->opts_remove) conf->opts &= ~(new->opts_remove); + + if (new->override != OR_UNSET) conf->override = new->override; + if (new->default_type) conf->default_type = new->default_type; + + if (new->auth_type) conf->auth_type = new->auth_type; + if (new->auth_name) conf->auth_name = new->auth_name; + if (new->requires) conf->requires = new->requires; + + if( new->response_code_strings ) { + if( conf->response_code_strings == NULL ) { + conf->response_code_strings = palloc(a, + sizeof(*conf->response_code_strings) * RESPONSE_CODES ); + memcpy( conf->response_code_strings, new->response_code_strings, + sizeof(*conf->response_code_strings) * RESPONSE_CODES ); + } else { + for (i = 0; i < RESPONSE_CODES; ++i) + if (new->response_code_strings[i] != NULL) + conf->response_code_strings[i] = new->response_code_strings[i]; + } + } + if (new->hostname_lookups != 2) + conf->hostname_lookups = new->hostname_lookups; + if ((new->do_rfc1413 & 2) == 0) conf->do_rfc1413 = new->do_rfc1413; + if ((new->content_md5 & 2) == 0) conf->content_md5 = new->content_md5; + +#ifdef RLIMIT_CPU + if (new->limit_cpu) conf->limit_cpu = new->limit_cpu; +#endif +#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) + if (new->limit_mem) conf->limit_mem = new->limit_mem; +#endif +#ifdef RLIMIT_NPROC + if (new->limit_nproc) conf->limit_nproc = new->limit_nproc; +#endif + + conf->sec = append_arrays (a, base->sec, new->sec); + + if (new->satisfy != SATISFY_NOSPEC) conf->satisfy = new->satisfy; + return (void*)conf; +} + +void *create_core_server_config (pool *a, server_rec *s) +{ + core_server_config *conf = + (core_server_config *)pcalloc(a, sizeof(core_server_config)); + int is_virtual = s->is_virtual; + + conf->access_name = is_virtual ? NULL : DEFAULT_ACCESS_FNAME; + conf->document_root = is_virtual ? NULL : DOCUMENT_LOCATION; + conf->sec = make_array (a, 40, sizeof(void *)); + conf->sec_url = make_array (a, 40, sizeof(void *)); + + return (void *)conf; +} + +void *merge_core_server_configs (pool *p, void *basev, void *virtv) +{ + core_server_config *base = (core_server_config *)basev; + core_server_config *virt = (core_server_config *)virtv; + core_server_config *conf = + (core_server_config *)pcalloc(p, sizeof(core_server_config)); + + *conf = *virt; + if (!conf->access_name) conf->access_name = base->access_name; + if (!conf->document_root) conf->document_root = base->document_root; + conf->sec = append_arrays (p, virt->sec, base->sec); + conf->sec_url = append_arrays (p, virt->sec_url, base->sec_url); + + return conf; +} + +/* Add per-directory configuration entry (for <directory> section); + * these are part of the core server config. + */ + +void add_per_dir_conf (server_rec *s, void *dir_config) +{ + core_server_config *sconf = get_module_config (s->module_config, + &core_module); + void **new_space = (void **) push_array (sconf->sec); + + *new_space = dir_config; +} + +void add_per_url_conf (server_rec *s, void *url_config) +{ + core_server_config *sconf = get_module_config (s->module_config, + &core_module); + void **new_space = (void **) push_array (sconf->sec_url); + + *new_space = url_config; +} + +void add_file_conf (core_dir_config *conf, void *url_config) +{ + void **new_space = (void **) push_array (conf->sec); + + *new_space = url_config; +} + +/***************************************************************** + * + * There are some elements of the core config structures in which + * other modules have a legitimate interest (this is ugly, but necessary + * to preserve NCSA back-compatibility). So, we have a bunch of accessors + * here... + */ + +int allow_options (request_rec *r) +{ + core_dir_config *conf = + (core_dir_config *)get_module_config(r->per_dir_config, &core_module); + + return conf->opts; +} + +int allow_overrides (request_rec *r) +{ + core_dir_config *conf = + (core_dir_config *)get_module_config(r->per_dir_config, &core_module); + + return conf->override; +} + +char *auth_type (request_rec *r) +{ + core_dir_config *conf = + (core_dir_config *)get_module_config(r->per_dir_config, &core_module); + + return conf->auth_type; +} + +char *auth_name (request_rec *r) +{ + core_dir_config *conf = + (core_dir_config *)get_module_config(r->per_dir_config, &core_module); + + return conf->auth_name; +} + +char *default_type (request_rec *r) +{ + core_dir_config *conf = + (core_dir_config *)get_module_config(r->per_dir_config, &core_module); + + return conf->default_type ? conf->default_type : DEFAULT_TYPE; +} + +char *document_root (request_rec *r) /* Don't use this!!! */ +{ + core_server_config *conf = + (core_server_config *)get_module_config(r->server->module_config, + &core_module); + + return conf->document_root; +} + +array_header *requires (request_rec *r) +{ + core_dir_config *conf = + (core_dir_config *)get_module_config(r->per_dir_config, &core_module); + + return conf->requires; +} + +int satisfies (request_rec *r) +{ + core_dir_config *conf = + (core_dir_config *)get_module_config(r->per_dir_config, &core_module); + + return conf->satisfy; +} + +/* Should probably just get rid of this... the only code that cares is + * part of the core anyway (and in fact, it isn't publicised to other + * modules). + */ + +char *response_code_string (request_rec *r, int error_index) +{ + core_dir_config *conf = + (core_dir_config *)get_module_config(r->per_dir_config, &core_module); + + if( conf->response_code_strings == NULL ) { + return NULL; + } + return conf->response_code_strings[error_index]; +} + +const char * +get_remote_host(conn_rec *conn, void *dir_config, int type) +{ + struct in_addr *iaddr; + struct hostent *hptr; +#ifdef MAXIMUM_DNS + char **haddr; +#endif + core_dir_config *dir_conf = NULL; + +/* If we haven't checked the host name, and we want to */ + if (dir_config) + dir_conf = (core_dir_config *)get_module_config(dir_config, &core_module); + + if ((!dir_conf) || (type != REMOTE_NOLOOKUP && conn->remote_host == NULL && dir_conf->hostname_lookups)) + { +#ifdef STATUS + int old_stat = update_child_status(conn->child_num, + SERVER_BUSY_DNS, + (request_rec*)NULL); +#endif /* STATUS */ + iaddr = &(conn->remote_addr.sin_addr); + hptr = gethostbyaddr((char *)iaddr, sizeof(struct in_addr), AF_INET); + if (hptr != NULL) + { + conn->remote_host = pstrdup(conn->pool, (void *)hptr->h_name); + str_tolower (conn->remote_host); + +#ifdef MAXIMUM_DNS + /* Grrr. Check THAT name to make sure it's really the name of the addr. */ + /* Code from Harald Hanche-Olsen <hanche@imf.unit.no> */ + + hptr = gethostbyname(conn->remote_host); + if (hptr) + { + for(haddr=hptr->h_addr_list; *haddr; haddr++) + if(((struct in_addr *)(*haddr))->s_addr == iaddr->s_addr) + break; + } + if((!hptr) || (!(*haddr))) + conn->remote_host = NULL; +#endif + } +/* if failed, set it to the NULL string to indicate error */ + if (conn->remote_host == NULL) conn->remote_host = ""; +#ifdef STATUS + (void)update_child_status(conn->child_num,old_stat,(request_rec*)NULL); +#endif /* STATUS */ + } + +/* + * Return the desired information; either the remote DNS name, if found, + * or either NULL (if the hostname was requested) or the IP address + * (if any identifier was requested). + */ + if (conn->remote_host != NULL && conn->remote_host[0] != '\0') + return conn->remote_host; + else + { + if (type == REMOTE_HOST) return NULL; + else return conn->remote_ip; + } +} + +const char * +get_remote_logname(request_rec *r) +{ + core_dir_config *dir_conf; + + if (r->connection->remote_logname != NULL) + return r->connection->remote_logname; + +/* If we haven't checked the identity, and we want to */ + dir_conf = (core_dir_config *) + get_module_config(r->per_dir_config, &core_module); + + if (dir_conf->do_rfc1413 & 1) + return rfc1413(r->connection, r->server); + else + return NULL; +} + +/***************************************************************** + * + * Commands... this module handles almost all of the NCSA httpd.conf + * commands, but most of the old srm.conf is in the the modules. + */ + +const char *set_access_name (cmd_parms *cmd, void *dummy, char *arg) +{ + void *sconf = cmd->server->module_config; + core_server_config *conf = get_module_config (sconf, &core_module); + + conf->access_name = arg; + return NULL; +} + +const char *set_document_root (cmd_parms *cmd, void *dummy, char *arg) +{ + void *sconf = cmd->server->module_config; + core_server_config *conf = get_module_config (sconf, &core_module); + + if (!is_directory (arg)) + if (cmd->server->is_virtual) + fprintf (stderr, "Warning: DocumentRoot [%s] does not exist\n", arg); + else + return "DocumentRoot must be a directory"; + + conf->document_root = arg; + return NULL; +} + +const char *set_error_document (cmd_parms *cmd, core_dir_config *conf, + char *line) +{ + int error_number, index_number, idx500; + char *w; + + /* 1st parameter should be a 3 digit number, which we recognize; + * convert it into an array index + */ + + w = getword_conf_nc (cmd->pool, &line); + error_number = atoi(w); + + idx500 = index_of_response(HTTP_INTERNAL_SERVER_ERROR); + + if (error_number == HTTP_INTERNAL_SERVER_ERROR) + index_number = idx500; + else if ((index_number = index_of_response(error_number)) == idx500) + return pstrcat(cmd->pool, "Unsupported HTTP response code ", w, NULL); + + /* Store it... */ + + if( conf->response_code_strings == NULL ) { + conf->response_code_strings = pcalloc(cmd->pool, + sizeof(*conf->response_code_strings) * RESPONSE_CODES ); + } + conf->response_code_strings[index_number] = pstrdup (cmd->pool, line); + + return NULL; +} + +/* access.conf commands... + * + * The *only* thing that can appear in access.conf at top level is a + * <Directory> section. NB we need to have a way to cut the srm_command_loop + * invoked by dirsection (i.e., <Directory>) short when </Directory> is seen. + * We do that by returning an error, which dirsection itself recognizes and + * discards as harmless. Cheesy, but it works. + */ + +const char *set_override (cmd_parms *cmd, core_dir_config *d, const char *l) +{ + char *w; + + d->override = OR_NONE; + while(l[0]) { + w = getword_conf (cmd->pool, &l); + if(!strcasecmp(w,"Limit")) + d->override |= OR_LIMIT; + else if(!strcasecmp(w,"Options")) + d->override |= OR_OPTIONS; + else if(!strcasecmp(w,"FileInfo")) + d->override |= OR_FILEINFO; + else if(!strcasecmp(w,"AuthConfig")) + d->override |= OR_AUTHCFG; + else if(!strcasecmp(w,"Indexes")) + d->override |= OR_INDEXES; + else if(!strcasecmp(w,"None")) + d->override = OR_NONE; + else if(!strcasecmp(w,"All")) + d->override = OR_ALL; + else + return pstrcat (cmd->pool, "Illegal override option ", w, NULL); + } + + return NULL; +} + +const char *set_options (cmd_parms *cmd, core_dir_config *d, const char *l) +{ + char opt; + int first = 1; + char action; + + while(l[0]) { + char *w = getword_conf(cmd->pool, &l); + action = '\0'; + + if (*w == '+' || *w == '-') + action = *(w++); + else if (first) { + d->opts = OPT_NONE; + first = 0; + } + + if(!strcasecmp(w,"Indexes")) + opt = OPT_INDEXES; + else if(!strcasecmp(w,"Includes")) + opt = OPT_INCLUDES; + else if(!strcasecmp(w,"IncludesNOEXEC")) + opt = (OPT_INCLUDES | OPT_INCNOEXEC); + else if(!strcasecmp(w,"FollowSymLinks")) + opt = OPT_SYM_LINKS; + else if(!strcasecmp(w,"SymLinksIfOwnerMatch")) + opt = OPT_SYM_OWNER; + else if(!strcasecmp(w,"execCGI")) + opt = OPT_EXECCGI; + else if (!strcasecmp(w,"MultiViews")) + opt = OPT_MULTI; + else if (!strcasecmp(w,"RunScripts")) /* AI backcompat. Yuck */ + opt = OPT_MULTI|OPT_EXECCGI; + else if(!strcasecmp(w,"None")) + opt = OPT_NONE; + else if(!strcasecmp(w,"All")) + opt = OPT_ALL; + else + return pstrcat (cmd->pool, "Illegal option ", w, NULL); + + if (action == '-') + d->opts_remove |= opt; + else if (action == '+') + d->opts_add |= opt; + else + d->opts |= opt; + } + + return NULL; +} + +const char *satisfy (cmd_parms *cmd, core_dir_config *c, char *arg) +{ + if(!strcasecmp(arg,"all")) + c->satisfy = SATISFY_ALL; + else if(!strcasecmp(arg,"any")) + c->satisfy = SATISFY_ANY; + else + return "Satisfy either 'any' or 'all'."; + return NULL; +} + +const char *require (cmd_parms *cmd, core_dir_config *c, char *arg) +{ + require_line *r; + + if (!c->requires) + c->requires = make_array (cmd->pool, 2, sizeof(require_line)); + + r = (require_line *)push_array (c->requires); + r->requirement = pstrdup (cmd->pool, arg); + r->method_mask = cmd->limited; + return NULL; +} + +const char *limit (cmd_parms *cmd, void *dummy, const char *arg) +{ + const char *limited_methods = getword(cmd->pool,&arg,'>'); + int limited = 0; + + if (cmd->limited > 0) return "Can't nest <Limit> sections"; + + while(limited_methods[0]) { + char *method = getword_conf (cmd->pool, &limited_methods); + if(!strcasecmp(method,"GET")) limited |= (1 << M_GET); + else if(!strcasecmp(method,"PUT")) limited |= (1 << M_PUT); + else if(!strcasecmp(method,"POST")) limited |= (1 << M_POST); + else if(!strcasecmp(method,"DELETE")) limited |= (1 << M_DELETE); + else if(!strcasecmp(method,"CONNECT")) limited |= (1 << M_CONNECT); + else if(!strcasecmp(method,"OPTIONS")) limited |= (1 << M_OPTIONS); + else return "unknown method in <Limit>"; + } + + cmd->limited = limited; + return NULL; +} + +const char *endlimit (cmd_parms *cmd, void *dummy, void *dummy2) +{ + if (cmd->limited == -1) return "</Limit> unexpected"; + + cmd->limited = -1; + return NULL; +} + +static const char end_dir_magic[] = "</Directory> outside of any <Directory> section"; + +const char *end_dirsection (cmd_parms *cmd, void *dummy) { + return end_dir_magic; +} + +const char *dirsection (cmd_parms *cmd, void *dummy, const char *arg) +{ + const char *errmsg; + char *endp = strrchr (arg, '>'); + int old_overrides = cmd->override; + char *old_path = cmd->path; + core_dir_config *conf; + void *new_dir_conf = create_per_dir_config (cmd->pool); + regex_t *r = NULL; + + if (endp) *endp = '\0'; + + if (cmd->path) return "<Directory> sections don't nest"; + if (cmd->limited != -1) return "Can't have <Directory> within <Limit>"; + + cmd->path = getword_conf (cmd->pool, &arg); +#ifdef __EMX__ + /* Fix OS/2 HPFS filename case problem. */ + cmd->path = strlwr(cmd->path); +#endif + cmd->override = OR_ALL|ACCESS_CONF; + + if (!strcmp(cmd->path, "~")) { + cmd->path = getword_conf (cmd->pool, &arg); + r = pregcomp(cmd->pool, cmd->path, REG_EXTENDED); + } + + errmsg = srm_command_loop (cmd, new_dir_conf); + if (errmsg != end_dir_magic) return errmsg; + + conf = (core_dir_config *)get_module_config(new_dir_conf, &core_module); + conf->r = r; + + add_per_dir_conf (cmd->server, new_dir_conf); + + cmd->path = old_path; + cmd->override = old_overrides; + + return NULL; +} + +static const char end_url_magic[] = "</Location> outside of any <Location> section"; + +const char *end_urlsection (cmd_parms *cmd, void *dummy) { + return end_url_magic; +} + +const char *urlsection (cmd_parms *cmd, void *dummy, const char *arg) +{ + const char *errmsg; + char *endp = strrchr (arg, '>'); + int old_overrides = cmd->override; + char *old_path = cmd->path; + core_dir_config *conf; + regex_t *r = NULL; + + void *new_url_conf = create_per_dir_config (cmd->pool); + + if (endp) *endp = '\0'; + + if (cmd->path) return "<Location> sections don't nest"; + if (cmd->limited != -1) return "Can't have <Location> within <Limit>"; + + cmd->path = getword_conf (cmd->pool, &arg); + cmd->override = OR_ALL|ACCESS_CONF; + + if (!strcmp(cmd->path, "~")) { + cmd->path = getword_conf (cmd->pool, &arg); + r = pregcomp(cmd->pool, cmd->path, REG_EXTENDED); + } + + errmsg = srm_command_loop (cmd, new_url_conf); + if (errmsg != end_url_magic) return errmsg; + + conf = (core_dir_config *)get_module_config(new_url_conf, &core_module); + conf->d = pstrdup(cmd->pool, cmd->path); /* No mangling, please */ + conf->d_is_matchexp = is_matchexp( conf->d ); + conf->r = r; + + add_per_url_conf (cmd->server, new_url_conf); + + cmd->path = old_path; + cmd->override = old_overrides; + + return NULL; +} + +static char *end_file_magic = "</Files> outside of any <Files> section"; + +const char *end_filesection (cmd_parms *cmd, void *dummy) { + return end_file_magic; +} + +const char *filesection (cmd_parms *cmd, core_dir_config *c, const char *arg) +{ + const char *errmsg; + char *endp = strrchr (arg, '>'); + int old_overrides = cmd->override; + char *old_path = cmd->path; + core_dir_config *conf; + regex_t *r = NULL; + + void *new_file_conf = create_per_dir_config (cmd->pool); + + if (endp) *endp = '\0'; + + if (cmd->limited != -1) return "Can't have <Files> within <Limit>"; + + cmd->path = getword_conf (cmd->pool, &arg); + /* Only if not an .htaccess file */ + if (cmd->path) + cmd->override = OR_ALL|ACCESS_CONF; + + if (!strcmp(cmd->path, "~")) { + cmd->path = getword_conf (cmd->pool, &arg); + if (old_path && cmd->path[0] != '/' && cmd->path[0] != '^') + cmd->path = pstrcat(cmd->pool, "^", old_path, cmd->path, NULL); + r = pregcomp(cmd->pool, cmd->path, REG_EXTENDED); + } + else if (old_path && cmd->path[0] != '/') + cmd->path = pstrcat(cmd->pool, old_path, cmd->path, NULL); + + errmsg = srm_command_loop (cmd, new_file_conf); + if (errmsg != end_file_magic) return errmsg; + + conf = (core_dir_config *)get_module_config(new_file_conf, &core_module); + conf->d = pstrdup(cmd->pool, cmd->path); + conf->d_is_matchexp = is_matchexp( conf->d ); + conf->r = r; + + add_file_conf (c, new_file_conf); + + cmd->path = old_path; + cmd->override = old_overrides; + + return NULL; +} + +const char *end_ifmod (cmd_parms *cmd, void *dummy) { + return NULL; +} + +const char *start_ifmod (cmd_parms *cmd, void *dummy, char *arg) +{ + char *endp = strrchr (arg, '>'); + char l[MAX_STRING_LEN]; + int not = (arg[0] == '!'); + module *found; + int nest = 1; + + if (endp) *endp = '\0'; + if (not) arg++; + + found = find_linked_module(arg); + + if ((!not && found) || (not && !found)) + return NULL; + + while (nest && !(cfg_getline (l, MAX_STRING_LEN, cmd->infile))) { + if (!strncasecmp(l, "<IfModule", 9)) + nest++; + if (!strcasecmp(l, "</IfModule>")) + nest--; + } + + return NULL; +} + +/* httpd.conf commands... beginning with the <VirtualHost> business */ + +const char end_virthost_magic[] = "</Virtualhost> out of place"; + +const char *end_virtualhost_section (cmd_parms *cmd, void *dummy) +{ + return end_virthost_magic; +} + +const char *virtualhost_section (cmd_parms *cmd, void *dummy, char *arg) +{ + server_rec *main_server = cmd->server, *s; + const char *errmsg; + char *endp = strrchr (arg, '>'); + pool *p = cmd->pool, *ptemp = cmd->temp_pool; + + if (endp) *endp = '\0'; + + /* FIXME: There's another feature waiting to happen here -- since you + can now put multiple addresses/names on a single <VirtualHost> + you might want to use it to group common definitions and then + define other "subhosts" with their individual differences. But + personally I'd rather just do it with a macro preprocessor. -djg */ + if (main_server->is_virtual) + return "<VirtualHost> doesn't nest!"; + + s = init_virtual_host (p, arg, main_server); + s->next = main_server->next; + main_server->next = s; + + cmd->server = s; + errmsg = srm_command_loop (cmd, s->lookup_defaults); + cmd->server = main_server; + + if (s->srm_confname) + process_resource_config (s, s->srm_confname, p, ptemp); + + if (s->access_confname) + process_resource_config (s, s->access_confname, p, ptemp); + + if (errmsg == end_virthost_magic) return NULL; + return errmsg; +} + +const char *add_module_command (cmd_parms *cmd, void *dummy, char *arg) +{ + if (add_named_module (arg)) + return NULL; + return "required module not found"; +} + +const char *clear_module_list_command (cmd_parms *cmd, void *dummy) +{ + clear_module_list (); + return NULL; +} + +const char *set_server_string_slot (cmd_parms *cmd, void *dummy, char *arg) +{ + /* This one's pretty generic... */ + + int offset = (int)cmd->info; + char *struct_ptr = (char *)cmd->server; + + *(char **)(struct_ptr + offset) = pstrdup (cmd->pool, arg); + return NULL; +} + +const char *server_type (cmd_parms *cmd, void *dummy, char *arg) +{ + if (!strcasecmp (arg, "inetd")) standalone = 0; + else if (!strcasecmp (arg, "standalone")) standalone = 1; + else return "ServerType must be either 'inetd' or 'standalone'"; + + return NULL; +} + +const char *server_port (cmd_parms *cmd, void *dummy, char *arg) { + cmd->server->port = atoi (arg); + return NULL; +} + +const char *set_send_buffer_size (cmd_parms *cmd, void *dummy, char *arg) { + int s = atoi (arg); + if (s < 512 && s != 0) { + return "SendBufferSize must be >= 512 bytes, or 0 for system default."; + } + cmd->server->send_buffer_size = s; + return NULL; +} + +const char *set_user (cmd_parms *cmd, void *dummy, char *arg) +{ + if (!cmd->server->is_virtual) { + user_name = pstrdup (cmd->pool, arg); + cmd->server->server_uid = user_id = uname2id(arg); + } + else { + if (suexec_enabled) + cmd->server->server_uid = uname2id(arg); + else { + cmd->server->server_uid = user_id; + fprintf(stderr, + "Warning: User directive in <VirtualHost> requires SUEXEC wrapper.\n"); + } + } + + return NULL; +} + +const char *set_group (cmd_parms *cmd, void *dummy, char *arg) +{ + if (!cmd->server->is_virtual) + cmd->server->server_gid = group_id = gname2id(arg); + else { + if (suexec_enabled) + cmd->server->server_gid = gname2id(arg); + else { + cmd->server->server_gid = group_id; + fprintf(stderr, + "Warning: Group directive in <VirtualHost> requires SUEXEC wrapper.\n"); + } + } + + return NULL; +} + +const char *set_server_root (cmd_parms *cmd, void *dummy, char *arg) { + if (!is_directory (arg)) return "ServerRoot must be a valid directory"; + strncpy (server_root, arg, sizeof(server_root)-1); + server_root[sizeof(server_root)-1] = '\0'; + return NULL; +} + +const char *set_timeout (cmd_parms *cmd, void *dummy, char *arg) { + cmd->server->timeout = atoi (arg); + return NULL; +} + +const char *set_keep_alive_timeout (cmd_parms *cmd, void *dummy, char *arg) { + cmd->server->keep_alive_timeout = atoi (arg); + return NULL; +} + +const char *set_keep_alive (cmd_parms *cmd, void *dummy, char *arg) { + /* We've changed it to On/Off, but used to use numbers + * so we accept anything but "Off" or "0" as "On" + */ + if (!strcasecmp(arg, "off") || !strcmp(arg, "0")) + cmd->server->keep_alive = 0; + else + cmd->server->keep_alive = 1; + return NULL; +} + +const char *set_keep_alive_max (cmd_parms *cmd, void *dummy, char *arg) { + cmd->server->keep_alive_max = atoi (arg); + return NULL; +} + +const char *set_pidfile (cmd_parms *cmd, void *dummy, char *arg) { + pid_fname = pstrdup (cmd->pool, arg); + return NULL; +} + +const char *set_scoreboard (cmd_parms *cmd, void *dummy, char *arg) { + scoreboard_fname = pstrdup (cmd->pool, arg); + return NULL; +} + +const char *set_idcheck (cmd_parms *cmd, core_dir_config *d, int arg) { + d->do_rfc1413 = arg; + return NULL; +} + +const char *set_hostname_lookups (cmd_parms *cmd, core_dir_config *d, int arg) +{ + d->hostname_lookups = arg; + return NULL; +} + +const char *set_serverpath (cmd_parms *cmd, void *dummy, char *arg) { + cmd->server->path = pstrdup (cmd->pool, arg); + cmd->server->pathlen = strlen (arg); + return NULL; +} + +const char *set_content_md5 (cmd_parms *cmd, core_dir_config *d, int arg) { + d->content_md5 = arg; + return NULL; +} + +const char *set_daemons_to_start (cmd_parms *cmd, void *dummy, char *arg) { + daemons_to_start = atoi (arg); + return NULL; +} + +const char *set_min_free_servers (cmd_parms *cmd, void *dummy, char *arg) { + daemons_min_free = atoi (arg); + if (daemons_min_free <= 0) { + fprintf(stderr, "WARNING: detected MinSpareServers set to non-positive.\n"); + fprintf(stderr, "Resetting to 1 to avoid almost certain Apache failure.\n"); + fprintf(stderr, "Please read the documentation.\n"); + daemons_min_free = 1; + } + + return NULL; +} + +const char *set_max_free_servers (cmd_parms *cmd, void *dummy, char *arg) { + daemons_max_free = atoi (arg); + return NULL; +} + +const char *set_server_limit (cmd_parms *cmd, void *dummy, char *arg) { + daemons_limit = atoi (arg); + if (daemons_limit > HARD_SERVER_LIMIT) { + fprintf(stderr, "WARNING: Compile-time limit of %d servers\n", + HARD_SERVER_LIMIT); + fprintf(stderr, " Adjusting as required (to increase, please read\n"); + fprintf(stderr, " the documentation)\n"); + daemons_limit = HARD_SERVER_LIMIT; + } else if (daemons_limit < 1) { + fprintf (stderr, "WARNING: Require MaxClients > 0, setting to 1\n"); + daemons_limit = 1; + } + return NULL; +} + +const char *set_max_requests (cmd_parms *cmd, void *dummy, char *arg) { + max_requests_per_child = atoi (arg); + return NULL; +} + +#if defined(RLIMIT_CPU) || defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_NPROC) +static void set_rlimit(cmd_parms *cmd, struct rlimit **plimit, const char *arg, + const char * arg2, int type) +{ + char *str; + struct rlimit *limit; + /* If your platform doesn't define rlim_t then typedef it in conf.h */ + rlim_t cur = 0; + rlim_t max = 0; + + *plimit=(struct rlimit *)pcalloc(cmd->pool,sizeof **plimit); + limit=*plimit; + if ((getrlimit(type, limit)) != 0) + { + *plimit = NULL; + log_unixerr("getrlimit",cmd->cmd->name,"failed",cmd->server); + return; + } + + if ((str = getword_conf(cmd->pool, &arg))) + if (!strcasecmp(str, "max")) + cur = limit->rlim_max; + else + cur = atol(str); + else { + log_printf(cmd->server, "Invalid parameters for %s", cmd->cmd->name); + return; + } + + if (arg2 && (str = getword_conf(cmd->pool, &arg2))) + max = atol(str); + + /* if we aren't running as root, cannot increase max */ + if (geteuid()) { + limit->rlim_cur = cur; + if (max) + log_printf(cmd->server, "Must be uid 0 to raise maximum %s", + cmd->cmd->name); + } + else { + if (cur) + limit->rlim_cur = cur; + if (max) + limit->rlim_max = max; + } +} +#endif + +#if !defined (RLIMIT_CPU) || !(defined (RLIMIT_DATA) || defined (RLIMIT_VMEM)) || !defined (RLIMIT_NPROC) +static const char *no_set_limit (cmd_parms *cmd, core_dir_config *conf, + char *arg, char *arg2) +{ + log_printf(cmd->server, "%s not supported on this platform", + cmd->cmd->name); + return NULL; +} +#endif + +#ifdef RLIMIT_CPU +const char *set_limit_cpu (cmd_parms *cmd, core_dir_config *conf, char *arg, char *arg2) +{ + set_rlimit(cmd,&conf->limit_cpu,arg,arg2,RLIMIT_CPU); + return NULL; +} +#endif + +#if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) +const char *set_limit_mem (cmd_parms *cmd, core_dir_config *conf, char *arg, char * arg2) +{ +#ifdef RLIMIT_DATA + set_rlimit(cmd,&conf->limit_mem,arg,arg2,RLIMIT_DATA); +#else + set_rlimit(cmd,&conf->limit_mem,arg,arg2,RLIMIT_VMEM); +#endif + return NULL; +} +#endif + +#ifdef RLIMIT_NPROC +const char *set_limit_nproc (cmd_parms *cmd, core_dir_config *conf, char *arg, char * arg2) +{ + set_rlimit(cmd,&conf->limit_nproc,arg,arg2,RLIMIT_NPROC); + return NULL; +} +#endif + +const char *set_bind_address (cmd_parms *cmd, void *dummy, char *arg) { + bind_address.s_addr = get_virthost_addr (arg, NULL); + return NULL; +} + +const char *set_listener(cmd_parms *cmd, void *dummy, char *ips) +{ + listen_rec *new; + char *ports; + unsigned port; + + if (cmd->server->is_virtual) return "Listen not allowed in <VirtualHost>"; + ports=strchr(ips, ':'); + if (ports != NULL) + { + if (ports == ips) return "Missing IP address"; + else if (ports[0] == '\0') + return "Address must end in :<port-number>"; + *(ports++) = '\0'; + } else + ports = ips; + + new=pcalloc(cmd->pool, sizeof(listen_rec)); + new->local_addr.sin_family = AF_INET; + if (ports == ips) /* no address */ + new->local_addr.sin_addr.s_addr = htonl(INADDR_ANY); + else + new->local_addr.sin_addr.s_addr = get_virthost_addr(ips, NULL); + port=atoi(ports); + if(!port) + return "Port must be numeric"; + new->local_addr.sin_port = htons(port); + new->fd = -1; + new->used = 0; + new->next = listeners; + listeners = new; + return NULL; +} + +/* Note --- ErrorDocument will now work from .htaccess files. + * The AllowOverride of Fileinfo allows webmasters to turn it off + */ + +command_rec core_cmds[] = { + +/* Old access config file commands */ + +{ "<Directory", dirsection, NULL, RSRC_CONF, RAW_ARGS, "Container for directives affecting resources located in the specified directories" }, +{ "</Directory>", end_dirsection, NULL, ACCESS_CONF, NO_ARGS, NULL }, +{ "<Location", urlsection, NULL, RSRC_CONF, RAW_ARGS, "Container for directives affecting resources accessed through the specified URL paths" }, +{ "</Location>", end_urlsection, NULL, ACCESS_CONF, NO_ARGS, NULL }, +{ "<VirtualHost", virtualhost_section, NULL, RSRC_CONF, RAW_ARGS, "Container to map directives to a particular virtual host" }, +{ "</VirtualHost>", end_virtualhost_section, NULL, RSRC_CONF, NO_ARGS, NULL }, +{ "<Files", filesection, NULL, OR_ALL, RAW_ARGS, "Container for directives affecting files matching specified patterns" }, +{ "</Files>", end_filesection, NULL, OR_ALL, NO_ARGS, NULL }, +{ "<Limit", limit, NULL, OR_ALL, RAW_ARGS, "Container for authentication directives when accessed using specified HTTP methods" }, +{ "</Limit>", endlimit, NULL, OR_ALL, RAW_ARGS, NULL }, +{ "<IfModule", start_ifmod, NULL, OR_ALL, RAW_ARGS, "Container for directives based on existance of specified modules" }, +{ "</IfModule>", end_ifmod, NULL, OR_ALL, NO_ARGS, NULL }, +{ "AuthType", set_string_slot, (void*)XtOffsetOf(core_dir_config, auth_type), + OR_AUTHCFG, TAKE1, "An HTTP authorization type (e.g., \"Basic\")" }, +{ "AuthName", set_string_slot, (void*)XtOffsetOf(core_dir_config, auth_name), + OR_AUTHCFG, RAW_ARGS, "The authentication realm (e.g. \"Members Only\")" }, +{ "Require", require, NULL, OR_AUTHCFG, RAW_ARGS, "Selects which authenticated users or groups may access a protected space" }, +{ "Satisfy", satisfy, NULL, OR_AUTHCFG, TAKE1, + "access policy if both allow and require used ('all' or 'any')" }, + +/* Old resource config file commands */ + +{ "AccessFileName", set_access_name, NULL, RSRC_CONF, TAKE1, "Name of per-directory config files (default: .htaccess)" }, +{ "DocumentRoot", set_document_root, NULL, RSRC_CONF, TAKE1, "Root directory of the document tree" }, +{ "ErrorDocument", set_error_document, NULL, OR_FILEINFO, RAW_ARGS, "Change responses for HTTP errors" }, +{ "AllowOverride", set_override, NULL, ACCESS_CONF, RAW_ARGS, "Controls what groups of directives can be configured by per-directory config files" }, +{ "Options", set_options, NULL, OR_OPTIONS, RAW_ARGS, "Set a number of attributes for a given directory" }, +{ "DefaultType", set_string_slot, + (void*)XtOffsetOf (core_dir_config, default_type), + OR_FILEINFO, TAKE1, "the default MIME type for untypable files" }, + +/* Old server config file commands */ + +{ "ServerType", server_type, NULL, RSRC_CONF, TAKE1,"'inetd' or 'standalone'"}, +{ "Port", server_port, NULL, RSRC_CONF, TAKE1, "A TCP port number"}, +{ "HostnameLookups", set_hostname_lookups, NULL, ACCESS_CONF|RSRC_CONF, FLAG, "\"on\" to enable or \"off\" to disable reverse DNS lookups" }, +{ "User", set_user, NULL, RSRC_CONF, TAKE1, "Effective user id for this server"}, +{ "Group", set_group, NULL, RSRC_CONF, TAKE1, "Effective group id for this server"}, +{ "ServerAdmin", set_server_string_slot, + (void *)XtOffsetOf (server_rec, server_admin), RSRC_CONF, TAKE1, + "The email address of the server administrator" }, +{ "ServerName", set_server_string_slot, + (void *)XtOffsetOf (server_rec, server_hostname), RSRC_CONF, TAKE1, + "The hostname of the server" }, +{ "ServerRoot", set_server_root, NULL, RSRC_CONF, TAKE1, "Common directory of server-related files (logs, confs, etc)" }, +{ "ErrorLog", set_server_string_slot, + (void *)XtOffsetOf (server_rec, error_fname), RSRC_CONF, TAKE1, + "The filename of the error log" }, +{ "PidFile", set_pidfile, NULL, RSRC_CONF, TAKE1, + "A file for logging the server process ID"}, +{ "ScoreBoardFile", set_scoreboard, NULL, RSRC_CONF, TAKE1, + "A file for Apache to maintain runtime process management information"}, +{ "AccessConfig", set_server_string_slot, + (void *)XtOffsetOf (server_rec, access_confname), RSRC_CONF, TAKE1, + "The filename of the access config file" }, +{ "ResourceConfig", set_server_string_slot, + (void *)XtOffsetOf (server_rec, srm_confname), RSRC_CONF, TAKE1, + "The filename of the resource config file" }, +{ "ServerAlias", set_server_string_slot, + (void *)XtOffsetOf (server_rec, names), RSRC_CONF, RAW_ARGS, + "A name or names alternately used to access the server" }, +{ "ServerPath", set_serverpath, NULL, RSRC_CONF, TAKE1, + "The pathname the server can be reached at" }, +{ "Timeout", set_timeout, NULL, RSRC_CONF, TAKE1, "Timeout duration (sec)"}, +{ "KeepAliveTimeout", set_keep_alive_timeout, NULL, RSRC_CONF, TAKE1, "Keep-Alive timeout duration (sec)"}, +{ "MaxKeepAliveRequests", set_keep_alive_max, NULL, RSRC_CONF, TAKE1, "Maximum number of Keep-Alive requests per connection, or 0 for infinite" }, +{ "KeepAlive", set_keep_alive, NULL, RSRC_CONF, TAKE1, "Whether persistent connections should be On or Off" }, +{ "IdentityCheck", set_idcheck, NULL, RSRC_CONF|ACCESS_CONF, FLAG, "Enable identd (RFC 1413) user lookups - SLOW" }, +{ "ContentDigest", set_content_md5, NULL, RSRC_CONF|ACCESS_CONF|OR_AUTHCFG, FLAG, "whether or not to send a Content-MD5 header with each request" }, +{ "StartServers", set_daemons_to_start, NULL, RSRC_CONF, TAKE1, "Number of child processes launched at server startup" }, +{ "MinSpareServers", set_min_free_servers, NULL, RSRC_CONF, TAKE1, "Minimum number of idle children, to handle request spikes" }, +{ "MaxSpareServers", set_max_free_servers, NULL, RSRC_CONF, TAKE1, "Maximum number of idle children" }, +{ "MaxServers", set_max_free_servers, NULL, RSRC_CONF, TAKE1, "Deprecated equivalent to MaxSpareServers" }, +{ "ServersSafetyLimit", set_server_limit, NULL, RSRC_CONF, TAKE1, "Deprecated equivalent to MaxClients" }, +{ "MaxClients", set_server_limit, NULL, RSRC_CONF, TAKE1, "Maximum number of children alive at the same time" }, +{ "MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, TAKE1, "Maximum number of requests a particular child serves before dying." }, +{ "RLimitCPU", +#ifdef RLIMIT_CPU + set_limit_cpu, (void*)XtOffsetOf(core_dir_config, limit_cpu), +#else + no_set_limit, NULL, +#endif + OR_ALL, TAKE12, "soft/hard limits for max CPU usage in seconds" }, +{ "RLimitMEM", +#if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) + set_limit_mem, (void*)XtOffsetOf(core_dir_config, limit_mem), +#else + no_set_limit, NULL, +#endif + OR_ALL, TAKE12, "soft/hard limits for max memory usage per process" }, +{ "RLimitNPROC", +#ifdef RLIMIT_NPROC + set_limit_nproc, (void*)XtOffsetOf(core_dir_config, limit_nproc), +#else + no_set_limit, NULL, +#endif + OR_ALL, TAKE12, "soft/hard limits for max number of processes per uid" }, +{ "BindAddress", set_bind_address, NULL, RSRC_CONF, TAKE1, + "'*', a numeric IP address, or the name of a host with a unique IP address"}, +{ "Listen", set_listener, NULL, RSRC_CONF, TAKE1, + "a port number or a numeric IP address and a port number"}, +{ "SendBufferSize", set_send_buffer_size, NULL, RSRC_CONF, TAKE1, "send buffer size in bytes"}, +{ "AddModule", add_module_command, NULL, RSRC_CONF, ITERATE, + "the name of a module" }, +{ "ClearModuleList", clear_module_list_command, NULL, RSRC_CONF, NO_ARGS, NULL }, +{ NULL }, +}; + +/***************************************************************** + * + * Core handlers for various phases of server operation... + */ + +int core_translate (request_rec *r) +{ + void *sconf = r->server->module_config; + core_server_config *conf = get_module_config (sconf, &core_module); + + if (r->proxyreq) return HTTP_FORBIDDEN; + if ((r->uri[0] != '/') && strcmp(r->uri, "*")) { + log_printf(r->server, "Invalid URI in request %s", r->the_request); + return BAD_REQUEST; + } + + if (r->server->path && + !strncmp(r->uri, r->server->path, r->server->pathlen) && + (r->server->path[r->server->pathlen - 1] == '/' || + r->uri[r->server->pathlen] == '/' || + r->uri[r->server->pathlen] == '\0')) + r->filename = pstrcat (r->pool, conf->document_root, + (r->uri + r->server->pathlen), NULL); + else + r->filename = pstrcat (r->pool, conf->document_root, r->uri, NULL); + + return OK; +} + +int do_nothing (request_rec *r) { return OK; } + +/* + * Default handler for MIME types without other handlers. Only GET + * and OPTIONS at this point... anyone who wants to write a generic + * handler for PUT or POST is free to do so, but it seems unwise to provide + * any defaults yet... So, for now, we assume that this will always be + * the last handler called and return 405 or 501. + */ + +int default_handler (request_rec *r) +{ + core_dir_config *d = + (core_dir_config *)get_module_config(r->per_dir_config, &core_module); + int rangestatus, errstatus; + FILE *f; + + r->allowed |= (1 << M_GET); + r->allowed |= (1 << M_TRACE); + r->allowed |= (1 << M_OPTIONS); + + if (r->method_number == M_INVALID) { + log_printf(r->server, "Invalid method in request %s", r->the_request); + return NOT_IMPLEMENTED; + } + if (r->method_number == M_OPTIONS) return send_http_options(r); + if (r->method_number == M_PUT) return METHOD_NOT_ALLOWED; + + if (r->finfo.st_mode == 0 || (r->path_info && *r->path_info)) { + log_reason("File does not exist", + r->path_info ? pstrcat(r->pool, r->filename, r->path_info, NULL) + : r->filename, r); + return NOT_FOUND; + } + if (r->method_number != M_GET) return METHOD_NOT_ALLOWED; + +#ifdef __EMX__ + /* Need binary mode for OS/2 */ + f = pfopen (r->pool, r->filename, "rb"); +#else + f = pfopen (r->pool, r->filename, "r"); +#endif + + if (f == NULL) { + log_reason("file permissions deny server access", r->filename, r); + return FORBIDDEN; + } + + if ((errstatus = set_last_modified (r, r->finfo.st_mtime)) + || (errstatus = set_content_length (r, r->finfo.st_size))) + return errstatus; + + if (d->content_md5 & 1) { + table_set (r->headers_out, "Content-MD5", md5digest(r->pool, f)); + } + + rangestatus = set_byterange(r); + send_http_header (r); + + if (!r->header_only) { + if (!rangestatus) + send_fd (f, r); + else { + long offset, length; + while (each_byterange(r, &offset, &length)) { + fseek(f, offset, SEEK_SET); + send_fd_length(f, r, length); + } + } + } + + pfclose(r->pool, f); + return OK; +} + +handler_rec core_handlers[] = { +{ "*/*", default_handler }, +{ NULL } +}; + +module core_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + create_core_dir_config, /* create per-directory config structure */ + merge_core_dir_configs, /* merge per-directory config structures */ + create_core_server_config, /* create per-server config structure */ + merge_core_server_configs, /* merge per-server config structures */ + core_cmds, /* command table */ + core_handlers, /* handlers */ + core_translate, /* translate_handler */ + NULL, /* check_user_id */ + NULL, /* check auth */ + do_nothing, /* check access */ + do_nothing, /* type_checker */ + NULL, /* pre-run fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/main/http_log.c b/APACHE_1_2_X/src/main/http_log.c new file mode 100644 index 00000000000..896c0a8dc59 --- /dev/null +++ b/APACHE_1_2_X/src/main/http_log.c @@ -0,0 +1,197 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +/* + * http_log.c: Dealing with the logs and errors + * + * Rob McCool + * + */ + + +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_log.h" + +#include <stdarg.h> + +void error_log_child (void *cmd) +{ + /* Child process code for 'ErrorLog "|..."'; + * may want a common framework for this, since I expect it will + * be common for other foo-loggers to want this sort of thing... + */ + + cleanup_for_exec(); + signal (SIGHUP, SIG_IGN); +#ifdef __EMX__ + /* For OS/2 we need to use a '/' */ + execl (SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); +#else + execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL); +#endif + exit (1); +} + +void open_error_log(server_rec *s, pool *p) +{ + char *fname; + + fname = server_root_relative (p, s->error_fname); + + if (*s->error_fname == '|') { + FILE *dummy; + + if (!spawn_child (p, error_log_child, (void *)(s->error_fname+1), + kill_after_timeout, &dummy, NULL)) { + perror ("spawn_child"); + fprintf (stderr, "Couldn't fork child for ErrorLog process\n"); + exit (1); + } + + s->error_log = dummy; + } else { + if(!(s->error_log = pfopen(p, fname, "a"))) { + perror("fopen"); + fprintf(stderr,"httpd: could not open error log file %s.\n", fname); + exit(1); + } + } +} + +void open_logs (server_rec *s_main, pool *p) +{ + server_rec *virt, *q; + + open_error_log (s_main, p); + + for (virt = s_main->next; virt; virt = virt->next) { + if (virt->error_fname) + { + for (q=s_main; q != virt; q = q->next) + if (q->error_fname != NULL && + strcmp(q->error_fname, virt->error_fname) == 0) + break; + if (q == virt) open_error_log (virt, p); + else virt->error_log = q->error_log; + } + else + virt->error_log = s_main->error_log; + } +} + +void error_log2stderr(server_rec *s) { + if(fileno(s->error_log) != STDERR_FILENO) + dup2(fileno(s->error_log),STDERR_FILENO); +} + +void log_pid(pool *p, char *pid_fname) { + FILE *pid_file; + + if (!pid_fname) return; + pid_fname = server_root_relative (p, pid_fname); + if(!(pid_file = fopen(pid_fname,"w"))) { + perror("fopen"); + fprintf(stderr,"httpd: could not log pid to file %s\n", pid_fname); + exit(1); + } + fprintf(pid_file,"%ld\n",(long)getpid()); + fclose(pid_file); +} + +void log_error(char *err, server_rec *s) { + fprintf(s->error_log, "[%s] %s\n",get_time(),err); + fflush(s->error_log); +} + +void +log_unixerr(const char *routine, const char *file, const char *msg, + server_rec *s) +{ + const char *p, *q; + + p = strerror(errno); + q = get_time(); + + if (file != NULL) + fprintf(s->error_log, "[%s] %s: %s: %s\n", q, routine, file, p); + else + fprintf(s->error_log, "[%s] %s: %s\n", q, routine, p); + if (msg != NULL) fprintf(s->error_log, "[%s] - %s\n", q, msg); + + fflush(s->error_log); +} + +void +log_printf(const server_rec *s, const char *fmt, ...) +{ + va_list args; + + fprintf(s->error_log, "[%s] ", get_time()); + va_start (args, fmt); + vfprintf (s->error_log, fmt, args); + va_end (args); + + fputc('\n', s->error_log); + fflush(s->error_log); +} + +void log_reason(const char *reason, const char *file, request_rec *r) { + fprintf (r->server->error_log, + "[%s] access to %s failed for %s, reason: %s\n", + get_time(), file, + get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME), + reason); + fflush (r->server->error_log); +} + diff --git a/APACHE_1_2_X/src/main/http_main.c b/APACHE_1_2_X/src/main/http_main.c new file mode 100644 index 00000000000..20ef2bba263 --- /dev/null +++ b/APACHE_1_2_X/src/main/http_main.c @@ -0,0 +1,2518 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +/* + * httpd.c: simple http daemon for answering WWW file requests + * + * + * 03-21-93 Rob McCool wrote original code (up to NCSA HTTPd 1.3) + * + * 03-06-95 blong + * changed server number for child-alone processes to 0 and changed name + * of processes + * + * 03-10-95 blong + * Added numerous speed hacks proposed by Robert S. Thau (rst@ai.mit.edu) + * including set group before fork, and call gettime before to fork + * to set up libraries. + * + * 04-14-95 rst / rh + * Brandon's code snarfed from NCSA 1.4, but tinkered to work with the + * Apache server, and also to have child processes do accept() directly. + * + * April-July '95 rst + * Extensive rework for Apache. + */ + +#define CORE_PRIVATE + +#include "httpd.h" +#include "http_main.h" +#include "http_log.h" +#include "http_config.h" /* for read_config */ +#include "http_protocol.h" /* for read_request */ +#include "http_request.h" /* for process_request */ +#include "http_conf_globals.h" +#include "http_core.h" /* for get_remote_host */ +#include "scoreboard.h" +#include <assert.h> +#include <sys/stat.h> +#ifdef HAVE_SHMGET +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#endif +#ifdef SecureWare +#include <sys/security.h> +#include <sys/audit.h> +#include <prot.h> +#endif +#include <netinet/tcp.h> + +#ifdef HAVE_BSTRING_H +#include <bstring.h> /* for IRIX, FD_SET calls bzero() */ +#endif + +#include "explain.h" + +#if !defined(max) +#define max(a,b) (a > b ? a : b) +#endif + +#ifdef __EMX__ + /* Add MMAP style functionality to OS/2 */ + #ifdef HAVE_MMAP + #define INCL_DOSMEMMGR + #include <os2.h> + #include <umalloc.h> + #include <stdio.h> + caddr_t create_shared_heap (const char *, size_t); + caddr_t get_shared_heap (const char *); + #endif +#endif + + +DEF_Explain + +/* + * Actual definitions of config globals... here because this is + * for the most part the only code that acts on 'em. (Hmmm... mod_main.c?) + */ + +int standalone; +uid_t user_id; +char *user_name; +gid_t group_id; +#ifdef MULTIPLE_GROUPS +gid_t group_id_list[NGROUPS_MAX]; +#endif +int max_requests_per_child; +char *pid_fname; +char *scoreboard_fname; +char *server_argv0; +struct in_addr bind_address; +listen_rec *listeners; +int daemons_to_start; +int daemons_min_free; +int daemons_max_free; +int daemons_limit; +time_t restart_time; +int suexec_enabled = 0; + +char server_root[MAX_STRING_LEN]; +char server_confname[MAX_STRING_LEN]; + +/* *Non*-shared http_main globals... */ + +server_rec *server_conf; +JMP_BUF jmpbuffer; +int sd; +static fd_set listenfds; +static int listenmaxfd; +pid_t pgrp; + +/* one_process --- debugging mode variable; can be set from the command line + * with the -X flag. If set, this gets you the child_main loop running + * in the process which originally started up (no detach, no make_child), + * which is a pretty nice debugging environment. (You'll get a SIGHUP + * early in standalone_main; just continue through. This is the server + * trying to kill off any child processes which it might have lying + * around --- Apache doesn't keep track of their pids, it just sends + * SIGHUP to the process group, ignoring it in the root process. + * Continue through and you'll be fine.). + */ + +int one_process = 0; + +/* small utility macros to make things easier to read */ + +#ifdef NO_KILLPG +#define ap_killpg(x, y) (kill (-(x), (y))) +#else +#define ap_killpg(x, y) (killpg ((x), (y))) +#endif + +#if defined(USE_FCNTL_SERIALIZED_ACCEPT) +static struct flock lock_it; +static struct flock unlock_it; + +static int lock_fd=-1; + +/* + * Initialize mutex lock. + * Must be safe to call this on a restart. + */ +void +accept_mutex_init(pool *p) + { + char lock_fname[256]; + + lock_it.l_whence = SEEK_SET; /* from current point */ + lock_it.l_start = 0; /* -"- */ + lock_it.l_len = 0; /* until end of file */ + lock_it.l_type = F_WRLCK; /* set exclusive/write lock */ + lock_it.l_pid = 0; /* pid not actually interesting */ + unlock_it.l_whence = SEEK_SET; /* from current point */ + unlock_it.l_start = 0; /* -"- */ + unlock_it.l_len = 0; /* until end of file */ + unlock_it.l_type = F_UNLCK; /* set exclusive/write lock */ + unlock_it.l_pid = 0; /* pid not actually interesting */ + +#ifdef __MACHTEN__ + strncpy(lock_fname, "/var/tmp/htlock.XXXXXX", sizeof(lock_fname)-1); +#else + strncpy(lock_fname, "/usr/tmp/htlock.XXXXXX", sizeof(lock_fname)-1); +#endif + lock_fname[sizeof(lock_fname)-1] = '\0'; + + if (mktemp(lock_fname) == NULL || lock_fname[0] == '\0') + { + fprintf (stderr, "Cannot assign name to lock file!\n"); + exit (1); + } + + lock_fd = popenf(p, lock_fname, O_CREAT | O_WRONLY | O_EXCL, 0644); + if (lock_fd == -1) + { + perror ("open"); + fprintf (stderr, "Cannot open lock file: %s\n", lock_fname); + exit (1); + } + unlink(lock_fname); +} + +void accept_mutex_on() +{ + int ret; + + while ((ret = fcntl(lock_fd, F_SETLKW, &lock_it)) < 0 && errno == EINTR) + continue; + + if (ret < 0) { + log_unixerr("fcntl", "F_SETLKW", "Error getting accept lock. Exiting!", + server_conf); + exit(1); + } +} + +void accept_mutex_off() +{ + if (fcntl (lock_fd, F_SETLKW, &unlock_it) < 0) + { + log_unixerr("fcntl", "F_SETLKW", "Error freeing accept lock. Exiting!", + server_conf); + exit(1); + } +} +#elif defined(USE_FLOCK_SERIALIZED_ACCEPT) + +static int lock_fd=-1; + +/* + * Initialize mutex lock. + * Must be safe to call this on a restart. + */ +void +accept_mutex_init(pool *p) +{ + char lock_fname[256]; + + strncpy(lock_fname, "/usr/tmp/htlock.XXXXXX", sizeof(lock_fname)-1); + lock_fname[sizeof(lock_fname)-1] = '\0'; + + if (mktemp(lock_fname) == NULL || lock_fname[0] == '\0') + { + fprintf (stderr, "Cannot assign name to lock file!\n"); + exit (1); + } + + lock_fd = popenf(p, lock_fname, O_CREAT | O_WRONLY | O_EXCL, 0644); + if (lock_fd == -1) + { + perror ("open"); + fprintf (stderr, "Cannot open lock file\n"); + exit (1); + } + unlink(lock_fname); +} + +void accept_mutex_on() +{ + int ret; + + while ((ret = flock(lock_fd, LOCK_EX)) < 0 && errno == EINTR) + continue; + + if (ret < 0) { + log_unixerr("flock", "LOCK_EX", "Error getting accept lock. Exiting!", + server_conf); + exit(1); + } +} + +void accept_mutex_off() +{ + if (flock (lock_fd, LOCK_UN) < 0) + { + log_unixerr("flock", "LOCK_UN", "Error freeing accept lock. Exiting!", + server_conf); + exit(1); + } +} +#else +/* Default --- no serialization. Other methods *could* go here, + * as #elifs... + */ +#define accept_mutex_init(x) +#define accept_mutex_on() +#define accept_mutex_off() +#endif + +void usage(char *bin) +{ + fprintf(stderr,"Usage: %s [-d directory] [-f file] [-v] [-h] [-l]\n",bin); + fprintf(stderr,"-d directory : specify an alternate initial ServerRoot\n"); + fprintf(stderr,"-f file : specify an alternate ServerConfigFile\n"); + fprintf(stderr,"-v : show version number\n"); + fprintf(stderr,"-h : list directives\n"); + fprintf(stderr,"-l : list modules\n"); + exit(1); +} + +/***************************************************************** + * + * Timeout handling. DISTINCTLY not thread-safe, but all this stuff + * has to change for threads anyway. Note that this code allows only + * one timeout in progress at a time... + */ + +static conn_rec *current_conn; +static request_rec *timeout_req; +static char *timeout_name = NULL; +static int alarms_blocked = 0; +static int alarm_pending = 0; + +#ifndef NO_USE_SIGACTION +/* + * Replace standard signal() with the more reliable sigaction equivalent + * from W. Richard Stevens' "Advanced Programming in the UNIX Environment" + * (the version that does not automatically restart system calls). + */ +Sigfunc *signal(int signo, Sigfunc *func) +{ + struct sigaction act, oact; + + act.sa_handler = func; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; +#ifdef SA_INTERRUPT /* SunOS */ + act.sa_flags |= SA_INTERRUPT; +#endif + if (sigaction(signo, &act, &oact) < 0) + return SIG_ERR; + return oact.sa_handler; +} +#endif + +void timeout(int sig) /* Also called on SIGPIPE */ +{ + char errstr[MAX_STRING_LEN]; + void *dirconf; + + signal(SIGPIPE, SIG_IGN); /* Block SIGPIPE */ + if (alarms_blocked) { + alarm_pending = 1; + return; + } + + if (!current_conn) { + ap_longjmp (jmpbuffer, 1); + } + + if (timeout_req != NULL) dirconf = timeout_req->per_dir_config; + else dirconf = current_conn->server->lookup_defaults; + if (sig == SIGPIPE) { + ap_snprintf(errstr, sizeof(errstr), "%s lost connection to client %s", + timeout_name ? timeout_name : "request", + get_remote_host(current_conn, dirconf, REMOTE_NAME)); + } else { + ap_snprintf(errstr, sizeof(errstr), "%s timed out for %s", + timeout_name ? timeout_name : "request", + get_remote_host(current_conn, dirconf, REMOTE_NAME)); + } + + if (!current_conn->keptalive) + log_error(errstr, current_conn->server); + + if (timeout_req) { + /* Someone has asked for this transaction to just be aborted + * if it times out... + */ + + request_rec *log_req = timeout_req; + + while (log_req->main || log_req->prev) { + /* Get back to original request... */ + if (log_req->main) log_req = log_req->main; + else log_req = log_req->prev; + } + + if (!current_conn->keptalive) + log_transaction(log_req); + + bsetflag(timeout_req->connection->client, B_EOUT, 1); + bclose(timeout_req->connection->client); + + if (!standalone) exit(0); + + ap_longjmp (jmpbuffer, 1); + } + else { /* abort the connection */ + bsetflag(current_conn->client, B_EOUT, 1); + current_conn->aborted = 1; + } +} + +/* + * These two called from alloc.c to protect its critical sections... + * Note that they can nest (as when destroying the sub_pools of a pool + * which is itself being cleared); we have to support that here. + */ + +void block_alarms() { + ++alarms_blocked; +} + +void unblock_alarms() { + --alarms_blocked; + if (alarms_blocked == 0 && alarm_pending) { + alarm_pending = 0; + timeout(0); + } +} + +void keepalive_timeout (char *name, request_rec *r) +{ + timeout_req = r; + timeout_name = name; + + signal(SIGALRM, timeout); + if (r->connection->keptalive) + alarm (r->server->keep_alive_timeout); + else + alarm (r->server->timeout); +} + +void hard_timeout (char *name, request_rec *r) +{ + timeout_req = r; + timeout_name = name; + + signal(SIGALRM, timeout); + alarm (r->server->timeout); +} + +void soft_timeout (char *name, request_rec *r) +{ + timeout_name = name; + + signal(SIGALRM, timeout); + alarm (r->server->timeout); +} + +void kill_timeout (request_rec *dummy) { + alarm (0); + timeout_req = NULL; + timeout_name = NULL; +} + +/* reset_timeout (request_rec *) resets the timeout in effect, + * as long as it hasn't expired already. + */ + +void reset_timeout (request_rec *r) { + int i; + + if (timeout_name) { /* timeout has been set */ + i = alarm(r->server->timeout); + if (i == 0) /* timeout already expired, so set it back to 0 */ + alarm(0); + } +} + +/* + * More machine-dependent networking gooo... on some systems, + * you've got to be *really* sure that all the packets are acknowledged + * before closing the connection, since the client will not be able + * to see the last response if their TCP buffer is flushed by a RST + * packet from us, which is what the server's TCP stack will send + * if it receives any request data after closing the connection. + * + * In an ideal world, this function would be accomplished by simply + * setting the socket option SO_LINGER and handling it within the + * server's TCP stack while the process continues on to the next request. + * Unfortunately, it seems that most (if not all) operating systems + * block the server process on close() when SO_LINGER is used. + * For those that don't, see USE_SO_LINGER below. For the rest, + * we have created a home-brew lingering_close. + * + * Many operating systems tend to block, puke, or otherwise mishandle + * calls to shutdown only half of the connection. You should define + * NO_LINGCLOSE in conf.h if such is the case for your system. + */ +#ifndef MAX_SECS_TO_LINGER +#define MAX_SECS_TO_LINGER 30 +#endif + +#ifdef USE_SO_LINGER +#define NO_LINGCLOSE /* The two lingering options are exclusive */ + +static void sock_enable_linger (int s) +{ + struct linger li; + + li.l_onoff = 1; + li.l_linger = MAX_SECS_TO_LINGER; + + if (setsockopt(s, SOL_SOCKET, SO_LINGER, + (char *)&li, sizeof(struct linger)) < 0) { + log_unixerr("setsockopt", "(SO_LINGER)", NULL, server_conf); + /* not a fatal error */ + } +} + +#else +#define sock_enable_linger(s) /* NOOP */ +#endif /* USE_SO_LINGER */ + +#ifndef NO_LINGCLOSE + +/* Special version of timeout for lingering_close */ + +static void lingerout(sig) +int sig; +{ + if (alarms_blocked) { + alarm_pending = 1; + return; + } + + if (!current_conn) { + ap_longjmp (jmpbuffer, 1); + } + bsetflag(current_conn->client, B_EOUT, 1); + current_conn->aborted = 1; +} + +static void linger_timeout () +{ + timeout_name = "lingering close"; + + signal(SIGALRM, lingerout); + alarm(MAX_SECS_TO_LINGER); +} + +/* Since many clients will abort a connection instead of closing it, + * attempting to log an error message from this routine will only + * confuse the webmaster. There doesn't seem to be any portable way to + * distinguish between a dropped connection and something that might be + * worth logging. + */ +static void lingering_close (request_rec *r) +{ + int dummybuf[512]; + struct timeval tv; + fd_set lfds, fds_read, fds_err; + int select_rv = 0, read_rv = 0; + int lsd; + + /* Prevent a slow-drip client from holding us here indefinitely */ + + linger_timeout(); + + /* Send any leftover data to the client, but never try to again */ + + if (bflush(r->connection->client) == -1) { + kill_timeout(r); + bclose(r->connection->client); + return; + } + bsetflag(r->connection->client, B_EOUT, 1); + + /* Close our half of the connection --- send the client a FIN */ + + lsd = r->connection->client->fd; + + if ((shutdown(lsd, 1) != 0) || r->connection->aborted) { + kill_timeout(r); + bclose(r->connection->client); + return; + } + + /* Set up to wait for readable data on socket... */ + + FD_ZERO(&lfds); + FD_SET(lsd, &lfds); + + /* Wait for readable data or error condition on socket; + * slurp up any data that arrives... We exit when we go for + * an interval of tv length without getting any more data, get an + * error from select(), get an exception on lsd, get an error or EOF + * on a read, or the timer expires. + */ + + do { + /* We use a 2 second timeout because current (Feb 97) browsers + * fail to close a connection after the server closes it. Thus, + * to avoid keeping the child busy, we are only lingering long enough + * for a client that is actively sending data on a connection. + * This should be sufficient unless the connection is massively + * losing packets, in which case we might have missed the RST anyway. + * These parameters are reset on each pass, since they might be + * changed by select. + */ + tv.tv_sec = 2; + tv.tv_usec = 0; + read_rv = 0; + fds_read = lfds; + fds_err = lfds; + +#ifdef SELECT_NEEDS_CAST + select_rv = select(lsd+1, (int*)&fds_read, NULL, (int*)&fds_err, &tv); +#else + select_rv = select(lsd+1, &fds_read, NULL, &fds_err, &tv); +#endif + } while ((select_rv > 0) && /* Something to see on socket */ + !FD_ISSET(lsd, &fds_err) && /* that isn't an error condition */ + FD_ISSET(lsd, &fds_read) && /* and is worth trying to read */ + ((read_rv = read(lsd, dummybuf, sizeof dummybuf)) > 0)); + + /* Should now have seen final ack. Safe to finally kill socket */ + + bclose(r->connection->client); + + kill_timeout(r); +} +#endif /* ndef NO_LINGCLOSE */ + +/***************************************************************** + * + * Dealing with the scoreboard... a lot of these variables are global + * only to avoid getting clobbered by the longjmp() that happens when + * a hard timeout expires... + * + * We begin with routines which deal with the file itself... + */ + +#if defined(HAVE_MMAP) +static scoreboard *scoreboard_image=NULL; + +static void setup_shared_mem(void) +{ + caddr_t m; + +#ifdef __EMX__ + char errstr[MAX_STRING_LEN]; + int rc; + + m = (caddr_t)create_shared_heap("\\SHAREMEM\\SCOREBOARD", HARD_SERVER_LIMIT*sizeof(short_score)); + if(m == 0) { + fprintf(stderr, "httpd: Could not create OS/2 Shared memory pool.\n"); + exit(1); + } + + rc = _uopen((Heap_t)m); + if(rc != 0) { + fprintf(stderr, "httpd: Could not uopen() newly created OS/2 Shared memory pool.\n"); + } + +#elif defined(MAP_ANON) || defined(MAP_FILE) +/* BSD style */ + m = mmap((caddr_t)0, SCOREBOARD_SIZE, + PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); + if (m == (caddr_t)-1) + { + perror("mmap"); + fprintf(stderr, "httpd: Could not mmap memory\n"); + exit(1); + } +#else +/* Sun style */ + int fd; + + fd = open("/dev/zero", O_RDWR); + if (fd == -1) + { + perror("open"); + fprintf(stderr, "httpd: Could not open /dev/zero\n"); + exit(1); + } + m = mmap((caddr_t)0, SCOREBOARD_SIZE, + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (m == (caddr_t)-1) + { + perror("mmap"); + fprintf(stderr, "httpd: Could not mmap /dev/zero\n"); + exit(1); + } + close(fd); +#endif + scoreboard_image = (scoreboard *)m; + scoreboard_image->global.exit_generation=0; +} + +#elif defined(HAVE_SHMGET) +static scoreboard *scoreboard_image=NULL; +static key_t shmkey = IPC_PRIVATE; +static int shmid = -1; + +static void setup_shared_mem(void) +{ + char errstr[MAX_STRING_LEN]; + struct shmid_ds shmbuf; +#ifdef MOVEBREAK + char *obrk; +#endif + + if ((shmid = shmget(shmkey, SCOREBOARD_SIZE, IPC_CREAT|SHM_R|SHM_W)) == -1) + { + perror("shmget"); + fprintf(stderr, "httpd: Could not call shmget\n"); + exit(1); + } + + ap_snprintf(errstr, sizeof(errstr), "created shared memory segment #%d", shmid); + log_error(errstr, server_conf); + +#ifdef MOVEBREAK + /* + * Some SysV systems place the shared segment WAY too close + * to the dynamic memory break point (sbrk(0)). This severely + * limits the use of malloc/sbrk in the program since sbrk will + * refuse to move past that point. + * + * To get around this, we move the break point "way up there", + * attach the segment and then move break back down. Ugly + */ + if ((obrk=sbrk(MOVEBREAK)) == (char *)-1) + { + perror("sbrk"); + fprintf(stderr, "httpd: Could not move break\n"); + } +#endif + +#define BADSHMAT ((scoreboard *)(-1)) + if ((scoreboard_image = (scoreboard *)shmat(shmid, 0, 0)) == BADSHMAT) + { + perror("shmat"); + fprintf(stderr, "httpd: Could not call shmat\n"); + /* + * We exit below, after we try to remove the segment + */ + } + else /* only worry about permissions if we attached the segment */ + { + if (shmctl(shmid, IPC_STAT, &shmbuf) != 0) { + perror("shmctl"); + fprintf(stderr, "httpd: Could not stat segment #%d\n", shmid); + } + else + { + shmbuf.shm_perm.uid = user_id; + shmbuf.shm_perm.gid = group_id; + if (shmctl(shmid, IPC_SET, &shmbuf) != 0) { + perror("shmctl"); + fprintf(stderr, "httpd: Could not set segment #%d\n", shmid); + } + } + } + /* + * We must avoid leaving segments in the kernel's + * (small) tables. + */ + if (shmctl(shmid, IPC_RMID, NULL) != 0) { + perror("shmctl"); + fprintf(stderr, "httpd: Could not delete segment #%d\n", shmid); + ap_snprintf(errstr, sizeof(errstr), "could not remove shared memory segment #%d", shmid); + log_unixerr("shmctl","IPC_RMID",errstr, server_conf); + } + if (scoreboard_image == BADSHMAT) /* now bailout */ + exit(1); + +#ifdef MOVEBREAK + if (obrk == (char *)-1) + return; /* nothing else to do */ + if (sbrk(-(MOVEBREAK)) == (char *)-1) + { + perror("sbrk"); + fprintf(stderr, "httpd: Could not move break back\n"); + } +#endif + scoreboard_image->global.exit_generation=0; +} + +#else +#define SCOREBOARD_FILE +static scoreboard _scoreboard_image; +static scoreboard *scoreboard_image=&_scoreboard_image; +static int scoreboard_fd; + +/* XXX: things are seriously screwed if we ever have to do a partial + * read or write ... we could get a corrupted scoreboard + */ +static int force_write (int fd, char *buffer, int bufsz) +{ + int rv, orig_sz = bufsz; + + do { + rv = write (fd, buffer, bufsz); + if (rv > 0) { + buffer += rv; + bufsz -= rv; + } + } while ((rv > 0 && bufsz > 0) || (rv == -1 && errno == EINTR)); + + return rv < 0? rv : orig_sz - bufsz; +} + +static int force_read (int fd, char *buffer, int bufsz) +{ + int rv, orig_sz = bufsz; + + do { + rv = read (fd, buffer, bufsz); + if (rv > 0) { + buffer += rv; + bufsz -= rv; + } + } while ((rv > 0 && bufsz > 0) || (rv == -1 && errno == EINTR)); + + return rv < 0? rv : orig_sz - bufsz; +} +#endif + +/* Called by parent process */ +void reinit_scoreboard (pool *p) +{ + int exit_gen=0; + if(scoreboard_image) + exit_gen=scoreboard_image->global.exit_generation; + +#ifndef SCOREBOARD_FILE + if (scoreboard_image == NULL) + { + setup_shared_mem(); + } + memset(scoreboard_image, 0, SCOREBOARD_SIZE); + scoreboard_image->global.exit_generation=exit_gen; +#else + scoreboard_fname = server_root_relative (p, scoreboard_fname); + +#ifdef __EMX__ + /* OS/2 needs binary mode set. */ + scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_BINARY|O_RDWR, 0644); +#else + scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_RDWR, 0644); +#endif + if (scoreboard_fd == -1) + { + perror (scoreboard_fname); + fprintf (stderr, "Cannot open scoreboard file:\n"); + exit (1); + } + + memset ((char*)scoreboard_image, 0, sizeof(*scoreboard_image)); + scoreboard_image->global.exit_generation=exit_gen; + force_write (scoreboard_fd, (char*)scoreboard_image, + sizeof(*scoreboard_image)); +#endif +} + +/* called by child */ +void reopen_scoreboard (pool *p) +{ +#ifdef SCOREBOARD_FILE + if (scoreboard_fd != -1) pclosef (p, scoreboard_fd); + +#ifdef __EMX__ + /* OS/2 needs binary mode set. */ + scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_BINARY|O_RDWR, 0666); +#else + scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_RDWR, 0666); +#endif + if (scoreboard_fd == -1) + { + perror (scoreboard_fname); + fprintf (stderr, "Cannot open scoreboard file:\n"); + exit (1); + } +#else +#ifdef __EMX__ +#ifdef HAVE_MMAP + caddr_t m; + int rc; + + m = (caddr_t)get_shared_heap("\\SHAREMEM\\SCOREBOARD"); + if(m == 0) { + fprintf(stderr, "httpd: Could not find existing OS/2 Shared memory pool.\n"); + exit(1); + } + + rc = _uopen((Heap_t)m); + scoreboard_image = (scoreboard *)m; +#endif +#endif +#endif +} + +void cleanup_scoreboard () +{ +#ifdef SCOREBOARD_FILE + unlink (scoreboard_fname); +#endif +} + +/* Routines called to deal with the scoreboard image + * --- note that we do *not* need write locks, since update_child_status + * only updates a *single* record in place, and only one process writes to + * a given scoreboard slot at a time (either the child process owning that + * slot, or the parent, noting that the child has died). + * + * As a final note --- setting the score entry to getpid() is always safe, + * since when the parent is writing an entry, it's only noting SERVER_DEAD + * anyway. + */ + +void sync_scoreboard_image () +{ +#ifdef SCOREBOARD_FILE + lseek (scoreboard_fd, 0L, 0); + force_read (scoreboard_fd, (char*)scoreboard_image, + sizeof(*scoreboard_image)); +#endif +} + +int update_child_status (int child_num, int status, request_rec *r) +{ + int old_status; + short_score new_score_rec; + + if (child_num < 0) + return -1; + + sync_scoreboard_image(); + new_score_rec = scoreboard_image->servers[child_num]; + new_score_rec.pid = getpid(); + old_status = new_score_rec.status; + new_score_rec.status = status; + +#if defined(STATUS) + new_score_rec.last_used=time(NULL); + if (status == SERVER_READY || status == SERVER_DEAD) { + /* + * Reset individual counters + */ + if (status == SERVER_DEAD) { + new_score_rec.my_access_count = 0L; + new_score_rec.my_bytes_served = 0L; + } + new_score_rec.conn_count = (unsigned short)0; + new_score_rec.conn_bytes = (unsigned long)0; + } + if (r) { + int slot_size; + conn_rec *c = r->connection; + slot_size = sizeof(new_score_rec.client) - 1; + strncpy(new_score_rec.client, get_remote_host(c, r->per_dir_config, + REMOTE_NOLOOKUP), slot_size); + new_score_rec.client[slot_size] = '\0'; + slot_size = sizeof(new_score_rec.request) - 1; + strncpy(new_score_rec.request, (r->the_request ? r->the_request : + "NULL"), slot_size); + new_score_rec.request[slot_size] = '\0'; + slot_size = sizeof(new_score_rec.vhost) - 1; + strncpy(new_score_rec.vhost,r->server->server_hostname, slot_size); + new_score_rec.vhost[slot_size] = '\0'; + } +#endif + +#ifndef SCOREBOARD_FILE + memcpy(&scoreboard_image->servers[child_num], &new_score_rec, sizeof new_score_rec); +#else + lseek (scoreboard_fd, (long)child_num * sizeof(short_score), 0); + force_write (scoreboard_fd, (char*)&new_score_rec, sizeof(short_score)); +#endif + + return old_status; +} + +void update_scoreboard_global() + { +#ifdef SCOREBOARD_FILE + lseek(scoreboard_fd, + (char *)&scoreboard_image->global-(char *)scoreboard_image,0); + force_write(scoreboard_fd,(char *)&scoreboard_image->global, + sizeof scoreboard_image->global); +#endif + } + +int get_child_status (int child_num) +{ + if (child_num<0 || child_num>=HARD_SERVER_LIMIT) + return -1; + else + return scoreboard_image->servers[child_num].status; +} + +int count_busy_servers () +{ + int i; + int res = 0; + + for (i = 0; i < HARD_SERVER_LIMIT; ++i) + if (scoreboard_image->servers[i].status == SERVER_BUSY_READ || + scoreboard_image->servers[i].status == SERVER_BUSY_WRITE || + scoreboard_image->servers[i].status == SERVER_BUSY_KEEPALIVE || + scoreboard_image->servers[i].status == SERVER_BUSY_LOG || + scoreboard_image->servers[i].status == SERVER_BUSY_DNS) + ++res; + return res; +} + +int count_live_servers() + { + int i; + int res = 0; + + for (i = 0; i < HARD_SERVER_LIMIT; ++i) + if (scoreboard_image->servers[i].status != SERVER_DEAD) + ++res; + return res; + } + +short_score get_scoreboard_info(int i) +{ + return (scoreboard_image->servers[i]); +} + +#if defined(STATUS) +static void increment_counts (int child_num, request_rec *r) +{ + long int bs=0; + short_score new_score_rec; + + sync_scoreboard_image(); + new_score_rec = scoreboard_image->servers[child_num]; + if (r->sent_bodyct) + bgetopt(r->connection->client, BO_BYTECT, &bs); + + new_score_rec.access_count ++; + new_score_rec.my_access_count ++; + new_score_rec.conn_count ++; + new_score_rec.bytes_served += (unsigned long)bs; + new_score_rec.my_bytes_served += (unsigned long)bs; + new_score_rec.conn_bytes += (unsigned long)bs; + + times(&new_score_rec.times); + + +#ifndef SCOREBOARD_FILE + memcpy(&scoreboard_image->servers[child_num], &new_score_rec, sizeof(short_score)); +#else + lseek (scoreboard_fd, (long)child_num * sizeof(short_score), 0); + force_write (scoreboard_fd, (char*)&new_score_rec, sizeof(short_score)); +#endif +} +#endif + +int count_idle_servers () +{ + int i; + int res = 0; + + for (i = 0; i < HARD_SERVER_LIMIT; ++i) + if (scoreboard_image->servers[i].status == SERVER_READY) + ++res; + + return res; +} + +int find_free_child_num () +{ + int i; + + for (i = 0; i < HARD_SERVER_LIMIT; ++i) + if (scoreboard_image->servers[i].status == SERVER_DEAD) + return i; + + return -1; +} + +int find_child_by_pid (int pid) +{ + int i; + + for (i = 0; i < HARD_SERVER_LIMIT; ++i) + if (scoreboard_image->servers[i].pid == pid) + return i; + + return -1; +} + +void reclaim_child_processes () +{ + int i, status; + int my_pid = getpid(); + + sync_scoreboard_image(); + for (i = 0; i < HARD_SERVER_LIMIT; ++i) { + int pid = scoreboard_image->servers[i].pid; + + if (pid != my_pid && pid != 0) { + int waitret = 0, + tries = 1; + + while (waitret == 0 && tries <= 4) { + long int waittime = 4096; /* in usecs */ + struct timeval tv; + + /* don't want to hold up progress any more than + * necessary, so keep checking to see if the child + * has exited with an exponential backoff. + * Currently set for a maximum wait of a bit over + * four seconds. + */ + while (((waitret = waitpid(pid, &status, WNOHANG)) == 0) && + waittime < 3000000) { + tv.tv_sec = waittime / 1000000; + tv.tv_usec = waittime % 1000000; + waittime = waittime * 2; + select(0, NULL, NULL, NULL, &tv); + } + if (waitret == 0) { + switch (tries) { + case 1: + /* perhaps it missed the SIGHUP, lets try again */ + log_printf(server_conf, "child process %d did not exit, sending another SIGHUP", pid); + kill(pid, SIGHUP); + break; + case 2: + /* ok, now it's being annoying */ + log_printf(server_conf, "child process %d still did not exit, sending a SIGTERM", pid); + kill(pid, SIGTERM); + break; + case 3: + /* die child scum */ + log_printf(server_conf, "child process %d still did not exit, sending a SIGKILL", pid); + kill(pid, SIGKILL); + break; + case 4: + /* gave it our best shot, but alas... If this really + * is a child we are trying to kill and it really hasn't + * exited, we will likely fail to bind to the port + * after the restart. + */ + log_printf(server_conf, "could not make child process %d exit, attempting to continue anyway", pid); + break; + } + } + tries++; + } + } + } +} + +#if defined(BROKEN_WAIT) || defined(NEED_WAITPID) +/* +Some systems appear to fail to deliver dead children to wait() at times. +This sorts them out. In fact, this may have been caused by a race condition +in wait_or_timeout(). But this routine is still useful for systems with no +waitpid(). +*/ +int reap_children () +{ + int status, n; + int ret = 0; + + for (n = 0; n < HARD_SERVER_LIMIT; ++n) { + if (scoreboard_image->servers[n].status != SERVER_DEAD + && waitpid (scoreboard_image->servers[n].pid, &status, WNOHANG) + == -1 + && errno == ECHILD) { + sync_scoreboard_image (); + update_child_status (n, SERVER_DEAD, NULL); + ret = 1; + } + } + return ret; +} +#endif + +/* Finally, this routine is used by the caretaker process to wait for + * a while... + */ + +static int wait_or_timeout () +{ +#ifndef NEED_WAITPID + int ret; + + ret = waitpid (-1, NULL, WNOHANG); + if (ret == -1 && errno == EINTR) { + return -1; + } + if (ret <= 0) { + sleep (1); + return -1; + } + return ret; +#else + if (!reap_children ()) { + sleep(1); + } + return -1; +#endif +} + + +void sig_term() { + log_error("httpd: caught SIGTERM, shutting down", server_conf); + cleanup_scoreboard(); + ap_killpg (pgrp, SIGKILL); + close(sd); + exit(1); +} + +void bus_error(void) { + char emsg[256]; + + ap_snprintf + ( + emsg, + sizeof(emsg) - 1, + "httpd: caught SIGBUS, attempting to dump core in %s", + server_root + ); + log_error(emsg, server_conf); + chdir(server_root); + abort(); + exit(1); +} + +void seg_fault() { + char emsg[256]; + + ap_snprintf + ( + emsg, + sizeof(emsg) - 1, + "httpd: caught SIGSEGV, attempting to dump core in %s", + server_root + ); + log_error(emsg, server_conf); + chdir(server_root); + abort(); + exit(1); +} + +void just_die() /* SIGHUP to child process??? */ +{ + exit (0); +} + +static int deferred_die; + +static void deferred_die_handler () +{ + deferred_die = 1; +} + +/* volatile just in case */ +static volatile int restart_pending; +static volatile int is_graceful; +static volatile int generation; + +static void restart (int sig) +{ + is_graceful = (sig == SIGUSR1); + restart_pending = 1; +} + + +void set_signals() +{ +#ifndef NO_USE_SIGACTION + struct sigaction sa; + + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + + if (!one_process) { + sa.sa_handler = (void (*)())seg_fault; + if (sigaction (SIGSEGV, &sa, NULL) < 0) + log_unixerr ("sigaction(SIGSEGV)", NULL, NULL, server_conf); + sa.sa_handler = (void (*)())bus_error; + if (sigaction (SIGBUS, &sa, NULL) < 0) + log_unixerr ("sigaction(SIGBUS)", NULL, NULL, server_conf); + } + sa.sa_handler = (void (*)())sig_term; + if (sigaction (SIGTERM, &sa, NULL) < 0) + log_unixerr ("sigaction(SIGTERM)", NULL, NULL, server_conf); + + /* wait_or_timeout uses sleep() which could deliver a SIGALRM just as we're + * trying to process the restart requests. That's not good. restart + * cleans out the SIGALRM handler, but this totally avoids the race + * condition between when the restart request is made and when the handler + * is invoked. + * + * We also don't want to ignore HUPs and USR1 while we're busy processing + * one. + */ + sigaddset (&sa.sa_mask, SIGALRM); + sigaddset (&sa.sa_mask, SIGHUP); + sigaddset (&sa.sa_mask, SIGUSR1); + sa.sa_handler = (void (*)())restart; + if (sigaction (SIGHUP, &sa, NULL) < 0) + log_unixerr ("sigaction(SIGHUP)", NULL, NULL, server_conf); + if (sigaction (SIGUSR1, &sa, NULL) < 0) + log_unixerr ("sigaction(SIGUSR1)", NULL, NULL, server_conf); +#else + if(!one_process) { + signal (SIGSEGV, (void (*)())seg_fault); + signal (SIGBUS, (void (*)())bus_error); + } + + signal (SIGTERM, (void (*)())sig_term); + signal (SIGHUP, (void (*)())restart); + signal (SIGUSR1, (void (*)())restart); +#endif +} + + +/***************************************************************** + * Here follows a long bunch of generic server bookkeeping stuff... + */ + +void detach() +{ + int x; + + chdir("/"); +#ifndef MPE +/* Don't detach for MPE because child processes can't survive the death of + the parent. */ + if((x = fork()) > 0) + exit(0); + else if(x == -1) { + perror("fork"); + fprintf(stderr,"httpd: unable to fork new process\n"); + exit(1); + } +#endif +#ifndef NO_SETSID + if((pgrp=setsid()) == -1) { + perror("setsid"); + fprintf(stderr,"httpd: setsid failed\n"); + exit(1); + } +#elif defined(NEXT) + if(setpgrp(0,getpid()) == -1 || (pgrp = getpgrp(0)) == -1) { + perror("setpgrp"); + fprintf(stderr,"httpd: setpgrp or getpgrp failed\n"); + exit(1); + } +#elif defined(__EMX__) + /* OS/2 doesn't support process group IDs */ + pgrp=getpid(); +#elif defined(MPE) + /* MPE uses negative pid for process group */ + pgrp=-getpid(); +#else + if((pgrp=setpgrp(getpid(),0)) == -1) { + perror("setpgrp"); + fprintf(stderr,"httpd: setpgrp failed\n"); + exit(1); + } +#endif +} + +/* Reset group privileges, after rereading the config files + * (our uid may have changed, and if so, we want the new perms). + * + * Don't reset the uid yet --- we do that only in the child process, + * so as not to lose any root privs. But we can set the group stuff + * now, once, as opposed to once per each new child. + * + * Note that we use the username as set in the config files, rather than + * the lookup of to uid --- the same uid may have multiple passwd entries, + * with different sets of groups for each. + */ + +static void set_group_privs() +{ + if(!geteuid()) { + char *name; + + /* Get username if passed as a uid */ + + if (user_name[0] == '#') { + struct passwd* ent; + uid_t uid=atoi(&user_name[1]); + + if ((ent = getpwuid(uid)) == NULL) { + log_unixerr("getpwuid",NULL,"couldn't determine user name from uid", server_conf); + exit(1); + } + + name = ent->pw_name; + } else name = user_name; + +#ifndef __EMX__ + /* OS/2 dosen't support groups. */ + + /* Reset `groups' attributes. */ + + if (initgroups(name, group_id) == -1) { + log_unixerr("initgroups", NULL, "unable to set groups", server_conf); + exit (1); + } +#ifdef MULTIPLE_GROUPS + if (getgroups(NGROUPS_MAX, group_id_list) == -1) { + log_unixerr("getgroups", NULL, "unable to get group list", server_conf); + exit (1); + } +#endif + if (setgid(group_id) == -1) { + log_unixerr("setgid", NULL, "unable to set group id", server_conf); + exit (1); + } +#endif + } +} + +/* check to see if we have the 'suexec' setuid wrapper installed */ +int init_suexec () +{ + struct stat wrapper; + + if ((stat(SUEXEC_BIN, &wrapper)) != 0) + return (suexec_enabled); + + if ((wrapper.st_mode & S_ISUID) && wrapper.st_uid == 0) { + suexec_enabled = 1; + fprintf(stderr, "Configuring Apache for use with suexec wrapper.\n"); + } + + return (suexec_enabled); +} + +/***************************************************************** + * Connection structures and accounting... + * Should these be global? Only to this file, at least... + */ + +pool *pconf; /* Pool for config stuff */ +pool *ptrans; /* Pool for per-transaction stuff */ + +static server_rec *find_virtual_server (struct in_addr server_ip, + unsigned port, server_rec *server) +{ + server_rec *virt; + server_addr_rec *sar; + server_rec *def; + + def = server; + for (virt = server->next; virt; virt = virt->next) { + for (sar = virt->addrs; sar; sar = sar->next) { + if ((virt->is_virtual == 1) && /* VirtualHost */ + (sar->host_addr.s_addr == htonl(INADDR_ANY) || + sar->host_addr.s_addr == server_ip.s_addr) && + (sar->host_port == 0 || sar->host_port == port)) { + return virt; + } else if ( sar->host_addr.s_addr == DEFAULT_VHOST_ADDR + && (sar->host_port == 0 || sar->host_port == port)) { + /* this is so that you can build a server that is the + "default" for any interface which isn't explicitly + specified. So that you can implement "deny anything + which isn't expressly permitted" -djg */ + def = virt; + } + } + } + + return def; +} + +void default_server_hostnames(server_rec *s) +{ + struct hostent *h; + struct in_addr *main_addr; + int num_addr; + char *def_hostname; + int n; + server_addr_rec *sar; + int has_default_vhost_addr; + unsigned mainport = s->port; + int from_local=0; + + /* Main host first */ + + if (!s->server_hostname) { + s->server_hostname = get_local_host(pconf); + from_local = 1; + } + + def_hostname = s->server_hostname; + h = gethostbyname(def_hostname); + if( h == NULL ) { + fprintf(stderr,"httpd: cannot determine the IP address of "); + if (from_local) { + fprintf(stderr,"the local host (%s). Use ServerName to set it manually.\n", + s->server_hostname ? s->server_hostname : "<NULL>"); + } else { + fprintf(stderr,"the specified ServerName (%s).\n", + s->server_hostname ? s->server_hostname : "<NULL>"); + }; + exit(1); + } + /* we need to use gethostbyaddr below... and since it shares a static + area with gethostbyname it'd clobber the value we just got. So + we need to make a copy. -djg */ + for (num_addr = 0; h->h_addr_list[num_addr] != NULL; num_addr++) { + /* nop */ + } + main_addr = palloc( pconf, sizeof( *main_addr ) * num_addr ); + for (n = 0; n < num_addr; n++) { + main_addr[n] = *(struct in_addr *)h->h_addr_list[n]; + } + + /* Then virtual hosts */ + + for (s = s->next; s; s = s->next) { + /* Check to see if we might be a HTTP/1.1 virtual host - same IP */ + has_default_vhost_addr = 0; + for (n = 0; n < num_addr; n++) { + for(sar = s->addrs; sar; sar = sar->next) { + if (sar->host_addr.s_addr == main_addr[n].s_addr && + s->port == mainport) + s->is_virtual = 2; + if( sar->host_addr.s_addr == DEFAULT_VHOST_ADDR ) { + has_default_vhost_addr = 1; + } + } + } + + /* FIXME: some of this decision doesn't make a lot of sense in + the presence of multiple addresses on the <VirtualHost> + directive. It should issue warnings here perhaps. -djg */ + if (!s->server_hostname) { + if (s->is_virtual == 2) { + if (s->addrs) { + s->server_hostname = s->addrs->virthost; + } else { + /* what else can we do? at this point this vhost has + no configured name, probably because they used + DNS in the VirtualHost statement. It's disabled + anyhow by the host matching code. -djg */ + s->server_hostname = "bogus_host_without_forward_dns"; + } + } else if (has_default_vhost_addr) { + s->server_hostname = def_hostname; + } else { + if (s->addrs + && (h = gethostbyaddr ((char *)&(s->addrs->host_addr), + sizeof (struct in_addr), AF_INET))) { + s->server_hostname = pstrdup (pconf, (char *)h->h_name); + } else { + /* again, what can we do? They didn't specify a + ServerName, and their DNS isn't working. -djg */ + if (s->addrs) { + fprintf(stderr, "Failed to resolve server name " + "for %s (check DNS)\n", + inet_ntoa(s->addrs->host_addr)); + } + s->server_hostname = "bogus_host_without_reverse_dns"; + } + } + } + } +} + +conn_rec *new_connection (pool *p, server_rec *server, BUFF *inout, + const struct sockaddr_in *remaddr, + const struct sockaddr_in *saddr, + int child_num) +{ + conn_rec *conn = (conn_rec *)pcalloc (p, sizeof(conn_rec)); + + /* Got a connection structure, so initialize what fields we can + * (the rest are zeroed out by pcalloc). + */ + + conn->child_num = child_num; + + conn->pool = p; + conn->local_addr = *saddr; + conn->server = find_virtual_server(saddr->sin_addr, ntohs(saddr->sin_port), + server); + conn->base_server = conn->server; + conn->client = inout; + + conn->remote_addr = *remaddr; + conn->remote_ip = pstrdup (conn->pool, + inet_ntoa(conn->remote_addr.sin_addr)); + + return conn; +} + +#if defined(TCP_NODELAY) && !defined(MPE) +static void sock_disable_nagle (int s) +{ + /* The Nagle algorithm says that we should delay sending partial + * packets in hopes of getting more data. We don't want to do + * this; we are not telnet. There are bad interactions between + * persistent connections and Nagle's algorithm that have very severe + * performance penalties. (Failing to disable Nagle is not much of a + * problem with simple HTTP.) + * + * In spite of these problems, failure here is not a shooting offense. + */ + int just_say_no = 1; + + if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char*)&just_say_no, + sizeof(int)) < 0) { + log_unixerr("setsockopt", "(TCP_NODELAY)", NULL, server_conf); + } +} +#else +#define sock_disable_nagle(s) /* NOOP */ +#endif + +/***************************************************************** + * Child process main loop. + * The following vars are static to avoid getting clobbered by longjmp(); + * they are really private to child_main. + */ + +static int srv; +static int csd; +static int dupped_csd; +static int requests_this_child; +static int child_num; +static fd_set main_fds; + +void child_main(int child_num_arg) +{ +#if defined(UW) + size_t clen; +#else + int clen; +#endif + struct sockaddr sa_server; + struct sockaddr sa_client; + + csd = -1; + dupped_csd = -1; + child_num = child_num_arg; + requests_this_child = 0; + + reopen_scoreboard(pconf); + (void)update_child_status(child_num, SERVER_READY, (request_rec*)NULL); + +#ifdef MPE + /* Only try to switch if we're running as MANAGER.SYS */ + if (geteuid() == 1 && user_id > 1) { + GETPRIVMODE(); + if (setuid(user_id) == -1) { + GETUSERMODE(); +#else + /* Only try to switch if we're running as root */ + if (!geteuid() && setuid(user_id) == -1) { +#endif + log_unixerr("setuid", NULL, "unable to change uid", server_conf); + exit (1); + } +#ifdef MPE + GETUSERMODE(); + } +#endif + + /* + * Setup the jump buffers so that we can return here after + * a signal or a timeout (yeah, I know, same thing). + */ + ap_setjmp (jmpbuffer); +#ifndef __EMX__ + signal(SIGURG, timeout); +#endif + + while (1) { + int errsave; + BUFF *conn_io; + request_rec *r; + + /* Prepare to receive a SIGUSR1 due to graceful restart so that + * we can exit cleanly. Since we're between connections right + * now it's the right time to exit, but we might be blocked in a + * system call when the graceful restart request is made. */ + signal (SIGUSR1, (void (*)())just_die); + + /* + * (Re)initialize this child to a pre-connection state. + */ + + alarm(0); /* Cancel any outstanding alarms. */ + timeout_req = NULL; /* No request in progress */ + current_conn = NULL; + signal(SIGPIPE, timeout); + + clear_pool (ptrans); + + sync_scoreboard_image(); + if (scoreboard_image->global.exit_generation >= generation) + exit(0); + + if ((count_idle_servers() >= daemons_max_free) + || (max_requests_per_child > 0 + && ++requests_this_child >= max_requests_per_child)) + { + exit(0); + } + + (void)update_child_status(child_num, SERVER_READY, (request_rec*)NULL); + + if (listeners == NULL) { + FD_ZERO(&listenfds); + FD_SET(sd, &listenfds); + listenmaxfd = sd; + } + + /* + * Wait for an acceptable connection to arrive. + */ + + accept_mutex_on(); /* Lock around "accept", if necessary */ + + for (;;) { + memcpy(&main_fds, &listenfds, sizeof(fd_set)); +#ifdef SELECT_NEEDS_CAST + srv = select(listenmaxfd+1, (int*)&main_fds, NULL, NULL, NULL); +#else + srv = select(listenmaxfd+1, &main_fds, NULL, NULL, NULL); +#endif + errsave = errno; + + sync_scoreboard_image(); + if (scoreboard_image->global.exit_generation >= generation) + exit(0); + + errno = errsave; + if (srv < 0 && errno != EINTR) + log_unixerr("select", "(listen)", NULL, server_conf); + + if (srv <= 0) + continue; + + if (listeners != NULL) { + for (sd = listenmaxfd; sd >= 0; sd--) + if (FD_ISSET(sd, &main_fds)) break; + if (sd < 0) + continue; + } + + /* if we accept() something we don't want to die, so we have to + * defer the exit + */ + deferred_die = 0; + signal (SIGUSR1, (void (*)())deferred_die_handler); + for (;;) { + clen = sizeof(sa_client); + csd = accept(sd, &sa_client, &clen); + if (csd >= 0 || errno != EINTR) break; + if (deferred_die) { + /* we didn't get a socket, and we were told to die */ + exit (0); + } + } + + if (csd >= 0) + break; /* We have a socket ready for reading */ + else { + +#if defined(EPROTO) && defined(ECONNABORTED) + if ((errno != EPROTO) && (errno != ECONNABORTED)) +#elif defined(EPROTO) + if (errno != EPROTO) +#elif defined(ECONNABORTED) + if (errno != ECONNABORTED) +#endif + log_unixerr("accept", "(client socket)", NULL, server_conf); + } + + /* go around again, safe to die */ + signal (SIGUSR1, (void (*)())just_die); + if (deferred_die) { + /* ok maybe not, see ya later */ + exit (0); + } + } + + accept_mutex_off(); /* unlock after "accept" */ + + /* We've got a socket, let's at least process one request off the + * socket before we accept a graceful restart request. + */ + signal (SIGUSR1, SIG_IGN); + + note_cleanups_for_fd(ptrans,csd); + + /* + * We now have a connection, so set it up with the appropriate + * socket options, file descriptors, and read/write buffers. + */ + + clen = sizeof(sa_server); + if (getsockname(csd, &sa_server, &clen) < 0) { + log_unixerr("getsockname", NULL, NULL, server_conf); + continue; + } + + sock_disable_nagle(csd); + + (void)update_child_status(child_num, SERVER_BUSY_READ, + (request_rec*)NULL); + + conn_io = bcreate(ptrans, B_RDWR); + dupped_csd = csd; +#if defined(NEED_DUPPED_CSD) + if ((dupped_csd = dup(csd)) < 0) { + log_unixerr("dup", NULL, "couldn't duplicate csd", server_conf); + dupped_csd = csd; /* Oh well... */ + } + note_cleanups_for_fd(ptrans,dupped_csd); +#endif + bpushfd(conn_io, csd, dupped_csd); + + current_conn = new_connection (ptrans, server_conf, conn_io, + (struct sockaddr_in *)&sa_client, + (struct sockaddr_in *)&sa_server, + child_num); + + /* + * Read and process each request found on our connection + * until no requests are left or we decide to close. + */ + + while ((r = read_request(current_conn)) != NULL) { + + /* ok we've read the request... it's a little too late + * to do a graceful restart, so ignore them for now. + */ + signal (SIGUSR1, SIG_IGN); + + (void)update_child_status(child_num, SERVER_BUSY_WRITE, r); + + process_request(r); +#if defined(STATUS) + increment_counts(child_num, r); +#endif + if (!current_conn->keepalive || current_conn->aborted) + break; + + destroy_pool(r->pool); + (void)update_child_status(child_num, SERVER_BUSY_KEEPALIVE, + (request_rec*)NULL); + + sync_scoreboard_image(); + if (scoreboard_image->global.exit_generation >= generation) { + bclose(conn_io); + exit(0); + } + + /* In case we get a graceful restart while we're blocked + * waiting for the request. + * + * XXX: This isn't perfect, we might actually read the + * request and then just die without saying anything to + * the client. This can be fixed by using deferred_die + * but you have to teach buff.c about it so that it can handle + * the EINTR properly. + * + * In practice though browsers (have to) expect keepalive + * connections to close before receiving a response because + * of network latencies and server timeouts. + */ + signal (SIGUSR1, (void (*)())just_die); + } + + /* + * Close the connection, being careful to send out whatever is still + * in our buffers. If possible, try to avoid a hard close until the + * client has ACKed our FIN and/or has stopped sending us data. + */ + +#ifdef NO_LINGCLOSE + bclose(conn_io); /* just close it */ +#else + if (r && r->connection + && !r->connection->aborted + && r->connection->client + && (r->connection->client->fd >= 0)) { + + lingering_close(r); + } + else { + bsetflag(conn_io, B_EOUT, 1); + bclose(conn_io); + } +#endif + } +} + +int make_child(server_rec *server_conf, int child_num) +{ + int pid; + + if (one_process) { + signal (SIGHUP, (void (*)())just_die); + signal (SIGTERM, (void (*)())just_die); + child_main (child_num); + } + + Explain1 ("Starting new child in slot %d", child_num); + (void)update_child_status (child_num, SERVER_STARTING, (request_rec *)NULL); + + if ((pid = fork()) == -1) { + log_unixerr("fork", NULL, "Unable to fork new process", server_conf); + + /* fork didn't succeed. Fix the scoreboard or else + * it will say SERVER_STARTING forever and ever + */ + (void)update_child_status (child_num, SERVER_DEAD, (request_rec*)NULL); + + /* In case system resources are maxxed out, we don't want + Apache running away with the CPU trying to fork over and + over and over again. */ + sleep(10); + + return -1; + } + + if (!pid) { + /* Disable the restart signal handlers and enable the just_die stuff. + * Note that since restart() just notes that a restart has been + * requested there's no race condition here. + */ + signal (SIGHUP, (void (*)())just_die); + signal (SIGUSR1, (void (*)())just_die); + signal (SIGTERM, (void (*)())just_die); + child_main (child_num); + } + + /* If the parent proceeds with a restart before the child has written + * their pid into the scoreboard we'll end up "forgetting" about the + * child. So we write the child pid into the scoreboard now. (This + * is safe, because the child is going to be writing the same value + * to the same word.) + * XXX: this needs to be sync'd to disk in the non shared memory stuff + */ + scoreboard_image->servers[child_num].pid = pid; + + return 0; +} + +static int make_sock(pool *pconf, const struct sockaddr_in *server) +{ + int s; + int one = 1; + + if ((s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == -1) { + log_unixerr("socket", NULL, "Failed to get a socket, exiting child", + server_conf); + exit(1); + } + + note_cleanups_for_fd(pconf, s); /* arrange to close on exec or restart */ + +#ifndef MPE +/* MPE does not support SO_REUSEADDR and SO_KEEPALIVE */ + if (setsockopt(s, SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(int)) < 0) { + log_unixerr("setsockopt", "(SO_REUSEADDR)", NULL, server_conf); + exit(1); + } + one = 1; + if (setsockopt(s, SOL_SOCKET,SO_KEEPALIVE,(char *)&one,sizeof(int)) < 0) { + log_unixerr("setsockopt", "(SO_KEEPALIVE)", NULL, server_conf); + exit(1); + } +#endif + + sock_disable_nagle(s); + sock_enable_linger(s); + + /* + * To send data over high bandwidth-delay connections at full + * speed we must force the TCP window to open wide enough to keep the + * pipe full. The default window size on many systems + * is only 4kB. Cross-country WAN connections of 100ms + * at 1Mb/s are not impossible for well connected sites. + * If we assume 100ms cross-country latency, + * a 4kB buffer limits throughput to 40kB/s. + * + * To avoid this problem I've added the SendBufferSize directive + * to allow the web master to configure send buffer size. + * + * The trade-off of larger buffers is that more kernel memory + * is consumed. YMMV, know your customers and your network! + * + * -John Heidemann <johnh@isi.edu> 25-Oct-96 + * + * If no size is specified, use the kernel default. + */ + if (server_conf->send_buffer_size) { + if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, + (char *)&server_conf->send_buffer_size, sizeof(int)) < 0) { + log_unixerr("setsockopt", "(SO_SNDBUF)", + "Failed to set SendBufferSize, using default", + server_conf); + /* not a fatal error */ + } + } + +#ifdef MPE +/* MPE requires CAP=PM and GETPRIVMODE to bind to ports less than 1024 */ + if (ntohs(server->sin_port) < 1024) GETPRIVMODE(); +#endif + if(bind(s, (struct sockaddr *)server,sizeof(struct sockaddr_in)) == -1) + { + perror("bind"); +#ifdef MPE + if (ntohs(server->sin_port) < 1024) GETUSERMODE(); +#endif + if (server->sin_addr.s_addr != htonl(INADDR_ANY)) + fprintf(stderr,"httpd: could not bind to address %s port %d\n", + inet_ntoa(server->sin_addr), ntohs(server->sin_port)); + else + fprintf(stderr,"httpd: could not bind to port %d\n", + ntohs(server->sin_port)); + exit(1); + } +#ifdef MPE + if (ntohs(server->sin_port) < 1024) GETUSERMODE(); +#endif + listen(s, 512); + return s; +} + +static listen_rec *old_listeners; + +static void copy_listeners(pool *p) + { + listen_rec *lr; + + assert(old_listeners == NULL); + for(lr=listeners ; lr ; lr=lr->next) + { + listen_rec *nr=malloc(sizeof *nr); + if (nr == NULL) { + fprintf (stderr, "Ouch! malloc failed in copy_listeners()\n"); + exit (1); + } + *nr=*lr; + kill_cleanups_for_fd(p,nr->fd); + nr->next=old_listeners; + assert(!nr->used); + old_listeners=nr; + } + } + +static int find_listener(listen_rec *lr) + { + listen_rec *or; + + for(or=old_listeners ; or ; or=or->next) + if(!memcmp(&or->local_addr,&lr->local_addr,sizeof or->local_addr)) + { + or->used=1; + return or->fd; + } + return -1; + } + +static void close_unused_listeners() + { + listen_rec *or,*next; + + for(or=old_listeners ; or ; or=next) + { + next=or->next; + if(!or->used) + close(or->fd); + free(or); + } + old_listeners=NULL; + } + +/***************************************************************** + * Executive routines. + */ + +void standalone_main(int argc, char **argv) +{ + struct sockaddr_in sa_server; + int saved_sd; + int remaining_children_to_start; + + standalone = 1; + sd = listenmaxfd = -1; + + is_graceful = 0; + ++generation; + + if (!one_process) detach (); + + do { + copy_listeners(pconf); + saved_sd = sd; + if (!is_graceful) { + restart_time = time(NULL); + } +#ifdef SCOREBOARD_FILE + else { + kill_cleanups_for_fd (pconf, scoreboard_fd); + } +#endif + clear_pool (pconf); + ptrans = make_sub_pool (pconf); + + server_conf = read_config (pconf, ptrans, server_confname); + open_logs (server_conf, pconf); + set_group_privs (); + accept_mutex_init (pconf); + if (!is_graceful) { + reinit_scoreboard(pconf); + } +#ifdef SCOREBOARD_FILE + else { + scoreboard_fname = server_root_relative (pconf, scoreboard_fname); + note_cleanups_for_fd (pconf, scoreboard_fd); + } +#endif + + default_server_hostnames (server_conf); + + if (listeners == NULL) { + if (!is_graceful) { + memset ((char *)&sa_server, 0, sizeof (sa_server)); + sa_server.sin_family = AF_INET; + sa_server.sin_addr = bind_address; + sa_server.sin_port = htons (server_conf->port); + sd = make_sock (pconf, &sa_server); + } + else { + sd = saved_sd; + note_cleanups_for_fd(pconf, sd); + } + } + else { + listen_rec *lr; + int fd; + + listenmaxfd = -1; + FD_ZERO (&listenfds); + for (lr = listeners; lr != NULL; lr = lr->next) + { + fd = find_listener (lr); + if (fd < 0) { + fd = make_sock (pconf, &lr->local_addr); + } + FD_SET (fd, &listenfds); + if (fd > listenmaxfd) listenmaxfd = fd; + lr->fd = fd; + } + close_unused_listeners (); + sd = -1; + } + + set_signals (); + log_pid (pconf, pid_fname); + + if (daemons_max_free < daemons_min_free + 1) /* Don't thrash... */ + daemons_max_free = daemons_min_free + 1; + + /* If we're doing a graceful_restart then we're going to see a lot + * of children exiting immediately when we get into the main loop + * below (because we just sent them SIGUSR1). This happens pretty + * rapidly... and for each one that exits we'll start a new one until + * we reach at least daemons_min_free. But we may be permitted to + * start more than that, so we'll just keep track of how many we're + * supposed to start up without the 1 second penalty between each fork. + */ + remaining_children_to_start = daemons_to_start; + if( remaining_children_to_start > daemons_limit ) { + remaining_children_to_start = daemons_limit; + } + if (!is_graceful) { + while (remaining_children_to_start) { + --remaining_children_to_start; + make_child (server_conf, remaining_children_to_start); + } + } + + log_error ("Server configured -- resuming normal operations", + server_conf); + restart_pending = 0; + + while (!restart_pending) { + int child_slot; + int pid = wait_or_timeout (); + + /* XXX: if it takes longer than 1 second for all our children + * to start up and get into IDLE state then we may spawn an + * extra child + */ + if (pid >= 0) { + /* Child died... note that it's gone in the scoreboard. */ + sync_scoreboard_image (); + child_slot = find_child_by_pid (pid); + Explain2 ("Reaping child %d slot %d", pid, child_slot); + if (child_slot >= 0) { + (void)update_child_status (child_slot, SERVER_DEAD, + (request_rec *)NULL); + } else if (is_graceful) { + /* Great, we've probably just lost a slot in the + * scoreboard. Somehow we don't know about this + * child. + */ + log_printf (server_conf, + "long lost child came home! (pid %d)", pid ); + } + } else if (remaining_children_to_start) { + /* we hit a 1 second timeout in which none of the previous + * generation of children needed to be reaped... so assume + * they're all done, and pick up the slack if any is left. + */ + while (remaining_children_to_start > 0) { + child_slot = find_free_child_num (); + if (child_slot < 0 || child_slot >= daemons_limit) { + remaining_children_to_start = 0; + break; + } + if (make_child (server_conf, child_slot) < 0) { + remaining_children_to_start = 0; + break; + } + --remaining_children_to_start; + } + /* In any event we really shouldn't do the code below because + * few of the servers we just started are in the IDLE state + * yet, so we'd mistakenly create an extra server. + */ + continue; + } + + sync_scoreboard_image (); + if ((remaining_children_to_start + || (count_idle_servers () < daemons_min_free)) + && (child_slot = find_free_child_num ()) >= 0 + && child_slot < daemons_limit) { + make_child (server_conf, child_slot); + } + if (remaining_children_to_start) { + --remaining_children_to_start; + } + } + + /* we've been told to restart */ + + if (one_process) { + /* not worth thinking about */ + exit (0); + } + + if (is_graceful) { +#ifndef SCOREBOARD_FILE + int i; +#endif + + /* USE WITH CAUTION: Graceful restarts are not known to work + * in various configurations on the architectures we support. */ + scoreboard_image->global.exit_generation = generation; + update_scoreboard_global (); + + log_error ("SIGUSR1 received. Doing graceful restart",server_conf); + kill_cleanups_for_fd (pconf, sd); + /* kill off the idle ones */ + if (ap_killpg(pgrp, SIGUSR1) < 0) { + log_unixerr ("killpg SIGUSR1", NULL, NULL, server_conf); + } +#ifndef SCOREBOARD_FILE + /* This is mostly for debugging... so that we know what is still + * gracefully dealing with existing request. But we can't really + * do it if we're in a SCOREBOARD_FILE because it'll cause + * corruption too easily. + */ + sync_scoreboard_image(); + for (i = 0; i < daemons_limit; ++i ) { + if (scoreboard_image->servers[i].status != SERVER_DEAD) { + scoreboard_image->servers[i].status = SERVER_GRACEFUL; + } + } +#endif + } + else { + /* Kill 'em off */ + if (ap_killpg (pgrp, SIGHUP) < 0) { + log_unixerr ("killpg SIGHUP", NULL, NULL, server_conf); + } + reclaim_child_processes(); /* Not when just starting up */ + log_error ("SIGHUP received. Attempting to restart", server_conf); + } + ++generation; + + } while (restart_pending); + +} /* standalone_main */ + +extern char *optarg; +extern int optind; + +int +main(int argc, char *argv[]) +{ + int c; + +#ifdef AUX + (void)set42sig(); +#endif + +#ifdef SecureWare + if(set_auth_parameters(argc,argv) < 0) + perror("set_auth_parameters"); + if(getluid() < 0) + if(setluid(getuid()) < 0) + perror("setluid"); + if(setreuid(0, 0) < 0) + perror("setreuid"); +#endif + + init_alloc(); + pconf = permanent_pool; + ptrans = make_sub_pool(pconf); + + server_argv0 = argv[0]; + strncpy (server_root, HTTPD_ROOT, sizeof(server_root)-1); + server_root[sizeof(server_root)-1] = '\0'; + strncpy (server_confname, SERVER_CONFIG_FILE, sizeof(server_root)-1); + server_confname[sizeof(server_confname)-1] = '\0'; + + while((c = getopt(argc,argv,"Xd:f:vhl")) != -1) { + switch(c) { + case 'd': + strncpy (server_root, optarg, sizeof(server_root)-1); + server_root[sizeof(server_root)-1] = '\0'; + break; + case 'f': + strncpy (server_confname, optarg, sizeof(server_confname)-1); + server_confname[sizeof(server_confname)-1] = '\0'; + break; + case 'v': + printf("Server version %s.\n",SERVER_VERSION); + exit(0); + case 'h': + show_directives(); + exit(0); + case 'l': + show_modules(); + exit(0); + case 'X': + ++one_process; /* Weird debugging mode. */ + break; + case '?': + usage(argv[0]); + } + } + +#ifdef __EMX__ + printf("%s \n",SERVER_VERSION); + printf("OS/2 port by Garey Smiley <garey@slink.com> \n"); +#endif + + setup_prelinked_modules(); + + suexec_enabled = init_suexec(); + server_conf = read_config (pconf, ptrans, server_confname); + + if(standalone) { + clear_pool (pconf); /* standalone_main rereads... */ + standalone_main(argc, argv); + } + else { + conn_rec *conn; + request_rec *r; + struct sockaddr sa_server, sa_client; + BUFF *cio; + + open_logs(server_conf, pconf); + set_group_privs(); + default_server_hostnames (server_conf); + +#ifdef MPE + /* Only try to switch if we're running as MANAGER.SYS */ + if (geteuid() == 1 && user_id > 1) { + GETPRIVMODE(); + if (setuid(user_id) == -1) { + GETUSERMODE(); +#else + /* Only try to switch if we're running as root */ + if(!geteuid() && setuid(user_id) == -1) { +#endif + log_unixerr("setuid", NULL, "unable to change uid", server_conf); + exit (1); + } +#ifdef MPE + GETUSERMODE(); + } +#endif + + c = sizeof(sa_client); + if ((getpeername(fileno(stdin), &sa_client, &c)) < 0) + { +/* get peername will fail if the input isn't a socket */ + perror("getpeername"); + memset(&sa_client, '\0', sizeof(sa_client)); + } + + c = sizeof(sa_server); + if(getsockname(fileno(stdin), &sa_server, &c) < 0) { + perror("getsockname"); + fprintf(stderr, "Error getting local address\n"); + exit(1); + } + server_conf->port =ntohs(((struct sockaddr_in *)&sa_server)->sin_port); + cio = bcreate(ptrans, B_RDWR); +#ifdef MPE +/* HP MPE 5.5 inetd only passes the incoming socket as stdin (fd 0), whereas + HPUX inetd passes the incoming socket as stdin (fd 0) and stdout (fd 1). + Go figure. SR 5003355016 has been submitted to request that the existing + functionality be documented, and then to enhance the functionality to be + like HPUX. */ + + cio->fd = fileno(stdin); +#else + cio->fd = fileno(stdout); +#endif + cio->fd_in = fileno(stdin); + conn = new_connection (ptrans, server_conf, cio, + (struct sockaddr_in *)&sa_client, + (struct sockaddr_in *)&sa_server,-1); + r = read_request (conn); + if (r) process_request (r); /* else premature EOF (ignore) */ + + while (r && conn->keepalive && !conn->aborted) { + destroy_pool(r->pool); + r = read_request (conn); + if (r) process_request (r); + } + + bclose(cio); + } + exit (0); +} + +#ifdef __EMX__ +#ifdef HAVE_MMAP +/* The next two routines are used to access shared memory under OS/2. */ +/* This requires EMX v09c to be installed. */ + +caddr_t create_shared_heap (const char *name, size_t size) +{ + ULONG rc; + void *mem; + Heap_t h; + + rc = DosAllocSharedMem (&mem, name, size, + PAG_COMMIT | PAG_READ | PAG_WRITE); + if (rc != 0) + return NULL; + h = _ucreate (mem, size, !_BLOCK_CLEAN, _HEAP_REGULAR | _HEAP_SHARED, + NULL, NULL); + if (h == NULL) + DosFreeMem (mem); + return (caddr_t)h; +} + +caddr_t get_shared_heap (const char *Name) +{ + + PVOID BaseAddress; /* Pointer to the base address of + the shared memory object */ + ULONG AttributeFlags; /* Flags describing characteristics + of the shared memory object */ + APIRET rc; /* Return code */ + + /* Request read and write access to */ + /* the shared memory object */ + AttributeFlags = PAG_WRITE | PAG_READ; + + rc = DosGetNamedSharedMem(&BaseAddress, Name, AttributeFlags); + + if(rc != 0) { + printf("DosGetNamedSharedMem error: return code = %ld", rc); + return 0; + } + + return BaseAddress; +} +#endif +#endif + diff --git a/APACHE_1_2_X/src/main/http_protocol.c b/APACHE_1_2_X/src/main/http_protocol.c new file mode 100644 index 00000000000..9b7c4da6e80 --- /dev/null +++ b/APACHE_1_2_X/src/main/http_protocol.c @@ -0,0 +1,1915 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +/* + * http_protocol.c --- routines which directly communicate with the client. + * + * Code originally by Rob McCool; much redone by Robert S. Thau + * and the Apache Group. + */ + +#define CORE_PRIVATE +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_protocol.h" +#include "http_main.h" +#include "http_log.h" /* For errors detected in basic auth + * common support code... + */ +#include "util_date.h" /* For parseHTTPdate and BAD_DATE */ +#include <stdarg.h> + +#define SET_BYTES_SENT(r) \ + do { if (r->sent_bodyct) \ + bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \ + } while (0) + + +static int parse_byterange (char *range, long clength, long *start, long *end) +{ + char *dash = strchr(range, '-'); + + if (!dash) + return 0; + + if ((dash == range)) { + /* In the form "-5" */ + *start = clength - atol(dash + 1); + *end = clength - 1; + } + else { + *dash = '\0'; + dash++; + *start = atol(range); + if (*dash) + *end = atol(dash); + else /* "5-" */ + *end = clength -1; + } + + if (*start > *end) + return 0; + + if (*end >= clength) + *end = clength - 1; + + return 1; +} + +static int internal_byterange(int, long*, request_rec*, char**, long*, long*); + +int set_byterange (request_rec *r) +{ + char *range, *if_range, *match; + char ts[MAX_STRING_LEN]; + long range_start, range_end; + + if (!r->clength || r->assbackwards) return 0; + + /* Check for Range request-header (HTTP/1.1) or Request-Range for + * backwards-compatibility with second-draft Luotonen/Franks + * byte-ranges (e.g. Netscape Navigator 2-3). + * + * We support this form, with Request-Range, and (farther down) we + * send multipart/x-byteranges instead of multipart/byteranges for + * Request-Range based requests to work around a bug in Netscape + * Navigator 2-3 and MSIE 3. + */ + + if (!(range = table_get(r->headers_in, "Range"))) + range = table_get(r->headers_in, "Request-Range"); + + if (!range || strncmp(range, "bytes=", 6)) { + table_set (r->headers_out, "Accept-Ranges", "bytes"); + return 0; + } + + /* Check the If-Range header for Etag or Date */ + + if ((if_range = table_get(r->headers_in, "If-Range"))) { + if (if_range[0] == '"') { + if (!(match = table_get(r->headers_out, "Etag")) || + (strcasecmp(if_range, match) != 0)) + return 0; + } + else if (!(match = table_get(r->headers_out, "Last-Modified")) || + (strcasecmp(if_range, match) != 0)) + return 0; + } + + if (!strchr(range, ',')) { + /* A single range */ + if (!parse_byterange(pstrdup(r->pool, range + 6), r->clength, + &range_start, &range_end)) + return 0; + + r->byterange = 1; + + ap_snprintf(ts, sizeof(ts), "bytes %ld-%ld/%ld", + range_start, range_end, r->clength); + table_set(r->headers_out, "Content-Range", ts); + ap_snprintf(ts, sizeof(ts), "%ld", range_end - range_start + 1); + table_set(r->headers_out, "Content-Length", ts); + } + else { + /* a multiple range */ + char boundary[33]; /* Long enough */ + char *r_range = pstrdup(r->pool, range + 6); + long tlength = 0; + + r->byterange = 2; + ap_snprintf(boundary, sizeof(boundary), "%lx%lx", + r->request_time, (long)getpid()); + r->boundary = pstrdup(r->pool, boundary); + while (internal_byterange(0, &tlength, r, &r_range, NULL, NULL)); + ap_snprintf(ts, sizeof(ts), "%ld", tlength); + table_set(r->headers_out, "Content-Length", ts); + } + + r->status = PARTIAL_CONTENT; + r->range = range + 6; + + return 1; +} + +int each_byterange (request_rec *r, long *offset, long *length) +{ + return internal_byterange(1, NULL, r, &r->range, offset, length); +} + +/* If this function is called with realreq=1, it will spit out + * the correct headers for a byterange chunk, and set offset and + * length to the positions they should be. + * + * If it is called with realreq=0, it will add to tlength the length + * it *would* have used with realreq=1. + * + * Either case will return 1 if it should be called again, and 0 + * when done. + * + */ + +static int internal_byterange(int realreq, long *tlength, request_rec *r, + char **r_range, long *offset, long *length) +{ + long range_start, range_end; + char *range; + + if (!**r_range) { + if (r->byterange > 1) { + if (realreq) + rvputs(r, "\015\012--", r->boundary, "--\015\012", NULL); + else + *tlength += 4 + strlen(r->boundary) + 4; + } + return 0; + } + + range = getword_nc(r->pool, r_range, ','); + if (!parse_byterange(range, r->clength, &range_start, &range_end)) + /* Skip this one */ + return internal_byterange(realreq, tlength, r, r_range, offset, + length); + + if (r->byterange > 1) { + char *ct = r->content_type ? r->content_type : default_type(r); + char ts[MAX_STRING_LEN]; + + ap_snprintf(ts, sizeof(ts), "%ld-%ld/%ld", range_start, range_end, r->clength); + if (realreq) + rvputs(r, "\015\012--", r->boundary, "\015\012Content-type: ", + ct, "\015\012Content-range: bytes ", ts, "\015\012\015\012", + NULL); + else + *tlength += 4 + strlen(r->boundary) + 16 + strlen(ct) + 23 + + strlen(ts) + 4; + } + + if (realreq) { + *offset = range_start; + *length = range_end - range_start + 1; + } + else { + *tlength += range_end - range_start + 1; + } + return 1; +} + +int set_content_length (request_rec *r, long clength) +{ + char ts[MAX_STRING_LEN]; + + r->clength = clength; + + ap_snprintf (ts, sizeof(ts), "%ld", clength); + table_set (r->headers_out, "Content-Length", ts); + + return 0; +} + +int set_keepalive(request_rec *r) +{ + int ka_sent = 0; + int wimpy = find_token(r->pool, + table_get(r->headers_out, "Connection"), "close"); + char *conn = table_get(r->headers_in, "Connection"); + + /* The following convoluted conditional determines whether or not + * the current connection should remain persistent after this response + * (a.k.a. HTTP Keep-Alive) and whether or not the output message + * body should use the HTTP/1.1 chunked transfer-coding. In English, + * + * IF we have not marked this connection as errored; + * and the response body has a defined length due to the status code + * being 304 or 204, the request method being HEAD, already + * having defined Content-Length or Transfer-Encoding: chunked, or + * the request version being HTTP/1.1 and thus capable of being set + * as chunked [we know the (r->chunked = 1) side-effect is ugly]; + * and the server configuration enables keep-alive; + * and the server configuration has a reasonable inter-request timeout; + * and there is no maximum # requests or the max hasn't been reached; + * and the response status does not require a close; + * and the response generator has not already indicated close; + * and the client did not request non-persistence (Connection: close); + * and the client is requesting an HTTP/1.0-style keep-alive + * and we haven't been configured to ignore the buggy twit, + * or the client claims to be HTTP/1.1 compliant (perhaps a proxy); + * THEN we can be persistent, which requires more headers be output. + * + * Note that the condition evaluation order is extremely important. + */ + if ((r->connection->keepalive != -1) && + ((r->status == HTTP_NOT_MODIFIED) || + (r->status == HTTP_NO_CONTENT) || + r->header_only || + table_get(r->headers_out, "Content-Length") || + find_last_token(r->pool, + table_get(r->headers_out, "Transfer-Encoding"), + "chunked") || + ((r->proto_num >= 1001) && (r->chunked = 1))) && + r->server->keep_alive && + (r->server->keep_alive_timeout > 0) && + ((r->server->keep_alive_max == 0) || + (r->server->keep_alive_max > r->connection->keepalives)) && + !status_drops_connection(r->status) && + !wimpy && + !find_token(r->pool, conn, "close") && + (((ka_sent = find_token(r->pool, conn, "keep-alive")) && + !table_get(r->subprocess_env, "nokeepalive")) || + (r->proto_num >= 1001)) + ) { + char header[256]; + int left = r->server->keep_alive_max - r->connection->keepalives; + + r->connection->keepalive = 1; + r->connection->keepalives++; + + /* If they sent a Keep-Alive token, send one back */ + if (ka_sent) { + if (r->server->keep_alive_max) + ap_snprintf(header, sizeof(header), "timeout=%d, max=%d", + r->server->keep_alive_timeout, left); + else + ap_snprintf(header, sizeof(header), "timeout=%d", + r->server->keep_alive_timeout); + table_set(r->headers_out, "Keep-Alive", header); + table_merge(r->headers_out, "Connection", "Keep-Alive"); + } + + return 1; + } + + /* Otherwise, we need to indicate that we will be closing this + * connection immediately after the current response. + * + * We only really need to send "close" to HTTP/1.1 clients, but we + * always send it anyway, because a broken proxy may identify itself + * as HTTP/1.0, but pass our request along with our HTTP/1.1 tag + * to a HTTP/1.1 client. Better safe than sorry. + */ + table_merge(r->headers_out, "Connection", "close"); + + r->connection->keepalive = 0; + + return 0; +} + +int set_last_modified(request_rec *r, time_t mtime) +{ + char *etag, weak_etag[MAX_STRING_LEN]; + char *if_match, *if_modified_since, *if_unmodified, *if_nonematch; + time_t now = time(NULL); + + if (now < 0) + now = r->request_time; + + table_set(r->headers_out, "Last-Modified", + gm_timestr_822(r->pool, (mtime > now) ? now : mtime)); + + /* Make an ETag header out of various pieces of information. We use + * the last-modified date and, if we have a real file, the + * length and inode number - note that this doesn't have to match + * the content-length (i.e. includes), it just has to be unique + * for the file. + * + * If the request was made within a second of the last-modified date, + * we send a weak tag instead of a strong one, since it could + * be modified again later in the second, and the validation + * would be incorrect. + */ + + if (r->finfo.st_mode != 0) + ap_snprintf(weak_etag, sizeof(weak_etag), "W/\"%lx-%lx-%lx\"", + (unsigned long)r->finfo.st_ino, + (unsigned long)r->finfo.st_size, (unsigned long)mtime); + else + ap_snprintf(weak_etag, sizeof(weak_etag), "W/\"%lx\"", + (unsigned long)mtime); + + etag = weak_etag + ((r->request_time - mtime > 1) ? 2 : 0); + table_set(r->headers_out, "ETag", etag); + + /* Check for conditional requests --- note that we only want to do + * this if we are successful so far and we are not processing a + * subrequest or an ErrorDocument. + * + * The order of the checks is important, since etag checks are supposed + * to be more accurate than checks relative to the modification time. + */ + + if (!is_HTTP_SUCCESS(r->status) || r->no_local_copy) + return OK; + + /* If an If-Match request-header field was given and + * if our ETag does not match any of the entity tags in that field + * and the field value is not "*" (meaning match anything), then + * respond with a status of 412 (Precondition Failed). + */ + + if ((if_match = table_get(r->headers_in, "If-Match")) != NULL) { + if ((if_match[0] != '*') && !find_token(r->pool, if_match, etag)) + return HTTP_PRECONDITION_FAILED; + } + + /* Else if a valid If-Unmodified-Since request-header field was given + * and the requested resource has been modified since the time + * specified in this field, then the server MUST + * respond with a status of 412 (Precondition Failed). + */ + + else if ((if_unmodified = table_get(r->headers_in, "If-Unmodified-Since")) + != NULL) { + time_t ius = parseHTTPdate(if_unmodified); + + if ((ius != BAD_DATE) && (mtime > ius)) + return HTTP_PRECONDITION_FAILED; + } + + /* If an If-None-Match request-header field was given and + * if our ETag matches any of the entity tags in that field or + * if the field value is "*" (meaning match anything), then + * if the request method was GET or HEAD, the server SHOULD + * respond with a 304 (Not Modified) response. + * For all other request methods, the server MUST + * respond with a status of 412 (Precondition Failed). + */ + + if ((if_nonematch = table_get(r->headers_in, "If-None-Match")) != NULL) { + if ((if_nonematch[0] == '*') || find_token(r->pool,if_nonematch,etag)) + return (r->method_number == M_GET) ? HTTP_NOT_MODIFIED + : HTTP_PRECONDITION_FAILED; + } + + /* Else if a valid If-Modified-Since request-header field was given + * and it is a GET or HEAD request + * and the requested resource has not been modified since the time + * specified in this field, then the server MUST + * respond with a status of 304 (Not Modified). + * A date later than the server's current request time is invalid. + */ + + else if ((r->method_number == M_GET) && ((if_modified_since = + table_get(r->headers_in, "If-Modified-Since")) != NULL)) { + time_t ims = parseHTTPdate(if_modified_since); + + if ((ims >= mtime) && (ims <= r->request_time)) + return HTTP_NOT_MODIFIED; + } + + return OK; +} + +/* Get a line of protocol input, including any continuation lines + * caused by MIME folding (or broken clients) if fold != 0, and place it + * in the buffer s, of size n bytes, without the ending newline. + * + * Returns -1 on error, or the length of s. + * + * Note: Because bgets uses 1 char for newline and 1 char for NUL, + * the most we can get is (n - 2) actual characters if it + * was ended by a newline, or (n - 1) characters if the line + * length exceeded (n - 1). So, if the result == (n - 1), + * then the actual input line exceeded the buffer length, + * and it would be a good idea for the caller to puke 400 or 414. + */ +static int getline(char *s, int n, BUFF *in, int fold) +{ + char *pos, next; + int retval; + int total = 0; + + pos = s; + + do { + retval = bgets(pos, n, in); /* retval == -1 if error, 0 if EOF */ + + if (retval <= 0) + return ((retval < 0) && (total == 0)) ? -1 : total; + + /* retval is the number of characters read, not including NUL */ + + n -= retval; /* Keep track of how much of s is full */ + pos += (retval-1); /* and where s ends */ + total += retval; /* and how long s has become */ + + if (*pos == '\n') { /* Did we get a full line of input? */ + *pos = '\0'; + --total; ++n; + } + else return total; /* if not, input line exceeded buffer size */ + + /* Continue appending if line folding is desired and + * the last line was not empty and we have room in the buffer and + * the next line begins with a continuation character. + */ + } while (fold && (retval != 1) && (n > 1) && + (blookc(&next, in) == 1) && + ((next == ' ') || (next == '\t'))); + + return total; +} + +void parse_uri (request_rec *r, const char *uri) +{ + const char *s; + +#ifdef __EMX__ + /* Variable for OS/2 fix below. */ + int loop; +#endif + +/* A proxy request contains a ':' early on, but not as first character */ + for (s=uri; s != '\0'; s++) + if (!isalnum(*s) && *s != '+' && *s != '-' && *s != '.') break; + + if (*s == ':' && s != uri) + { + r->proxyreq = 1; + r->uri = pstrdup(r->pool, uri); + r->args = NULL; + } + else if (r->method && !strcmp(r->method, "TRACE")) { + r->proxyreq = 0; + r->uri = pstrdup(r->pool, uri); + r->args = NULL; + } + else { + r->proxyreq = 0; + r->uri = getword (r->pool, &uri, '?'); + +#ifdef __EMX__ + /* Handle path translations for OS/2 and plug security hole. */ + /* This will prevent "http://www.wherever.com/..\..\/" from + returning a directory for the root drive. */ + for (loop = 0; loop <= strlen(r->uri); ++loop) { + if (r->uri[loop] == '\\') + r->uri[loop] = '/'; + }; + + /* Fix OS/2 HPFS filename case problem. */ + r->uri = strlwr(r->uri); +#endif + + if (*uri) r->args= pstrdup(r->pool, uri); + else r->args = NULL; + } +} + +const char *check_fulluri (request_rec *r, const char *uri) { + char *name, *host; + int i; + unsigned port; + + /* This routine parses full URLs, if they match the server */ + if (strncmp(uri, "http://", 7)) return uri; + name = pstrdup(r->pool, uri + 7); + + /* Find the hostname, assuming a valid request */ + i = ind(name, '/'); + name[i] = '\0'; + + /* Find the port */ + host = getword_nc(r->pool, &name, ':'); + if (*name) port = atoi(name); + else port = 80; + + /* Make sure ports patch */ + if (port != r->server->port) return uri; + + /* Save it for later use */ + r->hostname = pstrdup(r->pool, host); + r->hostlen = 7 + i; + + /* The easy cases first */ + if (!strcasecmp(host, r->server->server_hostname)) { + return (uri + r->hostlen); + } + else if (!strcmp(host, inet_ntoa(r->connection->local_addr.sin_addr))) { + return (uri + r->hostlen); + } + + /* Now things get a bit trickier - check the IP address(es) of the host */ + /* they gave, see if it matches ours. */ + else { + struct hostent *hp; + int n; + + if ((hp = gethostbyname(host))) { + for (n = 0; hp->h_addr_list[n] != NULL; n++) { + if (r->connection->local_addr.sin_addr.s_addr == + (((struct in_addr *)(hp->h_addr_list[n]))->s_addr)) { + return (uri + r->hostlen); + } + } + } + } + + return uri; +} + +int read_request_line (request_rec *r) +{ + char l[HUGE_STRING_LEN]; + const char *ll = l, *uri; + conn_rec *conn = r->connection; + int major = 1, minor = 0; /* Assume HTTP/1.0 if non-"HTTP" protocol*/ + int len; + + /* Read past empty lines until we get a real request line, + * a read error, the connection closes (EOF), or we timeout. + * + * We skip empty lines because browsers have to tack a CRLF on to the end + * of POSTs to support old CERN webservers. But note that we may not + * have flushed any previous response completely to the client yet. + * We delay the flush as long as possible so that we can improve + * performance for clients that are pipelining requests. If a request + * is pipelined then we won't block during the (implicit) read() below. + * If the requests aren't pipelined, then the client is still waiting + * for the final buffer flush from us, and we will block in the implicit + * read(). B_SAFEREAD ensures that the BUFF layer flushes if it will + * have to block during a read. + */ + bsetflag( conn->client, B_SAFEREAD, 1 ); + while ((len = getline(l, HUGE_STRING_LEN, conn->client, 0)) <= 0) { + if ((len < 0) || bgetflag(conn->client, B_EOF)) { + bsetflag( conn->client, B_SAFEREAD, 0 ); + return 0; + } + } + /* we've probably got something to do, ignore graceful restart requests */ + signal (SIGUSR1, SIG_IGN); + bsetflag( conn->client, B_SAFEREAD, 0 ); + if (len == (HUGE_STRING_LEN - 1)) { + log_printf(r->server, "request failed for %s, reason: URI too long", + get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME)); + r->status = HTTP_REQUEST_URI_TOO_LARGE; + return 0; + } + + r->request_time = time(NULL); + r->the_request = pstrdup (r->pool, l); + r->method = getword_white(r->pool, &ll); + uri = getword_white(r->pool, &ll); + uri = check_fulluri(r, uri); + parse_uri (r, uri); + + r->assbackwards = (ll[0] == '\0'); + r->protocol = pstrdup (r->pool, ll[0] ? ll : "HTTP/0.9"); + sscanf(r->protocol, "HTTP/%d.%d", &major, &minor); + r->proto_num = 1000*major + minor; + + return 1; +} + +void get_mime_headers (request_rec *r) +{ + conn_rec *c = r->connection; + int len; + char *value; + char field[MAX_STRING_LEN]; + + /* Read header lines until we get the empty separator line, + * a read error, the connection closes (EOF), or we timeout. + * Should we also check for overflow (len == MAX_STRING_LEN-1)? + */ + while ((len = getline(field, MAX_STRING_LEN, c->client, 1)) > 0) { + + if (!(value = strchr(field,':'))) /* Find the colon separator */ + continue; /* or should puke 400 here */ + + *value = '\0'; + ++value; + while (isspace(*value)) ++value; /* Skip to start of value */ + + table_merge(r->headers_in, field, value); + } +} + +static void check_hostalias (request_rec *r) { + const char *hostname=r->hostname; + char *host = getword(r->pool, &hostname, ':'); /* Get rid of port */ + unsigned port = (*hostname) ? atoi(hostname) : 80; + server_rec *s; + int l; + + if (port && (port != r->server->port)) + return; + + l = strlen(host)-1; + if ((host[l]) == '.') { + host[l] = '\0'; + } + + r->hostname = host; + + for (s = r->server->next; s; s = s->next) { + const char *names; + server_addr_rec *sar; + + if (s->addrs == NULL) { + /* this server has been disabled because of DNS screwups during + configuration */ + continue; + } + + if ((!strcasecmp(host, s->server_hostname)) && (port == s->port)) { + r->server = r->connection->server = s; + if (r->hostlen && !strncmp(r->uri, "http://", 7)) { + r->uri += r->hostlen; + parse_uri(r, r->uri); + } + } + + /* search all the names from <VirtualHost> directive */ + for( sar = s->addrs; sar; sar = sar->next ) { + if( !strcasecmp( sar->virthost, host ) && + ( (sar->host_port == 0) || (port == sar->host_port) )) { + r->server = r->connection->server = s; + if( r->hostlen && !strncmp( r->uri, "http://", 7) ) { + r->uri += r->hostlen; + r->proxyreq = 0; + } + } + } + + /* search all the aliases from ServerAlias directive */ + names = s->names; + if( names ) { + while (*names) { + char *name = getword_conf (r->pool, &names); + + if ((is_matchexp(name) && !strcasecmp_match(host, name)) || + (!strcasecmp(host, name))) { + r->server = r->connection->server = s; + if (r->hostlen && !strncmp(r->uri, "http://", 7)) { + r->uri += r->hostlen; + r->proxyreq = 0; + } + } + } + } + } +} + +void check_serverpath (request_rec *r) { + server_rec *s; + + /* This is in conjunction with the ServerPath code in + * http_core, so we get the right host attached to a non- + * Host-sending request. + */ + + for (s = r->server->next; s; s = s->next) { + if (s->addrs && s->path && !strncmp(r->uri, s->path, s->pathlen) && + (s->path[s->pathlen - 1] == '/' || + r->uri[s->pathlen] == '/' || + r->uri[s->pathlen] == '\0')) + r->server = r->connection->server = s; + } +} + +request_rec *read_request (conn_rec *conn) +{ + request_rec *r = (request_rec *)pcalloc (conn->pool, sizeof(request_rec)); + + r->connection = conn; + conn->server = conn->base_server; + r->server = conn->server; + r->pool = make_sub_pool(conn->pool); + + conn->keptalive = conn->keepalive; + conn->keepalive = 0; + + conn->user = NULL; + conn->auth_type = NULL; + + r->headers_in = make_table (r->pool, 50); + r->subprocess_env = make_table (r->pool, 50); + r->headers_out = make_table (r->pool, 5); + r->err_headers_out = make_table (r->pool, 5); + r->notes = make_table (r->pool, 5); + + r->request_config = create_request_config (r->pool); + r->per_dir_config = r->server->lookup_defaults; /* For now. */ + + r->sent_bodyct = 0; /* bytect isn't for body */ + + r->read_length = 0; + r->read_body = REQUEST_NO_BODY; + + r->status = HTTP_REQUEST_TIME_OUT; /* Until we get a request */ + + /* Get the request... */ + + keepalive_timeout("read request line", r); + if (!read_request_line (r)) { + kill_timeout(r); + return NULL; + } + if (!r->assbackwards) { + hard_timeout("read request headers", r); + get_mime_headers (r); + } + kill_timeout(r); + + r->status = HTTP_OK; /* Until further notice. */ + + /* handle Host header here, to get virtual server */ + + if (r->hostname || (r->hostname = table_get(r->headers_in, "Host"))) + check_hostalias(r); + else + check_serverpath(r); + + /* we may have switched to another server */ + r->per_dir_config = r->server->lookup_defaults; + + conn->keptalive = 0; /* We now have a request to play with */ + + if(!strcmp(r->method, "HEAD")) { + r->header_only=1; + r->method_number = M_GET; + } + else if(!strcmp(r->method, "GET")) + r->method_number = M_GET; + else if(!strcmp(r->method,"POST")) + r->method_number = M_POST; + else if(!strcmp(r->method,"PUT")) + r->method_number = M_PUT; + else if(!strcmp(r->method,"DELETE")) + r->method_number = M_DELETE; + else if(!strcmp(r->method,"CONNECT")) + r->method_number = M_CONNECT; + else if(!strcmp(r->method,"OPTIONS")) + r->method_number = M_OPTIONS; + else if(!strcmp(r->method,"TRACE")) + r->method_number = M_TRACE; + else + r->method_number = M_INVALID; /* Will eventually croak. */ + + return r; +} + +/* + * A couple of other functions which initialize some of the fields of + * a request structure, as appropriate for adjuncts of one kind or another + * to a request in progress. Best here, rather than elsewhere, since + * *someone* has to set the protocol-specific fields... + */ + +void set_sub_req_protocol (request_rec *rnew, const request_rec *r) +{ + rnew->the_request = r->the_request; /* Keep original request-line */ + + rnew->assbackwards = 1; /* Don't send headers from this. */ + rnew->no_local_copy = 1; /* Don't try to send USE_LOCAL_COPY for a + * fragment. + */ + rnew->method = "GET"; rnew->method_number = M_GET; + rnew->protocol = "INCLUDED"; + + rnew->status = HTTP_OK; + + rnew->headers_in = r->headers_in; + rnew->subprocess_env = copy_table (rnew->pool, r->subprocess_env); + rnew->headers_out = make_table (rnew->pool, 5); + rnew->err_headers_out = make_table (rnew->pool, 5); + rnew->notes = make_table (rnew->pool, 5); + + rnew->read_length = r->read_length; + rnew->read_body = REQUEST_NO_BODY; + + rnew->main = (request_rec *)r; +} + +void finalize_sub_req_protocol (request_rec *sub) +{ + SET_BYTES_SENT (sub->main); +} + +/* Support for the Basic authentication protocol, and a bit for Digest. + */ + +void note_auth_failure(request_rec *r) +{ + if (!strcasecmp(auth_type(r), "Basic")) + note_basic_auth_failure(r); + else if(!strcasecmp(auth_type(r), "Digest")) + note_digest_auth_failure(r); +} + +void note_basic_auth_failure(request_rec *r) +{ + if (strcasecmp(auth_type(r), "Basic")) + note_auth_failure(r); + else + table_set (r->err_headers_out, "WWW-Authenticate", + pstrcat(r->pool, "Basic realm=\"", auth_name(r), "\"", NULL)); +} + +void note_digest_auth_failure(request_rec *r) +{ + char nonce[256]; + + ap_snprintf(nonce, sizeof(nonce), "%lu", r->request_time); + table_set (r->err_headers_out, "WWW-Authenticate", + pstrcat(r->pool, "Digest realm=\"", auth_name(r), + "\", nonce=\"", nonce, "\"", NULL)); +} + +int get_basic_auth_pw (request_rec *r, char **pw) +{ + const char *auth_line = table_get (r->headers_in, "Authorization"); + char *t; + + if(!(t = auth_type(r)) || strcasecmp(t, "Basic")) + return DECLINED; + + if (!auth_name (r)) { + log_reason ("need AuthName", r->uri, r); + return SERVER_ERROR; + } + + if(!auth_line) { + note_basic_auth_failure (r); + return AUTH_REQUIRED; + } + + if (strcmp(getword (r->pool, &auth_line, ' '), "Basic")) { + /* Client tried to authenticate using wrong auth scheme */ + log_reason ("client used wrong authentication scheme", r->uri, r); + note_basic_auth_failure (r); + return AUTH_REQUIRED; + } + + t = uudecode (r->pool, auth_line); + r->connection->user = getword_nulls_nc (r->pool, &t, ':'); + r->connection->auth_type = "Basic"; + + *pw = t; + + return OK; +} + +/* New Apache routine to map status codes into array indicies + * e.g. 100 -> 0, 101 -> 1, 200 -> 2 ... + * The number of status lines must equal the value of RESPONSE_CODES (httpd.h) + * and must be listed in order. + */ + +static char *status_lines[] = { + "100 Continue", + "101 Switching Protocols", +#define LEVEL_200 2 + "200 OK", + "201 Created", + "202 Accepted", + "203 Non-Authoritative Information", + "204 No Content", + "205 Reset Content", + "206 Partial Content", +#define LEVEL_300 9 + "300 Multiple Choices", + "301 Moved Permanently", + "302 Moved Temporarily", + "303 See Other", + "304 Not Modified", + "305 Use Proxy", +#define LEVEL_400 15 + "400 Bad Request", + "401 Authorization Required", + "402 Payment Required", + "403 Forbidden", + "404 File Not Found", + "405 Method Not Allowed", + "406 Not Acceptable", + "407 Proxy Authentication Required", + "408 Request Time-out", + "409 Conflict", + "410 Gone", + "411 Length Required", + "412 Precondition Failed", + "413 Request Entity Too Large", + "414 Request-URI Too Large", + "415 Unsupported Media Type", +#define LEVEL_500 31 + "500 Internal Server Error", + "501 Method Not Implemented", + "502 Bad Gateway", + "503 Service Temporarily Unavailable", + "504 Gateway Time-out", + "505 HTTP Version Not Supported", + "506 Variant Also Varies" +}; + +/* The index is found by its offset from the x00 code of each level. + * Although this is fast, it will need to be replaced if some nutcase + * decides to define a high-numbered code before the lower numbers. + * If that sad event occurs, replace the code below with a linear search + * from status_lines[shortcut[i]] to status_lines[shortcut[i+1]-1]; + */ + +int index_of_response(int status) +{ + static int shortcut[6] = { 0, LEVEL_200, LEVEL_300, LEVEL_400, + LEVEL_500, RESPONSE_CODES }; + int i, pos; + + if (status < 100) /* Below 100 is illegal for HTTP status */ + return LEVEL_500; + + for (i = 0; i < 5; i++) { + status -= 100; + if (status < 100) { + pos = (status + shortcut[i]); + if (pos < shortcut[i+1]) + return pos; + else + return LEVEL_500; /* status unknown (falls in gap) */ + } + } + return LEVEL_500; /* 600 or above is also illegal */ +} + +/* Send a single HTTP header field to the client. Note that this function + * is used in calls to table_do(), so their interfaces are co-dependent. + * In other words, don't change this one without checking table_do in alloc.c. + * It returns true unless there was a write error of some kind. + */ +int send_header_field (request_rec *r, const char *fieldname, + const char *fieldval) +{ + return (0 < bvputs(r->connection->client, + fieldname, ": ", fieldval, "\015\012", NULL)); +} + +void basic_http_header (request_rec *r) +{ + char *protocol; + + if (r->assbackwards) return; + + if (!r->status_line) + r->status_line = status_lines[index_of_response(r->status)]; + + if (table_get(r->subprocess_env,"force-response-1.0")) + protocol = "HTTP/1.0"; + else + protocol = SERVER_PROTOCOL; + + /* Output the HTTP/1.x Status-Line and the Date and Server fields */ + + bvputs(r->connection->client, + protocol, " ", r->status_line, "\015\012", NULL); + + send_header_field(r, "Date", gm_timestr_822(r->pool, r->request_time)); + send_header_field(r, "Server", SERVER_VERSION); + + table_unset(r->headers_out, "Date"); /* Avoid bogosity */ + table_unset(r->headers_out, "Server"); +} + +/* Navigator versions 2.x, 3.x and 4.0 betas up to and including 4.0b2 + * have a header parsing bug. If the terminating \r\n occur starting + * at the 256th or 257th byte of output then it will not properly parse + * the headers. Curiously it doesn't exhibit this problem at 512, 513. + * We are guessing that this is because their initial read of a new request + * uses a 256 byte buffer, and subsequent reads use a larger buffer. + * So the problem might exist at different offsets as well. + * + * This should also work on keepalive connections assuming they use the + * same small buffer for the first read of each new request. + * + * At any rate, we check the bytes written so far and, if we are about to + * tickle the bug, we instead insert a bogus padding header. Since the bug + * manifests as a broken image in Navigator, users blame the server. :( + * It is more expensive to check the User-Agent than it is to just add the + * bytes, so we haven't used the BrowserMatch feature here. + */ +static void terminate_header (BUFF *client) +{ + long int bs; + + bgetopt(client, BO_BYTECT, &bs); + if (bs == 256 || bs == 257) + bputs("X-Pad: avoid browser bug\015\012", client); + + bputs("\015\012", client); /* Send the terminating empty line */ +} + +static char *make_allow(request_rec *r) +{ + int allowed = r->allowed; + + if( allowed == 0 ) { + /* RFC2068 #14.7, Allow must contain at least one method. So rather + * than deal with the possibility of trying not to emit an Allow: + * header, i.e. #10.4.6 says 405 Method Not Allowed MUST include + * an Allow header, we'll just say TRACE is valid. + */ + return( "TRACE" ); + } + + return 2 + pstrcat(r->pool, (allowed & (1 << M_GET)) ? ", GET, HEAD" : "", + (allowed & (1 << M_POST)) ? ", POST" : "", + (allowed & (1 << M_PUT)) ? ", PUT" : "", + (allowed & (1 << M_DELETE)) ? ", DELETE" : "", + (allowed & (1 << M_OPTIONS)) ? ", OPTIONS" : "", + (allowed & (1 << M_TRACE)) ? ", TRACE" : "", + NULL); + +} + +int send_http_trace (request_rec *r) +{ + /* Get the original request */ + while (r->prev) r = r->prev; + + hard_timeout("send TRACE", r); + + r->content_type = "message/http"; + send_http_header(r); + + /* Now we recreate the request, and echo it back */ + + rvputs( r, r->the_request, "\015\012", NULL ); + + table_do((int (*)(void *, const char *, const char *))send_header_field, + (void *)r, r->headers_in, NULL); + bputs("\015\012", r->connection->client); + + kill_timeout(r); + return OK; +} + +int send_http_options(request_rec *r) +{ + const long int zero = 0L; + + if (r->assbackwards) return DECLINED; + + hard_timeout("send OPTIONS", r); + + basic_http_header(r); + + table_set(r->headers_out, "Content-Length", "0"); + table_set(r->headers_out, "Allow", make_allow(r)); + set_keepalive(r); + + table_do((int (*)(void *, const char *, const char *))send_header_field, + (void *)r, r->headers_out, NULL); + + terminate_header(r->connection->client); + + kill_timeout(r); + bsetopt(r->connection->client, BO_BYTECT, &zero); + + return OK; +} + +/* + * Here we try to be compatible with clients that want multipart/x-byteranges + * instead of multipart/byteranges (also see above), as per HTTP/1.1. We + * look for the Request-Range header (e.g. Netscape 2 and 3) as an indication + * that the browser supports an older protocol. We also check User-Agent + * for Microsoft Internet Explorer 3, which needs this as well. + */ + +static int use_range_x(request_rec *r) { + char *ua; + return (table_get(r->headers_in, "Request-Range") || + ((ua = table_get(r->headers_in, "User-Agent")) + && strstr(ua, "MSIE 3"))); +} + +void send_http_header(request_rec *r) +{ + int i; + const long int zero = 0L; + + if (r->assbackwards) { + if(!r->main) + bsetopt(r->connection->client, BO_BYTECT, &zero); + r->sent_bodyct = 1; + return; + } + + /* Now that we are ready to send a response, we need to combine the two + * header field tables into a single table. If we don't do this, our + * later attempts to set or unset a given fieldname might be bypassed. + */ + if (!is_empty_table(r->err_headers_out)) + r->headers_out = overlay_tables(r->pool, r->err_headers_out, + r->headers_out); + + hard_timeout("send headers", r); + + basic_http_header(r); + + set_keepalive(r); + + if (r->chunked) { + table_merge(r->headers_out, "Transfer-Encoding", "chunked"); + table_unset(r->headers_out, "Content-Length"); + } + + if (r->byterange > 1) + table_set(r->headers_out, "Content-Type", + pstrcat(r->pool, "multipart", use_range_x(r) ? "/x-" : "/", + "byteranges; boundary=", r->boundary, NULL)); + else if (r->content_type) + table_set(r->headers_out, "Content-Type", r->content_type); + else + table_set(r->headers_out, "Content-Type", default_type(r)); + + if (r->content_encoding) + table_set(r->headers_out, "Content-Encoding", r->content_encoding); + + if (r->content_languages && r->content_languages->nelts) { + for (i = 0; i < r->content_languages->nelts; ++i) { + table_merge(r->headers_out, "Content-Language", + ((char**)(r->content_languages->elts))[i]); + } + } + else if (r->content_language) + table_set(r->headers_out, "Content-Language", r->content_language); + + /* Control cachability for non-cachable responses if not already set + * by some other part of the server configuration. + */ + if (r->no_cache && !table_get(r->headers_out, "Expires")) + table_add(r->headers_out, "Expires", + gm_timestr_822(r->pool, r->request_time)); + + /* Send the entire table of header fields, terminated by an empty line. */ + + table_do((int (*)(void *, const char *, const char *))send_header_field, + (void *)r, r->headers_out, NULL); + + terminate_header(r->connection->client); + + kill_timeout(r); + + bsetopt(r->connection->client, BO_BYTECT, &zero); + r->sent_bodyct = 1; /* Whatever follows is real body stuff... */ + + /* Set buffer flags for the body */ + if (r->chunked) bsetflag(r->connection->client, B_CHUNK, 1); +} + +void finalize_request_protocol (request_rec *r) +{ + /* Turn off chunked encoding */ + + if (r->chunked && !r->connection->aborted) { + soft_timeout("send ending chunk", r); + bsetflag(r->connection->client, B_CHUNK, 0); + bputs("0\015\012", r->connection->client); + /* If we had footer "headers", we'd send them now */ + bputs("\015\012", r->connection->client); + kill_timeout(r); + } +} + +/* Here we deal with getting the request message body from the client. + * Whether or not the request contains a body is signaled by the presence + * of a non-zero Content-Length or by a Transfer-Encoding: chunked. + * + * Note that this is more complicated than it was in Apache 1.1 and prior + * versions, because chunked support means that the module does less. + * + * The proper procedure is this: + * + * 1. Call setup_client_block() near the beginning of the request + * handler. This will set up all the necessary properties, and will + * return either OK, or an error code. If the latter, the module should + * return that error code. The second parameter selects the policy to + * apply if the request message indicates a body, and how a chunked + * transfer-coding should be interpreted. Choose one of + * + * REQUEST_NO_BODY Send 413 error if message has any body + * REQUEST_CHUNKED_ERROR Send 411 error if body without Content-Length + * REQUEST_CHUNKED_DECHUNK If chunked, remove the chunks for me. + * REQUEST_CHUNKED_PASS Pass the chunks to me without removal. + * + * In order to use the last two options, the caller MUST provide a buffer + * large enough to hold a chunk-size line, including any extensions. + * + * 2. When you are ready to read a body (if any), call should_client_block(). + * This will tell the module whether or not to read input. If it is 0, + * the module should assume that there is no message body to read. + * This step also sends a 100 Continue response to HTTP/1.1 clients, + * so should not be called until the module is *definitely* ready to + * read content. (otherwise, the point of the 100 response is defeated). + * Never call this function more than once. + * + * 3. Finally, call get_client_block in a loop. Pass it a buffer and its size. + * It will put data into the buffer (not necessarily a full buffer), and + * return the length of the input block. When it is done reading, it will + * return 0 if EOF, or -1 if there was an error. + * If an error occurs on input, we force an end to keepalive. + */ + +int setup_client_block (request_rec *r, int read_policy) +{ + char *tenc = table_get(r->headers_in, "Transfer-Encoding"); + char *lenp = table_get(r->headers_in, "Content-Length"); + + r->read_body = read_policy; + r->read_chunked = 0; + r->remaining = 0; + + if (tenc) { + if (strcasecmp(tenc, "chunked")) { + log_printf(r->server, "Unknown Transfer-Encoding %s", tenc); + return HTTP_BAD_REQUEST; + } + if (r->read_body == REQUEST_CHUNKED_ERROR) { + log_reason("chunked Transfer-Encoding forbidden", r->uri, r); + return (lenp) ? HTTP_BAD_REQUEST : HTTP_LENGTH_REQUIRED; + } + + r->read_chunked = 1; + } + else if (lenp) { + char *pos = lenp; + + while (isdigit(*pos) || isspace(*pos)) ++pos; + if (*pos != '\0') { + log_printf(r->server, "Invalid Content-Length %s", lenp); + return HTTP_BAD_REQUEST; + } + + r->remaining = atol(lenp); + } + + if ((r->read_body == REQUEST_NO_BODY) && + (r->read_chunked || (r->remaining > 0))) { + log_printf(r->server, "%s with body is not allowed for %s", + r->method, r->uri); + return HTTP_REQUEST_ENTITY_TOO_LARGE; + } + + return OK; +} + +int should_client_block (request_rec *r) +{ + if (is_HTTP_ERROR(r->status)) + return 0; + + if (!r->read_chunked && (r->remaining <= 0)) + return 0; + + if (r->proto_num >= 1001) { /* sending 100 Continue interim response */ + bvputs(r->connection->client, + SERVER_PROTOCOL, " ", status_lines[0], "\015\012\015\012", NULL); + bflush(r->connection->client); + } + + return 1; +} + +static long get_chunk_size (char *b) +{ + long chunksize = 0; + + while (isxdigit(*b)) { + int xvalue = 0; + + if (*b >= '0' && *b <= '9') xvalue = *b - '0'; + else if (*b >= 'A' && *b <= 'F') xvalue = *b - 'A' + 0xa; + else if (*b >= 'a' && *b <= 'f') xvalue = *b - 'a' + 0xa; + + chunksize = (chunksize << 4) | xvalue; + ++b; + } + + return chunksize; +} + +/* get_client_block is called in a loop to get the request message body. + * This is quite simple if the client includes a content-length + * (the normal case), but gets messy if the body is chunked. Note that + * r->remaining is used to maintain state across calls and that + * r->read_length is the total number of bytes given to the caller + * across all invocations. It is messy because we have to be careful not + * to read past the data provided by the client, since these reads block. + * Returns 0 on End-of-body, -1 on error or premature chunk end. + * + * Reading the chunked encoding requires a buffer size large enough to + * hold a chunk-size line, including any extensions. For now, we'll leave + * that to the caller, at least until we can come up with a better solution. + */ +long get_client_block (request_rec *r, char *buffer, int bufsiz) +{ + int c; + long len_read, len_to_read; + long chunk_start = 0; + + if (!r->read_chunked) { /* Content-length read */ + len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining; + len_read = bread(r->connection->client, buffer, len_to_read); + if (len_read <= 0) { + if (len_read < 0) r->connection->keepalive = -1; + return len_read; + } + r->read_length += len_read; + r->remaining -= len_read; + return len_read; + } + + /* Handle chunked reading + * Note: we are careful to shorten the input bufsiz so that there + * will always be enough space for us to add a CRLF (if necessary). + */ + if (r->read_body == REQUEST_CHUNKED_PASS) + bufsiz -= 2; + if (bufsiz <= 0) + return -1; /* Cannot read chunked with a small buffer */ + + if (r->remaining == 0) { /* Start of new chunk */ + + chunk_start = getline(buffer, bufsiz, r->connection->client, 0); + if ((chunk_start <= 0) || (chunk_start >= (bufsiz - 1)) + || !isxdigit(*buffer)) { + r->connection->keepalive = -1; + return -1; + } + + len_to_read = get_chunk_size(buffer); + + if (len_to_read == 0) { /* Last chunk indicated, get footers */ + if (r->read_body == REQUEST_CHUNKED_DECHUNK) { + get_mime_headers(r); + ap_snprintf(buffer, bufsiz, "%ld", r->read_length); + table_unset(r->headers_in, "Transfer-Encoding"); + table_set(r->headers_in, "Content-Length", buffer); + return 0; + } + r->remaining = -1; /* Indicate footers in-progress */ + } + else { + r->remaining = len_to_read; + } + if (r->read_body == REQUEST_CHUNKED_PASS) { + buffer[chunk_start++] = CR; /* Restore chunk-size line end */ + buffer[chunk_start++] = LF; + buffer += chunk_start; /* and pass line on to caller */ + bufsiz -= chunk_start; + } + } + /* When REQUEST_CHUNKED_PASS, we are */ + if (r->remaining == -1) { /* reading footers until empty line */ + len_read = chunk_start; + + while ((bufsiz > 1) && ((len_read = + getline(buffer, bufsiz, r->connection->client, 1)) > 0)) { + + if (len_read != (bufsiz - 1)) { + buffer[len_read++] = CR; /* Restore footer line end */ + buffer[len_read++] = LF; + } + chunk_start += len_read; + buffer += len_read; + bufsiz -= len_read; + } + if (len_read < 0) { + r->connection->keepalive = -1; + return -1; + } + + if (len_read == 0) { /* Indicates an empty line */ + buffer[0] = CR; + buffer[1] = LF; + chunk_start += 2; + r->remaining = -2; + } + r->read_length += chunk_start; + return chunk_start; + } + /* When REQUEST_CHUNKED_PASS, we */ + if (r->remaining == -2) { /* finished footers when last called */ + r->remaining = 0; /* so now we must signal EOF */ + return 0; + } + + /* Otherwise, we are in the midst of reading a chunk of data */ + + len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining; + + len_read = bread(r->connection->client, buffer, len_to_read); + if (len_read <= 0) { + r->connection->keepalive = -1; + return -1; + } + + r->remaining -= len_read; + + if (r->remaining == 0) { /* End of chunk, get trailing CRLF */ + if ((c = bgetc(r->connection->client)) == CR) { + c = bgetc(r->connection->client); + } + if (c != LF) { + r->connection->keepalive = -1; + return -1; + } + if (r->read_body == REQUEST_CHUNKED_PASS) { + buffer[len_read++] = CR; + buffer[len_read++] = LF; + } + } + r->read_length += (chunk_start + len_read); + + return (chunk_start + len_read); +} + +long send_fd(FILE *f, request_rec *r) { return send_fd_length(f, r, -1); } + +long send_fd_length(FILE *f, request_rec *r, long length) +{ + char buf[IOBUFSIZE]; + long total_bytes_sent = 0; + register int n, w, o, len; + + if (length == 0) return 0; + + soft_timeout("send body", r); + + while (!r->connection->aborted) { + if ((length > 0) && (total_bytes_sent + IOBUFSIZE) > length) + len = length - total_bytes_sent; + else len = IOBUFSIZE; + + while ((n= fread(buf, sizeof(char), len, f)) < 1 + && ferror(f) && errno == EINTR && !r->connection->aborted) + continue; + + if (n < 1) { + break; + } + o=0; + total_bytes_sent += n; + + while (n && !r->connection->aborted) { + w = bwrite(r->connection->client, &buf[o], n); + if (w > 0) { + reset_timeout(r); /* reset timeout after successful write */ + n-=w; + o+=w; + } + else if (w < 0) { + if (r->connection->aborted) + break; + else if (errno == EAGAIN) + continue; + else { + log_unixerr("send body lost connection to", + get_remote_host(r->connection, + r->per_dir_config, REMOTE_NAME), + NULL, r->server); + bsetflag(r->connection->client, B_EOUT, 1); + r->connection->aborted = 1; + break; + } + } + } + } + + kill_timeout(r); + SET_BYTES_SENT(r); + return total_bytes_sent; +} + +int rputc (int c, request_rec *r) +{ + if (r->connection->aborted) return EOF; + bputc(c, r->connection->client); + SET_BYTES_SENT(r); + return c; +} + +int rputs(const char *str, request_rec *r) +{ + if (r->connection->aborted) return EOF; + SET_BYTES_SENT(r); + return bputs(str, r->connection->client); +} + +int rwrite(const void *buf, int nbyte, request_rec *r) +{ + int n; + if (r->connection->aborted) return EOF; + n=bwrite(r->connection->client, buf, nbyte); + SET_BYTES_SENT(r); + return n; +} + +int rprintf(request_rec *r,const char *fmt,...) +{ + va_list vlist; + int n; + + if(r->connection->aborted) return EOF; + va_start(vlist,fmt); + n=vbprintf(r->connection->client,fmt,vlist); + va_end(vlist); + SET_BYTES_SENT(r); + return n; +} + +int rvputs(request_rec *r, ...) +{ + va_list args; + int i, j, k; + const char *x; + BUFF *fb=r->connection->client; + + if (r->connection->aborted) return EOF; + + va_start (args, r); + for (k=0;;) + { + x = va_arg(args, const char *); + if (x == NULL) break; + j = strlen(x); + i = bwrite(fb, x, j); + if (i != j) + { + va_end(args); + return -1; + } + k += i; + } + va_end(args); + + SET_BYTES_SENT(r); + return k; +} + +int rflush (request_rec *r) { + return bflush(r->connection->client); +} + +/* We should have named this send_canned_response, since it is used for any + * response that can be generated by the server from the request record. + * This includes all 204 (no content), 3xx (redirect), 4xx (client error), + * and 5xx (server error) messages that have not been redirected to another + * handler via the ErrorDocument feature. + */ +void send_error_response (request_rec *r, int recursive_error) +{ + BUFF *fd = r->connection->client; + int status = r->status; + int idx = index_of_response (status); + char *custom_response; + char *location = pstrdup(r->pool, table_get(r->headers_out, "Location")); + + /* We need to special-case the handling of 204 and 304 responses, + * since they have specific HTTP requirements and do not include a + * message body. Note that being assbackwards here is not an option. + */ + if (status == HTTP_NOT_MODIFIED) { + if (!is_empty_table(r->err_headers_out)) + r->headers_out = overlay_tables(r->pool, r->err_headers_out, + r->headers_out); + hard_timeout("send 304", r); + + basic_http_header(r); + set_keepalive(r); + + table_do((int (*)(void *, const char *, const char *))send_header_field, + (void *)r, r->headers_out, + "Connection", + "Keep-Alive", + "ETag", + "Content-Location", + "Expires", + "Cache-Control", + "Vary", + "Warning", + "WWW-Authenticate", + NULL); + + terminate_header(r->connection->client); + + kill_timeout(r); + return; + } + + if (status == HTTP_NO_CONTENT) { + send_http_header(r); + finalize_request_protocol(r); + return; + } + + if (!r->assbackwards) { + table *tmp = r->headers_out; + + /* For all HTTP/1.x responses for which we generate the message, + * we need to avoid inheriting the "normal status" header fields + * that may have been set by the request handler before the + * error or redirect, except for Location on external redirects. + */ + r->headers_out = r->err_headers_out; + r->err_headers_out = tmp; + clear_table(r->err_headers_out); + + if (location && *location + && (is_HTTP_REDIRECT(status) || status == HTTP_CREATED)) + table_set(r->headers_out, "Location", location); + + r->content_language = NULL; + r->content_languages = NULL; + r->content_encoding = NULL; + r->clength = 0; + r->content_type = "text/html"; + + if ((status == METHOD_NOT_ALLOWED) || (status == NOT_IMPLEMENTED)) + table_set(r->headers_out, "Allow", make_allow(r)); + + send_http_header(r); + + if (r->header_only) { + finalize_request_protocol(r); + return; + } + } + + hard_timeout("send error body", r); + + if ((custom_response = response_code_string (r, idx))) { + /* + * We have a custom response output. This should only be + * a text-string to write back. But if the ErrorDocument + * was a local redirect and the requested resource failed + * for any reason, the custom_response will still hold the + * redirect URL. We don't really want to output this URL + * as a text message, so first check the custom response + * string to ensure that it is a text-string (using the + * same test used in die(), i.e. does it start with a + * "). If it doesn't, we've got a recursive error, so find + * the original error and output that as well. + */ + if (custom_response[0] == '\"') { + bputs(custom_response+1, fd); + kill_timeout(r); + finalize_request_protocol(r); + return; + } + /* Redirect failed, so get back the original error + */ + while (r->prev && (r->prev->status != HTTP_OK)) + r = r->prev; + } + { + char *title = status_lines[idx]; + /* folks decided they didn't want the error code in the H1 text */ + + char *h1 = 4 + status_lines[idx]; + + bvputs + ( + fd, + "<HTML><HEAD>\n<TITLE>", + title, + "\n\n

    ", + h1, + "

    \n", + NULL + ); + + switch (status) { + case REDIRECT: + case MOVED: + bvputs(fd, "The document has moved pool, location), "\">here.

    \n", NULL); + break; + case HTTP_SEE_OTHER: + bvputs(fd, "The answer to your request is located pool, location), "\">here.

    \n", NULL); + break; + case HTTP_USE_PROXY: + bvputs(fd, "This resource is only accessible through the proxy\n", + escape_html(r->pool, location), "
    \nYou will need to ", + "configure your client to use that proxy.

    \n", NULL); + break; + case AUTH_REQUIRED: + bputs("This server could not verify that you\n", fd); + bputs("are authorized to access the document you\n", fd); + bputs("requested. Either you supplied the wrong\n", fd); + bputs("credentials (e.g., bad password), or your\n", fd); + bputs("browser doesn't understand how to supply\n", fd); + bputs("the credentials required.

    \n", fd); + break; + case BAD_REQUEST: + bputs("Your browser sent a request that\n", fd); + bputs("this server could not understand.

    \n", fd); + break; + case FORBIDDEN: + bvputs(fd, "You don't have permission to access ", + escape_html(r->pool, r->uri), "\non this server.

    \n", + NULL); + break; + case NOT_FOUND: + bvputs(fd, "The requested URL ", escape_html(r->pool, r->uri), + " was not found on this server.

    \n", NULL); + break; + case METHOD_NOT_ALLOWED: + bvputs(fd, "The requested method ", r->method, " is not allowed " + "for the URL ", escape_html(r->pool, r->uri), + ".

    \n", NULL); + break; + case NOT_ACCEPTABLE: + bvputs(fd, + "An appropriate representation of the requested resource ", + escape_html(r->pool, r->uri), + " could not be found on this server.

    \n", NULL); + /* fall through */ + case MULTIPLE_CHOICES: + { + char *list; + if ((list = table_get (r->notes, "variant-list"))) + bputs(list, fd); + } + break; + case LENGTH_REQUIRED: + bvputs(fd, "A request of the requested method ", r->method, + " requires a valid Content-length.

    \n", NULL); + break; + case PRECONDITION_FAILED: + bvputs(fd, "The precondition on the request for the URL ", + escape_html(r->pool, r->uri), " evaluated to false.

    \n", + NULL); + break; + case NOT_IMPLEMENTED: + bvputs(fd, escape_html(r->pool, r->method), " to ", + escape_html(r->pool, r->uri), " not supported.

    \n", NULL); + break; + case BAD_GATEWAY: + bputs("The proxy server received an invalid\015\012", fd); + bputs("response from an upstream server.

    \015\012", fd); + break; + case VARIANT_ALSO_VARIES: + bvputs(fd, "A variant for the requested entity ", + escape_html(r->pool, r->uri), " is itself a ", + "transparently negotiable resource.

    \n", NULL); + break; + case HTTP_REQUEST_TIME_OUT: + bputs("I'm tired of waiting for your request.\n", fd); + break; + case HTTP_GONE: + bvputs(fd, "The requested resource
    ", + escape_html(r->pool, r->uri), + "
    \nis no longer available on this server ", + "and there is no forwarding address.\n", + "Please remove all references to this resource.\n", NULL); + break; + case HTTP_REQUEST_ENTITY_TOO_LARGE: + bvputs(fd, "The requested resource
    ", + escape_html(r->pool, r->uri), "
    \n", + "does not allow request data with ", r->method, + " requests, or the amount of data provided in\n", + "the request exceeds the capacity limit.\n", NULL); + break; + case HTTP_REQUEST_URI_TOO_LARGE: + bputs("The requested URL's length exceeds the capacity\n", fd); + bputs("limit for this server.\n", fd); + break; + case HTTP_UNSUPPORTED_MEDIA_TYPE: + bputs("The supplied request data is not in a format\n", fd); + bputs("acceptable for processing by this resource.\n", fd); + break; + case HTTP_SERVICE_UNAVAILABLE: + bputs("The server is temporarily unable to service your\n", fd); + bputs("request due to maintenance downtime or capacity\n", fd); + bputs("problems. Please try again later.\n", fd); + break; + case HTTP_GATEWAY_TIME_OUT: + bputs("The proxy server did not receive a timely response\n", fd); + bputs("from the upstream server.

    \n", fd); + break; + default: /* HTTP_INTERNAL_SERVER_ERROR */ + bputs("The server encountered an internal error or\n", fd); + bputs("misconfiguration and was unable to complete\n", fd); + bputs("your request.

    \n", fd); + bputs("Please contact the server administrator,\n ", fd); + bputs(escape_html(r->pool, r->server->server_admin), fd); + bputs(" and inform them of the time the error occurred,\n", fd); + bputs("and anything you might have done that may have\n", fd); + bputs("caused the error.

    \n", fd); + break; + } + + if (recursive_error) { + bvputs(fd, "

    Additionally, a ", + status_lines[index_of_response(recursive_error)], + "\nerror was encountered while trying to use an " + "ErrorDocument to handle the request.\n", NULL); + } + bputs("\n", fd); + } + kill_timeout(r); + finalize_request_protocol(r); +} + +/* Finally, this... it's here to support nph- scripts + * Now what ever are we going to do about them when HTTP-NG packetization + * comes along? + */ + +void client_to_stdout (conn_rec *c) +{ + bflush(c->client); + dup2(c->client->fd, STDOUT_FILENO); +} diff --git a/APACHE_1_2_X/src/main/http_request.c b/APACHE_1_2_X/src/main/http_request.c new file mode 100644 index 00000000000..72574be4739 --- /dev/null +++ b/APACHE_1_2_X/src/main/http_request.c @@ -0,0 +1,1084 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * http_request.c: functions to get and process requests + * + * Rob McCool 3/21/93 + * + * Thoroughly revamped by rst for Apache. NB this file reads + * best from the bottom up. + * + */ + +#define CORE_PRIVATE +#include "httpd.h" +#include "http_config.h" +#include "http_request.h" +#include "http_core.h" +#include "http_protocol.h" +#include "http_log.h" +#include "http_main.h" +#include "scoreboard.h" + +/***************************************************************** + * + * Getting and checking directory configuration. Also checks the + * FollowSymlinks and FollowSymOwner stuff, since this is really the + * only place that can happen (barring a new mid_dir_walk callout). + * + * We can't do it as an access_checker module function which gets + * called with the final per_dir_config, since we could have a directory + * with FollowSymLinks disabled, which contains a symlink to another + * with a .htaccess file which turns FollowSymLinks back on --- and + * access in such a case must be denied. So, whatever it is that + * checks FollowSymLinks needs to know the state of the options as + * they change, all the way down. + */ + +int check_symlinks (char *d, int opts) +{ + struct stat lfi, fi; + char *lastp; + int res; + +#ifdef __EMX__ + /* OS/2 dosen't have symlinks */ + return OK; +#else + + if (opts & OPT_SYM_LINKS) return OK; + + /* Strip trailing '/', if any, off what we're checking; trailing + * slashes make some systems follow symlinks to directories even in + * lstat(). After we've done the lstat, put it back. Also, don't + * bother checking '/' at all... + * + * Note that we don't have to worry about multiple slashes here + * because of no2slash() below... + */ + + lastp = d + strlen(d) - 1; + if (lastp == d) return OK; /* Root directory, '/' */ + + if (*lastp == '/') *lastp = '\0'; + else lastp = NULL; + + res = lstat (d, &lfi); + + if (lastp) *lastp = '/'; + + /* Note that we don't reject accesses to nonexistent files (multiviews + * or the like may cons up a way to run the transaction anyway)... + */ + + if (!(res >= 0) || !S_ISLNK(lfi.st_mode)) return OK; + + /* OK, it's a symlink. May still be OK with OPT_SYM_OWNER */ + + if (!(opts & OPT_SYM_OWNER)) return HTTP_FORBIDDEN; + + if (stat (d, &fi) < 0) return HTTP_FORBIDDEN; + + return (fi.st_uid == lfi.st_uid) ? OK : HTTP_FORBIDDEN; + +#endif +} + +/* Dealing with the file system to get PATH_INFO + */ + +int get_path_info(request_rec *r) +{ + char *cp; + char *path = r->filename; + char *end = &path[strlen(path)]; + char *last_cp = NULL; + int rv; + + /* Advance over trailing slashes ... NOT part of filename */ + + for (cp = end; cp > path && cp[-1] == '/'; --cp) + continue; + + while (cp > path) { + + /* See if the pathname ending here exists... */ + + *cp = '\0'; + + errno = 0; + rv = stat(path, &r->finfo); + + if (cp != end) *cp = '/'; + + if (!rv) { + + /* Aha! Found something. If it was a directory, we will + * search contents of that directory for a multi_match, so + * the PATH_INFO argument starts with the component after that. + */ + + if (S_ISDIR(r->finfo.st_mode) && last_cp) { + r->finfo.st_mode = 0; /* No such file... */ + cp = last_cp; + } + + r->path_info = pstrdup (r->pool, cp); + *cp = '\0'; + return OK; + } +#if defined(ENOENT) && defined(ENOTDIR) + else if (errno == ENOENT || errno == ENOTDIR) { +#else +#error ENOENT || ENOTDIR not defined -- check the comment below this line in the source for details + /* + * If ENOENT || ENOTDIR is not defined in one of the your OS's + * include files, Apache does not know how to check to see why + * the stat() of the index file failed; there are cases where + * it can fail even though the file exists. This means + * that it is possible for someone to get a directory + * listing of a directory even though there is an index + * (eg. index.html) file in it. If you do not have a + * problem with this, delete the above #error line and + * start the compile again. If you need to do this, please + * submit a bug report from http://www.apache.org/bug_report.html + * letting us know that you needed to do this. Please be + * sure to include the operating system you are using. + */ + + else { +#endif + last_cp = cp; + + while (--cp > path && *cp != '/') + continue; + + while (cp > path && cp[-1] == '/') + --cp; + } +#if defined(ENOENT) && defined(ENOTDIR) + else { +#if defined(EACCES) + if (errno != EACCES) +#endif + log_printf(r->server, + "access to %s failed for %s, reason: stat: %s (errno = %d)", + r->uri, get_remote_host(r->connection, r->per_dir_config, + REMOTE_NAME), strerror(errno), errno); + + return HTTP_FORBIDDEN; + } +#endif /* ENOENT && ENOTDIR */ + } + return OK; +} + +int directory_walk (request_rec *r) +{ + core_server_config *sconf = get_module_config (r->server->module_config, + &core_module); + array_header *sec_array = copy_array (r->pool, sconf->sec); + void *per_dir_defaults = r->server->lookup_defaults; + + core_dir_config **sec = (core_dir_config **)sec_array->elts; + int num_sec = sec_array->nelts; + char *test_filename = pstrdup (r->pool, r->filename); + + int num_dirs, res; + int i; + + /* Are we dealing with a file? If not, we can (hopefuly) safely assume + * we have a handler that doesn't require one, but for safety's sake, + * and so we have something find_types() can get something out of, + * fake one. But don't run through the directory entries. + */ + + if (test_filename == NULL) { + r->filename = pstrdup(r->pool, r->uri); + r->finfo.st_mode = 0; /* Not really a file... */ + r->per_dir_config = per_dir_defaults; + + return OK; + } + + /* Go down the directory hierarchy. Where we have to check for symlinks, + * do so. Where a .htaccess file has permission to override anything, + * try to find one. If either of these things fails, we could poke + * around, see why, and adjust the lookup_rec accordingly --- this might + * save us a call to get_path_info (with the attendant stat()s); however, + * for the moment, that's not worth the trouble. + */ + +#ifdef __EMX__ + /* Add OS/2 drive name support */ + if ((test_filename[0] != '/') && (test_filename[1] != ':')) +#else + if (test_filename[0] != '/') +#endif + { +/* fake filenames only match Directory sections */ + void *this_conf, *entry_config; + core_dir_config *entry_core; + char *entry_dir; + int j; + + for (j = 0; j < num_sec; ++j) { + + entry_config = sec[j]; + if (!entry_config) continue; + + entry_core =(core_dir_config *) + get_module_config(entry_config, &core_module); + entry_dir = entry_core->d; + + this_conf = NULL; + if (entry_core->r) { + if (!regexec(entry_core->r, test_filename, 0, NULL, 0)) + this_conf = entry_config; + } + else if (entry_core->d_is_matchexp) { + if (!strcmp_match(test_filename, entry_dir)) + this_conf = entry_config; + } + else if (!strncmp (test_filename, entry_dir, strlen(entry_dir))) + this_conf = entry_config; + + if (this_conf) + per_dir_defaults = merge_per_dir_configs (r->pool, + per_dir_defaults, this_conf); + } + + r->per_dir_config = per_dir_defaults; + + return OK; + } + + no2slash (test_filename); + num_dirs = count_dirs(test_filename); + + res = get_path_info (r); + if (res != OK) { + return res; + } + + if (test_filename[strlen(test_filename)-1] == '/') + --num_dirs; + + if (S_ISDIR (r->finfo.st_mode)) ++num_dirs; + + for (i = 1; i <= num_dirs; ++i) { + core_dir_config *core_dir = + (core_dir_config *)get_module_config(per_dir_defaults, &core_module); + int overrides_here; + void *this_conf = NULL, *htaccess_conf = NULL; + char *this_dir = make_dirstr (r->pool, test_filename, i); + int j; + + /* Do symlink checks first, because they are done with the + * permissions appropriate to the *parent* directory... + */ + + if ((res = check_symlinks (this_dir, core_dir->opts))) + { + log_reason("Symbolic link not allowed", this_dir, r); + return res; + } + + /* Begin *this* level by looking for matching sections from + * access.conf. + */ + + for (j = 0; j < num_sec; ++j) { + void *entry_config = sec[j]; + core_dir_config *entry_core; + char *entry_dir; + + if (!entry_config) continue; + + entry_core = + (core_dir_config *)get_module_config(entry_config, &core_module); + entry_dir = entry_core->d; + + if (entry_core->r) { + if (!regexec(entry_core->r, this_dir, 0, NULL, + (j == num_sec) ? 0 : REG_NOTEOL)) { + /* Don't try this wildcard again --- if it ends in '*' + * it'll match again, and subdirectories won't be able to + * override it... + */ + sec[j] = NULL; + this_conf = entry_config; + } + } + else if (entry_core->d_is_matchexp && + !strcmp_match(this_dir, entry_dir)) { + sec[j] = NULL; + this_conf = entry_config; + } + else if (!strcmp (this_dir, entry_dir)) + this_conf = entry_config; + + if (this_conf) { + per_dir_defaults = + merge_per_dir_configs (r->pool, per_dir_defaults, this_conf); + core_dir =(core_dir_config *)get_module_config(per_dir_defaults, + &core_module); + } + + } + + overrides_here = core_dir->override; + + /* If .htaccess files are enabled, check for one. + */ + + if (overrides_here) { + char *config_name = make_full_path(r->pool, this_dir, + sconf->access_name); + res = parse_htaccess (&htaccess_conf, r, overrides_here, + this_dir, config_name); + if (res) return res; + } + + if (htaccess_conf) + per_dir_defaults = + merge_per_dir_configs (r->pool, per_dir_defaults, + htaccess_conf); + + } + + r->per_dir_config = per_dir_defaults; + + if ((res = check_symlinks (r->filename, allow_options(r)))) + { + log_reason("Symbolic link not allowed", r->filename, r); + return res; + } + + return OK; /* Can only "fail" if access denied + * by the symlink goop. + */ +} + +int location_walk (request_rec *r) +{ + core_server_config *sconf = get_module_config (r->server->module_config, + &core_module); + array_header *url_array = copy_array (r->pool, sconf->sec_url); + void *per_dir_defaults = r->per_dir_config; + + core_dir_config **url = (core_dir_config **)url_array->elts; + int len, num_url = url_array->nelts; + char *test_location = pstrdup (r->pool, r->uri); + + /* Collapse multiple slashes, if it's a path URL (we don't want to + * do anything to or such). + */ + if (test_location[0] == '/') + no2slash (test_location); + + /* Go through the location entries, and check for matches. */ + + if (num_url) { + void *this_conf, *entry_config; + core_dir_config *entry_core; + char *entry_url; + int j; + +/* + * we apply the directive sections in some order; should really try them + * with the most general first. + */ + for (j = 0; j < num_url; ++j) { + + entry_config = url[j]; + if (!entry_config) continue; + + entry_core =(core_dir_config *) + get_module_config(entry_config, &core_module); + entry_url = entry_core->d; + + len = strlen(entry_url); + + this_conf = NULL; + + if (entry_core->r) { + if (!regexec(entry_core->r, test_location, 0, NULL, 0)) + this_conf = entry_config; + } + else if( entry_core->d_is_matchexp ) { + if (!strcmp_match(test_location, entry_url)) + this_conf = entry_config; + } + else if (!strncmp (test_location, entry_url, len) && + (entry_url[len - 1] == '/' || + test_location[len] == '/' || test_location[len] == '\0')) + this_conf = entry_config; + + if (this_conf) + per_dir_defaults = merge_per_dir_configs (r->pool, + per_dir_defaults, this_conf); + } + + r->per_dir_config = per_dir_defaults; + } + + return OK; +} + +int file_walk (request_rec *r) +{ + core_dir_config *conf = get_module_config(r->per_dir_config, &core_module); + array_header *file_array = copy_array (r->pool, conf->sec); + void *per_dir_defaults = r->per_dir_config; + + core_dir_config **file = (core_dir_config **)file_array->elts; + int len, num_files = file_array->nelts; + char *test_file = pstrdup (r->pool, r->filename); + + /* Collapse multiple slashes */ + no2slash (test_file); + + /* Go through the file entries, and check for matches. */ + + if (num_files) { + void *this_conf, *entry_config; + core_dir_config *entry_core; + char *entry_file; + int j; + +/* + * we apply the directive sections in some order; should really try them + * with the most general first. + */ + for (j = 0; j < num_files; ++j) { + + entry_config = file[j]; + if (!entry_config) continue; + + entry_core =(core_dir_config *) + get_module_config(entry_config, &core_module); + entry_file = entry_core->d; + + len = strlen(entry_file); + + this_conf = NULL; + + if (entry_core->r) { + if (!regexec(entry_core->r, test_file, 0, NULL, 0)) + this_conf = entry_config; + } + else if ( entry_core->d_is_matchexp ) { + if (!strcmp_match(test_file, entry_file)) + this_conf = entry_config; + } + else if (!strncmp (test_file, entry_file, len) && + (entry_file[len - 1] == '/' || + test_file[len] == '/' || test_file[len] == '\0')) + this_conf = entry_config; + + if (this_conf) + per_dir_defaults = merge_per_dir_configs (r->pool, + per_dir_defaults, this_conf); + } + + r->per_dir_config = per_dir_defaults; + } + + return OK; +} + +/***************************************************************** + * + * The sub_request mechanism. + * + * Fns to look up a relative URI from, e.g., a map file or SSI document. + * These do all access checks, etc., but don't actually run the transaction + * ... use run_sub_req below for that. Also, be sure to use destroy_sub_req + * as appropriate if you're likely to be creating more than a few of these. + * (An early Apache version didn't destroy the sub_reqs used in directory + * indexing. The result, when indexing a directory with 800-odd files in + * it, was massively excessive storage allocation). + * + * Note more manipulation of protocol-specific vars in the request + * structure... + */ + +request_rec *make_sub_request (const request_rec *r) +{ + pool *rrp = make_sub_pool (r->pool); + request_rec *rr = pcalloc (rrp, sizeof (request_rec)); + + rr->pool = rrp; + return rr; +} + + +request_rec *sub_req_lookup_uri (const char *new_file, const request_rec *r) +{ + request_rec *rnew; + int res; + char *udir; + + rnew = make_sub_request (r); + rnew->request_time = r->request_time; + rnew->connection = r->connection; + rnew->server = r->server; + rnew->request_config = create_request_config (rnew->pool); + rnew->htaccess = r->htaccess; /* copy htaccess cache */ + rnew->per_dir_config=r->server->lookup_defaults; + set_sub_req_protocol (rnew, r); + + if (new_file[0] == '/') + parse_uri(rnew, new_file); + else + { + udir = make_dirstr (rnew->pool, r->uri, count_dirs (r->uri)); + udir = escape_uri(rnew->pool, udir); /* re-escape it */ + parse_uri (rnew, make_full_path (rnew->pool, udir, new_file)); + } + + res = unescape_url (rnew->uri); + if (res) + { + rnew->status = res; + return rnew; + } + + getparents (rnew->uri); + + if ((res = location_walk (rnew))) { + rnew->status=res; + return rnew; + } + + res = translate_name(rnew); + if (res) + { + rnew->status = res; + return rnew; + } + + /* We could be clever at this point, and avoid calling directory_walk, etc. + * However, we'd need to test that the old and new filenames contain the + * same directory components, so it would require duplicating the start + * of translate_name. + * Instead we rely on the cache of .htaccess results. + */ + /* NB: directory_walk() clears the per_dir_config, so we don't inherit from + location_walk() above */ + + if ((res = directory_walk (rnew)) + || (res = file_walk (rnew)) + || (res = location_walk (rnew)) + || ((satisfies(rnew)==SATISFY_ALL || satisfies(rnew)==SATISFY_NOSPEC)? + ((res = check_access (rnew)) + || (some_auth_required (rnew) && + ((res = check_user_id (rnew)) || (res = check_auth (rnew))))): + ((res = check_access (rnew)) + && (!some_auth_required (rnew) || + ((res = check_user_id (rnew)) || (res = check_auth (rnew))))) + ) + || (res = find_types (rnew)) + || (res = run_fixups (rnew)) + ) + { + rnew->status = res; + } + + return rnew; +} + +request_rec *sub_req_lookup_file (const char *new_file, const request_rec *r) +{ + request_rec *rnew; + int res; + char *fdir; + + rnew = make_sub_request (r); + rnew->request_time = r->request_time; + rnew->connection = r->connection; /* For now... */ + rnew->server = r->server; + rnew->request_config = create_request_config (rnew->pool); + rnew->htaccess = r->htaccess; /* copy htaccess cache */ + set_sub_req_protocol (rnew, r); + fdir = make_dirstr (rnew->pool, r->filename, count_dirs (r->filename)); + + /* Check for a special case... if there are no '/' characters in new_file + * at all, then we are looking at a relative lookup in the same directory. + * That means we won't have to redo directory_walk, and we may not + * even have to redo access checks. + */ + + if (strchr (new_file, '/') == NULL) { + char *udir = make_dirstr(rnew->pool, r->uri, count_dirs(r->uri)); + + rnew->uri = make_full_path (rnew->pool, udir, new_file); + rnew->filename = make_full_path (rnew->pool, fdir, new_file); + if (stat (rnew->filename, &rnew->finfo) < 0) { + rnew->finfo.st_mode = 0; + } + + rnew->per_dir_config = r->per_dir_config; + + if ((res = check_symlinks (rnew->filename, allow_options (rnew)))) { + log_reason ("Symbolic link not allowed", rnew->filename, rnew); + rnew->status = res; + return rnew; + } + /* do a file_walk, if it doesn't change the per_dir_config then + * we know that we don't have to redo all the access checks */ + if ((res = file_walk (rnew))) { + rnew->status = res; + return rnew; + } + if (rnew->per_dir_config == r->per_dir_config) { + if ((res = find_types (rnew)) || (res = run_fixups (rnew))) { + rnew->status = res; + } + return rnew; + } + } else { + /* XXX: this should be set properly like it is in the same-dir case + * but it's actually sometimes to impossible to do it... because the + * file may not have a uri associated with it -djg */ + rnew->uri = "INTERNALLY GENERATED file-relative req"; + rnew->filename = ((new_file[0] == '/') ? + pstrdup(rnew->pool,new_file) : + make_full_path (rnew->pool, fdir, new_file)); + rnew->per_dir_config = r->server->lookup_defaults; + res = directory_walk (rnew); + if (!res) { + res = file_walk (rnew); + } + } + + if (res + || ((satisfies(rnew)==SATISFY_ALL || satisfies(rnew)==SATISFY_NOSPEC)? + ((res = check_access (rnew)) + || (some_auth_required (rnew) && + ((res = check_user_id (rnew)) || (res = check_auth (rnew))))): + ((res = check_access (rnew)) + && (!some_auth_required (rnew) || + ((res = check_user_id (rnew)) || (res = check_auth (rnew))))) + ) + || (res = find_types (rnew)) + || (res = run_fixups (rnew)) + ) + { + rnew->status = res; + } + + return rnew; +} + +int run_sub_req (request_rec *r) +{ + int retval = invoke_handler (r); + finalize_sub_req_protocol (r); + return retval; +} + +void destroy_sub_req (request_rec *r) +{ + /* Reclaim the space */ + destroy_pool (r->pool); +} + +/***************************************************************** + * + * Mainline request processing... + */ + +void die(int type, request_rec *r) +{ + int error_index = index_of_response (type); + char *custom_response = response_code_string(r, error_index); + int recursive_error = 0; + + /* The following takes care of Apache redirects to custom response URLs + * Note that if we are already dealing with the response to some other + * error condition, we just report on the original error, and give up on + * any attempt to handle the other thing "intelligently"... + */ + + if (r->status != HTTP_OK) { + recursive_error = type; + + while (r->prev && (r->prev->status != HTTP_OK)) + r = r->prev; /* Get back to original error */ + + type = r->status; + custom_response = NULL; /* Do NOT retry the custom thing! */ + } + + r->status = type; + + /* Two types of custom redirects --- plain text, and URLs. + * Plain text has a leading '"', so the URL code, here, is triggered + * on its absence + */ + + if (custom_response && custom_response[0] != '"') { + + if (is_url(custom_response)) { + /* The URL isn't local, so lets drop through the rest of + * this apache code, and continue with the usual REDIRECT + * handler. But note that the client will ultimately see + * the wrong status... + */ + r->status = REDIRECT; + table_set (r->headers_out, "Location", custom_response); + } else if ( custom_response[0] == '/') { + r->no_local_copy = 1; /* Do NOT send USE_LOCAL_COPY for + * error documents! + */ + /* This redirect needs to be a GET no matter what the original + * method was. + */ + table_set(r->subprocess_env, "REQUEST_METHOD", r->method); + r->method = pstrdup(r->pool, "GET"); + r->method_number = M_GET; + internal_redirect (custom_response, r); + return; + } else { + /* Dumb user has given us a bad url to redirect to + * --- fake up dying with a recursive server error... + */ + recursive_error = SERVER_ERROR; + log_reason("Invalid error redirection directive", custom_response, + r); + } + } + + send_error_response (r, recursive_error); +} + +static void decl_die (int status, char *phase, request_rec *r) +{ + if (status == DECLINED) { + log_reason (pstrcat (r->pool, + "configuration error: couldn't ", + phase, NULL), + r->uri, + r); + die (SERVER_ERROR, r); + } + else die (status, r); +} + +int some_auth_required (request_rec *r) +{ + /* Is there a require line configured for the type of *this* req? */ + + array_header *reqs_arr = requires (r); + require_line *reqs; + int i; + + if (!reqs_arr) return 0; + + reqs = (require_line *)reqs_arr->elts; + + for (i = 0; i < reqs_arr->nelts; ++i) + if (reqs[i].method_mask & (1 << r->method_number)) + return 1; + + return 0; +} + +void process_request_internal (request_rec *r) +{ + int access_status; + + /* Kludge to be reading the assbackwards field outside of protocol.c, + * but we've got to check for this sort of nonsense somewhere... + */ + + if (r->assbackwards && r->header_only) { + /* Client asked for headers only with HTTP/0.9, which doesn't + * send headers! Have to dink things even to make sure the + * error message comes through... + */ + log_reason ("client sent illegal HTTP/0.9 request", r->uri, r); + r->header_only = 0; + die (BAD_REQUEST, r); + return; + } + + if ((!r->hostname && (r->proto_num >= 1001)) || + ((r->proto_num == 1001) && !table_get(r->headers_in, "Host"))) { + /* Client sent us a HTTP/1.1 or later request without telling + * us the hostname, either with a full URL or a Host: header. + * We therefore need to (as per the 1.1 spec) send an error + */ + log_reason ("client sent HTTP/1.1 request without hostname", + r->uri, r); + die (BAD_REQUEST, r); + return; + } + + if (!r->proxyreq) + { + /* We don't want TRACE to run through the normal handler set, + * we handle it specially. + */ + if (r->method_number == M_TRACE) { + send_http_trace(r); + finalize_request_protocol(r); + return; + } + + access_status = unescape_url(r->uri); + if (access_status) + { + die(access_status, r); + return; + } + + getparents(r->uri); /* OK --- shrinking transformations... */ + } + + if ((access_status = location_walk (r))) { + die (access_status, r); + return; + } + + if ((access_status = translate_name (r))) { + decl_die (access_status, "translate", r); + return; + } + + /* NB: directory_walk() clears the per_dir_config, so we don't inherit from + location_walk() above */ + + if ((access_status = directory_walk (r))) { + die (access_status, r); + return; + } + + if ((access_status = file_walk (r))) { + die (access_status, r); + return; + } + + if ((access_status = location_walk (r))) { + die (access_status, r); + return; + } + + if ((access_status = header_parse (r))) { + die (access_status, r); + return; + } + + switch (satisfies(r)) { + case SATISFY_ALL: case SATISFY_NOSPEC: + if ((access_status = check_access (r)) != 0) { + decl_die (access_status, "check access", r); + return; + } + if (some_auth_required (r)) { + if ((access_status = check_user_id (r)) != 0) { + decl_die (access_status, "check user. No user file?", r); + return; + } + if ((access_status = check_auth (r)) != 0) { + decl_die (access_status, "check access. No groups file?", r); + return; + } + } + break; + case SATISFY_ANY: + if ((access_status = check_access (r)) != 0) { + if (!some_auth_required (r)) { + decl_die (access_status, "check access", r); + return; + } + if ((access_status = check_user_id (r)) != 0) { + decl_die (access_status, "check user. No user file?", r); + return; + } + if ((access_status = check_auth (r)) != 0) { + decl_die (access_status, "check access. No groups file?", r); + return; + } + } + break; + } + + if ((access_status = find_types (r)) != 0) { + decl_die (access_status, "find types", r); + return; + } + + if ((access_status = run_fixups (r)) != 0) { + die (access_status, r); + return; + } + + if ((access_status = invoke_handler (r)) != 0) { + die (access_status, r); + return; + } + + /* Take care of little things that need to happen when we're done */ + finalize_request_protocol (r); +} + +void process_request (request_rec *r) +{ +#ifdef STATUS + int old_stat; +#endif /* STATUS */ + process_request_internal (r); +#ifdef STATUS + old_stat = update_child_status (r->connection->child_num, SERVER_BUSY_LOG, + r); +#endif /* STATUS */ + log_transaction (r); +#ifdef STATUS + (void)update_child_status (r->connection->child_num, old_stat, r); +#endif /* STATUS */ +} + +table *rename_original_env (pool *p, table *t) +{ + array_header *env_arr = table_elts (t); + table_entry *elts = (table_entry *)env_arr->elts; + table *new = make_table (p, env_arr->nelts); + int i; + + for (i = 0; i < env_arr->nelts; ++i) { + if (!elts[i].key) continue; + table_set (new, pstrcat (p, "REDIRECT_", elts[i].key, NULL), + elts[i].val); + } + + return new; +} + +request_rec *internal_internal_redirect (const char *new_uri, request_rec *r) +{ + request_rec *new = (request_rec *)pcalloc(r->pool, sizeof(request_rec)); + char t[256]; /* Long enough... */ + + new->connection = r->connection; + new->server = r->server; + new->pool = r->pool; + + /* A whole lot of this really ought to be shared with protocol.c... + * another missing cleanup. It's particularly inappropriate to be + * setting header_only, etc., here. + */ + + parse_uri (new, new_uri); + new->request_config = create_request_config (r->pool); + new->per_dir_config = r->server->lookup_defaults; + + new->prev = r; + r->next = new; + + /* Inherit the rest of the protocol info... */ + + new->the_request = r->the_request; + + new->method = r->method; + new->method_number = r->method_number; + new->allowed = r->allowed; + + new->status = r->status; + new->assbackwards = r->assbackwards; + new->header_only = r->header_only; + new->protocol = r->protocol; + new->proto_num = r->proto_num; + new->hostname = r->hostname; + new->hostlen = r->hostlen; + new->request_time = r->request_time; + new->main = r->main; + + new->headers_in = r->headers_in; + new->headers_out = make_table (r->pool, 5); + new->err_headers_out = r->err_headers_out; + new->subprocess_env = rename_original_env (r->pool, r->subprocess_env); + new->notes = make_table (r->pool, 5); + new->htaccess = r->htaccess; /* copy .htaccess cache */ + + new->no_cache = r->no_cache; /* If we've already made up our minds + * about this, don't change 'em back! + */ + new->no_local_copy = r->no_local_copy; + + ap_snprintf (t, sizeof(t), "%d", r->status); + table_set (new->subprocess_env, "REDIRECT_STATUS", pstrdup (r->pool, t)); + + return new; +} + +void internal_redirect (const char *new_uri, request_rec *r) +{ + request_rec *new = internal_internal_redirect(new_uri, r); + process_request_internal (new); +} + +/* This function is designed for things like actions or CGI scripts, when + * using AddHandler, and you want to preserve the content type across + * an internal redirect. + */ + +void internal_redirect_handler (const char *new_uri, request_rec *r) +{ + request_rec *new = internal_internal_redirect(new_uri, r); + if (r->handler) + new->content_type = r->content_type; + process_request_internal (new); +} diff --git a/APACHE_1_2_X/src/main/md5c.c b/APACHE_1_2_X/src/main/md5c.c new file mode 100644 index 00000000000..fd42bcb456e --- /dev/null +++ b/APACHE_1_2_X/src/main/md5c.c @@ -0,0 +1,354 @@ +/* + * This is work is derived from material Copyright RSA Data Security, Inc. + * + * The RSA copyright statement and Licence for that original material is + * included below. This is followed by the Apache copyright statement and + * licence for the modifications made to that material. + */ + +/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +/* ==================================================================== + * Copyright (c) 1996,1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +#include + +#include "md5.h" + +/* Constants for MD5Transform routine. + */ + +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static void MD5Transform(UINT4 state[4], const unsigned char block[64]); +static void Encode(unsigned char *output, const UINT4 *input, + unsigned int len); +static void Decode(UINT4 *output, const unsigned char *input, + unsigned int len); + +static unsigned char PADDING[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/* MD5 initialization. Begins an MD5 operation, writing a new context. + */ +void +MD5Init(MD5_CTX *context) +{ + context->count[0] = context->count[1] = 0; + /* Load magic initialization constants. */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. + */ +void +MD5Update(MD5_CTX *context, const unsigned char *input, unsigned int inputLen) +{ + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((UINT4)inputLen << 3)) < ((UINT4)inputLen << 3)) + context->count[1]++; + context->count[1] += (UINT4)inputLen >> 29; + + partLen = 64 - index; + + /* Transform as many times as possible. */ + if (inputLen >= partLen) + { + memcpy(&context->buffer[index], input, partLen); + MD5Transform(context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform(context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + memcpy(&context->buffer[index], &input[i], inputLen-i); +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. + */ +void +MD5Final(unsigned char digest[16], MD5_CTX *context) +{ + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* Pad out to 56 mod 64. */ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update(context, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update(context, bits, 8); + + /* Store state in digest */ + Encode(digest, context->state, 16); + + /* Zeroize sensitive information. */ + memset(context, 0, sizeof (*context)); +} + +/* MD5 basic transformation. Transforms state based on block. */ +static void +MD5Transform(UINT4 state[4], const unsigned char block[64]) +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. */ + memset(x, 0, sizeof (x)); +} + +/* Encodes input (UINT4) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void +Encode(unsigned char *output, const UINT4 *input, unsigned int len) +{ + unsigned int i, j; + UINT4 k; + + for (i = 0, j = 0; j < len; i++, j += 4) + { + k = input[i]; + output[j] = (unsigned char)(k & 0xff); + output[j+1] = (unsigned char)((k >> 8) & 0xff); + output[j+2] = (unsigned char)((k >> 16) & 0xff); + output[j+3] = (unsigned char)((k >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (UINT4). Assumes len is + a multiple of 4. + */ +static void +Decode(UINT4 *output, const unsigned char *input, unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | + (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); +} diff --git a/APACHE_1_2_X/src/main/rfc1413.c b/APACHE_1_2_X/src/main/rfc1413.c new file mode 100644 index 00000000000..858a1b0b241 --- /dev/null +++ b/APACHE_1_2_X/src/main/rfc1413.c @@ -0,0 +1,226 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * rfc1413() speaks a common subset of the RFC 1413, AUTH, TAP and IDENT + * protocols. The code queries an RFC 1413 etc. compatible daemon on a remote + * host to look up the owner of a connection. The information should not be + * used for authentication purposes. This routine intercepts alarm signals. + * + * Diagnostics are reported through syslog(3). + * + * Author: Wietse Venema, Eindhoven University of Technology, + * The Netherlands. + */ + +/* Some small additions for Apache --- ditch the "sccsid" var if + * compiling with gcc (it *has* changed), include conf.h for the + * prototypes it defines on at least one system (SunlOSs) which has + * them missing from the standard header files, and one minor change + * below (extra parens around assign "if (foo = bar) ..." to shut up + * gcc -Wall). + */ + +/* Rewritten by David Robinson */ + +#include "httpd.h" /* for server_rec, conn_rec, ap_longjmp, etc. */ +#include "http_log.h" /* for log_unixerr */ +#include "rfc1413.h" + +#ifndef SCO +extern char *strchr(); +extern char *inet_ntoa(); +#endif + +/* Local stuff. */ +/* Semi-well-known port */ +#define RFC1413_PORT 113 +/* maximum allowed length of userid */ +#define RFC1413_USERLEN 512 +/* rough limit on the amount of data we accept. */ +#define RFC1413_MAXDATA 1000 + +#ifndef RFC1413_TIMEOUT +#define RFC1413_TIMEOUT 30 +#endif +#define ANY_PORT 0 /* Any old port will do */ +#define FROM_UNKNOWN "unknown" + +int rfc1413_timeout = RFC1413_TIMEOUT; /* Global so it can be changed */ + +JMP_BUF timebuf; + +/* bind_connect - bind both ends of a socket */ + +static int +get_rfc1413(int sock, const struct sockaddr_in *our_sin, + const struct sockaddr_in *rmt_sin, char user[256], server_rec *srv) +{ + struct sockaddr_in rmt_query_sin, our_query_sin; + unsigned int rmt_port, our_port; + int i; + char *cp; + char buffer[RFC1413_MAXDATA+1]; + + /* + * Bind the local and remote ends of the query socket to the same + * IP addresses as the connection under investigation. We go + * through all this trouble because the local or remote system + * might have more than one network address. The RFC1413 etc. + * client sends only port numbers; the server takes the IP + * addresses from the query socket. + */ + + our_query_sin = *our_sin; + our_query_sin.sin_port = htons(ANY_PORT); + rmt_query_sin = *rmt_sin; + rmt_query_sin.sin_port = htons(RFC1413_PORT); + + if (bind(sock, (struct sockaddr *)&our_query_sin, + sizeof(struct sockaddr_in)) < 0) + { + log_unixerr("bind", NULL, "rfc1413: Error binding to local port", srv); + return -1; + } + +/* + * errors from connect usually imply the remote machine doesn't support + * the service + */ + if (connect(sock, (struct sockaddr *)&rmt_query_sin, + sizeof(struct sockaddr_in)) < 0) + return -1; + +/* send the data */ + ap_snprintf(buffer, sizeof(buffer), "%u,%u\r\n", ntohs(rmt_sin->sin_port), + ntohs(our_sin->sin_port)); + do i = write(sock, buffer, strlen(buffer)); + while (i == -1 && errno == EINTR); + if (i == -1) + { + log_unixerr("write", NULL, "rfc1413: error sending request", srv); + return -1; + } + + /* + * Read response from server. We assume that all the data + * comes in a single packet. + */ + + do i = read(sock, buffer, RFC1413_MAXDATA); + while (i == -1 && errno == EINTR); + if (i == -1) + { + log_unixerr("read", NULL, "rfc1413: error reading response", srv); + return -1; + } + + buffer[i] = '\0'; +/* RFC1413_USERLEN = 512 */ + if (sscanf(buffer, "%u , %u : USERID :%*[^:]:%512s", &rmt_port, &our_port, + user) != 3 || ntohs(rmt_sin->sin_port) != rmt_port + || ntohs(our_sin->sin_port) != our_port) return -1; + + /* + * Strip trailing carriage return. It is part of the + * protocol, not part of the data. + */ + + if ((cp = strchr(user, '\r'))) *cp = '\0'; + + return 0; +} + +/* ident_timeout - handle timeouts */ +static void +ident_timeout(int sig) +{ + ap_longjmp(timebuf, sig); +} + +/* rfc1413 - return remote user name, given socket structures */ +char * +rfc1413(conn_rec *conn, server_rec *srv) +{ + static char user[RFC1413_USERLEN+1]; /* XXX */ + static char *result; + static int sock; + + result = FROM_UNKNOWN; + + sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock < 0) + { + log_unixerr("socket", NULL, "rfc1413: error creating socket", srv); + conn->remote_logname = result; + } + + /* + * Set up a timer so we won't get stuck while waiting for the server. + */ + if (ap_setjmp(timebuf) == 0) + { + signal(SIGALRM, ident_timeout); + alarm(rfc1413_timeout); + + if (get_rfc1413(sock, &conn->local_addr, &conn->remote_addr, user, + srv) + >= 0) + result = user; + + alarm(0); + } + close(sock); + conn->remote_logname = result; + + return conn->remote_logname; +} diff --git a/APACHE_1_2_X/src/main/util.c b/APACHE_1_2_X/src/main/util.c new file mode 100644 index 00000000000..bd853d853e2 --- /dev/null +++ b/APACHE_1_2_X/src/main/util.c @@ -0,0 +1,1328 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * util.c: string utility things + * + * 3/21/93 Rob McCool + * 1995-96 Many changes by the Apache Group + * + */ + +#include "httpd.h" +#include "http_conf_globals.h" /* for user_id & group_id */ + +const char month_snames[12][4] = { + "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" +}; + +char *get_time() { + time_t t; + char *time_string; + + t=time(NULL); + time_string = ctime(&t); + time_string[strlen(time_string) - 1] = '\0'; + return (time_string); +} + +char *ht_time(pool *p, time_t t, const char *fmt, int gmt) { + char ts[MAX_STRING_LEN]; + struct tm *tms; + + tms = (gmt ? gmtime(&t) : localtime(&t)); + + /* check return code? */ + strftime(ts,MAX_STRING_LEN,fmt,tms); + return pstrdup (p, ts); +} + +char *gm_timestr_822(pool *p, time_t sec) { + static const char *const days[7]= + {"Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; + char ts[50]; + struct tm *tms; + + tms = gmtime(&sec); + +/* RFC date format; as strftime '%a, %d %b %Y %T GMT' */ + ap_snprintf(ts, sizeof(ts), + "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", days[tms->tm_wday], + tms->tm_mday, month_snames[tms->tm_mon], tms->tm_year + 1900, + tms->tm_hour, tms->tm_min, tms->tm_sec); + + return pstrdup (p, ts); +} + +/* What a pain in the ass. */ +#if defined(HAVE_GMTOFF) +struct tm *get_gmtoff(int *tz) { + time_t tt = time(NULL); + struct tm *t; + + t = localtime(&tt); + *tz = (int) (t->tm_gmtoff / 60); + return t; +} +#else +struct tm *get_gmtoff(int *tz) { + time_t tt = time(NULL); + struct tm gmt; + struct tm *t; + int days, hours, minutes; + + /* Assume we are never more than 24 hours away. */ + gmt = *gmtime(&tt); /* remember gmtime/localtime return ptr to static */ + t = localtime(&tt); /* buffer... so be careful */ + days = t->tm_yday - gmt.tm_yday; + hours = ((days < -1 ? 24 : 1 < days ? -24 : days * 24) + + t->tm_hour - gmt.tm_hour); + minutes = hours * 60 + t->tm_min - gmt.tm_min; + *tz = minutes; + return t; +} +#endif + + +/* Match = 0, NoMatch = 1, Abort = -1 */ +/* Based loosely on sections of wildmat.c by Rich Salz + * Hmmm... shouldn't this really go component by component? + */ +int strcmp_match(const char *str, const char *exp) { + int x,y; + + for(x=0,y=0;exp[y];++y,++x) { + if((!str[x]) && (exp[y] != '*')) + return -1; + if(exp[y] == '*') { + while(exp[++y] == '*'); + if(!exp[y]) + return 0; + while(str[x]) { + int ret; + if((ret = strcmp_match(&str[x++],&exp[y])) != 1) + return ret; + } + return -1; + } else + if((exp[y] != '?') && (str[x] != exp[y])) + return 1; + } + return (str[x] != '\0'); +} + +int strcasecmp_match(const char *str, const char *exp) { + int x,y; + + for(x=0,y=0;exp[y];++y,++x) { + if((!str[x]) && (exp[y] != '*')) + return -1; + if(exp[y] == '*') { + while(exp[++y] == '*'); + if(!exp[y]) + return 0; + while(str[x]) { + int ret; + if((ret = strcasecmp_match(&str[x++],&exp[y])) != 1) + return ret; + } + return -1; + } else + if((exp[y] != '?') && (tolower(str[x]) != tolower(exp[y]))) + return 1; + } + return (str[x] != '\0'); +} + +int is_matchexp(const char *str) { + register int x; + + for(x=0;str[x];x++) + if((str[x] == '*') || (str[x] == '?')) + return 1; + return 0; +} + +/* This function substitutes for $0-$9, filling in regular expression + * submatches. Pass it the same nmatch and pmatch arguments that you + * passed regexec(). pmatch should not be greater than the maximum number + * of subexpressions - i.e. one more than the re_nsub member of regex_t. + * + * input should be the string with the $-expressions, source should be the + * string that was matched against. + * + * It returns the substituted string, or NULL on error. + * + * Parts of this code are based on Henry Spencer's regsub(), from his + * AT&T V8 regexp package. + */ + +char *pregsub(pool *p, const char *input, const char *source, + size_t nmatch, regmatch_t pmatch[]) { + const char *src = input; + char *dest, *dst; + char c; + int no, len; + + if (!source) return NULL; + if (!nmatch) return pstrdup(p, src); + + /* First pass, find the size */ + + len = 0; + + while ((c = *src++) != '\0') { + if (c == '&') + no = 0; + else if (c == '$' && isdigit(*src)) + no = *src++ - '0'; + else + no = -1; + + if (no < 0) { /* Ordinary character. */ + if (c == '\\' && (*src == '$' || *src == '&')) + c = *src++; + len++; + } else if (no <= nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) { + len += pmatch[no].rm_eo - pmatch[no].rm_so; + } + + } + + dest = dst = pcalloc(p, len + 1); + + /* Now actually fill in the string */ + + src = input; + + while ((c = *src++) != '\0') { + if (c == '&') + no = 0; + else if (c == '$' && isdigit(*src)) + no = *src++ - '0'; + else + no = -1; + + if (no < 0) { /* Ordinary character. */ + if (c == '\\' && (*src == '$' || *src == '&')) + c = *src++; + *dst++ = c; + } else if (no <= nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) { + len = pmatch[no].rm_eo - pmatch[no].rm_so; + strncpy(dst, source + pmatch[no].rm_so, len); + dst += len; + if (*(dst-1) == '\0') /* strncpy hit NULL. */ + return NULL; + } + + } + *dst = '\0'; + + return dest; +} + +/* + * Parse .. so we don't compromise security + */ +void getparents(char *name) +{ + int l, w; + + /* Four paseses, as per RFC 1808 */ + /* a) remove ./ path segments */ + + for (l=0, w=0; name[l] != '\0';) + { + if (name[l] == '.' && name[l+1] == '/' && (l == 0 || name[l-1] == '/')) + l += 2; + else + name[w++] = name[l++]; + } + + /* b) remove trailing . path, segment */ + if (w == 1 && name[0] == '.') w--; + else if (w > 1 && name[w-1] == '.' && name[w-2] == '/') w--; + name[w] = '\0'; + + /* c) remove all xx/../ segments. (including leading ../ and /../) */ + l = 0; + + while(name[l]!='\0') { + if(name[l] == '.' && name[l+1] == '.' && name[l+2] == '/' && + (l == 0 || name[l-1] == '/')) { + register int m=l+3,n; + + l=l-2; + if(l>=0) { + while(l >= 0 && name[l] != '/') l--; + l++; + } + else l=0; + n=l; + while((name[n]=name[m])) (++n,++m); + } + else ++l; + } + + /* d) remove trailing xx/.. segment. */ + if (l == 2 && name[0] == '.' && name[1] == '.') name[0] = '\0'; + else if (l > 2 && name[l-1] == '.' && name[l-2] == '.' && name[l-3] == '/') + { + l = l - 4; + if (l >= 0) + { + while (l >= 0 && name[l] != '/') l--; + l++; + } + else l = 0; + name[l] = '\0'; + } +} + +void no2slash(char *name) { + register int x,y; + + for(x=0; name[x];) + if(x && (name[x-1] == '/') && (name[x] == '/')) + for(y=x+1;name[y-1];y++) + name[y-1] = name[y]; + else x++; +} + +char *make_dirstr(pool *p, const char *s, int n) { + register int x,f; + char *res; + + for(x=0,f=0;s[x];x++) { + if(s[x] == '/') + if((++f) == n) { + res = palloc(p, x + 2); + strncpy (res, s, x); + res[x] = '/'; + res[x+1] = '\0'; + return res; + } + } + + if (s[strlen(s) - 1] == '/') + return pstrdup (p, s); + else + return pstrcat (p, s, "/", NULL); +} + +int count_dirs(const char *path) { + register int x,n; + + for(x=0,n=0;path[x];x++) + if(path[x] == '/') n++; + return n; +} + + +void chdir_file(const char *file) { + int i; + + if((i = rind(file,'/')) == -1) + return; + ((char *)file)[i] = '\0'; + chdir(file); + ((char *)file)[i] = '/'; +} + +char *getword_nc(pool* atrans, char **line, char stop) + { + return getword(atrans,(const char **)line,stop); + } + +char *getword(pool* atrans, const char **line, char stop) { + int pos = ind(*line, stop); + char *res; + + if (pos == -1) { + res = pstrdup (atrans, *line); + *line += strlen (*line); + return res; + } + + res = palloc(atrans, pos + 1); + strncpy (res, *line, pos); + res[pos] = '\0'; + + while ((*line)[pos] == stop) ++pos; + + *line += pos; + + return res; +} + +char *getword_white_nc(pool* atrans, char **line) +{ + return getword_white(atrans,(const char **)line); +} + +char *getword_white(pool* atrans, const char **line) { + int pos = -1, x; + char *res; + + for(x=0;(*line)[x];x++) { + if (isspace((*line)[x])) { + pos=x; + break; + } + } + + if (pos == -1) { + res = pstrdup (atrans, *line); + *line += strlen (*line); + return res; + } + + res = palloc(atrans, pos + 1); + strncpy (res, *line, pos); + res[pos] = '\0'; + + while (isspace((*line)[pos])) ++pos; + + *line += pos; + + return res; +} + +char *getword_nulls_nc(pool* atrans, char **line, char stop) +{ + return getword_nulls(atrans,(const char **)line,stop); +} + +char *getword_nulls(pool* atrans, const char **line, char stop) { + int pos = ind(*line, stop); + char *res; + + if (pos == -1) { + res = pstrdup (atrans, *line); + *line += strlen (*line); + return res; + } + + res = palloc(atrans, pos + 1); + strncpy (res, *line, pos); + res[pos] = '\0'; + + ++pos; + + *line += pos; + + return res; +} + +/* Get a word, (new) config-file style --- quoted strings and backslashes + * all honored + */ + +static char *substring_conf (pool *p, const char *start, int len, char quote) +{ + char *result = palloc (p, len + 2); + char *resp = result; + int i; + + for (i = 0; i < len; ++i) { + if (start[i] == '\\' && (start[i+1] == '/' + || (quote && start[i+1] == quote))) + *resp++ = start[++i]; + else + *resp++ = start[i]; + } + + *resp++ = '\0'; + return result; +} + +char *getword_conf_nc(pool* p, char **line) { + return getword_conf(p,(const char **)line); +} + +char *getword_conf(pool* p, const char **line) { + const char *str = *line, *strend; + char *res; + char quote; + + while (*str && isspace (*str)) + ++str; + + if (!*str) { + *line = str; + return ""; + } + + if ((quote = *str) == '"' || quote == '\'') { + strend = str + 1; + while (*strend && *strend != quote) { + if (*strend == '\\' && strend[1] && strend[1] == quote) + strend += 2; + else ++strend; + } + res = substring_conf (p, str + 1, strend - str - 1, quote); + + if (*strend == quote) ++strend; + } else { + strend = str; + while (*strend && !isspace (*strend)) + ++strend; + + res = substring_conf (p, str, strend - str, 0); + } + + while (*strend && isspace(*strend)) ++ strend; + *line = strend; + return res; +} + +#ifdef UNDEF +/* this function is dangerous, and superceded by getword_white, so don't use it + */ +void cfg_getword(char *word, char *line) { + int x=0,y; + + for(x=0;line[x] && isspace(line[x]);x++); + y=0; + while(1) { + if(!(word[y] = line[x])) + break; + if(isspace(line[x])) + if((!x) || (line[x-1] != '\\')) + break; + if(line[x] != '\\') ++y; + ++x; + } + word[y] = '\0'; + while(line[x] && isspace(line[x])) ++x; + for(y=0;(line[y] = line[x]);++x,++y); +} +#endif + +int +cfg_getline(char *s, int n, FILE *f) { + register int i=0, c; + + s[0] = '\0'; + /* skip leading whitespace */ + do { + c = getc(f); + } while (c == '\t' || c == ' '); + + if(c == EOF) + return 1; + + while(1) { + if((c == '\t') || (c == ' ')) { + s[i++] = ' '; + while((c == '\t') || (c == ' ')) + c = getc(f); + } + if(c == CR) { + c = getc(f); + } + if(c == EOF || c == 0x4 || c == LF || i == (n-1)) { + /* blast trailing whitespace */ + while(i && (s[i-1] == ' ')) --i; + s[i] = '\0'; + return 0; + } + s[i] = c; + ++i; + c = getc(f); + } +} + +/* Retrieve a token, spacing over it and returning a pointer to + * the first non-white byte afterwards. Note that these tokens + * are delimited by semis and commas; and can also be delimited + * by whitespace at the caller's option. + */ + +char *get_token (pool *p, char **accept_line, int accept_white) +{ + char *ptr = *accept_line; + char *tok_start; + char *token; + int tok_len; + + /* Find first non-white byte */ + + while (*ptr && isspace(*ptr)) + ++ptr; + + tok_start = ptr; + + /* find token end, skipping over quoted strings. + * (comments are already gone). + */ + + while (*ptr && (accept_white || !isspace(*ptr)) + && *ptr != ';' && *ptr != ',') + { + if (*ptr++ == '"') + while (*ptr) + if (*ptr++ == '"') break; + } + + tok_len = ptr - tok_start; + token = palloc (p, tok_len + 1); + strncpy (token, tok_start, tok_len); + token[tok_len] = '\0'; + + /* Advance accept_line pointer to the next non-white byte */ + + while (*ptr && isspace(*ptr)) + ++ptr; + + *accept_line = ptr; + return token; +} + +static char* tspecials = " \t()<>@,;:\\/[]?={}"; + +/* Next HTTP token from a header line. Warning --- destructive! + * Use only with a copy! + */ + +static char *next_token (char **toks) { + char *cp = *toks; + char *ret; + + while (*cp && (iscntrl (*cp) || strchr (tspecials, *cp))) { + if (*cp == '"') + while (*cp && (*cp != '"')) ++cp; + else + ++cp; + } + + if (!*cp) ret = NULL; + else { + ret = cp; + + while (*cp && !iscntrl(*cp) && !strchr (tspecials, *cp)) + ++cp; + + if (*cp) { + *toks = cp + 1; + *cp = '\0'; + } + else *toks = cp; + } + + return ret; +} + +int find_token (pool *p, const char *line, const char *tok) { + char *ltok; + char *lcopy; + + if (!line) return 0; + + lcopy = pstrdup (p, line); + while ((ltok = next_token (&lcopy))) + if (!strcasecmp (ltok, tok)) + return 1; + + return 0; +} + +int find_last_token (pool *p, const char *line, const char *tok) +{ + int llen, tlen, lidx; + + if (!line) return 0; + + llen = strlen(line); + tlen = strlen(tok); + lidx = llen - tlen; + + if ((lidx < 0) || + ((lidx > 0) && !(isspace(line[lidx-1]) || line[lidx-1] == ','))) + return 0; + + return (strncasecmp(&line[lidx], tok, tlen) == 0); +} + +char *escape_shell_cmd(pool *p, const char *s) { + register int x,y,l; + char *cmd; + + l=strlen(s); + cmd = palloc (p, 2 * l + 1); /* Be safe */ + strcpy (cmd, s); + + for(x=0;cmd[x];x++) { + +#ifdef __EMX__ + /* Don't allow '&' in parameters under OS/2. */ + /* This can be used to send commands to the shell. */ + if (cmd[x] == '&') { + cmd[x] = ' '; + } +#endif + + if(ind("&;`'\"|*?~<>^()[]{}$\\\n",cmd[x]) != -1){ + for(y=l+1;y>x;y--) + cmd[y] = cmd[y-1]; + l++; /* length has been increased */ + cmd[x] = '\\'; + x++; /* skip the character */ + } + } + + return cmd; +} + +void plustospace(char *str) { + register int x; + + for(x=0;str[x];x++) if(str[x] == '+') str[x] = ' '; +} + +void spacetoplus(char *str) { + register int x; + + for(x=0;str[x];x++) if(str[x] == ' ') str[x] = '+'; +} + +static char x2c(const char *what) { + register char digit; + + digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0')); + digit *= 16; + digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0')); + return(digit); +} + +/* + * Unescapes a URL. + * Returns 0 on success, non-zero on error + * Failure is due to + * bad % escape returns BAD_REQUEST + * + * decoding %00 -> \0 + * decoding %2f -> / (a special character) + * returns NOT_FOUND + */ +int +unescape_url(char *url) { + register int x,y, badesc, badpath; + + badesc = 0; + badpath = 0; + for(x=0,y=0;url[y];++x,++y) { + if (url[y] != '%') url[x] = url[y]; + else + { + if (!isxdigit(url[y+1]) || !isxdigit(url[y+2])) + { + badesc = 1; + url[x] = '%'; + } else + { + url[x] = x2c(&url[y+1]); + y += 2; + if (url[x] == '/' || url[x] == '\0') badpath = 1; + } + } + } + url[x] = '\0'; + if (badesc) return BAD_REQUEST; + else if (badpath) return NOT_FOUND; + else return OK; +} + +char *construct_server(pool *p, const char *hostname, unsigned port) { + char portnum[22]; + /* Long enough, even if port > 16 bits for some reason */ + + if (port == DEFAULT_PORT) + return (char *)hostname; + else { + ap_snprintf (portnum, sizeof(portnum), "%u", port); + return pstrcat (p, hostname, ":", portnum, NULL); + } +} + +char *construct_url(pool *p, const char *uri, const server_rec *s) { + return pstrcat (p, "http://", + construct_server(p, s->server_hostname, s->port), + uri, NULL); +} + +#define c2x(what,where) sprintf(where,"%%%02x",(unsigned char)what) + +/* +escape_path_segment() escapes a path segment, as defined in RFC 1808. This +routine is (should be) OS independent. + +os_escape_path() converts an OS path to a URL, in an OS dependent way. In all +cases if a ':' occurs before the first '/' in the URL, the URL should be +prefixed with "./" (or the ':' escaped). In the case of Unix, this means +leaving '/' alone, but otherwise doing what escape_path_segment() does. For +efficiency reasons, we don't use escape_path_segment(), which is provided for +reference. Again, RFC 1808 is where this stuff is defined. + +If partial is set, os_escape_path() assumes that the path will be appended to +something with a '/' in it (and thus does not prefix "./"). +*/ + +char *escape_path_segment(pool *p, const char *segment) { + register int x,y; + char *copy = palloc (p, 3 * strlen (segment) + 1); + + for(x=0,y=0; segment[x]; x++,y++) { + char c=segment[x]; + if((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c >'9') + && ind("$-_.+!*'(),:@&=~",c) == -1) + { + c2x(c,©[y]); + y+=2; + } + else + copy[y]=c; + } + copy[y] = '\0'; + return copy; +} + +char *os_escape_path(pool *p,const char *path,int partial) { + char *copy=palloc(p,3*strlen(path)+3); + char *s=copy; + + if(!partial) + { + int colon=ind(path,':'); + int slash=ind(path,'/'); + + if(colon >= 0 && (colon < slash || slash < 0)) + { + *s++='.'; + *s++='/'; + } + } + for( ; *path ; ++path) + { + char c=*path; + if((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c >'9') + && ind("$-_.+!*'(),:@&=/~",c) == -1) + { + c2x(c,s); + s+=3; + } + else + *s++=c; + } + *s='\0'; + return copy; +} + +/* escape_uri is now a macro for os_escape_path */ + +char *escape_html(pool *p, const char *s) +{ + int i, j; + char *x; + +/* first, count the number of extra characters */ + for (i=0, j=0; s[i] != '\0'; i++) + if (s[i] == '<' || s[i] == '>') j += 3; + else if (s[i] == '&') j += 4; + + if (j == 0) return pstrdup(p, s); + x = palloc(p, i + j + 1); + for (i=0, j=0; s[i] != '\0'; i++, j++) + if (s[i] == '<') + { + memcpy(&x[j], "<", 4); + j += 3; + } else if (s[i] == '>') + { + memcpy(&x[j], ">", 4); + j += 3; + } else if (s[i] == '&') + { + memcpy(&x[j], "&", 5); + j += 4; + } else + x[j] = s[i]; + + x[j] = '\0'; + return x; +} + +int is_directory(const char *path) { + struct stat finfo; + + if(stat(path,&finfo) == -1) + return 0; /* in error condition, just return no */ + + return(S_ISDIR(finfo.st_mode)); +} + +char *make_full_path(pool *a, const char *src1, const char *src2) { + register int x; + + x = strlen(src1); + if (x == 0) return pstrcat (a, "/", src2, NULL); + + if (src1[x - 1] != '/') return pstrcat (a, src1, "/", src2, NULL); + else return pstrcat (a, src1, src2, NULL); +} + +/* + * Check for an absoluteURI syntax (see section 3.2 in RFC2068). + */ +int is_url(const char *u) { + register int x; + + for (x = 0; u[x] != ':'; x++) { + if ((! u[x]) || + ((! isalpha(u[x])) && (! isdigit(u[x])) && + (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) { + return 0; + } + } + + return (x ? 1 : 0); /* If the first character is ':', it's broken, too */ +} + +int can_exec(const struct stat *finfo) { +#ifdef MULTIPLE_GROUPS + int cnt; +#endif +#ifdef __EMX__ + /* OS/2 dosen't have Users and Groups */ + return 1; +#else + if(user_id == finfo->st_uid) + if(finfo->st_mode & S_IXUSR) + return 1; + if(group_id == finfo->st_gid) + if(finfo->st_mode & S_IXGRP) + return 1; +#ifdef MULTIPLE_GROUPS + for(cnt=0; cnt < NGROUPS_MAX; cnt++) { + if(group_id_list[cnt] == finfo->st_gid) + if(finfo->st_mode & S_IXGRP) + return 1; + } +#endif + return (finfo->st_mode & S_IXOTH); +#endif +} + +#ifdef NEED_STRDUP +char *strdup (const char *str) +{ + char *dup; + + if(!(dup = (char *)malloc (strlen (str) + 1))) + return NULL; + dup = strcpy (dup, str); + + return dup; +} +#endif + +/* The following two routines were donated for SVR4 by Andreas Vogel */ +#ifdef NEED_STRCASECMP +int strcasecmp (const char *a, const char *b) +{ + const char *p = a; + const char *q = b; + for (p = a, q = b; *p && *q; p++, q++) + { + int diff = tolower(*p) - tolower(*q); + if (diff) return diff; + } + if (*p) return 1; /* p was longer than q */ + if (*q) return -1; /* p was shorter than q */ + return 0; /* Exact match */ +} + +#endif + +#ifdef NEED_STRNCASECMP +int strncasecmp (const char *a, const char *b, int n) +{ + const char *p = a; + const char *q = b; + + for (p = a, q = b; /*NOTHING*/; p++, q++) + { + int diff; + if (p == a + n) return 0; /* Match up to n characters */ + if (!(*p && *q)) return *p - *q; + diff = tolower(*p) - tolower(*q); + if (diff) return diff; + } + /*NOTREACHED*/ +} +#endif + + + +#ifdef NEED_INITGROUPS +int initgroups(const char *name, gid_t basegid) +{ +#if defined(QNX) || defined(MPE) +/* QNX and MPE do not appear to support supplementary groups. */ + return 0; +#else /* ndef QNX */ + gid_t groups[NGROUPS_MAX]; + struct group *g; + int index = 0; + + setgrent(); + + groups[index++] = basegid; + + while (index < NGROUPS_MAX && ((g = getgrent()) != NULL)) + if (g->gr_gid != basegid) + { + char **names; + + for (names = g->gr_mem; *names != NULL; ++names) + if (!strcmp(*names, name)) + groups[index++] = g->gr_gid; + } + + endgrent(); + + return setgroups(index, groups); +#endif /* def QNX */ +} +#endif /* def NEED_INITGROUPS */ + +#ifdef NEED_WAITPID +/* From ikluft@amdahl.com */ +/* this is not ideal but it works for SVR3 variants */ +/* httpd does not use the options so this doesn't implement them */ +int waitpid(pid_t pid, int *statusp, int options) +{ + int tmp_pid; + if ( kill ( pid,0 ) == -1) { + errno=ECHILD; + return -1; + } + while ((( tmp_pid = wait(statusp)) != pid) && ( tmp_pid != -1 )); + return tmp_pid; +} +#endif + +int ind(const char *s, char c) { + register int x; + + for(x=0;s[x];x++) + if(s[x] == c) return x; + + return -1; +} + +int rind(const char *s, char c) { + register int x; + + for(x=strlen(s)-1;x != -1;x--) + if(s[x] == c) return x; + + return -1; +} + +void str_tolower(char *str) { + while(*str) { + *str = tolower(*str); + ++str; + } +} + +uid_t uname2id(const char *name) { + struct passwd *ent; + + if(name[0] == '#') + return(atoi(&name[1])); + + if(!(ent = getpwnam(name))) { + fprintf(stderr,"httpd: bad user name %s\n",name); + exit(1); + } + return(ent->pw_uid); +} + +gid_t gname2id(const char *name) { + struct group *ent; + + if(name[0] == '#') + return(atoi(&name[1])); + + if(!(ent = getgrnam(name))) { + fprintf(stderr,"httpd: bad group name %s\n",name); + exit(1); + } + return(ent->gr_gid); +} + +#if 0 +int get_portnum(int sd) { + struct sockaddr addr; + int len; + + len = sizeof(struct sockaddr); + if(getsockname(sd,&addr,&len) < 0) + return -1; + return ntohs(((struct sockaddr_in *)&addr)->sin_port); +} + +struct in_addr get_local_addr(int sd) { + struct sockaddr addr; + int len; + + len = sizeof(struct sockaddr); + if(getsockname(sd,&addr,&len) < 0) { + perror ("getsockname"); + fprintf (stderr, "Can't get local host address!\n"); + exit(1); + } + + return ((struct sockaddr_in *)&addr)->sin_addr; +} +#endif + +/* + * Parses a host of the form

    [:port] + * :port is permitted if 'port' is not NULL + */ +unsigned long get_virthost_addr (const char *w, unsigned short *ports) { + struct hostent *hep; + unsigned long my_addr; + char *p; + + p = strchr(w, ':'); + if (ports != NULL) + { + *ports = 0; + if (p != NULL && strcmp(p+1, "*") != 0) *ports = atoi(p+1); + } + + if (p != NULL) *p = '\0'; + if (strcmp(w, "*") == 0) + { + if (p != NULL) *p = ':'; + return htonl(INADDR_ANY); + } + +#ifdef DGUX + my_addr = inet_network(w); +#else + my_addr = inet_addr(w); +#endif + if (my_addr != INADDR_NONE) + { + if (p != NULL) *p = ':'; + return my_addr; + } + + hep = gethostbyname(w); + + if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) { + fprintf (stderr, "Cannot resolve host name %s --- exiting!\n", w); + exit(1); + } + + if (hep->h_addr_list[1]) { + fprintf(stderr, "Host %s has multiple addresses ---\n", w); + fprintf(stderr, "you must choose one explicitly for use as\n"); + fprintf(stderr, "a virtual host. Exiting!!!\n"); + exit(1); + } + + if (p != NULL) *p = ':'; + + return ((struct in_addr *)(hep->h_addr))->s_addr; +} + + +static char *find_fqdn(pool *a, struct hostent *p) { + int x; + + if(ind(p->h_name,'.') == -1) { + for(x=0;p->h_aliases[x];++x) { + if((ind(p->h_aliases[x],'.') != -1) && + (!strncmp(p->h_aliases[x],p->h_name,strlen(p->h_name)))) + return pstrdup(a, p->h_aliases[x]); + } + return NULL; + } + return pstrdup(a, (void *)p->h_name); +} + +char *get_local_host(pool *a) +{ +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 256 +#endif + char str[MAXHOSTNAMELEN+1]; + char *server_hostname; + struct hostent *p; + + if( gethostname( str, sizeof( str ) - 1 ) != 0 ) { + perror( "Unable to gethostname" ); + exit(1); + } + str[MAXHOSTNAMELEN] = '\0'; + if((!(p=gethostbyname(str))) || (!(server_hostname = find_fqdn(a, p)))) { + fprintf(stderr,"httpd: cannot determine local host name.\n"); + fprintf(stderr,"Use ServerName to set it manually.\n"); + exit(1); + } + + return server_hostname; +} + +/* aaaack but it's fast and const should make it shared text page. */ +const int pr2six[256]={ + 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, + 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63, + 52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9, + 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27, + 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51, + 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, + 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, + 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, + 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, + 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, + 64,64,64,64,64,64,64,64,64,64,64,64,64 +}; + +char *uudecode(pool *p, const char *bufcoded) { + int nbytesdecoded; + register unsigned char *bufin; + register char *bufplain; + register unsigned char *bufout; + register int nprbytes; + + /* Strip leading whitespace. */ + + while(*bufcoded==' ' || *bufcoded == '\t') bufcoded++; + + /* Figure out how many characters are in the input buffer. + * Allocate this many from the per-transaction pool for the result. + */ + bufin = (unsigned char *)bufcoded; + while(pr2six[*(bufin++)] <= 63); + nprbytes = (char *)bufin - bufcoded - 1; + nbytesdecoded = ((nprbytes+3)/4) * 3; + + bufplain = palloc(p, nbytesdecoded + 1); + bufout = (unsigned char *)bufplain; + + bufin = (unsigned char *)bufcoded; + + while (nprbytes > 0) { + *(bufout++) = + (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4); + *(bufout++) = + (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2); + *(bufout++) = + (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]); + bufin += 4; + nprbytes -= 4; + } + + if(nprbytes & 03) { + if(pr2six[bufin[-2]] > 63) + nbytesdecoded -= 2; + else + nbytesdecoded -= 1; + } + bufplain[nbytesdecoded] = '\0'; + return bufplain; +} + +#ifdef __EMX__ +void os2pathname(char *path) { + char newpath[MAX_STRING_LEN]; + int loop; + int offset; + + offset = 0; + for (loop=0; loop < (strlen(path) + 1) && loop < sizeof(newpath)-1; loop++) { + if (path[loop] == '/') { + newpath[offset] = '\\'; + /* + offset = offset + 1; + newpath[offset] = '\\'; + */ + } else + newpath[offset] = path[loop]; + offset = offset + 1; + }; + /* Debugging code */ + /* fprintf(stderr, "%s \n", newpath); */ + + strcpy(path, newpath); +}; +#endif + + +#ifdef NEED_STRERROR +char * +strerror (int err) { + + char *p; + extern char *const sys_errlist[]; + + p = sys_errlist[err]; + return (p); +} +#endif diff --git a/APACHE_1_2_X/src/main/util_date.c b/APACHE_1_2_X/src/main/util_date.c new file mode 100644 index 00000000000..e544a0fe1cc --- /dev/null +++ b/APACHE_1_2_X/src/main/util_date.c @@ -0,0 +1,296 @@ +/* ==================================================================== + * Copyright (c) 1996,1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * util_date.c: date parsing utility routines + * These routines are (hopefully) platform-independent. + * + * 27 Oct 1996 Roy Fielding + * Extracted (with many modifications) from mod_proxy.c and + * tested with over 50,000 randomly chosen valid date strings + * and several hundred variations of invalid date strings. + * + */ + +#include "util_date.h" +#include +#include + +/* + * Compare a string to a mask + * Mask characters (arbitrary maximum is 256 characters, just in case): + * @ - uppercase letter + * $ - lowercase letter + * & - hex digit + * # - digit + * ~ - digit or space + * * - swallow remaining characters + * - exact match for any other character + */ +int checkmask(const char *data, const char *mask) +{ + int i; + char d; + + for (i = 0; i < 256; i++) { + d = data[i]; + switch (mask[i]) { + case '\0': return (d == '\0'); + + case '*': return 1; + + case '@': if (!isupper(d)) return 0; + break; + case '$': if (!islower(d)) return 0; + break; + case '#': if (!isdigit(d)) return 0; + break; + case '&': if (!isxdigit(d)) return 0; + break; + case '~': if ((d != ' ') && !isdigit(d)) return 0; + break; + default: if (mask[i] != d) return 0; + break; + } + } + return 0; /* We only get here if mask is corrupted (exceeds 256) */ +} + +/* + * tm2sec converts a GMT tm structure into the number of seconds since + * 1st January 1970 UT. Note that we ignore tm_wday, tm_yday, and tm_dst. + * + * The return value is always a valid time_t value -- (time_t)0 is returned + * if the input date is outside that capable of being represented by time(), + * i.e., before Thu, 01 Jan 1970 00:00:00 for all systems and + * beyond 2038 for 32bit systems. + * + * This routine is intended to be very fast, much faster than mktime(). + */ +time_t tm2sec(const struct tm *t) +{ + int year; + time_t days; + const int dayoffset[12] = + {306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275}; + + year = t->tm_year; + + if (year < 70 || ((sizeof(time_t) <= 4) && (year >= 138))) + return BAD_DATE; + + /* shift new year to 1st March in order to make leap year calc easy */ + + if (t->tm_mon < 2) year--; + + /* Find number of days since 1st March 1900 (in the Gregorian calendar). */ + + days = year * 365 + year/4 - year/100 + (year/100 + 3)/4; + days += dayoffset[t->tm_mon] + t->tm_mday - 1; + days -= 25508; /* 1 jan 1970 is 25508 days since 1 mar 1900 */ + + days = ((days * 24 + t->tm_hour) * 60 + t->tm_min) * 60 + t->tm_sec; + + if (days < 0) + return BAD_DATE; /* must have overflowed */ + else + return days; /* must be a valid time */ +} + +/* + * Parses an HTTP date in one of three standard forms: + * + * Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 + * Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 + * Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format + * + * and returns the time_t number of seconds since 1 Jan 1970 GMT, or + * 0 if this would be out of range or if the date is invalid. + * + * The restricted HTTP syntax is + * + * HTTP-date = rfc1123-date | rfc850-date | asctime-date + * + * rfc1123-date = wkday "," SP date1 SP time SP "GMT" + * rfc850-date = weekday "," SP date2 SP time SP "GMT" + * asctime-date = wkday SP date3 SP time SP 4DIGIT + * + * date1 = 2DIGIT SP month SP 4DIGIT + * ; day month year (e.g., 02 Jun 1982) + * date2 = 2DIGIT "-" month "-" 2DIGIT + * ; day-month-year (e.g., 02-Jun-82) + * date3 = month SP ( 2DIGIT | ( SP 1DIGIT )) + * ; month day (e.g., Jun 2) + * + * time = 2DIGIT ":" 2DIGIT ":" 2DIGIT + * ; 00:00:00 - 23:59:59 + * + * wkday = "Mon" | "Tue" | "Wed" + * | "Thu" | "Fri" | "Sat" | "Sun" + * + * weekday = "Monday" | "Tuesday" | "Wednesday" + * | "Thursday" | "Friday" | "Saturday" | "Sunday" + * + * month = "Jan" | "Feb" | "Mar" | "Apr" + * | "May" | "Jun" | "Jul" | "Aug" + * | "Sep" | "Oct" | "Nov" | "Dec" + * + * However, for the sake of robustness (and Netscapeness), we ignore the + * weekday and anything after the time field (including the timezone). + * + * This routine is intended to be very fast; 10x faster than using sscanf. + * + * Originally from Andrew Daviel , 29 Jul 96 + * but many changes since then. + * + */ +time_t parseHTTPdate(const char *date) +{ + struct tm ds; + int mint, mon; + const char *monstr, *timstr; + const int months[12] = { + ('J' << 16) | ( 'a' << 8) | 'n', ('F' << 16) | ( 'e' << 8) | 'b', + ('M' << 16) | ( 'a' << 8) | 'r', ('A' << 16) | ( 'p' << 8) | 'r', + ('M' << 16) | ( 'a' << 8) | 'y', ('J' << 16) | ( 'u' << 8) | 'n', + ('J' << 16) | ( 'u' << 8) | 'l', ('A' << 16) | ( 'u' << 8) | 'g', + ('S' << 16) | ( 'e' << 8) | 'p', ('O' << 16) | ( 'c' << 8) | 't', + ('N' << 16) | ( 'o' << 8) | 'v', ('D' << 16) | ( 'e' << 8) | 'c'}; + + if (!date) + return BAD_DATE; + + while (*date && isspace(*date)) /* Find first non-whitespace char */ + ++date; + + if (*date == '\0') + return BAD_DATE; + + if ((date = strchr(date,' ')) == NULL) /* Find space after weekday */ + return BAD_DATE; + + ++date; /* Now pointing to first char after space, which should be */ + /* start of the actual date information for all 3 formats. */ + + if (checkmask(date, "## @$$ #### ##:##:## *")) { /* RFC 1123 format */ + ds.tm_year = ((date[7] - '0') * 10 + (date[8] - '0') - 19) * 100; + if (ds.tm_year < 0) + return BAD_DATE; + + ds.tm_year += ((date[9] - '0') * 10) + (date[10] - '0'); + + ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0'); + + monstr = date + 3; + timstr = date + 12; + } + else if (checkmask(date, "##-@$$-## ##:##:## *")) { /* RFC 850 format */ + ds.tm_year = ((date[7] - '0') * 10) + (date[8] - '0'); + if (ds.tm_year < 70) + ds.tm_year += 100; + + ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0'); + + monstr = date + 3; + timstr = date + 10; + } + else if (checkmask(date, "@$$ ~# ##:##:## ####*")) { /* asctime format */ + ds.tm_year = ((date[16] - '0') * 10 + (date[17] - '0') - 19) * 100; + if (ds.tm_year < 0) + return BAD_DATE; + + ds.tm_year += ((date[18] - '0') * 10) + (date[19] - '0'); + + if (date[4] == ' ') + ds.tm_mday = 0; + else + ds.tm_mday = (date[4] - '0') * 10; + + ds.tm_mday += (date[5] - '0'); + + monstr = date; + timstr = date + 7; + } + else return BAD_DATE; + + if (ds.tm_mday <= 0 || ds.tm_mday > 31) + return BAD_DATE; + + ds.tm_hour = ((timstr[0] - '0') * 10) + (timstr[1] - '0'); + ds.tm_min = ((timstr[3] - '0') * 10) + (timstr[4] - '0'); + ds.tm_sec = ((timstr[6] - '0') * 10) + (timstr[7] - '0'); + + if ((ds.tm_hour > 23) || (ds.tm_min > 59) || (ds.tm_sec > 61)) + return BAD_DATE; + + mint = (monstr[0] << 16) | (monstr[1] << 8) | monstr[2]; + for (mon=0; mon < 12; mon++) + if (mint == months[mon]) + break; + if (mon == 12) + return BAD_DATE; + + if ((ds.tm_mday == 31) && (mon == 3 || mon == 5 || mon == 8 || mon == 10)) + return BAD_DATE; + + /* February gets special check for leapyear */ + + if ((mon == 1) && ((ds.tm_mday > 29) || + ((ds.tm_mday == 29) && ((ds.tm_year & 3) || + (((ds.tm_year % 100) == 0) && (((ds.tm_year % 400) != 100))))))) + return BAD_DATE; + + ds.tm_mon = mon; + + return tm2sec(&ds); +} + diff --git a/APACHE_1_2_X/src/main/util_md5.c b/APACHE_1_2_X/src/main/util_md5.c new file mode 100644 index 00000000000..bf5565e21f0 --- /dev/null +++ b/APACHE_1_2_X/src/main/util_md5.c @@ -0,0 +1,192 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/************************************************************************ + * NCSA HTTPd Server + * Software Development Group + * National Center for Supercomputing Applications + * University of Illinois at Urbana-Champaign + * 605 E. Springfield, Champaign, IL 61820 + * httpd@ncsa.uiuc.edu + * + * Copyright (C) 1995, Board of Trustees of the University of Illinois + * + ************************************************************************ + * + * md5.c: NCSA HTTPd code which uses the md5c.c RSA Code + * + * Original Code Copyright (C) 1994, Jeff Hostetler, Spyglass, Inc. + * Portions of Content-MD5 code Copyright (C) 1993, 1994 by Carnegie Mellon + * University (see Copyright below). + * Portions of Content-MD5 code Copyright (C) 1991 Bell Communications + * Research, Inc. (Bellcore) (see Copyright below). + * Portions extracted from mpack, John G. Myers - jgm+@cmu.edu + * Content-MD5 Code contributed by Martin Hamilton (martin@net.lut.ac.uk) + * + */ + + + +/* md5.c --Module Interface to MD5. */ +/* Jeff Hostetler, Spyglass, Inc., 1994. */ + +#include "httpd.h" +#include "util_md5.h" + +char *md5 (pool *p, unsigned char *string) +{ + MD5_CTX my_md5; + unsigned char hash[16]; + char *r, result[33]; + int i; + + /* + * Take the MD5 hash of the string argument. + */ + + MD5Init(&my_md5); + MD5Update(&my_md5, string, strlen((const char *)string)); + MD5Final(hash, &my_md5); + + for (i=0, r=result; i<16; i++, r+=2) + sprintf(r, "%02x", hash[i]); + *r = '\0'; + + return pstrdup(p, result); +} + +/* these portions extracted from mpack, John G. Myers - jgm+@cmu.edu */ + +/* (C) Copyright 1993,1994 by Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of Carnegie + * Mellon University not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. Carnegie Mellon University makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore) + * + * Permission to use, copy, modify, and distribute this material + * for any purpose and without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies, and that the name of Bellcore not be + * used in advertising or publicity pertaining to this + * material without the specific, prior written permission + * of an authorized representative of Bellcore. BELLCORE + * MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY + * OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS", + * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. + */ + +static char basis_64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +char *md5contextTo64(pool *a, MD5_CTX *context) +{ + unsigned char digest[18]; + char *encodedDigest; + int i; + char *p; + + encodedDigest = (char *)pcalloc(a, 25 * sizeof(char)); + + MD5Final(digest, context); + digest[sizeof(digest)-1] = digest[sizeof(digest)-2] = 0; + + p = encodedDigest; + for (i=0; i < sizeof(digest); i+=3) { + *p++ = basis_64[digest[i]>>2]; + *p++ = basis_64[((digest[i] & 0x3)<<4) | ((int)(digest[i+1] & 0xF0)>>4)]; + *p++ = basis_64[((digest[i+1] & 0xF)<<2) | ((int)(digest[i+2] & 0xC0)>>6)]; + *p++ = basis_64[digest[i+2] & 0x3F]; + } + *p-- = '\0'; + *p-- = '='; + *p-- = '='; + return encodedDigest; +} + +char *md5digest(pool *p, FILE *infile) +{ + MD5_CTX context; + unsigned char buf[1000]; + long length = 0; + int nbytes; + + MD5Init(&context); + while ((nbytes = fread(buf, 1, sizeof(buf), infile))) { + length += nbytes; + MD5Update(&context, buf, nbytes); + } + rewind(infile); + return md5contextTo64(p, &context); +} + diff --git a/APACHE_1_2_X/src/main/util_script.c b/APACHE_1_2_X/src/main/util_script.c new file mode 100644 index 00000000000..12e57b44d1f --- /dev/null +++ b/APACHE_1_2_X/src/main/util_script.c @@ -0,0 +1,638 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +#define CORE_PRIVATE +#include "httpd.h" +#include "http_config.h" +#include "http_conf_globals.h" +#include "http_main.h" +#include "http_log.h" +#include "http_protocol.h" +#include "http_core.h" /* For document_root. Sigh... */ +#include "http_request.h" /* for sub_req_lookup_uri() */ +#include "util_script.h" +#include + +/* + * Various utility functions which are common to a whole lot of + * script-type extensions mechanisms, and might as well be gathered + * in one place (if only to avoid creating inter-module dependancies + * where there don't have to be). + */ + +#define MALFORMED_MESSAGE "malformed header from script. Bad header=" +#define MALFORMED_HEADER_LENGTH_TO_SHOW 30 + +/* If a request includes query info in the URL (stuff after "?"), and + * the query info does not contain "=" (indicative of a FORM submission), + * then this routine is called to create the argument list to be passed + * to the CGI script. When suexec is enabled, the suexec path, user, and + * group are the first three arguments to be passed; if not, all three + * must be NULL. The query info is split into separate arguments, where + * "+" is the separator between keyword arguments. + */ +static char **create_argv(pool *p, char *path, char *user, char *group, + char *av0, const char *args) +{ + int x, numwords; + char **av; + char *w; + int idx = 0; + + /* count the number of keywords */ + + for (x = 0, numwords = 1; args[x]; x++) + if (args[x] == '+') ++numwords; + + if (numwords > APACHE_ARG_MAX - 5) { + numwords = APACHE_ARG_MAX - 5; /* Truncate args to prevent overrun */ + } + av = (char **)palloc(p, (numwords + 5) * sizeof(char *)); + + if (path) + av[idx++] = path; + if (user) + av[idx++] = user; + if (group) + av[idx++] = group; + + av[idx++] = av0; + + for (x = 1; x <= numwords; x++) { + w = getword_nulls(p, &args, '+'); + unescape_url(w); + av[idx++] = escape_shell_cmd(p, w); + } + av[idx] = NULL; + return av; +} + + +static char *http2env(pool *a, char *w) +{ + char *res = pstrcat (a, "HTTP_", w, NULL); + char *cp = res; + + while (*++cp) + if (*cp == '-') *cp = '_'; + else *cp = toupper(*cp); + + return res; +} + +char **create_environment(pool *p, table *t) +{ + array_header *env_arr = table_elts (t); + table_entry *elts = (table_entry *)env_arr->elts; + char **env = (char **)palloc (p, (env_arr->nelts + 2) *sizeof (char *)); + int i, j; + char *tz; + + j = 0; + tz = getenv("TZ"); + if (tz!= NULL) env[j++] = pstrcat(p, "TZ=", tz, NULL); + for (i = 0; i < env_arr->nelts; ++i) { + if (!elts[i].key) continue; + env[j++] = pstrcat (p, elts[i].key, "=", elts[i].val, NULL); + } + + env[j] = NULL; + return env; +} + +void add_common_vars(request_rec *r) +{ + table *e = r->subprocess_env; + server_rec *s = r->server; + conn_rec *c = r->connection; + const char *rem_logname; + + char port[40],*env_path; + + array_header *hdrs_arr = table_elts (r->headers_in); + table_entry *hdrs = (table_entry *)hdrs_arr->elts; + int i; + + /* First, add environment vars from headers... this is as per + * CGI specs, though other sorts of scripting interfaces see + * the same vars... + */ + + for (i = 0; i < hdrs_arr->nelts; ++i) { + if (!hdrs[i].key) continue; + + /* A few headers are special cased --- Authorization to prevent + * rogue scripts from capturing passwords; content-type and -length + * for no particular reason. + */ + + if (!strcasecmp (hdrs[i].key, "Content-type")) + table_set (e, "CONTENT_TYPE", hdrs[i].val); + else if (!strcasecmp (hdrs[i].key, "Content-length")) + table_set (e, "CONTENT_LENGTH", hdrs[i].val); + else if (!strcasecmp (hdrs[i].key, "Authorization")) + continue; + else + table_set (e, http2env (r->pool, hdrs[i].key), hdrs[i].val); + } + + ap_snprintf(port, sizeof(port), "%u", s->port); + + if(!(env_path = getenv("PATH"))) + env_path=DEFAULT_PATH; + + table_set (e, "PATH", env_path); + table_set (e, "SERVER_SOFTWARE", SERVER_VERSION); + table_set (e, "SERVER_NAME", s->server_hostname); + table_set (e, "SERVER_PORT", port); + table_set (e, "REMOTE_HOST", + get_remote_host(c, r->per_dir_config, REMOTE_NAME)); + table_set (e, "REMOTE_ADDR", c->remote_ip); + table_set (e, "DOCUMENT_ROOT", document_root(r)); /* Apache */ + table_set (e, "SERVER_ADMIN", s->server_admin); /* Apache */ + table_set (e, "SCRIPT_FILENAME", r->filename); /* Apache */ + + ap_snprintf(port, sizeof(port), "%d", ntohs(c->remote_addr.sin_port)); + table_set (e, "REMOTE_PORT", port); /* Apache */ + + if (c->user) table_set(e, "REMOTE_USER", c->user); + if (c->auth_type) table_set(e, "AUTH_TYPE", c->auth_type); + rem_logname = get_remote_logname(r); + if (rem_logname) table_set(e, "REMOTE_IDENT", rem_logname); + + /* Apache custom error responses. If we have redirected set two new vars */ + + if (r->prev) { + if (r->prev->args) table_set(e,"REDIRECT_QUERY_STRING", r->prev->args); + if (r->prev->uri) table_set (e, "REDIRECT_URL", r->prev->uri); + } +} + +/* This "cute" little function comes about because the path info on + * filenames and URLs aren't always the same. So we take the two, + * and find as much of the two that match as possible. + */ + +int find_path_info (char *uri, char *path_info) +{ + int lu = strlen(uri); + int lp = strlen(path_info); + + while (lu-- && lp-- && uri[lu] == path_info[lp]); + + if (lu == -1) + lu=0; + + while (uri[lu] != '\0' && uri[lu] != '/') + lu++; + + return lu; +} + +/* Obtain the Request-URI from the original request-line, returning + * a new string from the request pool containing the URI or "". + */ +static char *original_uri(request_rec *r) +{ + char *first, *last; + + if (r->the_request == NULL) + return (char *)pcalloc(r->pool, 1); + + first = r->the_request; /* use the request-line */ + + while (*first && !isspace(*first)) ++first; /* skip over the method */ + while (isspace(*first)) ++first; /* and the space(s) */ + + last = first; + while (*last && !isspace(*last)) ++last; /* end at next whitespace */ + + return pstrndup(r->pool, first, last - first); +} + +void add_cgi_vars(request_rec *r) +{ + table *e = r->subprocess_env; + + table_set (e, "GATEWAY_INTERFACE","CGI/1.1"); + table_set (e, "SERVER_PROTOCOL", r->protocol); + table_set (e, "REQUEST_METHOD", r->method); + table_set (e, "QUERY_STRING", r->args ? r->args : ""); + table_set (e, "REQUEST_URI", original_uri(r)); + + /* Note that the code below special-cases scripts run from includes, + * because it "knows" that the sub_request has been hacked to have the + * args and path_info of the original request, and not any that may have + * come with the script URI in the include command. Ugh. + */ + + if (!strcmp (r->protocol, "INCLUDED")) { + table_set (e, "SCRIPT_NAME", r->uri); + if (r->path_info && *r->path_info) + table_set (e, "PATH_INFO", r->path_info); + } else if (!r->path_info || !*r->path_info) { + table_set (e, "SCRIPT_NAME", r->uri); + } else { + int path_info_start = find_path_info (r->uri, r->path_info); + + table_set (e, "SCRIPT_NAME", pstrndup(r->pool, r->uri, + path_info_start)); + + table_set (e, "PATH_INFO", r->path_info); + } + + if (r->path_info && r->path_info[0]) { + /* + * To get PATH_TRANSLATED, treat PATH_INFO as a URI path. + * Need to re-escape it for this, since the entire URI was + * un-escaped before we determined where the PATH_INFO began. + */ + request_rec *pa_req = sub_req_lookup_uri( + escape_uri(r->pool, r->path_info), r); + + /* Don't bother destroying pa_req --- it's only created in + * child processes which are about to jettison their address + * space anyway. BTW, we concatenate filename and path_info + * from the sub_request to be compatible in case the PATH_INFO + * is pointing to an object which doesn't exist. + */ + + if (pa_req->filename) + table_set (e, "PATH_TRANSLATED", + pstrcat (r->pool, pa_req->filename, pa_req->path_info, + NULL)); + } +} + +int scan_script_header_err(request_rec *r, FILE *f, char *buffer) +{ + char x[MAX_STRING_LEN]; + char *w, *l; + int p; + + if (buffer) *buffer = '\0'; + w = buffer ? buffer : x; + + hard_timeout ("read script header", r); + + while(1) { + + if (fgets(w, MAX_STRING_LEN-1, f) == NULL) { + kill_timeout (r); + log_reason ("Premature end of script headers", r->filename, r); + return SERVER_ERROR; + } + + /* Delete terminal (CR?)LF */ + + p = strlen(w); + if (p > 0 && w[p-1] == '\n') + { + if (p > 1 && w[p-2] == '\015') w[p-2] = '\0'; + else w[p-1] = '\0'; + } + + if(w[0] == '\0') { + kill_timeout (r); + return OK; + } + + /* if we see a bogus header don't ignore it. Shout and scream */ + + if(!(l = strchr(w,':'))) { + char malformed[(sizeof MALFORMED_MESSAGE)+1+MALFORMED_HEADER_LENGTH_TO_SHOW]; + strcpy(malformed, MALFORMED_MESSAGE); + strncat(malformed, w, MALFORMED_HEADER_LENGTH_TO_SHOW); + + if (!buffer) + /* Soak up all the script output --- may save an outright kill */ + while (fgets(w, MAX_STRING_LEN-1, f) != NULL) + continue; + + kill_timeout (r); + log_reason (malformed, r->filename, r); + return SERVER_ERROR; + } + + *l++ = '\0'; + while (*l && isspace (*l)) ++l; + + if(!strcasecmp(w,"Content-type")) { + + /* Nuke trailing whitespace */ + + char *endp = l + strlen(l) - 1; + while (endp > l && isspace(*endp)) *endp-- = '\0'; + + r->content_type = pstrdup (r->pool, l); + } + else if(!strcasecmp(w,"Status")) { + sscanf(l, "%d", &r->status); + r->status_line = pstrdup(r->pool, l); + } + else if(!strcasecmp(w,"Location")) { + table_set (r->headers_out, w, l); + } + else if(!strcasecmp(w,"Content-Length")) { + table_set (r->headers_out, w, l); + } + else if(!strcasecmp(w,"Transfer-Encoding")) { + table_set (r->headers_out, w, l); + } + +/* The HTTP specification says that it is legal to merge duplicate + * headers into one. Some browsers that support Cookies don't like + * merged headers and prefer that each Set-Cookie header is sent + * separately. Lets humour those browsers. + */ + else if(!strcasecmp(w, "Set-Cookie")) { + table_add(r->err_headers_out, w, l); + } + else { + table_merge (r->err_headers_out, w, l); + } + } +} + +void send_size(size_t size, request_rec *r) { + char ss[20]; + + if(size == -1) + strcpy(ss, " -"); + else if(!size) + strcpy(ss, " 0k"); + else if(size < 1024) + strcpy(ss, " 1k"); + else if(size < 1048576) + ap_snprintf(ss, sizeof(ss), "%4dk", (size + 512) / 1024); + else if(size < 103809024) + ap_snprintf(ss, sizeof(ss), "%4.1fM", size / 1048576.0); + else + ap_snprintf(ss, sizeof(ss), "%4dM", (size + 524288) / 1048576); + rputs(ss, r); +} + +#ifdef __EMX__ +static char **create_argv_cmd(pool *p, char *av0, const char *args, char *path) +{ + register int x,n; + char **av; + char *w; + + for(x=0,n=2;args[x];x++) + if(args[x] == '+') ++n; + + /* Add extra strings to array. */ + n = n + 2; + + av = (char **)palloc(p, (n+1)*sizeof(char *)); + av[0] = av0; + + /* Now insert the extra strings we made room for above. */ + av[1] = strdup("/C"); + av[2] = strdup(path); + + for(x=(1+2);xper_dir_config, &core_module); + +#endif + + /* the fd on r->server->error_log is closed, but we need somewhere to + * put the error messages from the log_* functions. So, we use stderr, + * since that is better than allowing errors to go unnoticed. + */ + r->server->error_log = stderr; + +#ifdef RLIMIT_CPU + if (conf->limit_cpu != NULL) + if ((setrlimit (RLIMIT_CPU, conf->limit_cpu)) != 0) + log_unixerr("setrlimit", NULL, "failed to set CPU usage limit", + r->server); +#endif +#ifdef RLIMIT_NPROC + if (conf->limit_nproc != NULL) + if ((setrlimit (RLIMIT_NPROC, conf->limit_nproc)) != 0) + log_unixerr("setrlimit", NULL, "failed to set process limit", + r->server); +#endif +#ifdef RLIMIT_DATA + if (conf->limit_mem != NULL) + if ((setrlimit (RLIMIT_DATA, conf->limit_mem)) != 0) + log_unixerr("setrlimit", NULL, "failed to set memory usage limit", + r->server); +#endif +#ifdef RLIMIT_VMEM + if (conf->limit_mem != NULL) + if ((setrlimit (RLIMIT_VMEM, conf->limit_mem)) != 0) + log_unixerr("setrlimit", NULL, "failed to set memory usage limit", + r->server); +#endif + +#ifdef __EMX__ + { + /* Additions by Alec Kloss, to allow exec'ing of scripts under OS/2 */ + int is_script; + char interpreter[2048]; /* hope this is large enough for the interpreter path */ + FILE * program; + program = fopen (r->filename, "r"); + if (!program) { + char err_string[HUGE_STRING_LEN]; + ap_snprintf(err_string, sizeof(err_string), "open of %s failed, errno is %d\n", r->filename, errno); + /* write(2, err_string, strlen(err_string)); */ + /* exit(0); */ + log_unixerr("fopen", NULL, err_string, r->server); + return; + } + fgets (interpreter, 2048, program); + fclose (program); + if (!strncmp (interpreter, "#!", 2)) { + is_script = 1; + interpreter[strlen(interpreter)-1] = '\0'; + } else { + is_script = 0; + } + + if ((!r->args) || (!r->args[0]) || (ind(r->args,'=') >= 0)) { + int emxloop; + char *emxtemp; + + /* For OS/2 place the variables in the current + enviornment then it will be inherited. This way + the program will also get all of OS/2's other SETs. */ + for (emxloop=0; ((emxtemp = env[emxloop]) != NULL); emxloop++) + putenv(emxtemp); + + /* Additions by Alec Kloss, to allow exec'ing of scripts under OS/2 */ + if (is_script) { + /* here's the stuff to run the interpreter */ + execl (interpreter+2, interpreter+2, r->filename, NULL); + } else + + if (strstr(strupr(r->filename), ".CMD") > 0) { + /* Special case to allow use of REXX commands as scripts. */ + os2pathname(r->filename); + execl("CMD.EXE", "CMD.EXE", "/C", r->filename, NULL); + } + else { + execl(r->filename, argv0, NULL); + } + } + else { + int emxloop; + char *emxtemp; + + /* For OS/2 place the variables in the current + environment so that they will be inherited. This way + the program will also get all of OS/2's other SETs. */ + for (emxloop=0; ((emxtemp = env[emxloop]) != NULL); emxloop++) + putenv(emxtemp); + + if (strstr(strupr(r->filename), ".CMD") > 0) { + /* Special case to allow use of REXX commands as scripts. */ + os2pathname(r->filename); + execv("CMD.EXE", create_argv_cmd(r->pool, argv0, r->args, r->filename)); + } + else + execv(r->filename, + create_argv(r->pool, NULL, NULL, NULL, argv0, r->args)); + } + } +#else + if ( suexec_enabled && + ((r->server->server_uid != user_id) || + (r->server->server_gid != group_id) || + (!strncmp("/~",r->uri,2))) ) { + + char *execuser, *grpname; + struct passwd *pw; + struct group *gr; + + if (!strncmp("/~",r->uri,2)) { + gid_t user_gid; + char *username = pstrdup(r->pool, r->uri + 2); + int pos = ind(username, '/'); + + if (pos >= 0) username[pos] = '\0'; + + if ((pw = getpwnam(username)) == NULL) { + log_unixerr("getpwnam",username,"invalid username",r->server); + return; + } + execuser = pstrcat(r->pool, "~", pw->pw_name, NULL); + user_gid = pw->pw_gid; + + if ((gr = getgrgid(user_gid)) == NULL) { + if ((grpname = palloc (r->pool, 16)) == NULL) + return; + else + ap_snprintf(grpname, 16, "%d", user_gid); + } + else + grpname = gr->gr_name; + } + else { + if ((pw = getpwuid (r->server->server_uid)) == NULL) { + log_unixerr("getpwuid", NULL, "invalid userid", r->server); + return; + } + execuser = pstrdup(r->pool, pw->pw_name); + + if ((gr = getgrgid (r->server->server_gid)) == NULL) { + log_unixerr("getgrgid", NULL, "invalid groupid", r->server); + return; + } + grpname = gr->gr_name; + } + + if (shellcmd) + execle(SUEXEC_BIN, SUEXEC_BIN, execuser, grpname, argv0, NULL, env); + + else if((!r->args) || (!r->args[0]) || (ind(r->args,'=') >= 0)) + execle(SUEXEC_BIN, SUEXEC_BIN, execuser, grpname, argv0, NULL, env); + + else { + execve(SUEXEC_BIN, + create_argv(r->pool, SUEXEC_BIN, execuser, grpname, + argv0, r->args), + env); + } + } + else { + if (shellcmd) + execle(SHELL_PATH, SHELL_PATH, "-c", argv0, NULL, env); + + else if((!r->args) || (!r->args[0]) || (ind(r->args,'=') >= 0)) + execle(r->filename, argv0, NULL, env); + + else + execve(r->filename, + create_argv(r->pool, NULL, NULL, NULL, argv0, r->args), + env); + } +#endif +} diff --git a/APACHE_1_2_X/src/main/util_snprintf.c b/APACHE_1_2_X/src/main/util_snprintf.c new file mode 100644 index 00000000000..d37c634f753 --- /dev/null +++ b/APACHE_1_2_X/src/main/util_snprintf.c @@ -0,0 +1,949 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + * This code is based on, and used with the permission of, the + * SIO stdio-replacement strx_* functions by Panos Tsirigotis + * for xinetd. + */ + +#include "conf.h" + +#ifndef HAVE_SNPRINTF + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CVT + +# define ap_ecvt ecvt +# define ap_fcvt fcvt +# define ap_gcvt gcvt + +#else + +/* + * cvt.c - IEEE floating point formatting routines for FreeBSD + * from GNU libc-4.6.27 + */ + +/* + * ap_ecvt converts to decimal + * the number of digits is specified by ndigit + * decpt is set to the position of the decimal point + * sign is set to 0 for positive, 1 for negative + */ + +#define NDIG 80 + +static char * + ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag) +{ + register int r2; + double fi, fj; + register char *p, *p1; + static char buf[NDIG]; + + if (ndigits >= NDIG - 1) + ndigits = NDIG - 2; + r2 = 0; + *sign = 0; + p = &buf[0]; + if (arg < 0) { + *sign = 1; + arg = -arg; + } + arg = modf(arg, &fi); + p1 = &buf[NDIG]; + /* + * Do integer part + */ + if (fi != 0) { + p1 = &buf[NDIG]; + while (fi != 0) { + fj = modf(fi / 10, &fi); + *--p1 = (int) ((fj + .03) * 10) + '0'; + r2++; + } + while (p1 < &buf[NDIG]) + *p++ = *p1++; + } + else if (arg > 0) { + while ((fj = arg * 10) < 1) { + arg = fj; + r2--; + } + } + p1 = &buf[ndigits]; + if (eflag == 0) + p1 += r2; + *decpt = r2; + if (p1 < &buf[0]) { + buf[0] = '\0'; + return (buf); + } + while (p <= p1 && p < &buf[NDIG]) { + arg *= 10; + arg = modf(arg, &fj); + *p++ = (int) fj + '0'; + } + if (p1 >= &buf[NDIG]) { + buf[NDIG - 1] = '\0'; + return (buf); + } + p = p1; + *p1 += 5; + while (*p1 > '9') { + *p1 = '0'; + if (p1 > buf) + ++ * --p1; + else { + *p1 = '1'; + (*decpt)++; + if (eflag == 0) { + if (p > buf) + *p = '0'; + p++; + } + } + } + *p = '\0'; + return (buf); +} + +static char * + ap_ecvt(double arg, int ndigits, int *decpt, int *sign) +{ + return (ap_cvt(arg, ndigits, decpt, sign, 1)); +} + +static char * + ap_fcvt(double arg, int ndigits, int *decpt, int *sign) +{ + return (ap_cvt(arg, ndigits, decpt, sign, 0)); +} + +/* + * ap_gcvt - Floating output conversion to + * minimal length string + */ + +static char * + ap_gcvt(double number, int ndigit, char *buf) +{ + int sign, decpt; + register char *p1, *p2; + register i; + + p1 = ap_ecvt(number, ndigit, &decpt, &sign); + p2 = buf; + if (sign) + *p2++ = '-'; + for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--) + ndigit--; + if ((decpt >= 0 && decpt - ndigit > 4) + || (decpt < 0 && decpt < -3)) { /* use E-style */ + decpt--; + *p2++ = *p1++; + *p2++ = '.'; + for (i = 1; i < ndigit; i++) + *p2++ = *p1++; + *p2++ = 'e'; + if (decpt < 0) { + decpt = -decpt; + *p2++ = '-'; + } + else + *p2++ = '+'; + if (decpt / 100 > 0) + *p2++ = decpt / 100 + '0'; + if (decpt / 10 > 0) + *p2++ = (decpt % 100) / 10 + '0'; + *p2++ = decpt % 10 + '0'; + } + else { + if (decpt <= 0) { + if (*p1 != '0') + *p2++ = '.'; + while (decpt < 0) { + decpt++; + *p2++ = '0'; + } + } + for (i = 1; i <= ndigit; i++) { + *p2++ = *p1++; + if (i == decpt) + *p2++ = '.'; + } + if (ndigit < decpt) { + while (ndigit++ < decpt) + *p2++ = '0'; + *p2++ = '.'; + } + } + if (p2[-1] == '.') + p2--; + *p2 = '\0'; + return (buf); +} + +#endif /* HAVE_CVT */ + +typedef enum { + NO = 0, YES = 1 +} boolean_e; + +#define FALSE 0 +#define TRUE 1 +#define NUL '\0' +#define INT_NULL ((int *)0) +#define WIDE_INT long + +typedef WIDE_INT wide_int; +typedef unsigned WIDE_INT u_wide_int; +typedef int bool_int; + +#define S_NULL "(null)" +#define S_NULL_LEN 6 + +#define FLOAT_DIGITS 6 +#define EXPONENT_LENGTH 10 + +/* + * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions + * + * XXX: this is a magic number; do not decrease it + */ +#define NUM_BUF_SIZE 512 + + +/* + * Descriptor for buffer area + */ +struct buf_area { + char *buf_end; + char *nextb; /* pointer to next byte to read/write */ +}; + +typedef struct buf_area buffy; + +/* + * The INS_CHAR macro inserts a character in the buffer and writes + * the buffer back to disk if necessary + * It uses the char pointers sp and bep: + * sp points to the next available character in the buffer + * bep points to the end-of-buffer+1 + * While using this macro, note that the nextb pointer is NOT updated. + * + * NOTE: Evaluation of the c argument should not have any side-effects + */ +#define INS_CHAR( c, sp, bep, cc ) \ + { \ + if ( sp < bep ) \ + { \ + *sp++ = c ; \ + cc++ ; \ + } \ + } + +#define NUM( c ) ( c - '0' ) + +#define STR_TO_DEC( str, num ) \ + num = NUM( *str++ ) ; \ + while ( isdigit( *str ) ) \ + { \ + num *= 10 ; \ + num += NUM( *str++ ) ; \ + } + +/* + * This macro does zero padding so that the precision + * requirement is satisfied. The padding is done by + * adding '0's to the left of the string that is going + * to be printed. + */ +#define FIX_PRECISION( adjust, precision, s, s_len ) \ + if ( adjust ) \ + while ( s_len < precision ) \ + { \ + *--s = '0' ; \ + s_len++ ; \ + } + +/* + * Macro that does padding. The padding is done by printing + * the character ch. + */ +#define PAD( width, len, ch ) do \ + { \ + INS_CHAR( ch, sp, bep, cc ) ; \ + width-- ; \ + } \ + while ( width > len ) + +/* + * Prefix the character ch to the string str + * Increase length + * Set the has_prefix flag + */ +#define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YES + + +/* + * Convert num to its decimal format. + * Return value: + * - a pointer to a string containing the number (no sign) + * - len contains the length of the string + * - is_negative is set to TRUE or FALSE depending on the sign + * of the number (always set to FALSE if is_unsigned is TRUE) + * + * The caller provides a buffer for the string: that is the buf_end argument + * which is a pointer to the END of the buffer + 1 (i.e. if the buffer + * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) + */ +static char * + conv_10(register wide_int num, register bool_int is_unsigned, + register bool_int * is_negative, char *buf_end, register int *len) +{ + register char *p = buf_end; + register u_wide_int magnitude; + + if (is_unsigned) { + magnitude = (u_wide_int) num; + *is_negative = FALSE; + } + else { + *is_negative = (num < 0); + + /* + * On a 2's complement machine, negating the most negative integer + * results in a number that cannot be represented as a signed integer. + * Here is what we do to obtain the number's magnitude: + * a. add 1 to the number + * b. negate it (becomes positive) + * c. convert it to unsigned + * d. add 1 + */ + if (*is_negative) { + wide_int t = num + 1; + + magnitude = ((u_wide_int) - t) + 1; + } + else + magnitude = (u_wide_int) num; + } + + /* + * We use a do-while loop so that we write at least 1 digit + */ + do { + register u_wide_int new_magnitude = magnitude / 10; + + *--p = magnitude - new_magnitude * 10 + '0'; + magnitude = new_magnitude; + } + while (magnitude); + + *len = buf_end - p; + return (p); +} + + + +/* + * Convert a floating point number to a string formats 'f', 'e' or 'E'. + * The result is placed in buf, and len denotes the length of the string + * The sign is returned in the is_negative argument (and is not placed + * in buf). + */ +static char * + conv_fp(register char format, register double num, +boolean_e add_dp, int precision, bool_int * is_negative, char *buf, int *len) +{ + register char *s = buf; + register char *p; + int decimal_point; + + if (format == 'f') + p = ap_fcvt(num, precision, &decimal_point, is_negative); + else /* either e or E format */ + p = ap_ecvt(num, precision + 1, &decimal_point, is_negative); + + /* + * Check for Infinity and NaN + */ + if (isalpha(*p)) { + *len = strlen(strcpy(buf, p)); + *is_negative = FALSE; + return (buf); + } + + if (format == 'f') + if (decimal_point <= 0) { + *s++ = '0'; + if (precision > 0) { + *s++ = '.'; + while (decimal_point++ < 0) + *s++ = '0'; + } + else if (add_dp) + *s++ = '.'; + } + else { + while (decimal_point-- > 0) + *s++ = *p++; + if (precision > 0 || add_dp) + *s++ = '.'; + } + else { + *s++ = *p++; + if (precision > 0 || add_dp) + *s++ = '.'; + } + + /* + * copy the rest of p, the NUL is NOT copied + */ + while (*p) + *s++ = *p++; + + if (format != 'f') { + char temp[EXPONENT_LENGTH]; /* for exponent conversion */ + int t_len; + bool_int exponent_is_negative; + + *s++ = format; /* either e or E */ + decimal_point--; + if (decimal_point != 0) { + p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative, + &temp[EXPONENT_LENGTH], &t_len); + *s++ = exponent_is_negative ? '-' : '+'; + + /* + * Make sure the exponent has at least 2 digits + */ + if (t_len == 1) + *s++ = '0'; + while (t_len--) + *s++ = *p++; + } + else { + *s++ = '+'; + *s++ = '0'; + *s++ = '0'; + } + } + + *len = s - buf; + return (buf); +} + + +/* + * Convert num to a base X number where X is a power of 2. nbits determines X. + * For example, if nbits is 3, we do base 8 conversion + * Return value: + * a pointer to a string containing the number + * + * The caller provides a buffer for the string: that is the buf_end argument + * which is a pointer to the END of the buffer + 1 (i.e. if the buffer + * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) + */ +static char * + conv_p2(register u_wide_int num, register int nbits, + char format, char *buf_end, register int *len) +{ + register int mask = (1 << nbits) - 1; + register char *p = buf_end; + static char low_digits[] = "0123456789abcdef"; + static char upper_digits[] = "0123456789ABCDEF"; + register char *digits = (format == 'X') ? upper_digits : low_digits; + + do { + *--p = digits[num & mask]; + num >>= nbits; + } + while (num); + + *len = buf_end - p; + return (p); +} + + +/* + * Do format conversion placing the output in buffer + */ +static int format_converter(register buffy * odp, const char *fmt, + va_list ap) +{ + register char *sp; + register char *bep; + register int cc = 0; + register int i; + + register char *s = NULL; + char *q; + int s_len; + + register int min_width = 0; + int precision = 0; + enum { + LEFT, RIGHT + } adjust; + char pad_char; + char prefix_char; + + double fp_num; + wide_int i_num = (wide_int) 0; + u_wide_int ui_num; + + char num_buf[NUM_BUF_SIZE]; + char char_buf[2]; /* for printing %% and % */ + + /* + * Flag variables + */ + boolean_e is_long; + boolean_e alternate_form; + boolean_e print_sign; + boolean_e print_blank; + boolean_e adjust_precision; + boolean_e adjust_width; + bool_int is_negative; + + sp = odp->nextb; + bep = odp->buf_end; + + while (*fmt) { + if (*fmt != '%') { + INS_CHAR(*fmt, sp, bep, cc); + } + else { + /* + * Default variable settings + */ + adjust = RIGHT; + alternate_form = print_sign = print_blank = NO; + pad_char = ' '; + prefix_char = NUL; + + fmt++; + + /* + * Try to avoid checking for flags, width or precision + */ + if (isascii(*fmt) && !islower(*fmt)) { + /* + * Recognize flags: -, #, BLANK, + + */ + for (;; fmt++) { + if (*fmt == '-') + adjust = LEFT; + else if (*fmt == '+') + print_sign = YES; + else if (*fmt == '#') + alternate_form = YES; + else if (*fmt == ' ') + print_blank = YES; + else if (*fmt == '0') + pad_char = '0'; + else + break; + } + + /* + * Check if a width was specified + */ + if (isdigit(*fmt)) { + STR_TO_DEC(fmt, min_width); + adjust_width = YES; + } + else if (*fmt == '*') { + min_width = va_arg(ap, int); + fmt++; + adjust_width = YES; + if (min_width < 0) { + adjust = LEFT; + min_width = -min_width; + } + } + else + adjust_width = NO; + + /* + * Check if a precision was specified + * + * XXX: an unreasonable amount of precision may be specified + * resulting in overflow of num_buf. Currently we + * ignore this possibility. + */ + if (*fmt == '.') { + adjust_precision = YES; + fmt++; + if (isdigit(*fmt)) { + STR_TO_DEC(fmt, precision); + } + else if (*fmt == '*') { + precision = va_arg(ap, int); + fmt++; + if (precision < 0) + precision = 0; + } + else + precision = 0; + } + else + adjust_precision = NO; + } + else + adjust_precision = adjust_width = NO; + + /* + * Modifier check + */ + if (*fmt == 'l') { + is_long = YES; + fmt++; + } + else + is_long = NO; + + /* + * Argument extraction and printing. + * First we determine the argument type. + * Then, we convert the argument to a string. + * On exit from the switch, s points to the string that + * must be printed, s_len has the length of the string + * The precision requirements, if any, are reflected in s_len. + * + * NOTE: pad_char may be set to '0' because of the 0 flag. + * It is reset to ' ' by non-numeric formats + */ + switch (*fmt) { + case 'u': + if (is_long) + i_num = va_arg(ap, u_wide_int); + else + i_num = (wide_int) va_arg(ap, unsigned int); + /* + * The rest also applies to other integer formats, so fall + * into that case. + */ + case 'd': + case 'i': + /* + * Get the arg if we haven't already. + */ + if ((*fmt) != 'u') { + if (is_long) + i_num = va_arg(ap, wide_int); + else + i_num = (wide_int) va_arg(ap, int); + }; + s = conv_10(i_num, (*fmt) == 'u', &is_negative, + &num_buf[NUM_BUF_SIZE], &s_len); + FIX_PRECISION(adjust_precision, precision, s, s_len); + + if (*fmt != 'u') { + if (is_negative) + prefix_char = '-'; + else if (print_sign) + prefix_char = '+'; + else if (print_blank) + prefix_char = ' '; + } + break; + + + case 'o': + if (is_long) + ui_num = va_arg(ap, u_wide_int); + else + ui_num = (u_wide_int) va_arg(ap, unsigned int); + s = conv_p2(ui_num, 3, *fmt, + &num_buf[NUM_BUF_SIZE], &s_len); + FIX_PRECISION(adjust_precision, precision, s, s_len); + if (alternate_form && *s != '0') { + *--s = '0'; + s_len++; + } + break; + + + case 'x': + case 'X': + if (is_long) + ui_num = (u_wide_int) va_arg(ap, u_wide_int); + else + ui_num = (u_wide_int) va_arg(ap, unsigned int); + s = conv_p2(ui_num, 4, *fmt, + &num_buf[NUM_BUF_SIZE], &s_len); + FIX_PRECISION(adjust_precision, precision, s, s_len); + if (alternate_form && i_num != 0) { + *--s = *fmt; /* 'x' or 'X' */ + *--s = '0'; + s_len += 2; + } + break; + + + case 's': + s = va_arg(ap, char *); + if (s != NULL) { + s_len = strlen(s); + if (adjust_precision && precision < s_len) + s_len = precision; + } + else { + s = S_NULL; + s_len = S_NULL_LEN; + } + pad_char = ' '; + break; + + + case 'f': + case 'e': + case 'E': + fp_num = va_arg(ap, double); + + s = conv_fp(*fmt, fp_num, alternate_form, + (adjust_precision == NO) ? FLOAT_DIGITS : precision, + &is_negative, &num_buf[1], &s_len); + if (is_negative) + prefix_char = '-'; + else if (print_sign) + prefix_char = '+'; + else if (print_blank) + prefix_char = ' '; + break; + + + case 'g': + case 'G': + if (adjust_precision == NO) + precision = FLOAT_DIGITS; + else if (precision == 0) + precision = 1; + /* + * * We use &num_buf[ 1 ], so that we have room for the sign + */ + s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1]); + if (*s == '-') + prefix_char = *s++; + else if (print_sign) + prefix_char = '+'; + else if (print_blank) + prefix_char = ' '; + + s_len = strlen(s); + + if (alternate_form && (q = strchr(s, '.')) == NULL) + s[s_len++] = '.'; + if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL) + *q = 'E'; + break; + + + case 'c': + char_buf[0] = (char) (va_arg(ap, int)); + s = &char_buf[0]; + s_len = 1; + pad_char = ' '; + break; + + + case '%': + char_buf[0] = '%'; + s = &char_buf[0]; + s_len = 1; + pad_char = ' '; + break; + + + case 'n': + *(va_arg(ap, int *)) = cc; + break; + + /* + * Always extract the argument as a "char *" pointer. We + * should be using "void *" but there are still machines + * that don't understand it. + * If the pointer size is equal to the size of an unsigned + * integer we convert the pointer to a hex number, otherwise + * we print "%p" to indicate that we don't handle "%p". + */ + case 'p': + ui_num = (u_wide_int) va_arg(ap, char *); + + if (sizeof(char *) <= sizeof(u_wide_int)) + s = conv_p2(ui_num, 4, 'x', + &num_buf[NUM_BUF_SIZE], &s_len); + else { + s = "%p"; + s_len = 2; + } + pad_char = ' '; + break; + + + case NUL: + /* + * The last character of the format string was %. + * We ignore it. + */ + continue; + + + /* + * The default case is for unrecognized %'s. + * We print % to help the user identify what + * option is not understood. + * This is also useful in case the user wants to pass + * the output of format_converter to another function + * that understands some other % (like syslog). + * Note that we can't point s inside fmt because the + * unknown could be preceded by width etc. + */ + default: + char_buf[0] = '%'; + char_buf[1] = *fmt; + s = char_buf; + s_len = 2; + pad_char = ' '; + break; + } + + if (prefix_char != NUL) { + *--s = prefix_char; + s_len++; + } + + if (adjust_width && adjust == RIGHT && min_width > s_len) { + if (pad_char == '0' && prefix_char != NUL) { + INS_CHAR(*s, sp, bep, cc) + s++; + s_len--; + min_width--; + } + PAD(min_width, s_len, pad_char); + } + + /* + * Print the string s. + */ + for (i = s_len; i != 0; i--) { + INS_CHAR(*s, sp, bep, cc); + s++; + } + + if (adjust_width && adjust == LEFT && min_width > s_len) + PAD(min_width, s_len, pad_char); + } + fmt++; + } + odp->nextb = sp; + return (cc); +} + + +/* + * This is the general purpose conversion function. + */ +static void strx_printv(int *ccp, char *buf, size_t len, const char *format, + va_list ap) +{ + buffy od; + int cc; + + /* + * First initialize the descriptor + * Notice that if no length is given, we initialize buf_end to the + * highest possible address. + */ + od.buf_end = len ? &buf[len] : (char *) ~0; + od.nextb = buf; + + /* + * Do the conversion + */ + cc = format_converter(&od, format, ap); + if (len == 0 || od.nextb <= od.buf_end) + *(od.nextb) = '\0'; + if (ccp) + *ccp = cc; +} + + +int ap_snprintf(char *buf, size_t len, const char *format,...) +{ + int cc; + va_list ap; + + va_start(ap, format); + strx_printv(&cc, buf, (len - 1), format, ap); + va_end(ap); + return (cc); +} + + +int ap_vsnprintf(char *buf, size_t len, const char *format, va_list ap) +{ + int cc; + + strx_printv(&cc, buf, (len - 1), format, ap); + return (cc); +} + +#endif /* HAVE_SNPRINTF */ diff --git a/APACHE_1_2_X/src/mod_browser.c b/APACHE_1_2_X/src/mod_browser.c new file mode 100644 index 00000000000..67cf99d5761 --- /dev/null +++ b/APACHE_1_2_X/src/mod_browser.c @@ -0,0 +1,189 @@ +/* ==================================================================== + * Copyright (c) 1996,1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * mod_browser.c + * Set environment variables based on browser support. + * + * Alexei Kosut + */ + +#include "httpd.h" +#include "http_config.h" + +typedef struct { + char *name; + regex_t *preg; + table *features; +} browser_entry; + +typedef struct { + array_header *browsers; +} browser_server_config_rec; + +module browser_module; + +void *create_browser_config (pool *p, server_rec *dummy) +{ + browser_server_config_rec *new = + (browser_server_config_rec *) palloc (p, sizeof(browser_server_config_rec)); + + new->browsers = make_array (p, 20, sizeof(browser_entry)); + return (void *)new; +} + +void *merge_browser_config (pool *p, void *basev, void *overridesv) +{ + browser_server_config_rec *a = + pcalloc(p, sizeof(browser_server_config_rec)); + browser_server_config_rec *base = basev, *overrides = overridesv; + + a->browsers = append_arrays(p, base->browsers, overrides->browsers); + return a; +} + +const char *add_browser(cmd_parms *cmd, void *dummy, char *name, + const char *feature) +{ + browser_server_config_rec *sconf = + get_module_config (cmd->server->module_config, &browser_module); + browser_entry *new, *entries = (browser_entry *)sconf->browsers->elts; + char *var; + int i, cflags = (int)cmd->info; + + /* First, try to merge into an existing entry */ + + for (i = 0; i < sconf->browsers->nelts; ++i) { + browser_entry *b = &entries[i]; + if (!strcmp(b->name, name)) { + var = getword(cmd->pool, &feature, '='); + if (*feature) table_set(b->features, var, feature); + else if (*var == '!') table_set(b->features, var + 1, "!"); + else table_set(b->features, var, "1"); + return NULL; + } + } + + /* If none was found, create a new entry */ + + new = push_array(sconf->browsers); + new->name = name; + new->preg = pregcomp (cmd->pool, name, REG_EXTENDED|REG_NOSUB|cflags); + if (new->preg == NULL) { + return "Browser regex could not be compiled."; + } + new->features = make_table(cmd->pool, 5); + + var = getword(cmd->pool, &feature, '='); + if (*feature) table_set(new->features, var, feature); + else if (*var == '!') table_set(new->features, var + 1, "!"); + else table_set(new->features, var, "1"); + + return NULL; +} + +command_rec browser_module_cmds[] = { +{ "BrowserMatch", add_browser, (void*)0, + RSRC_CONF, ITERATE2, "A browser regex and a list of variables." }, +{ "BrowserMatchNoCase", add_browser, (void*)REG_ICASE, + RSRC_CONF, ITERATE2, "a browser regex and a list of variables." }, +{ NULL }, +}; + +int parse_headers_browser_module(request_rec *r) +{ + server_rec *s = r->server; + browser_server_config_rec *sconf = get_module_config (s->module_config, + &browser_module); + browser_entry *entries = (browser_entry *)sconf->browsers->elts; + table_entry *elts; + char *ua = table_get(r->headers_in, "User-Agent"); + int i, j; + + if (!ua) return DECLINED; + + for (i = 0; i < sconf->browsers->nelts; ++i) { + browser_entry *b = &entries[i]; + + if (!regexec(b->preg, ua, 0, NULL, 0)) { + elts = (table_entry *)b->features->elts; + + for (j = 0; j < b->features->nelts; ++j) { + if (!strcmp(elts[j].val, "!")) + table_unset(r->subprocess_env, elts[j].key); + else + table_set(r->subprocess_env, elts[j].key, elts[j].val); + } + } + } + + return OK; +} + +module browser_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + NULL, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + create_browser_config, /* server config */ + merge_browser_config, /* merge server configs */ + browser_module_cmds, /* command table */ + NULL, /* handlers */ + NULL, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* fixups */ + NULL, /* logger */ + parse_headers_browser_module /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/.cvsignore b/APACHE_1_2_X/src/modules/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/APACHE_1_2_X/src/modules/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/APACHE_1_2_X/src/modules/example/Makefile b/APACHE_1_2_X/src/modules/example/Makefile new file mode 100755 index 00000000000..9bec391a3bf --- /dev/null +++ b/APACHE_1_2_X/src/modules/example/Makefile @@ -0,0 +1,107 @@ +# ==================================================================== +# Copyright (c) 1995-1997 The Apache Group. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# 3. All advertising materials mentioning features or use of this +# software must display the following acknowledgment: +# "This product includes software developed by the Apache Group +# for use in the Apache HTTP server project (http://www.apache.org/)." +# +# 4. The names "Apache Server" and "Apache Group" must not be used to +# endorse or promote products derived from this software without +# prior written permission. +# +# 5. Redistributions of any form whatsoever must retain the following +# acknowledgment: +# "This product includes software developed by the Apache Group +# for use in the Apache HTTP server project (http://www.apache.org/)." +# +# THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY +# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR +# ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. +# ==================================================================== +# +# This software consists of voluntary contributions made by many +# individuals on behalf of the Apache Group and was originally based +# on public domain software written at the National Center for +# Supercomputing Applications, University of Illinois, Urbana-Champaign. +# For more information on the Apache Group and the Apache HTTP server +# project, please see . +# +# Makefile for the Apache example module +# + +# +# This normally lives in modules/example under the Apache source +# directory. If the depth or relationship changes, the following line +# may need to be changed. +# +INCDIR=../.. + +# +# Everything below this point should be invariant. +# +SHELL=/bin/sh + +# +# We inherit the definitions of CC, AUX_CFLAGS, and RANLIB from an +# upline make(1) call. +# +CFLAGS=-I$(INCDIR) $(AUX_CFLAGS) + +MODULES=mod_example.o +OBJS= \ + $(MODULES) + +# +# Now the rules saying how things are built. +# +.c.o: + $(CC) -c $(CFLAGS) $< + +all: $(OBJS) + +clean: + rm -f $(OBJS) + +# +# Finally, what depnds upon which, so make can figure out what it needs +# to do. +# + +# +# Make sure that things get rebuilt if the Makefiles are changed. +# +$(OBJS): \ + Makefile \ + $(INCDIR)/Makefile + +mod_example.o: \ + $(INCDIR)/httpd.h \ + $(INCDIR)/http_config.h \ + $(INCDIR)/http_core.h \ + $(INCDIR)/http_log.h \ + $(INCDIR)/http_main.h \ + $(INCDIR)/http_protocol.h \ + $(INCDIR)/util_script.h \ + mod_example.c diff --git a/APACHE_1_2_X/src/modules/example/README b/APACHE_1_2_X/src/modules/example/README new file mode 100644 index 00000000000..77abc097c00 --- /dev/null +++ b/APACHE_1_2_X/src/modules/example/README @@ -0,0 +1,53 @@ +README for Apache 1.2 Example Module +[April, 1997] + +The files in the src/modules/example directory under the Apache +distribution directory tree are provided as an example to those that +wish to write modules that use the Apache API. + +The main file is mod_example.c, which illustrates all the different +callback mechanisms and call syntaces. By no means does an add-on +module need to include routines for all of the callbacks - quite the +contrary! + +The example module is an actual working module. If you link it into +your server, enable the "example-handler" handler for a location, and then +browse to that location, you will see a display of some of the tracing +the example module did as the various callbacks were made. + +To include the example module in your server, follow the steps below: + + 1. Uncomment the "Module example_module" line near the bottom of + the src/Configuration file. If there isn't one, add it; it + should look like this: + + Module example_module modules/example/mod_example.o + + 2. Run the src/Configure script ("cd src; ./Configure"). This will + build the Makefile for the server itself, and update the + src/modules/Makefile for any additional modules you have + requested from beneath that subdirectory. + + 3. Make the server (run "make" in the src directory). + +To add another module of your own: + + A. mkdir src/modules/mymodule + B. cp src/modules/example/* src/modules/mymodule + C. Modify the files in the new directory + D. Follow steps [1] through [3] above, with appropriate changes. + +To activate the example module, include a block similar to the +following in your srm.conf file: + + + SetHandler example-handler + + +As an alternative, you can put the following into a .htaccess file and +then request the file "test.example" from that location: + + AddHandler example-handler .example + +After reloading/restarting your server, you should be able to browse +to this location and see the brief display mentioned earlier. diff --git a/APACHE_1_2_X/src/modules/example/mod_example.c b/APACHE_1_2_X/src/modules/example/mod_example.c new file mode 100644 index 00000000000..1aeda876d01 --- /dev/null +++ b/APACHE_1_2_X/src/modules/example/mod_example.c @@ -0,0 +1,1110 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * Apache example module. Provide demonstrations of how modules do things. + * + */ + +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_log.h" +#include "http_main.h" +#include "http_protocol.h" +#include "util_script.h" + +#include + +/*--------------------------------------------------------------------------*/ +/* */ +/* Data declarations. */ +/* */ +/* Here are the static cells and structure declarations private to our */ +/* module. */ +/* */ +/*--------------------------------------------------------------------------*/ + +/* + * Sample configuration record. Used for both per-directory and per-server + * configuration data. + * + * It's perfectly reasonable to have two different structures for the two + * different environments. The same command handlers will be called for + * both, though, so the handlers need to be able to tell them apart. One + * possibility is for both structures to start with an int which is zero for + * one and 1 for the other. + * + * Note that while the per-directory and per-server configuration records are + * available to most of the module handlers, they should be treated as + * READ-ONLY by all except the command and merge handlers. Sometimes handlers + * are handed a record that applies to the current location by implication or + * inheritance, and modifying it will change the rules for other locations. + */ +typedef struct example_config { + int cmode; /* Environment to which record applies (directory, */ + /* server, or combination). */ +#define CONFIG_MODE_SERVER 1 +#define CONFIG_MODE_DIRECTORY 2 +#define CONFIG_MODE_COMBO 3 /* Shouldn't ever happen. */ + int local; /* Boolean: was "Example" directive declared here? */ + int congenital; /* Boolean: did we inherit an "Example"? */ + char *trace; /* Pointer to trace string. */ + char *loc; /* Location to which this record applies. */ +} example_config; + +/* + * Let's set up a module-local static cell to point to the accreting callback + * trace. As each API callback is made to us, we'll tack on the particulars + * to whatever we've already recorded. To avoid massive memory bloat as + * directories are walked again and again, we record the routine/environment + * the first time (non-request context only), and ignore subsequent calls for + * the same routine/environment. + */ +static char *trace = NULL; +static table *static_calls_made = NULL; + +/* + * To avoid leaking memory from pools other than the per-request one, we + * allocate a module-private pool, and then use a sub-pool of that which gets + * freed each time we modify the trace. That way previous layers of trace + * data don't get lost. + */ +static pool *example_pool = NULL; +static pool *example_subpool = NULL; + +/* + * Declare ourselves so the configuration routines can find and know us. + * We'll fill it in at the end of the module. + */ +module example_module; + +/*--------------------------------------------------------------------------*/ +/* */ +/* The following pseudo-prototype declarations illustrate the parameters */ +/* passed to command handlers for the different types of directive */ +/* syntax. If an argument was specified in the directive definition */ +/* (look for "command_rec" below), it's available to the command handler */ +/* via the (void *) info field in the cmd_parms argument passed to the */ +/* handler (cmd->info for the examples below). */ +/* */ +/*--------------------------------------------------------------------------*/ + +/* + * Command handler for a NO_ARGS directive. + * + * static const char *handle_NO_ARGS + * (cmd_parms *cmd, void *mconfig); + */ + +/* + * Command handler for a RAW_ARGS directive. The "args" argument is the text + * of the commandline following the directive itself. + * + * static const char *handle_RAW_ARGS + * (cmd_parms *cmd, void *mconfig, const char *args); + */ + +/* + * Command handler for a TAKE1 directive. The single parameter is passed in + * "word1". + * + * static const char *handle_TAKE1 + * (cmd_parms *cmd, void *mconfig, char *word1); + */ + +/* + * Command handler for a TAKE2 directive. TAKE2 commands must always have + * exactly two arguments. + * + * static const char *handle_TAKE2 + * (cmd_parms *cmd, void *mconfig, char *word1, char *word2); + */ + +/* + * Command handler for a TAKE3 directive. Like TAKE2, these must have exactly + * three arguments, or the parser complains and doesn't bother calling us. + * + * static const char *handle_TAKE3 + * (cmd_parms *cmd, void *mconfig, char *word1, char *word2, char *word3); + */ + +/* + * Command handler for a TAKE12 directive. These can take either one or two + * arguments. + * - word2 is a NULL pointer if no second argument was specified. + * + * static const char *handle_TAKE12 + * (cmd_parms *cmd, void *mconfig, char *word1, char *word2); + */ + +/* + * Command handler for a TAKE123 directive. A TAKE123 directive can be given, + * as might be expected, one, two, or three arguments. + * - word2 is a NULL pointer if no second argument was specified. + * - word3 is a NULL pointer if no third argument was specified. + * + * static const char *handle_TAKE123 + * (cmd_parms *cmd, void *mconfig, char *word1, char *word2, char *word3); + */ + +/* + * Command handler for a TAKE13 directive. Either one or three arguments are + * permitted - no two-parameters-only syntax is allowed. + * - word2 and word3 are NULL pointers if only one argument was specified. + * + * static const char *handle_TAKE13 + * (cmd_parms *cmd, void *mconfig, char *word1, char *word2, char *word3); + */ + +/* + * Command handler for a TAKE23 directive. At least two and as many as three + * arguments must be specified. + * - word3 is a NULL pointer if no third argument was specified. + * + * static const char *handle_TAKE23 + * (cmd_parms *cmd, void *mconfig, char *word1, char *word2, char *word3); + */ + +/* + * Command handler for a ITERATE directive. + * - Handler is called once for each of n arguments given to the directive. + * - word1 points to each argument in turn. + * + * static const char *handle_ITERATE + * (cmd_parms *cmd, void *mconfig, char *word1); + */ + +/* + * Command handler for a ITERATE2 directive. + * - Handler is called once for each of the second and subsequent arguments + * given to the directive. + * - word1 is the same for each call for a particular directive instance (the + * first argument). + * - word2 points to each of the second and subsequent arguments in turn. + * + * static const char *handle_ITERATE2 + * (cmd_parms *cmd, void *mconfig, char *word1, char *word2); + */ + +/*--------------------------------------------------------------------------*/ +/* */ +/* These routines are strictly internal to this module, and support its */ +/* operation. They are not referenced by any external portion of the */ +/* server. */ +/* */ +/*--------------------------------------------------------------------------*/ + +/* + * Locate our directory configuration record for the current request. + */ +static example_config *our_dconfig + (request_rec *r) { + + return (example_config *) get_module_config + ( + r->per_dir_config, + &example_module + ); +} + +/* + * Locate our server configuration record for the specified server. + */ +static example_config *our_sconfig + (server_rec *s) { + + return (example_config *) get_module_config + ( + s->module_config, + &example_module + ); +} + +/* + * Likewise for our configuration record for the specified request. + */ +static example_config *our_rconfig + (request_rec *r) { + + return (example_config *) get_module_config + ( + r->request_config, + &example_module + ); +} + +/* + * This routine sets up some module-wide cells if they haven't been already. + */ +static void setup_module_cells () { + /* + * If we haven't already allocated our module-private pool, do so now. + */ + if (example_pool == NULL) { + example_pool = make_sub_pool (NULL); + }; + /* + * Likewise for the table of routine/environment pairs we visit outside of + * request context. + */ + if (static_calls_made == NULL) { + static_calls_made = make_table (example_pool, 16); + }; +} + +/* + * This routine is used to add a trace of a callback to the list. We're + * passed the server record (if available), the request record (if available), + * a pointer to our private configuration record (if available) for the + * environment to which the callback is supposed to apply, and some text. We + * turn this into a textual representation and add it to the tail of the list. + * The list can be displayed by the example_handler() routine. + * + * If the call occurs within a request context (i.e., we're passed a request + * record), we put the trace into the request pool and attach it to the + * request via the notes mechanism. Otherwise, the trace gets added + * to the static (non-request-specific) list. + * + * Note that the r->notes table is only for storing strings; if you need to + * maintain per-request data of any other type, you need to use another + * mechanism. + */ + +#define TRACE_NOTE "example-trace" + +static void trace_add + (server_rec *s, request_rec *r, example_config *mconfig, + const char *note) { + + char *sofar; + char *addon; + char *where; + pool *p; + char *trace_copy; + example_config + *rconfig; + + /* + * Make sure our pools and tables are set up - we need 'em. + */ + setup_module_cells (); + /* + * Now, if we're in request-context, we use the request pool. + */ + if (r != NULL) { + p = r->pool; + if ((trace_copy = table_get (r->notes, TRACE_NOTE)) == NULL) { + trace_copy = ""; + } + } else { + /* + * We're not in request context, so the trace gets attached to our + * module-wide pool. We do the create/destroy every time we're called + * in non-request context; this avoids leaking memory in some of + * the subsequent calls that allocate memory only once (such as the + * key formation below). + * + * Make a new sub-pool and copy any existing trace to it. Point the + * trace cell at the copied value. + */ + p = make_sub_pool (example_pool); + if (trace != NULL) { + trace = pstrdup (p, trace); + } + /* + * Now, if we have a sub-pool from before, nuke it and replace with + * the one we just allocated. + */ + if (example_subpool != NULL) { + destroy_pool (example_subpool); + } + example_subpool = p; + trace_copy = trace; + } + /* + * If we weren't passed a configuration record, we can't figure out to + * what location this call applies. This only happens for co-routines + * that don't operate in a particular directory or server context. If we + * got a valid record, extract the location (directory or server) to which + * it applies. + */ + where = (mconfig != NULL) ? mconfig->loc : "nowhere"; + where = (where != NULL) ? where : ""; + /* + * Now, if we're not in request context, see if we've been called with + * this particular combination before. The table is allocated in the + * module's private pool, which doesn't get destroyed. + */ + if (r == NULL) { + char *key; + + key = pstrcat (p, note, ":", where, NULL); + if (table_get (static_calls_made, key) != NULL) { + /* + * Been here, done this. + */ + return; + } else { + /* + * First time for this combination of routine and environment - + * log it so we don't do it again. + */ + table_set (static_calls_made, key, "been here"); + } + } + addon = pstrcat + ( + p, + "
  • \n", + "
    \n", + "
    ", + note, + "\n", + "
    \n", + "
    [", + where, + "]\n", + "
    \n", + "
    \n", + "
  • \n", + NULL + ); + sofar = (trace_copy == NULL) ? "" : trace_copy; + trace_copy = pstrcat (p, sofar, addon, NULL); + if (r != NULL) { + table_set (r->notes, TRACE_NOTE, trace_copy); + } else { + trace = trace_copy; + } + /* + * You *could* uncomment the following if you wanted to see the calling + * sequence reported in the server's error_log, but beware - almost all of + * these co-routines are called for every single request, and the impact + * on the size (and readability) of the error_log is considerable. + */ +/* + if (s != NULL) { + log_printf (s, "mod_example: %s", note); + } + */ +} + +/*--------------------------------------------------------------------------*/ +/* We prototyped the various syntax for command handlers (routines that */ +/* are called when the configuration parser detects a directive declared */ +/* by our module) earlier. Now we actually declare a "real" routine that */ +/* will be invoked by the parser when our "real" directive is */ +/* encountered. */ +/* */ +/* If a command handler encounters a problem processing the directive, it */ +/* signals this fact by returning a non-NULL pointer to a string */ +/* describing the problem. */ +/* */ +/* The magic return value DECLINE_CMD is used to deal with directives */ +/* that might be declared by multiple modules. If the command handler */ +/* returns NULL, the directive was processed; if it returns DECLINE_CMD, */ +/* the next module (if any) that declares the directive is given a chance */ +/* at it. If it returns any other value, it's treated as the text of an */ +/* error message. */ +/*--------------------------------------------------------------------------*/ +/* + * Command handler for the NO_ARGS "Example" directive. All we do is mark the + * call in the trace log, and flag the applicability of the directive to the + * current location in that location's configuration record. + */ +static const char *cmd_example + (cmd_parms *cmd, void *mconfig) { + + example_config + *cfg = (example_config *) mconfig; + + /* + * "Example Wuz Here" + */ + cfg->local = 1; + trace_add (cmd->server, NULL, cfg, "cmd_example()"); + return NULL; +} + +/*--------------------------------------------------------------------------*/ +/* */ +/* Now we declare our content handlers, which are invoked when the server */ +/* encounters a document which our module is supposed to have a chance to */ +/* see. (See mod_mime's SetHandler and AddHandler directives, and the */ +/* mod_info and mod_status examples, for more details.) */ +/* */ +/* Since content handlers are dumping data directly into the connexion */ +/* (using the r*() routines, such as rputs() and rprintf()) without */ +/* intervention by other parts of the server, they need to make */ +/* sure any accumulated HTTP headers are sent first. This is done by */ +/* calling send_http_header(). Otherwise, no header will be sent at all, */ +/* and the output sent to the client will actually be HTTP-uncompliant. */ +/*--------------------------------------------------------------------------*/ +/* + * Sample content handler. All this does is display the call list that has + * been built up so far. + * + * The return value instructs the caller concerning what happened and what to + * do next: + * OK ("we did our thing") + * DECLINED ("this isn't something with which we want to get involved") + * HTTP_mumble ("an error status should be reported") + */ +static int example_handler + (request_rec *r) { + + example_config + *dcfg; + example_config + *rcfg; + + dcfg = our_dconfig (r); + trace_add (r->server, r, dcfg, "example_handler()"); + /* + * We're about to start sending content, so we need to force the HTTP + * headers to be sent at this point. Otherwise, no headers will be sent + * at all. We can set any we like first, of course. **NOTE** Here's + * where you set the "Content-type" header, and you do so by putting it in + * r->content_type, *not* r->headers_out("Content-type"). If you don't + * set it, it will be filled in with the server's default type (typically + * "text/plain"). + * + * We also need to start a timer so the server can know if the connexion + * is broken. + */ + r->content_type = "text/html"; + soft_timeout ("send example call trace", r); + send_http_header (r); + /* + * If we're only supposed to send header information (HEAD request), we're + * already there. + */ + if (r->header_only) { + kill_timeout (r); + return OK; + } + + /* + * Now send our actual output. Since we tagged this as being + * "text/html", we need to embed any HTML. + */ + rputs ("\n", r); + rputs ("\n", r); + rputs (" \n", r); + rputs (" mod_example Module Content-Handler Output\n", r); + rputs (" \n", r); + rputs (" \n", r); + rputs (" \n", r); + rputs ("

    mod_example Module Content-Handler Output\n", r); + rputs ("

    \n", r); + rputs ("

    \n", r); + rputs (" The format for the callback trace is:\n", r); + rputs ("

    \n", r); + rputs ("
    \n", r); + rputs ("
    n.<routine-name>", r); + rputs ("(<routine-data>)\n", r); + rputs ("
    \n", r); + rputs ("
    [<applies-to>]\n", r); + rputs ("
    \n", r); + rputs ("
    \n", r); + rputs ("

    \n", r); + rputs (" The <routine-data> is supplied by\n", r); + rputs (" the routine when it requests the trace,\n", r); + rputs (" and the <applies-to> is extracted\n", r); + rputs (" from the configuration record at the time of the trace.\n", r); + rputs (" SVR() indicates a server environment\n", r); + rputs (" (blank means the main or default server, otherwise it's\n", r); + rputs (" the name of the VirtualHost); DIR()\n", r); + rputs (" indicates a location in the URL or filesystem\n", r); + rputs (" namespace.\n", r); + rputs ("

    \n", r); + rprintf + ( + r, + "

    Static callbacks so far:

    \n
      \n%s
    \n", + trace + ); + rprintf + ( + r, + "

    Request-specific callbacks so far:

    \n
      \n%s
    \n", + table_get (r->notes, TRACE_NOTE) + ); + rputs ("

    Environment for this call:

    \n", r); + rputs ("
      \n", r); + rprintf (r, "
    • Applies-to: %s\n
    • \n", dcfg->loc); + rprintf + ( + r, + "
    • \"Example\" directive declared here: %s\n
    • \n", + (dcfg->local ? "YES" : "NO") + ); + rprintf + ( + r, + "
    • \"Example\" inherited: %s\n
    • \n", + (dcfg->congenital ? "YES" : "NO") + ); + rputs ("
    \n", r); + rputs (" \n", r); + rputs ("\n", r); + /* + * We're all done, so cancel the timeout we set. Since this is probably + * the end of the request we *could* assume this would be done during + * post-processing - but it's possible that another handler might be + * called and inherit our outstanding timer. Not good; to each its own. + */ + kill_timeout (r); + /* + * We did what we wanted to do, so tell the rest of the server we + * succeeded. + */ + return OK; +} + +/*--------------------------------------------------------------------------*/ +/* */ +/* Now let's declare routines for each of the callback phase in order. */ +/* (That's the order in which they're listed in the callback list, *not */ +/* the order in which the server calls them! See the command_rec */ +/* declaration near the bottom of this file.) Note that these may be */ +/* called for situations that don't relate primarily to our function - in */ +/* other words, the fixup handler shouldn't assume that the request has */ +/* to do with "example" stuff. */ +/* */ +/* With the exception of the content handler, all of our routines will be */ +/* called for each request, unless an earlier handler from another module */ +/* aborted the sequence. */ +/* */ +/* Handlers that are declared as "int" can return the following: */ +/* */ +/* OK Handler accepted the request and did its thing with it. */ +/* DECLINED Handler took no action. */ +/* HTTP_mumble Handler looked at request and found it wanting. */ +/* */ +/* What the server does after calling a module handler depends upon the */ +/* handler's return value. In all cases, if the handler returns */ +/* DECLINED, the server will continue to the next module with an handler */ +/* for the current phase. However, if the handler return a non-OK, */ +/* non-DECLINED status, the server aborts the request right there. If */ +/* the handler returns OK, the server's next action is phase-specific; */ +/* see the individual handler comments below for details. */ +/* */ +/*--------------------------------------------------------------------------*/ +/* + * This function is called during server initialisation. Any information + * that needs to be recorded must be in static cells, since there's no + * configuration record. + * + * There is no return value. + */ + +/* + * All our module-initialiser does is add its trace to the log. + */ +static void example_init + (server_rec *s, pool *p) { + + char *note; + char *sname = s->server_hostname; + + /* + * Set up any module cells that ought to be initialised. + */ + setup_module_cells (); + /* + * The arbitrary text we add to our trace entry indicates for which server + * we're being called. + */ + sname = (sname != NULL) ? sname : ""; + note = pstrcat (p, "example_init(", sname, ")", NULL); + trace_add (s, NULL, NULL, note); +} + +/* + * This function gets called to create up a per-directory configuration + * record. This will be called for the "default" server environment, and for + * each directory for which the parser finds any of our directives applicable. + * If a directory doesn't have any of our directives involved (i.e., they + * aren't in the .htaccess file, or a , , or related + * block), this routine will *not* be called - the configuration for the + * closest ancestor is used. + * + * The return value is a pointer to the created module-specific + * structure. + */ +static void *example_dir_create + (pool *p, char *dirspec) { + + example_config + *cfg; + char *dname = dirspec; + + /* + * Allocate the space for our record from the pool supplied. + */ + cfg = (example_config *) pcalloc (p, sizeof(example_config)); + /* + * Now fill in the defaults. If there are any `parent' configuration + * records, they'll get merged as part of a separate callback. + */ + cfg->local = 0; + cfg->congenital = 0; + cfg->cmode = CONFIG_MODE_DIRECTORY; + /* + * Finally, add our trace to the callback list. + */ + dname = (dname != NULL) ? dname : ""; + cfg->loc = pstrcat (p, "DIR(", dname, ")", NULL); + trace_add (NULL, NULL, cfg, "example_dir_create()"); + return (void *) cfg; +} + +/* + * This function gets called to merge two per-directory configuration + * records. This is typically done to cope with things like .htaccess files + * or directives for directories that are beneath one for which a + * configuration record was already created. The routine has the + * responsibility of creating a new record and merging the contents of the + * other two into it appropriately. If the module doesn't declare a merge + * routine, the record for the closest ancestor location (that has one) is + * used exclusively. + * + * The routine MUST NOT modify any of its arguments! + * + * The return value is a pointer to the created module-specific structure + * containing the merged values. + */ +static void *example_dir_merge + (pool *p, void *parent_conf, void *newloc_conf) { + + example_config + *merged_config = + (example_config *) pcalloc (p, sizeof(example_config)); + example_config + *pconf = (example_config *) parent_conf; + example_config + *nconf = (example_config *) newloc_conf; + char *note; + + /* + * Some things get copied directly from the more-specific record, rather + * than getting merged. + */ + merged_config->local = nconf->local; + merged_config->loc = pstrdup (p, nconf->loc); + /* + * Others, like the setting of the `congenital' flag, get ORed in. The + * setting of that particular flag, for instance, is TRUE if it was ever + * true anywhere in the upstream configuration. + */ + merged_config->congenital = (pconf->congenital | pconf->local); + /* + * If we're merging records for two different types of environment (server + * and directory), mark the new record appropriately. Otherwise, inherit + * the current value. + */ + merged_config->cmode = + (pconf->cmode == nconf->cmode) ? pconf->cmode : CONFIG_MODE_COMBO; + /* + * Now just record our being called in the trace list. Include the + * locations we were asked to merge. + */ + note = pstrcat + ( + p, + "example_dir_merge(\"", + pconf->loc, + "\",\"", + nconf->loc, + "\")", + NULL + ); + trace_add (NULL, NULL, merged_config, note); + return (void *) merged_config; +} + +/* + * This function gets called to create a per-server configuration + * record. It will always be called for the "default" server. + * + * The return value is a pointer to the created module-specific + * structure. + */ +static void *example_server_create + (pool *p, server_rec *s) { + + example_config + *cfg; + char *sname = s->server_hostname; + + /* + * As with the example_dir_create() reoutine, we allocate and fill in an + * empty record. + */ + cfg = (example_config *) pcalloc (p, sizeof(example_config)); + cfg->local = 0; + cfg->congenital = 0; + cfg->cmode = CONFIG_MODE_SERVER; + /* + * Note that we were called in the trace list. + */ + sname = (sname != NULL) ? sname : ""; + cfg->loc = pstrcat (p, "SVR(", sname, ")", NULL); + trace_add (s, NULL, cfg, "example_server_create()"); + return (void *) cfg; +} + +/* + * This function gets called to merge two per-server configuration + * records. This is typically done to cope with things like virtual hosts and + * the default server configuration The routine has the responsibility of + * creating a new record and merging the contents of the other two into it + * appropriately. If the module doesn't declare a merge routine, the more + * specific existing record is used exclusively. + * + * The routine MUST NOT modify any of its arguments! + * + * The return value is a pointer to the created module-specific structure + * containing the merged values. + */ +static void *example_server_merge + (pool *p, void *server1_conf, void *server2_conf) { + + example_config + *merged_config = + (example_config *) pcalloc (p, sizeof(example_config)); + example_config + *s1conf = (example_config *) server1_conf; + example_config + *s2conf = (example_config *) server2_conf; + char *note; + + /* + * Our inheritance rules are our own, and part of our module's semantics. + * Basically, just note whence we came. + */ + merged_config->cmode = + (s1conf->cmode == s2conf->cmode) ? s1conf->cmode : CONFIG_MODE_COMBO; + merged_config->local = s2conf->local; + merged_config->congenital = (s1conf->congenital | s1conf->local); + merged_config->loc = pstrdup (p, s2conf->loc); + /* + * Trace our call, including what we were asked to merge. + */ + note = pstrcat + ( + p, + "example_server_merge(\"", + s1conf->loc, + "\",\"", + s2conf->loc, + "\")", + NULL + ); + trace_add (NULL, NULL, merged_config, note); + return (void *) merged_config; +} + +/* + * This routine gives our module an opportunity to translate the URI into an + * actual filename. If we don't do anything special, the server's default + * rules (Alias directives and the like) will continue to be followed. + * + * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, no + * further modules are called for this phase. + */ +static int example_xlate + (request_rec *r) { + + example_config + *cfg; + + cfg = our_dconfig (r); + /* + * We don't actually *do* anything here, except note the fact that we were + * called. + */ + trace_add (r->server, r, cfg, "example_xlate()"); + return DECLINED; +} + +/* + * This routine is called to check the authentication information sent with + * the request (such as looking up the user in a database and verifying that + * the [encrypted] password sent matches the one in the database). + * + * The return value is OK, DECLINED, or some HTTP_mumble error (typically + * HTTP_UNAUTHORIZED). If we return OK, no other modules are given a chance + * at the request during this phase. + */ +static int example_ckuser + (request_rec *r) { + + example_config + *cfg; + + cfg = our_dconfig (r); + /* + * Don't do anything except log the call. + */ + trace_add (r->server, r, cfg, "example_ckuser()"); + return DECLINED; +} + +/* + * This routine is called to check to see if the resource being requested + * requires authorisation. + * + * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, no + * other modules are called during this phase. + * + * If *all* modules return DECLINED, the request is aborted with a server + * error. + */ +static int example_ckauth + (request_rec *r) { + + example_config + *cfg; + + cfg = our_dconfig (r); + /* + * Log the call and return OK, or access will be denied (even though we + * didn't actually do anything). + */ + trace_add (r->server, r, cfg, "example_ckauth()"); + return OK; +} + +/* + * This routine is called to check for any module-specific restrictions placed + * upon the requested resource. (See the mod_access module for an example.) + * + * The return value is OK, DECLINED, or HTTP_mumble. All modules with an + * handler for this phase are called regardless of whether their predecessors + * return OK or DECLINED. The first one to return any other status, however, + * will abort the sequence (and the request) as usual. + */ +static int example_ckaccess + (request_rec *r) { + + example_config + *cfg; + + cfg = our_dconfig (r); + trace_add (r->server, r, cfg, "example_ckaccess()"); + return OK; +} + +/* + * This routine is called to determine and/or set the various document type + * information bits, like Content-type (via r->content_type), language, et + * cetera. + * + * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, no + * further modules are given a chance at the request for this phase. + */ +static int example_typer + (request_rec *r) { + + example_config + *cfg; + + cfg = our_dconfig (r); + /* + * Log the call, but don't do anything else - and report truthfully that + * we didn't do anything. + */ + trace_add (r->server, r, cfg, "example_typer()"); + return DECLINED; +} + +/* + * This routine is called to perform any module-specific fixing of header + * fields, et cetera. It is invoked just before any content-handler. + * + * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, the + * server will still call any remaining modules with an handler for this + * phase. + */ +static int example_fixer + (request_rec *r) { + + example_config + *cfg; + + cfg = our_dconfig (r); + /* + * Log the call and exit. + */ + trace_add (r->server, r, cfg, "example_fixer()"); + return OK; +} + +/* + * This routine is called to perform any module-specific logging activities + * over and above the normal server things. + * + * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, any + * remaining modules with an handler for this phase will still be called. + */ +static int example_logger + (request_rec *r) { + + example_config + *cfg; + + cfg = our_dconfig (r); + trace_add (r->server, r, cfg, "example_logger()"); + return DECLINED; +} + +/* + * This routine is called to give the module a chance to look at the request + * headers and take any appropriate specific actions early in the processing + * sequence. + * + * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, any + * remaining modules with handlers for this phase will still be called. + */ +static int example_hparser + (request_rec *r) { + + example_config + *cfg; + + cfg = our_dconfig (r); + trace_add (r->server, r, cfg, "example_hparser()"); + return DECLINED; +} + +/*--------------------------------------------------------------------------*/ +/* */ +/* All of the routines have been declared now. Here's the list of */ +/* directives specific to our module, and information about where they */ +/* may appear and how the command parser should pass them to us for */ +/* processing. Note that care must be taken to ensure that there are NO */ +/* collisions of directive names between modules. */ +/* */ +/*--------------------------------------------------------------------------*/ +/* + * List of directives specific to our module. + */ +command_rec example_commands[] = { + { + "Example", /* directive name */ + cmd_example, /* action routine for directive */ + NULL, /* argument to include in call */ + OR_OPTIONS, /* where available */ + NO_ARGS, /* arguments */ + "Example directive - no arguments" + /* directive description */ + }, + { NULL } +}; + +/*--------------------------------------------------------------------------*/ +/* */ +/* Now the list of content handlers available from this module. */ +/* */ +/*--------------------------------------------------------------------------*/ +/* + * List of content handlers our module supplies. Each handler is defined by + * two parts: a name by which it can be referenced (such as by + * {Add,Set}Handler), and the actual routine name. The list is terminated by + * a NULL block, since it can be of variable length. + * + * Note that content-handlers are invoked on a most-specific to least-specific + * basis; that is, a handler that is declared for "text/plain" will be + * invoked before one that was declared for "text / *". Note also that + * if a content-handler returns anything except DECLINED, no other + * content-handlers will be called. + */ +handler_rec example_handlers[] = { + { "example-handler", example_handler }, + { NULL } +}; + +/*--------------------------------------------------------------------------*/ +/* */ +/* Finally, the list of callback routines and data structures that */ +/* provide the hooks into our module from the other parts of the server. */ +/* */ +/*--------------------------------------------------------------------------*/ +/* + * Module definition for configuration. If a particular callback is not + * needed, replace its routine name below with the word NULL. + * + * The number in brackets indicates the order in which the routine is called + * during request processing. Note that not all routines are necessarily + * called (such as if a resource doesn't have access restrictions). + */ +module example_module = { + STANDARD_MODULE_STUFF, + example_init, /* initializer */ + example_dir_create, /* per-directory config creater */ + example_dir_merge, /* dir config merger - default is to override */ + example_server_create, /* server config creator */ + example_server_merge, /* server config merger */ + example_commands, /* command table */ + example_handlers, /* [6] list of handlers */ + example_xlate, /* [1] filename-to-URI translation */ + example_ckuser, /* [4] check/validate HTTP user_id */ + example_ckauth, /* [5] check HTTP user_id is valid *here* */ + example_ckaccess, /* [3] check access by host address, etc. */ + example_typer, /* [6] MIME type checker/setter */ + example_fixer, /* [7] fixups */ + example_logger, /* [9] logger */ + example_hparser /* [2] header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/proxy/Makefile b/APACHE_1_2_X/src/modules/proxy/Makefile new file mode 100644 index 00000000000..102dea2a25f --- /dev/null +++ b/APACHE_1_2_X/src/modules/proxy/Makefile @@ -0,0 +1,89 @@ +# ==================================================================== +# Copyright (c) 1995-1997 The Apache Group. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# 3. All advertising materials mentioning features or use of this +# software must display the following acknowledgment: +# "This product includes software developed by the Apache Group +# for use in the Apache HTTP server project (http://www.apache.org/)." +# +# 4. The names "Apache Server" and "Apache Group" must not be used to +# endorse or promote products derived from this software without +# prior written permission. +# +# 5. Redistributions of any form whatsoever must retain the following +# acknowledgment: +# "This product includes software developed by the Apache Group +# for use in the Apache HTTP server project (http://www.apache.org/)." +# +# THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY +# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR +# ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. +# ==================================================================== +# +# This software consists of voluntary contributions made by many +# individuals on behalf of the Apache Group and was originally based +# on public domain software written at the National Center for +# Supercomputing Applications, University of Illinois, Urbana-Champaign. +# For more information on the Apache Group and the Apache HTTP server +# project, please see . +# +# Makefile for the Apache proxy library +# + +SHELL = /bin/sh + +INCDIR = ../.. + +LIB=libproxy.a + +# AUX_CFLAGS comes from higher level Makefile +CFLAGS=-I$(INCDIR) $(AUX_CFLAGS) + +# Internal stuff, should not need changing. +PROXYSRC=mod_proxy.c proxy_cache.c proxy_connect.c proxy_ftp.c proxy_http.c \ +proxy_util.c + +OBJS=$(PROXYSRC:.c=.o) + +default: force $(LIB) + +.c.a: + $(MAKE) $(CFLAGS) $< + +force: + rm -f $(LIB) + +$(LIB): $(OBJS) + ar crv $@ $(OBJS) + $(RANLIB) $@ + +clean: + rm -f *.o libproxy.a + +# dependencies +$(OBJS): mod_proxy.h $(INCDIR)/httpd.h $(INCDIR)/http_config.h $(INCDIR)/http_protocol.h +proxy_cache.o proxy_connect.o proxy_ftp.o proxy_http.o proxy_util.o: $(INCDIR)/http_main.h +proxy_cache.o proxy_connect.o proxy_http.o: $(INCDIR)/http_log.h +proxy_cache.o proxy_http.o: $(INCDIR)/util_date.h +proxy_cache.o proxy_util.o: $(INCDIR)/md5.h diff --git a/APACHE_1_2_X/src/modules/proxy/mod_proxy.c b/APACHE_1_2_X/src/modules/proxy/mod_proxy.c new file mode 100644 index 00000000000..c3dad860bfb --- /dev/null +++ b/APACHE_1_2_X/src/modules/proxy/mod_proxy.c @@ -0,0 +1,554 @@ +/* ==================================================================== + * Copyright (c) 1996,1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +#include "mod_proxy.h" + +/* Some WWW schemes and their default ports; this is basically /etc/services */ +/* This will become global when the protocol abstraction comes */ +static struct proxy_services defports[]={ + { "ftp", DEFAULT_FTP_PORT}, + { "gopher", DEFAULT_GOPHER_PORT}, + { "http", DEFAULT_PORT}, + { "nntp", DEFAULT_NNTP_PORT}, + { "wais", DEFAULT_WAIS_PORT}, + { "https", DEFAULT_HTTPS_PORT}, + { "snews", DEFAULT_SNEWS_PORT}, + { "prospero", DEFAULT_PROSPERO_PORT}, + { NULL, -1} /* unknown port */ +}; + +/* + * A Web proxy module. Stages: + * + * translate_name: set filename to proxy: + * type_checker: set type to PROXY_MAGIC_TYPE if filename begins proxy: + * fix_ups: convert the URL stored in the filename to the + * canonical form. + * handler: handle proxy requests + */ + +/* -------------------------------------------------------------- */ +/* Translate the URL into a 'filename' */ + +static int +alias_match(char *uri, char *alias_fakename) +{ + char *end_fakename = alias_fakename + strlen (alias_fakename); + char *aliasp = alias_fakename, *urip = uri; + + while (aliasp < end_fakename) + { + if (*aliasp == '/') + { + /* any number of '/' in the alias matches any number in + * the supplied URI, but there must be at least one... + */ + if (*urip != '/') return 0; + + while (*aliasp == '/') ++ aliasp; + while (*urip == '/') ++ urip; + } + else { + /* Other characters are compared literally */ + if (*urip++ != *aliasp++) return 0; + } + } + + /* Check last alias path component matched all the way */ + + if (aliasp[-1] != '/' && *urip != '\0' && *urip != '/') + return 0; + + /* Return number of characters from URI which matched (may be + * greater than length of alias, since we may have matched + * doubled slashes) + */ + + return urip - uri; +} + +static int +proxy_trans(request_rec *r) +{ + void *sconf = r->server->module_config; + proxy_server_conf *conf = + (proxy_server_conf *)get_module_config(sconf, &proxy_module); + + if (r->proxyreq) + { + if (!conf->req) return DECLINED; + + r->filename = pstrcat(r->pool, "proxy:", r->uri, NULL); + r->handler = "proxy-server"; + return OK; + } else + { + int i, len; + struct proxy_alias *ent=(struct proxy_alias *)conf->aliases->elts; + + for (i=0; i < conf->aliases->nelts; i++) + { + len = alias_match(r->uri, ent[i].fake); + + if (len > 0) + { + r->filename = pstrcat(r->pool, "proxy:", ent[i].real, + r->uri + len, NULL); + r->handler = "proxy-server"; + return OK; + } + } + return DECLINED; + } +} + +/* -------------------------------------------------------------- */ +/* Fixup the filename */ + +/* + * Canonicalise the URL + */ +static int +proxy_fixup(request_rec *r) +{ + char *url, *p; + int i; + + if (strncmp(r->filename, "proxy:", 6) != 0) return DECLINED; + + url = &r->filename[6]; +/* lowercase the scheme */ + p = strchr(url, ':'); + if (p == NULL || p == url) return BAD_REQUEST; + for (i=0; i != p - url; i++) url[i] = tolower(url[i]); + +/* canonicalise each specific scheme */ + if (strncmp(url, "http:", 5) == 0) + return proxy_http_canon(r, url+5, "http", DEFAULT_PORT); + else if (strncmp(url, "ftp:", 4) == 0) + return proxy_ftp_canon(r, url+4); + else return OK; /* otherwise; we've done the best we can */ +} + +/* -------------------------------------------------------------- */ +/* Invoke handler */ + +static int +proxy_handler(request_rec *r) +{ + char *url, *scheme, *p; + void *sconf = r->server->module_config; + proxy_server_conf *conf = + (proxy_server_conf *)get_module_config(sconf, &proxy_module); + array_header *proxies=conf->proxies; + struct proxy_remote *ents=(struct proxy_remote *)proxies->elts; + int i, rc; + struct cache_req *cr; + + if (strncmp(r->filename, "proxy:", 6) != 0) return DECLINED; + + if ((rc = setup_client_block(r, REQUEST_CHUNKED_ERROR))) + return rc; + + url = r->filename + 6; + p = strchr(url, ':'); + if (p == NULL) return BAD_REQUEST; + + rc = proxy_cache_check(r, url, &conf->cache, &cr); + if (rc != DECLINED) return rc; + + *p = '\0'; + scheme = pstrdup(r->pool, url); + *p = ':'; + +/* firstly, try a proxy */ + + for (i=0; i < proxies->nelts; i++) + { + p = strchr(ents[i].scheme, ':'); /* is it a partial URL? */ + if (strcmp(ents[i].scheme, "*") == 0 || + (p == NULL && strcmp(scheme, ents[i].scheme) == 0) || + (p != NULL && + strncmp(url, ents[i].scheme, strlen(ents[i].scheme)) == 0)) + { +/* we only know how to handle communication to a proxy via http */ + if (strcmp(ents[i].protocol, "http") == 0) + rc = proxy_http_handler(r, cr, url, ents[i].hostname, + ents[i].port); + else rc = DECLINED; + + /* an error or success */ + if (rc != DECLINED && rc != BAD_GATEWAY) return rc; + /* we failed to talk to the upstream proxy */ + } + } + +/* otherwise, try it direct */ +/* N.B. what if we're behind a firewall, where we must use a proxy or + * give up?? + */ + /* handle the scheme */ + if (r->method_number == M_CONNECT) + return proxy_connect_handler(r, cr, url); + if (strcmp(scheme, "http") == 0) + return proxy_http_handler(r, cr, url, NULL, 0); + if (strcmp(scheme, "ftp") == 0) + return proxy_ftp_handler(r, cr, url); + else return NOT_IMPLEMENTED; +} + +/* -------------------------------------------------------------- */ +/* Setup configurable data */ + +static void * +create_proxy_config(pool *p, server_rec *s) +{ + proxy_server_conf *ps = pcalloc(p, sizeof(proxy_server_conf)); + + ps->proxies = make_array(p, 10, sizeof(struct proxy_remote)); + ps->aliases = make_array(p, 10, sizeof(struct proxy_alias)); + ps->noproxies = make_array(p, 10, sizeof(struct noproxy_entry)); + ps->nocaches = make_array(p, 10, sizeof(struct nocache_entry)); + ps->req = 0; + + ps->cache.root = NULL; + ps->cache.space = DEFAULT_CACHE_SPACE; + ps->cache.maxexpire = DEFAULT_CACHE_MAXEXPIRE; + ps->cache.defaultexpire = DEFAULT_CACHE_EXPIRE; + ps->cache.lmfactor = DEFAULT_CACHE_LMFACTOR; + ps->cache.gcinterval = -1; + /* at these levels, the cache can have 2^18 directories (256,000) */ + ps->cache.dirlevels=3; + ps->cache.dirlength=1; + + return ps; +} + +static const char * +add_proxy(cmd_parms *cmd, void *dummy, char *f, char *r) +{ + server_rec *s = cmd->server; + proxy_server_conf *conf = + (proxy_server_conf *)get_module_config(s->module_config,&proxy_module); + struct proxy_remote *new; + char *p, *q; + int port; + + p = strchr(r, ':'); + if (p == NULL || p[1] != '/' || p[2] != '/' || p[3] == '\0') + return "Bad syntax for a remote proxy server"; + q = strchr(p + 3, ':'); + if (q != NULL) + { + if (sscanf(q+1, "%u", &port) != 1 || port > 65535) + return "Bad syntax for a remote proxy server (bad port number)"; + *q = '\0'; + } else port = -1; + *p = '\0'; + if (strchr(f, ':') == NULL) str_tolower(f); /* lowercase scheme */ + str_tolower(p + 3); /* lowercase hostname */ + + if (port == -1) + { + int i; + for (i=0; defports[i].scheme != NULL; i++) + if (strcmp(defports[i].scheme, r) == 0) break; + port = defports[i].port; + } + + new = push_array (conf->proxies); + new->scheme = f; + new->protocol = r; + new->hostname = p + 3; + new->port = port; + return NULL; +} + +static const char * +add_pass(cmd_parms *cmd, void *dummy, char *f, char *r) +{ + server_rec *s = cmd->server; + proxy_server_conf *conf = + (proxy_server_conf *)get_module_config(s->module_config,&proxy_module); + struct proxy_alias *new; + + new = push_array (conf->aliases); + new->fake = f; + new->real = r; + return NULL; +} + +static const char * +set_proxy_exclude(cmd_parms *parms, void *dummy, char *arg) +{ + server_rec *s = parms->server; + proxy_server_conf *conf = + get_module_config (s->module_config, &proxy_module); + struct noproxy_entry *new; + struct noproxy_entry *list=(struct noproxy_entry*)conf->noproxies->elts; + struct hostent hp; + int found = 0; + int i; + + /* Don't duplicate entries */ + for (i=0; i < conf->noproxies->nelts; i++) + { + if (strcmp(arg, list[i].name) == 0) + found = 1; + } + + if (!found) + { + new = push_array (conf->noproxies); + new->name = arg; + /* Don't do name lookups on things that aren't dotted */ + if (strchr(arg, '.') != NULL && proxy_host2addr(new->name, &hp) == NULL) + memcpy(&new->addr, hp.h_addr, sizeof(struct in_addr)); + else + new->addr.s_addr = 0; + } + return NULL; +} + +static const char * +set_proxy_req(cmd_parms *parms, void *dummy, int flag) +{ + proxy_server_conf *psf = + get_module_config (parms->server->module_config, &proxy_module); + + psf->req = flag; + return NULL; +} + + +static const char * +set_cache_size(cmd_parms *parms, char *struct_ptr, char *arg) +{ + proxy_server_conf *psf = + get_module_config (parms->server->module_config, &proxy_module); + int val; + + if (sscanf(arg, "%d", &val) != 1) return "Value must be an integer"; + psf->cache.space = val; + return NULL; +} + +static const char * +set_cache_root(cmd_parms *parms, void *dummy, char *arg) +{ + proxy_server_conf *psf = + get_module_config (parms->server->module_config, &proxy_module); + + psf->cache.root = arg; + + return NULL; +} + +static const char * +set_cache_factor(cmd_parms *parms, void *dummy, char *arg) +{ + proxy_server_conf *psf = + get_module_config (parms->server->module_config, &proxy_module); + double val; + + if (sscanf(arg, "%lg", &val) != 1) return "Value must be a float"; + psf->cache.lmfactor = val; + + return NULL; +} + +static const char * +set_cache_maxex(cmd_parms *parms, void *dummy, char *arg) +{ + proxy_server_conf *psf = + get_module_config (parms->server->module_config, &proxy_module); + double val; + + if (sscanf(arg, "%lg", &val) != 1) return "Value must be a float"; + psf->cache.maxexpire = (int)(val * (double)SEC_ONE_HR); + return NULL; +} + +static const char * +set_cache_defex(cmd_parms *parms, void *dummy, char *arg) +{ + proxy_server_conf *psf = + get_module_config (parms->server->module_config, &proxy_module); + double val; + + if (sscanf(arg, "%lg", &val) != 1) return "Value must be a float"; + psf->cache.defaultexpire = (int)(val * (double)SEC_ONE_HR); + return NULL; +} + +static const char * +set_cache_gcint(cmd_parms *parms, void *dummy, char *arg) +{ + proxy_server_conf *psf = + get_module_config (parms->server->module_config, &proxy_module); + double val; + + if (sscanf(arg, "%lg", &val) != 1) return "Value must be a float"; + psf->cache.gcinterval = (int)(val * (double)SEC_ONE_HR); + return NULL; +} + +static const char * +set_cache_dirlevels(cmd_parms *parms, char *struct_ptr, char *arg) +{ + proxy_server_conf *psf = + get_module_config (parms->server->module_config, &proxy_module); + int val; + + if (sscanf(arg, "%d", &val) != 1) return "Value must be an integer"; + psf->cache.dirlevels = val; + return NULL; +} + +static const char * +set_cache_dirlength(cmd_parms *parms, char *struct_ptr, char *arg) +{ + proxy_server_conf *psf = + get_module_config (parms->server->module_config, &proxy_module); + int val; + + if (sscanf(arg, "%d", &val) != 1) return "Value must be an integer"; + psf->cache.dirlength = val; + return NULL; +} + +static const char * +set_cache_exclude(cmd_parms *parms, void *dummy, char *arg) +{ + server_rec *s = parms->server; + proxy_server_conf *conf = + get_module_config (s->module_config, &proxy_module); + struct nocache_entry *new; + struct nocache_entry *list=(struct nocache_entry*)conf->nocaches->elts; + struct hostent hp; + int found = 0; + int i; + + /* Don't duplicate entries */ + for (i=0; i < conf->nocaches->nelts; i++) + { + if (strcmp(arg, list[i].name) == 0) + found = 1; + } + + if (!found) + { + new = push_array (conf->nocaches); + new->name = arg; + /* Don't do name lookups on things that aren't dotted */ + if (strchr(arg, '.') != NULL && proxy_host2addr(new->name, &hp) == NULL) + memcpy(&new->addr, hp.h_addr, sizeof(struct in_addr)); + else + new->addr.s_addr= 0; + } + return NULL; +} + +static handler_rec proxy_handlers[] = { +{ "proxy-server", proxy_handler }, +{ NULL } +}; + +static command_rec proxy_cmds[] = { +{ "ProxyRequests", set_proxy_req, NULL, RSRC_CONF, FLAG, + "on if the true proxy requests should be accepted"}, +{ "ProxyRemote", add_proxy, NULL, RSRC_CONF, TAKE2, + "a scheme, partial URL or '*' and a proxy server"}, +{ "ProxyPass", add_pass, NULL, RSRC_CONF, TAKE2, + "a virtual path and a URL"}, +{ "ProxyBlock", set_proxy_exclude, NULL, RSRC_CONF, ITERATE, + "A list of names, hosts or domains to which the proxy will not connect" }, +{ "CacheRoot", set_cache_root, NULL, RSRC_CONF, TAKE1, + "The directory to store cache files"}, +{ "CacheSize", set_cache_size, NULL, RSRC_CONF, TAKE1, + "The maximum disk space used by the cache in Kb"}, +{ "CacheMaxExpire", set_cache_maxex, NULL, RSRC_CONF, TAKE1, + "The maximum time in hours to cache a document"}, +{ "CacheDefaultExpire", set_cache_defex, NULL, RSRC_CONF, TAKE1, + "The default time in hours to cache a document"}, +{ "CacheLastModifiedFactor", set_cache_factor, NULL, RSRC_CONF, TAKE1, + "The factor used to estimate Expires date from LastModified date"}, +{ "CacheGcInterval", set_cache_gcint, NULL, RSRC_CONF, TAKE1, + "The interval between garbage collections, in hours"}, +{ "CacheDirLevels", set_cache_dirlevels, NULL, RSRC_CONF, TAKE1, + "The number of levels of subdirectories in the cache" }, +{ "CacheDirLength", set_cache_dirlength, NULL, RSRC_CONF, TAKE1, + "The number of characters in subdirectory names" }, +{ "NoCache", set_cache_exclude, NULL, RSRC_CONF, ITERATE, + "A list of names, hosts or domains for which caching is *not* provided" }, +{ NULL } +}; + +module proxy_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + NULL, /* create per-directory config structure */ + NULL, /* merge per-directory config structures */ + create_proxy_config, /* create per-server config structure */ + NULL, /* merge per-server config structures */ + proxy_cmds, /* command table */ + proxy_handlers, /* handlers */ + proxy_trans, /* translate_handler */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + proxy_fixup, /* pre-run fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; + diff --git a/APACHE_1_2_X/src/modules/proxy/mod_proxy.h b/APACHE_1_2_X/src/modules/proxy/mod_proxy.h new file mode 100644 index 00000000000..939ebea348c --- /dev/null +++ b/APACHE_1_2_X/src/modules/proxy/mod_proxy.h @@ -0,0 +1,273 @@ +/* ==================================================================== + * Copyright (c) 1996,1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * Main include file for the Apache proxy + */ + +/* + +Note that the Explain() stuff is not yet complete. +Also note numerous FIXMEs and CHECKMEs which should be eliminated. + +If TESTING is set, then garbage collection doesn't delete ... probably a good +idea when hacking. + +This code is still experimental! + +Things to do: + +1. Make it garbage collect in the background, not while someone is waiting for +a response! + +2. Check the logic thoroughly. + +3. Empty directories are only removed the next time round (but this does avoid +two passes). Consider doing them the first time round. + +Ben Laurie 30 Mar 96 + +More things to do: + +0. Code cleanup (ongoing) + +1. add 230 response output for ftp now that it works + +2. Make the ftp proxy transparent, also same with (future) gopher & wais + +3. Use protocol handler struct a la Apache module handlers (Dirk van Gulik) + +4. Use a cache expiry database for more efficient GC (Jeremy Wohl) + +5. Bulletproof GC against SIGALRM + +Chuck Murcko 15 April 1997 + +*/ + +#define TESTING 0 +#undef EXPLAIN + +#include "httpd.h" +#include "http_config.h" +#include "http_protocol.h" + +#include "explain.h" + +DEF_Explain + + +extern module proxy_module; + + +/* for proxy_canonenc() */ +enum enctype { enc_path, enc_search, enc_user, enc_fpath, enc_parm }; + +#define HDR_APP (0) /* append header, for proxy_add_header() */ +#define HDR_REP (1) /* replace header, for proxy_add_header() */ + +/* number of characters in the hash */ +#define HASH_LEN (22*2) + +#define SEC_ONE_DAY 86400 /* one day, in seconds */ +#define SEC_ONE_HR 3600 /* one hour, in seconds */ + +#define DEFAULT_FTP_DATA_PORT 20 +#define DEFAULT_FTP_PORT 21 +#define DEFAULT_GOPHER_PORT 70 +#define DEFAULT_NNTP_PORT 119 +#define DEFAULT_WAIS_PORT 210 +#define DEFAULT_HTTPS_PORT 443 +#define DEFAULT_SNEWS_PORT 563 +#define DEFAULT_PROSPERO_PORT 1525 /* WARNING: conflict w/Oracle */ + +/* Some WWW schemes and their default ports; this is basically /etc/services */ +struct proxy_services +{ + const char *scheme; + int port; +}; + +/* static information about a remote proxy */ +struct proxy_remote +{ + const char *scheme; /* the schemes handled by this proxy, or '*' */ + const char *protocol; /* the scheme used to talk to this proxy */ + const char *hostname; /* the hostname of this proxy */ + int port; /* the port for this proxy */ +}; + +struct proxy_alias { + char *real; + char *fake; +}; + +struct noproxy_entry { + char *name; + struct in_addr addr; +}; + +struct nocache_entry { + char *name; + struct in_addr addr; +}; + +#define DEFAULT_CACHE_SPACE 5 +#define DEFAULT_CACHE_MAXEXPIRE SEC_ONE_DAY +#define DEFAULT_CACHE_EXPIRE SEC_ONE_HR +#define DEFAULT_CACHE_LMFACTOR (0.1) + +/* static information about the local cache */ +struct cache_conf +{ + const char *root; /* the location of the cache directory */ + int space; /* Maximum cache size (in 1024 bytes) */ + int maxexpire; /* Maximum time to keep cached files in secs */ + int defaultexpire; /* default time to keep cached file in secs */ + double lmfactor; /* factor for estimating expires date */ + int gcinterval; /* garbage collection interval, in seconds */ + int dirlevels; /* Number of levels of subdirectories */ + int dirlength; /* Length of subdirectory names */ +}; + +typedef struct +{ + struct cache_conf cache; /* cache configuration */ + array_header *proxies; + array_header *aliases; + array_header *noproxies; + array_header *nocaches; + int req; /* true if proxy requests are enabled */ +} proxy_server_conf; + +struct hdr_entry +{ + char *field; + char *value; +}; + +/* caching information about a request */ +struct cache_req +{ + request_rec *req; /* the request */ + char *url; /* the URL requested */ + char *filename; /* name of the cache file, or NULL if no cache */ + char *tempfile; /* name of the temporary file, of NULL if not caching */ + time_t ims; /* if-modified-since date of request; -1 if no header */ + BUFF *fp; /* the cache file descriptor if the file is cached + and may be returned, or NULL if the file is + not cached (or must be reloaded) */ + time_t expire; /* calculated expire date of cached entity */ + time_t lmod; /* last-modified date of cached entity */ + time_t date; /* the date the cached file was last touched */ + int version; /* update count of the file */ + unsigned int len; /* content length */ + char *protocol; /* Protocol, and major/minor number, e.g. HTTP/1.1 */ + int status; /* the status of the cached file */ + char *resp_line; /* the whole status like (protocol, code + message) */ + array_header *hdrs; /* the HTTP headers of the file */ +}; + +/* Function prototypes */ + +/* proxy_cache.c */ + +void proxy_cache_tidy(struct cache_req *c); +int proxy_cache_check(request_rec *r, char *url, struct cache_conf *conf, + struct cache_req **cr); +int proxy_cache_update(struct cache_req *c, array_header *resp_hdrs, + const char *protocol, int nocache); +void proxy_garbage_coll(request_rec *r); + +/* proxy_connect.c */ + +int proxy_connect_handler(request_rec *r, struct cache_req *c, char *url); + +/* proxy_ftp.c */ + +int proxy_ftp_canon(request_rec *r, char *url); +int proxy_ftp_handler(request_rec *r, struct cache_req *c, char *url); + +/* proxy_http.c */ + +int proxy_http_canon(request_rec *r, char *url, const char *scheme, + int def_port); +int proxy_http_handler(request_rec *r, struct cache_req *c, char *url, + const char *proxyhost, int proxyport); + +/* proxy_util.c */ + +int proxy_hex2c(const char *x); +void proxy_c2hex(int ch, char *x); +char *proxy_canonenc(pool *p, const char *x, int len, enum enctype t, + int isenc); +char *proxy_canon_netloc(pool *pool, char **const urlp, char **userp, + char **passwordp, char **hostp, int *port); +char *proxy_date_canon(pool *p, char *x); +array_header *proxy_read_headers(pool *pool, char *buffer, int size, BUFF *f); +long int proxy_send_fb(BUFF *f, request_rec *r, BUFF *f2, struct cache_req *c); +struct hdr_entry *proxy_get_header(array_header *hdrs_arr, const char *name); +struct hdr_entry *proxy_add_header(array_header *hdrs_arr, char *field, + char *value, int rep); +void proxy_del_header(array_header *hdrs_arr, const char *field); +void proxy_send_headers(BUFF *fp, const char *respline, array_header *hdrs_arr); +int proxy_liststr(const char *list, const char *val); +void proxy_hash(const char *it, char *val,int ndepth,int nlength); +int proxy_hex2sec(const char *x); +void proxy_sec2hex(int t, char *y); +void proxy_log_uerror(const char *routine, const char *file, const char *err, + server_rec *s); +BUFF *proxy_cache_error(struct cache_req *r); +int proxyerror(request_rec *r, const char *message); +const char *proxy_host2addr(const char *host, struct hostent *reqhp); +int proxy_doconnect(int sock, struct sockaddr_in *addr, request_rec *r); + diff --git a/APACHE_1_2_X/src/modules/proxy/proxy_cache.c b/APACHE_1_2_X/src/modules/proxy/proxy_cache.c new file mode 100644 index 00000000000..5c0eda23e59 --- /dev/null +++ b/APACHE_1_2_X/src/modules/proxy/proxy_cache.c @@ -0,0 +1,932 @@ +/* ==================================================================== + * Copyright (c) 1996,1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* Cache and garbage collection routines for Apache proxy */ + +#include "md5.h" + +#include "mod_proxy.h" +#include "http_log.h" +#include "http_main.h" +#include "util_date.h" +#include + +#define abs(c) ((c) >= 0 ? (c) : -(c)) + +struct gc_ent +{ + unsigned long int len; + time_t expire; + char file[HASH_LEN+1]; + +}; + +static int +gcdiff(const void *ap, const void *bp) +{ + const struct gc_ent *a=*(struct gc_ent **)ap, *b=*(struct gc_ent **)bp; + + if (a->expire > b->expire) return 1; + else if (a->expire < b->expire) return -1; + else return 0; +} + +static int curbytes, cachesize, every; +static unsigned long int curblocks; +static time_t now, expire; +static char *filename; + +static int sub_garbage_coll(request_rec *r,array_header *files, + const char *cachedir,const char *cachesubdir); + +void proxy_garbage_coll(request_rec *r) + { + const char *cachedir; + void *sconf = r->server->module_config; + proxy_server_conf *pconf = + (proxy_server_conf *)get_module_config(sconf, &proxy_module); + const struct cache_conf *conf=&pconf->cache; + array_header *files; + struct stat buf; + struct gc_ent *fent,**elts; + int i, timefd; + static time_t lastcheck=BAD_DATE; /* static data!!! */ + + cachedir = conf->root; + cachesize = conf->space; + every = conf->gcinterval; + + if (cachedir == NULL || every == -1) return; + now = time(NULL); + if (now != -1 && lastcheck != BAD_DATE && now < lastcheck + every) return; + + block_alarms(); /* avoid SIGALRM on big cache cleanup */ + + filename = palloc(r->pool, strlen(cachedir) + HASH_LEN + 2); + strcpy(filename, cachedir); + strcat(filename, "/.time"); + if (stat(filename, &buf) == -1) /* does not exist */ + { + if (errno != ENOENT) + { + proxy_log_uerror("stat", filename, NULL, r->server); + unblock_alarms(); + return; + } + if ((timefd = creat(filename, 0666)) == -1) + { + if (errno != EEXIST) + proxy_log_uerror("creat", filename, NULL, r->server); + else + lastcheck = abs(now); /* someone else got in there */ + unblock_alarms(); + return; + } + close(timefd); + } else + { + lastcheck = buf.st_mtime; /* save the time */ + if (now < lastcheck + every) + { + unblock_alarms(); + return; + } + if (utime(filename, NULL) == -1) + proxy_log_uerror("utimes", filename, NULL, r->server); + } + files = make_array(r->pool, 100, sizeof(struct gc_ent *)); + curblocks = 0; + curbytes = 0; + + sub_garbage_coll(r,files,cachedir,"/"); + + if (curblocks < cachesize || curblocks + curbytes <= cachesize) + { + unblock_alarms(); + return; + } + + qsort(files->elts, files->nelts, sizeof(struct gc_ent *), gcdiff); + + elts = (struct gc_ent **)files->elts; + for (i=0; i < files->nelts; i++) + { + fent = elts[i]; + sprintf(filename, "%s%s", cachedir, fent->file); + Explain3("GC Unlinking %s (expiry %ld, now %ld)",filename,fent->expire,now); +#if TESTING + fprintf(stderr,"Would unlink %s\n",filename); +#else + if (unlink(filename) == -1) + { + if (errno != ENOENT) + proxy_log_uerror("unlink", filename, NULL, r->server); + } + else +#endif + { + curblocks -= fent->len >> 10; + curbytes -= fent->len & 0x3FF; + if (curbytes < 0) + { + curbytes += 1024; + curblocks--; + } + if (curblocks < cachesize || curblocks + curbytes <= cachesize) + break; + } + } + unblock_alarms(); +} + +static int sub_garbage_coll(request_rec *r,array_header *files, + const char *cachebasedir,const char *cachesubdir) +{ + char line[27]; + char cachedir[HUGE_STRING_LEN]; + struct stat buf; + int fd,i; + DIR *dir; +#if defined(NEXT) + struct DIR_TYPE *ent; +#else + struct dirent *ent; +#endif + struct gc_ent *fent; + int nfiles=0; + + ap_snprintf(cachedir, sizeof(cachedir), "%s%s",cachebasedir,cachesubdir); + Explain1("GC Examining directory %s",cachedir); + dir = opendir(cachedir); + if (dir == NULL) + { + proxy_log_uerror("opendir", cachedir, NULL, r->server); + return 0; + } + + while ((ent = readdir(dir)) != NULL) + { + if (ent->d_name[0] == '.') continue; + sprintf(filename, "%s%s", cachedir, ent->d_name); + Explain1("GC Examining file %s",filename); +/* is it a temporary file? */ + if (strncmp(ent->d_name, "tmp", 3) == 0) + { +/* then stat it to see how old it is; delete temporary files > 1 day old */ + if (stat(filename, &buf) == -1) + { + if (errno != ENOENT) + proxy_log_uerror("stat", filename, NULL, r->server); + } else if (now != -1 && buf.st_atime < now - SEC_ONE_DAY && + buf.st_mtime < now - SEC_ONE_DAY) + { + Explain1("GC unlink %s",filename); +#if TESTING + fprintf(stderr,"Would unlink %s\n",filename); +#else + unlink(filename); +#endif + } + continue; + } + ++nfiles; +/* is it another file? */ + /* FIXME: Shouldn't any unexpected files be deleted? */ + /* if (strlen(ent->d_name) != HASH_LEN) continue; */ + +/* read the file */ + fd = open(filename, O_RDONLY); + if (fd == -1) + { + if (errno != ENOENT) proxy_log_uerror("open", filename,NULL, + r->server); + continue; + } + if (fstat(fd, &buf) == -1) + { + proxy_log_uerror("fstat", filename, NULL, r->server); + close(fd); + continue; + } + if(S_ISDIR(buf.st_mode)) + { + char newcachedir[HUGE_STRING_LEN]; + close(fd); + ap_snprintf(newcachedir, sizeof(newcachedir), + "%s%s/",cachesubdir,ent->d_name); + if(!sub_garbage_coll(r,files,cachebasedir,newcachedir)) + { + ap_snprintf(newcachedir, sizeof(newcachedir), + "%s%s",cachedir,ent->d_name); +#if TESTING + fprintf(stderr,"Would remove directory %s\n",newcachedir); +#else + rmdir(newcachedir); +#endif + --nfiles; + } + continue; + } + + i = read(fd, line, 26); + if (i == -1) + { + proxy_log_uerror("read", filename, NULL, r->server); + close(fd); + continue; + } + close(fd); + line[i] = '\0'; + expire = proxy_hex2sec(line+18); + if (!checkmask(line, "&&&&&&&& &&&&&&&& &&&&&&&&") || + expire == BAD_DATE) + { + /* bad file */ + if (now != -1 && buf.st_atime > now + SEC_ONE_DAY && + buf.st_mtime > now + SEC_ONE_DAY) + { + log_error("proxy: deleting bad cache file", r->server); +#if TESTING + fprintf(stderr,"Would unlink bad file %s\n",filename); +#else + unlink(filename); +#endif + } + continue; + } + +/* + * we need to calculate an 'old' factor, and remove the 'oldest' files + * so that the space requirement is met; sort by the expires date of the + * file. + * + */ + /* FIXME: We should make the array an array of gc_ents, not gc_ent *s + */ + fent = palloc(r->pool, sizeof(struct gc_ent)); + fent->len = buf.st_size; + fent->expire = expire; + strcpy(fent->file,cachesubdir); + strcat(fent->file, ent->d_name); + *(struct gc_ent **)push_array(files) = fent; + +/* accumulate in blocks, to cope with directories > 4Gb */ + curblocks += buf.st_size >> 10; /* Kbytes */ + curbytes += buf.st_size & 0x3FF; + if (curbytes >= 1024) + { + curbytes -= 1024; + curblocks++; + } + } + + closedir(dir); + + return nfiles; + +} + +/* + * read a cache file; + * returns 1 on success, + * 0 on failure (bad file or wrong URL) + * -1 on UNIX error + */ +static int +rdcache(pool *pool, BUFF *cachefp, struct cache_req *c) +{ + char urlbuff[1034], *p; + int len; +/* read the data from the cache file */ +/* format + * date SP lastmod SP expire SP count SP content-length CRLF + * dates are stored as hex seconds since 1970 + */ + len = bgets(urlbuff, 1034, cachefp); + if (len == -1) return -1; + if (len == 0 || urlbuff[len-1] != '\n') return 0; + urlbuff[len-1] = '\0'; + + if (!checkmask(urlbuff, + "&&&&&&&& &&&&&&&& &&&&&&&& &&&&&&&& &&&&&&&&")) + return 0; + + c->date = proxy_hex2sec(urlbuff); + c->lmod = proxy_hex2sec(urlbuff+9); + c->expire = proxy_hex2sec(urlbuff+18); + c->version = proxy_hex2sec(urlbuff+27); + c->len = proxy_hex2sec(urlbuff+36); + +/* check that we have the same URL */ + len = bgets(urlbuff, 1034, cachefp); + if (len == -1) return -1; + if (len == 0 || strncmp(urlbuff, "X-URL: ", 7) != 0 || + urlbuff[len-1] != '\n') + return 0; + urlbuff[len-1] = '\0'; + if (strcmp(urlbuff+7, c->url) != 0) return 0; + +/* What follows is the message */ + len = bgets(urlbuff, 1034, cachefp); + if (len == -1) return -1; + if (len == 0 || urlbuff[len-1] != '\n') return 0; + urlbuff[--len] = '\0'; + + c->resp_line = pstrdup(pool, urlbuff); + p = strchr(urlbuff, ' '); + if (p == NULL) return 0; + + c->status = atoi(p); + c->hdrs = proxy_read_headers(pool, urlbuff, 1034, cachefp); + if (c->hdrs == NULL) return -1; + if (c->len != -1) /* add a content-length header */ + { + struct hdr_entry *q; + q = proxy_get_header(c->hdrs, "Content-Length"); + if (q == NULL) + { + p = palloc(pool, 15); + ap_snprintf(p, 15, "%u", c->len); + proxy_add_header(c->hdrs, "Content-Length", p, HDR_REP); + } + } + return 1; +} + + +/* + * Call this to test for a resource in the cache + * Returns DECLINED if we need to check the remote host + * or an HTTP status code if successful + * + * Functions: + * if URL is cached then + * if cached file is not expired then + * if last modified after if-modified-since then send body + * else send 304 Not modified + * else + * if last modified after if-modified-since then add + * last modified date to request + */ +int +proxy_cache_check(request_rec *r, char *url, struct cache_conf *conf, + struct cache_req **cr) +{ + char hashfile[33], *imstr, *pragma, *p, *auth; + struct cache_req *c; + time_t now; + BUFF *cachefp; + int cfd, i; + const long int zero=0L; + void *sconf = r->server->module_config; + proxy_server_conf *pconf = + (proxy_server_conf *)get_module_config(sconf, &proxy_module); + + c = pcalloc(r->pool, sizeof(struct cache_req)); + *cr = c; + c->req = r; + c->url = pstrdup(r->pool, url); + +/* get the If-Modified-Since date of the request */ + c->ims = BAD_DATE; + imstr = table_get(r->headers_in, "If-Modified-Since"); + if (imstr != NULL) + { +/* this may modify the value in the original table */ + imstr = proxy_date_canon(r->pool, imstr); + c->ims = parseHTTPdate(imstr); + if (c->ims == BAD_DATE) /* bad or out of range date; remove it */ + table_set(r->headers_in, "If-Modified-Since", NULL); + } + +/* find the filename for this cache entry */ + proxy_hash(url, hashfile,pconf->cache.dirlevels,pconf->cache.dirlength); + if (conf->root != NULL) + c->filename = pstrcat(r->pool, conf->root, "/", hashfile, NULL); + else + c->filename = NULL; + + cachefp = NULL; +/* find out about whether the request can access the cache */ + pragma = table_get(r->headers_in, "Pragma"); + auth = table_get(r->headers_in, "Authorization"); + Explain5("Request for %s, pragma=%s, auth=%s, ims=%ld, imstr=%s",url, + pragma,auth,c->ims,imstr); + if (c->filename != NULL && r->method_number == M_GET && + strlen(url) < 1024 && !proxy_liststr(pragma, "no-cache") && + auth == NULL) + { + Explain1("Check file %s",c->filename); + cfd = open(c->filename, O_RDWR); + if (cfd != -1) + { + note_cleanups_for_fd(r->pool, cfd); + cachefp = bcreate(r->pool, B_RD | B_WR); + bpushfd(cachefp, cfd, cfd); + } else if (errno != ENOENT) + proxy_log_uerror("open", c->filename, + "proxy: error opening cache file", r->server); +#ifdef EXPLAIN + else + Explain1("File %s not found",c->filename); +#endif + } + + if (cachefp != NULL) + { + i = rdcache(r->pool, cachefp, c); + if (i == -1) + proxy_log_uerror("read", c->filename, + "proxy: error reading cache file", r->server); + else if (i == 0) + log_error("proxy: bad cache file", r->server); + if (i != 1) + { + pclosef(r->pool, cachefp->fd); + cachefp = NULL; + } + } + if (cachefp == NULL) + c->hdrs = make_array(r->pool, 2, sizeof(struct hdr_entry)); + /* FIXME: Shouldn't we check the URL somewhere? */ + now = time(NULL); +/* Ok, have we got some un-expired data? */ + if (cachefp != NULL && c->expire != BAD_DATE && now < c->expire) + { + Explain0("Unexpired data available"); +/* check IMS */ + if (c->lmod != BAD_DATE && c->ims != BAD_DATE && c->ims >= c->lmod) + { +/* has the cached file changed since this request? */ + if (c->date == BAD_DATE || c->date > c->ims) + { +/* No, but these header values may have changed, so we send them with the + * 304 response + */ + /* CHECKME: surely this was wrong? (Ben) + p = table_get(r->headers_in, "Expires"); + */ + p = table_get(c->hdrs, "Expires"); + if (p != NULL) table_set(r->headers_out, "Expires", p); + } + pclosef(r->pool, cachefp->fd); + Explain0("Use local copy, cached file hasn't changed"); + return USE_LOCAL_COPY; + } + +/* Ok, has been modified */ + Explain0("Local copy modified, send it"); + r->status_line = strchr(c->resp_line, ' ') + 1; + r->status = c->status; + if (!r->assbackwards) { + soft_timeout("proxy send headers", r); + proxy_send_headers(r->connection->client, c->resp_line, c->hdrs); + kill_timeout(r); + } + bsetopt(r->connection->client, BO_BYTECT, &zero); + r->sent_bodyct = 1; + if (!r->header_only) proxy_send_fb (cachefp, r, NULL, NULL); + pclosef(r->pool, cachefp->fd); + return OK; + } + +/* if we already have data and a last-modified date, and it is not a head + * request, then add an If-Modified-Since + */ + + if (cachefp != NULL && c->lmod != BAD_DATE && !r->header_only) + { +/* + * use the later of the one from the request and the last-modified date + * from the cache + */ + if (c->ims == BAD_DATE || c->ims < c->lmod) + { + struct hdr_entry *q; + + q = proxy_get_header(c->hdrs, "Last-Modified"); + + if (q != NULL && q->value != NULL) + table_set(r->headers_in, "If-Modified-Since", + (char *)q->value); + } + } + c->fp = cachefp; + + Explain0("Local copy not present or expired. Declining."); + + return DECLINED; +} + +/* + * Having read the response from the client, decide what to do + * If the response is not cachable, then delete any previously cached + * response, and copy data from remote server to client. + * Functions: + * parse dates + * check for an uncachable response + * calculate an expiry date, if one is not provided + * if the remote file has not been modified, then return the document + * from the cache, maybe updating the header line + * otherwise, delete the old cached file and open a new temporary file + */ +int +proxy_cache_update(struct cache_req *c, array_header *resp_hdrs, + const char *protocol, int nocache) +{ + request_rec *r=c->req; + char *p; + int i; + struct hdr_entry *expire, *dates, *lmods, *clen; + time_t expc, date, lmod, now; + char buff[46]; + void *sconf = r->server->module_config; + proxy_server_conf *conf = + (proxy_server_conf *)get_module_config(sconf, &proxy_module); + const long int zero=0L; + + c->tempfile = NULL; + +/* we've received the response */ +/* read expiry date; if a bad date, then leave it so the client can + * read it + */ + expire = proxy_get_header(resp_hdrs, "Expires"); + if (expire != NULL) expc = parseHTTPdate(expire->value); + else expc = BAD_DATE; + +/* + * read the last-modified date; if the date is bad, then delete it + */ + lmods = proxy_get_header(resp_hdrs, "Last-Modified"); + if (lmods != NULL) + { + lmod = parseHTTPdate(lmods->value); + if (lmod == BAD_DATE) + { +/* kill last modified date */ + lmods->value = NULL; + lmods = NULL; + } + } else + lmod = BAD_DATE; + +/* + * what responses should we not cache? + * Unknown status responses and those known to be uncacheable + * 304 response when we have no valid cache file, or + * 200 response from HTTP/1.0 and up without a Last-Modified header, or + * HEAD requests, or + * requests with an Authorization header, or + * protocol requests nocache (e.g. ftp with user/password) + */ + if ((r->status != 200 && r->status != 301 && r->status != 304) || + (expire != NULL && expc == BAD_DATE) || + (r->status == 304 && c->fp == NULL) || + (r->status == 200 && lmods == NULL && + strncmp(protocol, "HTTP/1.", 7) == 0) || + r->header_only || + table_get(r->headers_in, "Authorization") != NULL || + nocache) + { + Explain1("Response is not cacheable, unlinking %s",c->filename); +/* close the file */ + if (c->fp != NULL) + { + pclosef(r->pool, c->fp->fd); + c->fp = NULL; + } +/* delete the previously cached file */ + unlink(c->filename); + return DECLINED; /* send data to client but not cache */ + } + +/* otherwise, we are going to cache the response */ +/* + * Read the date. Generate one if one is not supplied + */ + dates = proxy_get_header(resp_hdrs, "Date"); + if (dates != NULL) date = parseHTTPdate(dates->value); + else date = BAD_DATE; + + now = time(NULL); + + if (date == BAD_DATE) /* No, or bad date */ + { +/* no date header! */ +/* add one; N.B. use the time _now_ rather than when we were checking the cache + */ + date = abs(now); + p = gm_timestr_822(r->pool, now); + dates = proxy_add_header(resp_hdrs, "Date", p, HDR_REP); + Explain0("Added date header"); + } + +/* check last-modified date */ + if (lmod != BAD_DATE && lmod > date) +/* if its in the future, then replace by date */ + { + lmod = date; + lmods->value = dates->value; + Explain0("Last modified is in the future, replacing with now"); + } +/* if the response did not contain the header, then use the cached version */ + if (lmod == BAD_DATE && c->fp != NULL) + { + lmod = c->lmod; + Explain0("Reusing cached last modified"); + } + +/* we now need to calculate the expire data for the object. */ + if (expire == NULL && c->fp != NULL) /* no expiry data sent in response */ + { + expire = proxy_get_header(c->hdrs, "Expires"); + if (expire != NULL) expc = parseHTTPdate(expire->value); + } +/* so we now have the expiry date */ +/* if no expiry date then + * if lastmod + * expiry date = now + min((date - lastmod) * factor, maxexpire) + * else + * expire date = now + defaultexpire + */ + Explain1("Expiry date is %ld",expc); + if (expc == BAD_DATE) + { + if (lmod != BAD_DATE) + { + double x = (double)(date - lmod)*conf->cache.lmfactor; + double maxex=conf->cache.maxexpire; + if (x > maxex) x = maxex; + expc = abs(now) + (int)x; + } else + expc = abs(now) + conf->cache.defaultexpire; + Explain1("Expiry date calculated %ld",expc); + } + +/* get the content-length header */ + clen = proxy_get_header(c->hdrs, "Content-Length"); + if (clen == NULL) c->len = -1; + else c->len = atoi(clen->value); + + proxy_sec2hex(date, buff); + buff[8] = ' '; + proxy_sec2hex(lmod, buff+9); + buff[17] = ' '; + proxy_sec2hex(expc, buff+18); + buff[26] = ' '; + proxy_sec2hex(c->version++, buff+27); + buff[35] = ' '; + proxy_sec2hex(c->len, buff+36); + buff[44] = '\n'; + buff[45] = '\0'; + +/* if file not modified */ + if (r->status == 304) + { + if (c->ims != BAD_DATE && lmod != BAD_DATE && lmod <= c->ims) + { +/* set any changed headers somehow */ +/* update dates and version, but not content-length */ + if (lmod != c->lmod || expc != c->expire || date != c->date) + { + off_t curpos=lseek(c->fp->fd, 0, SEEK_SET); + if (curpos == -1) + proxy_log_uerror("lseek", c->filename, + "proxy: error seeking on cache file",r->server); + else if (write(c->fp->fd, buff, 35) == -1) + proxy_log_uerror("write", c->filename, + "proxy: error updating cache file", r->server); + } + pclosef(r->pool, c->fp->fd); + Explain0("Remote document not modified, use local copy"); + /* CHECKME: Is this right? Shouldn't we check IMS again here? */ + return USE_LOCAL_COPY; + } else + { +/* return the whole document */ + Explain0("Remote document updated, sending"); + r->status_line = strchr(c->resp_line, ' ') + 1; + r->status = c->status; + if (!r->assbackwards) { + soft_timeout("proxy send headers", r); + proxy_send_headers(r->connection->client, c->resp_line, + c->hdrs); + kill_timeout(r); + } + bsetopt(r->connection->client, BO_BYTECT, &zero); + r->sent_bodyct = 1; + if (!r->header_only) proxy_send_fb (c->fp, r, NULL, NULL); +/* set any changed headers somehow */ +/* update dates and version, but not content-length */ + if (lmod != c->lmod || expc != c->expire || date != c->date) + { + off_t curpos=lseek(c->fp->fd, 0, SEEK_SET); + + if (curpos == -1) + proxy_log_uerror("lseek", c->filename, + "proxy: error seeking on cache file",r->server); + else if (write(c->fp->fd, buff, 35) == -1) + proxy_log_uerror("write", c->filename, + "proxy: error updating cache file", r->server); + } + pclosef(r->pool, c->fp->fd); + return OK; + } + } +/* new or modified file */ + if (c->fp != NULL) + { + pclosef(r->pool, c->fp->fd); + c->fp->fd = -1; + } + c->version = 0; + proxy_sec2hex(0, buff+27); + buff[35] = ' '; + +/* open temporary file */ +#define TMPFILESTR "/tmpXXXXXX" + if (conf->cache.root == NULL) + return DECLINED; + c->tempfile=palloc(r->pool,strlen(conf->cache.root)+sizeof(TMPFILESTR)); + strcpy(c->tempfile,conf->cache.root); + strcat(c->tempfile,TMPFILESTR); +#undef TMPFILESTR + p = mktemp(c->tempfile); + if (p == NULL) + return DECLINED; + + Explain1("Create temporary file %s",c->tempfile); + + i = open(c->tempfile, O_WRONLY | O_CREAT | O_EXCL, 0622); + if (i == -1) + { + proxy_log_uerror("open", c->tempfile, + "proxy: error creating cache file", r->server); + return DECLINED; + } + note_cleanups_for_fd(r->pool, i); + c->fp = bcreate(r->pool, B_WR); + bpushfd(c->fp, -1, i); + + if (bvputs(c->fp, buff, "X-URL: ", c->url, "\n", NULL) == -1) + { + proxy_log_uerror("write", c->tempfile, + "proxy: error writing cache file", r->server); + pclosef(r->pool, c->fp->fd); + unlink(c->tempfile); + c->fp = NULL; + } + return DECLINED; +} + +void +proxy_cache_tidy(struct cache_req *c) +{ + server_rec *s=c->req->server; + long int bc; + + if (c->fp == NULL) return; + + bgetopt(c->req->connection->client, BO_BYTECT, &bc); + + if (c->len != -1) + { +/* file lengths don't match; don't cache it */ + if (bc != c->len) + { + pclosef(c->req->pool, c->fp->fd); /* no need to flush */ + unlink(c->tempfile); + return; + } + } else + if (c->req->connection->aborted) { + pclosef(c->req->pool, c->fp->fd); /* no need to flush */ + unlink(c->tempfile); + return; + } else + { +/* update content-length of file */ + char buff[9]; + off_t curpos; + + c->len = bc; + bflush(c->fp); + proxy_sec2hex(c->len, buff); + curpos = lseek(c->fp->fd, 36, SEEK_SET); + if (curpos == -1) + proxy_log_uerror("lseek", c->tempfile, + "proxy: error seeking on cache file", s); + else if (write(c->fp->fd, buff, 8) == -1) + proxy_log_uerror("write", c->tempfile, + "proxy: error updating cache file", s); + } + + if (bflush(c->fp) == -1) + { + proxy_log_uerror("write", c->tempfile, + "proxy: error writing to cache file", s); + pclosef(c->req->pool, c->fp->fd); + unlink(c->tempfile); + return; + } + + if (pclosef(c->req->pool, c->fp->fd) == -1) + { + proxy_log_uerror("close", c->tempfile, + "proxy: error closing cache file", s); + unlink(c->tempfile); + return; + } + + if (unlink(c->filename) == -1 && errno != ENOENT) + { + proxy_log_uerror("unlink", c->filename, + "proxy: error deleting old cache file", s); + } else + { + char *p; + proxy_server_conf *conf= + (proxy_server_conf *)get_module_config(s->module_config,&proxy_module); + + for(p=c->filename+strlen(conf->cache.root)+1 ; ; ) + { + p=strchr(p,'/'); + if(!p) + break; + *p='\0'; + if(mkdir(c->filename,S_IREAD|S_IWRITE|S_IEXEC) < 0 && errno != EEXIST) + proxy_log_uerror("mkdir",c->filename, + "proxy: error creating cache directory",s); + *p='/'; + ++p; + } +#ifdef __EMX__ + /* Under OS/2 use rename. */ + if (rename(c->tempfile, c->filename) == -1) + proxy_log_uerror("rename", c->filename, + "proxy: error renaming cache file", s); +} +#else + + if (link(c->tempfile, c->filename) == -1) + proxy_log_uerror("link", c->filename, + "proxy: error linking cache file", s); + } + + if (unlink(c->tempfile) == -1) + proxy_log_uerror("unlink", c->tempfile, + "proxy: error deleting temp file",s); +#endif + +} + diff --git a/APACHE_1_2_X/src/modules/proxy/proxy_connect.c b/APACHE_1_2_X/src/modules/proxy/proxy_connect.c new file mode 100644 index 00000000000..ba120271b66 --- /dev/null +++ b/APACHE_1_2_X/src/modules/proxy/proxy_connect.c @@ -0,0 +1,228 @@ +/* ==================================================================== + * Copyright (c) 1996,1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* CONNECT method SSL handling for Apache proxy */ + +#include "mod_proxy.h" +#include "http_log.h" +#include "http_main.h" + +#ifdef HAVE_BSTRING_H +#include /* for IRIX, FD_SET calls bzero() */ +#endif + +/* + * This handles Netscape CONNECT method secure proxy requests. + * A connection is opened to the specified host and data is + * passed through between the WWW site and the browser. + * + * This code is based on the INTERNET-DRAFT document + * "Tunneling SSL Through a WWW Proxy" currently at + * http://www.mcom.com/newsref/std/tunneling_ssl.html. + * + * FIXME: this is bad, because it does its own socket I/O + * instead of using the I/O in buff.c. However, + * the I/O in buff.c blocks on reads, and because + * this function doesn't know how much data will + * be sent either way (or when) it can't use blocking + * I/O. This may be very implementation-specific + * (to Linux). Any suggestions? + * FIXME: this doesn't log the number of bytes sent, but + * that may be okay, since the data is supposed to + * be transparent. In fact, this doesn't log at all + * yet. 8^) + * FIXME: doesn't check any headers initally sent from the + * client. + * FIXME: should allow authentication, but hopefully the + * generic proxy authentication is good enough. + * FIXME: no check for r->assbackwards, whatever that is. + */ + +int +proxy_connect_handler(request_rec *r, struct cache_req *c, char *url) +{ + struct sockaddr_in server; + struct in_addr destaddr; + struct hostent server_hp; + const char *host, *err; + char *p; + int port, sock; + char buffer[HUGE_STRING_LEN]; + int nbytes, i, j; + fd_set fds; + + void *sconf = r->server->module_config; + proxy_server_conf *conf = + (proxy_server_conf *)get_module_config(sconf, &proxy_module); + struct noproxy_entry *npent=(struct noproxy_entry *)conf->noproxies->elts; + + memset(&server, '\0', sizeof(server)); + server.sin_family=AF_INET; + + /* Break the URL into host:port pairs */ + + host = url; + p = strchr(url, ':'); + if (p==NULL) + port = DEFAULT_HTTPS_PORT; + else + { + port = atoi(p+1); + *p='\0'; + } + +/* check if ProxyBlock directive on this host */ + destaddr.s_addr = inet_addr(host); + for (i=0; i < conf->noproxies->nelts; i++) + { + if ((npent[i].name != NULL && strstr(host, npent[i].name) != NULL) + || destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*') + return proxyerror(r, "Connect to remote machine blocked"); + } + + switch (port) + { + case DEFAULT_HTTPS_PORT: + case DEFAULT_SNEWS_PORT: + break; + default: + return HTTP_SERVICE_UNAVAILABLE; + } + + Explain2("CONNECT to %s on port %d", host, port); + + server.sin_port = htons(port); + err = proxy_host2addr(host, &server_hp); + if (err != NULL) + return proxyerror(r, err); /* give up */ + + sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock == -1) + { + log_error("proxy: error creating socket", r->server); + return SERVER_ERROR; + } + note_cleanups_for_fd(r->pool, sock); + + j = 0; + while (server_hp.h_addr_list[j] != NULL) { + memcpy(&server.sin_addr, server_hp.h_addr_list[j], + sizeof(struct in_addr)); + i = proxy_doconnect(sock, &server, r); + if (i == 0) + break; + j++; + } + if (i == -1 ) + return proxyerror(r, "Could not connect to remote machine"); + + Explain0("Returning 200 OK Status"); + + rvputs(r, "HTTP/1.0 200 Connection established\015\012", NULL); + rvputs(r, "Proxy-agent: ", SERVER_VERSION, "\015\012\015\012", NULL); + bflush(r->connection->client); + + while (1) /* Infinite loop until error (one side closes the connection) */ + { + FD_ZERO(&fds); + FD_SET(sock, &fds); + FD_SET(r->connection->client->fd, &fds); + + Explain0("Going to sleep (select)"); + i = select((r->connection->client->fd > sock ? + r->connection->client->fd+1 : +#ifdef HPUX + sock+1), (int*)&fds, NULL, NULL, NULL); +#else + sock+1), &fds, NULL, NULL, NULL); +#endif + Explain1("Woke from select(), i=%d",i); + + if (i) + { + if (FD_ISSET(sock, &fds)) + { + Explain0("sock was set"); + if((nbytes=read(sock,buffer,HUGE_STRING_LEN))!=0) + { + if (nbytes==-1) + break; + if (write(r->connection->client->fd, buffer, nbytes)==EOF) + break; + Explain1("Wrote %d bytes to client", nbytes); + } + else break; + } + else if (FD_ISSET(r->connection->client->fd, &fds)) + { + Explain0("client->fd was set"); + if((nbytes=read(r->connection->client->fd,buffer, + HUGE_STRING_LEN))!=0) + { + if (nbytes==-1) + break; + if (write(sock,buffer,nbytes)==EOF) + break; + Explain1("Wrote %d bytes to server", nbytes); + } + else break; + } + else break; /* Must be done waiting */ + } + else break; + } + + pclosef(r->pool,sock); + + return OK; +} + diff --git a/APACHE_1_2_X/src/modules/proxy/proxy_ftp.c b/APACHE_1_2_X/src/modules/proxy/proxy_ftp.c new file mode 100644 index 00000000000..a0f0d5e1ae1 --- /dev/null +++ b/APACHE_1_2_X/src/modules/proxy/proxy_ftp.c @@ -0,0 +1,1014 @@ +/* ==================================================================== + * Copyright (c) 1996,1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* FTP routines for Apache proxy */ + +#include "mod_proxy.h" +#include "http_main.h" + +extern int find_ct(request_rec *r); + +/* + * Decodes a '%' escaped string, and returns the number of characters + */ +static int +decodeenc(char *x) +{ + int i, j, ch; + + if (x[0] == '\0') return 0; /* special case for no characters */ + for (i=0, j=0; x[i] != '\0'; i++, j++) + { +/* decode it if not already done */ + ch = x[i]; + if ( ch == '%' && isxdigit(x[i+1]) && isxdigit(x[i+2])) + { + ch = proxy_hex2c(&x[i+1]); + i += 2; + } + x[j] = ch; + } + x[j] = '\0'; + return j; +} + +/* + * checks an encoded ftp string for bad characters, namely, CR, LF or + * non-ascii character + */ +static int +ftp_check_string(const char *x) +{ + int i, ch; + + for (i=0; x[i] != '\0'; i++) + { + ch = x[i]; + if ( ch == '%' && isxdigit(x[i+1]) && isxdigit(x[i+2])) + { + ch = proxy_hex2c(&x[i+1]); + i += 2; + } + if (ch == '\015' || ch == '\012' || (ch & 0x80)) return 0; + } + return 1; +} + +/* + * Canonicalise ftp URLs. + */ +int +proxy_ftp_canon(request_rec *r, char *url) +{ + char *user, *password, *host, *path, *parms, *p, sport[7]; + pool *pool=r->pool; + const char *err; + int port; + + port = DEFAULT_FTP_PORT; + err = proxy_canon_netloc(pool, &url, &user, &password, &host, &port); + if (err) return BAD_REQUEST; + if (user != NULL && !ftp_check_string(user)) return BAD_REQUEST; + if (password != NULL && !ftp_check_string(password)) return BAD_REQUEST; + +/* now parse path/parameters args, according to rfc1738 */ +/* N.B. if this isn't a true proxy request, then the URL path + * (but not query args) has already been decoded. + * This gives rise to the problem of a ; being decoded into the + * path. + */ + p = strchr(url, ';'); + if (p != NULL) + { + *(p++) = '\0'; + parms = proxy_canonenc(pool, p, strlen(p), enc_parm, r->proxyreq); + if (parms == NULL) return BAD_REQUEST; + } else + parms = ""; + + path = proxy_canonenc(pool, url, strlen(url), enc_path, r->proxyreq); + if (path == NULL) return BAD_REQUEST; + if (!ftp_check_string(path)) return BAD_REQUEST; + + if (!r->proxyreq && r->args != NULL) + { + if (p != NULL) + { + p = proxy_canonenc(pool, r->args, strlen(r->args), enc_parm, 1); + if (p == NULL) return BAD_REQUEST; + parms = pstrcat(pool, parms, "?", p, NULL); + } + else + { + p = proxy_canonenc(pool, r->args, strlen(r->args), enc_fpath, 1); + if (p == NULL) return BAD_REQUEST; + path = pstrcat(pool, path, "?", p, NULL); + } + r->args = NULL; + } + +/* now, rebuild URL */ + + if (port != DEFAULT_FTP_PORT) ap_snprintf(sport, sizeof(sport), ":%d", port); + else sport[0] = '\0'; + + r->filename = pstrcat(pool, "proxy:ftp://", (user != NULL) ? user : "", + (password != NULL) ? ":" : "", + (password != NULL) ? password : "", + (user != NULL) ? "@" : "", host, sport, "/", path, + (parms[0] != '\0') ? ";" : "", parms, NULL); + + return OK; +} + +/* + * Returns the ftp status code; + * or -1 on I/O error, 0 on data error + */ +static int +ftp_getrc(BUFF *f) +{ + int i, len, status; + char linebuff[100], buff[5]; + + len = bgets(linebuff, 100, f); + if (len == -1) return -1; +/* check format */ + if (len < 5 || !isdigit(linebuff[0]) || !isdigit(linebuff[1]) || + !isdigit(linebuff[2]) || (linebuff[3] != ' ' && linebuff[3] != '-')) + status = 0; + else + status = 100 * linebuff[0] + 10 * linebuff[1] + linebuff[2] - 111 * '0'; + + if (linebuff[len-1] != '\n') + { + i = bskiplf(f); + } + +/* skip continuation lines */ + if (linebuff[3] == '-') + { + memcpy(buff, linebuff, 3); + buff[3] = ' '; + do + { + len = bgets(linebuff, 100, f); + if (len == -1) return -1; + if (linebuff[len-1] != '\n') + { + i = bskiplf(f); + } + } while (memcmp(linebuff, buff, 4) != 0); + } + + return status; +} + +static char * +encode_space(request_rec *r, char *path) +{ + pool *pool=r->pool; + char *newpath; + int i, j, len; + + len = strlen(path); + newpath = palloc(pool, 3 * len + 1); + for (i=0, j=0; i < len; i++, j++) { + if (path[i] != ' ') + newpath[j] = path[i]; + else { + proxy_c2hex(' ', &newpath[j]); + j += 2; + } + } + newpath[j] = '\0'; + return newpath; +} + +static long int +send_dir(BUFF *f, request_rec *r, BUFF *f2, struct cache_req *c, char *url) +{ + char buf[IOBUFSIZE]; + char buf2[IOBUFSIZE]; + char *filename; + char *tempurl; + char *newurlptr; + int searchidx = 0; + char *searchptr = NULL; + int firstfile = 1; + char urlptr[HUGE_STRING_LEN]; + long total_bytes_sent; + register int n, o, w; + conn_rec *con = r->connection; + + tempurl = pstrdup(r->pool, url); + if ((n = strcspn(tempurl, "@")) != strlen(tempurl)) /* hide user/passwd */ + { + memmove(tempurl + (n - 5), tempurl, 6); + tempurl += n - 5; /* leave room for ftp:// */ + } + + n = decodeenc(tempurl); + ap_snprintf(buf, sizeof(buf), "%s

    Directory %s


    ", tempurl, tempurl);
    +    bwrite(con->client, buf, strlen(buf));
    +    if (f2 != NULL) bwrite(f2, buf, strlen(buf));
    +    total_bytes_sent=strlen(buf);
    +    while(!con->aborted)
    +    {
    +        n = bgets(buf, IOBUFSIZE, f);
    +        if (n == -1) /* input error */
    +        {
    +            if (f2 != NULL) f2 = proxy_cache_error(c);
    +            break;
    +        }
    +        if (n == 0) break; /* EOF */
    +        if(buf[0]=='l')
    +        {
    +            char *link;
    +
    +            link=strstr(buf, " -> ");
    +            filename=link;
    +            do filename--; while (filename[0]!=' ');
    +            *(filename++)=0;
    +            *(link++)=0;
    +            ap_snprintf(urlptr, sizeof(urlptr), "%s%s%s",url,(url[strlen(url)-1]=='/' ? "" : "/"), filename);
    +            ap_snprintf(buf2, sizeof(urlptr), "%s %s %s\015\012", buf, urlptr, filename, link);
    +            strncpy(buf, buf2, sizeof(buf)-1);
    +	    buf[sizeof(buf)-1] = '\0';
    +            n=strlen(buf);
    +        }
    +        else if(buf[0]=='d' || buf[0]=='-' || buf[0]=='l' || isdigit(buf[0]))
    +        {
    +	    if(isdigit(buf[0])) {		/* handle DOS dir */
    +	        searchptr = strchr(buf, '<');
    +	        if(searchptr != NULL)
    +		    *searchptr = '[';
    +	        searchptr = strchr(buf, '>');
    +	        if(searchptr != NULL)
    +		    *searchptr = ']';
    +	    }
    +		
    +            filename=strrchr(buf, ' ');
    +            *(filename++)=0;
    +            filename[strlen(filename)-1]=0;
    +
    +            /* handle filenames with spaces in 'em */
    +            if(!strcmp(filename, ".") || !strcmp(filename, "..") || firstfile) {
    +		firstfile = 0;
    +                searchidx = filename - buf;
    +            }
    +            else if (searchidx != 0 && buf[searchidx] != 0) {
    +                *(--filename) = ' ';
    +                buf[searchidx - 1] = 0;
    +                filename = &buf[searchidx];    
    +            }   
    +
    +            /* Special handling for '.' and '..' */
    +            if (!strcmp(filename, "."))
    +            {
    +                ap_snprintf(urlptr, sizeof(urlptr), "%s",url);
    +                ap_snprintf(buf2, sizeof(buf2), "%s %s\015\012", buf, urlptr, filename);
    +            }
    +            else if (!strcmp(filename, ".."))
    +            {
    +                char temp[200];
    +                char newpath[200];
    +                char *method, *host, *path, *newfile;
    +   
    +                strncpy(temp, url, sizeof(temp)-1);
    +		temp[sizeof(temp)-1] = '\0';
    +                method=temp;
    +
    +                host=strchr(method,':');
    +                if (host == NULL) host="";
    +                else *(host++)=0;
    +                host++; host++;
    +                
    +                path=strchr(host,'/');
    +                if (path == NULL) path="";
    +                else *(path++)=0;
    +                
    +                strncpy(newpath, path, sizeof(newpath)-1);
    +		newpath[sizeof(newpath)-1] = '\0';
    +                newfile=strrchr(newpath,'/');
    +                if (newfile) *(newfile)=0;
    +                else newpath[0]=0;
    +
    +                ap_snprintf(urlptr, sizeof(urlptr), "%s://%s/%s",method,host,newpath);
    +                ap_snprintf(buf2, sizeof(buf2), "%s %s\015\012", buf, urlptr, filename);
    +            }
    +            else 
    +            {
    +                ap_snprintf(urlptr, sizeof(urlptr), "%s%s%s",url,(url[strlen(url)-1]=='/' ? "" : "/"), filename);
    +		newurlptr = encode_space(r, urlptr);
    +                ap_snprintf(buf2, sizeof(buf2), "%s %s\015\012", buf, newurlptr, filename);
    +            }
    +            strncpy(buf, buf2, sizeof(buf));
    +	    buf[sizeof(buf)-1] = '\0';
    +            n=strlen(buf);
    +        }      
    +
    +        o=0;
    +	total_bytes_sent += n;
    +
    +	if (f2 != NULL)
    +	    if (bwrite(f2, buf, n) != n) f2 = proxy_cache_error(c);
    +	
    +        while(n && !r->connection->aborted) {
    +            w = bwrite(con->client, &buf[o], n);
    +	    if (w <= 0)
    +		break;
    +	    reset_timeout(r); /* reset timeout after successfule write */
    +            n-=w;
    +            o+=w;
    +        }
    +    }
    +    ap_snprintf(buf, sizeof(buf), "

    %s", SERVER_VERSION); + bwrite(con->client, buf, strlen(buf)); + if (f2 != NULL) bwrite(f2, buf, strlen(buf)); + total_bytes_sent+=strlen(buf); + bflush(con->client); + + return total_bytes_sent; +} + +/* + * Handles direct access of ftp:// URLs + * Original (Non-PASV) version from + * Troy Morrison + * PASV added by Chuck + */ +int +proxy_ftp_handler(request_rec *r, struct cache_req *c, char *url) +{ + char *host, *path, *p, *user, *password, *parms; + const char *err; + int port, userlen, i, j, len, sock, dsock, rc, nocache; + int passlen = 0; + int csd = 0; + struct sockaddr_in server; + struct hostent server_hp; + struct hdr_entry *hdr; + struct in_addr destaddr; + array_header *resp_hdrs; + BUFF *f, *cache; + BUFF *data = NULL; + pool *pool=r->pool; + const int one=1; + const long int zero=0L; + + void *sconf = r->server->module_config; + proxy_server_conf *conf = + (proxy_server_conf *)get_module_config(sconf, &proxy_module); + struct noproxy_entry *npent=(struct noproxy_entry *)conf->noproxies->elts; + struct nocache_entry *ncent=(struct nocache_entry *)conf->nocaches->elts; + +/* stuff for PASV mode */ + unsigned int presult, h0, h1, h2, h3, p0, p1; + unsigned int paddr; + unsigned short pport; + struct sockaddr_in data_addr; + int pasvmode = 0; + char pasv[64]; + char *pstr; + +/* we only support GET and HEAD */ + + if (r->method_number != M_GET) return NOT_IMPLEMENTED; + +/* We break the URL into host, port, path-search */ + + host = pstrdup(pool, url + 6); + port = DEFAULT_FTP_PORT; + path = strchr(host, '/'); + if (path == NULL) + path = ""; + else + *(path++) = '\0'; + + user = password = NULL; + nocache = 0; + p = strchr(host, '@'); + if (p != NULL) + { + (*p++) = '\0'; + user = host; + host = p; +/* find password */ + p = strchr(user, ':'); + if (p != NULL) + { + *(p++) = '\0'; + password = p; + passlen = decodeenc(password); + } + userlen = decodeenc(user); + nocache = 1; /* don't cache when a username is supplied */ + } else + { + user = "anonymous"; + userlen = 9; + + password = "apache_proxy@"; + passlen = strlen(password); + } + + p = strchr(host, ':'); + if (p != NULL) + { + *(p++) = '\0'; + if (isdigit(*p)) + port = atoi(p); + } + +/* check if ProxyBlock directive on this host */ + destaddr.s_addr = inet_addr(host); + for (i=0; i < conf->noproxies->nelts; i++) + { + if ((npent[i].name != NULL && strstr(host, npent[i].name) != NULL) + || destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*') + return proxyerror(r, "Connect to remote machine blocked"); + } + + Explain2("FTP: connect to %s:%d",host,port); + + parms = strchr(path, ';'); + if (parms != NULL) *(parms++) = '\0'; + + memset(&server, 0, sizeof(struct sockaddr_in)); + server.sin_family = AF_INET; + server.sin_port = htons(port); + err = proxy_host2addr(host, &server_hp); + if (err != NULL) return proxyerror(r, err); /* give up */ + + sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock == -1) + { + proxy_log_uerror("socket", NULL, "proxy: error creating socket", + r->server); + return SERVER_ERROR; + } + note_cleanups_for_fd(pool, sock); + + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&one, + sizeof(int)) == -1) + { + proxy_log_uerror("setsockopt", NULL, + "proxy: error setting reuseaddr option", r->server); + pclosef(pool, sock); + return SERVER_ERROR; + } + + j = 0; + while (server_hp.h_addr_list[j] != NULL) { + memcpy(&server.sin_addr, server_hp.h_addr_list[j], + sizeof(struct in_addr)); + i = proxy_doconnect(sock, &server, r); + if (i == 0) + break; + j++; + } + if (i == -1) + return proxyerror(r, "Could not connect to remote machine"); + + f = bcreate(pool, B_RDWR); + bpushfd(f, sock, sock); +/* shouldn't we implement telnet control options here? */ + +/* possible results: 120, 220, 421 */ + hard_timeout ("proxy ftp", r); + i = ftp_getrc(f); + Explain1("FTP: returned status %d", i); + if (i == -1) { + kill_timeout(r); + return proxyerror(r, "Error reading from remote server"); + } + if (i != 220) { + kill_timeout(r); + return BAD_GATEWAY; + } + + Explain0("FTP: connected."); + + bputs("USER ", f); + bwrite(f, user, userlen); + bputs("\015\012", f); + bflush(f); /* capture any errors */ + Explain1("FTP: USER %s",user); + +/* possible results; 230, 331, 332, 421, 500, 501, 530 */ +/* states: 1 - error, 2 - success; 3 - send password, 4,5 fail */ + i = ftp_getrc(f); + Explain1("FTP: returned status %d",i); + if (i == -1) { + kill_timeout(r); + return proxyerror(r, "Error sending to remote server"); + } + if (i == 530) { + kill_timeout(r); + return proxyerror(r, "Not logged in"); + } + if (i != 230 && i != 331) { + kill_timeout(r); + return BAD_GATEWAY; + } + + if (i == 331) /* send password */ + { + if (password == NULL) return FORBIDDEN; + bputs("PASS ", f); + bwrite(f, password, passlen); + bputs("\015\012", f); + bflush(f); + Explain1("FTP: PASS %s",password); +/* possible results 202, 230, 332, 421, 500, 501, 503, 530 */ + i = ftp_getrc(f); + Explain1("FTP: returned status %d",i); + if (i == -1) { + kill_timeout(r); + return proxyerror(r, "Error sending to remote server"); + } + if (i == 332) { + kill_timeout(r); + return proxyerror(r, "Need account for login"); + } + if (i == 530) { + kill_timeout(r); + return proxyerror(r, "Not logged in"); + } + if (i != 230 && i != 202) { + kill_timeout(r); + return BAD_GATEWAY; + } + } + +/* set the directory */ +/* this is what we must do if we don't know the OS type of the remote + * machine + */ + for (;;) + { + p = strchr(path, '/'); + if (p == NULL) break; + *p = '\0'; + + len = decodeenc(path); + bputs("CWD ", f); + bwrite(f, path, len); + bputs("\015\012", f); + bflush(f); + Explain1("FTP: CWD %s",path); +/* responses: 250, 421, 500, 501, 502, 530, 550 */ +/* 1,3 error, 2 success, 4,5 failure */ + i = ftp_getrc(f); + Explain1("FTP: returned status %d",i); + if (i == -1) { + kill_timeout(r); + return proxyerror(r, "Error sending to remote server"); + } + if (i == 550) { + kill_timeout(r); + return NOT_FOUND; + } + if (i != 250) { + kill_timeout(r); + return BAD_GATEWAY; + } + + path = p + 1; + } + + if (parms != NULL && strncmp(parms, "type=", 5) == 0) + { + parms += 5; + if ((parms[0] != 'd' && parms[0] != 'a' && parms[0] != 'i') || + parms[1] != '\0') parms = ""; + } + else parms = ""; + + /* changed to make binary transfers the default */ + + if (parms[0] != 'a') + { + /* set type to image */ + /* TM - Added \015\012 to the end of TYPE I, otherwise it hangs the + connection */ + bputs("TYPE I\015\012", f); + bflush(f); + Explain0("FTP: TYPE I"); +/* responses: 200, 421, 500, 501, 504, 530 */ + i = ftp_getrc(f); + Explain1("FTP: returned status %d",i); + if (i == -1) { + kill_timeout(r); + return proxyerror(r, "Error sending to remote server"); + } + if (i != 200 && i != 504) { + kill_timeout(r); + return BAD_GATEWAY; + } +/* Allow not implemented */ + if (i == 504) + parms[0] = '\0'; + } + +/* try to set up PASV data connection first */ + dsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (dsock == -1) + { + proxy_log_uerror("socket", NULL, "proxy: error creating PASV socket", + r->server); + pclosef(pool, sock); + kill_timeout(r); + return SERVER_ERROR; + } + note_cleanups_for_fd(pool, dsock); + + bputs("PASV\015\012", f); + bflush(f); + Explain0("FTP: PASV command issued"); +/* possible results: 227, 421, 500, 501, 502, 530 */ + i = bgets(pasv, sizeof(pasv), f); + + if (i == -1) + { + proxy_log_uerror("command", NULL, "PASV: control connection is toast", + r->server); + pclosef(pool, dsock); + pclosef(pool, sock); + kill_timeout(r); + return SERVER_ERROR; + } else + { + pasv[i-1] = '\0'; + pstr = strtok(pasv, " "); /* separate result code */ + if (pstr != NULL) + { + presult = atoi(pstr); + pstr = strtok(NULL, "("); /* separate address & port params */ + if (pstr != NULL) + pstr = strtok(NULL, ")"); + } + else + presult = atoi(pasv); + + Explain1("FTP: returned status %d", presult); + + if (presult == 227 && pstr != NULL && (sscanf(pstr, + "%d,%d,%d,%d,%d,%d", &h3, &h2, &h1, &h0, &p1, &p0) == 6)) + { + /* pardon the parens, but it makes gcc happy */ + paddr = (((((h3 << 8) + h2) << 8) + h1) << 8) + h0; + pport = (p1 << 8) + p0; + Explain5("FTP: contacting host %d.%d.%d.%d:%d", + h3, h2, h1, h0, pport); + data_addr.sin_family = AF_INET; + data_addr.sin_addr.s_addr = htonl(paddr); + data_addr.sin_port = htons(pport); + i = proxy_doconnect(dsock, &data_addr, r); + + if (i == -1) { + kill_timeout(r); + return proxyerror(r, "Could not connect to remote machine"); + } + else { + data = bcreate(pool, B_RDWR); + bpushfd(data, dsock, dsock); + pasvmode = 1; + } + } else + pclosef(pool, dsock); /* and try the regular way */ + } + + if (!pasvmode) /* set up data connection */ + { + len = sizeof(struct sockaddr_in); + if (getsockname(sock, (struct sockaddr *)&server, &len) < 0) + { + proxy_log_uerror("getsockname", NULL, + "proxy: error getting socket address", r->server); + pclosef(pool, sock); + kill_timeout(r); + return SERVER_ERROR; + } + + dsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (dsock == -1) + { + proxy_log_uerror("socket", NULL, "proxy: error creating socket", + r->server); + pclosef(pool, sock); + kill_timeout(r); + return SERVER_ERROR; + } + note_cleanups_for_fd(pool, dsock); + + if (setsockopt(dsock, SOL_SOCKET, SO_REUSEADDR, (const char *)&one, + sizeof(int)) == -1) + { + proxy_log_uerror("setsockopt", NULL, + "proxy: error setting reuseaddr option", r->server); + pclosef(pool, dsock); + pclosef(pool, sock); + kill_timeout(r); + return SERVER_ERROR; + } + + if (bind(dsock, (struct sockaddr *)&server, + sizeof(struct sockaddr_in)) == -1) + { + char buff[22]; + + ap_snprintf(buff, sizeof(buff), "%s:%d", inet_ntoa(server.sin_addr), server.sin_port); + proxy_log_uerror("bind", buff, + "proxy: error binding to ftp data socket", r->server); + pclosef(pool, sock); + pclosef(pool, dsock); + } + listen(dsock, 2); /* only need a short queue */ + } + +/* set request */ + len = decodeenc(path); + + /* TM - if len == 0 then it must be a directory (you can't RETR nothing) */ + + if(len==0) + { + parms="d"; + } else + { + bputs("SIZE ", f); + bwrite(f, path, len); + bputs("\015\012", f); + bflush(f); + Explain1("FTP: SIZE %s",path); + i = ftp_getrc(f); + Explain1("FTP: returned status %d", i); + if (i != 500) /* Size command not recognized */ + { + if (i==550) /* Not a regular file */ + { + Explain0("FTP: SIZE shows this is a directory"); + parms="d"; + bputs("CWD ", f); + bwrite(f, path, len); + bputs("\015\012", f); + bflush(f); + Explain1("FTP: CWD %s",path); + i = ftp_getrc(f); + Explain1("FTP: returned status %d", i); + if (i == -1) { + kill_timeout(r); + return proxyerror(r, "Error sending to remote server"); + } + if (i == 550) { + kill_timeout(r); + return NOT_FOUND; + } + if (i != 250) { + kill_timeout(r); + return BAD_GATEWAY; + } + path=""; len=0; + } + } + } + + if (parms[0] == 'd') + { + if (len != 0) bputs("LIST ", f); + else bputs("LIST -lag", f); + Explain1("FTP: LIST %s",(len==0 ? "" : path)); + } + else + { + bputs("RETR ", f); + Explain1("FTP: RETR %s",path); + } + bwrite(f, path, len); + bputs("\015\012", f); + bflush(f); +/* RETR: 110, 125, 150, 226, 250, 421, 425, 426, 450, 451, 500, 501, 530, 550 + NLST: 125, 150, 226, 250, 421, 425, 426, 450, 451, 500, 501, 502, 530 */ + rc = ftp_getrc(f); + Explain1("FTP: returned status %d",rc); + if (rc == -1) { + kill_timeout(r); + return proxyerror(r, "Error sending to remote server"); + } + if (rc == 550) + { + Explain0("FTP: RETR failed, trying LIST instead"); + parms="d"; + bputs("CWD ", f); + bwrite(f, path, len); + bputs("\015\012", f); + bflush(f); + Explain1("FTP: CWD %s", path); + rc = ftp_getrc(f); + Explain1("FTP: returned status %d", rc); + if (rc == -1) { + kill_timeout(r); + return proxyerror(r, "Error sending to remote server"); + } + if (rc == 550) { + kill_timeout(r); + return NOT_FOUND; + } + if (rc != 250) { + kill_timeout(r); + return BAD_GATEWAY; + } + + bputs("LIST -lag\015\012", f); + bflush(f); + Explain0("FTP: LIST -lag"); + rc = ftp_getrc(f); + Explain1("FTP: returned status %d", rc); + if (rc == -1) return proxyerror(r, "Error sending to remote server"); + } + kill_timeout(r); + if (rc != 125 && rc != 150 && rc != 226 && rc != 250) return BAD_GATEWAY; + + r->status = 200; + r->status_line = "200 OK"; + + resp_hdrs = make_array(pool, 2, sizeof(struct hdr_entry)); + if (parms[0] == 'd') + proxy_add_header(resp_hdrs, "Content-Type", "text/html", HDR_REP); + else + { + find_ct(r); + if(r->content_type != NULL) + { + proxy_add_header(resp_hdrs, "Content-Type", r->content_type, + HDR_REP); + Explain1("FTP: Content-Type set to %s",r->content_type); + } else + { + proxy_add_header(resp_hdrs, "Content-Type", "text/plain", HDR_REP); + } + } + +/* check if NoCache directive on this host */ + for (i=0; i < conf->nocaches->nelts; i++) + { + if ((ncent[i].name != NULL && strstr(host, ncent[i].name) != NULL) + || destaddr.s_addr == ncent[i].addr.s_addr || ncent[i].name[0] == '*') + nocache = 1; + } + + i = proxy_cache_update(c, resp_hdrs, "FTP", nocache); + + if (i != DECLINED) + { + pclosef(pool, dsock); + pclosef(pool, sock); + return i; + } + cache = c->fp; + + if (!pasvmode) /* wait for connection */ + { + hard_timeout ("proxy ftp data connect", r); + len = sizeof(struct sockaddr_in); + do csd = accept(dsock, (struct sockaddr *)&server, &len); + while (csd == -1 && errno == EINTR); + if (csd == -1) + { + proxy_log_uerror("accept", NULL, + "proxy: failed to accept data connection", r->server); + pclosef(pool, dsock); + pclosef(pool, sock); + kill_timeout(r); + proxy_cache_error(c); + return BAD_GATEWAY; + } + note_cleanups_for_fd(pool, csd); + data = bcreate(pool, B_RDWR); + bpushfd(data, csd, -1); + kill_timeout(r); + } + + hard_timeout ("proxy receive", r); +/* send response */ +/* write status line */ + if (!r->assbackwards) + rvputs(r, SERVER_PROTOCOL, " ", r->status_line, "\015\012", NULL); + if (cache != NULL) + if (bvputs(cache, SERVER_PROTOCOL, " ", r->status_line, "\015\012", + NULL) == -1) + cache = proxy_cache_error(c); + +/* send headers */ + len = resp_hdrs->nelts; + hdr = (struct hdr_entry *)resp_hdrs->elts; + for (i=0; i < len; i++) + { + if (hdr[i].field == NULL || hdr[i].value == NULL || + hdr[i].value[0] == '\0') continue; + if (!r->assbackwards) + rvputs(r, hdr[i].field, ": ", hdr[i].value, "\015\012", NULL); + if (cache != NULL) + if (bvputs(cache, hdr[i].field, ": ", hdr[i].value, "\015\012", + NULL) == -1) + cache = proxy_cache_error(c); + } + + if (!r->assbackwards) rputs("\015\012", r); + if (cache != NULL) + if (bputs("\015\012", cache) == -1) cache = proxy_cache_error(c); + + bsetopt(r->connection->client, BO_BYTECT, &zero); + r->sent_bodyct = 1; +/* send body */ + if (!r->header_only) + { + if (parms[0] != 'd') proxy_send_fb(data, r, cache, c); + else send_dir(data, r, cache, c, url); + + if (rc == 125 || rc == 150) rc = ftp_getrc(f); + if (rc != 226 && rc != 250) proxy_cache_error(c); + } + else + { +/* abort the transfer */ + bputs("ABOR\015\012", f); + bflush(f); + if (!pasvmode) + pclosef(pool, csd); + Explain0("FTP: ABOR"); +/* responses: 225, 226, 421, 500, 501, 502 */ + i = ftp_getrc(f); + Explain1("FTP: returned status %d",i); + } + + kill_timeout(r); + proxy_cache_tidy(c); + +/* finish */ + bputs("QUIT\015\012", f); + bflush(f); + Explain0("FTP: QUIT"); +/* responses: 221, 500 */ + + if (!pasvmode) + pclosef(pool, csd); + pclosef(pool, dsock); + pclosef(pool, sock); + + proxy_garbage_coll(r); + + return OK; +} + diff --git a/APACHE_1_2_X/src/modules/proxy/proxy_http.c b/APACHE_1_2_X/src/modules/proxy/proxy_http.c new file mode 100644 index 00000000000..4ca9cabfbdd --- /dev/null +++ b/APACHE_1_2_X/src/modules/proxy/proxy_http.c @@ -0,0 +1,414 @@ +/* ==================================================================== + * Copyright (c) 1996,1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* HTTP routines for Apache proxy */ + +#include "mod_proxy.h" +#include "http_log.h" +#include "http_main.h" +#include "util_date.h" + +/* + * Canonicalise http-like URLs. + * scheme is the scheme for the URL + * url is the URL starting with the first '/' + * def_port is the default port for this scheme. + */ +int +proxy_http_canon(request_rec *r, char *url, const char *scheme, int def_port) +{ + char *host, *path, *search, *p, sport[7]; + const char *err; + int port; + +/* do syntatic check. + * We break the URL into host, port, path, search + */ + port = def_port; + err = proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port); + if (err) return BAD_REQUEST; + +/* now parse path/search args, according to rfc1738 */ +/* N.B. if this isn't a true proxy request, then the URL _path_ + * has already been decoded + */ + if (r->proxyreq) + { + p = strchr(url, '?'); + if (p != NULL) *(p++) = '\0'; + } else + p = r->args; + +/* process path */ + path = proxy_canonenc(r->pool, url, strlen(url), enc_path, r->proxyreq); + if (path == NULL) return BAD_REQUEST; + +/* process search */ + if (p != NULL) + { + search = p; + if (search == NULL) return BAD_REQUEST; + } else + search = NULL; + + if (port != def_port) ap_snprintf(sport, sizeof(sport), ":%d", port); + else sport[0] = '\0'; + + r->filename = pstrcat(r->pool, "proxy:", scheme, "://", host, sport, "/", + path, (search) ? "?" : "", (search) ? search : "", NULL); + return OK; +} + +/* Clear all connection-based headers from the incoming headers table */ +static void clear_connection (table *headers) +{ + char *name; + char *next = table_get(headers, "Connection"); + + if (!next) return; + + while (*next) { + name = next; + while (*next && !isspace(*next) && (*next != ',')) ++next; + while (*next && (isspace(*next) || (*next == ','))) { + *next = '\0'; + ++next; + } + table_unset(headers, name); + } + table_unset(headers, "Connection"); +} + +/* + * This handles http:// URLs, and other URLs using a remote proxy over http + * If proxyhost is NULL, then contact the server directly, otherwise + * go via the proxy. + * Note that if a proxy is used, then URLs other than http: can be accessed, + * also, if we have trouble which is clearly specific to the proxy, then + * we return DECLINED so that we can try another proxy. (Or the direct + * route.) + */ +int +proxy_http_handler(request_rec *r, struct cache_req *c, char *url, + const char *proxyhost, int proxyport) +{ + char *p; + const char *err, *desthost; + int i, j, sock, len; + array_header *reqhdrs_arr, *resp_hdrs; + table_entry *reqhdrs; + struct sockaddr_in server; + struct in_addr destaddr; + struct hostent server_hp; + BUFF *f, *cache; + struct hdr_entry *hdr; + char buffer[HUGE_STRING_LEN], inprotocol[9], outprotocol[9]; + pool *pool=r->pool; + const long int zero=0L; + int destport = 0; + char *destportstr = NULL; + + void *sconf = r->server->module_config; + proxy_server_conf *conf = + (proxy_server_conf *)get_module_config(sconf, &proxy_module); + struct noproxy_entry *npent=(struct noproxy_entry *)conf->noproxies->elts; + struct nocache_entry *ncent=(struct nocache_entry *)conf->nocaches->elts; + int nocache = 0; + + memset(&server, '\0', sizeof(server)); + server.sin_family = AF_INET; + +/* We break the URL into host, port, path-search */ + + url += 7; /* skip http:// */ + destport = DEFAULT_PORT; + p = strchr(url, '/'); + if (p == NULL) + { + desthost = pstrdup(pool, url); + url = "/"; + } else + { + char *q = palloc(pool, p-url+1); + memcpy(q, url, p-url); + q[p-url] = '\0'; + url = p; + desthost = q; + } + + p = strchr(desthost, ':'); + if (p != NULL) + { + *(p++) = '\0'; + if (isdigit(*p)) + { + destport = atoi(p); + destportstr = p; + } + } + +/* check if ProxyBlock directive on this host */ + destaddr.s_addr = inet_addr(desthost); + for (i=0; i < conf->noproxies->nelts; i++) + { + if ((npent[i].name != NULL && strstr(desthost, npent[i].name) != NULL) + || destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*') + return proxyerror(r, "Connect to remote machine blocked"); + } + + if (proxyhost != NULL) + { + url = r->uri; /* restore original URL */ + server.sin_port = htons(proxyport); + err = proxy_host2addr(proxyhost, &server_hp); + if (err != NULL) return DECLINED; /* try another */ + } else + { + server.sin_port = htons(destport); + err = proxy_host2addr(desthost, &server_hp); + if (err != NULL) return proxyerror(r, err); /* give up */ + } + + sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock == -1) + { + log_error("proxy: error creating socket", r->server); + return SERVER_ERROR; + } + note_cleanups_for_fd(pool, sock); + + + j = 0; + while (server_hp.h_addr_list[j] != NULL) { + memcpy(&server.sin_addr, server_hp.h_addr_list[j], + sizeof(struct in_addr)); + i = proxy_doconnect(sock, &server, r); + if (i == 0) + break; + j++; + } + if (i == -1) + { + if (proxyhost != NULL) return DECLINED; /* try again another way */ + else return proxyerror(r, "Could not connect to remote machine"); + } + + clear_connection(r->headers_in); /* Strip connection-based headers */ + + f = bcreate(pool, B_RDWR); + bpushfd(f, sock, sock); + + hard_timeout ("proxy send", r); + bvputs(f, r->method, " ", url, " HTTP/1.0\015\012", NULL); + bvputs(f, "Host: ", desthost, NULL); + if (destportstr != NULL && destport != DEFAULT_PORT) + bvputs(f, ":", destportstr, "\015\012", NULL); + else + bputs("\015\012", f); + + reqhdrs_arr = table_elts (r->headers_in); + reqhdrs = (table_entry *)reqhdrs_arr->elts; + for (i=0; i < reqhdrs_arr->nelts; i++) + { + if (reqhdrs[i].key == NULL || reqhdrs[i].val == NULL + || !strcmp(reqhdrs[i].key, "Host")) /* already sent if there */ + continue; + bvputs(f, reqhdrs[i].key, ": ", reqhdrs[i].val, "\015\012", NULL); + } + + bputs("\015\012", f); +/* send the request data, if any. N.B. should we trap SIGPIPE ? */ + + if (should_client_block(r)) + { + while ((i = get_client_block(r, buffer, HUGE_STRING_LEN)) > 0) + bwrite(f, buffer, i); + } + bflush(f); + kill_timeout(r); + + hard_timeout ("proxy receive", r); + + len = bgets(buffer, HUGE_STRING_LEN-1, f); + if (len == -1 || len == 0) + { + pclosef(pool, sock); + kill_timeout(r); + return proxyerror(r, "Error reading from remote server"); + } + +/* Is it an HTTP/1 response? */ + if (checkmask(buffer, "HTTP/#.# ###*")) + { +/* If not an HTTP/1 messsage or if the status line was > 8192 bytes */ + if (buffer[5] != '1' || buffer[len-1] != '\n') + { + pclosef(pool, sock); + kill_timeout(r); + return BAD_GATEWAY; + } + buffer[--len] = '\0'; + memcpy(inprotocol, buffer, 8); + inprotocol[8] = '\0'; + +/* we use the same protocol on output as on input */ + strcpy(outprotocol, inprotocol); + buffer[12] = '\0'; + r->status = atoi(&buffer[9]); + buffer[12] = ' '; + r->status_line = pstrdup(pool, &buffer[9]); + +/* read the headers. */ +/* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers */ +/* Also, take care with headers with multiple occurences. */ + + resp_hdrs = proxy_read_headers(pool, buffer, HUGE_STRING_LEN, f); + } else + { +/* an http/0.9 response */ + strcpy(inprotocol, "HTTP/0.9"); + strcpy(outprotocol, "HTTP/1.0"); + r->status = 200; + r->status_line = "200 OK"; + +/* no headers */ + resp_hdrs = make_array(pool, 2, sizeof(struct hdr_entry)); + } + + kill_timeout(r); + +/* + * HTTP/1.0 requires us to accept 3 types of dates, but only generate + * one type + */ + + len = resp_hdrs->nelts; + hdr = (struct hdr_entry *)resp_hdrs->elts; + for (i=0; i < len; i++) + { + if (hdr[i].value[0] == '\0') continue; + p = hdr[i].field; + if (strcasecmp(p, "Date") == 0 || + strcasecmp(p, "Last-Modified") == 0 || + strcasecmp(p, "Expires") == 0) + hdr[i].value = proxy_date_canon(pool, hdr[i].value); + } + +/* check if NoCache directive on this host */ + for (i=0; i < conf->nocaches->nelts; i++) + { + if ((ncent[i].name != NULL && strstr(desthost, ncent[i].name) != NULL) + || destaddr.s_addr == ncent[i].addr.s_addr || ncent[i].name[0] == '*') + nocache = 1; + } + + i = proxy_cache_update(c, resp_hdrs, inprotocol, nocache); + if (i != DECLINED) + { + pclosef(pool, sock); + return i; + } + + cache = c->fp; + + hard_timeout ("proxy receive", r); + +/* write status line */ + if (!r->assbackwards) + rvputs(r, "HTTP/1.0 ", r->status_line, "\015\012", NULL); + if (cache != NULL) + if (bvputs(cache, outprotocol, " ", r->status_line, "\015\012", NULL) + == -1) + cache = proxy_cache_error(c); + +/* send headers */ + len = resp_hdrs->nelts; + for (i=0; i < len; i++) + { + if (hdr[i].field == NULL || hdr[i].value == NULL || + hdr[i].value[0] == '\0') continue; + if (!r->assbackwards) + rvputs(r, hdr[i].field, ": ", hdr[i].value, "\015\012", NULL); + if (cache != NULL) + if (bvputs(cache, hdr[i].field, ": ", hdr[i].value, "\015\012", + NULL) == -1) + cache = proxy_cache_error(c); + } + + if (!r->assbackwards) rputs("\015\012", r); + if (cache != NULL) + if (bputs("\015\012", cache) == -1) cache = proxy_cache_error(c); + + bsetopt(r->connection->client, BO_BYTECT, &zero); + r->sent_bodyct = 1; +/* Is it an HTTP/0.9 respose? If so, send the extra data */ + if (strcmp(inprotocol, "HTTP/0.9") == 0) + { + bwrite(r->connection->client, buffer, len); + if (cache != NULL) + if (bwrite(f, buffer, len) != len) cache = proxy_cache_error(c); + } + kill_timeout(r); + +/* send body */ +/* if header only, then cache will be NULL */ +/* HTTP/1.0 tells us to read to EOF, rather than content-length bytes */ + if (!r->header_only) proxy_send_fb(f, r, cache, c); + + proxy_cache_tidy(c); + + pclosef(pool, sock); + + proxy_garbage_coll(r); + return OK; +} + diff --git a/APACHE_1_2_X/src/modules/proxy/proxy_util.c b/APACHE_1_2_X/src/modules/proxy/proxy_util.c new file mode 100644 index 00000000000..6cd3bdb47ce --- /dev/null +++ b/APACHE_1_2_X/src/modules/proxy/proxy_util.c @@ -0,0 +1,747 @@ +/* ==================================================================== + * Copyright (c) 1996,1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* Utility routines for Apache proxy */ + +#include "mod_proxy.h" +#include "http_main.h" +#include "md5.h" + +/* already called in the knowledge that the characters are hex digits */ +int +proxy_hex2c(const char *x) +{ + int i, ch; + + ch = x[0]; + if (isdigit(ch)) i = ch - '0'; + else if (isupper(ch)) i = ch - ('A' - 10); + else i = ch - ('a' - 10); + i <<= 4; + + ch = x[1]; + if (isdigit(ch)) i += ch - '0'; + else if (isupper(ch)) i += ch - ('A' - 10); + else i += ch - ('a' - 10); + return i; +} + +void +proxy_c2hex(int ch, char *x) +{ + int i; + + x[0] = '%'; + i = (ch & 0xF0) >> 4; + if (i >= 10) x[1] = ('A' - 10) + i; + else x[1] = '0' + i; + + i = ch & 0x0F; + if (i >= 10) x[2] = ('A' - 10) + i; + else x[2] = '0' + i; +} + +/* + * canonicalise a URL-encoded string + */ + +/* + * Convert a URL-encoded string to canonical form. + * It decodes characters which need not be encoded, + * and encodes those which must be encoded, and does not touch + * those which must not be touched. + */ +char * +proxy_canonenc(pool *p, const char *x, int len, enum enctype t, int isenc) +{ + int i, j, ispath, ch; + char *y; + const char *allowed; /* characters which should not be encoded */ + const char *reserved; /* characters which much not be en/de-coded */ + +/* N.B. in addition to :@&=, this allows ';' in an http path + * and '?' in an ftp path -- this may be revised + * + * Also, it makes a '+' character in a search string reserved, as + * it may be form-encoded. (Although RFC 1738 doesn't allow this - + * it only permits ; / ? : @ = & as reserved chars.) + */ + if (t == enc_path) allowed = "$-_.+!*'(),;:@&="; + else if (t == enc_search) allowed = "$-_.!*'(),;:@&="; + else if (t == enc_user) allowed = "$-_.+!*'(),;@&="; + else if (t == enc_fpath) allowed = "$-_.+!*'(),?:@&="; + else /* if (t == enc_parm) */ allowed = "$-_.+!*'(),?/:@&="; + + if (t == enc_path) reserved = "/"; + else if (t == enc_search) reserved = "+"; + else reserved = ""; + + y = palloc(p, 3*len+1); + ispath = (t == enc_path); + + for (i=0, j=0; i < len; i++, j++) + { +/* always handle '/' first */ + ch = x[i]; + if (ind(reserved, ch) != -1) + { + y[j] = ch; + continue; + } +/* decode it if not already done */ + if (isenc && ch == '%') + { + if (!isxdigit(x[i+1]) || !isxdigit(x[i+2])) + return NULL; + ch = proxy_hex2c(&x[i+1]); + i += 2; + if (ch != 0 && ind(reserved, ch) != -1) + { /* keep it encoded */ + proxy_c2hex(ch, &y[j]); + j += 2; + continue; + } + } +/* recode it, if necessary */ + if (!isalnum(ch) && ind(allowed, ch) == -1) + { + proxy_c2hex(ch, &y[j]); + j += 2; + } else y[j] = ch; + } + y[j] = '\0'; + return y; +} + +/* + * Parses network-location. + * urlp on input the URL; on output the path, after the leading / + * user NULL if no user/password permitted + * password holder for password + * host holder for host + * port port number; only set if one is supplied. + * + * Returns an error string. + */ +char * +proxy_canon_netloc(pool *pool, char **const urlp, char **userp, + char **passwordp, char **hostp, int *port) +{ + int i; + char *p, *host, *url=*urlp; + + if (url[0] != '/' || url[1] != '/') return "Malformed URL"; + host = url + 2; + url = strchr(host, '/'); + if (url == NULL) + url = ""; + else + *(url++) = '\0'; /* skip seperating '/' */ + + if (userp != NULL) + { + char *user=NULL, *password = NULL; + p = strchr(host, '@'); + + if (p != NULL) + { + *p = '\0'; + user = host; + host = p + 1; + +/* find password */ + p = strchr(user, ':'); + if (p != NULL) + { + *p = '\0'; + password = proxy_canonenc(pool, p+1, strlen(p+1), enc_user, 1); + if (password == NULL) + return "Bad %-escape in URL (password)"; + } + + user = proxy_canonenc(pool, user, strlen(user), enc_user, 1); + if (user == NULL) return "Bad %-escape in URL (username)"; + } + *userp = user; + *passwordp = password; + } + + p = strchr(host, ':'); + if (p != NULL) + { + *(p++) = '\0'; + + for (i=0; p[i] != '\0'; i++) + if (!isdigit(p[i])) break; + + if (i == 0 || p[i] != '\0') + return "Bad port number in URL"; + *port = atoi(p); + if (*port > 65535) return "Port number in URL > 65535"; + } + str_tolower(host); /* DNS names are case-insensitive */ + if (*host == '\0') return "Missing host in URL"; +/* check hostname syntax */ + for (i=0; host[i] != '\0'; i++) + if (!isdigit(host[i]) && host[i] != '.') + break; + /* must be an IP address */ + if (host[i] == '\0' && (inet_addr(host) == -1 || inet_network(host) == -1)) + return "Bad IP address in URL"; + + *urlp = url; + *hostp = host; + + return NULL; +} + +static const char *lwday[7]= +{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; +static const char *wday[7]= +{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; +static const char *months[12]= +{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", + "Dec"}; + +/* + * If the date is a valid RFC 850 date or asctime() date, then it + * is converted to the RFC 1123 format, otherwise it is not modified. + * This routine is not very fast at doing conversions, as it uses + * sscanf and sprintf. However, if the date is already correctly + * formatted, then it exits very quickly. + */ +char * +proxy_date_canon(pool *p, char *x) +{ + int wk, mday, year, hour, min, sec, mon; + char *q, month[4], zone[4], week[4]; + + q = strchr(x, ','); + /* check for RFC 850 date */ + if (q != NULL && q - x > 3 && q[1] == ' ') + { + *q = '\0'; + for (wk=0; wk < 7; wk++) + if (strcmp(x, lwday[wk]) == 0) break; + *q = ','; + if (wk == 7) return x; /* not a valid date */ + if (q[4] != '-' || q[8] != '-' || q[11] != ' ' || q[14] != ':' || + q[17] != ':' || strcmp(&q[20], " GMT") != 0) return x; + if (sscanf(q+2, "%u-%3s-%u %u:%u:%u %3s", &mday, month, &year, + &hour, &min, &sec, zone) != 7) return x; + if (year < 70) year += 2000; + else year += 1900; + } else + { +/* check for acstime() date */ + if (x[3] != ' ' || x[7] != ' ' || x[10] != ' ' || x[13] != ':' || + x[16] != ':' || x[19] != ' ' || x[24] != '\0') return x; + if (sscanf(x, "%3s %3s %u %u:%u:%u %u", week, month, &mday, &hour, + &min, &sec, &year) != 7) return x; + for (wk=0; wk < 7; wk++) + if (strcmp(week, wday[wk]) == 0) break; + if (wk == 7) return x; + } + +/* check date */ + for (mon=0; mon < 12; mon++) if (strcmp(month, months[mon]) == 0) break; + if (mon == 12) return x; + + if (strlen(x) < 31) x = palloc(p, 31); + ap_snprintf(x, strlen(x)+1, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", wday[wk], mday, + months[mon], year, hour, min, sec); + return x; +} + +/* + * Reads headers from a buffer and returns an array of headers. + * Returns NULL on file error + */ +array_header * +proxy_read_headers(pool *pool, char *buffer, int size, BUFF *f) +{ + int gotcr, len, i, j; + array_header *resp_hdrs; + struct hdr_entry *hdr; + char *p; + + resp_hdrs = make_array(pool, 10, sizeof(struct hdr_entry)); + hdr = NULL; + + gotcr = 1; + for (;;) + { + len = bgets(buffer, size, f); + if (len == -1) return NULL; + if (len == 0) break; + if (buffer[len-1] == '\n') + { + buffer[--len] = '\0'; + i = 1; + } else + i = 0; + + if (!gotcr || buffer[0] == ' ' || buffer[0] == '\t') + { + /* a continuation header */ + if (hdr == NULL) + { + /* error!! */ + if (!i) + { + i = bskiplf(f); + if (i == -1) return NULL; + } + gotcr = 1; + continue; + } + hdr->value = pstrcat(pool, hdr->value, buffer, NULL); + } + else if (gotcr && len == 0) break; + else + { + p = strchr(buffer, ':'); + if (p == NULL) + { + /* error!! */ + if (!gotcr) + { + i = bskiplf(f); + if (i == -1) return NULL; + } + gotcr = 1; + hdr = NULL; + continue; + } + hdr = push_array(resp_hdrs); + *(p++) = '\0'; + hdr->field = pstrdup(pool, buffer); + while (*p == ' ' || *p == '\t') p++; + hdr->value = pstrdup(pool, p); + gotcr = i; + } + } + + hdr = (struct hdr_entry *)resp_hdrs->elts; + for (i=0; i < resp_hdrs->nelts; i++) + { + p = hdr[i].value; + j = strlen(p); + while (j > 0 && (p[j-1] == ' ' || p[j-1] == '\t')) j--; + p[j] = '\0'; + } + + return resp_hdrs; +} + +long int +proxy_send_fb(BUFF *f, request_rec *r, BUFF *f2, struct cache_req *c) +{ + char buf[IOBUFSIZE]; + long total_bytes_sent; + register int n,o,w; + conn_rec *con = r->connection; + + total_bytes_sent = 0; + + /* Since we are reading from one buffer and writing to another, + * it is unsafe to do a soft_timeout here, at least until the proxy + * has its own timeout handler which can set both buffers to EOUT. + */ + hard_timeout("proxy send body", r); + + while (!con->aborted && f != NULL) { + n = bread(f, buf, IOBUFSIZE); + if (n == -1) /* input error */ + { + if (f2 != NULL) f2 = proxy_cache_error(c); + break; + } + if (n == 0) break; /* EOF */ + o=0; + total_bytes_sent += n; + + if (f2 != NULL) + if (bwrite(f2, buf, n) != n) f2 = proxy_cache_error(c); + + while(n && !con->aborted) { + w = bwrite(con->client, &buf[o], n); + if (w <= 0) { + if (f2 != NULL) { + pclosef(c->req->pool, c->fp->fd); + c->fp = NULL; + unlink(c->tempfile); + } + break; + } + reset_timeout(r); /* reset timeout after successful write */ + n-=w; + o+=w; + } + } + if (!con->aborted) + bflush(con->client); + + kill_timeout(r); + return total_bytes_sent; +} + +/* + * Read a header from the array, returning the first entry + */ +struct hdr_entry * +proxy_get_header(array_header *hdrs_arr, const char *name) +{ + struct hdr_entry *hdrs; + int i; + + hdrs = (struct hdr_entry *)hdrs_arr->elts; + for (i = 0; i < hdrs_arr->nelts; i++) + if (hdrs[i].field != NULL && strcasecmp(name, hdrs[i].field) == 0) + return &hdrs[i]; + + return NULL; +} + +/* + * Add to the header reply, either concatenating, or replacing existin + * headers. It stores the pointers provided, so make sure the data + * is not subsequently overwritten + */ +struct hdr_entry * +proxy_add_header(array_header *hdrs_arr, char *field, char *value, + int rep) +{ + int i; + struct hdr_entry *hdrs; + + hdrs = (struct hdr_entry *)hdrs_arr->elts; + if (rep) + for (i = 0; i < hdrs_arr->nelts; i++) + if (hdrs[i].field != NULL && strcasecmp(field, hdrs[i].field) == 0) + { + hdrs[i].value = value; + return hdrs; + } + + hdrs = push_array(hdrs_arr); + hdrs->field = field; + hdrs->value = value; + + return hdrs; +} + +void +proxy_del_header(array_header *hdrs_arr, const char *field) +{ + int i; + struct hdr_entry *hdrs; + + hdrs = (struct hdr_entry *)hdrs_arr->elts; + + for (i = 0; i < hdrs_arr->nelts; i++) + if (hdrs[i].field != NULL && strcasecmp(field, hdrs[i].field) == 0) + hdrs[i].value = NULL; +} + +/* + * Sends response line and headers + * A timeout should be set before calling this routine. + */ +void +proxy_send_headers(BUFF *fp, const char *respline, array_header *hdrs_arr) +{ + struct hdr_entry *hdrs; + int i; + + hdrs = (struct hdr_entry *)hdrs_arr->elts; + + bputs(respline, fp); + bputs("\015\012", fp); + for (i = 0; i < hdrs_arr->nelts; i++) + { + if (hdrs[i].field == NULL) continue; + bvputs(fp, hdrs[i].field, ": ", hdrs[i].value, "\015\012", NULL); + } + + bputs("\015\012", fp); +} + + +/* + * list is a comma-separated list of case-insensitive tokens, with + * optional whitespace around the tokens. + * The return returns 1 if the token val is found in the list, or 0 + * otherwise. + */ +int +proxy_liststr(const char *list, const char *val) +{ + int len, i; + const char *p; + + len = strlen(val); + + while (list != NULL) + { + p = strchr(list, ','); + if (p != NULL) + { + i = p - list; + do p++; while (isspace(*p)); + } + else + i = strlen(list); + + while (i > 0 && isspace(list[i-1])) i--; + if (i == len && strncasecmp(list, val, len) == 0) return 1; + list = p; + } + return 0; +} + +void +proxy_hash(const char *it, char *val,int ndepth,int nlength) +{ + MD5_CTX context; + unsigned char digest[16]; + char tmp[22]; + int i, k, d; + unsigned int x; + static const char table[64]= +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_@"; + + MD5Init(&context); + MD5Update(&context, (const unsigned char *)it, strlen(it)); + MD5Final(digest, &context); + +/* encode 128 bits as 22 characters, using a modified uuencoding */ +/* the encoding is 3 bytes -> 4 characters + * i.e. 128 bits is 5 x 3 bytes + 1 byte -> 5 * 4 characters + 2 characters + */ + for (i=0, k=0; i < 15; i += 3) + { + x = (digest[i] << 16) | (digest[i+1] << 8) | digest[i+2]; + tmp[k++] = table[x >> 18]; + tmp[k++] = table[(x >> 12) & 0x3f]; + tmp[k++] = table[(x >> 6) & 0x3f]; + tmp[k++] = table[x & 0x3f]; + } +/* one byte left */ + x = digest[15]; + tmp[k++] = table[x >> 2]; /* use up 6 bits */ + tmp[k++] = table[(x << 4) & 0x3f]; + /* now split into directory levels */ + + for(i=k=d=0 ; d < ndepth ; ++d) + { + strncpy(&val[i],&tmp[k],nlength); + k+=nlength; + val[i+nlength]='/'; + i+=nlength+1; + } + memcpy(&val[i],&tmp[k],22-k); + val[i+22-k]='\0'; +} + +/* + * Converts 8 hex digits to a time integer + */ +int +proxy_hex2sec(const char *x) +{ + int i, ch; + unsigned int j; + + for (i=0, j=0; i < 8; i++) + { + ch = x[i]; + j <<= 4; + if (isdigit(ch)) j |= ch - '0'; + else if (isupper(ch)) j |= ch - ('A' - 10); + else j |= ch - ('a' - 10); + } + if (j == 0xffffffff) return -1; /* so that it works with 8-byte ints */ + else return j; +} + +/* + * Converts a time integer to 8 hex digits + */ +void +proxy_sec2hex(int t, char *y) +{ + int i, ch; + unsigned int j=t; + + for (i=7; i >= 0; i--) + { + ch = j & 0xF; + j >>= 4; + if (ch >= 10) y[i] = ch + ('A' - 10); + else y[i] = ch + '0'; + } + y[8] = '\0'; +} + +void +proxy_log_uerror(const char *routine, const char *file, const char *err, + server_rec *s) +{ + char *p, *q; + + q = get_time(); + p = strerror(errno); + + if (err != NULL) + { + fprintf(s->error_log, "[%s] %s\n", q, err); + if (file != NULL) + fprintf(s->error_log, "- %s: %s: %s\n", routine, file, p); + else + fprintf(s->error_log, "- %s: %s\n", routine, p); + } else + { + if (file != NULL) + fprintf(s->error_log, "[%s] %s: %s: %s\n", q, routine, file, p); + else + fprintf(s->error_log, "[%s] %s: %s\n", q, routine, p); + } + + fflush(s->error_log); +} + +BUFF * +proxy_cache_error(struct cache_req *c) +{ + proxy_log_uerror("write", c->tempfile, "proxy: error writing to cache file", + c->req->server); + pclosef(c->req->pool, c->fp->fd); + c->fp = NULL; + unlink(c->tempfile); + return NULL; +} + +int +proxyerror(request_rec *r, const char *message) +{ + r->status = SERVER_ERROR; + r->status_line = "500 Proxy Error"; + r->content_type = "text/html"; + + send_http_header(r); + soft_timeout("proxy error", r); + + rvputs(r, "\015\012\ +Proxy Error\015\012

    Proxy Error\ +

    \015\012The proxy server could not handle this request.\ +\015\012

    \015\012Reason: ", message, "\015\012\015\012", + NULL); + + kill_timeout(r); + return OK; +} + +/* + * This routine returns its own error message + */ +const char * +proxy_host2addr(const char *host, struct hostent *reqhp) +{ + int i; + struct hostent *hp; + static struct hostent hpbuf; + static u_long ipaddr; + static char* charpbuf[2]; + + for (i=0; host[i] != '\0'; i++) + if (!isdigit(host[i]) && host[i] != '.') + break; + + if (host[i] != '\0') + { + hp = gethostbyname(host); + if (hp == NULL) + return "Host not found"; + } else + { + ipaddr = inet_addr(host); + hp = gethostbyaddr((char *)&ipaddr, sizeof(u_long), AF_INET); + if (hp == NULL) { + memset(&hpbuf, 0, sizeof(hpbuf)); + hpbuf.h_name = 0; + hpbuf.h_addrtype = AF_INET; + hpbuf.h_length = sizeof(u_long); + hpbuf.h_addr_list = charpbuf; + hpbuf.h_addr_list[0] = (char*)&ipaddr; + hpbuf.h_addr_list[1] = 0; + hp = &hpbuf; + } + } + memcpy(reqhp, hp, sizeof(struct hostent)); + return NULL; +} + +int +proxy_doconnect(int sock, struct sockaddr_in *addr, request_rec *r) +{ + int i; + + hard_timeout("proxy connect", r); + do i = connect(sock, (struct sockaddr *)addr, sizeof(struct sockaddr_in)); + while (i == -1 && errno == EINTR); + if (i == -1) proxy_log_uerror("connect", NULL, NULL, r->server); + kill_timeout(r); + + return i; +} + diff --git a/APACHE_1_2_X/src/modules/standard/mod_access.c b/APACHE_1_2_X/src/modules/standard/mod_access.c new file mode 100644 index 00000000000..eb352380123 --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_access.c @@ -0,0 +1,283 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * Security options etc. + * + * Module derived from code originally written by Rob McCool + * + */ + +#include "httpd.h" +#include "http_core.h" +#include "http_config.h" +#include "http_log.h" +#include "http_request.h" + +typedef struct { + char *from; + int limited; +} allowdeny; + +/* things in the 'order' array */ +#define DENY_THEN_ALLOW 0 +#define ALLOW_THEN_DENY 1 +#define MUTUAL_FAILURE 2 + +typedef struct { + int order[METHODS]; + array_header *allows; + array_header *denys; +} access_dir_conf; + +module access_module; + +void *create_access_dir_config (pool *p, char *dummy) +{ + access_dir_conf *conf = + (access_dir_conf *)pcalloc(p, sizeof(access_dir_conf)); + int i; + + for (i = 0; i < METHODS; ++i) conf->order[i] = DENY_THEN_ALLOW; + conf->allows = make_array (p, 1, sizeof (allowdeny)); + conf->denys = make_array (p, 1, sizeof (allowdeny)); + + return (void *)conf; +} + +const char *order (cmd_parms *cmd, void *dv, char *arg) +{ + access_dir_conf *d = (access_dir_conf *)dv; + int i, order; + + if (!strcasecmp (arg, "allow,deny")) order = ALLOW_THEN_DENY; + else if (!strcasecmp (arg, "deny,allow")) order = DENY_THEN_ALLOW; + else if (!strcasecmp (arg, "mutual-failure")) order = MUTUAL_FAILURE; + else return "unknown order"; + + for (i = 0; i < METHODS; ++i) + if (cmd->limited & (1 << i)) + d->order[i] = order; + + return NULL; +} + +const char *allow_cmd (cmd_parms *cmd, void *dv, char *from, char *where) +{ + access_dir_conf *d = (access_dir_conf *)dv; + allowdeny *a; + + if (strcasecmp (from, "from")) + return "allow and deny must be followed by 'from'"; + + a = (allowdeny *)push_array (cmd->info ? d->allows : d->denys); + a->from = pstrdup (cmd->pool, where); + a->limited = cmd->limited; + return NULL; +} + +static char its_an_allow; + +command_rec access_cmds[] = { +{ "order", order, NULL, OR_LIMIT, TAKE1, + "'allow,deny', 'deny,allow', or 'mutual-failure'" }, +{ "allow", allow_cmd, &its_an_allow, OR_LIMIT, ITERATE2, + "'from' followed by hostnames or IP-address wildcards" }, +{ "deny", allow_cmd, NULL, OR_LIMIT, ITERATE2, + "'from' followed by hostnames or IP-address wildcards" }, +{NULL} +}; + +int in_domain(const char *domain, const char *what) { + int dl=strlen(domain); + int wl=strlen(what); + + if((wl-dl) >= 0) { + if (strcasecmp(domain,&what[wl-dl]) != 0) return 0; + + /* Make sure we matched an *entire* subdomain --- if the user + * said 'allow from good.com', we don't want people from nogood.com + * to be able to get in. + */ + + if (wl == dl) return 1; /* matched whole thing */ + else return (domain[0] == '.' || what[wl - dl - 1] == '.'); + } else + return 0; +} + +int in_ip(char *domain, char *what) { + + /* Check a similar screw case to the one checked above --- + * "allow from 204.26.2" shouldn't let in people from 204.26.23 + */ + + int l = strlen(domain); + if (strncmp(domain,what,l) != 0) return 0; + if (domain[l - 1] == '.') return 1; + return (what[l] == '\0' || what[l] == '.'); +} + +static int is_ip(const char *host) +{ + while ((*host == '.') || isdigit(*host)) + host++; + return (*host == '\0'); +} + +int find_allowdeny (request_rec *r, array_header *a, int method) +{ + allowdeny *ap = (allowdeny *)a->elts; + int mmask = (1 << method); + int i; + int gothost = 0; + const char *remotehost = NULL; + + for (i = 0; i < a->nelts; ++i) { + if (!(mmask & ap[i].limited)) + continue; + + if (!strncmp(ap[i].from,"env=",4) && table_get(r->subprocess_env,ap[i].from+4)) + return 1; + + if (ap[i].from && !strcmp(ap[i].from, "user-agents")) { + char * this_agent = table_get(r->headers_in, "User-Agent"); + int j; + + if (!this_agent) return 0; + + for (j = i+1; j < a->nelts; ++j) { + if (strstr(this_agent, ap[j].from)) return 1; + } + return 0; + } + + if (!strcmp (ap[i].from, "all")) + return 1; + + if (!gothost) { + remotehost = get_remote_host(r->connection, r->per_dir_config, + REMOTE_HOST); + + if ((remotehost == NULL) || is_ip(remotehost)) + gothost = 1; + else + gothost = 2; + } + + if ((gothost == 2) && in_domain(ap[i].from, remotehost)) + return 1; + + if (in_ip (ap[i].from, r->connection->remote_ip)) + return 1; + } + + return 0; +} + +int check_dir_access (request_rec *r) +{ + int method = r->method_number; + access_dir_conf *a = + (access_dir_conf *) + get_module_config (r->per_dir_config, &access_module); + int ret = OK; + + if (a->order[method] == ALLOW_THEN_DENY) { + ret = FORBIDDEN; + if (find_allowdeny (r, a->allows, method)) + ret = OK; + if (find_allowdeny (r, a->denys, method)) + ret = FORBIDDEN; + } else if (a->order[method] == DENY_THEN_ALLOW) { + if (find_allowdeny (r, a->denys, method)) + ret = FORBIDDEN; + if (find_allowdeny (r, a->allows, method)) + ret = OK; + } + else { + if (find_allowdeny(r, a->allows, method) + && !find_allowdeny(r, a->denys, method)) + ret = OK; + else + ret = FORBIDDEN; + } + + if (ret == FORBIDDEN && ( + satisfies(r) != SATISFY_ANY || !some_auth_required(r) + )) { + log_reason ("Client denied by server configuration", r->filename, r); + } + + return ret; +} + + + +module access_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + create_access_dir_config, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + NULL, /* server config */ + NULL, /* merge server config */ + access_cmds, + NULL, /* handlers */ + NULL, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + check_dir_access, /* check access */ + NULL, /* type_checker */ + NULL, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_actions.c b/APACHE_1_2_X/src/modules/standard/mod_actions.c new file mode 100644 index 00000000000..570147069ed --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_actions.c @@ -0,0 +1,219 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * mod_actions.c: executes scripts based on MIME type + * + * by Alexei Kosut; based on mod_cgi.c, mod_mime.c and mod_includes.c, + * adapted by rst from original NCSA code by Rob McCool + * + * Usage instructions: + * + * Action mime/type /cgi-bin/script + * + * will activate /cgi-bin/script when a file of content type mime/type is + * requested. It sends the URL and file path of the requested document using + * the standard CGI PATH_INFO and PATH_TRANSLATED environment variables. + * + */ + +#include "httpd.h" +#include "http_config.h" +#include "http_request.h" +#include "http_core.h" +#include "http_protocol.h" +#include "http_main.h" +#include "http_log.h" +#include "util_script.h" + +typedef struct { + table *action_types; /* Added with Action... */ + char *get; /* Added with Script GET */ + char *post; /* Added with Script POST */ + char *put; /* Added with Script PUT */ + char *delete; /* Added with Script DELETE */ +} action_dir_config; + +module action_module; + +void *create_action_dir_config (pool *p, char *dummy) +{ + action_dir_config *new = + (action_dir_config *) palloc (p, sizeof(action_dir_config)); + + new->action_types = make_table (p, 4); + new->get = NULL; + new->post = NULL; + new->put = NULL; + new->delete = NULL; + + return new; +} + +void *merge_action_dir_configs (pool *p, void *basev, void *addv) +{ + action_dir_config *base = (action_dir_config *)basev; + action_dir_config *add = (action_dir_config *)addv; + action_dir_config *new = + (action_dir_config *)palloc (p, sizeof(action_dir_config)); + + new->action_types = overlay_tables (p, add->action_types, + base->action_types); + + new->get = add->get ? add->get : base->get; + new->post = add->post ? add->post : base->post; + new->put = add->put ? add->put : base->put; + new->delete = add->delete ? add->delete : base->delete; + + return new; +} + +const char *add_action(cmd_parms *cmd, action_dir_config *m, char *type, + char *script) +{ + table_set (m->action_types, type, script); + return NULL; +} + +const char *set_script (cmd_parms *cmd, action_dir_config *m, char *method, + char *script) +{ + if (!strcmp(method, "GET")) + m->get = pstrdup(cmd->pool, script); + else if (!strcmp(method, "POST")) + m->post = pstrdup(cmd->pool, script); + else if (!strcmp(method, "PUT")) + m->put = pstrdup(cmd->pool, script); + else if (!strcmp(method, "DELETE")) + m->delete = pstrdup(cmd->pool, script); + else + return "Unknown method type for Script"; + + return NULL; +} + +command_rec action_cmds[] = { +{ "Action", add_action, NULL, OR_FILEINFO, TAKE2, + "a media type followed by a script name" }, +{ "Script", set_script, NULL, ACCESS_CONF|RSRC_CONF, TAKE2, + "a method followed by a script name" }, +{ NULL } +}; + +int action_handler (request_rec *r) +{ + action_dir_config *conf = + (action_dir_config *)get_module_config(r->per_dir_config,&action_module); + char *t, *action = r->handler ? r->handler : r->content_type; + char *script = NULL; + + /* Set allowed stuff */ + if (conf->get) r->allowed |= (1 << M_GET); + if (conf->post) r->allowed |= (1 << M_POST); + if (conf->put) r->allowed |= (1 << M_PUT); + if (conf->delete) r->allowed |= (1 << M_DELETE); + + /* First, check for the method-handling scripts */ + if ((r->method_number == M_GET) && r->args && conf->get) + script = conf->get; + else if ((r->method_number == M_POST) && conf->post) + script = conf->post; + else if ((r->method_number == M_PUT) && conf->put) + script = conf->put; + else if ((r->method_number == M_DELETE) && conf->delete) + script = conf->delete; + + /* Check for looping, which can happen if the CGI script isn't */ + if (script && r->prev && r->prev->prev) + return DECLINED; + + /* Second, check for actions (which override the method scripts) */ + if ((t = table_get(conf->action_types, + action ? action : default_type(r)))) { + script = t; + if (r->finfo.st_mode == 0) { + log_reason("File does not exist", r->filename, r); + return NOT_FOUND; + } + } + + if (script == NULL) + return DECLINED; + + internal_redirect_handler(pstrcat(r->pool, script, escape_uri(r->pool, + r->uri), r->args ? "?" : NULL, r->args, NULL), r); + return OK; +} + +handler_rec action_handlers[] = { +{ "*/*", action_handler }, +{ NULL } +}; + +module action_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + create_action_dir_config, /* dir config creater */ + merge_action_dir_configs, /* dir merger --- default is to override */ + NULL, /* server config */ + NULL, /* merge server config */ + action_cmds, /* command table */ + action_handlers, /* handlers */ + NULL, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_alias.c b/APACHE_1_2_X/src/modules/standard/mod_alias.c new file mode 100644 index 00000000000..2d96fd713fd --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_alias.c @@ -0,0 +1,329 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * http_alias.c: Stuff for dealing with directory aliases + * + * Original by Rob McCool, rewritten in succession by David Robinson + * and rst. + * + */ + +#include "httpd.h" +#include "http_config.h" + +typedef struct { + char *real; + char *fake; + char *handler; + int redir_status; /* 301, 302, 303, 410, etc */ +} alias_entry; + +typedef struct { + array_header *aliases; + array_header *redirects; +} alias_server_conf; + +typedef struct { + array_header *redirects; +} alias_dir_conf; +module alias_module; + +void *create_alias_config (pool *p, server_rec *s) +{ + alias_server_conf *a = + (alias_server_conf *)pcalloc (p, sizeof(alias_server_conf)); + + a->aliases = make_array (p, 20, sizeof(alias_entry)); + a->redirects = make_array (p, 20, sizeof(alias_entry)); + return a; +} + +void *create_alias_dir_config (pool *p, char *d) +{ + alias_dir_conf *a = + (alias_dir_conf *)pcalloc (p, sizeof(alias_dir_conf)); + a->redirects = make_array (p, 2, sizeof(alias_entry)); + return a; +} +void *merge_alias_config (pool *p, void *basev, void *overridesv) +{ + alias_server_conf *a = + (alias_server_conf *)pcalloc (p, sizeof(alias_server_conf)); + alias_server_conf *base = (alias_server_conf *)basev, + *overrides = (alias_server_conf *)overridesv; + + a->aliases = append_arrays (p, overrides->aliases, base->aliases); + a->redirects = append_arrays (p, overrides->redirects, base->redirects); + return a; +} + +void *merge_alias_dir_config (pool *p, void *basev, void *overridesv) +{ + alias_dir_conf *a = + (alias_dir_conf *)pcalloc (p, sizeof(alias_dir_conf)); + alias_dir_conf *base = (alias_dir_conf *)basev, + *overrides = (alias_dir_conf *)overridesv; + a->redirects = append_arrays (p, overrides->redirects, base->redirects); + return a; +} + +const char *add_alias(cmd_parms *cmd, void *dummy, char *f, char *r) +{ + server_rec *s = cmd->server; + alias_server_conf *conf = + (alias_server_conf *)get_module_config(s->module_config,&alias_module); + alias_entry *new = push_array (conf->aliases); + + /* XX r can NOT be relative to DocumentRoot here... compat bug. */ + + new->fake = f; new->real = r; new->handler = cmd->info; + return NULL; +} + +const char *add_redirect(cmd_parms *cmd, alias_dir_conf *dirconf, char *arg1, + char *arg2, char *arg3) +{ + alias_entry *new; + server_rec *s = cmd->server; + alias_server_conf *serverconf = + (alias_server_conf *)get_module_config(s->module_config,&alias_module); + int status = (int)cmd->info; + char *f = arg2; + char *url = arg3; + + if (!strcasecmp(arg1, "gone")) + status = HTTP_GONE; + else if (!strcasecmp(arg1, "permanent")) + status = HTTP_MOVED_PERMANENTLY; + else if (!strcasecmp(arg1, "temp")) + status = HTTP_MOVED_TEMPORARILY; + else if (!strcasecmp(arg1, "seeother")) + status = HTTP_SEE_OTHER; + else if (isdigit(*arg1)) + status = atoi(arg1); + else { + f = arg1; + url = arg2; + } + + if (is_HTTP_REDIRECT(status)) { + if (!url) return "URL to redirect to is missing"; + if (!is_url (url)) return "Redirect to non-URL"; + } + else { + if (url) return "Redirect URL not valid for this status"; + } + + if ( cmd->path ) + new = push_array (dirconf->redirects); + else + new = push_array (serverconf->redirects); + + new->fake = f; new->real = url; + new->redir_status = status; + return NULL; +} + +command_rec alias_cmds[] = { +{ "Alias", add_alias, NULL, RSRC_CONF, TAKE2, + "a fakename and a realname"}, +{ "ScriptAlias", add_alias, "cgi-script", RSRC_CONF, TAKE2, + "a fakename and a realname"}, +{ "Redirect", add_redirect, (void*)HTTP_MOVED_TEMPORARILY, + OR_FILEINFO, TAKE23, + "an optional status, then document to be redirected and destination URL" }, +{ "RedirectTemp", add_redirect, (void*)HTTP_MOVED_TEMPORARILY, + OR_FILEINFO, TAKE2, + "a document to be redirected, then the destination URL" }, +{ "RedirectPermanent", add_redirect, (void*)HTTP_MOVED_PERMANENTLY, + OR_FILEINFO, TAKE2, + "a document to be redirected, then the destination URL" }, +{ NULL } +}; + +int alias_matches (char *uri, char *alias_fakename) +{ + char *end_fakename = alias_fakename + strlen (alias_fakename); + char *aliasp = alias_fakename, *urip = uri; + + while (aliasp < end_fakename) { + if (*aliasp == '/') { + /* any number of '/' in the alias matches any number in + * the supplied URI, but there must be at least one... + */ + if (*urip != '/') return 0; + + while (*aliasp == '/') ++ aliasp; + while (*urip == '/') ++ urip; + } + else { + /* Other characters are compared literally */ + if (*urip++ != *aliasp++) return 0; + } + } + + /* Check last alias path component matched all the way */ + + if (aliasp[-1] != '/' && *urip != '\0' && *urip != '/') + return 0; + + /* Return number of characters from URI which matched (may be + * greater than length of alias, since we may have matched + * doubled slashes) + */ + + return urip - uri; +} + +char *try_alias_list (request_rec *r, array_header *aliases, int doesc, int *status) +{ + alias_entry *entries = (alias_entry *)aliases->elts; + int i; + + for (i = 0; i < aliases->nelts; ++i) { + alias_entry *p = &entries[i]; + int l = alias_matches (r->uri, p->fake); + + if (l > 0) { + if (p->handler) { /* Set handler, and leave a note for mod_cgi */ + r->handler = pstrdup(r->pool, p->handler); + table_set (r->notes, "alias-forced-type", p->handler); + } + + *status = p->redir_status; + + if (doesc) { + char *escurl; + escurl = os_escape_path(r->pool, r->uri + l, 1); + + return pstrcat(r->pool, p->real, escurl, NULL); + } else + return pstrcat(r->pool, p->real, r->uri + l, NULL); + } + } + + return NULL; +} + +int translate_alias_redir(request_rec *r) +{ + void *sconf = r->server->module_config; + alias_server_conf *serverconf = + (alias_server_conf *)get_module_config(sconf, &alias_module); + char *ret; + int status; + +#ifdef __EMX__ + /* Add support for OS/2 drive names */ + if ((r->uri[0] != '/' && r->uri[0] != '\0') && r->uri[1] != ':') +#else + if (r->uri[0] != '/' && r->uri[0] != '\0') +#endif + return DECLINED; + + if ((ret = try_alias_list (r, serverconf->redirects, 1, &status)) != NULL) { + if (is_HTTP_REDIRECT(status)) { + /* include QUERY_STRING if any */ + if (r->args) { + ret = pstrcat (r->pool, ret, "?", r->args, NULL); + } + table_set (r->headers_out, "Location", ret); + } + return status; + } + + if ((ret = try_alias_list (r, serverconf->aliases, 0, &status)) != NULL) { + r->filename = ret; + return OK; + } + + return DECLINED; +} + +int fixup_redir(request_rec *r) +{ + void *dconf = r->per_dir_config; + alias_dir_conf *dirconf = + (alias_dir_conf *)get_module_config(dconf, &alias_module); + char *ret; + int status; + + /* It may have changed since last time, so try again */ + + if ((ret = try_alias_list (r, dirconf->redirects, 1, &status)) != NULL) { + if (is_HTTP_REDIRECT(status)) + table_set (r->headers_out, "Location", ret); + return status; + } + + return DECLINED; +} + +module alias_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + create_alias_dir_config, /* dir config creater */ + merge_alias_dir_config, /* dir merger --- default is to override */ + create_alias_config, /* server config */ + merge_alias_config, /* merge server configs */ + alias_cmds, /* command table */ + NULL, /* handlers */ + translate_alias_redir, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + fixup_redir, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_asis.c b/APACHE_1_2_X/src/modules/standard/mod_asis.c new file mode 100644 index 00000000000..93c590afab0 --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_asis.c @@ -0,0 +1,130 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +#include "httpd.h" +#include "http_config.h" +#include "http_protocol.h" +#include "http_log.h" +#include "util_script.h" +#include "http_main.h" +#include "http_request.h" + +int asis_handler (request_rec *r) +{ + FILE *f; + char *location; + + if (r->method_number != M_GET) return DECLINED; + if (r->finfo.st_mode == 0) { + log_reason("File does not exist", r->filename, r); + return NOT_FOUND; + } + + f = pfopen (r->pool, r->filename, "r"); + + if (f == NULL) { + log_reason("file permissions deny server access", r->filename, r); + return FORBIDDEN; + } + + scan_script_header (r, f); + location = table_get (r->headers_out, "Location"); + + if (location && location[0] == '/' && + ((r->status == HTTP_OK) || is_HTTP_REDIRECT(r->status))) { + + pfclose(r->pool, f); + + /* Internal redirect -- fake-up a pseudo-request */ + r->status = HTTP_OK; + + /* This redirect needs to be a GET no matter what the original + * method was. + */ + r->method = pstrdup(r->pool, "GET"); + r->method_number = M_GET; + + internal_redirect_handler (location, r); + return OK; + } + + send_http_header (r); + if (!r->header_only) send_fd (f, r); + + pfclose(r->pool, f); + return OK; +} + +handler_rec asis_handlers[] = { +{ ASIS_MAGIC_TYPE, asis_handler }, +{ "send-as-is", asis_handler }, +{ NULL } +}; + +module asis_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + NULL, /* create per-directory config structure */ + NULL, /* merge per-directory config structures */ + NULL, /* create per-server config structure */ + NULL, /* merge per-server config structures */ + NULL, /* command table */ + asis_handlers, /* handlers */ + NULL, /* translate_handler */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* pre-run fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_auth.c b/APACHE_1_2_X/src/modules/standard/mod_auth.c new file mode 100644 index 00000000000..acacaf07b2f --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_auth.c @@ -0,0 +1,298 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * http_auth: authentication + * + * Rob McCool + * + * Adapted to Apache by rst. + * + * dirkx - Added Authoritative control to allow passing on to lower + * modules if and only if the user-id is not known to this + * module. A known user with a faulty or absent password still + * causes an AuthRequired. The default is 'Authoritative', i.e. + * no control is passed along. + */ + +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_log.h" +#include "http_protocol.h" +#if defined(HAVE_CRYPT_H) +#include +#endif + +typedef struct auth_config_struct { + char *auth_pwfile; + char *auth_grpfile; + int auth_authoritative; +} auth_config_rec; + +void *create_auth_dir_config (pool *p, char *d) +{ + auth_config_rec *sec = + (auth_config_rec *) pcalloc (p, sizeof(auth_config_rec)); + sec->auth_pwfile = NULL; /* just to illustrate the default really */ + sec->auth_grpfile = NULL; /* unless you have a broken HP cc */ + sec->auth_authoritative = 1; /* keep the fortress secure by default */ + return sec; +} + +const char *set_auth_slot (cmd_parms *cmd, void *offset, char *f, char *t) +{ + if (t && strcmp(t, "standard")) + return pstrcat(cmd->pool, "Invalid auth file type: ", t, NULL); + + return set_string_slot(cmd, offset, f); +} + +command_rec auth_cmds[] = { +{ "AuthUserFile", set_auth_slot, + (void*)XtOffsetOf(auth_config_rec,auth_pwfile), OR_AUTHCFG, TAKE12, NULL }, +{ "AuthGroupFile", set_auth_slot, + (void*)XtOffsetOf(auth_config_rec,auth_grpfile), OR_AUTHCFG, TAKE12, NULL }, +{ "AuthAuthoritative", set_flag_slot, + (void*)XtOffsetOf(auth_config_rec,auth_authoritative), + OR_AUTHCFG, FLAG, + "Set to 'no' to allow access control to be passed along to lower modules if the UserID is not known to this module" }, +{ NULL } +}; + +module auth_module; + +char *get_pw(request_rec *r, char *user, char *auth_pwfile) +{ + FILE *f; + char l[MAX_STRING_LEN]; + const char *rpw, *w; + + if(!(f=pfopen(r->pool, auth_pwfile, "r"))) { + log_reason ("Could not open password file", auth_pwfile, r); + return NULL; + } + while(!(cfg_getline(l,MAX_STRING_LEN,f))) { + if((l[0] == '#') || (!l[0])) continue; + rpw = l; + w = getword(r->pool, &rpw, ':'); + + if(!strcmp(user,w)) { + pfclose(r->pool, f); + return pstrdup (r->pool, rpw); + } + } + pfclose(r->pool, f); + return NULL; +} + +table *groups_for_user (pool *p, char *user, char *grpfile) { + FILE *f; + table *grps = make_table (p, 15); + pool *sp; + char l[MAX_STRING_LEN]; + const char *group_name, *ll, *w; + + if(!(f=pfopen(p, grpfile, "r"))) + return NULL; + + sp = make_sub_pool (p); + + while(!(cfg_getline(l,MAX_STRING_LEN,f))) { + if((l[0] == '#') || (!l[0])) continue; + ll = l; + clear_pool (sp); + + group_name = getword(sp, &ll, ':'); + + while(ll[0]) { + w = getword_conf (sp, &ll); + if(!strcmp(w,user)) { + table_set (grps, group_name, "in"); + break; + } + } + } + pfclose(p, f); + destroy_pool (sp); + return grps; +} + +/* These functions return 0 if client is OK, and proper error status + * if not... either AUTH_REQUIRED, if we made a check, and it failed, or + * SERVER_ERROR, if things are so totally confused that we couldn't + * figure out how to tell if the client is authorized or not. + * + * If they return DECLINED, and all other modules also decline, that's + * treated by the server core as a configuration error, logged and + * reported as such. + */ + +/* Determine user ID, and check if it really is that user, for HTTP + * basic authentication... + */ + +int authenticate_basic_user (request_rec *r) +{ + auth_config_rec *sec = + (auth_config_rec *)get_module_config (r->per_dir_config, &auth_module); + conn_rec *c = r->connection; + char *sent_pw, *real_pw; + char errstr[MAX_STRING_LEN]; + int res; + + if ((res = get_basic_auth_pw (r, &sent_pw))) return res; + + if(!sec->auth_pwfile) + return DECLINED; + + if (!(real_pw = get_pw(r, c->user, sec->auth_pwfile))) { + if (!(sec->auth_authoritative)) + return DECLINED; + ap_snprintf(errstr, sizeof(errstr), "user %s not found",c->user); + log_reason (errstr, r->uri, r); + note_basic_auth_failure (r); + return AUTH_REQUIRED; + } + /* anyone know where the prototype for crypt is? */ + if(strcmp(real_pw,(char *)crypt(sent_pw,real_pw))) { + ap_snprintf(errstr, sizeof(errstr), "user %s: password mismatch",c->user); + log_reason (errstr, r->uri, r); + note_basic_auth_failure (r); + return AUTH_REQUIRED; + } + return OK; +} + +/* Checking ID */ + +int check_user_access (request_rec *r) { + auth_config_rec *sec = + (auth_config_rec *)get_module_config (r->per_dir_config, &auth_module); + char *user = r->connection->user; + int m = r->method_number; + int method_restricted = 0; + register int x; + const char *t, *w; + table *grpstatus; + array_header *reqs_arr = requires (r); + require_line *reqs; + + /* BUG FIX: tadc, 11-Nov-1995. If there is no "requires" directive, + * then any user will do. + */ + if (!reqs_arr) + return (OK); + reqs = (require_line *)reqs_arr->elts; + + if(sec->auth_grpfile) + grpstatus = groups_for_user (r->pool, user, sec->auth_grpfile); + else + grpstatus = NULL; + + for(x=0; x < reqs_arr->nelts; x++) { + + if (! (reqs[x].method_mask & (1 << m))) continue; + + method_restricted = 1; + + t = reqs[x].requirement; + w = getword(r->pool, &t, ' '); + if(!strcmp(w,"valid-user")) + return OK; + if(!strcmp(w,"user")) { + while(t[0]) { + w = getword_conf (r->pool, &t); + if(!strcmp(user,w)) + return OK; + } + } + else if(!strcmp(w,"group")) { + if(!grpstatus) + return DECLINED; /* DBM group? Something else? */ + + while(t[0]) { + w = getword_conf(r->pool, &t); + if(table_get (grpstatus, w)) + return OK; + } + } + } + + if (!method_restricted) + return OK; + + if (!(sec -> auth_authoritative)) + return DECLINED; + + note_basic_auth_failure (r); + return AUTH_REQUIRED; +} + +module auth_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + create_auth_dir_config, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + NULL, /* server config */ + NULL, /* merge server config */ + auth_cmds, /* command table */ + NULL, /* handlers */ + NULL, /* filename translation */ + authenticate_basic_user, /* check_user_id */ + check_user_access, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_auth_anon.c b/APACHE_1_2_X/src/modules/standard/mod_auth_anon.c new file mode 100644 index 00000000000..2a979e61116 --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_auth_anon.c @@ -0,0 +1,299 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * http_auth: authentication + * + * Rob McCool & Brian Behlendorf. + * + * Adapted to Apache by rst. + * + * Version 0.5 May 1996 + * + * Modified by Dirk.vanGulik@jrc.it to + * + * Adapted to allow anonymous logins, just like with Anon-FTP, when + * one gives the magic user name 'anonymous' and ones email address + * as the password. + * + * Just add the following tokes to your setup: + * + * Anonymous magic-user-id [magic-user-id]... + * + * Anonymous_MustGiveEmail [ on | off ] default = off + * Anonymous_LogEmail [ on | off ] default = on + * Anonymous_VerifyEmail [ on | off ] default = off + * Anonymous_NoUserId [ on | off ] default = off + * Anonymous_Authoritative [ on | off ] default = off + * + * The magic user id is something like 'anonymous', it is NOT case sensitive. + * + * The MustGiveEmail flag can be used to force users to enter something + * in the password field (like an email address). Default is off. + * + * Furthermore the 'NoUserID' flag can be set to allow completely empty + * usernames in as well; this can be is convenient as a single return + * in broken GUIs like W95 is often given by the user. The Default is off. + * + * Dirk.vanGulik@jrc.it; http://ewse.ceo.org; http://me-www.jrc.it/~dirkx + * + */ + +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_log.h" +#include "http_protocol.h" + +typedef struct auth_anon { + char *password; + struct auth_anon * next; + } auth_anon; + +typedef struct { + + auth_anon *auth_anon_passwords; + int auth_anon_nouserid; + int auth_anon_logemail; + int auth_anon_verifyemail; + int auth_anon_mustemail; + int auth_anon_authoritative; + +} anon_auth_config_rec; + +void *create_anon_auth_dir_config (pool *p, char *d) +{ + anon_auth_config_rec * sec = (anon_auth_config_rec *) + pcalloc (p, sizeof(anon_auth_config_rec)); + + if (!sec) return NULL; /* no memory... */ + + /* just to illustrate the defaults really. */ + sec -> auth_anon_passwords =NULL; + + sec -> auth_anon_nouserid =0; + sec -> auth_anon_logemail =1; + sec -> auth_anon_verifyemail =0; + sec -> auth_anon_mustemail =1; + sec -> auth_anon_authoritative =0; + return sec; +} + +const char *anon_set_passwd_flag (cmd_parms *cmd, + anon_auth_config_rec *sec, int arg) { + sec->auth_anon_mustemail=arg; + return NULL; +} + +const char *anon_set_userid_flag (cmd_parms *cmd, + anon_auth_config_rec *sec, int arg) { + sec->auth_anon_nouserid=arg; + return NULL; +} +const char *anon_set_logemail_flag (cmd_parms *cmd, + anon_auth_config_rec *sec, int arg) { + sec->auth_anon_logemail=arg; + return NULL; +} +const char *anon_set_verifyemail_flag (cmd_parms *cmd, + anon_auth_config_rec *sec, int arg) { + sec->auth_anon_verifyemail=arg; + return NULL; +} +const char *anon_set_authoritative_flag (cmd_parms *cmd, + anon_auth_config_rec *sec, int arg) { + sec->auth_anon_authoritative=arg; + return NULL; +} + +const char *anon_set_string_slots (cmd_parms *cmd, + anon_auth_config_rec *sec, char *arg) { + + auth_anon * first; + + if (!(*arg)) + return "Anonymous string cannot be empty, use Anonymous_NoUserId instead"; + + /* squeeze in a record */ + first = sec->auth_anon_passwords; + + if ( + (!(sec->auth_anon_passwords=(auth_anon *) palloc(cmd -> pool, sizeof(auth_anon)))) || + (!(sec->auth_anon_passwords->password = pstrdup(cmd -> pool, arg))) + ) return "Failed to claim memory for an anonymous password..."; + + /* and repair the next */ + sec->auth_anon_passwords->next = first; + + return NULL; +} + +command_rec anon_auth_cmds[] = { +{ "Anonymous", anon_set_string_slots, + NULL,OR_AUTHCFG, ITERATE, NULL }, +{ "Anonymous_MustGiveEmail", anon_set_passwd_flag, NULL, OR_AUTHCFG, FLAG, + "Limited to 'on' or 'off'" }, +{ "Anonymous_NoUserId", anon_set_userid_flag, NULL, OR_AUTHCFG, FLAG, + "Limited to 'on' or 'off'" }, +{ "Anonymous_VerifyEmail", anon_set_verifyemail_flag, NULL, OR_AUTHCFG, FLAG, + "Limited to 'on' or 'off'" }, +{ "Anonymous_LogEmail", anon_set_logemail_flag, NULL, OR_AUTHCFG, FLAG, + "Limited to 'on' or 'off'" }, +{ "Anonymous_Authoritative", anon_set_authoritative_flag, NULL, OR_AUTHCFG, FLAG, + "Limited to 'on' or 'off'" }, + +{ NULL } +}; + +module anon_auth_module; + +int anon_authenticate_basic_user (request_rec *r) +{ + anon_auth_config_rec *sec = + (anon_auth_config_rec *)get_module_config (r->per_dir_config, + &anon_auth_module); + conn_rec *c = r->connection; + char *send_pw; + char errstr[MAX_STRING_LEN]; + int res=DECLINED; + + + if ((res=get_basic_auth_pw (r,&send_pw))) + return res; + + /* Ignore if we are not configured */ + if (!sec->auth_anon_passwords) return DECLINED; + + /* Do we allow an empty userID and/or is it the magic one + */ + + if ( (!(c->user[0])) && (sec->auth_anon_nouserid) ) { + res=OK; + } else { + auth_anon *p=sec->auth_anon_passwords; + res=DECLINED; + while ((res == DECLINED) && (p !=NULL)) { + if (!(strcasecmp(c->user,p->password))) + res=OK; + p=p->next; + } + } + if ( + /* username is OK */ + (res == OK) && + /* password been filled out ? */ + ( (!sec->auth_anon_mustemail) || strlen(send_pw) ) && + /* does the password look like an email address ? */ + ( (!sec->auth_anon_verifyemail) || + ((strpbrk("@",send_pw) != NULL) + && + (strpbrk(".",send_pw) != NULL)) + ) + ) { + if (sec->auth_anon_logemail) { + ap_snprintf(errstr, sizeof(errstr), "Anonymous: Passwd <%s> Accepted", + send_pw ? send_pw : "\'none\'"); + log_error (errstr, r->server ); + } + return OK; + } else { + if (sec->auth_anon_authoritative) { + ap_snprintf(errstr, sizeof(errstr), + "Anonymous: Authoritative, Passwd <%s> not accepted", + send_pw ? send_pw : "\'none\'"); + log_error(errstr,r->server); + return AUTH_REQUIRED; + } + /* Drop out the bottom to return DECLINED */ + } + + + return DECLINED; +} + +int check_anon_access (request_rec *r) { + +#ifdef NOTYET + conn_rec *c = r->connection; + anon_auth_config_rec *sec = + (anon_auth_config_rec *)get_module_config (r->per_dir_config, + &anon_auth_module); + + if (!sec->auth_anon) return DECLINED; + + if ( strcasecmp(r->connection->user,sec->auth_anon )) + return DECLINED; + + return OK; +#endif + return DECLINED; +} + + +module anon_auth_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + create_anon_auth_dir_config, /* dir config creater */ + NULL, /* dir merger ensure strictness */ + NULL, /* server config */ + NULL, /* merge server config */ + anon_auth_cmds, /* command table */ + NULL, /* handlers */ + NULL, /* filename translation */ + anon_authenticate_basic_user,/* check_user_id */ + check_anon_access, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_auth_db.c b/APACHE_1_2_X/src/modules/standard/mod_auth_db.c new file mode 100644 index 00000000000..76d21d7ea6c --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_auth_db.c @@ -0,0 +1,303 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * mod_auth_db: authentication + * + * Original work by Rob McCool & Brian Behlendorf. + * + * Adapted to Apache by rst (mod_auth_dbm) + * + * Adapted for Berkeley DB by Andrew Cohen + * + * mod_auth_db was based on mod_auth_dbm. + * + * Warning, this is not a drop in replacement for mod_auth_dbm, + * for people wanting to switch from dbm to Berkeley DB. + * It requires the use of AuthDBUserFile and AuthDBGroupFile + * instead of AuthDBMUserFile AuthDBMGroupFile + * + * Also, in the configuration file you need to specify + * db_auth_module rather than dbm_auth_module + * + * On some BSD systems (e.g. FreeBSD and NetBSD) dbm is automatically + * mapped to Berkeley DB. You can use either mod_auth_dbm or + * mod_auth_db. The latter makes it more obvious that it's Berkeley. + * + * dirkx - Added Authoritative control to allow passing on to lower + * modules if and only if the user-id is not known to this + * module. A known user with a faulty or absent password still + * causes an AuthRequired. The default is 'Authoritative', i.e. + * no control is passed along. + */ + +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_log.h" +#include "http_protocol.h" +#include + +typedef struct { + + char *auth_dbpwfile; + char *auth_dbgrpfile; + int auth_dbauthoritative; +} db_auth_config_rec; + +void *create_db_auth_dir_config (pool *p, char *d) +{ + db_auth_config_rec *sec + = (db_auth_config_rec *)pcalloc (p, sizeof(db_auth_config_rec)); + sec->auth_dbpwfile = NULL; + sec->auth_dbgrpfile = NULL; + sec->auth_dbauthoritative=1; /* fortress is secure by default */ + return sec; +} + +const char *set_db_slot (cmd_parms *cmd, void *offset, char *f, char *t) +{ + if (!t || strcmp(t, "db")) + return DECLINE_CMD; + + return set_string_slot(cmd, offset, f); +} + +command_rec db_auth_cmds[] = { +{ "AuthDBUserFile", set_string_slot, + (void*)XtOffsetOf(db_auth_config_rec, auth_dbpwfile), + OR_AUTHCFG, TAKE1, NULL }, +{ "AuthDBGroupFile", set_string_slot, + (void*)XtOffsetOf(db_auth_config_rec, auth_dbgrpfile), + OR_AUTHCFG, TAKE1, NULL }, +{ "AuthUserFile", set_db_slot, + (void*)XtOffsetOf(db_auth_config_rec, auth_dbpwfile), + OR_AUTHCFG, TAKE12, NULL }, +{ "AuthGroupFile", set_db_slot, + (void*)XtOffsetOf(db_auth_config_rec, auth_dbgrpfile), + OR_AUTHCFG, TAKE12, NULL }, +{ "AuthDBAuthoritative", set_flag_slot, + (void*)XtOffsetOf(db_auth_config_rec, auth_dbauthoritative), + OR_AUTHCFG, FLAG, + "Set to 'no' to allow access control to be passed along to lower modules if the userID is not known to this module" }, +{ NULL } +}; + +module db_auth_module; + +char *get_db_pw(request_rec *r, char *user, const char *auth_dbpwfile) { + DB *f; + DBT d, q; + char *pw = NULL; + + q.data = user; + q.size = strlen(q.data); + + if(!(f=dbopen(auth_dbpwfile,O_RDONLY,0664,DB_HASH,NULL))) { + log_reason ("could not open db auth file", (char *) auth_dbpwfile, r); + return NULL; + } + + if (!((f->get)(f,&q,&d,0))) { + pw = palloc (r->pool, d.size + 1); + strncpy(pw,d.data,d.size); + pw[d.size] = '\0'; /* Terminate the string */ + } + + (f->close)(f); + return pw; +} + +/* We do something strange with the group file. If the group file + * contains any : we assume the format is + * key=username value=":"groupname [":"anything here is ignored] + * otherwise we now (0.8.14+) assume that the format is + * key=username value=groupname + * The first allows the password and group files to be the same + * physical DB file; key=username value=password":"groupname[":"anything] + * + * mark@telescope.org, 22Sep95 + */ + +char *get_db_grp(request_rec *r, char *user, const char *auth_dbgrpfile) { + char *grp_data = get_db_pw (r, user, auth_dbgrpfile); + char *grp_colon; char *grp_colon2; + + if (grp_data == NULL) return NULL; + + if ((grp_colon = strchr(grp_data, ':'))!=NULL) { + grp_colon2 = strchr(++grp_colon, ':'); + if (grp_colon2) *grp_colon2='\0'; + return grp_colon; + } + return grp_data; +} + +int db_authenticate_basic_user (request_rec *r) +{ + db_auth_config_rec *sec = + (db_auth_config_rec *)get_module_config (r->per_dir_config, + &db_auth_module); + conn_rec *c = r->connection; + char *sent_pw, *real_pw, *colon_pw; + char errstr[MAX_STRING_LEN]; + int res; + + if ((res = get_basic_auth_pw (r, &sent_pw))) + return res; + + if(!sec->auth_dbpwfile) + return DECLINED; + + if(!(real_pw = get_db_pw(r, c->user, sec->auth_dbpwfile))) { + if (!(sec -> auth_dbauthoritative)) + return DECLINED; + ap_snprintf(errstr, sizeof(errstr), "DB user %s not found", c->user); + log_reason (errstr, r->filename, r); + note_basic_auth_failure (r); + return AUTH_REQUIRED; + } + /* Password is up to first : if exists */ + colon_pw = strchr(real_pw,':'); + if (colon_pw) *colon_pw='\0'; + /* anyone know where the prototype for crypt is? */ + if(strcmp(real_pw,(char *)crypt(sent_pw,real_pw))) { + ap_snprintf(errstr, sizeof(errstr), + "user %s: password mismatch",c->user); + log_reason (errstr, r->uri, r); + note_basic_auth_failure (r); + return AUTH_REQUIRED; + } + return OK; +} + +/* Checking ID */ + +int db_check_auth(request_rec *r) { + db_auth_config_rec *sec = + (db_auth_config_rec *)get_module_config (r->per_dir_config, + &db_auth_module); + char *user = r->connection->user; + int m = r->method_number; + char errstr[MAX_STRING_LEN]; + + array_header *reqs_arr = requires (r); + require_line *reqs = reqs_arr ? (require_line *)reqs_arr->elts : NULL; + + register int x; + const char *t; + char *w; + + if (!sec->auth_dbgrpfile) return DECLINED; + if (!reqs_arr) return DECLINED; + + for(x=0; x < reqs_arr->nelts; x++) { + + if (! (reqs[x].method_mask & (1 << m))) continue; + + t = reqs[x].requirement; + w = getword(r->pool, &t, ' '); + + if(!strcmp(w,"group") && sec->auth_dbgrpfile) { + const char *orig_groups,*groups; + char *v; + + if (!(groups = get_db_grp(r, user, sec->auth_dbgrpfile))) { + if (!(sec->auth_dbauthoritative)) + return DECLINED; + ap_snprintf(errstr, sizeof(errstr), + "user %s not in DB group file %s", + user, sec->auth_dbgrpfile); + log_reason (errstr, r->filename, r); + note_basic_auth_failure (r); + return AUTH_REQUIRED; + } + orig_groups = groups; + while(t[0]) { + w = getword(r->pool, &t, ' '); + groups = orig_groups; + while(groups[0]) { + v = getword(r->pool, &groups,','); + if(!strcmp(v,w)) + return OK; + } + } + ap_snprintf(errstr, sizeof(errstr), + "user %s not in right group",user); + log_reason (errstr, r->filename, r); + note_basic_auth_failure(r); + return AUTH_REQUIRED; + } + } + + return DECLINED; +} + + +module db_auth_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + create_db_auth_dir_config, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + NULL, /* server config */ + NULL, /* merge server config */ + db_auth_cmds, /* command table */ + NULL, /* handlers */ + NULL, /* filename translation */ + db_authenticate_basic_user, /* check_user_id */ + db_check_auth, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_auth_dbm.c b/APACHE_1_2_X/src/modules/standard/mod_auth_dbm.c new file mode 100644 index 00000000000..d383264e9f6 --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_auth_dbm.c @@ -0,0 +1,291 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * http_auth: authentication + * + * Rob McCool & Brian Behlendorf. + * + * Adapted to Apache by rst. + * + * dirkx - Added Authoritative control to allow passing on to lower + * modules if and only if the user-id is not known to this + * module. A known user with a faulty or absent password still + * causes an AuthRequired. The default is 'Authoritative', i.e. + * no control is passed along. + */ + +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_log.h" +#include "http_protocol.h" +#include + +typedef struct { + + char *auth_dbmpwfile; + char *auth_dbmgrpfile; + int auth_dbmauthoritative; + +} dbm_auth_config_rec; + +void *create_dbm_auth_dir_config (pool *p, char *d) +{ + dbm_auth_config_rec *sec + = (dbm_auth_config_rec *)pcalloc (p, sizeof(dbm_auth_config_rec)); + + sec->auth_dbmpwfile = NULL; + sec->auth_dbmgrpfile = NULL; + sec->auth_dbmauthoritative = 1; /* fortress is secure by default */ + + return sec; +} + +const char *set_dbm_slot (cmd_parms *cmd, void *offset, char *f, char *t) +{ + if (!t || strcmp(t, "dbm")) + return DECLINE_CMD; + + return set_string_slot(cmd, offset, f); +} + +command_rec dbm_auth_cmds[] = { +{ "AuthDBMUserFile", set_string_slot, + (void*)XtOffsetOf(dbm_auth_config_rec, auth_dbmpwfile), + OR_AUTHCFG, TAKE1, NULL }, +{ "AuthDBMGroupFile", set_string_slot, + (void*)XtOffsetOf(dbm_auth_config_rec, auth_dbmgrpfile), + OR_AUTHCFG, TAKE1, NULL }, +{ "AuthUserFile", set_dbm_slot, + (void*)XtOffsetOf(dbm_auth_config_rec, auth_dbmpwfile), + OR_AUTHCFG, TAKE12, NULL }, +{ "AuthGroupFile", set_dbm_slot, + (void*)XtOffsetOf(dbm_auth_config_rec, auth_dbmgrpfile), + OR_AUTHCFG, TAKE12, NULL }, +{ "AuthDBMAuthoritative", set_flag_slot, + (void*)XtOffsetOf(dbm_auth_config_rec, auth_dbmauthoritative), + OR_AUTHCFG, FLAG, "Set to 'no' to allow access control to be passed along to lower modules, if the UserID is not known in this module" }, +{ NULL } +}; + +module dbm_auth_module; + +char *get_dbm_pw(request_rec *r, char *user, char *auth_dbmpwfile) { + DBM *f; + datum d, q; + char *pw = NULL; + + q.dptr = user; + q.dsize = strlen(q.dptr); + + if(!(f=dbm_open(auth_dbmpwfile,O_RDONLY,0664))) { + log_reason ("could not open dbm auth file", auth_dbmpwfile, r); + return NULL; + } + + d = dbm_fetch(f, q); + + if (d.dptr) { + pw = palloc (r->pool, d.dsize + 1); + strncpy(pw,d.dptr,d.dsize); + pw[d.dsize] = '\0'; /* Terminate the string */ + } + + dbm_close(f); + return pw; +} + +/* We do something strange with the group file. If the group file + * contains any : we assume the format is + * key=username value=":"groupname [":"anything here is ignored] + * otherwise we now (0.8.14+) assume that the format is + * key=username value=groupname + * The first allows the password and group files to be the same + * physical DBM file; key=username value=password":"groupname[":"anything] + * + * mark@telescope.org, 22Sep95 + */ + +char *get_dbm_grp(request_rec *r, char *user, char *auth_dbmgrpfile) { + char *grp_data = get_dbm_pw (r, user, auth_dbmgrpfile); + char *grp_colon; char *grp_colon2; + + if (grp_data == NULL) return NULL; + + if ((grp_colon = strchr(grp_data, ':'))!=NULL) { + grp_colon2 = strchr(++grp_colon, ':'); + if (grp_colon2) *grp_colon2='\0'; + return grp_colon; + } + return grp_data; +} + +int dbm_authenticate_basic_user (request_rec *r) +{ + dbm_auth_config_rec *sec = + (dbm_auth_config_rec *)get_module_config (r->per_dir_config, + &dbm_auth_module); + conn_rec *c = r->connection; + char *sent_pw, *real_pw, *colon_pw; + char errstr[MAX_STRING_LEN]; + int res; + + if ((res = get_basic_auth_pw (r, &sent_pw))) + return res; + + if(!sec->auth_dbmpwfile) + return DECLINED; + + if(!(real_pw = get_dbm_pw(r, c->user, sec->auth_dbmpwfile))) { + if (!(sec->auth_dbmauthoritative)) + return DECLINED; + ap_snprintf(errstr, sizeof(errstr), "DBM user %s not found", c->user); + log_reason (errstr, r->filename, r); + note_basic_auth_failure (r); + return AUTH_REQUIRED; + } + /* Password is up to first : if exists */ + colon_pw = strchr(real_pw,':'); + if (colon_pw) *colon_pw='\0'; + /* anyone know where the prototype for crypt is? */ + if(strcmp(real_pw,(char *)crypt(sent_pw,real_pw))) { + ap_snprintf(errstr, sizeof(errstr), + "user %s: password mismatch",c->user); + log_reason (errstr, r->uri, r); + note_basic_auth_failure (r); + return AUTH_REQUIRED; + } + return OK; +} + +/* Checking ID */ + +int dbm_check_auth(request_rec *r) { + dbm_auth_config_rec *sec = + (dbm_auth_config_rec *)get_module_config (r->per_dir_config, + &dbm_auth_module); + char *user = r->connection->user; + int m = r->method_number; + char errstr[MAX_STRING_LEN]; + + array_header *reqs_arr = requires (r); + require_line *reqs = reqs_arr ? (require_line *)reqs_arr->elts : NULL; + + register int x; + const char *t; + char *w; + + if (!sec->auth_dbmgrpfile) return DECLINED; + if (!reqs_arr) return DECLINED; + + for(x=0; x < reqs_arr->nelts; x++) { + + if (! (reqs[x].method_mask & (1 << m))) continue; + + t = reqs[x].requirement; + w = getword(r->pool, &t, ' '); + + if(!strcmp(w,"group") && sec->auth_dbmgrpfile) { + const char *orig_groups,*groups; + char *v; + + if (!(groups = get_dbm_grp(r, user, sec->auth_dbmgrpfile))) { + if (!(sec->auth_dbmauthoritative)) + return DECLINED; + ap_snprintf(errstr, sizeof(errstr), + "user %s not in DBM group file %s", + user, sec->auth_dbmgrpfile); + log_reason (errstr, r->filename, r); + note_basic_auth_failure (r); + return AUTH_REQUIRED; + } + orig_groups = groups; + while(t[0]) { + w = getword(r->pool, &t, ' '); + groups = orig_groups; + while(groups[0]) { + v = getword(r->pool, &groups,','); + if(!strcmp(v,w)) + return OK; + } + } + ap_snprintf(errstr, sizeof(errstr), + "user %s not in right group",user); + log_reason (errstr, r->filename, r); + note_basic_auth_failure(r); + return AUTH_REQUIRED; + } + } + + return DECLINED; +} + + +module dbm_auth_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + create_dbm_auth_dir_config, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + NULL, /* server config */ + NULL, /* merge server config */ + dbm_auth_cmds, /* command table */ + NULL, /* handlers */ + NULL, /* filename translation */ + dbm_authenticate_basic_user, /* check_user_id */ + dbm_check_auth, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_auth_msql.c b/APACHE_1_2_X/src/modules/standard/mod_auth_msql.c new file mode 100644 index 00000000000..dc8064276e8 --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_auth_msql.c @@ -0,0 +1,996 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * mod_auth_msql: authentication + * + * Rob McCool & Brian Behlendorf. + * + * Adapted to Apache by rst. + * + * Addapted for use with the mSQL database + * (see ftp:/ftp.bond.edu.au/pub/Minerva/mSQL) + * + * Version 1.0 May 1996 - Blame: Dirk.vanGulik@jrc.it. + * + * A (sometimes more up to date) version of the documentation + * can be found at the http://www.apache.org site or at + * http://me-www.jrc.it/~dirkx/mod_auth_msql.html. + * + * Outline: + * + * This module allows access control using the public domain + * mSQL database; a fast but limted SQL engine which can be + * contacted over an internal unix domain protocol as well as + * over normal inter-machine tcp/ip socket communication. + * + * An example table could be: + * + * create table user_records ( + * User_id char(32) primary key, + * Cpasswd char(32), + * [ Xgroup char(32) ] + * ) \g + * + * The user_id can be as long as desired; however some of the + * popular web browsers truncate, or stop the user from entering + * names longer than 32 characters. Furthermore the 'crypt' function + * on your platform might impose further limits. Also use of + * the 'require users uid [uid..]' directive in the access.conf file, + * where the user ids are separated by spaces can possibly prohibit the + * use of spaces in your user-names. Also, not the MAX_FIELD_LEN define + * somewhere below. + * + * To use the above, the following example could be in your access.conf + * file. Also there is a more elaborate description afther this example. + * + * + * + * Auth_MSQLhost localhost + * or + * Auth_MSQLhost datab.machine.your.org + * + * If this directive is ommited, or set to + * localhost, the machine on which apache + * runs is assumed, and the faster /dev/msql + * communication channel will be used. Otherwise + * it is the machine to contact by tcp/ip. + * + * Auth_MSQLdatabase www + * + * The name of the database on the above machine, + * which contains *both* the tables for group and + * for user/passwords. Currently it is not possible + * to have these split over two databases. Make + * sure that the msql.acl (access control file) of + * mSQL does indeed allow the effective uid of the + * web server read access to this database. Check the + * httpd.conf file for this uid. + * + * Auth_MSQLpwd_table user_records + * + * Here the table which contain the uid/password combination + * is specified. + * + * Auth_MSQLuid_field User_id + * Auth_MSQLpwd_field Cpasswd + * + * These two directive specify the field names in the 'user_record' + * table. If this module is compiled with the BACKWARD_VITEK + * compatibility switch, the defaults 'user' and 'password' are + * assumed if you do not specify them. Currently the user_id field + * *MUST* be a primary key or one must ensure that each user only + * occurs *once* in the table. If a UID occurs twice access is + * denied by default. + * + * Auth_MSQLgrp_table user_records + * Auth_MSQLgrp_field Xgroup + * + * Optionaly one can also specify a table which contains the + * user/group combinations. This can be the same table which + * also contains the username/password combinations. However + * if a user belongs to two or more groups, one will have to + * use a differt table with multiple entries. + * + * Auth_MSQL_nopasswd off + * Auth_MSQL_Authoritative on + * Auth_MSQL_EncryptedPasswords on + * + * These three optional fields (all set to the sensible defaults, + * so you really do not have to enter them) are described in more + * detail below. If you choose to set these to any other values than + * the above be very sure you understand the security implications and + * do verify that apache does what you exect it to do. + * + * AuthName example mSQL realm + * AuthType basic + * + * Normal apache/ncsa tokens for access control + * + * + * order deny,allow + * allow from all + * + * require valid-user + * 'valid-user'; allow in any user which has a valid uid/passwd + * pair in the above pwd_table. + * or + * require user smith jones + * Limit access to users who have a valid uid/passwd pair in the + * above pwd_table AND whose uid is 'smith' or 'jones'. Do note that + * the uid's are separated by 'spaces' for historic (ncsa) reasons. + * So allowing uids with spaces might cause problems. + * + * require group has_paid + * Optionally also ensure that the uid has the value 'has_paid' in the group + * field in the group table. + * + * + * + * End of the example + * + * - full description of all tokens: - + * + * Directives: + * + * Auth_MSQLhost Hostname of the machine running + * the mSQL demon. The effective uid + * of the server should be allowed + * access. If not given, or if it is + * the magic name 'localhost', it is + * passed to the mSQL libary as a null + * pointer. This effectively forces it + * to use /dev/msql rather than the + * (slower) socket communication. + * + * Auth_MSQLdatabase Name of the database in which the following + * table(s) are contained. + * + * Auth_MSQLpwd_table Contains at least the fields with the + * username and the (encrypted) password. Each + * uid should only occur once in this table and + * for performance reasons should be a primary key. + * Normally this table is compulsory, but it is + * possible to use a fall-through to other methods + * and use the mSQL module for group control only; + * see the Authoritative directive below. + * + * Auth_MSQLgrp_table Contains at least the fields with the + * username and the groupname. A user which + * is in multiple groups has therefore + * multiple entries; this might be some per- + * formance problems associated with this; and one + * might consider to have separate tables for each + * group (rather than all groups in one table) if + * your directory structure allows for it. + * One only needs to specify this table when doing + * group control. + * + * Auth_MSQLuid_field Name of the field containing the username + * Auth_MSQLpwd_field Fieldname for the passwords + * Auth_MSQLgrp_field Fieldname for the groupname + * + * Only the fields used need to be specified. When this + * module is compiled with the BACKWARD_VITEK option the + * uid and pwd field names default to 'user' and 'password'. + * + * + * Auth_MSQL_nopasswd + * skip password comparison if passwd field is + * empty; i.e. allow 'any' password. This is off + * by default; thus to ensure that an empty field + * in the mSQL table does not allow people in by + * default with a random password. + * + * Auth_MSQL_Authoritative + * default is 'on'. When set on, there is no + * fall through to other authorization methods. So if a + * user is not in the mSQL dbase table (and perhaps + * not in the right group) or has the password wrong, then + * he or she is denied access. When this directive is set to + * 'off' control is passed on to any other authorization + * modules, such as the basic auth module wih the htpasswd + * file and or the unix-(g)dbm modules. + * The default is 'ON' to avoid nasty 'fall-through' sur- + * prizes. Do be sure you know what you decide to switch + * it off. + * + * Auth_MSQL_EncryptedPasswords + * default is on. When set on, the values in the + * pwd_field are assumed to be crypted using *your* + * machines 'crypt' function; and the incoming password + * is 'crypt'ed before comparison. When this function is + * off, the comparison is done directly with the plaintext + * entered password. (Yes; http-basic-auth does send the + * password as plaintext over the wire :-( ). The default + * is a sensible 'on', and I personally thing that it is + * a *very-bad-idea* to change this. However a multi + * vendor or international environment (which sometimes + * leads to different crypts functions) might force you to. + * + * Dirk.vanGulik@jrc.it; http://ewse.ceo.org; http://me-www.jrc.it/~dirkx + * 23 Nov 1995, 24 Feb 1996, 16 May 1996. + * + * Version 0.0 First release + * 0.1 Update to apache 1.00 + * 0.2 added lines which got missing god knows when + * and which did the valid-user authentification + * no good at all ! + * 0.3 Added 'Auth_MSQL_nopasswd' option + * 0.4 Cleaned out the error messages mess. + * 0.6 Inconsistency with gid/grp in comment/token/source + * Make sure you really use 'Auth_MSQLgrp_field' as + * indicated above. + * 0.7 *host to host fixed. Credits go to Rob Stout, + * for spotting this one. + * 0.8 Authoritative directive added. See above. + * 0.9 palloc return code check(s), should be backward compatible with + * 1.11 version of Vivek Khera msql module, + * fixed broken err msg in group control, changed command table + * messages to make more sense when displayed in that new module + * management tool. Added EncryptedPassword on/off functionality. + * msqlClose() statements added upon error. Support for persistent + * connections with the mSQL database (riscy). Escaping of ' and \. + * Replaced some MAX_STRING_LEN claims. + * 1.0 removed some error check as they where already done elsehwere + * NumFields -> NumRows (Thanks Vitek). More stack memory. + * 1.1 no logging of empty password strings. + * 1.2 Problem with the Backward vitek which cause it to check + * even if msql_auth was not configured; Also more carefull + * with the authoritative stuff; caught by thomas@marvin.calvacom.fr. + * 1.3 Even more changes to get it right; that BACKWARD thing was a bad + * idea. + */ + + +#define ONLY_ONCE 1 +/* + * If the mSQL table containing the uid/passwd combination does + * not have the uid field as a primary key, it is possible for the + * uid to occur more than once in the table with possibly different + * passwords. When this module is compiled with the ONLY_ONCE directive + * set, access is denied if the uid occures more than once in the + * uid/passwd table. If you choose not to set it, the software takes + * the first pair returned and ignores any further pairs. The SQL + * statement used for this is + * + * "select password form pwd_table where user='uid'" + * + * this might lead to unpredictable results. For this reason as well + * as for performance reasons you are strongly adviced to make the + * uid field a primary key. Use at your own peril :-) + */ + +#undef KEEP_MSQL_CONNECTION_OPEN +/* + * Normally the (tcp/ip) connection with the database is opened and + * closed for each SQL query. When the httpd-server and the database + * are on the same machine, and /dev/msql is used this does not + * cause a serious overhead. However when your platform does not + * support this (see the mSQL documentation) or when the web server + * and the database are on different machines the overhead can be + * considerable. When the above is set defined the server leaves the + * connection open; i.e. no call to msqlClose(). If an error occures + * an attempt is made to re-open the connection for the next http-rq. + * + * This has a number of very serious drawbacks + * - It costs 2 already rare filedescriptors for each child. + * - It costs msql-connections, typically one per child. The (compiled in) + * number of connections mSQL can handle is low, typically 6 or 12. + * which might prohibit access to the mSQL database for later + * processes. + * - when a child dies, it might not free that connection properly + * or quick enough. + * - When errors start to occur, connection/file-descr resources might + * become exausted very quickly. + * + * In short; use this at your own peril and only in a highly controled and + * monitored environment + */ + +#define BACKWARD_VITEK +#define VITEX_uid_name "user" +#define VITEX_gid_name "passwd" +/* A second mSQL auth module for apache has also been developed by + * Vivek Khera and was subsequently distributed + * with some early versions of Apache. It can be optained from + * ftp://ftp.kcilink.com/pub/mod_auth_msql.c*. Older 'vitek' versions had + * the field/table names compiled in; newer versions, v.1.11 have + * more access.conf configuration options; however these where + * choosen not to be in line the 'ewse' version of this module. Also, + * the 'vitek' module does not give group control or 'empty' password + * control. + * + * To get things slightly more in line this version (0.9) should + * be backward compatible with the vitek module by: + * + * - adding support for the EncryptedPassword on/off functionality + * + * - adding support for the different spelling fo the 4 configuration + * tokens for user-table-name, user/password-field-name and dbase-name. + * + * - setting some field names to a default which used to be hard + * coded in in older vitek modules. + * + * If this troubles you; remove the 'BACKWARD_VITEX' define. + */ + +/* get some sensible values; rather than that big MAX_STRING_LEN, + */ + +/* Max field value length limit; well above the limit of some browsers :-) + */ +#define MAX_FIELD_LEN (64) +/* the next two values can be pulled from msql_priv.c, which is *NOT* copied to your + * /usr/local/include as part of the normal install procedure which comes with + * mSQL. + */ +#define MSQL_FIELD_NAME_LEN (19) +#define MSQL_TABLE_NAME_LEN (19) +/* We only do the following two queries: + * + * - for the user/passwd combination + * select PWDFIELD from PWDTABEL where USERFIELD='UID' + * + * - optionally for the user/group combination: + * select GROUPFIELD from GROUPTABLE where USERFIELD='UID' and GROUPFIELD='GID' + * + * This leads to the following limits: (we are ignoring escaping a wee bit bit here + * assuming not more than 24 escapes.) + */ + +#define MAX_QUERY_LEN (32+24+MAX_FIELD_LEN*2+3*MSQL_FIELD_NAME_LEN+1*MSQL_TABLE_NAME_LEN) + + +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_log.h" +#include "http_protocol.h" +#include +#ifdef HAVE_CRYPT_H +#include +#endif + +typedef struct { + + char *auth_msql_host; + char *auth_msql_database; + + char *auth_msql_pwd_table; + char *auth_msql_grp_table; + + char *auth_msql_pwd_field; + char *auth_msql_uname_field; + char *auth_msql_grp_field; + + int auth_msql_nopasswd; + int auth_msql_authoritative; + int auth_msql_encrypted; + +} msql_auth_config_rec; + +void *create_msql_auth_dir_config (pool *p, char *d) +{ + msql_auth_config_rec * sec= (msql_auth_config_rec *) pcalloc (p, sizeof(msql_auth_config_rec)); + + sec->auth_msql_host = NULL; /* just to enforce the default 'localhost' behaviour */ + + /* just in case, to be nice... */ + sec->auth_msql_database = NULL; + sec->auth_msql_pwd_table = NULL; + sec->auth_msql_grp_table = NULL; + sec->auth_msql_pwd_field = NULL; + sec->auth_msql_uname_field = NULL; + sec->auth_msql_grp_field = NULL; + + + sec->auth_msql_authoritative = 1; /* set some defaults, just in case... */ + sec->auth_msql_encrypted = 1; + sec->auth_msql_nopasswd = 0; + +#ifdef BACKWARD_VITEK + /* these are for backward compatibility with the Vivek + * msql module, as it used to have compile-time defaults. + */ + sec->auth_msql_uname_field = VITEX_uid_name; + sec->auth_msql_pwd_field = VITEX_gid_name; +#endif + + return sec; +} + +const char *set_passwd_flag (cmd_parms *cmd, msql_auth_config_rec *sec, int arg) { + sec->auth_msql_nopasswd=arg; + return NULL; +} + +const char *set_authoritative_flag (cmd_parms *cmd, msql_auth_config_rec *sec, int arg) { + sec->auth_msql_authoritative=arg; + return NULL; +} + +const char *set_crypted_password_flag (cmd_parms *cmd, msql_auth_config_rec *sec , int arg) { + sec->auth_msql_encrypted = arg; + return NULL; +} + +const char *msql_set_string_slot (cmd_parms *cmd, char *struct_ptr, char *arg) { + int offset = (int)cmd->info; + *(char **)(struct_ptr + offset) = pstrdup (cmd->pool, arg); + return NULL; +} + + +command_rec msql_auth_cmds[] = { +{ "Auth_MSQLhost", msql_set_string_slot, + (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_host), + OR_AUTHCFG, TAKE1, "Host on which the mSQL database engine resides (defaults to localhost)" }, + +{ "Auth_MSQLdatabase", msql_set_string_slot, + (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_database), + OR_AUTHCFG, TAKE1, "Name of the mSQL database which contains the password (and possibly the group) tables. " }, + +{ "Auth_MSQLpwd_table", msql_set_string_slot, + (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_pwd_table), + OR_AUTHCFG, TAKE1, "Name of the mSQL table containing the password/user-name combination" }, + +{ "Auth_MSQLgrp_table", msql_set_string_slot, + (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_grp_table), + OR_AUTHCFG, TAKE1, "Name of the mSQL table containing the group-name/user-name combination; can be the same as the password-table." }, + +{ "Auth_MSQLpwd_field", msql_set_string_slot, + (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_pwd_field), + OR_AUTHCFG, TAKE1, "The name of the field in the mSQL password table" }, + +{ "Auth_MSQLuid_field", msql_set_string_slot, + (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_uname_field), + OR_AUTHCFG, TAKE1, "The name of the user-name field in the mSQL password (and possibly group) table(s)." }, + +{ "Auth_MSQLgrp_field", msql_set_string_slot, + (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_grp_field), + OR_AUTHCFG, TAKE1, + "The name of the group field in the mSQL group table; must be set if you want to use groups." }, + +{ "Auth_MSQL_nopasswd", set_passwd_flag, NULL, OR_AUTHCFG, FLAG, + "Enable (on) or disable (off) empty password strings; in which case any user password is accepted." }, + +{ "Auth_MSQL_Authoritative", set_authoritative_flag, NULL, OR_AUTHCFG, FLAG, + "When 'on' the mSQL database is taken to be authoritative and access control is not passed along to other db or access modules." }, + +{ "Auth_MSQL_EncryptedPasswords", set_crypted_password_flag, NULL, OR_AUTHCFG, FLAG, + "When 'on' the password in the password table are taken to be crypt()ed using your machines crypt() function." }, + +#ifdef BACKWARD_VITEK +/* These 'altenative' tokens should ensure backward compatibility + * with viteks mSQL module. The only difference is the spelling. + * Note that these tokens do not allow group configuration. + */ +{ "AuthMSQLHost", set_string_slot, + (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_host), + OR_AUTHCFG, TAKE1, "mSQL server hostname" }, +{ "AuthMSQLDB", set_string_slot, + (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_database), + OR_AUTHCFG, TAKE1, "mSQL database name" }, +{ "AuthMSQLUserTable", set_string_slot, + (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_pwd_table), + OR_AUTHCFG, TAKE1, "mSQL user table name" }, +{ "AuthMSQLGroupTable", set_string_slot, + (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_grp_table), + OR_AUTHCFG, TAKE1, "mSQL group table name" }, +{ "AuthMSQLNameField", set_string_slot, + (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_uname_field), + OR_AUTHCFG, TAKE1, "mSQL User ID field name within table" }, +{ "AuthMSQLGroupField", set_string_slot, + (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_grp_field), + OR_AUTHCFG, TAKE1, "mSQL Group field name within table" }, +{ "AuthMSQLPasswordField", set_string_slot, + (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_pwd_field), + OR_AUTHCFG, TAKE1, "mSQL Password field name within table" }, +{ "AuthMSQLCryptedPasswords", set_crypted_password_flag, NULL, + OR_AUTHCFG, FLAG, "mSQL passwords are stored encrypted if On" }, + +#endif + +{ NULL } +}; + +module msql_auth_module; + +/* boring little routine which escapes the ' and \ in the + * SQL query. See the mSQL FAQ for more information :-) on + * this very popular subject in the msql-mailing list. + */ +char *msql_escape(char *out, char *in, char *msql_errstr) { + + register int i=0,j=0; + + do { + /* do we need to escape */ + if ( (in[i] == '\'') || (in[i] == '\\')) { + + /* does this fit ? */ + if (j >= (MAX_FIELD_LEN-1)) { + ap_snprintf(msql_errstr, MAX_STRING_LEN, + "Could not escape '%s', longer than %d",in,MAX_FIELD_LEN); + return NULL; + }; + + out[j++] = '\\'; /* insert that escaping slash for good measure */ + }; + + /* Do things still fit ? */ + if (j >= MAX_FIELD_LEN) return NULL; + + } while ( ( out[j++] = in[i++]) != '\0' ); + + return out; +} + +/* get the password for uname=user, and copy it + * into r. Assume that user is a string and stored + * as such in the mSQL database + */ +char *do_msql_query(request_rec *r, char *query, msql_auth_config_rec *sec, int once , char *msql_errstr) { + + static int sock=-1; + int hit; + m_result *results; + m_row currow; + + char *result=NULL; + char *host=sec->auth_msql_host; + +#ifndef KEEP_MSQL_CONNECTION_OPEN + sock=-1; +#endif + + /* force fast access over /dev/msql */ + + if ((host) && (!(strcasecmp(host,"localhost")))) + host=NULL; + + /* (re) open if nessecary + */ + if (sock==-1) if ((sock=msqlConnect(host)) == -1) { + ap_snprintf (msql_errstr, MAX_STRING_LEN, + "mSQL: Could not connect to Msql DB %s (%s)", + (sec->auth_msql_host ? sec->auth_msql_host : "\'unset, assuming localhost!\'"), + msqlErrMsg); + return NULL; + } + + /* we always do this, as it avoids book-keeping + * and is quite cheap anyway + */ + if (msqlSelectDB(sock,sec->auth_msql_database) == -1 ) { + ap_snprintf (msql_errstr, MAX_STRING_LEN, + "mSQL: Could not select Msql Table \'%s\' on host \'%s\'(%s)", + (sec->auth_msql_database ? sec->auth_msql_database : "\'unset!\'"), + (sec->auth_msql_host ? sec->auth_msql_host : "\'unset, assuming localhost!\'"), + msqlErrMsg); + msqlClose(sock); + sock=-1; + return NULL; + } + + if (msqlQuery(sock,query) == -1 ) { + ap_snprintf (msql_errstr, MAX_STRING_LEN, + "mSQL: Could not Query database '%s' on host '%s' (%s) with query [%s]", + (sec->auth_msql_database ? sec->auth_msql_database : "\'unset!\'"), + (sec->auth_msql_host ? sec->auth_msql_host : "\'unset, assuming localhost!\'"), + msqlErrMsg, + ( query ? query : "\'unset!\'") ); + msqlClose(sock); + sock=-1; + return NULL; + } + + if (!(results=msqlStoreResult())) { + ap_snprintf (msql_errstr, MAX_STRING_LEN, + "mSQL: Could not get the results from mSQL database \'%s\' on \'%s\' (%s) with query [%s]", + (sec->auth_msql_database ? sec->auth_msql_database : "\'unset!\'"), + (sec->auth_msql_host ? sec->auth_msql_host : "\'unset, assuming localhost!\'"), + msqlErrMsg, + ( query ? query : "\'unset!\'") ); + msqlClose(sock); + sock=-1; + return NULL; + }; + + hit=msqlNumRows(results); + + if (( once ) && ( hit >1 )) { + /* complain if there are to many + * matches. + */ + ap_snprintf (msql_errstr, MAX_STRING_LEN, + "mSQL: More than %d matches (%d) whith query [%s]", + once,hit,( query ? query : "\'unset!\'") ); + } else + /* if we have a it, try to get it + */ + if ( hit ) { + if ( (currow=msqlFetchRow(results)) != NULL) { + /* copy the first matching field value */ + if (!(result=palloc(r->pool,strlen(currow[0])+1))) { + ap_snprintf (msql_errstr, MAX_STRING_LEN, + "mSQL: Could not get memory for mSQL %s (%s) with [%s]", + (sec->auth_msql_database ? sec->auth_msql_database : "\'unset!\'"), + msqlErrMsg, + ( query ? query : "\'unset!\'") ); + /* do not return right away, to ensure Free/Close. + */ + } else { + strcpy(result,currow[0]); + }; + } + }; + + /* ignore errors, functions are voids anyway. */ + msqlFreeResult(results); + +#ifndef KEEP_MSQL_CONNECTION_OPEN + /* close the connection, unless explicitly told not to. Do note that + * we do not have a decent closing option of child termination due + * the lack of hooks in the API (or my understanding thereof) + */ + msqlClose(sock); + sock=-1; +#endif + + return result; +} + +char *get_msql_pw(request_rec *r, char *user, msql_auth_config_rec *sec ,char *msql_errstr) { + char query[MAX_QUERY_LEN]; + char esc_user[MAX_FIELD_LEN]; + + /* do we have enough information to build a query */ + if ( + (!sec->auth_msql_pwd_table) || + (!sec->auth_msql_pwd_field) || + (!sec->auth_msql_uname_field) + ) { + ap_snprintf(msql_errstr, MAX_STRING_LEN, + "mSQL: Missing parameters for password lookup: %s%s%s", + (sec->auth_msql_pwd_table ? "" : "Password table "), + (sec->auth_msql_pwd_field ? "" : "Password field name "), + (sec->auth_msql_uname_field ? "" : "UserID field name ") + ); + return NULL; + }; + + if (!(msql_escape(esc_user, user, msql_errstr))) { + ap_snprintf(msql_errstr, MAX_STRING_LEN, + "mSQL: Could not cope/escape the '%s' user_id value; ",user); + return NULL; + }; + ap_snprintf(query, sizeof(query), + "select %s from %s where %s='%s'", + sec->auth_msql_pwd_field, + sec->auth_msql_pwd_table, + sec->auth_msql_uname_field, + esc_user + ); + + return do_msql_query(r,query,sec,ONLY_ONCE,msql_errstr); +} + +char *get_msql_grp(request_rec *r, char *group,char *user, msql_auth_config_rec *sec, char *msql_errstr) { + char query[MAX_QUERY_LEN]; + + char esc_user[MAX_FIELD_LEN]; + char esc_group[MAX_FIELD_LEN]; + + /* do we have enough information to build a query */ + if ( + (!sec->auth_msql_grp_table) || + (!sec->auth_msql_grp_field) || + (!sec->auth_msql_uname_field) + ) { + ap_snprintf(msql_errstr, MAX_STRING_LEN, + "mSQL: Missing parameters for group lookup: %s%s%s", + (sec->auth_msql_grp_table ? "" : "Group table "), + (sec->auth_msql_grp_field ? "" : "GroupID field name "), + (sec->auth_msql_uname_field ? "" : "UserID field name ") + ); + return NULL; + }; + + if (!(msql_escape(esc_user, user,msql_errstr))) { + ap_snprintf(msql_errstr, MAX_STRING_LEN, + "mSQL: Could not cope/escape the '%s' user_id value",user); + + return NULL; + }; + if (!(msql_escape(esc_group, group,msql_errstr))) { + ap_snprintf(msql_errstr, MAX_STRING_LEN, + "mSQL: Could not cope/escape the '%s' group_id value",group); + + return NULL; + }; + + ap_snprintf(query, sizeof(query), + "select %s from %s where %s='%s' and %s='%s'", + sec->auth_msql_grp_field, + sec->auth_msql_grp_table, + sec->auth_msql_uname_field,esc_user, + sec->auth_msql_grp_field, esc_group + ); + + return do_msql_query(r,query,sec,0,msql_errstr); +} + + +int msql_authenticate_basic_user (request_rec *r) +{ + msql_auth_config_rec *sec = + (msql_auth_config_rec *)get_module_config (r->per_dir_config, + &msql_auth_module); + char msql_errstr[MAX_STRING_LEN]; + /* msql_errstr must be MAX_STRING_LEN in size unless you + * change size in ap_snprintf() calls + */ + conn_rec *c = r->connection; + char *sent_pw, *real_pw; + int res; + msql_errstr[0]='\0'; + + if ((res = get_basic_auth_pw (r, &sent_pw))) + return res; + + /* if mSQL *password* checking is configured in any way, i.e. then + * handle it, if not decline and leave it to the next in line.. + * We do not check on dbase, group, userid or host name, as it is + * perfectly possible to only do group control with mSQL and leave + * user control to the next (dbm) guy in line. + * We no longer check on the user field name; to avoid problems + * with Backward VITEK. + */ + if (!sec->auth_msql_pwd_table) return DECLINED; + + if(!(real_pw = get_msql_pw(r, c->user, sec,msql_errstr ))) { + if ( msql_errstr[0] ) { + res = SERVER_ERROR; + } else { + if (sec->auth_msql_authoritative) { + /* insist that the user is in the database + */ + ap_snprintf(msql_errstr, MAX_STRING_LEN, + "mSQL: Password for user %s not found", c->user); + note_basic_auth_failure (r); + res = AUTH_REQUIRED; + } else { + /* pass control on to the next authorization module. + */ + return DECLINED; + }; /* if authoritative */ + }; /* if no error */ + log_reason (msql_errstr, r->filename, r); + return res; + } + + /* allow no password, if the flag is set and the password + * is empty. But be sure to log this. + */ + + if ((sec->auth_msql_nopasswd) && (!strlen(real_pw))) { +/* + ap_snprintf(msql_errstr, MAX_STRING_LEN, + "mSQL: user %s: Empty/'any' password accepted",c->user); + log_reason (msql_errstr, r->uri, r); + */ + return OK; + }; + + /* if the flag is off however, keep that kind of stuff at + * an arms length. + */ + if ((!strlen(real_pw)) || (!strlen(sent_pw))) { + ap_snprintf(msql_errstr, MAX_STRING_LEN, + "mSQL: user %s: Empty Password(s) Rejected",c->user); + log_reason (msql_errstr, r->uri, r); + note_basic_auth_failure (r); + return AUTH_REQUIRED; + }; + + if(sec->auth_msql_encrypted) { + /* anyone know where the prototype for crypt is? + * + * PLEASE NOTE: + * The crypt function (at least under FreeBSD 2.0.5) returns + * a ptr to a *static* array (max 120 chars) and does *not* + * modify the string pointed at by sent_pw ! + */ + sent_pw=(char *)crypt(sent_pw,real_pw); + }; + + if (strcmp(real_pw,sent_pw)) { + ap_snprintf(msql_errstr, MAX_STRING_LEN, + "mSQL user %s: password mismatch",c->user); + log_reason (msql_errstr, r->uri, r); + note_basic_auth_failure (r); + return AUTH_REQUIRED; + } + return OK; +} + +/* Checking ID */ + +int msql_check_auth (request_rec *r) { + int user_result=DECLINED,group_result=DECLINED; + + msql_auth_config_rec *sec = + (msql_auth_config_rec *)get_module_config (r->per_dir_config, + &msql_auth_module); + char msql_errstr[MAX_STRING_LEN]; + /* msql_errstr must be MAX_STRING_LEN in size unless you + * change size in ap_snprintf() calls + */ + char *user = r->connection->user; + int m = r->method_number; + array_header *reqs_arr = requires (r); + require_line *reqs = reqs_arr ? (require_line *)reqs_arr->elts : NULL; + + register int x; + const char *t, *w; + msql_errstr[0]='\0'; + + /* If we are not configured, ignore */ + if (!sec->auth_msql_pwd_table) return DECLINED; + + if (!reqs_arr) { + if (sec->auth_msql_authoritative) { + ap_snprintf(msql_errstr, MAX_STRING_LEN, "user %s denied, no access rules specified (MSQL-Authoritative) ",user); + log_reason (msql_errstr, r->uri, r); + note_basic_auth_failure(r); + return AUTH_REQUIRED; + }; + return DECLINED; + }; + + for(x=0; (x < reqs_arr->nelts) ; x++) { + + if (! (reqs[x].method_mask & (1 << m))) continue; + + t = reqs[x].requirement; + w = getword(r->pool, &t, ' '); + + if ((user_result != OK) && (!strcmp(w,"user"))) { + user_result=AUTH_REQUIRED; + while(t[0]) { + w = getword_conf (r->pool, &t); + if (!strcmp(user,w)) { + user_result= OK; + break; + }; + } + if ((sec->auth_msql_authoritative) && ( user_result != OK)) { + ap_snprintf(msql_errstr, MAX_STRING_LEN, "User %s not found (MSQL-Auhtorative)",user); + log_reason (msql_errstr, r->uri, r); + note_basic_auth_failure(r); + return AUTH_REQUIRED; + }; + } + + if ( (group_result != OK) && + (!strcmp(w,"group")) && + (sec->auth_msql_grp_table) && + (sec->auth_msql_grp_field) + ) { + /* look up the membership for each of the groups in the table + */ + group_result=AUTH_REQUIRED; + while ( (t[0]) && (group_result != OK) && (!msql_errstr[0]) ) { + if (get_msql_grp(r,getword(r->pool, &t, ' '),user,sec,msql_errstr)) { + group_result= OK; + break; + }; + }; + + if (msql_errstr[0]) { + log_reason (msql_errstr, r->filename, r); + return SERVER_ERROR; + }; + + if ( (sec->auth_msql_authoritative) && (group_result != OK) ) { + ap_snprintf(msql_errstr, MAX_STRING_LEN, "user %s not in right groups (MSQL-Authoritative) ",user); + log_reason (msql_errstr, r->uri, r); + note_basic_auth_failure(r); + return AUTH_REQUIRED; + }; + }; + + if(!strcmp(w,"valid-user")) { + user_result= OK; + }; + } + + /* Get serious if we are authoritative, previous + * returns are only if msql yielded a correct result. + * This really is not needed. + */ + if (((group_result == AUTH_REQUIRED) || (user_result == AUTH_REQUIRED)) && (sec->auth_msql_authoritative) ) { + ap_snprintf(msql_errstr, MAX_STRING_LEN, "mSQL-Authoritative: Access denied on %s %s rule(s) ", + (group_result == AUTH_REQUIRED) ? "USER" : "", + (user_result == AUTH_REQUIRED) ? "GROUP" : "" + ); + log_reason (msql_errstr, r->uri, r); + return AUTH_REQUIRED; + }; + + if ( (user_result == OK) || (group_result == OK)) + return OK; + + return DECLINED; +} + + +module msql_auth_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + create_msql_auth_dir_config, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + NULL, /* server config */ + NULL, /* merge server config */ + msql_auth_cmds, /* command table */ + NULL, /* handlers */ + NULL, /* filename translation */ + msql_authenticate_basic_user,/* check_user_id */ + msql_check_auth, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* pre-run fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_cern_meta.c b/APACHE_1_2_X/src/modules/standard/mod_cern_meta.c new file mode 100644 index 00000000000..321175f36c3 --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_cern_meta.c @@ -0,0 +1,331 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * mod_cern_meta.c + * version 0.0.5 + * status beta + * + * Andrew Wilson 25.Jan.96 + * + * Emulate the CERN HTTPD Meta file semantics. Meta files are HTTP + * headers that can be output in addition to the normal range of + * headers for each file accessed. They appear rather like the Apache + * .asis files, and are able to provide a crude way of influencing + * the Expires: header, as well as providing other curiosities. + * There are many ways to manage meta information, this one was + * chosen because there is already a large number of CERN users + * who can exploit this module. It should be noted that there are probably + * more sensitive ways of managing the Expires: header specifically. + * + * The module obeys the following directives, which can only appear + * in the server's .conf files and not in any .htaccess file. + * + * MetaDir + * + * specifies the name of the directory in which Apache can find + * meta information files. The directory is usually a 'hidden' + * subdirectory of the directory that contains the file being + * accessed. eg: + * + * # .meta files are in the *same* directory as the + * # file being accessed + * MetaDir . + * + * the default is to look in a '.web' subdirectory. This is the + * same as for CERN 3.+ webservers and behaviour is the same as + * for the directive: + * + * MetaDir .web + * + * MetaSuffix + * + * specifies the file name suffix for the file containing the + * meta information. eg: + * + * # our meta files are suffixed with '.cern_meta' + * MetaSuffix .cern_meta + * + * the default is to look for files with the suffix '.meta'. This + * behaviour is the same as for the directive: + * + * MetaSuffix .meta + * + * When accessing the file + * + * DOCUMENT_ROOT/somedir/index.html + * + * this module will look for the file + * + * DOCUMENT_ROOT/somedir/.web/index.html.meta + * + * and will use its contents to generate additional MIME header + * information. + * + * For more information on the CERN Meta file semantics see: + * + * http://www.w3.org/hypertext/WWW/Daemon/User/Config/General.html#MetaDir + * + * Change-log: + * 29.Jan.96 pfopen/pfclose instead of fopen/fclose + * DECLINE when real file not found, we may be checking each + * of the index.html/index.shtml/index.htm variants and don't + * need to report missing ones as spurious errors. + * 31.Jan.96 log_error reports about a malformed .meta file, rather + * than a script error. + * + */ + +#include "httpd.h" +#include "http_config.h" +#include +#include +#include "util_script.h" +#include "http_log.h" + +#define DEFAULT_METADIR ".web" +#define DEFAULT_METASUFFIX ".meta" + +module cern_meta_module; + +typedef struct { + char *metadir; + char *metasuffix; +} cern_meta_config; + +void *create_cern_meta_config (pool *p, server_rec *dummy) +{ + cern_meta_config *new = + (cern_meta_config *) palloc (p, sizeof(cern_meta_config)); + + new->metadir = DEFAULT_METADIR; + new->metasuffix = DEFAULT_METASUFFIX; + + return new; +} + +const char *set_metadir (cmd_parms *parms, void *dummy, char *arg) +{ + cern_meta_config *cmc ; + + cmc = get_module_config (parms->server->module_config, + &cern_meta_module); + cmc->metadir = arg; + return NULL; +} + +const char *set_metasuffix (cmd_parms *parms, void *dummy, char *arg) +{ + cern_meta_config *cmc ; + + cmc = get_module_config (parms->server->module_config, + &cern_meta_module); + cmc->metasuffix = arg; + return NULL; +} + +command_rec cern_meta_cmds[] = { +{ "MetaDir", set_metadir, NULL, RSRC_CONF, TAKE1, + "the name of the directory containing meta files"}, +{ "MetaSuffix", set_metasuffix, NULL, RSRC_CONF, TAKE1, + "the filename suffix for meta files"}, +{ NULL } +}; + +int scan_meta_file(request_rec *r, FILE *f) +{ + char w[MAX_STRING_LEN]; + char *l; + int p; + + while( fgets(w, MAX_STRING_LEN-1, f) != NULL ) { + + /* Delete terminal (CR?)LF */ + + p = strlen(w); + if (p > 0 && w[p-1] == '\n') + { + if (p > 1 && w[p-2] == '\015') w[p-2] = '\0'; + else w[p-1] = '\0'; + } + + if(w[0] == '\0') { + return OK; + } + + /* if we see a bogus header don't ignore it. Shout and scream */ + + if(!(l = strchr(w,':'))) { + log_reason ("malformed header in meta file", r->filename, r); + return SERVER_ERROR; + } + + *l++ = '\0'; + while (*l && isspace (*l)) ++l; + + if(!strcasecmp(w,"Content-type")) { + + /* Nuke trailing whitespace */ + + char *endp = l + strlen(l) - 1; + while (endp > l && isspace(*endp)) *endp-- = '\0'; + + r->content_type = pstrdup (r->pool, l); + } + else if(!strcasecmp(w,"Status")) { + sscanf(l, "%d", &r->status); + r->status_line = pstrdup(r->pool, l); + } + else { + table_set (r->headers_out, w, l); + } + } + return OK; +} + +int add_cern_meta_data(request_rec *r) +{ + char *metafilename; + char *last_slash; + char *real_file; + char *scrap_book; + struct stat meta_stat; + FILE *f; + cern_meta_config *cmc ; + int rv; + + cmc = get_module_config (r->server->module_config, + &cern_meta_module); + + /* if ./.web/$1.meta exists then output 'asis' */ + + if (r->finfo.st_mode == 0) { + return DECLINED; + }; + + /* does uri end in a trailing slash? */ + if ( r->uri[strlen(r->uri) - 1] == '/' ) { + return DECLINED; + }; + + /* what directory is this file in? */ + scrap_book = pstrdup( r->pool, r->filename ); + /* skip leading slash, recovered in later processing */ + scrap_book++; + last_slash = strrchr( scrap_book, '/' ); + if ( last_slash != NULL ) { + /* skip over last slash */ + real_file = last_slash; + real_file++; + *last_slash = '\0'; + } else { + /* no last slash, buh?! */ + log_reason("internal error in mod_cern_meta", r->filename, r); + /* should really barf, but hey, let's be friends... */ + return DECLINED; + }; + + metafilename = pstrcat(r->pool, "/", scrap_book, "/", cmc->metadir, "/", real_file, cmc->metasuffix, NULL); + + /* + * stat can legitimately fail for a bewildering number of reasons, + * only one of which implies the file isn't there. A hardened + * version of this module should test for all conditions, but later... + */ + if (stat(metafilename, &meta_stat) == -1) { + /* stat failed, possibly file missing */ + return DECLINED; + }; + + /* + * this check is to be found in other Jan/96 Apache code, I've + * not been able to find any corroboration in the man pages but + * I've been wrong before so I'll put it in anyway. Never + * admit to being clueless... + */ + if ( meta_stat.st_mode == 0 ) { + /* stat failed, definately file missing */ + return DECLINED; + }; + + f = pfopen (r->pool, metafilename, "r"); + + if (f == NULL) { + log_reason("meta file permissions deny server access", metafilename, r); + return FORBIDDEN; + }; + + /* read the headers in */ + rv = scan_meta_file(r, f); + pfclose( r->pool, f ); + + return rv; +} + +module cern_meta_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + NULL, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + create_cern_meta_config, /* server config */ + NULL, /* merge server configs */ + cern_meta_cmds, /* command table */ + NULL, /* handlers */ + NULL, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + add_cern_meta_data, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_cgi.c b/APACHE_1_2_X/src/modules/standard/mod_cgi.c new file mode 100644 index 00000000000..ceed899ad7b --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_cgi.c @@ -0,0 +1,574 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * http_script: keeps all script-related ramblings together. + * + * Compliant to CGI/1.1 spec + * + * Adapted by rst from original NCSA code by Rob McCool + * + * Apache adds some new env vars; REDIRECT_URL and REDIRECT_QUERY_STRING for + * custom error responses, and DOCUMENT_ROOT because we found it useful. + * It also adds SERVER_ADMIN - useful for scripts to know who to mail when + * they fail. + */ + +#include "httpd.h" +#include "http_config.h" +#include "http_request.h" +#include "http_core.h" +#include "http_protocol.h" +#include "http_main.h" +#include "http_log.h" +#include "util_script.h" +#include "http_conf_globals.h" + +module cgi_module; + +/* KLUDGE --- for back-combatibility, we don't have to check ExecCGI + * in ScriptAliased directories, which means we need to know if this + * request came through ScriptAlias or not... so the Alias module + * leaves a note for us. + */ + +int is_scriptaliased (request_rec *r) +{ + char *t = table_get (r->notes, "alias-forced-type"); + return t && (!strcmp (t, "cgi-script")); +} + +/* Configuration stuff */ + +#define DEFAULT_LOGBYTES 10385760 +#define DEFAULT_BUFBYTES 1024 + +typedef struct { + char *logname; + long logbytes; + int bufbytes; +} cgi_server_conf; + +void *create_cgi_config (pool *p, server_rec *s) +{ + cgi_server_conf *c = + (cgi_server_conf *)pcalloc (p, sizeof(cgi_server_conf)); + + c->logname = NULL; + c->logbytes = DEFAULT_LOGBYTES; + c->bufbytes = DEFAULT_BUFBYTES; + + return c; +} + +void *merge_cgi_config (pool *p, void *basev, void *overridesv) +{ + cgi_server_conf *base = (cgi_server_conf *)basev, + *overrides = (cgi_server_conf *)overridesv; + + return overrides->logname ? overrides : base; +} + +const char *set_scriptlog (cmd_parms *cmd, void *dummy, char *arg) { + server_rec *s = cmd->server; + cgi_server_conf *conf = + (cgi_server_conf *)get_module_config(s->module_config, &cgi_module); + + conf->logname = arg; + return NULL; +} + +const char *set_scriptlog_length (cmd_parms *cmd, void *dummy, char *arg) { + server_rec *s = cmd->server; + cgi_server_conf *conf = + (cgi_server_conf *)get_module_config(s->module_config, &cgi_module); + + conf->logbytes = atol (arg); + return NULL; +} + +const char *set_scriptlog_buffer (cmd_parms *cmd, void *dummy, char *arg) { + server_rec *s = cmd->server; + cgi_server_conf *conf = + (cgi_server_conf *)get_module_config(s->module_config, &cgi_module); + + conf->bufbytes = atoi (arg); + return NULL; +} + +command_rec cgi_cmds[] = { +{ "ScriptLog", set_scriptlog, NULL, RSRC_CONF, TAKE1, + "the name of a log for script debugging info"}, +{ "ScriptLogLength", set_scriptlog_length, NULL, RSRC_CONF, TAKE1, + "the maximum length (in bytes) of the script debug log"}, +{ "ScriptLogBuffer", set_scriptlog_buffer, NULL, RSRC_CONF, TAKE1, + "the maximum size (in bytes) to record of a POST request"}, +{ NULL} +}; + +static int log_scripterror(request_rec *r, cgi_server_conf *conf, int ret, + char *error) +{ + FILE *f; + + log_reason(error, r->filename, r); + + if (!conf->logname || + ((stat(server_root_relative(r->pool, conf->logname), &r->finfo) == 0) + && (r->finfo.st_size > conf->logbytes)) || + ((f = pfopen(r->pool, server_root_relative(r->pool, conf->logname), + "a")) == NULL)) { + return ret; + } + + /* "%% [Wed Jun 19 10:53:21 1996] GET /cgi-bin/printenv HTTP/1.0" */ + fprintf(f, "%%%% [%s] %s %s%s%s %s\n", get_time(), r->method, r->uri, + r->args ? "?" : "", r->args ? r->args : "", r->protocol); + /* "%% 500 /usr/local/etc/httpd/cgi-bin */ + fprintf(f, "%%%% %d %s\n", ret, r->filename); + + fprintf(f, "%%error\n%s\n", error); + + pfclose(r->pool, f); + return ret; +} + +static int log_script(request_rec *r, cgi_server_conf *conf, int ret, + char *dbuf, char *sbuf, FILE *script_in, FILE *script_err) +{ + table *hdrs_arr = r->headers_in; + table_entry *hdrs = (table_entry *)hdrs_arr->elts; + char argsbuffer[HUGE_STRING_LEN]; + FILE *f; + int i; + + if (!conf->logname || + ((stat(server_root_relative(r->pool, conf->logname), &r->finfo) == 0) + && (r->finfo.st_size > conf->logbytes)) || + ((f = pfopen(r->pool, server_root_relative(r->pool, conf->logname), + "a")) == NULL)) { + /* Soak up script output */ + while (fgets(argsbuffer, MAX_STRING_LEN-1, script_in) != NULL) + continue; + while (fgets(argsbuffer, MAX_STRING_LEN-1, script_err) != NULL) + continue; + return ret; + } + + /* "%% [Wed Jun 19 10:53:21 1996] GET /cgi-bin/printenv HTTP/1.0" */ + fprintf(f, "%%%% [%s] %s %s%s%s %s\n", get_time(), r->method, r->uri, + r->args ? "?" : "", r->args ? r->args : "", r->protocol); + /* "%% 500 /usr/local/etc/httpd/cgi-bin */ + fprintf(f, "%%%% %d %s\n", ret, r->filename); + + fputs("%request\n", f); + for (i = 0; i < hdrs_arr->nelts; ++i) { + if (!hdrs[i].key) continue; + fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val); + } + if ((r->method_number == M_POST || r->method_number == M_PUT) + && dbuf && *dbuf) { + fprintf(f, "\n%s\n", dbuf); + } + + fputs("%response\n", f); + hdrs_arr = r->err_headers_out; + hdrs = (table_entry *)hdrs_arr->elts; + + for (i = 0; i < hdrs_arr->nelts; ++i) { + if (!hdrs[i].key) continue; + fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val); + } + + if (sbuf && *sbuf) + fprintf(f, "%s\n", sbuf); + + *argsbuffer = '\0'; + fgets(argsbuffer, HUGE_STRING_LEN-1, script_in); + if (*argsbuffer) { + fputs("%stdout\n", f); + fputs(argsbuffer, f); + while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_in) != NULL) + fputs(argsbuffer, f); + fputs("\n", f); + } + + *argsbuffer = '\0'; + fgets(argsbuffer, HUGE_STRING_LEN-1, script_err); + if (*argsbuffer) { + fputs("%stderr\n", f); + fputs(argsbuffer, f); + while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_err) != NULL) + fputs(argsbuffer, f); + fputs("\n", f); + } + + pfclose(r->main ? r->main->pool : r->pool, script_in); + pfclose(r->main ? r->main->pool : r->pool, script_err); + + pfclose(r->pool, f); + return ret; +} + +/**************************************************************** + * + * Actual CGI handling... + */ + + +struct cgi_child_stuff { + request_rec *r; + int nph; + int debug; + char *argv0; +}; + +void cgi_child (void *child_stuff) +{ + struct cgi_child_stuff *cld = (struct cgi_child_stuff *)child_stuff; + request_rec *r = cld->r; + char *argv0 = cld->argv0; + int nph = cld->nph; + +#ifdef DEBUG_CGI +#ifdef __EMX__ + /* Under OS/2 need to use device con. */ + FILE *dbg = fopen ("con", "w"); +#else + FILE *dbg = fopen ("/dev/tty", "w"); +#endif + int i; +#endif + + char **env; + char err_string[HUGE_STRING_LEN]; + +#ifdef DEBUG_CGI + fprintf (dbg, "Attempting to exec %s as %sCGI child (argv0 = %s)\n", + r->filename, nph ? "NPH " : "", argv0); +#endif + + add_cgi_vars (r); + env = create_environment (r->pool, r->subprocess_env); + +#ifdef DEBUG_CGI + fprintf (dbg, "Environment: \n"); + for (i = 0; env[i]; ++i) fprintf (dbg, "'%s'\n", env[i]); +#endif + + chdir_file (r->filename); + if (!cld->debug) + error_log2stderr (r->server); + +#ifndef __EMX__ + if (nph) client_to_stdout (r->connection); +#endif + + /* Transumute outselves into the script. + * NB only ISINDEX scripts get decoded arguments. + */ + + cleanup_for_exec(); + + call_exec(r, argv0, env, 0); + + /* Uh oh. Still here. Where's the kaboom? There was supposed to be an + * EARTH-shattering kaboom! + * + * Oh, well. Muddle through as best we can... + * + * (NB we can't use log_error, or anything like that, because we + * just closed the file descriptor which r->server->error_log + * was tied to in cleanup_for_exec(). It's only available on stderr + * now, so that's what we use). + */ + + ap_snprintf(err_string, sizeof(err_string), + "exec of %s failed, errno is %d\n", r->filename, errno); + write(2, err_string, strlen(err_string)); + exit(0); +} + +int cgi_handler (request_rec *r) +{ + int retval, nph, dbpos = 0; + char *argv0, *dbuf = NULL; + FILE *script_out, *script_in, *script_err; + char argsbuffer[HUGE_STRING_LEN]; + int is_included = !strcmp (r->protocol, "INCLUDED"); + void *sconf = r->server->module_config; + cgi_server_conf *conf = + (cgi_server_conf *)get_module_config(sconf, &cgi_module); + + struct cgi_child_stuff cld; + pid_t child_pid; + + if (r->method_number == M_OPTIONS) { + /* 99 out of 100 CGI scripts, this is all they support */ + r->allowed |= (1 << M_GET); + r->allowed |= (1 << M_POST); + return DECLINED; + } + + if((argv0 = strrchr(r->filename,'/')) != NULL) + argv0++; + else argv0 = r->filename; + + nph = !(strncmp(argv0,"nph-",4)); + + if (!(allow_options (r) & OPT_EXECCGI) && !is_scriptaliased (r)) + return log_scripterror(r, conf, FORBIDDEN, + "Options ExecCGI is off in this directory"); + if (nph && is_included) + return log_scripterror(r, conf, FORBIDDEN, + "attempt to include NPH CGI script"); + + if (S_ISDIR(r->finfo.st_mode)) + return log_scripterror(r, conf, FORBIDDEN, + "attempt to invoke directory as script"); +#ifdef __EMX__ + /* Allow for cgi files without the .EXE extension on them under OS/2 */ + if (r->finfo.st_mode == 0) { + struct stat statbuf; + + r->filename = pstrcat (r->pool, r->filename, ".EXE", NULL); + + if ((stat(r->filename, &statbuf) != 0) || (!S_ISREG(statbuf.st_mode))) { + return log_scripterror(r, conf, NOT_FOUND, + "script not found or unable to stat"); + } + } +#else + if (r->finfo.st_mode == 0) + return log_scripterror(r, conf, NOT_FOUND, + "script not found or unable to stat"); +#endif + if (!suexec_enabled) { + if (!can_exec(&r->finfo)) + return log_scripterror(r, conf, FORBIDDEN, + "file permissions deny server execution"); + } + + if ((retval = setup_client_block(r, REQUEST_CHUNKED_ERROR))) + return retval; + + add_common_vars (r); + cld.argv0 = argv0; cld.r = r; cld.nph = nph; + cld.debug = conf->logname ? 1 : 0; + + if (!(child_pid = + /* + * we spawn out of r->main if it's there so that we can avoid + * waiting for free_proc_chain to cleanup in the middle of an + * SSI request -djg + */ + spawn_child_err (r->main ? r->main->pool : r->pool, cgi_child, + (void *)&cld, + nph ? just_wait : kill_after_timeout, +#ifdef __EMX__ + &script_out, &script_in, &script_err))) { +#else + &script_out, nph ? NULL : &script_in, + &script_err))) { +#endif + log_reason ("couldn't spawn child process", r->filename, r); + return SERVER_ERROR; + } + + /* Transfer any put/post args, CERN style... + * Note that if a buggy script fails to read everything we throw + * at it, or a buggy client sends too much, we get a SIGPIPE, so + * we have to ignore SIGPIPE while doing this. CERN does the same + * (and in fact, they pretty nearly guarantee themselves a SIGPIPE + * on every invocation by chasing the real client data with a + * spurious newline). + */ + + if (should_client_block(r)) { + void (*handler)(); + int dbsize, len_read; + + if (conf->logname) { + dbuf = pcalloc(r->pool, conf->bufbytes+1); + dbpos = 0; + } + + hard_timeout ("copy script args", r); + handler = signal (SIGPIPE, SIG_IGN); + + while ((len_read = + get_client_block(r, argsbuffer, HUGE_STRING_LEN)) > 0) + { + if (conf->logname) { + if ((dbpos + len_read) > conf->bufbytes) { + dbsize = conf->bufbytes - dbpos; + } + else { + dbsize = len_read; + } + memcpy(dbuf + dbpos, argsbuffer, dbsize); + dbpos += dbsize; + } + reset_timeout(r); + if (fwrite(argsbuffer, sizeof(char), len_read, script_out) + < (size_t)len_read) { + /* silly script stopped reading, soak up remaining message */ + while (get_client_block(r, argsbuffer, HUGE_STRING_LEN) > 0) + ; /* dump it */ + break; + } + } + + fflush (script_out); + signal (SIGPIPE, handler); + + kill_timeout (r); + } + + pfclose (r->main ? r->main->pool : r->pool, script_out); + + /* Handle script return... */ + if (script_in && !nph) { + char *location, sbuf[MAX_STRING_LEN]; + int ret; + + if ((ret = scan_script_header_err(r, script_in, sbuf))) + return log_script(r, conf, ret, dbuf, sbuf, script_in, script_err); + + location = table_get (r->headers_out, "Location"); + + if (location && location[0] == '/' && r->status == 200) { + + /* Soak up all the script output */ + hard_timeout ("read from script", r); + while (fread(argsbuffer, sizeof(char), HUGE_STRING_LEN, script_in) + > 0) + continue; + while (fread(argsbuffer, sizeof(char), HUGE_STRING_LEN, script_err) + > 0) + continue; + kill_timeout (r); + + + /* This redirect needs to be a GET no matter what the original + * method was. + */ + r->method = pstrdup(r->pool, "GET"); + r->method_number = M_GET; + + /* We already read the message body (if any), so don't allow + * the redirected request to think it has one. We can ignore + * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. + */ + table_unset(r->headers_in, "Content-Length"); + + internal_redirect_handler (location, r); + return OK; + } + else if (location && r->status == 200) { + /* XX Note that if a script wants to produce its own Redirect + * body, it now has to explicitly *say* "Status: 302" + */ + return REDIRECT; + } + + send_http_header(r); + if (!r->header_only) + send_fd(script_in, r); + pfclose (r->main ? r->main->pool : r->pool, script_in); + + /* Soak up stderr */ + soft_timeout("soaking script stderr", r); + while (!r->connection->aborted && + (fread(argsbuffer, sizeof(char), HUGE_STRING_LEN, script_err) > 0)) + continue; + kill_timeout(r); + pfclose (r->main ? r->main->pool : r->pool, script_err); + } + + if (nph) { +#ifdef __EMX__ + while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_in) != NULL) { + bputs(argsbuffer, r->connection->client); + } +#else + waitpid(child_pid, (int*)0, 0); +#endif + } + + return OK; /* NOT r->status, even if it has changed. */ +} + +handler_rec cgi_handlers[] = { +{ CGI_MAGIC_TYPE, cgi_handler }, +{ "cgi-script", cgi_handler }, +{ NULL } +}; + +module cgi_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + NULL, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + create_cgi_config, /* server config */ + merge_cgi_config, /* merge server config */ + cgi_cmds, /* command table */ + cgi_handlers, /* handlers */ + NULL, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_digest.c b/APACHE_1_2_X/src/modules/standard/mod_digest.c new file mode 100644 index 00000000000..35644037da7 --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_digest.c @@ -0,0 +1,363 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * mod_digest: MD5 digest authentication + * + * by Alexei Kosut + * based on mod_auth, by Rob McCool and Robert S. Thau + * + */ + +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_log.h" +#include "http_protocol.h" +#include "util_md5.h" + +typedef struct digest_config_struct { + char *pwfile; +} digest_config_rec; + +typedef struct digest_header_struct { + char *username; + char *realm; + char *nonce; + char *requested_uri; + char *digest; +} digest_header_rec; + +void *create_digest_dir_config (pool *p, char *d) +{ + return pcalloc (p, sizeof(digest_config_rec)); +} + +const char *set_digest_slot (cmd_parms *cmd, void *offset, char *f, char *t) +{ + if (t && strcmp(t, "standard")) + return pstrcat(cmd->pool, "Invalid auth file type: ", t, NULL); + + return set_string_slot(cmd, offset, f); +} + +command_rec digest_cmds[] = { +{ "AuthDigestFile", set_digest_slot, + (void*)XtOffsetOf(digest_config_rec,pwfile), OR_AUTHCFG, TAKE12, NULL }, +{ NULL } +}; + +module digest_module; + +char *get_hash(request_rec *r, char *user, char *auth_pwfile) +{ + FILE *f; + char l[MAX_STRING_LEN]; + const char *rpw; + char *w, *x; + + if(!(f=pfopen(r->pool, auth_pwfile, "r"))) { + log_reason ("Could not open password file", auth_pwfile, r); + return NULL; + } + while(!(cfg_getline(l,MAX_STRING_LEN,f))) { + if((l[0] == '#') || (!l[0])) continue; + rpw = l; + w = getword(r->pool, &rpw, ':'); + x = getword(r->pool, &rpw, ':'); + + if(x && w && !strcmp(user,w) && !strcmp(auth_name(r), x)) { + pfclose(r->pool, f); + return pstrdup (r->pool, rpw); + } + } + pfclose(r->pool, f); + return NULL; +} + +/* Parse the Authorization header, if it exists */ + +int get_digest_rec(request_rec *r, digest_header_rec *response) { + const char *auth_line = table_get(r->headers_in, "Authorization"); + int l; + int s = 0, vk = 0, vv = 0; + char *t, *key, *value; + + if (!(t = auth_type(r)) || strcasecmp(t, "Digest")) + return DECLINED; + + if (!auth_name (r)) { + log_reason ("need AuthName", r->uri, r); + return SERVER_ERROR; + } + + if (!auth_line) { + note_digest_auth_failure (r); + return AUTH_REQUIRED; + } + + if (strcmp(getword (r->pool, &auth_line, ' '), "Digest")) { + /* Client tried to authenticate using wrong auth scheme */ + log_reason ("client used wrong authentication scheme", r->uri, r); + note_digest_auth_failure (r); + return AUTH_REQUIRED; + } + + l = strlen(auth_line); + + key=palloc(r->pool,l); + value=palloc(r->pool,l); + + /* There's probably a better way to do this, but for the time being... */ + +#define D_KEY 0 +#define D_VALUE 1 +#define D_STRING 2 +#define D_EXIT -1 + + while (s != D_EXIT) { + switch (s) { + case D_STRING: + if (auth_line[0] == '\"') { + s = D_VALUE; + } + else { + value[vv] = auth_line[0]; + vv++; + } + auth_line++; + break; + + case D_VALUE: + if (isalnum(auth_line[0])) { + value[vv] = auth_line[0]; + vv++; + } + else if (auth_line[0] == '\"') { + s = D_STRING; + } + else { + value[vv] = '\0'; + + if (!strcasecmp(key, "username")) + response->username = pstrdup(r->pool, value); + else if (!strcasecmp(key, "realm")) + response->realm = pstrdup(r->pool, value); + else if (!strcasecmp(key, "nonce")) + response->nonce = pstrdup(r->pool, value); + else if (!strcasecmp(key, "uri")) + response->requested_uri = pstrdup(r->pool, value); + else if (!strcasecmp(key, "response")) + response->digest = pstrdup(r->pool, value); + + vv = 0; + s = D_KEY; + } + auth_line++; + break; + + case D_KEY: + if (isalnum(auth_line[0])) { + key[vk] = auth_line[0]; + vk++; + } + else if (auth_line[0] == '=') { + key[vk] = '\0'; + vk = 0; + s = D_VALUE; + } + auth_line++; + break; + } + + if (auth_line[-1] == '\0') + s = D_EXIT; + } + + if (!response->username || !response->realm || !response->nonce || + !response->requested_uri || !response->digest) { + note_digest_auth_failure (r); + return AUTH_REQUIRED; + } + + r->connection->user = response->username; + r->connection->auth_type = "Digest"; + + return OK; +} + +/* The actual MD5 code... whee */ + +char *find_digest(request_rec *r, digest_header_rec *h, char *a1) { + return md5(r->pool, + (unsigned char *)pstrcat(r->pool, a1, ":", h->nonce, ":", + md5(r->pool, + (unsigned char *)pstrcat(r->pool,r->method,":", + h->requested_uri,NULL)), + NULL)); +} + +/* These functions return 0 if client is OK, and proper error status + * if not... either AUTH_REQUIRED, if we made a check, and it failed, or + * SERVER_ERROR, if things are so totally confused that we couldn't + * figure out how to tell if the client is authorized or not. + * + * If they return DECLINED, and all other modules also decline, that's + * treated by the server core as a configuration error, logged and + * reported as such. + */ + +/* Determine user ID, and check if it really is that user, for HTTP + * basic authentication... + */ + +int authenticate_digest_user (request_rec *r) +{ + digest_config_rec *sec = + (digest_config_rec *)get_module_config (r->per_dir_config, + &digest_module); + digest_header_rec *response = pcalloc (r->pool, sizeof(digest_header_rec)); + conn_rec *c = r->connection; + char *a1; + char errstr[MAX_STRING_LEN]; + int res; + + if ((res = get_digest_rec (r, response))) return res; + + if(!sec->pwfile) + return DECLINED; + + if (!(a1 = get_hash(r, c->user, sec->pwfile))) { + ap_snprintf(errstr, sizeof(errstr), "user %s not found",c->user); + log_reason (errstr, r->uri, r); + note_digest_auth_failure (r); + return AUTH_REQUIRED; + } + /* anyone know where the prototype for crypt is? */ + if(strcmp(response->digest, find_digest(r, response, a1))) { + ap_snprintf(errstr, sizeof(errstr), "user %s: password mismatch",c->user); + log_reason (errstr, r->uri, r); + note_digest_auth_failure (r); + return AUTH_REQUIRED; + } + return OK; +} + +/* Checking ID */ + +int digest_check_auth (request_rec *r) { + char *user = r->connection->user; + int m = r->method_number; + int method_restricted = 0; + register int x; + const char *t; + char *w; + array_header *reqs_arr; + require_line *reqs; + + if (!(t = auth_type(r)) || strcasecmp(t, "Digest")) + return DECLINED; + + reqs_arr = requires (r); + /* If there is no "requires" directive, + * then any user will do. + */ + if (!reqs_arr) + return OK; + reqs = (require_line *)reqs_arr->elts; + + for(x=0; x < reqs_arr->nelts; x++) { + + if (! (reqs[x].method_mask & (1 << m))) continue; + + method_restricted = 1; + + t = reqs[x].requirement; + w = getword(r->pool, &t, ' '); + if(!strcmp(w,"valid-user")) + return OK; + else if(!strcmp(w,"user")) { + while(t[0]) { + w = getword_conf (r->pool, &t); + if(!strcmp(user,w)) + return OK; + } + } + else + return DECLINED; + } + + if (!method_restricted) + return OK; + + note_digest_auth_failure(r); + return AUTH_REQUIRED; +} + +module digest_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + create_digest_dir_config, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + NULL, /* server config */ + NULL, /* merge server config */ + digest_cmds, /* command table */ + NULL, /* handlers */ + NULL, /* filename translation */ + authenticate_digest_user, /* check_user_id */ + digest_check_auth, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_dir.c b/APACHE_1_2_X/src/modules/standard/mod_dir.c new file mode 100644 index 00000000000..bb803ec9f52 --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_dir.c @@ -0,0 +1,891 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * http_dir.c: Handles the on-the-fly html index generation + * + * Rob McCool + * 3/23/93 + * + * Adapted to Apache by rst. + */ + +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_request.h" +#include "http_protocol.h" +#include "http_log.h" +#include "http_main.h" +#include "util_script.h" + +module dir_module; + +/**************************************************************** + * + * Handling configuration directives... + */ + +#define FANCY_INDEXING 1 /* Indexing options */ +#define ICONS_ARE_LINKS 2 +#define SCAN_HTML_TITLES 4 +#define SUPPRESS_LAST_MOD 8 +#define SUPPRESS_SIZE 16 +#define SUPPRESS_DESC 32 + +struct item { + char *type; + char *apply_to; + char *apply_path; + char *data; +}; + +typedef struct dir_config_struct { + + char *default_icon; + char *index_names; + + array_header *icon_list, *alt_list, *desc_list, *ign_list; + array_header *hdr_list, *rdme_list, *opts_list; + +} dir_config_rec; + +char c_by_encoding, c_by_type, c_by_path; + +#define BY_ENCODING &c_by_encoding +#define BY_TYPE &c_by_type +#define BY_PATH &c_by_path + +void push_item(array_header *arr, char *type, char *to, char *path, char *data) +{ + struct item *p = (struct item *)push_array(arr); + + if (!to) to = ""; + if (!path) path = ""; + + p->type = type; + p->data = data ? pstrdup(arr->pool, data): NULL; + p->apply_path = pstrcat(arr->pool, path, "*", NULL); + + if((type == BY_PATH) && (!is_matchexp(to))) + p->apply_to = pstrcat (arr->pool, "*", to, NULL); + else if (to) + p->apply_to = pstrdup (arr->pool, to); + else + p->apply_to = NULL; +} + +const char *add_alt(cmd_parms *cmd, void *d, char *alt, char *to) +{ + if (cmd->info == BY_PATH) + if(!strcmp(to,"**DIRECTORY**")) + to = "^^DIRECTORY^^"; + + push_item(((dir_config_rec *)d)->alt_list, cmd->info, to, cmd->path, alt); + return NULL; +} + +const char *add_icon(cmd_parms *cmd, void *d, char *icon, char *to) +{ + char *iconbak = pstrdup (cmd->pool, icon); + + if(icon[0] == '(') { + char *alt = getword_nc (cmd->pool, &iconbak, ','); + iconbak[strlen(iconbak) - 1] = '\0'; /* Lose closing paren */ + add_alt(cmd, d, &alt[1], to); + } + if(cmd->info == BY_PATH) + if(!strcmp(to,"**DIRECTORY**")) + to = "^^DIRECTORY^^"; + + push_item(((dir_config_rec *)d)->icon_list, cmd->info, to, cmd->path, + iconbak); + return NULL; +} + +const char *add_desc(cmd_parms *cmd, void *d, char *desc, char *to) +{ + push_item(((dir_config_rec *)d)->desc_list, cmd->info, to, cmd->path,desc); + return NULL; +} + +const char *add_ignore(cmd_parms *cmd, void *d, char *ext) { + push_item(((dir_config_rec *)d)->ign_list, 0, ext, cmd->path, NULL); + return NULL; +} + +const char *add_header(cmd_parms *cmd, void *d, char *name) { + push_item(((dir_config_rec *)d)->hdr_list, 0, NULL, cmd->path, name); + return NULL; +} + +const char *add_readme(cmd_parms *cmd, void *d, char *name) { + push_item(((dir_config_rec *)d)->rdme_list, 0, NULL, cmd->path, name); + return NULL; +} + + +const char *add_opts_int(cmd_parms *cmd, void *d, int opts) { + push_item(((dir_config_rec *)d)->opts_list, (char*)opts, NULL, + cmd->path, NULL); + return NULL; +} + +const char *fancy_indexing (cmd_parms *cmd, void *d, int arg) +{ + return add_opts_int (cmd, d, arg? FANCY_INDEXING : 0); +} + +const char *add_opts(cmd_parms *cmd, void *d, const char *optstr) { + char *w; + int opts = 0; + + while(optstr[0]) { + w = getword_conf(cmd->pool, &optstr); + if(!strcasecmp(w,"FancyIndexing")) + opts |= FANCY_INDEXING; + else if(!strcasecmp(w,"IconsAreLinks")) + opts |= ICONS_ARE_LINKS; + else if(!strcasecmp(w,"ScanHTMLTitles")) + opts |= SCAN_HTML_TITLES; + else if(!strcasecmp(w,"SuppressLastModified")) + opts |= SUPPRESS_LAST_MOD; + else if(!strcasecmp(w,"SuppressSize")) + opts |= SUPPRESS_SIZE; + else if(!strcasecmp(w,"SuppressDescription")) + opts |= SUPPRESS_DESC; + else if(!strcasecmp(w,"None")) + opts = 0; + else + return "Invalid directory indexing option"; + } + return add_opts_int(cmd, d, opts); +} + +#define DIR_CMD_PERMS OR_INDEXES + +command_rec dir_cmds[] = { +{ "AddIcon", add_icon, BY_PATH, DIR_CMD_PERMS, ITERATE2, + "an icon URL followed by one or more filenames" }, +{ "AddIconByType", add_icon, BY_TYPE, DIR_CMD_PERMS, ITERATE2, + "an icon URL followed by one or more MIME types" }, +{ "AddIconByEncoding", add_icon, BY_ENCODING, DIR_CMD_PERMS, ITERATE2, + "an icon URL followed by one or more content encodings" }, +{ "AddAlt", add_alt, BY_PATH, DIR_CMD_PERMS, ITERATE2, + "alternate descriptive text followed by one or more filenames" }, +{ "AddAltByType", add_alt, BY_TYPE, DIR_CMD_PERMS, ITERATE2, + "alternate descriptive text followed by one or more MIME types" }, +{ "AddAltByEncoding", add_alt, BY_ENCODING, DIR_CMD_PERMS, ITERATE2, + "alternate descriptive text followed by one or more content encodings" }, +{ "IndexOptions", add_opts, NULL, DIR_CMD_PERMS, RAW_ARGS, + "one or more index options" }, +{ "IndexIgnore", add_ignore, NULL, DIR_CMD_PERMS, ITERATE, + "one or more file extensions" }, +{ "AddDescription", add_desc, BY_PATH, DIR_CMD_PERMS, ITERATE2, + "Descriptive text followed by one or more filenames" }, +{ "HeaderName", add_header, NULL, DIR_CMD_PERMS, TAKE1, "a filename" }, +{ "ReadmeName", add_readme, NULL, DIR_CMD_PERMS, TAKE1, "a filename" }, +{ "FancyIndexing", fancy_indexing, NULL, DIR_CMD_PERMS, FLAG, NULL }, +{ "DefaultIcon", set_string_slot, + (void*)XtOffsetOf(dir_config_rec, default_icon), + DIR_CMD_PERMS, TAKE1, "an icon URL"}, +{ "DirectoryIndex", set_string_slot, + (void*)XtOffsetOf(dir_config_rec, index_names), + DIR_CMD_PERMS, RAW_ARGS, NULL }, +{ NULL } +}; + +void *create_dir_config (pool *p, char *dummy) +{ + dir_config_rec *new = + (dir_config_rec *) pcalloc (p, sizeof(dir_config_rec)); + + new->index_names = NULL; + new->icon_list = make_array (p, 4, sizeof (struct item)); + new->alt_list = make_array (p, 4, sizeof (struct item)); + new->desc_list = make_array (p, 4, sizeof (struct item)); + new->ign_list = make_array (p, 4, sizeof (struct item)); + new->hdr_list = make_array (p, 4, sizeof (struct item)); + new->rdme_list = make_array (p, 4, sizeof (struct item)); + new->opts_list = make_array (p, 4, sizeof (struct item)); + + return (void *)new; +} + +void *merge_dir_configs (pool *p, void *basev, void *addv) +{ + dir_config_rec *new=(dir_config_rec*)pcalloc (p, sizeof(dir_config_rec)); + dir_config_rec *base = (dir_config_rec *)basev; + dir_config_rec *add = (dir_config_rec *)addv; + + new->default_icon = add->default_icon?add->default_icon:base->default_icon; + new->index_names = add->index_names? add->index_names: base->index_names; + + new->alt_list = append_arrays (p, add->alt_list, base->alt_list); + new->ign_list = append_arrays (p, add->ign_list, base->ign_list); + new->hdr_list = append_arrays (p, add->hdr_list, base->hdr_list); + new->desc_list = append_arrays (p, add->desc_list, base->desc_list); + new->icon_list = append_arrays (p, add->icon_list, base->icon_list); + new->rdme_list = append_arrays (p, add->rdme_list, base->rdme_list); + new->opts_list = append_arrays (p, add->opts_list, base->opts_list); + + return new; +} + +/**************************************************************** + * + * Looking things up in config entries... + */ + +/* Structure used to hold entries when we're actually building an index */ + +struct ent { + char *name; + char *icon; + char *alt; + char *desc; + size_t size; + time_t lm; + struct ent *next; +}; + +char *find_item(request_rec *r, array_header *list, int path_only) { + char *content_type = r->content_type; + char *content_encoding = r->content_encoding; + char *path = r->filename; + + struct item *items = (struct item *)list->elts; + int i; + + for (i = 0; i < list->nelts; ++i) { + struct item *p = &items[i]; + + /* Special cased for ^^DIRECTORY^^ and ^^BLANKICON^^ */ + if((path[0] == '^') || (!strcmp_match(path,p->apply_path))) { + if(!*(p->apply_to)) + return p->data; + else if(p->type == BY_PATH || path[0] == '^') { + if(!strcmp_match(path,p->apply_to)) + return p->data; + } else if(!path_only) { + if(!content_encoding) { + if(p->type == BY_TYPE) { + if(content_type && !strcmp_match(content_type,p->apply_to)) + return p->data; + } + } else { + if(p->type == BY_ENCODING) { + if(!strcmp_match(content_encoding,p->apply_to)) + return p->data; + } + } + } + } + } + return NULL; +} + +#define find_icon(d,p,t) find_item(p,d->icon_list,t) +#define find_alt(d,p,t) find_item(p,d->alt_list,t) +#define find_desc(d,p) find_item(p,d->desc_list,0) +#define find_header(d,p) find_item(p,d->hdr_list,0) +#define find_readme(d,p) find_item(p,d->rdme_list,0) + +char *find_default_icon (dir_config_rec *d, char *bogus_name) +{ + request_rec r; + + /* Bleah. I tried to clean up find_item, and it lead to this bit + * of ugliness. Note that the fields initialized are precisely + * those that find_item looks at... + */ + + r.filename = bogus_name; + r.content_type = r.content_encoding = NULL; + + return find_item (&r, d->icon_list, 1); +} + +int ignore_entry(dir_config_rec *d, char *path) { + array_header *list = d->ign_list; + struct item *items = (struct item *)list->elts; + char *tt; + int i; + + if((tt=strrchr(path,'/')) == NULL) + tt=path; + else { + tt++; + } + + for (i = 0; i < list->nelts; ++i) { + struct item *p = &items[i]; + char *ap; + + if((ap=strrchr(p->apply_to,'/')) == NULL) + ap=p->apply_to; + else + ap++; + + if(!strcmp_match(path,p->apply_path) && !strcmp_match(tt,ap)) + return 1; + } + return 0; +} + +int find_opts(dir_config_rec *d, request_rec *r) { + char *path = r->filename; + array_header *list = d->opts_list; + struct item *items = (struct item *)list->elts; + int i; + + for (i = 0; i < list->nelts; ++i) { + struct item *p = &items[i]; + + if(!strcmp_match(path,p->apply_path)) + return (int)p->type; + } + return 0; +} + +/***************************************************************** + * + * Actually generating output + */ + + +int insert_readme(char *name, char *readme_fname, int rule, request_rec *r) { + char *fn; + FILE *f; + struct stat finfo; + int plaintext=0; + + fn = make_full_path(r->pool, name, readme_fname); + fn = pstrcat(r->pool, fn, ".html", NULL); + if(stat(fn,&finfo) == -1) { + /* A brief fake multiviews search for README.html */ + fn[strlen(fn)-5] = '\0'; + if(stat(fn,&finfo) == -1) + return 0; + plaintext=1; + if(rule) rputs("


    \n", r); + rputs("
    \n", r);
    +    }
    +    else if (rule) rputs("
    \n", r); + if(!(f = pfopen(r->pool,fn,"r"))) + return 0; + if (!plaintext) + send_fd(f, r); + else + { + char buf[IOBUFSIZE+1]; + int i, n, c, ch; + while (!feof(f)) + { + do n = fread(buf, sizeof(char), IOBUFSIZE, f); + while (n == -1 && ferror(f) && errno == EINTR); + if (n == -1 || n == 0) break; + buf[n] = '\0'; + c = 0; + while (c < n) + { + for (i=c; i < n; i++) + if (buf[i] == '<' || buf[i] == '>' || buf[i] == '&') break; + ch = buf[i]; + buf[i] = '\0'; + rputs(&buf[c], r); + if (ch == '<') rputs("<", r); + else if (ch == '>') rputs(">", r); + else if (ch == '&') rputs("&", r); + c = i + 1; + } + } + } + pfclose(r->pool, f); + if(plaintext) + rputs("
    \n", r); + return 1; +} + + +char *find_title(request_rec *r) { + char titlebuf[MAX_STRING_LEN], *find = ""; + FILE *thefile = NULL; + int x,y,n,p; + + if (r->content_type && !strcmp(r->content_type,"text/html") && !r->content_encoding) { + if(!(thefile = pfopen(r->pool, r->filename,"r"))) + return NULL; + n = fread(titlebuf,sizeof(char),MAX_STRING_LEN - 1,thefile); + titlebuf[n] = '\0'; + for(x=0,p=0;titlebuf[x];x++) { + if(toupper(titlebuf[x]) == find[p]) { + if(!find[++p]) { + if((p = ind(&titlebuf[++x],'<')) != -1) + titlebuf[x+p] = '\0'; + /* Scan for line breaks for Tanmoy's secretary */ + for(y=x;titlebuf[y];y++) + if((titlebuf[y] == CR) || (titlebuf[y] == LF)) + titlebuf[y] = ' '; + pfclose (r->pool, thefile); + return pstrdup(r->pool, &titlebuf[x]); + } + } else p=0; + } + pfclose(r->pool, thefile); + } + return NULL; +} + +struct ent *make_dir_entry(char *name, int dir_opts, + dir_config_rec *d, request_rec *r) +{ + struct ent *p; + + if((name[0] == '.') && (!name[1])) + return(NULL); + + if (ignore_entry(d, make_full_path (r->pool, r->filename, name))) + return(NULL); + + p=(struct ent *)pcalloc(r->pool, sizeof(struct ent)); + p->name = pstrdup (r->pool, name); + p->size = -1; + p->icon = NULL; + p->alt = NULL; + p->desc = NULL; + p->lm = -1; + + if(dir_opts & FANCY_INDEXING) { + request_rec *rr = sub_req_lookup_file (name, r); + + if (rr->finfo.st_mode != 0) { + p->lm = rr->finfo.st_mtime; + if(S_ISDIR(rr->finfo.st_mode)) { + if(!(p->icon = find_icon(d,rr,1))) + p->icon = find_default_icon(d,"^^DIRECTORY^^"); + if(!(p->alt = find_alt(d,rr,1))) + p->alt = "DIR"; + p->size = -1; + p->name = pstrcat (r->pool, name, "/", NULL); + } + else { + p->icon = find_icon(d, rr, 0); + p->alt = find_alt(d, rr, 0); + p->size = rr->finfo.st_size; + } + } + + p->desc = find_desc(d, rr); + + if((!p->desc) && (dir_opts & SCAN_HTML_TITLES)) + p->desc = pstrdup (r->pool, find_title(rr)); + + destroy_sub_req (rr); + } + return(p); +} + +char *terminate_description(dir_config_rec *d, char *desc, int dir_opts) { + int maxsize = 23; + register int x; + + if(dir_opts & SUPPRESS_LAST_MOD) maxsize += 17; + if(dir_opts & SUPPRESS_SIZE) maxsize += 7; + + for(x=0;desc[x] && maxsize;x++) { + if(desc[x] == '<') { + while(desc[x] != '>') { + if(!desc[x]) { + maxsize = 0; + break; + } + ++x; + } + } + else --maxsize; + } + if(!maxsize) { + desc[x-1] = '>'; /* Grump. */ + desc[x] = '\0'; /* Double Grump! */ + } + return desc; +} + +void output_directories(struct ent **ar, int n, + dir_config_rec *d, request_rec *r, int dir_opts) +{ + int x, len; + char *name = r->uri; + char *tp; + pool *scratch = make_sub_pool (r->pool); + + if(name[0] == '\0') name = "/"; + + if(dir_opts & FANCY_INDEXING) { + rputs("<PRE>", r); + if((tp = find_default_icon(d,"^^BLANKICON^^"))) + rvputs(r, "<IMG SRC=\"", escape_html(scratch, tp), + "\" ALT=\" \"> ", NULL); + rputs("Name ", r); + if(!(dir_opts & SUPPRESS_LAST_MOD)) + rputs("Last modified ", r); + if(!(dir_opts & SUPPRESS_SIZE)) + rputs("Size ", r); + if(!(dir_opts & SUPPRESS_DESC)) + rputs("Description", r); + rputs("\n<HR>\n", r); + } + else { + rputs("<UL>", r); + } + + for(x=0;x<n;x++) { + char *anchor = NULL, *t = NULL, *t2 = NULL; + + clear_pool (scratch); + + if((!strcmp(ar[x]->name,"../")) || (!strcmp(ar[x]->name,".."))) { + char *t = make_full_path (scratch, name, "../"); + getparents(t); + if(t[0] == '\0') t = "/"; + anchor = pstrcat (scratch, "<A HREF=\"", + escape_html(scratch, os_escape_path(scratch, t, 0)), + "\">", NULL); + t2 = "Parent Directory</A> "; + } + else { + t = ar[x]->name; + len = strlen(t); + if(len > 23) { + t2 = pstrdup(scratch, t); + t2[21] = '.'; + t2[22] = '.'; + t2[23] = '\0'; + t2 = escape_html(scratch, t2); + t2 = pstrcat(scratch, t2, "</A>", NULL); + } else + { + char buff[24]=" "; + t2 = escape_html(scratch, t); + buff[23-len] = '\0'; + t2 = pstrcat(scratch, t2, "</A>", buff, NULL); + } + anchor = pstrcat (scratch, "<A HREF=\"", + escape_html(scratch, os_escape_path(scratch, t, 0)), + "\">", NULL); + } + + if(dir_opts & FANCY_INDEXING) { + if(dir_opts & ICONS_ARE_LINKS) + rputs(anchor, r); + if((ar[x]->icon) || d->default_icon) { + rvputs(r, "<IMG SRC=\"", + escape_html(scratch, ar[x]->icon ? + ar[x]->icon : d->default_icon), + "\" ALT=\"[", (ar[x]->alt ? ar[x]->alt : " "), + "]\">", NULL); + } + if(dir_opts & ICONS_ARE_LINKS) + rputs("</A>", r); + + rvputs(r," ", anchor, t2, NULL); + if(!(dir_opts & SUPPRESS_LAST_MOD)) { + if(ar[x]->lm != -1) { + char time[MAX_STRING_LEN]; + struct tm *ts = localtime(&ar[x]->lm); + strftime(time,MAX_STRING_LEN,"%d-%b-%y %H:%M ",ts); + rputs(time, r); + } + else { + rputs(" ", r); + } + } + if(!(dir_opts & SUPPRESS_SIZE)) { + send_size(ar[x]->size,r); + rputs(" ", r); + } + if(!(dir_opts & SUPPRESS_DESC)) { + if(ar[x]->desc) { + rputs(terminate_description(d, ar[x]->desc, dir_opts), r); + } + } + } + else + rvputs(r, "<LI> ", anchor," ", t2, NULL); + rputc('\n', r); + } + if(dir_opts & FANCY_INDEXING) { + rputs("</PRE>", r); + } + else { + rputs("</UL>", r); + } +} + + +int dsortf(struct ent **s1,struct ent **s2) +{ + return(strcmp((*s1)->name,(*s2)->name)); +} + + +int index_directory(request_rec *r, dir_config_rec *dir_conf) +{ + char *title_name = escape_html(r->pool, r->uri); + char *title_endp; + char *name = r->filename; + + DIR *d; + struct DIR_TYPE *dstruct; + int num_ent=0,x; + struct ent *head,*p; + struct ent **ar = NULL; + char *tmp; + int dir_opts = find_opts(dir_conf, r); + + if(!(d=opendir(name))) { + log_reason ("Can't open directory for index", r->filename, r); + return HTTP_FORBIDDEN; + } + + r->content_type = "text/html"; + + send_http_header(r); + + if (r->header_only) { + closedir (d); + return 0; + } + hard_timeout("send directory", r); + + /* Spew HTML preamble */ + + title_endp = title_name + strlen(title_name) - 1; + + while (title_endp > title_name && *title_endp == '/') + *title_endp-- = '\0'; + + rvputs + ( + r, + "<HTML><HEAD>\n<TITLE>Index of ", + title_name, + "\n\n", + NULL + ); + + if((!(tmp = find_header(dir_conf,r))) || (!(insert_readme(name,tmp,0,r)))) + rvputs(r, "

    Index of ", title_name, "

    \n", NULL); + + /* + * Since we don't know how many dir. entries there are, put them into a + * linked list and then arrayificate them so qsort can use them. + */ + head=NULL; + while((dstruct=readdir(d))) { + if((p = make_dir_entry(dstruct->d_name, dir_opts, dir_conf, r))) { + p->next=head; + head=p; + num_ent++; + } + } + if (num_ent > 0) { + ar=(struct ent **) palloc(r->pool, num_ent*sizeof(struct ent *)); + p=head; + x=0; + while(p) { + ar[x++]=p; + p = p->next; + } + + qsort((void *)ar,num_ent,sizeof(struct ent *), +#ifdef ULTRIX_BRAIN_DEATH + (int (*))dsortf); +#else + (int (*)(const void *,const void *))dsortf); +#endif + } + output_directories(ar, num_ent, dir_conf, r, dir_opts); + closedir(d); + + if (dir_opts & FANCY_INDEXING) + if((tmp = find_readme(dir_conf, r))) + insert_readme(name,tmp,1,r); + else { + rputs("", r); + } + + rputs ("\n", r); + + kill_timeout(r); + return 0; +} + +/* The formal handler... */ + +int handle_dir (request_rec *r) +{ + dir_config_rec *d = + (dir_config_rec *)get_module_config (r->per_dir_config, &dir_module); + const char *names_ptr = d->index_names ? d->index_names : DEFAULT_INDEX; + int allow_opts = allow_options (r); + int error_notfound = 0; + + if (r->uri[0] == '\0' || r->uri[strlen(r->uri)-1] != '/') { + char* ifile; + if (r->args != NULL) + ifile = pstrcat (r->pool, escape_uri(r->pool, r->uri), + "/", "?", r->args, NULL); + else + ifile = pstrcat (r->pool, escape_uri(r->pool, r->uri), + "/", NULL); + + table_set (r->headers_out, "Location", + construct_url(r->pool, ifile, r->server)); + return HTTP_MOVED_PERMANENTLY; + } + + /* KLUDGE --- make the sub_req lookups happen in the right directory. + * Fixing this in the sub_req_lookup functions themselves is difficult, + * and would probably break virtual includes... + */ + + r->filename = pstrcat (r->pool, r->filename, "/", NULL); + + while (*names_ptr) { + + char *name_ptr = getword_conf (r->pool, &names_ptr); + request_rec *rr = sub_req_lookup_uri (name_ptr, r); + + if (rr->status == HTTP_OK && rr->finfo.st_mode != 0) { + char* new_uri = escape_uri(r->pool, rr->uri); + + if (rr->args != NULL) + new_uri = pstrcat(r->pool, new_uri, "?", rr->args, NULL); + else if (r->args != NULL) + new_uri = pstrcat(r->pool, new_uri, "?", r->args, NULL); + + destroy_sub_req (rr); + internal_redirect (new_uri, r); + return OK; + } + + /* If the request returned a redirect, propagate it to the client */ + + if (is_HTTP_REDIRECT(rr->status) || + (rr->status == HTTP_NOT_ACCEPTABLE && *names_ptr == '\0')) { + + error_notfound = rr->status; + r->notes = overlay_tables(r->pool, r->notes, rr->notes); + r->headers_out = overlay_tables(r->pool, r->headers_out, + rr->headers_out); + r->err_headers_out = overlay_tables(r->pool, r->err_headers_out, + rr->err_headers_out); + destroy_sub_req(rr); + return error_notfound; + } + + /* If the request returned something other than 404 (or 200), + * it means the module encountered some sort of problem. To be + * secure, we should return the error, rather than create + * along a (possibly unsafe) directory index. + * + * So we store the error, and if none of the listed files + * exist, we return the last error response we got, instead + * of a directory listing. + */ + if (rr->status && rr->status != HTTP_NOT_FOUND && rr->status != HTTP_OK) + error_notfound = rr->status; + + destroy_sub_req (rr); + } + + if (error_notfound) + return error_notfound; + + if (r->method_number != M_GET) return NOT_IMPLEMENTED; + + /* OK, nothing easy. Trot out the heavy artillery... */ + + if (allow_opts & OPT_INDEXES) + return index_directory (r, d); + else { + log_reason ("Directory index forbidden by rule", r->filename, r); + return HTTP_FORBIDDEN; + } +} + + +handler_rec dir_handlers[] = { +{ DIR_MAGIC_TYPE, handle_dir }, +{ NULL } +}; + +module dir_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + create_dir_config, /* dir config creater */ + merge_dir_configs, /* dir merger --- default is to override */ + NULL, /* server config */ + NULL, /* merge server config */ + dir_cmds, /* command table */ + dir_handlers, /* handlers */ + NULL, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_dld.c b/APACHE_1_2_X/src/modules/standard/mod_dld.c new file mode 100644 index 00000000000..ac6ff33a7ad --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_dld.c @@ -0,0 +1,190 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * A first stab at dynamic loading, using the GNU dld library + * (or at least, an embarassingly old version of it...). + */ + +#include "httpd.h" +#include "http_config.h" +#include "http_conf_globals.h" /* server_argv0. Sigh... */ +#include + +/* + * The hard part of implementing LoadModule is deciding what to do about + * rereading the config files. This proof-of-concept implementation takes the + * cheap way out: we only actually load the modules the first time through. + */ + +static int been_there_done_that = 0; /* Loaded the modules yet? */ +static int have_symbol_table = 0; + +char *insure_dld_sane() +{ + int errcode; + char *bin_name; + + if (have_symbol_table) return NULL; + + bin_name = dld_find_executable (server_argv0); + + if ((errcode = dld_init (bin_name))) { + dld_perror (server_argv0); + return "Cannot find server binary (needed for dynamic linking)."; + } + + have_symbol_table = 1; + return NULL; +} + +char *link_file (pool *p, char *filename) +{ + int errcode; + + filename = server_root_relative (p, filename); + if ((errcode = dld_link (filename))) { + dld_perror (server_argv0); + return pstrcat (p, "Cannot load ", filename, " into server", NULL); + } + return NULL; +} + +char *load_module (cmd_parms *cmd, void *dummy, char *modname, char *filename) +{ + char *errname; + module *modp; + + if (been_there_done_that) return NULL; + + if ((errname = insure_dld_sane())) return errname; + if ((errname = link_file (cmd->pool, filename))) return errname; + if (!(modp = (module *)dld_get_symbol (modname))) { + return pstrcat (cmd->pool, "Can't find module ", modname, + " in file ", filename, NULL); + } + + add_module (modp); + + /* Alethea Patch (rws,djw2) - need to run configuration functions + in new modules */ + + if (modp->create_server_config) + ((void**)cmd->server->module_config)[modp->module_index]= + (*modp->create_server_config)(cmd->pool, cmd->server); + + if (modp->create_dir_config) + ((void**)cmd->server->lookup_defaults)[modp->module_index]= + (*modp->create_dir_config)(cmd->pool, NULL); + + + return NULL; +} + +char *load_file (cmd_parms *cmd, void *dummy, char *filename) +{ + char *errname; + + if (been_there_done_that) return NULL; + + if ((errname = insure_dld_sane())) return errname; + if ((errname = link_file (cmd->pool, filename))) return errname; + return NULL; +} + +void check_loaded_modules (server_rec *dummy, pool *p) +{ + if (been_there_done_that) return; + + if (dld_undefined_sym_count > 0) { + /* Screwup. Do the best we can to inform the user, and exit */ + char **bad_syms = dld_list_undefined_sym(); + int i; + + fprintf(stderr, "Dynamic linking error --- symbols left undefined.\n"); + fprintf(stderr, "(It may help to relink libraries).\n"); + fprintf(stderr, "Undefined symbols follow:\n"); + + for (i = 0; i < dld_undefined_sym_count; ++i) + fprintf (stderr, "%s\n", bad_syms[i]); + + exit (1); + } + + been_there_done_that = 1; +} + +command_rec dld_cmds[] = { +{ "LoadModule", load_module, NULL, RSRC_CONF, TAKE2, + "a module name, and the name of a file to load it from"}, +{ "LoadFile", load_file, NULL, RSRC_CONF, ITERATE, + "files or libraries to link into the server at runtime"}, +{ NULL } +}; + +module dld_module = { + STANDARD_MODULE_STUFF, + check_loaded_modules, /* initializer */ + NULL, /* create per-dir config */ + NULL, /* merge per-dir config */ + NULL, /* server config */ + NULL, /* merge server config */ + dld_cmds, /* command table */ + NULL, /* handlers */ + NULL, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_env.c b/APACHE_1_2_X/src/modules/standard/mod_env.c new file mode 100644 index 00000000000..8ae697038da --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_env.c @@ -0,0 +1,261 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * mod_env.c + * version 0.0.5 + * status beta + * Pass environment variables to CGI/SSI scripts. + * + * Andrew Wilson 06.Dec.95 + * + * Change log: + * 08.Dec.95 Now allows PassEnv directive to appear more than once in + * conf files. + * 10.Dec.95 optimisation. getenv() only called at startup and used + * to build a fast-to-access table. table used to build + * per-server environment for each request. + * robustness. better able to handle errors in configuration + * files: + * 1) PassEnv directive present, but no environment variable listed + * 2) PassEnv FOO present, but $FOO not present in environment + * 3) no PassEnv directive present + * 23.Dec.95 Now allows SetEnv directive with same semantics as 'sh' setenv: + * SetEnv Var sets Var to the empty string + * SetEnv Var Val sets Var to the value Val + * Values containing whitespace should be quoted, eg: + * SetEnv Var "this is some text" + * Environment variables take their value from the last instance + * of PassEnv / SetEnv to be reached in the configuration file. + * For example, the sequence: + * PassEnv FOO + * SetEnv FOO override + * Causes FOO to take the value 'override'. + * 23.Feb.96 Added UnsetEnv directive to allow environment variables + * to be removed. + * Virtual hosts now 'inherit' parent server environment which + * they're able to overwrite with their own directives or + * selectively ignore with UnsetEnv. + * *** IMPORTANT - the way that virtual hosts inherit their *** + * *** environment variables from the default server's *** + * *** configuration has changed. You should test your *** + * *** configuration carefully before accepting this *** + * *** version of the module in a live webserver which used *** + * *** older versions of the module. *** + */ + +#include "httpd.h" +#include "http_config.h" + +typedef struct { + table *vars; + char *unsetenv; + int vars_present; +} env_server_config_rec; + +module env_module; + +void *create_env_server_config (pool *p, server_rec *dummy) +{ + env_server_config_rec *new = + (env_server_config_rec *) palloc (p, sizeof(env_server_config_rec)); + new->vars = make_table (p, 50); + new->unsetenv = ""; + new->vars_present = 0; + return (void *) new; +} + +void *merge_env_server_configs (pool *p, void *basev, void *addv) +{ + env_server_config_rec *base = (env_server_config_rec *)basev; + env_server_config_rec *add = (env_server_config_rec *)addv; + env_server_config_rec *new = + (env_server_config_rec *)palloc (p, sizeof(env_server_config_rec)); + + table *new_table; + table_entry *elts; + + int i; + const char *uenv, *unset; + + /* + * new_table = copy_table( p, base->vars ); + * foreach $element ( @add->vars ) { + * table_set( new_table, $element.key, $element.val ); + * }; + * foreach $unsetenv ( @UNSETENV ) { + * table_unset( new_table, $unsetenv ); + * } + */ + + new_table = copy_table( p, base->vars ); + + elts = (table_entry *) add->vars->elts; + + for ( i = 0; i < add->vars->nelts; ++i ) { + table_set( new_table, elts[i].key, elts[i].val ); + } + + unset = add->unsetenv; + uenv = getword_conf( p, &unset ); + while ( uenv[0] != '\0' ) { + table_unset( new_table, uenv ); + uenv = getword_conf( p, &unset ); + } + + new->vars = new_table; + + new->vars_present = base->vars_present || add->vars_present; + + return new; +} + +const char *add_env_module_vars_passed (cmd_parms *cmd, char *struct_ptr, + const char *arg) +{ + env_server_config_rec *sconf = + get_module_config (cmd->server->module_config, &env_module); + table *vars = sconf->vars; + char *env_var; + char *name_ptr; + + while (*arg) { + name_ptr = getword_conf (cmd->pool, &arg); + env_var = getenv(name_ptr); + if ( env_var != NULL ) { + sconf->vars_present = 1; + table_set (vars, name_ptr, env_var); + } + } + return NULL; +} + +const char *add_env_module_vars_set (cmd_parms *cmd, char *struct_ptr, + const char *arg) +{ + env_server_config_rec *sconf = + get_module_config (cmd->server->module_config, &env_module); + table *vars = sconf->vars; + char *name, *value; + + name = getword_conf( cmd->pool, &arg ); + value = getword_conf( cmd->pool, &arg ); + + /* name is mandatory, value is optional. no value means + * set the variable to an empty string + */ + + + if ( (*name == '\0') || (*arg != '\0')) { + return "SetEnv takes one or two arguments. An environment variable name and an optional value to pass to CGI." ; + } + + sconf->vars_present = 1; + table_set (vars, name, value); + + return NULL; +} + +const char *add_env_module_vars_unset (cmd_parms *cmd, char *struct_ptr, + char *arg) +{ + env_server_config_rec *sconf = + get_module_config (cmd->server->module_config, &env_module); + sconf->unsetenv = sconf->unsetenv ? + pstrcat( cmd->pool, sconf->unsetenv, " ", arg, NULL ) : + pstrdup( cmd->pool, arg ); + return NULL; +} + +command_rec env_module_cmds[] = { +{ "PassEnv", add_env_module_vars_passed, NULL, + RSRC_CONF, RAW_ARGS, "a list of environment variables to pass to CGI." }, +{ "SetEnv", add_env_module_vars_set, NULL, + RSRC_CONF, RAW_ARGS, "an environment variable name and a value to pass to CGI." }, +{ "UnsetEnv", add_env_module_vars_unset, NULL, + RSRC_CONF, RAW_ARGS, "a list of variables to remove from the CGI environment." }, +{ NULL }, +}; + +int fixup_env_module(request_rec *r) +{ + table *e = r->subprocess_env; + server_rec *s = r->server; + env_server_config_rec *sconf = get_module_config (s->module_config, + &env_module); + table *vars = sconf->vars; + + if ( !sconf->vars_present ) return DECLINED; + + r->subprocess_env = overlay_tables( r->pool, e, vars ); + + return OK; +} + +module env_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + NULL, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + create_env_server_config, /* server config */ + merge_env_server_configs, /* merge server configs */ + env_module_cmds, /* command table */ + NULL, /* handlers */ + NULL, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + fixup_env_module, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_expires.c b/APACHE_1_2_X/src/modules/standard/mod_expires.c new file mode 100644 index 00000000000..226726a0a93 --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_expires.c @@ -0,0 +1,477 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * mod_expires.c + * version 0.0.11 + * status beta + * + * Andrew Wilson 26.Jan.96 + * + * This module allows you to control the form of the Expires: header + * that Apache issues for each access. Directives can appear in + * configuration files or in .htaccess files so expiry semantics can + * be defined on a per-directory basis. + * + * DIRECTIVE SYNTAX + * + * Valid directives are: + * + * ExpiresActive on | off + * ExpiresDefault + * ExpiresByType type/encoding + * + * Valid values for are: + * + * 'M' expires header shows file modification date + + * 'A' expires header shows access time + + * + * [I'm not sure which of these is best under different + * circumstances, I guess it's for other people to explore. + * The effects may be indistinguishable for a number of cases] + * + * should be an integer value [acceptable to atoi()] + * + * There is NO space between the and . + * + * For example, a directory which contains information which changes + * frequently might contain: + * + * # reports generated by cron every hour. don't let caches + * # hold onto stale information + * ExpiresDefault M3600 + * + * Another example, our html pages can change all the time, the gifs + * tend not to change often: + * + * # pages are hot (1 week), images are cold (1 month) + * ExpiresByType text/html A604800 + * ExpiresByType image/gif A2592000 + * + * Expires can be turned on for all URLs on the server by placing the + * following directive in a conf file: + * + * ExpiresActive on + * + * ExpiresActive can also appear in .htaccess files, enabling the + * behaviour to be turned on or off for each chosen directory. + * + * # turn off Expires behaviour in this directory + * # and subdirectories + * ExpiresActive off + * + * Directives defined for a directory are valid in subdirectories + * unless explicitly overridden by new directives in the subdirectory + * .htaccess files. + * + * ALTERNATIVE DIRECTIVE SYNTAX + * + * Directives can also be defined in a more readable syntax of the form: + * + * ExpiresDefault " [plus] { }*" + * ExpiresByType type/encoding " [plus] { }*" + * + * where is one of: + * access + * now equivalent to 'access' + * modification + * + * where the 'plus' keyword is optional + * + * where should be an integer value [acceptable to atoi()] + * + * where is one of: + * years + * months + * weeks + * days + * hours + * minutes + * seconds + * + * For example, any of the following directives can be used to make + * documents expire 1 month after being accessed, by default: + * + * ExpiresDefault "access plus 1 month" + * ExpiresDefault "access plus 4 weeks" + * ExpiresDefault "access plus 30 days" + * + * The expiry time can be fine-tuned by adding several ' ' + * clauses: + * + * ExpiresByType text/html "access plus 1 month 15 days 2 hours" + * ExpiresByType image/gif "modification plus 5 hours 3 minutes" + * + * --- + * + * Change-log: + * 29.Jan.96 Hardened the add_* functions. Server will now bail out + * if bad directives are given in the conf files. + * 02.Feb.96 Returns DECLINED if not 'ExpiresActive on', giving other + * expires-aware modules a chance to play with the same + * directives. [Michael Rutman] + * 03.Feb.96 Call tzset() before localtime(). Trying to get the module + * to work properly in non GMT timezones. + * 12.Feb.96 Modified directive syntax to allow more readable commands: + * ExpiresDefault "now plus 10 days 20 seconds" + * ExpiresDefault "access plus 30 days" + * ExpiresDefault "modification plus 1 year 10 months 30 days" + * 13.Feb.96 Fix call to table_get() with NULL 2nd parameter [Rob Hartill] + * 19.Feb.96 Call gm_timestr_822() to get time formatted correctly, can't + * rely on presence of HTTP_TIME_FORMAT in Apache 1.1+. + * 21.Feb.96 This version (0.0.9) reverses assumptions made in 0.0.8 + * about star/star handlers. Reverting to 0.0.7 behaviour. + * 08.Jun.96 allows ExpiresDefault to be used with responses that use + * the DefaultType by not DECLINING, but instead skipping + * the table_get check and then looking for an ExpiresDefault. + * [Rob Hartill] + * 04.Nov.96 'const' definitions added. + * + * TODO + * add support for Cache-Control: max-age=20 from the HTTP/1.1 + * proposal (in this case, a ttl of 20 seconds) [ask roy] + * add per-file expiry and explicit expiry times - duplicates some + * of the mod_cern_meta.c functionality. eg: + * ExpiresExplicit index.html "modification plus 30 days" + * + * BUGS + * Hi, welcome to the internet. + */ + +#include +#include "httpd.h" +#include "http_config.h" +#include "http_log.h" + +typedef struct { + int active; + char *expiresdefault; + table *expiresbytype; +} expires_dir_config; + +/* from mod_dir, why is this alias used? + */ +#define DIR_CMD_PERMS OR_INDEXES + +#define ACTIVE_ON 1 +#define ACTIVE_OFF 0 +#define ACTIVE_DONTCARE 2 + +module expires_module; + +void *create_dir_expires_config (pool *p, char *dummy) +{ + expires_dir_config *new = + (expires_dir_config *) pcalloc (p, sizeof(expires_dir_config)); + new->active = ACTIVE_DONTCARE; + new->expiresdefault = ""; + new->expiresbytype = make_table(p, 4); + return (void *)new; +} + +const char *set_expiresactive (cmd_parms *cmd, expires_dir_config *dir_config, int arg) +{ + /* if we're here at all it's because someone explicitly + * set the active flag + */ + dir_config->active = ACTIVE_ON; + if ( arg == 0 ) { + dir_config->active = ACTIVE_OFF; + }; + return NULL; +} + +/* check_code() parse 'code' and return NULL or an error response + * string. If we return NULL then real_code contains code converted + * to the cnnnn format. + */ +char *check_code( pool *pool, const char *code, char **real_code ) +{ + char *word; + char base = 'X'; + int modifier = 0; + int num = 0; + int factor = 0; + char foo[MAX_STRING_LEN]; + + /* 0.0.4 compatibility? + */ + if ( (code[0] == 'A') || (code[0] == 'M') ) { + *real_code = pstrdup( pool, code ); + return NULL; + }; + + /* [plus] { }* + */ + + /* + */ + word = getword_conf( pool, &code ); + if ( !strncasecmp( word, "now", 1 ) || + !strncasecmp( word, "access", 1 ) ) { + base = 'A'; + } else if ( !strncasecmp( word, "modification", 1 ) ) { + base = 'M'; + } else { + return pstrcat( pool, "bad expires code, unrecognised '", + word, "'", NULL); + }; + + /* [plus] + */ + word = getword_conf( pool, &code ); + if ( !strncasecmp( word, "plus", 1 ) ) { + word = getword_conf( pool, &code ); + }; + + /* { }* + */ + while ( word[0] ) { + /* + */ + if (isdigit(word[0])) { + num = atoi( word ); + } else { + return pstrcat( pool, "bad expires code, numeric value expected '", + word, "'", NULL); + }; + + /* + */ + word = getword_conf( pool, &code ); + if ( word[0] ) { + /* do nothing */ + } else { + return pstrcat( pool, "bad expires code, missing ", NULL); + }; + + factor = 0; + if ( !strncasecmp( word, "years", 1 ) ) { + factor = 60*60*24*365; + } else if ( !strncasecmp( word, "months", 2 ) ) { + factor = 60*60*24*30; + } else if ( !strncasecmp( word, "weeks", 1 ) ) { + factor = 60*60*24*7; + } else if ( !strncasecmp( word, "days", 1 ) ) { + factor = 60*60*24; + } else if ( !strncasecmp( word, "hours", 1 ) ) { + factor = 60*60; + } else if ( !strncasecmp( word, "minutes", 2 ) ) { + factor = 60; + } else if ( !strncasecmp( word, "seconds", 1 ) ) { + factor = 1; + } else { + return pstrcat( pool, "bad expires code, unrecognised ", + "'", word, "'", NULL); + }; + + modifier = modifier + factor * num; + + /* next + */ + word = getword_conf( pool, &code ); + }; + + ap_snprintf(foo, sizeof(foo), "%c%d", base, modifier ); + *real_code = pstrdup( pool, foo ); + + return NULL; +} + +const char *set_expiresbytype(cmd_parms *cmd, expires_dir_config *dir_config, char *mime, char *code) +{ + char *response, *real_code; + + if ( (response = check_code( cmd->pool, code, &real_code )) == NULL ) { + table_set (dir_config->expiresbytype, mime, real_code); + return NULL; + }; + return pstrcat( cmd->pool, + "'ExpiresByType ", mime, " ", code, "': ", response, NULL ); +} + +const char *set_expiresdefault (cmd_parms *cmd, expires_dir_config *dir_config, char *code) +{ + char *response, *real_code; + + if ( (response = check_code( cmd->pool, code, &real_code )) == NULL ) { + dir_config->expiresdefault = pstrdup( cmd->pool, real_code ); + return NULL; + }; + return pstrcat( cmd->pool, + "'ExpiresDefault ", code, "': ", response, NULL ); +} + +command_rec expires_cmds[] = { +{ "ExpiresActive", set_expiresactive, NULL, DIR_CMD_PERMS, FLAG, NULL}, +{ "ExpiresBytype", set_expiresbytype, NULL, DIR_CMD_PERMS, TAKE2, + "a mime type followed by an expiry date code"}, +{ "ExpiresDefault", set_expiresdefault, NULL, DIR_CMD_PERMS, TAKE1, + "an expiry date code"}, +{ NULL } +}; + +void *merge_expires_dir_configs (pool *p, void *basev, void *addv) +{ + expires_dir_config *new= (expires_dir_config*)pcalloc (p, sizeof(expires_dir_config)); + expires_dir_config *base = (expires_dir_config *)basev; + expires_dir_config *add = (expires_dir_config *)addv; + + if ( add->active == ACTIVE_DONTCARE ) { + new->active = base->active; + } else { + new->active = add->active; + }; + + if ( add->expiresdefault != '\0' ) { + new->expiresdefault = add->expiresdefault; + }; + + new->expiresbytype = overlay_tables (p, add->expiresbytype, + base->expiresbytype); + return new; +} + +int add_expires(request_rec *r) +{ + expires_dir_config *conf = + (expires_dir_config *)get_module_config(r->per_dir_config, &expires_module); + char *code; + time_t base; + time_t additional; + time_t expires; + + if ( r->finfo.st_mode == 0 ) + return DECLINED; + + /* COMMA bites my ass... + */ + if ( conf == NULL ) { + log_reason ("internal error in expires_module; add_expires(), conf == NULL", r->filename, r); + return SERVER_ERROR; + }; + + if ( conf->active != ACTIVE_ON ) + return DECLINED; + + /* we perhaps could use the default_type(r) in its place but that + * may be 2nd guesing the desired configuration... calling table_get + * with a NULL key will SEGV us + * + * I still don't know *why* r->content_type would ever be NULL, this + * is possibly a result of fixups being called in many different + * places. Fixups is probably the wrong place to be doing all this + * work... Bah. + * + * Changed as of 08.Jun.96 don't DECLINE, look for an ExpiresDefault. + */ + if ( r->content_type == NULL ) + code = NULL; + else + code = (char *) table_get( conf->expiresbytype, r->content_type ); + + if ( code == NULL ) { + /* no expires defined for that type, is there a default? */ + code = conf->expiresdefault; + + if ( code[0] == '\0' ) + return OK; + }; + + /* we have our code */ + + switch (code[0]) { + case 'M': + base = r->finfo.st_mtime; + additional = atoi( &code[1] ); + break; + case 'A': + /* there's been some discussion and it's possible that + * 'access time' will be stored in request structure + */ + base = time( NULL ); + additional = atoi( &code[1] ); + break; + default: + /* expecting the add_* routines to be case-hardened this + * is just a reminder that module is beta + */ + log_reason ("internal error in expires_module; bad expires code", r->filename, r); + return SERVER_ERROR; + }; + + expires = base + additional; + tzset(); /* redundant? called implicitly by localtime, at least + * under FreeBSD + */ + table_set( r->headers_out, "Expires", gm_timestr_822( r->pool, expires )); + return OK; +} + +module expires_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + create_dir_expires_config, /* dir config creater */ + merge_expires_dir_configs, /* dir merger --- default is to override */ + NULL, /* server config */ + NULL, /* merge server configs */ + expires_cmds, /* command table */ + NULL, /* handlers */ + NULL, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + add_expires, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_headers.c b/APACHE_1_2_X/src/modules/standard/mod_headers.c new file mode 100644 index 00000000000..3976be7ba8a --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_headers.c @@ -0,0 +1,253 @@ +/* ==================================================================== + * Copyright (c) 1996,1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * mod_headers.c: Add/append/remove HTTP response headers + * Written by Paul Sutton, paul@ukweb.com, 1 Oct 1996 + * + * New directive, Header, can be used to add/replace/remove HTTP headers. + * Valid in both per-server and per-dir configurations. + * + * Syntax is: + * + * Header action header value + * + * Where action is one of: + * set - set this header, replacing any old value + * add - add this header, possible resulting in two or more + * headers with the same name + * append - append this text onto any existing header of this same + * unset - remove this header + * + * Where action is unset, the third argument (value) should not be given. + * The header name can include the colon, or not. + * + * The Header directive can only be used where allowed by the FileInfo + * override. + * + * When the request is processed, the header directives are processed in + * this order: firstly, the main server, then the virtual server handling + * this request (if any), then any sections (working downwards + * from the root dir), then an sections (working down from + * shortest URL component), the any sections. This order is + * important if any 'set' or 'unset' actions are used. For example, + * the following two directives have different effect if applied in + * the reverse order: + * + * Header append Author "John P. Doe" + * Header unset Author + * + * Examples: + * + * To set the "Author" header, use + * Header add Author "John P. Doe" + * + * To remove a header: + * Header unset Author + * + */ + +#include "httpd.h" +#include "http_config.h" + +typedef enum { + hdr_add = 'a', /* add header (could mean multiple hdrs) */ + hdr_set = 's', /* set (replace old value) */ + hdr_append = 'm', /* append (merge into any old value) */ + hdr_unset = 'u' /* unset header */ +} hdr_actions; + +typedef struct { + hdr_actions action; + char *header; + char *value; +} header_entry; + +/* + * headers_conf is our per-module configuration. This is used as both + * a per-dir and per-server config + */ +typedef struct { + array_header *headers; +} headers_conf; + +module headers_module; + +void *create_headers_config (pool *p, server_rec *s) +{ + headers_conf *a = + (headers_conf *)pcalloc (p, sizeof(headers_conf)); + + a->headers = make_array (p, 2, sizeof(header_entry)); + return a; +} + +void *create_headers_dir_config (pool *p, char *d) +{ + return (headers_conf*)create_headers_config(p, NULL); +} + +void *merge_headers_config (pool *p, void *basev, void *overridesv) +{ + headers_conf *a = + (headers_conf *)pcalloc (p, sizeof(headers_conf)); + headers_conf *base = (headers_conf *)basev, + *overrides = (headers_conf *)overridesv; + + a->headers = append_arrays(p, base->headers, overrides->headers); + + return a; +} + + +const char *header_cmd(cmd_parms *cmd, headers_conf *dirconf, char *action, char *hdr, char *value) +{ + header_entry *new; + server_rec *s = cmd->server; + headers_conf *serverconf = + (headers_conf *)get_module_config(s->module_config,&headers_module); + char *colon; + + if ( cmd->path ) + { + new = (header_entry*)push_array(dirconf->headers); + } + else + { + new = (header_entry*)push_array(serverconf->headers); + } + + if (!strcasecmp(action, "set")) new->action = hdr_set; + else if (!strcasecmp(action, "add")) new->action = hdr_add; + else if (!strcasecmp(action, "append")) new->action = hdr_append; + else if (!strcasecmp(action, "unset")) new->action = hdr_unset; + else + return "first argument must be add, set, append or unset."; + + if (new->action == hdr_unset) { + if (value) return "Header unset takes two arguments"; + } + else if (!value) + return "Header requires three arguments"; + + if ((colon = strchr(hdr, ':'))) + *colon = '\0'; + + new->header = pstrdup(cmd->pool, hdr); + new->value = value ? pstrdup(cmd->pool, value) : NULL; + + return NULL; +} + +command_rec headers_cmds[] = { +{ "Header", header_cmd, NULL, OR_FILEINFO, TAKE23, + "an action, header and value"}, +{ NULL } +}; + +void do_headers_fixup(request_rec *r, array_header *headers) +{ + int i; + + for (i = 0; i < headers->nelts; ++i) { + header_entry *hdr = &((header_entry*)(headers->elts))[i]; + switch (hdr->action) { + case hdr_add: + table_add(r->headers_out, hdr->header, hdr->value); + break; + case hdr_append: + table_merge(r->headers_out, hdr->header, hdr->value); + break; + case hdr_set: + table_set(r->headers_out, hdr->header, hdr->value); + break; + case hdr_unset: + table_unset(r->headers_out, hdr->header); + break; + } + } + +} + +int fixup_headers(request_rec *r) +{ + void *sconf = r->server->module_config; + headers_conf *serverconf = + (headers_conf *)get_module_config(sconf, &headers_module); + void *dconf = r->per_dir_config; + headers_conf *dirconf = + (headers_conf *)get_module_config(dconf, &headers_module); + + do_headers_fixup(r, serverconf->headers); + do_headers_fixup(r, dirconf->headers); + + return DECLINED; +} + +module headers_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + create_headers_dir_config, /* dir config creater */ + merge_headers_config, /* dir merger --- default is to override */ + create_headers_config, /* server config */ + merge_headers_config, /* merge server configs */ + headers_cmds, /* command table */ + NULL, /* handlers */ + NULL, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + fixup_headers, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_imap.c b/APACHE_1_2_X/src/modules/standard/mod_imap.c new file mode 100644 index 00000000000..e65925b5a30 --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_imap.c @@ -0,0 +1,837 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * This imagemap module started as a port of the original imagemap.c + * written by Rob McCool (11/13/93 robm@ncsa.uiuc.edu). + * This version includes the mapping algorithms found in version 1.3 + * of imagemap.c. + * + * Contributors to this code include: + * + * Kevin Hughes, kevinh@pulua.hcc.hawaii.edu + * + * Eric Haines, erich@eye.com + * "macmartinized" polygon code copyright 1992 by Eric Haines, erich@eye.com + * + * Randy Terbush, randy@zyzzyva.com + * port to Apache module format, "base_uri" and support for relative URLs + * + * James H. Cloos, Jr., cloos@jhcloos.com + * Added point datatype, using code in NCSA's version 1.8 imagemap.c + * program, as distributed with version 1.4.1 of their server. + * The point code is originally added by Craig Milo Rogers, Rogers@ISI.Edu + * + * Nathan Kurz, nate@tripod.com + * Rewrite/reorganization. New handling of default, base and relative URLs. + * New Configuration directives: + * ImapMenu {none, formatted, semiformatted, unformatted} + * ImapDefault {error, nocontent, referer, menu, URL} + * ImapBase {map, referer, URL} + * Support for creating non-graphical menu added. (backwards compatible): + * Old: directive URL [x,y ...] + * New: directive URL "Menu text" [x,y ...] + * or: directive URL x,y ... "Menu text" + * Map format and menu concept courtesy Joshua Bell, jsbell@acs.ucalgary.ca. + * + * Mark Cox, mark@ukweb.com, Allow relative URLs even when no base specified + */ + +#include "httpd.h" +#include "http_config.h" +#include "http_request.h" +#include "http_core.h" +#include "http_protocol.h" +#include "http_main.h" +#include "http_log.h" +#include "util_script.h" + +#define IMAP_MAGIC_TYPE "application/x-httpd-imap" +#define LARGEBUF 500 +#define SMALLBUF 256 +#define MAXVERTS 100 +#define X 0 +#define Y 1 + +#define IMAP_MENU_DEFAULT "formatted" +#define IMAP_DEFAULT_DEFAULT "nocontent" +#define IMAP_BASE_DEFAULT "map" + +#ifdef SUNOS4 +double strtod(); /* SunOS needed this */ +#endif + +module imap_module; + +typedef struct { + char *imap_menu; + char *imap_default; + char *imap_base; +} imap_conf_rec; + +void *create_imap_dir_config (pool *p, char *dummy) { + imap_conf_rec *icr = + (imap_conf_rec *)palloc(p, sizeof(imap_conf_rec)); + + icr->imap_menu = NULL; + icr->imap_default = NULL; + icr->imap_base = NULL; + + return icr; +} + +void *merge_imap_dir_configs (pool *p, void *basev, void *addv) +{ + imap_conf_rec *new=(imap_conf_rec *)pcalloc (p, sizeof(imap_conf_rec)); + imap_conf_rec *base = (imap_conf_rec *)basev; + imap_conf_rec *add = (imap_conf_rec *)addv; + + new->imap_menu = add->imap_menu ? add->imap_menu : base->imap_menu; + new->imap_default=add->imap_default ? add->imap_default : base->imap_default; + new->imap_base =add-> imap_base ? add->imap_base : base->imap_base; + + return new; +} + + +command_rec imap_cmds[] = { +{ "ImapMenu", set_string_slot, + (void*)XtOffsetOf(imap_conf_rec, imap_menu), OR_INDEXES, TAKE1, + "the type of menu generated: none, formatted, semiformatted, unformatted"}, +{ "ImapDefault", set_string_slot, + (void*)XtOffsetOf(imap_conf_rec, imap_default), OR_INDEXES, TAKE1, + "the action taken if no match: error, nocontent, referer, menu, URL" }, +{ "ImapBase", set_string_slot, + (void*)XtOffsetOf(imap_conf_rec, imap_base), OR_INDEXES, TAKE1, + "the base for all URL's: map, referer, URL (or start of)" }, +{ NULL } +}; + +int pointinrect(double point[2], double coords[MAXVERTS][2]) +{ + double max[2], min[2]; + if (coords[0][X] > coords[1][X]) { + max[0] = coords[0][X]; + min[0] = coords[1][X]; + } else { + max[0] = coords[1][X]; + min[0] = coords[0][X]; + } + + if (coords[0][Y] > coords[1][Y]) { + max[1] = coords[0][Y]; + min[1] = coords[1][Y]; + } else { + max[1] = coords[1][Y]; + min[1] = coords[0][Y]; + } + + return ((point[X] >= min[0] && point[X] <= max[0]) && + (point[Y] >= min[1] && point[Y] <= max[1])); +} + +int pointincircle(double point[2], double coords[MAXVERTS][2]) +{ + int radius1, radius2; + + radius1 = ((coords[0][Y] - coords[1][Y]) * (coords[0][Y] - coords[1][Y])) + + ((coords[0][X] - coords[1][X]) * (coords[0][X] - coords[1][X])); + + radius2 = ((coords[0][Y] - point[Y]) * (coords[0][Y] - point[Y])) + + ((coords[0][X] - point[X]) * (coords[0][X] - point[X])); + + return (radius2 <= radius1); +} + +int pointinpoly(double point[2], double pgon[MAXVERTS][2]) +{ + int i, numverts, inside_flag, xflag0; + int crossings; + double *p, *stop; + double tx, ty, y; + + for (i = 0; pgon[i][X] != -1 && i < MAXVERTS; i++); + + numverts = i; + crossings = 0; + + tx = point[X]; + ty = point[Y]; + y = pgon[numverts - 1][Y]; + + p = (double *) pgon + 1; + if ((y >= ty) != (*p >= ty)) { + + if ((xflag0 = (pgon[numverts - 1][X] >= tx)) == (*(double *) pgon >= tx)) { + if (xflag0) + crossings++; + } + else { + crossings += (pgon[numverts - 1][X] - (y - ty) * + (*(double *) pgon - pgon[numverts - 1][X]) / + (*p - y)) >= tx; + } + } + + stop = pgon[numverts]; + + for (y = *p, p += 2; p < stop; y = *p, p += 2) { + + if (y >= ty) { + + while ((p < stop) && (*p >= ty)) + p += 2; + + if (p >= stop) + break; + if ((xflag0 = (*(p - 3) >= tx)) == (*(p - 1) >= tx)) { + + if (xflag0) + crossings++; + } + else { + crossings += (*(p - 3) - (*(p - 2) - ty) * + (*(p - 1) - *(p - 3)) / (*p - *(p - 2))) >= tx; + } + } + else { + while ((p < stop) && (*p < ty)) + p += 2; + + if (p >= stop) + break; + + if ((xflag0 = (*(p - 3) >= tx)) == (*(p - 1) >= tx)) { + if (xflag0) + crossings++; + } + else { + crossings += (*(p - 3) - (*(p - 2) - ty) * + (*(p - 1) - *(p - 3)) / (*p - *(p - 2))) >= tx; + } + } + } + + inside_flag = crossings & 0x01; + return (inside_flag); +} + + +int is_closer(double point[2], double coords[MAXVERTS][2], double *closest) +{ + double dist_squared =((point[X] - coords[0][X]) * (point[X] - coords[0][X])) + + ((point[Y] - coords[0][Y]) * (point[Y] - coords[0][Y])); + + if (point[X] < 0 || point[Y] < 0 ) + return(0); /* don't mess around with negative coordinates */ + + if ( *closest < 0 || dist_squared < *closest ) { + *closest = dist_squared; + return(1); /* if this is the first point or is the closest yet + set 'closest' equal to this distance^2 */ + } + + return(0); /* if it's not the first or closest */ + +} + +double get_x_coord(char *args) +{ + char *endptr; /* we want it non-null */ + double x_coord = -1; /* -1 is returned if no coordinate is given */ + + if (args == NULL) + return(-1); /* in case we aren't passed anything */ + + while( *args && !isdigit(*args) && *args != ',') + args++; /* jump to the first digit, but not past a comma or end */ + + x_coord = strtod(args, &endptr); + + if (endptr > args) /* if a conversion was made */ + return(x_coord); + + return(-1); /* else if no conversion was made, or if no args was given */ +} + +double get_y_coord(char *args) +{ + char *endptr; /* we want it non-null */ + char *start_of_y = NULL; + double y_coord = -1; /* -1 is returned on error */ + + if (args == NULL) + return(-1); /* in case we aren't passed anything */ + + start_of_y = strchr(args, ','); /* the comma */ + + if (start_of_y) { + + start_of_y++; /* start looking at the character after the comma */ + + while( *start_of_y && !isdigit(*start_of_y)) + start_of_y++; /* jump to the first digit, but not past the end */ + + y_coord = strtod(start_of_y, &endptr); + + if (endptr > start_of_y) + return(y_coord); + } + + return(-1); /* if no conversion was made, or no comma was found in args */ +} + + +int read_quoted(char *string, char *quoted_part) +{ + char *starting_pos = string; + + while ( isspace(*string) ) + string++; /* go along string until non-whitespace */ + + if ( *string == '"' ) { /* if that character is a double quote */ + + string++; /* step over it */ + + while ( *string && *string != '"' ) { + *quoted_part++ = *string++; /* copy the quoted portion */ + } + + *quoted_part = '\0'; /* end the string with a SNUL */ + + string++; /* step over the last double quote */ + } + + return(string - starting_pos); /* return the total characters read */ +} + +/* + * url needs to point to a string with at least SMALLBUF memory allocated + */ +void imap_url(request_rec *r, char *base, char *value, char *url) +{ +/* translates a value into a URL. */ + int slen, clen; + char *string_pos = NULL; + char *directory = NULL; + char *referer = NULL; + char my_base[SMALLBUF] = {'\0'}; + + if ( ! strcasecmp(value, "map" ) || ! strcasecmp(value, "menu") ) { + if (r->server->port == DEFAULT_PORT ) { + ap_snprintf(url, SMALLBUF, + "http://%s%s", r->server->server_hostname, r->uri); + } + else { + ap_snprintf(url, SMALLBUF, "http://%s:%d%s", r->server->server_hostname, + r->server->port, r->uri); + } + return; + } + + if ( ! strcasecmp(value, "nocontent") || ! strcasecmp(value, "error") ) { + strncpy(url, value, SMALLBUF-1); + url[SMALLBUF-1] = '\0'; + return; /* these are handled elsewhere, so just copy them */ + } + + if ( ! strcasecmp(value, "referer" ) ) { + referer = table_get(r->headers_in, "Referer"); + if ( referer && *referer ) { + strncpy(url, referer, SMALLBUF-1); + url[SMALLBUF-1] = '\0'; + return; + } + else { + *value = '\0'; /* if 'referer' but no referring page, null the value */ + } + } + + string_pos = value; + while ( isalpha(*string_pos) ) + string_pos++; /* go along the URL from the map until a non-letter */ + if ( *string_pos == ':' ) { + strncpy(url, value, SMALLBUF-1); /* if letters and then a colon (like http:) */ + url[SMALLBUF-1] = '\0'; + return; /* it's an absolute URL, so use it! */ + } + + if ( ! base || ! *base ) { + if ( value && *value ) { + strncpy(url, value, SMALLBUF-1); /* no base: use what is given */ + url[SMALLBUF-1] = '\0'; + } + else { + if (r->server->port == DEFAULT_PORT ) { + ap_snprintf(url, SMALLBUF, "http://%s/", r->server->server_hostname); + } + if (r->server->port != DEFAULT_PORT ) { + ap_snprintf(url, SMALLBUF, "http://%s:%d/", + r->server->server_hostname, r->server->port); + } /* no base, no value: pick a simple default */ + } + return; + } + + strncpy(my_base, base, sizeof(my_base)-1); /* must be a relative URL to be combined with base */ + my_base[sizeof(my_base)-1] = '\0'; + if (strchr(my_base, '/') == NULL && (!strncmp(value, "../", 3) || !strcmp(value, "..")) ) { + url[0] = '\0'; + log_reason("invalid base directive in map file", r->uri, r); + return; + } + string_pos = my_base; + while (*string_pos) { + if (*string_pos == '/' && *(string_pos+1) == '/') { + string_pos += 2; /* if there are two slashes, jump over them */ + continue; + } + if (*string_pos == '/') { /* the first single slash */ + if ( value[0] == '/' ) { + *string_pos = '\0'; + } /* if the URL from the map starts from root, end the + base URL string at the first single slash */ + else { + directory = string_pos; /* save the start of the directory portion */ + + string_pos = strrchr(string_pos, '/'); /* now reuse string_pos */ + string_pos++; /* step over that last slash */ + *string_pos = '\0'; + } /* but if the map url is relative, leave the + slash on the base (if there is one) */ + break; + } + string_pos++; /* until we get to the end of my_base without finding + a slash by itself */ + } + + while ( ! strncmp(value, "../", 3) || ! strcmp(value, "..") ) { + + if (directory && (slen = strlen (directory))) { + + /* for each '..', knock a directory off the end + by ending the string right at the last slash. + But only consider the directory portion: don't eat + into the server name. And only try if a directory + portion was found */ + + clen = slen - 1; + + while ((slen - clen) == 1) { + + if ((string_pos = strrchr(directory, '/'))) + *string_pos = '\0'; + clen = strlen (directory); + if (clen == 0) break; + } + + value += 2; /* jump over the '..' that we found in the value */ + } + + if (! strncmp(value, "/../", 4) || ! strcmp(value, "/..") ) + + value++; /* step over the '/' if there are more '..' to do. + this way, we leave the starting '/' on value after + the last '..', but get rid of it otherwise */ + + } /* by this point, value does not start with '..' */ + + if ( value && *value ) { + ap_snprintf(url, SMALLBUF, "%s%s", my_base, value); + } + else { + ap_snprintf(url, SMALLBUF, "%s", my_base); + } + return; +} + +int imap_reply(request_rec *r, char *redirect) +{ + if ( ! strcasecmp(redirect, "error") ) { + return SERVER_ERROR; /* they actually requested an error! */ + } + if ( ! strcasecmp(redirect, "nocontent") ) { + return HTTP_NO_CONTENT; /* tell the client to keep the page it has */ + } + if (redirect && *redirect ) { + table_set(r->headers_out, "Location", redirect); + return REDIRECT; /* must be a URL, so redirect to it */ + } + return SERVER_ERROR; +} + +void menu_header(request_rec *r, char *menu) +{ + r->content_type = "text/html"; + send_http_header(r); + hard_timeout("send menu", r); /* killed in menu_footer */ + + rvputs(r, "\nMenu for ", r->uri, + "\n\n", NULL); + + if (!strcasecmp(menu, "formatted")) { + rvputs(r, "

    Menu for ", r->uri, "

    \n
    \n\n", NULL); + } + + return; +} + +void menu_blank(request_rec *r, char *menu) +{ + if (! strcasecmp(menu, "formatted") ) { + rputs("\n", r); + } + if (! strcasecmp(menu, "semiformatted") ) { + rputs("
    \n", r); + } + if (! strcasecmp(menu, "unformatted") ) { + rputs("\n", r); + } + return; +} + +void menu_comment(request_rec *r, char *menu, char *comment) +{ + if (! strcasecmp(menu, "formatted") ) { + rputs("\n", r); /* print just a newline if 'formatted' */ + } + if (! strcasecmp(menu, "semiformatted") && *comment ) { + rvputs(r, comment, "\n", NULL); + } + if (! strcasecmp(menu, "unformatted") && *comment ) { + rvputs(r, comment, "\n", NULL); + } + return; /* comments are ignored in the 'formatted' form */ +} + +void menu_default(request_rec *r, char *menu, char *href, char *text) +{ + if ( ! strcasecmp(href, "error") || ! strcasecmp(href, "nocontent") ) { + return; /* don't print such lines, these aren'te really href's */ + } + if ( ! strcasecmp(menu, "formatted" ) ) { + rvputs(r, "
    (Default) ", text, "
    \n", + NULL); + } + if ( ! strcasecmp(menu, "semiformatted" ) ) { + rvputs(r, "
    (Default) ", text, "
    \n", + NULL); + } + if ( ! strcasecmp(menu, "unformatted" ) ) { + rvputs(r, "", text, "", NULL); + } + return; +} + +void menu_directive(request_rec *r, char *menu, char *href, char *text) +{ + if ( ! strcasecmp(href, "error") || ! strcasecmp(href, "nocontent") ) { + return; /* don't print such lines, as this isn't really an href */ + } + if ( ! strcasecmp(menu, "formatted" ) ) { + rvputs(r, "
              ", text, "
    \n", + NULL); + } + if ( ! strcasecmp(menu, "semiformatted" ) ) { + rvputs(r, "
              ", text, "
    \n", + NULL); + } + if ( ! strcasecmp(menu, "unformatted" ) ) { + rvputs(r, "", text, "", NULL); + } + return; +} + +void menu_footer(request_rec *r) +{ + rputs("\n\n\n\n", r); /* finish the menu */ + kill_timeout(r); +} + +int imap_handler(request_rec *r) +{ + char input[LARGEBUF] = {'\0'}; + /* size of input can not be lowered without changing hard-coded + * checks + */ + char href_text[SMALLBUF] = {'\0'}; + char base[SMALLBUF] = {'\0'}; + char redirect[SMALLBUF] = {'\0'}; + char directive[SMALLBUF] = {'\0'}; + char value[SMALLBUF] = {'\0'}; + char mapdflt[SMALLBUF] = {'\0'}; + char closest[SMALLBUF] = {'\0'}; + double closest_yet = -1; + + double testpoint[2] = { -1,-1 }; + double pointarray[MAXVERTS + 1][2] = { {-1,-1} }; + int vertex = 0; + + char *string_pos = NULL; + int chars_read = 0; + int showmenu = 0; + + imap_conf_rec *icr = get_module_config(r->per_dir_config, &imap_module); + + char *imap_menu = icr->imap_menu ? + icr->imap_menu : IMAP_MENU_DEFAULT; + char *imap_default = icr->imap_default ? + icr->imap_default : IMAP_DEFAULT_DEFAULT; + char *imap_base = icr->imap_base ? + icr->imap_base : IMAP_BASE_DEFAULT; + + FILE *imap = pfopen(r->pool, r->filename, "r"); + + if ( ! imap ) + return NOT_FOUND; + + imap_url(r, NULL, imap_base, base); /* set base according to default */ + imap_url(r, NULL, imap_default, mapdflt); /* and default to global default */ + + testpoint[X] = get_x_coord(r->args); + testpoint[Y] = get_y_coord(r->args); + + if ((testpoint[X] == -1 || testpoint[Y] == -1) || + (testpoint[X] == 0 && testpoint[Y] == 0) ) { + /* if either is -1 or if both are zero (new Lynx) */ + /* we don't have valid coordinates */ + testpoint[X] = -1; + testpoint[Y] = -1; + if ( strncasecmp(imap_menu, "none", 2) ) + showmenu = 1; /* show the menu _unless_ ImapMenu is 'none' or 'no' */ + } + + if (showmenu) { /* send start of imagemap menu if we're going to */ + menu_header(r, imap_menu); + } + + while (!cfg_getline(input, LARGEBUF, imap)) { + string_pos = input; /* always start at the beginning of line */ + + directive[0] = '\0'; + value[0] = '\0'; + href_text[0] = '\0'; + redirect[0] = '\0'; + chars_read = 0; /* clear these before using */ + + if ( ! input[0] ) { + if (showmenu) { + menu_blank(r, imap_menu); + } + continue; + } + + if ( input[0] == '#' ) { + if (showmenu) { + menu_comment(r, imap_menu, input + 1); + } + continue; + } /* blank lines and comments are ignored if we aren't printing a menu */ + + + if (sscanf(input, "%255s %255s", directive, value) != 2) { + continue; /* make sure we read two fields */ + } + /* Now skip what we just read... we can't use ANSIism %n */ + while (!(isspace(*string_pos))) /* past directive */ + string_pos++; + while (isspace(*string_pos)) /* and whitespace */ + string_pos++; + while (!(isspace(*string_pos))) /* and value... have to watch it */ + string_pos++; /* can have punctuation and stuff */ + + if ( ! strncasecmp(directive, "base", 4 ) ) { /* base, base_uri */ + imap_url(r, NULL, value, base); + continue; /* base is never printed to a menu */ + } + + chars_read = read_quoted(string_pos, href_text); + string_pos += chars_read; /* read the quoted href text if present */ + + if ( ! strcasecmp(directive, "default" ) ) { /* default */ + imap_url(r, NULL, value, mapdflt); + if (showmenu) { /* print the default if there's a menu */ + if (! *href_text) { /* if we didn't find a "href text" */ + strncpy(href_text, mapdflt, sizeof(href_text)-1); /* use the href itself as text */ + href_text[sizeof(href_text)-1] = '\0'; + } + imap_url(r, base, mapdflt, redirect); + menu_default(r, imap_menu, redirect, href_text); + } + continue; + } + + vertex = 0; + while ( vertex < MAXVERTS && + sscanf(string_pos, "%lf, %lf", + &pointarray[vertex][X], &pointarray[vertex][Y]) == 2) + { + /* Now skip what we just read... we can't use ANSIism %n */ + while(isspace(*string_pos)) /* past whitespace */ + string_pos++; + while(isdigit(*string_pos)) /* and the 1st number */ + string_pos++; + string_pos++; /* skip the ',' */ + while(isspace(*string_pos)) /* past any more whitespace */ + string_pos++; + while(isdigit(*string_pos)) /* 2nd number */ + string_pos++; + vertex++; + } /* so long as there are more vertices to read, and + we have room, read them in. We start where we left + off of the last sscanf, not at the beginning.*/ + + pointarray[vertex][X] = -1; /* signals the end of vertices */ + + if (showmenu) { + read_quoted(string_pos, href_text); /* href text could be here instead */ + if (! *href_text) { /* if we didn't find a "href text" */ + strncpy(href_text, value, sizeof(href_text)-1); /* use the href itself in the menu */ + href_text[sizeof(href_text)-1] = '\0'; + } + imap_url(r, base, value, redirect); + menu_directive(r, imap_menu, redirect, href_text); + continue; + } + /* note that we don't make it past here if we are making a menu */ + + if (testpoint[X] == -1 || pointarray[0][X] == -1 ) + continue; /* don't try the following tests if testpoints + are invalid, or if there are no coordinates */ + + if ( ! strcasecmp(directive, "poly" ) ) { /* poly */ + + if (pointinpoly (testpoint, pointarray) ) { + pfclose(r->pool, imap); + imap_url(r, base, value, redirect); + return (imap_reply(r, redirect)); + } + continue; + } + + if ( ! strcasecmp(directive, "circle" ) ) { /* circle */ + + if (pointincircle (testpoint, pointarray) ) { + pfclose(r->pool, imap); + imap_url(r, base, value, redirect); + return (imap_reply(r, redirect)); + } + continue; + } + + if ( ! strcasecmp(directive, "rect" ) ) { /* rect */ + + if (pointinrect (testpoint, pointarray) ) { + pfclose(r->pool, imap); + imap_url(r, base, value, redirect); + return (imap_reply(r, redirect)); + } + continue; + } + + if ( ! strcasecmp(directive, "point" ) ) { /* point */ + + if (is_closer(testpoint, pointarray, &closest_yet) ) { + strncpy(closest, value, sizeof(closest)-1); /* if the closest point yet save it */ + closest[sizeof(closest)-1] = '\0'; + } + + continue; + } /* move on to next line whether it's closest or not */ + + } /* nothing matched, so we get another line! */ + + pfclose(r->pool, imap); /* we are done with the map file, so close it */ + + if (showmenu) { + menu_footer(r); /* finish the menu and we are done */ + return OK; + } + + if (*closest) { /* if a 'point' directive has been seen */ + imap_url(r, base, closest, redirect); + return (imap_reply(r, redirect)); + } + + if (*mapdflt ) { /* a default should be defined, even if only 'nocontent'*/ + imap_url(r, base, mapdflt, redirect); + return(imap_reply(r, redirect)); + } + + return SERVER_ERROR; /* If we make it this far, we failed. They lose! */ +} + + +handler_rec imap_handlers[] = { +{ IMAP_MAGIC_TYPE, imap_handler }, +{ "imap-file", imap_handler }, +{ NULL } +}; + +module imap_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + create_imap_dir_config, /* dir config creater */ + merge_imap_dir_configs, /* dir merger --- default is to override */ + NULL, /* server config */ + NULL, /* merge server config */ + imap_cmds, /* command table */ + imap_handlers, /* handlers */ + NULL, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_include.c b/APACHE_1_2_X/src/modules/standard/mod_include.c new file mode 100644 index 00000000000..66403979383 --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_include.c @@ -0,0 +1,1892 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * http_include.c: Handles the server-parsed HTML documents + * + * Original by Rob McCool; substantial fixups by David Robinson; + * incorporated into the Apache module framework by rst. + * + */ +/* + * sub key may be anything a Perl*Handler can be: + * subroutine name, package name (defaults to package::handler), + * Class->method call or anoymous sub {} + * + * Child accessed + * times.
    + * + * + * + * -Doug MacEachern + */ + +#ifdef USE_PERL_SSI +#include "config.h" +#ifdef USE_SFIO +#undef USE_SFIO +#define USE_STDIO +#endif +#include "modules/perl/mod_perl.h" +#else +#include "httpd.h" +#include "http_config.h" +#include "http_request.h" +#include "http_core.h" +#include "http_protocol.h" +#include "http_log.h" +#include "http_main.h" +#include "util_script.h" +#endif + +#define STARTING_SEQUENCE "" +#define DEFAULT_ERROR_MSG "[an error occurred while processing this directive]" +#define DEFAULT_TIME_FORMAT "%A, %d-%b-%y %T %Z" +#define SIZEFMT_BYTES 0 +#define SIZEFMT_KMG 1 + +static void decodehtml(char *s); +static char *get_tag(pool *p, FILE *in, char *tag, int tag_len, int dodecode); +static int get_directive(FILE *in, char *d, pool *p); + + +/* ------------------------ Environment function -------------------------- */ + +void add_include_vars(request_rec *r, char *timefmt) +{ + struct passwd *pw; + table *e = r->subprocess_env; + char *t; + time_t date = r->request_time; + + table_set(e, "DATE_LOCAL", ht_time(r->pool, date, timefmt, 0)); + table_set(e, "DATE_GMT", ht_time(r->pool, date, timefmt, 1)); + table_set(e, "LAST_MODIFIED",ht_time(r->pool,r->finfo.st_mtime,timefmt,0)); + table_set(e, "DOCUMENT_URI", r->uri); + table_set(e, "DOCUMENT_PATH_INFO", r->path_info); + pw = getpwuid(r->finfo.st_uid); + if (pw) { + table_set(e, "USER_NAME", pw->pw_name); + } else { + char uid[16]; + ap_snprintf(uid, sizeof(uid), "user#%lu", (unsigned long)r->finfo.st_uid); + table_set(e, "USER_NAME", uid); + } + + if((t = strrchr(r->filename, '/'))) + table_set (e, "DOCUMENT_NAME", ++t); + else + table_set (e, "DOCUMENT_NAME", r->uri); + if (r->args) { + unescape_url (r->args); + table_set (e, "QUERY_STRING_UNESCAPED", + escape_shell_cmd (r->pool, r->args)); + } +} + + + +/* --------------------------- Parser functions --------------------------- */ + +#define OUTBUFSIZE 4096 +/* PUT_CHAR and FLUSH_BUF currently only work within the scope of + * find_string(); they are hacks to avoid calling rputc for each and + * every character output. A common set of buffering calls for this + * type of output SHOULD be implemented. + */ +#define PUT_CHAR(c,r) \ + { \ + outbuf[outind++] = c; \ + if (outind == OUTBUFSIZE) { FLUSH_BUF(r) }; \ + } + +/* there SHOULD be some error checking on the return value of + * rwrite, however it is unclear what the API for rwrite returning + * errors is and little can really be done to help the error in + * any case. + */ +#define FLUSH_BUF(r) \ + { \ + rwrite(outbuf, outind, r); \ + outind = 0; \ + } + +/* + * f: file handle being read from + * c: character to read into + * ret: return value to use if input fails + * r: current request_rec + * + * This macro is redefined after find_string() for historical reasons + * to avoid too many code changes. This is one of the many things + * that should be fixed. + */ +#define GET_CHAR(f,c,ret,r) \ + { \ + int i = getc(f); \ + if(i == EOF) { /* either EOF or error -- needs error handling if latter */ \ + if (ferror(f)) \ + fprintf(stderr, "encountered error in GET_CHAR macro, mod_include.\n"); \ + FLUSH_BUF(r); \ + pfclose(r->pool,f); \ + return ret; \ + } \ + c = (char)i; \ + } + +int find_string(FILE *in,char *str, request_rec *r, int printing) { + int x,l=strlen(str),p; + char outbuf[OUTBUFSIZE]; + int outind = 0; + char c; + + p=0; + while(1) { + GET_CHAR(in,c,1,r); + if(c == str[p]) { + if((++p) == l) { + FLUSH_BUF(r); + return 0; + } + } + else { + if (printing) { + for(x=0;x= 11 && val <= 31) || + (val >= 127 && val <= 160) || val >= 256) + p--; /* no data to output */ + else + *p = val; + } else{ + j = i-1; + if (i-1 > MAXENTLEN || entlist[i-1] == NULL) { /* wrong length */ + *p = '&'; + continue; /* skip it */ + } + for (ents=entlist[i-1]; *ents != '\0'; ents += i) + if (strncmp(s+1, ents, i-1) == 0) break; + + if (*ents == '\0') + *p = '&'; /* unknown */ + else { + *p = ((const unsigned char *)ents)[i-1]; + s += i; + } + } + } + + *p = '\0'; +} + +/* + * extract the next tag name and value. + * if there are no more tags, set the tag name to 'done' + * the tag value is html decoded if dodecode is non-zero + */ + +static char * +get_tag(pool *p, FILE *in, char *tag, int tagbuf_len, int dodecode) { + char *t = tag, *tag_val, c, term; + int n; + + n = 0; + + do { /* skip whitespace */ + GET_CHAR(in,c,NULL,p); + } while (isspace(c)); + + /* tags can't start with - */ + if(c == '-') { + GET_CHAR(in,c,NULL,p); + if(c == '-') { + do { + GET_CHAR(in,c,NULL,p); + } while (isspace(c)); + if(c == '>') { + strncpy(tag,"done", tagbuf_len-1); + tag[tagbuf_len-1] = '\0'; + return tag; + } + } + return NULL; /* failed */ + } + + /* find end of tag name */ + while(1) { + if(++n == tagbuf_len) { + t[tagbuf_len - 1] = '\0'; + return NULL; + } + if(c == '=' || isspace(c)) break; + *(t++) = tolower(c); + GET_CHAR(in,c,NULL,p); + } + + *t++ = '\0'; + tag_val = t; + + while (isspace(c)) GET_CHAR(in, c, NULL,p); /* space before = */ + if (c != '=') { + ungetc(c, in); + return NULL; + } + + do { + GET_CHAR(in,c,NULL,p); /* space after = */ + } while (isspace(c)); + + /* we should allow a 'name' as a value */ + + if (c != '"' && c != '\'') return NULL; + term = c; + while(1) { + GET_CHAR(in,c,NULL,p); + if(++n == tagbuf_len) { + t[tagbuf_len - 1] = '\0'; + return NULL; + } +/* Want to accept \" as a valid character within a string. */ + if (c == '\\') { + *(t++) = c; /* Add backslash */ + GET_CHAR(in,c,NULL,p); + if (c == term) /* Only if */ + *(--t) = c; /* Replace backslash ONLY for terminator */ + } else if (c == term) break; + *(t++) = c; + } + *t = '\0'; + if (dodecode) decodehtml(tag_val); + return pstrdup (p, tag_val); +} + +static int +get_directive(FILE *in, char *d, pool *p) { + char c; + + /* skip initial whitespace */ + while(1) { + GET_CHAR(in,c,1,p); + if(!isspace(c)) + break; + } + /* now get directive */ + while(1) { + *d++ = tolower(c); + GET_CHAR(in,c,1,p); + if(isspace(c)) + break; + } + *d = '\0'; + return 0; +} + +/* + * Do variable substitution on strings + */ +void parse_string(request_rec *r, char *in, char *out, int length, + int leave_name) +{ + char ch; + char *next = out; + int numchars = 0; + + while ((ch = *in++) != '\0') { + switch(ch) { + case '\\': + if(*in == '$') + *next++=*in++; + else + *next++=ch; + break; + case '$': + { + char var[MAX_STRING_LEN]; + char vtext[MAX_STRING_LEN]; + char *val; + int braces=0; + int vlen, vtlen; + /* + * Keep the $ and { around because we do no substitution + * if the variable isn't found + */ + vlen = vtlen = 0; + vtext[vtlen++] = ch; + if (*in == '{') { braces = 1; vtext[vtlen++] = *in++; } + while (*in != '\0') { + if (vlen == (MAX_STRING_LEN - 1)) continue; + if (braces == 1) { + if (*in == '}') break; + } + else if (! (isalpha((int)*in) || (*in == '_') || isdigit((int)*in)) ) break; + if (vtlen < (MAX_STRING_LEN - 1)) vtext[vtlen++] = *in; + var[vlen++] = *in++; + } + var[vlen] = vtext[vtlen] = '\0'; + if (braces == 1) { + if (*in != '}') { + log_printf(r->server, "Invalid variable %s%s", vtext,in); + *next = '\0'; + return; + } else + in++; + } + + val = (char *)NULL; + if (var[0] == '\0') { + val = &vtext[0]; + } else { + val = table_get (r->subprocess_env, &var[0]); + if (!val && leave_name) + val = &vtext[0]; + } + while ((val != (char *)NULL) && (*val != '\0')) { + *next++ = *val++; + if (++numchars == (length -1)) break; + } + break; + } + default: + *next++ = ch; + break; + } + if (++numchars == (length -1)) break; + } + *next = '\0'; + return; +} + +/* --------------------------- Action handlers ---------------------------- */ + +int include_cgi(char *s, request_rec *r) +{ + request_rec *rr = sub_req_lookup_uri (s, r); + + if (rr->status != 200) return -1; + + /* No hardwired path info or query allowed */ + + if ((rr->path_info && rr->path_info[0]) || rr->args) return -1; + if (rr->finfo.st_mode == 0) return -1; + + /* Script gets parameters of the *document*, for back compatibility */ + + rr->path_info = r->path_info; /* painful to get right; see mod_cgi.c */ + rr->args = r->args; + + /* Force sub_req to be treated as a CGI request, even if ordinary + * typing rules would have called it something else. + */ + + rr->content_type = CGI_MAGIC_TYPE; + + /* Run it. */ + + if (run_sub_req (rr) == REDIRECT) { + char *location = table_get (rr->headers_out, "Location"); + location = escape_html(rr->pool, location); + rvputs(r,"", location, "", NULL); + } + + destroy_sub_req (rr); + + return 0; +} + +int handle_include(FILE *in, request_rec *r, char *error, int noexec) { + char tag[MAX_STRING_LEN]; + char parsed_string[MAX_STRING_LEN]; + char *tag_val; + + while(1) { + if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1))) + return 1; + if(!strcmp(tag,"file") || !strcmp (tag, "virtual")) { + request_rec *rr=NULL; + char *error_fmt = NULL; + + parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0); + if (tag[0] == 'f') + { /* be safe; only files in this directory or below allowed */ + char tmp[MAX_STRING_LEN+2]; + ap_snprintf(tmp, sizeof(tmp), "/%s/", parsed_string); + if (parsed_string[0] == '/' || strstr(tmp, "/../") != NULL) + error_fmt = "unable to include file %s in parsed file %s"; + else + rr = sub_req_lookup_file (parsed_string, r); + } else + rr = sub_req_lookup_uri (parsed_string, r); + + if (!error_fmt && rr->status != 200) + error_fmt = "unable to include %s in parsed file %s"; + + if (!error_fmt && noexec && rr->content_type + && (strncmp (rr->content_type, "text/", 5))) + error_fmt = + "unable to include potential exec %s in parsed file %s"; + if (error_fmt == NULL) + { + request_rec *p; + + for (p=r; p != NULL; p=p->main) + if (strcmp(p->filename, rr->filename) == 0) break; + if (p != NULL) + error_fmt = "Recursive include of %s in parsed file %s"; + } + + if (!error_fmt && run_sub_req (rr)) + error_fmt = "unable to include %s in parsed file %s"; + + if (error_fmt) { + log_printf(r->server, error_fmt, tag_val, r->filename); + rputs(error, r); + } + + if (rr != NULL) destroy_sub_req (rr); + } + else if(!strcmp(tag,"done")) + return 0; + else { + log_printf(r->server, "unknown parameter %s to tag include in %s", + tag, r->filename); + rputs(error, r); + } + } +} + +typedef struct { + request_rec *r; + char *s; +} include_cmd_arg; + +void include_cmd_child (void *arg) +{ + request_rec *r = ((include_cmd_arg *)arg)->r; + char *s = ((include_cmd_arg *)arg)->s; + table *env = r->subprocess_env; +#ifdef DEBUG_INCLUDE_CMD + FILE *dbg = fopen ("/dev/tty", "w"); +#endif + char err_string [MAX_STRING_LEN]; + +#ifdef DEBUG_INCLUDE_CMD +#ifdef __EMX__ + /* under OS/2 /dev/tty is referenced as con */ + FILE *dbg = fopen ("con", "w"); +#else + fprintf (dbg, "Attempting to include command '%s'\n", s); +#endif +#endif + + if (r->path_info && r->path_info[0] != '\0') + { + request_rec *pa_req; + + table_set (env, "PATH_INFO", escape_shell_cmd (r->pool, r->path_info)); + + pa_req = sub_req_lookup_uri(escape_uri(r->pool, r->path_info), r); + if (pa_req->filename) + table_set(env, "PATH_TRANSLATED", + pstrcat(r->pool, pa_req->filename, pa_req->path_info, + NULL)); + } + + if (r->args) { + table_set (env, "QUERY_STRING", r->args); + unescape_url (r->args); + table_set (env, "QUERY_STRING_UNESCAPED", + escape_shell_cmd (r->pool, r->args)); + } + + error_log2stderr (r->server); + +#ifdef DEBUG_INCLUDE_CMD + fprintf (dbg, "Attempting to exec '%s'\n", s); +#endif + cleanup_for_exec(); + /* set shellcmd flag to pass arg to SHELL_PATH */ + call_exec(r, s, create_environment (r->pool, env), 1); + + /* Oh, drat. We're still here. The log file descriptors are closed, + * so we have to whimper a complaint onto stderr... + */ + +#ifdef DEBUG_INCLUDE_CMD + fprintf (dbg, "Exec failed\n"); +#endif + ap_snprintf(err_string, sizeof(err_string), + "httpd: exec of %s failed, errno is %d\n", + SHELL_PATH,errno); + write (2, err_string, strlen(err_string)); + exit(0); +} + +int include_cmd(char *s, request_rec *r) { + include_cmd_arg arg; + FILE *f; + + arg.r = r; arg.s = s; + + if (!spawn_child (r->pool, include_cmd_child, &arg, + kill_after_timeout, NULL, &f)) + return -1; + + send_fd(f,r); + pfclose(r->pool, f); /* will wait for zombie when + * r->pool is cleared + */ + return 0; +} + + +int handle_exec(FILE *in, request_rec *r, char *error) +{ + char tag[MAX_STRING_LEN]; + char *tag_val; + char *file = r->filename; + char parsed_string[MAX_STRING_LEN]; + + while(1) { + if(!(tag_val = get_tag (r->pool, in, tag, MAX_STRING_LEN, 1))) + return 1; + if(!strcmp(tag,"cmd")) { + parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 1); + if(include_cmd(parsed_string, r) == -1) { + log_printf(r->server, "unknown parameter %s to tag include in %s", + tag, r->filename); + rputs(error, r); + } + /* just in case some stooge changed directories */ + chdir_file(r->filename); + } + else if(!strcmp(tag,"cgi")) { + parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0); + if(include_cgi(parsed_string, r) == -1) { + log_printf(r->server, "invalid CGI ref %s in %s",tag_val,file); + rputs(error, r); + } + /* grumble groan */ + chdir_file(r->filename); + } + else if(!strcmp(tag,"done")) + return 0; + else { + log_printf(r->server, "unknown parameter %s to tag exec in %s", + tag, file); + rputs(error, r); + } + } + +} + +int handle_echo (FILE *in, request_rec *r, char *error) { + char tag[MAX_STRING_LEN]; + char *tag_val; + + while(1) { + if(!(tag_val = get_tag (r->pool, in, tag, MAX_STRING_LEN, 1))) + return 1; + if(!strcmp(tag,"var")) { + char *val = table_get (r->subprocess_env, tag_val); + + if (val) rputs(val, r); + else rputs("(none)", r); + } else if(!strcmp(tag,"done")) + return 0; + else { + log_printf(r->server, "unknown parameter %s to tag echo in %s", + tag, r->filename); + rputs(error, r); + } + } +} +#ifdef USE_PERL_SSI +int handle_perl (FILE *in, request_rec *r, char *error) { + char tag[MAX_STRING_LEN]; + char *tag_val; + SV *sub = Nullsv; + AV *av = newAV(); + + if (!(allow_options (r) & OPT_INCLUDES)) { + log_printf(r->server, + "httpd: #perl SSI disallowed by IncludesNoExec in %s", r->filename); + return DECLINED; + } + while(1) { + if(!(tag_val = get_tag (r->pool, in, tag, MAX_STRING_LEN, 1))) + break; + if(strnEQ(tag, "sub", 3)) + sub = newSVpv(tag_val,0); + else if(strnEQ(tag, "arg", 3)) + av_push(av, newSVpv(tag_val,0)); + else if(strnEQ(tag,"done", 4)) + break; + } + perl_stdout2client(r); + perl_call_handler(sub, r, av); + return OK; +} +#endif + +/* error and tf must point to a string with room for at + * least MAX_STRING_LEN characters + */ +int handle_config(FILE *in, request_rec *r, char *error, char *tf, + int *sizefmt) { + char tag[MAX_STRING_LEN]; + char *tag_val; + char parsed_string[MAX_STRING_LEN]; + table *env = r->subprocess_env; + + while(1) { + if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 0))) + return 1; + if(!strcmp(tag,"errmsg")) { + parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0); + strncpy(error,parsed_string,MAX_STRING_LEN-1); + error[MAX_STRING_LEN-1] = '\0'; + } else if(!strcmp(tag,"timefmt")) { + time_t date = r->request_time; + parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0); + strncpy(tf,parsed_string,MAX_STRING_LEN-1); + tf[MAX_STRING_LEN-1] = '\0'; + table_set (env, "DATE_LOCAL", ht_time(r->pool,date,tf,0)); + table_set (env, "DATE_GMT", ht_time(r->pool,date,tf,1)); + table_set (env, "LAST_MODIFIED", ht_time(r->pool,r->finfo.st_mtime,tf,0)); + } + else if(!strcmp(tag,"sizefmt")) { + parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0); + decodehtml(parsed_string); + if(!strcmp(parsed_string,"bytes")) + *sizefmt = SIZEFMT_BYTES; + else if(!strcmp(parsed_string,"abbrev")) + *sizefmt = SIZEFMT_KMG; + } + else if(!strcmp(tag,"done")) + return 0; + else { + log_printf(r->server,"unknown parameter %s to tag config in %s", + tag, r->filename); + rputs(error, r); + } + } +} + + + +int find_file(request_rec *r, char *directive, char *tag, + char *tag_val, struct stat *finfo, char *error) +{ + char *dir = "./"; + char *to_send; + + if(!strcmp(tag,"file")) { + getparents(tag_val); /* get rid of any nasties */ + to_send = make_full_path (r->pool, dir, tag_val); + if(stat(to_send,finfo) == -1) { + log_printf(r->server, + "unable to get information about %s in parsed file %s", + to_send, r->filename); + rputs(error, r); + return -1; + } + return 0; + } + else if(!strcmp(tag,"virtual")) { + request_rec *rr = sub_req_lookup_uri (tag_val, r); + + if (rr->status == 200 && rr->finfo.st_mode != 0) { + memcpy ((char*)finfo, (const char *)&rr->finfo, sizeof (struct stat)); + destroy_sub_req (rr); + return 0; + } else { + log_printf(r->server, + "unable to get information about %s in parsed file %s", + tag_val, r->filename); + rputs(error, r); + destroy_sub_req (rr); + return -1; + } + } + else { + log_printf(r->server,"unknown parameter %s to tag %s in %s", + tag, directive, r->filename); + rputs(error, r); + return -1; + } +} + + +int handle_fsize(FILE *in, request_rec *r, char *error, int sizefmt) +{ + char tag[MAX_STRING_LEN]; + char *tag_val; + struct stat finfo; + char parsed_string[MAX_STRING_LEN]; + + while(1) { + if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1))) + return 1; + else if(!strcmp(tag,"done")) + return 0; + else { + parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0); + if(!find_file(r,"fsize",tag,parsed_string,&finfo,error)) { + if(sizefmt == SIZEFMT_KMG) { + send_size(finfo.st_size, r); + } + else { + int l,x; +#if defined(BSD) && BSD > 199305 + /* ap_snprintf can't handle %qd */ + sprintf(tag,"%qd", finfo.st_size); +#else + ap_snprintf(tag, sizeof(tag), "%ld",finfo.st_size); +#endif + l = strlen(tag); /* grrr */ + for(x=0;xpool, in, tag, MAX_STRING_LEN, 1))) + return 1; + else if(!strcmp(tag,"done")) + return 0; + else { + parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0); + if(!find_file(r,"flastmod",tag,parsed_string,&finfo,error)) + rputs(ht_time(r->pool, finfo.st_mtime, tf, 0), r); + } + } +} + +int re_check(request_rec *r, char *string, char *rexp) +{ + regex_t *compiled; + int regex_error; + + compiled = pregcomp (r->pool, rexp, REG_EXTENDED|REG_NOSUB); + if (compiled == NULL) { + log_printf(r->server, "unable to compile pattern %s", rexp); + return -1; + } + regex_error = regexec(compiled, string, 0, (regmatch_t *)NULL, 0); + pregfree (r->pool, compiled); + return(!regex_error); +} + +enum token_type { token_string, + token_and, token_or, token_not, token_eq, token_ne, + token_rbrace, token_lbrace, token_group +}; +struct token { + enum token_type type; + char value[MAX_STRING_LEN]; +}; + +char *get_ptoken(request_rec *r, char *string, struct token *token) { + char ch; + int next=0; + int qs=0; + + /* Skip leading white space */ + if (string == (char *)NULL) return (char *)NULL; + while ((ch = *string++)) + if (!isspace(ch)) break; + if (ch == '\0') return (char *)NULL; + + switch(ch) { + case '(': + token->type = token_lbrace; + return(string); + case ')': + token->type = token_rbrace; + return(string); + case '=': + token->type = token_eq; + return(string); + case '!': + if (*string == '=') { + token->type = token_ne; + return(string+1); + } else { + token->type = token_not; + return(string); + } + case '\'': + token->type = token_string; + qs = 1; + break; + case '|': + if (*string == '|') { + token->type = token_or; + return(string+1); + } + case '&': + if (*string == '&') { + token->type = token_and; + return(string+1); + } + default: + token->type = token_string; + break; + } + /* We should only be here if we are in a string */ + if (!qs) token->value[next++] = ch; + + /* + * Yes I know that goto's are BAD. But, c doesn't allow me to + * exit a loop from a switch statement. Yes, I could use a flag, + * but that is (IMHO) even less readable/maintainable than the goto. + */ + /* + * I used the ++string throughout this section so that string + * ends up pointing to the next token and I can just return it + */ + for (ch = *string; ch != '\0'; ch = *++string) { + if (ch == '\\') { + if ((ch = *++string) == '\0') goto TOKEN_DONE; + token->value[next++] = ch; + continue; + } + if (!qs) { + if (isspace(ch)) goto TOKEN_DONE; + switch(ch) { + case '(': goto TOKEN_DONE; + case ')': goto TOKEN_DONE; + case '=': goto TOKEN_DONE; + case '!': goto TOKEN_DONE; + case '|': if (*(string+1) == '|') goto TOKEN_DONE; + case '&': if (*(string+1) == '&') goto TOKEN_DONE; + } + token->value[next++] = ch; + } else { + if (ch == '\'') { qs=0; ++string; goto TOKEN_DONE; } + token->value[next++] = ch; + } + } +TOKEN_DONE: + /* If qs is still set, I have an unmatched ' */ + if (qs) { rputs("\nUnmatched '\n", r); next=0; } + token->value[next] = '\0'; + return(string); +} + + +/* + * Hey I still know that goto's are BAD. I don't think that I've ever + * used two in the same project, let alone the same file before. But, + * I absolutely want to make sure that I clean up the memory in all + * cases. And, without rewriting this completely, the easiest way + * is to just branch to the return code which cleans it up. + */ +int parse_expr(request_rec *r, char *expr, char *error) +{ + struct parse_node { + struct parse_node *left, *right, *parent; + struct token token; + int value, done; + } *root, *current, *new; + char *parse; + char buffer[MAX_STRING_LEN]; + struct pool *expr_pool; + int retval = 0; + + if ((parse = expr) == (char *)NULL) return(0); + root = current = (struct parse_node*)NULL; + if ((expr_pool = make_sub_pool(r->pool)) == (struct pool *)NULL) { + log_printf(r->server, "out of memory", r->filename); + rputs(error, r); + return(0); + } + + /* Create Parse Tree */ + while (1) { + new = (struct parse_node*)palloc(expr_pool, sizeof (struct parse_node)); + if (new == (struct parse_node*)NULL) { + log_printf(r->server,"out of memory", r->filename); + rputs(error, r); + goto RETURN; + } + new->parent = new->left = new->right = (struct parse_node*)NULL; + new->done = 0; + if ((parse = get_ptoken(r, parse, &new->token)) == (char *)NULL) + break; + switch(new->token.type) { + + case token_string: +#ifdef DEBUG_INCLUDE + rvputs(r," Token: string (", new->token.value, ")\n", NULL); +#endif + if (current == (struct parse_node*)NULL) { + root = current = new; + break; + } + switch(current->token.type) { + case token_string: + if (current->token.value[0] != '\0') + strncat(current->token.value, " ", + MAX_STRING_LEN-strlen(current->token.value)-1); + strncat(current->token.value, new->token.value, + MAX_STRING_LEN-strlen(current->token.value)-1); + break; + case token_eq: + case token_ne: + case token_and: + case token_or: + case token_lbrace: + case token_not: + new->parent = current; + current = current->right = new; + break; + default: + log_printf(r->server, + "Invalid expression %s", expr, r->filename); + rputs(error, r); + goto RETURN; + } + break; + + case token_and: + case token_or: +#ifdef DEBUG_INCLUDE +rputs (" Token: and/or\n", r); +#endif + if (current == (struct parse_node*)NULL) { + log_printf(r->server, + "Invalid expression %s", expr, r->filename); + rputs(error, r); + goto RETURN; + } + /* Percolate upwards */ + while (current != (struct parse_node *)NULL) { + switch(current->token.type) { + case token_string: + case token_group: + case token_not: + case token_eq: + case token_ne: + case token_and: + case token_or: + current = current->parent; + continue; + case token_lbrace: + break; + default: + log_printf(r->server, + "Invalid expression %s", expr, r->filename); + rputs(error, r); + goto RETURN; + } + break; + } + if (current == (struct parse_node*)NULL) { + new->left = root; + new->left->parent = new; + new->parent = (struct parse_node*)NULL; + root = new; + } else { + new->left = current->right; + current->right = new; + new->parent = current; + } + current = new; + break; + + case token_not: +#ifdef DEBUG_INCLUDE +rputs(" Token: not\n", r); +#endif + if (current == (struct parse_node*)NULL) { + root = current = new; + break; + } + /* Percolate upwards */ + while (current != (struct parse_node *)NULL) { + switch(current->token.type) { + case token_not: + case token_eq: + case token_ne: + case token_and: + case token_or: + case token_lbrace: + break; + default: + log_printf(r->server, + "Invalid expression %s", expr, r->filename); + rputs(error, r); + goto RETURN; + } + break; + } + if (current == (struct parse_node*)NULL) { + new->left = root; + new->left->parent = new; + new->parent = (struct parse_node*)NULL; + root = new; + } else { + new->left = current->right; + current->right = new; + new->parent = current; + } + current = new; + break; + + case token_eq: + case token_ne: +#ifdef DEBUG_INCLUDE +rputs(" Token: eq/ne\n", r); +#endif + if (current == (struct parse_node*)NULL) { + log_printf(r->server, + "Invalid expression %s", expr, r->filename); + rputs(error, r); + goto RETURN; + } + /* Percolate upwards */ + while (current != (struct parse_node *)NULL) { + switch(current->token.type) { + case token_string: + case token_group: + current = current->parent; + continue; + case token_lbrace: + case token_and: + case token_or: + break; + case token_not: + case token_eq: + case token_ne: + default: + log_printf(r->server, + "Invalid expression %s", expr, r->filename); + rputs(error, r); + goto RETURN; + } + break; + } + if (current == (struct parse_node*)NULL) { + new->left = root; + new->left->parent = new; + new->parent = (struct parse_node*)NULL; + root = new; + } else { + new->left = current->right; + current->right = new; + new->parent = current; + } + current = new; + break; + + case token_rbrace: +#ifdef DEBUG_INCLUDE +rputs(" Token: rbrace\n", r); +#endif + while (current != (struct parse_node*)NULL) { + if (current->token.type == token_lbrace) { + current->token.type = token_group; + break; + } + current = current->parent; + } + if (current == (struct parse_node*)NULL) { + log_printf(r->server,"Unmatched ')'in %s\n", expr, r->filename); + rputs(error, r); + goto RETURN; + } + break; + + case token_lbrace: +#ifdef DEBUG_INCLUDE +rputs(" Token: lbrace\n", r); +#endif + if (current == (struct parse_node*)NULL) { + root = current = new; + break; + } + /* Percolate upwards */ + while (current != (struct parse_node *)NULL) { + switch(current->token.type) { + case token_not: + case token_eq: + case token_ne: + case token_and: + case token_or: + case token_lbrace: + break; + case token_string: + case token_group: + default: + log_printf(r->server, + "Invalid expression %s", expr, r->filename); + rputs(error, r); + goto RETURN; + } + break; + } + if (current == (struct parse_node*)NULL) { + new->left = root; + new->left->parent = new; + new->parent = (struct parse_node*)NULL; + root = new; + } else { + new->left = current->right; + current->right = new; + new->parent = current; + } + current = new; + break; + default: + break; + } + } + + /* Evaluate Parse Tree */ + current = root; + while (current != (struct parse_node *)NULL) { + switch(current->token.type) { + case token_string: +#ifdef DEBUG_INCLUDE +rputs(" Evaluate string\n", r); +#endif + parse_string(r, current->token.value, buffer, MAX_STRING_LEN, 0); + strncpy(current->token.value, buffer, MAX_STRING_LEN-1); + current->token.value[MAX_STRING_LEN-1] = '\0'; + current->value = (current->token.value[0] != '\0'); + current->done = 1; + current = current->parent; + break; + + case token_and: + case token_or: +#ifdef DEBUG_INCLUDE +rputs(" Evaluate and/or\n", r); +#endif + if (current->left == (struct parse_node*)NULL || + current->right == (struct parse_node*)NULL) { + log_printf(r->server, + "Invalid expression %s", expr, r->filename); + rputs(error, r); + goto RETURN; + } + if (!current->left->done) { + switch(current->left->token.type) { + case token_string: + parse_string(r, current->left->token.value, + buffer, MAX_STRING_LEN, 0); + strncpy(current->left->token.value, buffer, + MAX_STRING_LEN-1); + current->left->token.value[MAX_STRING_LEN-1] = '\0'; + current->left->done = 1; + break; + default: + current = current->left; + continue; + } + } + if (!current->right->done) { + switch(current->right->token.type) { + case token_string: + parse_string(r, current->right->token.value, + buffer, MAX_STRING_LEN, 0); + strncpy(current->right->token.value, buffer, + MAX_STRING_LEN-1); + current->right->token.value[MAX_STRING_LEN-1] = '\0'; + current->right->done = 1; + break; + default: + current = current->right; + continue; + } + } +#ifdef DEBUG_INCLUDE +rvputs(r," Left: ", current->left->value ? "1" : "0", "\n", NULL); +rvputs(r," Right: ", current->right->value ? "1" : "0", "\n", NULL); +#endif + if (current->token.type == token_and) + current->value = + current->left->value && current->right->value; + else + current->value = + current->left->value || current->right->value; +#ifdef DEBUG_INCLUDE +rvputs(r," Returning ", current->value ? "1" : "0", "\n", NULL); +#endif + current->done = 1; + current = current->parent; + break; + + case token_eq: + case token_ne: +#ifdef DEBUG_INCLUDE +rputs(" Evaluate eq/ne\n", r); +#endif + if ((current->left == (struct parse_node*)NULL) || + (current->right == (struct parse_node*)NULL) || + (current->left->token.type != token_string) || + (current->right->token.type != token_string)) { + log_printf(r->server, + "Invalid expression %s", expr, r->filename); + rputs(error, r); + goto RETURN; + } + parse_string(r, current->left->token.value, + buffer, MAX_STRING_LEN, 0); + strncpy(current->left->token.value, buffer, MAX_STRING_LEN-1); + current->left->token.value[MAX_STRING_LEN-1] = '\0'; + parse_string(r, current->right->token.value, + buffer, MAX_STRING_LEN, 0); + strncpy(current->right->token.value, buffer, MAX_STRING_LEN-1); + current->right->token.value[MAX_STRING_LEN-1] = '\0'; + if (current->right->token.value[0] == '/') { + int len; + len = strlen(current->right->token.value); + if (current->right->token.value[len-1] == '/') { + current->right->token.value[len-1] = '\0'; + } else { + log_printf(r->server,"Invalid rexp %s", + current->right->token.value, r->filename); + rputs(error, r); + goto RETURN; + } +#ifdef DEBUG_INCLUDE +rvputs(r," Re Compare (", current->left->token.value, + ") with /", ¤t->right->token.value[1], "/\n", NULL); +#endif + current->value = + re_check(r, current->left->token.value, + ¤t->right->token.value[1]); + } else { +#ifdef DEBUG_INCLUDE +rvputs(r," Compare (", current->left->token.value, + ") with (", current->right->token.value, ")\n", NULL); +#endif + current->value = + (strcmp(current->left->token.value, + current->right->token.value) == 0); + } + if (current->token.type == token_ne) + current->value = !current->value; +#ifdef DEBUG_INCLUDE +rvputs(r," Returning ", current->value ? "1" : "0", "\n", NULL); +#endif + current->done = 1; + current = current->parent; + break; + + case token_not: + if (current->right != (struct parse_node *)NULL) { + if (!current->right->done) { + current = current->right; + continue; + } + current->value = !current->right->value; + } else { + current->value = 0; + } +#ifdef DEBUG_INCLUDE +rvputs(r," Evaluate !: ", current->value ? "1" : "0", "\n", NULL); +#endif + current->done = 1; + current = current->parent; + break; + + case token_group: + if (current->right != (struct parse_node *)NULL) { + if (!current->right->done) { + current = current->right; + continue; + } + current->value = current->right->value; + } else { + current->value = 1; + } +#ifdef DEBUG_INCLUDE +rvputs(r," Evaluate (): ", current->value ? "1" : "0", "\n", NULL); +#endif + current->done = 1; + current = current->parent; + break; + + case token_lbrace: + log_printf(r->server,"Unmatched '(' in %s\n", expr, r->filename); + rputs(error, r); + goto RETURN; + + case token_rbrace: + log_printf(r->server,"Unmatched ')' in %s\n", expr, r->filename); + rputs(error, r); + goto RETURN; + + default: + log_printf(r->server,"bad token type"); + rputs(error, r); + goto RETURN; + } + } + + retval = (root == (struct parse_node *)NULL) ? 0 : root->value; +RETURN: + destroy_pool(expr_pool); + return (retval); +} + +int handle_if(FILE *in, request_rec *r, char *error, + int *conditional_status, int *printing) +{ + char tag[MAX_STRING_LEN]; + char *tag_val = '\0'; + char *expr = '\0'; + + while(1) { + tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 0); + if(*tag == '\0') + return 1; + else if(!strcmp(tag,"done")) { + *printing = *conditional_status = parse_expr(r, expr, error); +#ifdef DEBUG_INCLUDE +rvputs(r,"**** if conditional_status=\"", *conditional_status ? "1" : "0", "\"\n", NULL); +#endif + return 0; + } else if(!strcmp(tag,"expr")) { + expr = tag_val; +#ifdef DEBUG_INCLUDE +rvputs(r,"**** if expr=\"", expr, "\"\n", NULL); +#endif + } else { + log_printf(r->server,"unknown parameter %s to tag if in %s", + tag, r->filename); + rputs(error, r); + } + } +} + +int handle_elif(FILE *in, request_rec *r, char *error, + int *conditional_status, int *printing) +{ + char tag[MAX_STRING_LEN]; + char *tag_val = '\0'; + char *expr = '\0'; + + while(1) { + tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 0); + if(*tag == '\0') + return 1; + else if(!strcmp(tag,"done")) { +#ifdef DEBUG_INCLUDE +rvputs(r,"**** elif conditional_status=\"", *conditional_status ? "1" : "0", "\"\n", NULL); +#endif + if (*conditional_status) { + *printing = 0; + return(0); + } + *printing = *conditional_status = parse_expr(r, expr, error); +#ifdef DEBUG_INCLUDE +rvputs(r,"**** elif conditional_status=\"", *conditional_status ? "1" : "0", "\"\n", NULL); +#endif + return 0; + } else if(!strcmp(tag,"expr")) { + expr = tag_val; +#ifdef DEBUG_INCLUDE +rvputs(r,"**** if expr=\"", expr, "\"\n", NULL); +#endif + } else { + log_printf(r->server,"unknown parameter %s to tag if in %s", + tag, r->filename); + rputs(error, r); + } + } +} + +int handle_else(FILE *in, request_rec *r, char *error, + int *conditional_status, int *printing) +{ + char tag[MAX_STRING_LEN]; + char *tag_val; + + if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1))) + return 1; + else if(!strcmp(tag,"done")) { +#ifdef DEBUG_INCLUDE +rvputs(r,"**** else conditional_status=\"", *conditional_status ? "1" : "0", "\"\n", NULL); +#endif + *printing = !(*conditional_status); + *conditional_status = 1; + return 0; + } else { + log_printf(r->server, "else directive does not take tags"); + if (*printing) rputs(error, r); + return -1; + } +} + +int handle_endif(FILE *in, request_rec *r, char *error, + int *conditional_status, int *printing) +{ + char tag[MAX_STRING_LEN]; + char *tag_val; + + if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1))) { + return 1; + } else if(!strcmp(tag,"done")) { +#ifdef DEBUG_INCLUDE +rvputs(r,"**** endif conditional_status=\"", *conditional_status ? "1" : "0", "\"\n", NULL); +#endif + *conditional_status = 1; + return 0; + } else { + log_printf(r->server, "endif directive does not take tags"); + rputs(error, r); + return -1; + } +} + +int handle_set(FILE *in, request_rec *r, char *error) +{ + char tag[MAX_STRING_LEN]; + char parsed_string[MAX_STRING_LEN]; + char *tag_val; + char *var; + + var = (char *)NULL; + while (1) { + if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1))) + return 1; + else if(!strcmp(tag,"done")) + return 0; + else if (!strcmp(tag,"var")) { + var = tag_val; + } else if (!strcmp(tag,"value")) { + if (var == (char *)NULL) { + log_printf(r->server, + "variable must precede value in set directive"); + rputs(error, r); + return -1; + } + parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0); + table_set (r->subprocess_env, var, parsed_string); + } + } +} + +int handle_printenv(FILE *in, request_rec *r, char *error) +{ + char tag[MAX_STRING_LEN]; + char *tag_val; + table_entry *elts = (table_entry *) r->subprocess_env->elts; + int i; + + if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1))) + return 1; + else if(!strcmp(tag,"done")) { + for (i = 0; i < r->subprocess_env->nelts; ++i) + rvputs(r, elts[i].key, "=", elts[i].val, "\n", NULL); + return 0; + } else { + log_printf(r->server, "printenv directive does not take tags"); + rputs(error, r); + return -1; + } +} + + + +/* -------------------------- The main function --------------------------- */ + +/* This is a stub which parses a file descriptor. */ + +void send_parsed_content(FILE *f, request_rec *r) +{ + char directive[MAX_STRING_LEN], error[MAX_STRING_LEN]; + char timefmt[MAX_STRING_LEN]; + int noexec = allow_options (r) & OPT_INCNOEXEC; + int ret, sizefmt; + int if_nesting; + int printing; + int conditional_status; + + strncpy(error,DEFAULT_ERROR_MSG, sizeof(error)-1); + error[sizeof(error)-1] = '\0'; + strncpy(timefmt,DEFAULT_TIME_FORMAT, sizeof(timefmt)-1); + timefmt[sizeof(timefmt)-1] = '\0'; + sizefmt = SIZEFMT_KMG; + +/* Turn printing on */ + printing = conditional_status = 1; + if_nesting = 0; + + chdir_file (r->filename); + if (r->args) { /* add QUERY stuff to env cause it ain't yet */ + table_set (r->subprocess_env, "QUERY_STRING", r->args); + unescape_url (r->args); + table_set (r->subprocess_env, "QUERY_STRING_UNESCAPED", + escape_shell_cmd (r->pool, r->args)); + } + + while(1) { + if(!find_string(f,STARTING_SEQUENCE,r,printing)) { + if(get_directive(f,directive,r->pool)) + return; + if(!strcmp(directive,"if")) { + if (!printing) { + if_nesting++; + } else { + ret=handle_if(f, r, error, &conditional_status, &printing); + if_nesting = 0; + } + continue; + } else if(!strcmp(directive,"else")) { + if (!if_nesting) + ret=handle_else(f, r, error, &conditional_status, &printing); + continue; + } else if(!strcmp(directive,"elif")) { + if (!if_nesting) + ret = handle_elif(f, r, error, &conditional_status, &printing); + continue; + } else if(!strcmp(directive,"endif")) { + if (!if_nesting) { + ret=handle_else(f, r, error, &conditional_status, &printing); + printing = 1; + } else { + if_nesting--; + } + continue; + } + if (!printing) continue; + if(!strcmp(directive,"exec")) { + if(noexec) { + log_printf(r->server,"httpd: exec used but not allowed in %s", + r->filename); + if (printing) rputs(error, r); + ret = find_string(f,ENDING_SEQUENCE,r,0); + } else + ret=handle_exec(f, r, error); + } else if(!strcmp(directive,"config")) + ret=handle_config(f, r, error, timefmt, &sizefmt); + else if(!strcmp(directive,"set")) + ret=handle_set(f, r, error); + else if(!strcmp(directive,"include")) + ret=handle_include(f, r, error, noexec); + else if(!strcmp(directive,"echo")) + ret=handle_echo(f, r, error); + else if(!strcmp(directive,"fsize")) + ret=handle_fsize(f, r, error, sizefmt); + else if(!strcmp(directive,"flastmod")) + ret=handle_flastmod(f, r, error, timefmt); + else if(!strcmp(directive,"printenv")) + ret=handle_printenv(f, r, error); +#ifdef USE_PERL_SSI + else if(!strcmp(directive,"perl")) + ret=handle_perl(f, r, error); +#endif + else { + log_printf(r->server, + "httpd: unknown directive %s in parsed doc %s", + directive,r->filename); + if (printing) rputs(error, r); + ret=find_string(f,ENDING_SEQUENCE,r,0); + } + if(ret) { + log_printf(r->server,"httpd: premature EOF in parsed file %s", + r->filename); + return; + } + } else + return; + } +} + +/***************************************************************** + * + * XBITHACK. Sigh... NB it's configurable per-directory; the compile-time + * option only changes the default. + */ + +module includes_module; +enum xbithack { xbithack_off, xbithack_on, xbithack_full }; + +#ifdef XBITHACK +#define DEFAULT_XBITHACK xbithack_full +#else +#define DEFAULT_XBITHACK xbithack_off +#endif + +void *create_includes_dir_config (pool *p, char *dummy) +{ + enum xbithack *result = (enum xbithack*)palloc(p, sizeof (enum xbithack)); + *result = DEFAULT_XBITHACK; + return result; +} + +const char *set_xbithack (cmd_parms *cmd, void *xbp, char *arg) +{ + enum xbithack *state = (enum xbithack *)xbp; + + if (!strcasecmp (arg, "off")) *state = xbithack_off; + else if (!strcasecmp (arg, "on")) *state = xbithack_on; + else if (!strcasecmp (arg, "full")) *state = xbithack_full; + else return "XBitHack must be set to Off, On, or Full"; + + return NULL; +} + +int send_parsed_file(request_rec *r) +{ + FILE *f; + enum xbithack *state = + (enum xbithack *)get_module_config(r->per_dir_config,&includes_module); + int errstatus; + + if (!(allow_options (r) & OPT_INCLUDES)) return DECLINED; + if (r->method_number != M_GET) return DECLINED; + if (r->finfo.st_mode == 0) { + log_reason("File does not exist", + r->path_info ? pstrcat(r->pool, r->filename, r->path_info, NULL) + : r->filename, r); + return NOT_FOUND; + } + + if(!(f=pfopen(r->pool, r->filename, "r"))) { + log_reason("file permissions deny server access", r->filename, r); + return FORBIDDEN; + } + + if (*state == xbithack_full +#ifndef __EMX__ + /* OS/2 dosen't support Groups. */ + && (r->finfo.st_mode & S_IXGRP) +#endif + && (errstatus = set_last_modified (r, r->finfo.st_mtime))) + return errstatus; + + send_http_header(r); + + if (r->header_only) { + pfclose (r->pool, f); + return OK; + } + + if (r->main) { + /* Kludge --- for nested includes, we want to keep the + * subprocess environment of the base document (for compatibility); + * that means torquing our own last_modified date as well so that + * the LAST_MODIFIED variable gets reset to the proper value if + * the nested document resets + */ + r->subprocess_env = r->main->subprocess_env; + r->finfo.st_mtime= r->main->finfo.st_mtime; + } else { + add_common_vars (r); + add_cgi_vars(r); + add_include_vars (r, DEFAULT_TIME_FORMAT); + } + hard_timeout("send SSI", r); + + send_parsed_content (f, r); + + kill_timeout (r); + return OK; +} + +int send_shtml_file (request_rec *r) +{ + r->content_type = "text/html"; + return send_parsed_file(r); +} + +int xbithack_handler (request_rec *r) +{ + enum xbithack *state; + +#ifdef __EMX__ + /* OS/2 dosen't currently support the xbithack. This is being worked on. */ + return DECLINED; +#else + if (!(r->finfo.st_mode & S_IXUSR)) return DECLINED; + + state = (enum xbithack *)get_module_config(r->per_dir_config, + &includes_module); + + if (*state == xbithack_off) return DECLINED; + return send_parsed_file (r); +#endif +} + +command_rec includes_cmds[] = { +{ "XBitHack", set_xbithack, NULL, OR_OPTIONS, TAKE1, "Off, On, or Full" }, +{ NULL } +}; + +handler_rec includes_handlers[] = { +{ INCLUDES_MAGIC_TYPE, send_shtml_file }, +{ INCLUDES_MAGIC_TYPE3, send_shtml_file }, +{ "server-parsed", send_parsed_file }, +{ "text/html", xbithack_handler }, +{ NULL } +}; + +module includes_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + create_includes_dir_config, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + NULL, /* server config */ + NULL, /* merge server config */ + includes_cmds, /* command table */ + includes_handlers, /* handlers */ + NULL, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_info.c b/APACHE_1_2_X/src/modules/standard/mod_info.c new file mode 100644 index 00000000000..1525dc7c888 --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_info.c @@ -0,0 +1,446 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * Info Module. Display configuration information for the server and + * all included modules. + * + * + * SetHandler server-info + * + * + * GET /server-info - Returns full configuration page for server and all modules + * GET /server-info?server - Returns server configuration only + * GET /server-info?module_name - Returns configuration for a single module + * GET /server-info?list - Returns quick list of included modules + * + * Rasmus Lerdorf , May 1996 + * + * 05.01.96 Initial Version + * + */ + +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_log.h" +#include "http_main.h" +#include "http_protocol.h" +#include "util_script.h" + +typedef struct mod_info_config_lines { + char *cmd; + char *line; + struct mod_info_config_lines *next; +} mod_info_config_lines; + +module info_module; +extern module *top_module; + +char *mod_info_html_cmd_string(char *string) { + char *s,*t; + static char ret[256]; /* What is the max size of a command? */ + char *end_ret; + + ret[0]='\0'; + s = string; + t=ret; + end_ret = t + sizeof(ret); + while((*s) && ((t-ret) < sizeof(ret))) { + if(*s=='<') { + strncpy(t,"<", end_ret - t); + t+=4; + } else if(*s=='>') { + strncpy(t,">", end_ret - t); + t+=4; + } else if(*s=='&') { + strncpy(t,"&", end_ret - t); + t+=5; + } else { + *t++=*s; + } + s++; + } + *t='\0'; + return(ret); +} + +mod_info_config_lines *mod_info_load_config(pool *p, char *filename, request_rec *r) { + char s[MAX_STRING_LEN]; + FILE *fp; + mod_info_config_lines *new, *ret=NULL, *prev=NULL; + char *t,*tt,o, *msg; + + fp = pfopen(p,filename,"r"); + if(!fp) { + msg = pstrcat + ( + r->pool, + "mod_info: couldn't open config file ", + filename, + NULL + ); + log_error (msg, r->server); + return NULL; + } + while(!cfg_getline(s,MAX_STRING_LEN,fp)) { + if(*s=='#') continue; /* skip comments */ + new = palloc(p,sizeof(struct mod_info_config_lines)); + new->next = NULL; + if(!ret) ret=new; + if(prev) prev->next=new; + t=strchr(s,' '); + tt=strchr(s,'\t'); + if(t && tt) t = (tcmd = pstrdup(p,s); + new->line = pstrdup(p,t+1); + *t=o; + } else { + new->cmd = pstrdup(p,s); + new->line = NULL; + } + prev=new; + } + pfclose(p,fp); + return(ret); +} + +void mod_info_module_cmds(request_rec *r, mod_info_config_lines *cfg, command_rec *cmds,char *label) { + command_rec *cmd=cmds; + mod_info_config_lines *li=cfg,*li_st=NULL,*li_se=NULL,*block_start=NULL; + int lab=0, nest=0; + + while(li) { + if(!strncasecmp(li->cmd,"cmd,"cmd,"next; + nest++; + continue; + } else if(nest && (!strncasecmp(li->cmd,"cmd,"cmd,"",r); + if(nest==2) rputs("  ",r); + rputs(mod_info_html_cmd_string(li->cmd),r); + rputs(" ",r); + if(li->line) rputs(mod_info_html_cmd_string(li->line),r); + rputs("\n",r); + nest--; + if(!nest) { + block_start=NULL; + li_st=NULL; + } else { + block_start=li_st; + } + li_se=NULL; + } else { + nest--; + if(!nest) { + li_st=NULL; + } + li_se=NULL; + } + } else { + nest--; + if(!nest) { + li_st=NULL; + } + li_se=NULL; + } + li=li->next; + continue; + } + cmd = cmds; + while(cmd) { + if(cmd->name) { + if(!strcasecmp(cmd->name,li->cmd)) { + if(!lab) { + rputs("
    ",r); + rputs(label,r); + rputs("\n",r); + lab=1; + } + if(((nest && block_start==NULL) || (nest==2 && block_start==li_st)) + && (strncasecmp(li->cmd,"cmd,"cmd,"cmd,"cmd,"cmd,"",r); + rputs(mod_info_html_cmd_string(li_st->cmd),r); + rputs(" ",r); + if(li_st->line) rputs(mod_info_html_cmd_string(li_st->line),r); + rputs("\n",r); + block_start=li_st; + if(li_se) { + rputs("
      ",r); + rputs(mod_info_html_cmd_string(li_se->cmd),r); + rputs(" ",r); + if(li_se->line) rputs(mod_info_html_cmd_string(li_se->line),r); + rputs("\n",r); + block_start=li_se; + } + } + rputs("
    ",r); + if(nest) rputs("  ",r); + if(nest==2) rputs("  ",r); + rputs(mod_info_html_cmd_string(li->cmd),r); + if(li->line) { + rputs(" ",r); + rputs(mod_info_html_cmd_string(li->line),r); + rputs("",r); + } + } + } else break; + cmd++; + } + li = li->next; + } +} + +int display_info(request_rec *r) { + module *modp = NULL; + char buf[512], *cfname; + command_rec *cmd=NULL; + handler_rec *hand=NULL; + server_rec *serv = r->server; + int comma=0; + mod_info_config_lines *mod_info_cfg_httpd=NULL; + mod_info_config_lines *mod_info_cfg_srm=NULL; + mod_info_config_lines *mod_info_cfg_access=NULL; + extern int standalone; + extern uid_t user_id; + extern char *user_name; + extern gid_t group_id; + extern int max_requests_per_child; + extern char *pid_fname; + extern char *scoreboard_fname; + extern int daemons_to_start; + extern int daemons_min_free; + extern int daemons_max_free; + extern int daemons_limit; + extern char server_root[MAX_STRING_LEN]; + extern char server_confname[MAX_STRING_LEN]; + + r->content_type = "text/html"; + send_http_header(r); + if(r->header_only) { + return 0; + } + hard_timeout("send server info", r); + + rputs("Server Information\n",r); + rputs("

    Apache Server Information

    \n",r); + if(!r->args || strcasecmp(r->args,"list")) { + cfname = server_root_relative (r->pool, server_confname); + mod_info_cfg_httpd = mod_info_load_config (r->pool, cfname, r); + cfname = server_root_relative (r->pool, serv->srm_confname); + mod_info_cfg_srm = mod_info_load_config(r->pool, cfname, r); + cfname = server_root_relative (r->pool, serv->access_confname); + mod_info_cfg_access = mod_info_load_config (r->pool, cfname, r); + if(!r->args) { + rputs("Server Settings, ",r); + for(modp = top_module; modp; modp = modp->next) { + ap_snprintf(buf, sizeof(buf), "%s",modp->name,modp->name); + rputs(buf, r); + if(modp->next) rputs(", ",r); + } + rputs("
    ",r); + + } + if(!r->args || !strcasecmp(r->args,"server")) { + ap_snprintf(buf, sizeof(buf), "Server Version: %s
    \n",SERVER_VERSION); + rputs(buf,r); + ap_snprintf(buf, sizeof(buf), "API Version: %d
    \n",MODULE_MAGIC_NUMBER); + rputs(buf,r); + ap_snprintf(buf, sizeof(buf), "Run Mode: %s
    \n",standalone?"standalone":"inetd"); + rputs(buf,r); + ap_snprintf(buf, sizeof(buf), "User/Group: %s(%d)/%d
    \n",user_name,(int)user_id,(int)group_id); + rputs(buf,r); + ap_snprintf(buf, sizeof(buf), "Hostname/port: %s:%u
    \n",serv->server_hostname,serv->port); + rputs(buf,r); + ap_snprintf(buf, sizeof(buf), "Daemons: start: %d    min idle: %d    max idle: %d    max: %d
    \n",daemons_to_start,daemons_min_free,daemons_max_free,daemons_limit); + rputs(buf,r); + ap_snprintf(buf, sizeof(buf), "Max Requests: per child: %d    keep alive: %s    max per connection: %d
    \n",max_requests_per_child,serv->keep_alive ? "on":"off", serv->keep_alive_max); + rputs(buf,r); + ap_snprintf(buf, sizeof(buf), "Timeouts: connection: %d    keep-alive: %d
    ",serv->timeout,serv->keep_alive_timeout); + rputs(buf,r); + ap_snprintf(buf, sizeof(buf), "Server Root: %s
    \n",server_root); + rputs(buf,r); + ap_snprintf(buf, sizeof(buf), "Config File: %s
    \n",server_confname); + rputs(buf,r); + ap_snprintf(buf, sizeof(buf), "PID File: %s
    \n",pid_fname); + rputs(buf,r); + ap_snprintf(buf, sizeof(buf), "Scoreboard File: %s
    \n",scoreboard_fname); + rputs(buf,r); + } + rputs("
    ",r); + for(modp = top_module; modp; modp = modp->next) { + if(!r->args || !strcasecmp(modp->name,r->args)) { + ap_snprintf(buf, sizeof(buf), "
    Module Name: %s\n",modp->name,modp->name); + rputs(buf,r); + rputs("
    Content-types affected:",r); + hand = modp->handlers; + if(hand) { + while(hand) { + if(hand->content_type) { + ap_snprintf(buf, sizeof(buf), " %s\n",hand->content_type); + rputs(buf,r); + } else break; + hand++; + if(hand && hand->content_type) rputs(",",r); + } + } else { + rputs(" none",r); + } + rputs("
    Module Groups: \n",r); + if(modp->translate_handler) { + rputs("Translate Handler\n",r); + comma=1; + } + if(modp->check_user_id) { + if(comma) rputs(", ",r); + rputs("User ID Checking\n",r); + comma=1; + } + if(modp->auth_checker) { + if(comma) rputs(", ",r); + rputs("Authentication Checking\n",r); + comma=1; + } + if(modp->access_checker) { + if(comma) rputs(", ",r); + rputs("Access Checking\n",r); + comma=1; + } + if(modp->type_checker) { + if(comma) rputs(", ",r); + rputs("Type Checking\n",r); + comma=1; + } + if(modp->fixer_upper) { + if(comma) rputs(", ",r); + rputs("Header Fixer\n",r); + comma=1; + } + if(modp->logger) { + if(comma) rputs(", ",r); + rputs("Logging\n",r); + comma=1; + } + if(!comma) rputs(" none",r); + comma=0; + rputs("
    Module Configuration Commands: ",r); + cmd = modp->cmds; + if(cmd) { + while(cmd) { + if(cmd->name) { + ap_snprintf(buf, sizeof(buf), "
    %s - ",mod_info_html_cmd_string(cmd->name)); + rputs(buf,r); + if(cmd->errmsg) rputs(cmd->errmsg,r); + rputs("\n",r); + } else break; + cmd++; + } + rputs("
    Current Configuration:\n",r); + mod_info_module_cmds(r,mod_info_cfg_httpd,modp->cmds,"httpd.conf"); + mod_info_module_cmds(r,mod_info_cfg_srm,modp->cmds,"srm.conf"); + mod_info_module_cmds(r,mod_info_cfg_access,modp->cmds,"access.conf"); + } else { + rputs(" none\n",r); + } + rputs("

    \n",r); + if(r->args) break; + } + } + if(!modp && r->args && strcasecmp(r->args,"server")) rputs("No such module\n",r); + } else { + for(modp = top_module; modp; modp = modp->next) { + rputs(modp->name,r); + if(modp->next) rputs("
    ",r); + } + } + rputs("
    \n",r); + /* Done, turn off timeout, close file and return */ + kill_timeout(r); + return 0; +} + +handler_rec info_handlers[] = { + { "server-info", display_info }, + { NULL } +}; + +module info_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + NULL, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + NULL, /* server config */ + NULL, /* merge server config */ + NULL, /* command table */ + info_handlers, /* handlers */ + NULL, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_log_agent.c b/APACHE_1_2_X/src/modules/standard/mod_log_agent.c new file mode 100644 index 00000000000..234de33ab24 --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_log_agent.c @@ -0,0 +1,198 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + + +#include "httpd.h" +#include "http_config.h" + +module agent_log_module; + +static int xfer_flags = ( O_WRONLY | O_APPEND | O_CREAT ); +#ifdef __EMX__ +/* OS/2 dosen't support users and groups */ +static mode_t xfer_mode = ( S_IREAD | S_IWRITE ); +#else +static mode_t xfer_mode = ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ); +#endif + +typedef struct { + char *fname; + int agent_fd; +} agent_log_state; + +void *make_agent_log_state (pool *p, server_rec *s) +{ + agent_log_state *cls = + (agent_log_state *)palloc (p, sizeof (agent_log_state)); + + cls->fname = ""; + cls->agent_fd = -1; + + + return (void *)cls; +} + +const char *set_agent_log (cmd_parms *parms, void *dummy, char *arg) +{ + agent_log_state *cls = get_module_config (parms->server->module_config, + &agent_log_module); + + cls->fname = arg; + return NULL; +} + +command_rec agent_log_cmds[] = { +{ "AgentLog", set_agent_log, NULL, RSRC_CONF, TAKE1, + "the filename of the agent log" }, +{ NULL } +}; + +void agent_log_child (void *cmd) +{ + /* Child process code for 'AgentLog "|..."'; + * may want a common framework for this, since I expect it will + * be common for other foo-loggers to want this sort of thing... + */ + + cleanup_for_exec(); + signal (SIGHUP, SIG_IGN); +#ifdef __EMX__ + /* For OS/2 we need to use a '/' */ + execl (SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); +#else + execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL); +#endif + perror ("exec"); + fprintf (stderr, "Exec of shell for logging failed!!!\n"); + exit (1); +} + +void open_agent_log (server_rec *s, pool *p) +{ + agent_log_state *cls = get_module_config (s->module_config, + &agent_log_module); + + char *fname = server_root_relative (p, cls->fname); + + if (cls->agent_fd > 0) return; /* virtual log shared w/main server */ + + if (*cls->fname == '|') { + FILE *dummy; + + if (!spawn_child (p, agent_log_child, (void *)(cls->fname+1), + kill_after_timeout, &dummy, NULL)) { + perror ("spawn_child"); + fprintf (stderr, "Couldn't fork child for AgentLog process\n"); + exit (1); + } + + cls->agent_fd = fileno (dummy); + } + else if(*cls->fname != '\0') { + if((cls->agent_fd = popenf(p, fname, xfer_flags, xfer_mode)) < 0) { + perror("open"); + fprintf(stderr,"httpd: could not open agent log file %s.\n", fname); + exit(1); + } + } +} + +void init_agent_log (server_rec *s, pool *p) +{ + for (; s; s = s->next) open_agent_log (s, p); +} + +int agent_log_transaction(request_rec *orig) +{ + agent_log_state *cls = get_module_config (orig->server->module_config, + &agent_log_module); + + char str[HUGE_STRING_LEN]; + char *agent; + request_rec *r; + + if(cls->agent_fd <0) + return OK; + + for (r = orig; r->next; r = r->next) + continue; + if (*cls->fname == '\0') /* Don't log agent */ + return DECLINED; + + agent = table_get(orig->headers_in, "User-Agent"); + if(agent != NULL) + { + ap_snprintf(str, sizeof(str), "%s\n", agent); + write(cls->agent_fd, str, strlen(str)); + } + + return OK; +} + +module agent_log_module = { + STANDARD_MODULE_STUFF, + init_agent_log, /* initializer */ + NULL, /* create per-dir config */ + NULL, /* merge per-dir config */ + make_agent_log_state, /* server config */ + NULL, /* merge server config */ + agent_log_cmds, /* command table */ + NULL, /* handlers */ + NULL, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* fixups */ + agent_log_transaction, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_log_config.c b/APACHE_1_2_X/src/modules/standard/mod_log_config.c new file mode 100644 index 00000000000..d383cd5f6bc --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_log_config.c @@ -0,0 +1,787 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * This is module implements the TransferLog directive (same as the + * common log module), and additional directives, LogFormat and CustomLog. + * + * + * Syntax: + * + * TransferLog fn Logs transfers to fn in standard log format, unless + * a custom format is set with LogFormat + * LogFormat format Set a log format from TransferLog files + * CustomLog fn format + * Log to file fn with format given by the format + * argument + * + * CookieLog fn For backwards compatability with old Cookie + * logging module - now deprecated. + * + * There can be any number of TransferLog and CustomLog + * commands. Each request will be logged to _ALL_ the + * named files, in the appropriate format. + * + * If no TransferLog or CustomLog directive appears in a VirtualHost, + * the request will be logged to the log file(s) defined outside + * the virtual host section. If a TransferLog or CustomLog directive + * appears in the VirtualHost section, the log files defined outside + * the VirtualHost will _not_ be used. This makes this module compatable + * with the CLF and config log modules, where the use of TransferLog + * inside the VirtualHost section overrides its use outside. + * + * Examples: + * + * TransferLog logs/access_log + * + * LogFormat "... custom format ..." + * TransferLog log/virtual_only + * CustomLog log/virtual_useragents "%t %{user-agent}i" + * + * + * This will log using CLF to access_log any requests handled by the + * main server, while any requests to the virtual host will be logged + * with the "... custom format..." to virtual_only _AND_ using + * the custom user-agent log to virtual_useragents. + * + * Note that the NCSA referer and user-agent logs are easily added with + * CustomLog: + * CustomLog logs/referer "%{referer}i -> %U" + * CustomLog logs/agent "%{user-agent}i" + * + * Except: no RefererIgnore functionality + * logs '-' if no Referer or User-Agent instead of nothing + * + * But using this method allows much easier modification of the + * log format, e.g. to log hosts along with UA: + * CustomLog logs/referer "%{referer}i %U %h" + * + * The argument to LogFormat and CustomLog is a string, which can include + * literal characters copied into the log files, and '%' directives as + * follows: + * + * %...b: bytes sent, excluding HTTP headers. + * %...{FOOBAR}e: The contents of the environment variable FOOBAR + * %...f: filename + * %...h: remote host + * %...{Foobar}i: The contents of Foobar: header line(s) in the request + * sent to the client. + * %...l: remote logname (from identd, if supplied) + * %...{Foobar}n: The contents of note "Foobar" from another module. + * %...{Foobar}o: The contents of Foobar: header line(s) in the reply. + * %...p: the port the request was served to + * %...P: the process ID of the child that serviced the request. + * %...r: first line of request + * %...s: status. For requests that got internally redirected, this + * is status of the *original* request --- %...>s for the last. + * %...t: time, in common log format time format + * %...{format}t: The time, in the form given by format, which should + * be in strftime(3) format. + * %...T: the time taken to serve the request, in seconds. + * %...u: remote user (from auth; may be bogus if return status (%s) is 401) + * %...U: the URL path requested. + * %...v: the name of the server (i.e. which virtual host?) + * + * The '...' can be nothing at all (e.g. "%h %u %r %s %b"), or it can + * indicate conditions for inclusion of the item (which will cause it + * to be replaced with '-' if the condition is not met). Note that + * there is no escaping performed on the strings from %r, %...i and + * %...o; some with long memories may remember that I thought this was + * a bad idea, once upon a time, and I'm still not comfortable with + * it, but it is difficult to see how to "do the right thing" with all + * of '%..i', unless we URL-escape everything and break with CLF. + * + * The forms of condition are a list of HTTP status codes, which may + * or may not be preceded by '!'. Thus, '%400,501{User-agent}i' logs + * User-agent: on 400 errors and 501 errors (Bad Request, Not + * Implemented) only; '%!200,304,302{Referer}i' logs Referer: on all + * requests which did *not* return some sort of normal status. + * + * The default LogFormat reproduces CLF; see below. + * + * The way this is supposed to work with virtual hosts is as follows: + * a virtual host can have its own LogFormat, or its own TransferLog. + * If it doesn't have its own LogFormat, it inherits from the main + * server. If it doesn't have its own TransferLog, it writes to the + * same descriptor (meaning the same process for "| ..."). + * + * --- rst */ + +#define DEFAULT_LOG_FORMAT "%h %l %u %t \"%r\" %>s %b" + +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" /* For REMOTE_NAME */ + +module config_log_module; + +static int xfer_flags = ( O_WRONLY | O_APPEND | O_CREAT ); +#ifdef __EMX__ +/* OS/2 dosen't support users and groups */ +static mode_t xfer_mode = ( S_IREAD | S_IWRITE ); +#else +static mode_t xfer_mode = ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ); +#endif + +/* + * multi_log_state is our per-(virtual)-server configuration. We store + * an array of the logs we are going to use, each of type config_log_state. + * If a default log format is given by LogFormat, store in default_format + * (backward compat. with mod_log_config). We also store a pointer to + * the logs specified for the main server for virtual servers, so that + * if this vhost has now logs defined, we can use the main server's + * logs instead. + * + * So, for the main server, config_logs contains a list of the log files + * and server_config_logs in empty. For a vhost, server_config_logs + * points to the same array as config_logs in the main server, and + * config_logs points to the array of logs defined inside this vhost, + * which might be empty. + */ + +typedef struct { + array_header *default_format; + array_header *config_logs; + array_header *server_config_logs; +} multi_log_state; + +/* + * config_log_state holds the status of a single log file. fname cannot + * be NULL. format might be NULL, in which case the default_format from + * the multi_log_state should be used, or if that is NULL as well, use + * the CLF. log_fd is -1 before the log file is opened and set to a valid + * fd after it is opened. + */ + +typedef struct { + char *fname; + array_header *format; + int log_fd; +} config_log_state; + +/* + * Format items... + */ + +typedef char *(*item_key_func)(request_rec *, char *); + +typedef struct { + item_key_func func; + char *arg; + int condition_sense; + int want_orig; + array_header *conditions; +} log_format_item; + +char *format_integer(pool *p, int i) +{ + char dummy[40]; + ap_snprintf (dummy, sizeof(dummy), "%d", i); + return pstrdup (p, dummy); +} + +static char *pfmt(pool *p, int i) +{ + if (i <= 0) return "-"; + else return format_integer (p, i); +} + +char *constant_item (request_rec *dummy, char *stuff) { return stuff; } + +char *log_remote_host (request_rec *r, char *a) +{ return (char *)get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME); } + +char *log_remote_logname(request_rec *r, char *a) +{return (char *)get_remote_logname(r);} + +char *log_remote_user (request_rec *r, char *a) { + char *rvalue = r->connection->user; + + if (rvalue == NULL) { + rvalue = "-"; + } else if (strlen (rvalue) == 0) { + rvalue = "\"\""; + } + return rvalue; +} + +char *log_request_line (request_rec *r, char *a) +{ return r->the_request; } + +char *log_request_file (request_rec *r, char *a) +{ return r->filename; } +char *log_request_uri (request_rec *r, char *a) +{ return r->uri; } +char *log_status (request_rec *r, char *a) +{ return pfmt(r->pool, r->status); } + +char *log_bytes_sent (request_rec *r, char *a) +{ + if (!r->sent_bodyct) return "-"; + else + { + long int bs; + char dummy[40]; + bgetopt(r->connection->client, BO_BYTECT, &bs); + ap_snprintf(dummy, sizeof(dummy), "%ld", bs); + return pstrdup(r->pool, dummy); + } +} + +char *log_header_in (request_rec *r, char *a) +{ return table_get (r->headers_in, a); } + +char *log_header_out (request_rec *r, char *a) +{ + char *cp = table_get (r->headers_out, a); + if (!strcasecmp(a, "Content-type") && r->content_type) + cp = r->content_type; + if (cp) return cp; + return table_get (r->err_headers_out, a); +} + +char *log_note (request_rec *r, char *a) +{ return table_get (r->notes, a); } +char *log_env_var (request_rec *r, char *a) +{ return table_get (r->subprocess_env, a); } + +char *log_request_time (request_rec *r, char *a) +{ + int timz; + struct tm *t; + char tstr[MAX_STRING_LEN]; + + t = get_gmtoff(&timz); + + if (a && *a) /* Custom format */ + strftime(tstr, MAX_STRING_LEN, a, t); + else { /* CLF format */ + char sign = (timz < 0 ? '-' : '+'); + + if(timz < 0) timz = -timz; + + strftime(tstr,MAX_STRING_LEN,"[%d/%b/%Y:%H:%M:%S ",t); + ap_snprintf (tstr + strlen(tstr), sizeof(tstr)-strlen(tstr), + "%c%.2d%.2d]", sign, timz/60, timz%60); + } + + return pstrdup (r->pool, tstr); +} + +char *log_request_duration (request_rec *r, char *a) { + char duration[22]; /* Long enough for 2^64 */ + + ap_snprintf(duration, sizeof(duration), "%ld", time(NULL) - r->request_time); + return pstrdup(r->pool, duration); +} + +char *log_virtual_host (request_rec *r, char *a) { + return pstrdup(r->pool, r->server->server_hostname); +} + +char *log_server_port (request_rec *r, char *a) { + char portnum[22]; + + ap_snprintf(portnum, sizeof(portnum), "%u", r->server->port); + return pstrdup(r->pool, portnum); +} + +char *log_child_pid (request_rec *r, char *a) { + char pidnum[22]; + ap_snprintf(pidnum, sizeof(pidnum), "%ld", (long)getpid()); + return pstrdup(r->pool, pidnum); +} +/***************************************************************** + * + * Parsing the log format string + */ + +struct log_item_list { + char ch; + item_key_func func; + int want_orig_default; +} log_item_keys[] = { + { 'h', log_remote_host, 0 }, + { 'l', log_remote_logname, 0 }, + { 'u', log_remote_user, 0 }, + { 't', log_request_time, 0 }, + { 'T', log_request_duration, 1 }, + { 'r', log_request_line, 1 }, + { 'f', log_request_file, 0 }, + { 'U', log_request_uri, 1 }, + { 's', log_status, 1 }, + { 'b', log_bytes_sent, 0 }, + { 'i', log_header_in, 0 }, + { 'o', log_header_out, 0 }, + { 'n', log_note, 0 }, + { 'e', log_env_var, 0 }, + { 'v', log_virtual_host, 0 }, + { 'p', log_server_port, 0 }, + { 'P', log_child_pid, 0 }, + { '\0' } +}; + +struct log_item_list *find_log_func (char k) +{ + int i; + + for (i = 0; log_item_keys[i].ch; ++i) + if (k == log_item_keys[i].ch) + return &log_item_keys[i]; + + return NULL; +} + +char *log_format_substring (pool *p, const char *start, const char *end) +{ + char *res = palloc (p, end - start + 1); + strncpy (res, start, end - start); + res[end - start] = '\0'; + return res; +} + +char *parse_log_misc_string (pool *p, log_format_item *it, const char **sa) +{ + const char *s = *sa; + + it->func = constant_item; + it->conditions = NULL; + + while (*s && *s != '%') ++s; + it->arg = log_format_substring (p, *sa, s); + *sa = s; + + return NULL; +} + +char *parse_log_item (pool *p, log_format_item *it, const char **sa) +{ + const char *s = *sa; + if (*s != '%') return parse_log_misc_string (p, it, sa); + + ++s; + it->condition_sense = 0; + it->conditions = NULL; + it->want_orig = -1; + it->arg = ""; /* For safety's sake... */ + + while (*s) { + int i; + struct log_item_list *l; + + switch (*s) { + case '!': + ++s; + it->condition_sense = !it->condition_sense; + break; + + case '<': + ++s; + it->want_orig = 1; + break; + + case '>': + ++s; + it->want_orig = 0; + break; + + case ',': + ++s; + break; + + case '{': + ++s; + it->arg = getword (p, &s, '}'); + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + i = *s - '0'; + while (isdigit (*++s)) i = i * 10 + (*s) - '0'; + if (!it->conditions) + it->conditions = make_array (p, 4, sizeof(int)); + *(int *)push_array(it->conditions) = i; + break; + + default: + l = find_log_func (*s++); + if (!l) { + char dummy[] = { '\0', '\0'}; + dummy[0] = s[-1]; + return pstrcat (p, "Unrecognized LogFormat directive %", + dummy, NULL); + } + it->func = l->func; + if (it->want_orig == -1) it->want_orig = l->want_orig_default; + *sa = s; + return NULL; + } + } + + return "Ran off end of LogFormat parsing args to some directive"; +} + +array_header *parse_log_string (pool *p, const char *s, const char **err) +{ + array_header *a = make_array (p, 30, sizeof (log_format_item)); + char *res; + + while (*s) { + if ((res = parse_log_item (p, (log_format_item *)push_array(a), &s))) { + *err = res; + return NULL; + } + } + + s = "\n"; + parse_log_item (p, (log_format_item *)push_array(a), &s); + return a; +} + +/***************************************************************** + * + * Actually logging. + */ + +char *process_item(request_rec *r, request_rec *orig, log_format_item *item) +{ + char *cp; + + /* First, see if we need to process this thing at all... */ + + if (item->conditions && item->conditions->nelts != 0) { + int i; + int *conds = (int *)item->conditions->elts; + int in_list = 0; + + for (i = 0; i < item->conditions->nelts; ++i) + if (r->status == conds[i]) { + in_list = 1; + break; + } + + if ((item->condition_sense && in_list) + || (!item->condition_sense && !in_list)) + { + return "-"; + } + } + + /* We do. Do it... */ + + cp = (*item->func)(item->want_orig ? orig : r, item->arg); + return cp ? cp : "-"; +} + +int config_log_transaction(request_rec *r, config_log_state *cls, + array_header *default_format) { + array_header *strsa; + log_format_item *items; + char *str, **strs, *s; + request_rec *orig; + int i; + int len = 0; + array_header *format; + + format = cls->format ? cls->format : default_format; + + strsa= make_array(r->pool, format->nelts,sizeof(char*)); + items = (log_format_item *)format->elts; + + orig = r; + while (orig->prev) orig = orig->prev; + while (r->next) r = r->next; + + for (i = 0; i < format->nelts; ++i) + *((char**)push_array (strsa)) = process_item (r, orig, &items[i]); + + strs = (char **)strsa->elts; + + for (i = 0; i < format->nelts; ++i) + len += strlen (strs[i]); + + str = palloc (r->pool, len + 1); + + for (i = 0, s = str; i < format->nelts; ++i) { + strcpy (s, strs[i]); + s += strlen (strs[i]); + } + + write(cls->log_fd, str, strlen(str)); + + return OK; +} + +int multi_log_transaction(request_rec *r) +{ + multi_log_state *mls = get_module_config (r->server->module_config, + &config_log_module); + config_log_state *clsarray; + int i; + + if (mls->config_logs->nelts) { + clsarray = (config_log_state *)mls->config_logs->elts; + for (i = 0; i < mls->config_logs->nelts; ++i) { + config_log_state *cls = &clsarray[i]; + + config_log_transaction(r, cls, mls->default_format); + } + } + else if (mls->server_config_logs) { + clsarray = (config_log_state *)mls->server_config_logs->elts; + for (i = 0; i < mls->server_config_logs->nelts; ++i) { + config_log_state *cls = &clsarray[i]; + + config_log_transaction(r, cls, mls->default_format); + } + } + + return OK; +} + +/***************************************************************** + * + * Module glue... + */ + +void *make_config_log_state (pool *p, server_rec *s) +{ + multi_log_state *mls = + (multi_log_state *)palloc(p, sizeof (multi_log_state)); + + mls->config_logs = + make_array(p, 5, sizeof (config_log_state)); + mls->default_format = NULL; + mls->server_config_logs = NULL; + + return mls; +} + +/* + * Use the merger to simply add a pointer from the vhost log state + * to the log of logs specified for the non-vhost configuration + */ + +void *merge_config_log_state (pool *p, void *basev, void *addv) +{ + multi_log_state *base = (multi_log_state *)basev; + multi_log_state *add = (multi_log_state *)addv; + + add->server_config_logs = base->config_logs; + if (!add->default_format) + add->default_format = base->default_format; + + return add; +} + +const char *log_format (cmd_parms *cmd, void *dummy, char *arg) +{ + const char *err_string = NULL; + multi_log_state *mls = get_module_config (cmd->server->module_config, + &config_log_module); + + mls->default_format = parse_log_string (cmd->pool, arg, &err_string); + return err_string; +} + +const char *add_custom_log(cmd_parms *cmd, void *dummy, char *fn, char *fmt) +{ + const char *err_string = NULL; + multi_log_state *mls = get_module_config (cmd->server->module_config, + &config_log_module); + config_log_state *cls; + + cls = (config_log_state*)push_array(mls->config_logs); + cls->fname = fn; + if (!fmt) + cls->format = NULL; + else + cls->format = parse_log_string (cmd->pool, fmt, &err_string); + cls->log_fd = -1; + + return err_string; +} + +const char *set_transfer_log(cmd_parms *cmd, void *dummy, char *fn) +{ + return add_custom_log(cmd, dummy, fn, NULL); +} + +const char *set_cookie_log(cmd_parms *cmd, void *dummy, char *fn) +{ + return add_custom_log(cmd, dummy, fn, "%{Cookie}n \"%r\" %t"); +} + +command_rec config_log_cmds[] = { +{ "CustomLog", add_custom_log, NULL, RSRC_CONF, TAKE2, + "a file name and a custom log format string" }, +{ "TransferLog", set_transfer_log, NULL, RSRC_CONF, TAKE1, + "the filename of the access log" }, +{ "LogFormat", log_format, NULL, RSRC_CONF, TAKE1, + "a log format string (see docs)" }, +{ "CookieLog", set_cookie_log, NULL, RSRC_CONF, TAKE1, + "the filename of the cookie log" }, +{ NULL } +}; + +void config_log_child (void *cmd) +{ + /* Child process code for 'TransferLog "|..."'; + * may want a common framework for this, since I expect it will + * be common for other foo-loggers to want this sort of thing... + */ + + cleanup_for_exec(); + signal (SIGHUP, SIG_IGN); +#ifdef __EMX__ + /* For OS/2 we need to use a '/' */ + execl (SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); +#else + execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL); +#endif + perror ("exec"); + fprintf (stderr, "Exec of shell for logging failed!!!\n"); + exit (1); +} + +config_log_state *open_config_log (server_rec *s, pool *p, + config_log_state *cls, + array_header *default_format) { + if (cls->log_fd > 0) return cls; /* virtual config shared w/main server */ + + if (*cls->fname == '|') { + FILE *dummy; + + if (!spawn_child (p, config_log_child, (void *)(cls->fname+1), + kill_after_timeout, &dummy, NULL)) { + perror ("spawn_child"); + fprintf (stderr, "Couldn't fork child for TransferLog process\n"); + exit (1); + } + + cls->log_fd = fileno (dummy); + } + else { + char *fname = server_root_relative (p, cls->fname); + if((cls->log_fd = popenf(p, fname, xfer_flags, xfer_mode)) < 0) { + perror("open"); + fprintf (stderr, + "httpd: could not open transfer log file %s.\n", fname); + exit(1); + } + } + + return cls; +} + +config_log_state *open_multi_logs (server_rec *s, pool *p) +{ + int i; + multi_log_state *mls = get_module_config(s->module_config, + &config_log_module); + config_log_state *clsarray; + const char *dummy; + + if (!mls->default_format) + mls->default_format = parse_log_string (p, DEFAULT_LOG_FORMAT, &dummy); + + if (mls->config_logs->nelts) { + clsarray = (config_log_state *)mls->config_logs->elts; + for (i = 0; i < mls->config_logs->nelts; ++i) { + config_log_state *cls = &clsarray[i]; + + cls = open_config_log(s, p, cls, mls->default_format); + } + } + else if (mls->server_config_logs) { + clsarray = (config_log_state *)mls->server_config_logs->elts; + for (i = 0; i < mls->server_config_logs->nelts; ++i) { + config_log_state *cls = &clsarray[i]; + + cls = open_config_log(s, p, cls, mls->default_format); + } + } + + return NULL; +} + +void init_config_log (server_rec *s, pool *p) +{ + /* First, do "physical" server, which gets default log fd and format + * for the virtual servers, if they don't override... + */ + + open_multi_logs (s, p); + + /* Then, virtual servers */ + + for (s = s->next; s; s = s->next) open_multi_logs (s, p); +} + +module config_log_module = { + STANDARD_MODULE_STUFF, + init_config_log, /* initializer */ + NULL, /* create per-dir config */ + NULL, /* merge per-dir config */ + make_config_log_state, /* server config */ + merge_config_log_state, /* merge server config */ + config_log_cmds, /* command table */ + NULL, /* handlers */ + NULL, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* fixups */ + multi_log_transaction, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_log_referer.c b/APACHE_1_2_X/src/modules/standard/mod_log_referer.c new file mode 100644 index 00000000000..e494298944c --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_log_referer.c @@ -0,0 +1,235 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + + +#include "httpd.h" +#include "http_config.h" + +module referer_log_module; + +static int xfer_flags = ( O_WRONLY | O_APPEND | O_CREAT ); + +#ifdef __EMX__ +/* OS/2 lacks support for users and groups */ +static mode_t xfer_mode = ( S_IREAD | S_IWRITE ); +#else +static mode_t xfer_mode = ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ); +#endif + +typedef struct { + char *fname; + int referer_fd; + array_header *referer_ignore_list; +} referer_log_state; + +void *make_referer_log_state (pool *p, server_rec *s) +{ + referer_log_state *cls = + (referer_log_state *)palloc (p, sizeof (referer_log_state)); + + cls->fname = ""; + cls->referer_fd = -1; + cls->referer_ignore_list = make_array(p, 1, sizeof(char *)); + return (void *)cls; +} + +const char *set_referer_log (cmd_parms *parms, void *dummy, char *arg) +{ + referer_log_state *cls = get_module_config (parms->server->module_config, + &referer_log_module); + + cls->fname = arg; + return NULL; +} + +const char *add_referer_ignore (cmd_parms *parms, void *dummy, char *arg) +{ + char **addme; + referer_log_state *cls = get_module_config (parms->server->module_config, + &referer_log_module); + + addme = push_array(cls->referer_ignore_list); + *addme = pstrdup(cls->referer_ignore_list->pool, arg); + return NULL; +} + +command_rec referer_log_cmds[] = { +{ "RefererLog", set_referer_log, NULL, RSRC_CONF, TAKE1, + "the filename of the referer log" }, +{ "RefererIgnore", add_referer_ignore, NULL, RSRC_CONF, ITERATE, + "referer hostnames to ignore" }, +{ NULL } +}; + +void referer_log_child (void *cmd) +{ + /* Child process code for 'RefererLog "|..."'; + * may want a common framework for this, since I expect it will + * be common for other foo-loggers to want this sort of thing... + */ + + cleanup_for_exec(); + signal (SIGHUP, SIG_IGN); +#ifdef __EMX__ + /* For OS/2 we need to use a '/' */ + execl (SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); +#else + execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL); +#endif + perror ("execl"); + fprintf (stderr, "Exec of shell for logging failed!!!\n"); + exit (1); +} + +void open_referer_log (server_rec *s, pool *p) +{ + referer_log_state *cls = get_module_config (s->module_config, + &referer_log_module); + + char *fname = server_root_relative (p, cls->fname); + + if (cls->referer_fd > 0) return; /* virtual log shared w/main server */ + + if (*cls->fname == '|') { + FILE *dummy; + + if (!spawn_child (p, referer_log_child, (void *)(cls->fname+1), + kill_after_timeout, &dummy, NULL)) { + perror ("spawn_child"); + fprintf (stderr, "Couldn't fork child for RefererLog process\n"); + exit (1); + } + + cls->referer_fd = fileno (dummy); + } + else if(*cls->fname != '\0') { + if((cls->referer_fd = popenf(p, fname, xfer_flags, xfer_mode)) < 0) { + perror("open"); + fprintf(stderr,"httpd: could not open referer log file %s.\n", fname); + exit(1); + } + } +} + +void init_referer_log (server_rec *s, pool *p) +{ + for (; s; s = s->next) open_referer_log (s, p); +} + +int referer_log_transaction(request_rec *orig) +{ + char **ptrptr, **ptrptr2; + referer_log_state *cls = get_module_config (orig->server->module_config, + &referer_log_module); + + char *str; + char *referer; + request_rec *r; + + if(cls->referer_fd <0) + return OK; + + for (r = orig; r->next; r = r->next) + continue; + if (*cls->fname == '\0') /* Don't log referer */ + return DECLINED; + + referer = table_get(orig->headers_in, "Referer"); + if(referer != NULL) + { + + + /* The following is an upsetting mess of pointers, I'm sorry + Anyone with the motiviation and/or the time should feel free + to make this cleaner... */ + + ptrptr2 = (char **) (cls->referer_ignore_list->elts + + (cls->referer_ignore_list->nelts * + cls->referer_ignore_list->elt_size)); + + /* Go through each element of the ignore list and compare it to the + referer_host. If we get a match, return without logging */ + + for(ptrptr = (char **) cls->referer_ignore_list->elts; + ptrptr < ptrptr2; + ptrptr = (char **)((char *)ptrptr + cls->referer_ignore_list->elt_size)) + { + if(strstr(referer, *ptrptr)) + return OK; + } + + + str = pstrcat(orig->pool, referer, " -> ", r->uri, "\n", NULL); + write(cls->referer_fd, str, strlen(str)); + } + + return OK; +} + +module referer_log_module = { + STANDARD_MODULE_STUFF, + init_referer_log, /* initializer */ + NULL, /* create per-dir config */ + NULL, /* merge per-dir config */ + make_referer_log_state, /* server config */ + NULL, /* merge server config */ + referer_log_cmds, /* command table */ + NULL, /* handlers */ + NULL, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* fixups */ + referer_log_transaction, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_mime.c b/APACHE_1_2_X/src/modules/standard/mod_mime.c new file mode 100644 index 00000000000..dc84975e1ae --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_mime.c @@ -0,0 +1,324 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * http_mime.c: Sends/gets MIME headers for requests + * + * Rob McCool + * + */ + +#define MIME_PRIVATE + +#include "httpd.h" +#include "http_config.h" + +typedef struct { + table *forced_types; /* Additional AddTyped stuff */ + table *encoding_types; /* Added with AddEncoding... */ + table *language_types; /* Added with AddLanguage... */ + table *handlers; /* Added with AddHandler... */ + + char *type; /* Type forced with ForceType */ + char *handler; /* Handler forced with SetHandler */ +} mime_dir_config; + +module mime_module; + +void *create_mime_dir_config (pool *p, char *dummy) +{ + mime_dir_config *new = + (mime_dir_config *) palloc (p, sizeof(mime_dir_config)); + + new->forced_types = make_table (p, 4); + new->encoding_types = make_table (p, 4); + new->language_types = make_table (p, 4); + new->handlers = make_table (p, 4); + + new->type = NULL; + new->handler = NULL; + + return new; +} + +void *merge_mime_dir_configs (pool *p, void *basev, void *addv) +{ + mime_dir_config *base = (mime_dir_config *)basev; + mime_dir_config *add = (mime_dir_config *)addv; + mime_dir_config *new = + (mime_dir_config *)palloc (p, sizeof(mime_dir_config)); + + new->forced_types = overlay_tables (p, add->forced_types, + base->forced_types); + new->encoding_types = overlay_tables (p, add->encoding_types, + base->encoding_types); + new->language_types = overlay_tables (p, add->language_types, + base->language_types); + new->handlers = overlay_tables (p, add->handlers, + base->handlers); + + new->type = add->type ? add->type : base->type; + new->handler = add->handler ? add->handler : base->handler; + + return new; +} + +const char *add_type(cmd_parms *cmd, mime_dir_config *m, char *ct, char *ext) +{ + if (*ext == '.') ++ext; + table_set (m->forced_types, ext, ct); + return NULL; +} + +const char *add_encoding(cmd_parms *cmd, mime_dir_config *m, char *enc, + char *ext) +{ + if (*ext == '.') ++ext; + table_set (m->encoding_types, ext, enc); + return NULL; +} + +const char *add_language(cmd_parms *cmd, mime_dir_config *m, char *lang, + char *ext) +{ + if (*ext == '.') ++ext; + table_set (m->language_types, ext, lang); + return NULL; +} + +const char *add_handler(cmd_parms *cmd, mime_dir_config *m, char *hdlr, + char *ext) +{ + if (*ext == '.') ++ext; + table_set (m->handlers, ext, hdlr); + return NULL; +} + +/* The sole bit of server configuration that the MIME module has is + * the name of its config file, so... + */ + +const char *set_types_config (cmd_parms *cmd, void *dummy, char *arg) +{ + set_module_config (cmd->server->module_config, &mime_module, + pstrdup (cmd->pool, arg)); + return NULL; +} + +command_rec mime_cmds[] = { +{ "AddType", add_type, NULL, OR_FILEINFO, ITERATE2, + "a mime type followed by one or more file extensions" }, +{ "AddEncoding", add_encoding, NULL, OR_FILEINFO, ITERATE2, + "an encoding (e.g., gzip), followed by one or more file extensions" }, +{ "AddLanguage", add_language, NULL, OR_FILEINFO, ITERATE2, + "a language (e.g., fr), followed by one or more file extensions" }, +{ "AddHandler", add_handler, NULL, OR_FILEINFO, ITERATE2, + "a handler name followed by one or more file extensions" }, +{ "ForceType", set_string_slot, (void*)XtOffsetOf(mime_dir_config, type), + OR_FILEINFO, TAKE1, "a media type" }, +{ "SetHandler", set_string_slot, (void*)XtOffsetOf(mime_dir_config, handler), + OR_FILEINFO, TAKE1, "a handler name" }, +{ "TypesConfig", set_types_config, NULL, RSRC_CONF, TAKE1, + "the MIME types config file" }, +{ NULL } +}; + +/* Hash table --- only one of these per daemon; virtual hosts can + * get private versions through AddType... + */ + +#define MIME_HASHSIZE 27 +#define hash(i) (isalpha(i) ? (tolower(i)) - 'a' : 26) + +static table *hash_buckets[MIME_HASHSIZE]; + +void init_mime (server_rec *s, pool *p) +{ + FILE *f; + char l[MAX_STRING_LEN]; + int x; + char *types_confname = get_module_config (s->module_config, &mime_module); + + if (!types_confname) types_confname = TYPES_CONFIG_FILE; + + types_confname = server_root_relative (p, types_confname); + + if(!(f = fopen(types_confname,"r"))) { + perror("fopen"); + fprintf(stderr,"httpd: could not open mime types file %s\n", + types_confname); + exit(1); + } + + for(x=0;x<27;x++) + hash_buckets[x] = make_table (p, 10); + + while(!(cfg_getline(l,MAX_STRING_LEN,f))) { + const char *ll = l, *ct; + + if(l[0] == '#') continue; + ct = getword_conf (p, &ll); + + while(ll[0]) { + char *ext = getword_conf (p, &ll); + str_tolower (ext); /* ??? */ + table_set (hash_buckets[hash(ext[0])], ext, ct); + } + } + fclose(f); +} + +int find_ct(request_rec *r) +{ + const char *fn = strrchr(r->filename, '/'); + mime_dir_config *conf = + (mime_dir_config *)get_module_config(r->per_dir_config, &mime_module); + char *ext, *type, *orighandler = r->handler; + + if (S_ISDIR(r->finfo.st_mode)) { + r->content_type = DIR_MAGIC_TYPE; + return OK; + } + + /* TM -- FIXME + * + * if r->filename does not contain a '/', the following passes a null + * pointer to getword, causing a SEGV .. + */ + + if(fn == NULL) fn = r->filename; + + /* Parse filename extensions, which can be in any order */ + while ((ext = getword(r->pool, &fn, '.')) && *ext) { + int found = 0; + + /* Check for Content-Type */ + if ((type = table_get (conf->forced_types, ext)) + || (type = table_get (hash_buckets[hash(*ext)], ext))) { + r->content_type = type; + found = 1; + } + + /* Check for Content-Language */ + if ((type = table_get (conf->language_types, ext))) { + char **new; + + r->content_language = type; /* back compat. only */ + if (!r->content_languages) + r->content_languages = make_array (r->pool, 2, sizeof(char*)); + new = (char **)push_array (r->content_languages); + *new = type; + found = 1; + } + + /* Check for Content-Encoding */ + if ((type = table_get (conf->encoding_types, ext))) { + if (!r->content_encoding) + r->content_encoding = type; + else + r->content_encoding = pstrcat(r->pool, r->content_encoding, + ", ", type, NULL); + found = 1; + } + + /* Check for a special handler, but not for proxy request */ + if ((type = table_get (conf->handlers, ext)) && !r->proxyreq) { + r->handler = type; + found = 1; + } + + /* This is to deal with cases such as foo.gif.bak, which we want + * to not have a type. So if we find an unknown extension, we + * zap the type/language/encoding and reset the handler + */ + + if (!found) { + r->content_type = NULL; + r->content_language = NULL; + r->content_languages = NULL; + r->content_encoding = NULL; + r->handler = orighandler; + } + + } + + /* Check for overrides with ForceType/SetHandler */ + + if (conf->type && strcmp(conf->type, "none")) + r->content_type = pstrdup(r->pool, conf->type); + if (conf->handler && strcmp(conf->handler, "none")) + r->handler = pstrdup(r->pool, conf->handler); + + if (!r->content_type) return DECLINED; + + return OK; +} + + +module mime_module = { + STANDARD_MODULE_STUFF, + init_mime, /* initializer */ + create_mime_dir_config, + merge_mime_dir_configs, + NULL, /* server config */ + NULL, /* merge server config */ + mime_cmds, + NULL, /* handlers */ + NULL, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + find_ct, /* type_checker */ + NULL, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_negotiation.c b/APACHE_1_2_X/src/modules/standard/mod_negotiation.c new file mode 100644 index 00000000000..02be3f10e38 --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_negotiation.c @@ -0,0 +1,2041 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * mod_negotiation.c: keeps track of MIME types the client is willing to + * accept, and contains code to handle type arbitration. + * + * rst + */ + +#include "httpd.h" +#include "http_config.h" +#include "http_request.h" +#include "http_core.h" +#include "http_log.h" +#include "util_script.h" + +/* define TCN_02 to allow for Holtman I-D transparent negotiation. + * This file currently implements the draft-02, except for + * anything to do with features and cache-control (max-age etc) + * + * Since the draft is just that, and we don't yet implement + * everything, regard the transparent negotiation stuff as experimental. + */ +/*#define TCN_02*/ + +/* Commands --- configuring document caching on a per (virtual?) + * server basis... + */ + +typedef struct { + array_header *language_priority; +} neg_dir_config; + +module negotiation_module; + +char *merge_string_array (pool *p, array_header *arr, char *sep) +{ + int i; + char *t = ""; + + for (i = 0; i < arr->nelts; i++) { + t = pstrcat(p, t, i ? sep : "", ((char**)arr->elts)[i], NULL); + } + return t; +} + +void *create_neg_dir_config (pool *p, char *dummy) +{ + neg_dir_config *new = + (neg_dir_config *) palloc (p, sizeof (neg_dir_config)); + + new->language_priority = make_array (p, 4, sizeof (char *)); + return new; +} + +void *merge_neg_dir_configs (pool *p, void *basev, void *addv) +{ + neg_dir_config *base = (neg_dir_config *)basev; + neg_dir_config *add = (neg_dir_config *)addv; + neg_dir_config *new = + (neg_dir_config *) palloc (p, sizeof (neg_dir_config)); + + /* give priority to the config in the subdirectory */ + new->language_priority = append_arrays (p, add->language_priority, + base->language_priority); + return new; +} + +const char *set_language_priority (cmd_parms *cmd, void *n, char *lang) +{ + array_header *arr = ((neg_dir_config *) n)->language_priority; + char **langp = (char **) push_array (arr); + + *langp = pstrdup (arr->pool, lang); + return NULL; +} + +const char *cache_negotiated_docs (cmd_parms *cmd, void *dummy, char *dummy2) +{ + void *server_conf = cmd->server->module_config; + + set_module_config (server_conf, &negotiation_module, "Cache"); + return NULL; +} + +int do_cache_negotiated_docs (server_rec *s) +{ + return (get_module_config (s->module_config, &negotiation_module) != NULL); +} + +command_rec negotiation_cmds[] = { +{ "CacheNegotiatedDocs", cache_negotiated_docs, NULL, RSRC_CONF, RAW_ARGS, + NULL }, +{ "LanguagePriority", set_language_priority, NULL, OR_FILEINFO, ITERATE, + NULL }, +{ NULL } +}; + +/* Record of available info on a media type specified by the client + * (we also use 'em for encodings and languages) + */ + +typedef struct accept_rec { + char *type_name; + float quality; + float max_bytes; + float level; + char *charset; /* for content-type only */ +} accept_rec; + +/* Record of available info on a particular variant + * + * Note that a few of these fields are updated by the actual negotiation + * code. These are: + * + * level_matched --- initialized to zero. Set to the value of level + * if the client actually accepts this media type at that + * level (and *not* if it got in on a wildcard). See level_cmp + * below. + */ + +typedef struct var_rec { + request_rec *sub_req; /* May be NULL (is, for map files) */ + char *type_name; + char *file_name; + char *content_encoding; + array_header *content_languages; /* list of languages for this variant */ + char *content_charset; + char *description; + + /* The next five items give the quality values for the dimensions + * of negotiation for this variant. They are obtained from the + * appropriate header lines, except for accept_type_quality, which + * is obtained from the variant itself (the 'qs' parameter value + * from the variant's mime-type). Apart from type_quality, + * these values are set when we find the quality for each variant + * (see best_match()). type_quality is set from the 'qs' parameter + * of the variant description or mime type: see set_mime_fields(). + */ + float lang_quality; /* quality of this variant's language */ + int encoding_quality; /* ditto encoding (1 or 0 only) */ + float charset_quality; /* ditto charset */ + float accept_type_quality; /* ditto media type */ + float type_quality; /* quality of source for this type */ + + /* Now some special values */ + float level; /* Auxiliary to content-type... */ + float bytes; /* content length, if known */ + int lang_index; /* pre HTTP/1.1 language priority stuff */ + int is_pseudo_html; /* text/html, *or* the INCLUDES_MAGIC_TYPEs */ + + /* Above are all written-once properties of the variant. The + * three fields below are changed during negotiation: + */ + + float level_matched; + int mime_stars; + int definite; +} var_rec; + +/* Something to carry around the state of negotiation (and to keep + * all of this thread-safe)... + */ + +typedef struct { + pool *pool; + request_rec *r; + char *dir_name; + int accept_q; /* 1 if an Accept item has a q= param */ + float default_lang_quality; /* fiddle lang q for variants with no lang */ + + + array_header *accepts; /* accept_recs */ + int have_accept_header; /* 1 if Accept-Header present */ + array_header *accept_encodings; /* accept_recs */ + array_header *accept_charsets; /* accept_recs */ + array_header *accept_langs; /* accept_recs */ + array_header *avail_vars; /* available variants */ + + int ua_can_negotiate; /* 1 if ua can do transparent negotiate */ + int use_transparent_neg; /* 1 if we are using transparent neg */ + int short_accept_headers; /* 1 if ua does trans neg & sent short accpt */ +} negotiation_state; + +/* A few functions to manipulate var_recs. + * Cleaning out the fields... + */ + +void clean_var_rec (var_rec *mime_info) +{ + mime_info->sub_req = NULL; + mime_info->type_name = ""; + mime_info->file_name = ""; + mime_info->content_encoding = ""; + mime_info->content_languages = NULL; + mime_info->content_charset = ""; + mime_info->description = ""; + + mime_info->is_pseudo_html = 0; + mime_info->level = 0.0; + mime_info->level_matched = 0.0; + mime_info->bytes = 0; + mime_info->lang_index = -1; + mime_info->mime_stars = 0; + mime_info->definite = 1; + + mime_info->charset_quality = 1.0; + mime_info->type_quality = 0.0; + mime_info->encoding_quality = 1; + mime_info->lang_quality = 1.0; + mime_info->accept_type_quality = 1.0; +} + +/* Initializing the relevant fields of a variant record from the + * accept_info read out of its content-type, one way or another. + */ + +void set_mime_fields (var_rec *var, accept_rec *mime_info) +{ + var->type_name = mime_info->type_name; + var->type_quality = mime_info->quality; + var->level = mime_info->level; + var->content_charset = mime_info->charset; + + var->is_pseudo_html = + (!strcmp (var->type_name, "text/html") + || !strcmp (var->type_name, INCLUDES_MAGIC_TYPE) + || !strcmp (var->type_name, INCLUDES_MAGIC_TYPE3)); +} + +/***************************************************************** + * + * Parsing (lists of) media types and their parameters, as seen in + * HTTPD header lines and elsewhere. + */ + +/* + * Get a single mime type entry --- one media type and parameters; + * enter the values we recognize into the argument accept_rec + */ + +char *get_entry (pool *p, accept_rec *result, char *accept_line) +{ + result->quality = 1.0; + result->max_bytes = 0.0; + result->level = 0.0; + result->charset = ""; + + /* Note that this handles what I gather is the "old format", + * + * Accept: text/html text/plain moo/zot + * + * without any compatibility kludges --- if the token after the + * MIME type begins with a semicolon, we know we're looking at parms, + * otherwise, we know we aren't. (So why all the pissing and moaning + * in the CERN server code? I must be missing something). + */ + + result->type_name = get_token (p, &accept_line, 0); + str_tolower (result->type_name); /* You want case-insensitive, + * you'll *get* case-insensitive. + */ + + + /* KLUDGE!!! Default HTML to level 2.0 unless the browser + * *explicitly* says something else. + */ + + if (!strcmp (result->type_name, "text/html") + && result->level == 0.0) + result->level = 2.0; + else if (!strcmp (result->type_name, INCLUDES_MAGIC_TYPE)) + result->level = 2.0; + else if (!strcmp (result->type_name, INCLUDES_MAGIC_TYPE3)) + result->level = 3.0; + + while (*accept_line == ';') { + /* Parameters ... */ + + char *parm; + char *cp; + char *end; + + ++accept_line; + parm = get_token (p, &accept_line, 1); + + /* Look for 'var = value' --- and make sure the var is in lcase. */ + + for (cp = parm; *cp && !isspace(*cp) && *cp != '='; ++cp) + *cp = tolower(*cp); + + if (!*cp) continue; /* No '='; just ignore it. */ + + *cp++ = '\0'; /* Delimit var */ + while (*cp && (isspace(*cp) || *cp == '=')) + ++cp; + + if (*cp == '"') { + ++cp; + for (end = cp; *end && + *end != '\n' && *end != '\r' && *end != '\"'; + end++) + ; + } + else { + for (end = cp; *end && !isspace(*end); end++) + ; + } + if (*end) + *end = '\0'; /* strip ending quote or return */ + str_tolower(cp); + + if (parm[0] == 'q' + && (parm[1] == '\0' || (parm[1] == 's' && parm[2] == '\0'))) + result->quality = atof(cp); + else if (parm[0] == 'm' && parm[1] == 'x' && + parm[2] == 'b' && parm[3] == '\0') + result->max_bytes = atof(cp); + else if (parm[0] == 'l' && !strcmp (&parm[1], "evel")) + result->level = atof(cp); + else if (!strcmp(parm, "charset")) + result->charset = cp; + } + + if (*accept_line == ',') ++accept_line; + + return accept_line; +} + +/***************************************************************** + * + * Dealing with header lines ... + * + * Accept, Accept-Charset, Accept-Language and Accept-Encoding + * are handled by do_header_line() - they all have the same + * basic structure of a list of items of the format + * name; q=N; charset=TEXT + * + * where q is only valid in Accept, Accept-Charset and Accept-Languages, + * and charset is only valid in Accept. + */ + +array_header *do_header_line (pool *p, char *accept_line) +{ + array_header *accept_recs = make_array (p, 40, sizeof (accept_rec)); + + if (!accept_line) return accept_recs; + + while (*accept_line) { + accept_rec *new = (accept_rec *)push_array (accept_recs); + accept_line = get_entry (p, new, accept_line); + } + + return accept_recs; +} + +/* Given the text of the Content-Languages: line from the var map file, + * return an array containing the languages of this variant + */ + +array_header *do_languages_line (pool *p, char **lang_line) +{ + array_header *lang_recs = make_array (p, 2, sizeof (char *)); + + if (!lang_line) return lang_recs; + + while (**lang_line) { + char **new = (char **)push_array (lang_recs); + *new = get_token (p, lang_line, 0); + str_tolower (*new); + if (**lang_line == ',' || **lang_line == ';') + ++(*lang_line); + } + + return lang_recs; +} + +/***************************************************************** + * + * Handling header lines from clients... + */ + +negotiation_state *parse_accept_headers (request_rec *r) +{ + negotiation_state *new = + (negotiation_state *)pcalloc (r->pool, sizeof (negotiation_state)); + accept_rec *elts; + table *hdrs = r->headers_in; + int i; + char *hdr; + + new->pool = r->pool; + new->r = r; + new->dir_name = make_dirstr(r->pool, r->filename, count_dirs(r->filename)); + + new->accepts = do_header_line (r->pool, table_get (hdrs, "Accept")); + + hdr = table_get (hdrs, "Accept-encoding"); + if (hdr) + new->have_accept_header = 1; + new->accept_encodings = do_header_line (r->pool, hdr); + + new->accept_langs = + do_header_line (r->pool, table_get (hdrs, "Accept-language")); + new->accept_charsets = + do_header_line (r->pool, table_get (hdrs, "Accept-charset")); + new->avail_vars = make_array (r->pool, 40, sizeof (var_rec)); + +#ifdef TCN_02 + if (table_get(r->headers_in, "Negotiate")) { + /* Negotiate: header tells us UA does transparent negotiation + * We have to decide whether we want to ... for now, yes, + * we do */ + + new->ua_can_negotiate = 1; + if (r->method_number == M_GET) + new->use_transparent_neg = 1; /* should be configurable */ + + /* Check for 'Short Accept', ie either no Accept: header, + * or just "Accept: * / *" */ + if (new->accepts->nelts == 0 || + (new->accepts->nelts == 1 && + (!strcmp(((accept_rec *)new->accepts->elts)[0].type_name, + "*/*")))) { + /* Using short accept header */ + new->short_accept_headers = 1; + } + } +#endif + + if (!new->use_transparent_neg) { + /* Now we check for q-values. If they're all 1.0, we assume the + * client is "broken", and we are allowed to fiddle with the + * values later. Otherwise, we leave them alone. + */ + + elts = (accept_rec *)new->accepts->elts; + + for (i = 0; i < new->accepts->nelts; ++i) + if (elts[i].quality < 1.0) new->accept_q = 1; + } + else new->accept_q = 1; + + return new; +} + +/* Sometimes clients will give us no Accept info at all; this routine sets + * up the standard default for that case, and also arranges for us to be + * willing to run a CGI script if we find one. (In fact, we set up to + * dramatically prefer CGI scripts in cases where that's appropriate, + * e.g., POST). + */ + +void maybe_add_default_encodings(negotiation_state *neg, int prefer_scripts) +{ + accept_rec *new_accept = (accept_rec *)push_array (neg->accepts); + + new_accept->type_name = CGI_MAGIC_TYPE; + new_accept->quality = prefer_scripts ? 1e-20 : 1e20; + new_accept->level = 0.0; + new_accept->max_bytes = 0.0; + + if (neg->accepts->nelts > 1) return; + + new_accept = (accept_rec *)push_array (neg->accepts); + + new_accept->type_name = "*/*"; + new_accept->quality = 1.0; + new_accept->level = 0.0; + new_accept->max_bytes = 0.0; +} + +/***************************************************************** + * + * Parsing type-map files, in Roy's meta/http format augmented with + * #-comments. + */ + +/* Reading RFC822-style header lines, ignoring #-comments and + * handling continuations. + */ + +enum header_state { header_eof, header_seen, header_sep }; + +enum header_state get_header_line (char *buffer, int len, FILE *map) +{ + char *buf_end = buffer + len; + char *cp; + int c; + + /* Get a noncommented line */ + + do { + if (fgets(buffer, MAX_STRING_LEN, map) == NULL) + return header_eof; + } while (buffer[0] == '#'); + + /* If blank, just return it --- this ends information on this variant */ + + for (cp = buffer; *cp && isspace (*cp); ++cp) + continue; + + if (*cp == '\0') return header_sep; + + /* If non-blank, go looking for header lines, but note that we still + * have to treat comments specially... + */ + + cp += strlen(cp); + + while ((c = getc(map)) != EOF) + { + if (c == '#') { + /* Comment line */ + while ((c = getc(map)) != EOF && c != '\n') + continue; + } else if (isspace(c)) { + /* Leading whitespace. POSSIBLE continuation line + * Also, possibly blank --- if so, we ungetc() the final newline + * so that we will pick up the blank line the next time 'round. + */ + + while (c != EOF && c != '\n' && isspace(c)) + c = getc(map); + + ungetc (c, map); + + if (c == '\n') return header_seen; /* Blank line */ + + /* Continuation */ + + while (cp < buf_end - 2 && (c = getc(map)) != EOF && c != '\n') + *cp++ = c; + + *cp++ = '\n'; + *cp = '\0'; + } else { + + /* Line beginning with something other than whitespace */ + + ungetc (c, map); + return header_seen; + } + } + + return header_seen; +} + +/* Stripping out RFC822 comments */ + +void strip_paren_comments (char *hdr) +{ + /* Hmmm... is this correct? In Roy's latest draft, (comments) can nest! */ + + while (*hdr) { + if (*hdr == '"') { + while (*++hdr && *hdr != '"') + continue; + ++hdr; + } + else if (*hdr == '(') { + while (*hdr && *hdr != ')') *hdr++ = ' '; + + if (*hdr) *hdr++ = ' '; + } + else ++hdr; + } +} + +/* Getting to a header body from the header */ + +char *lcase_header_name_return_body (char *header, request_rec *r) +{ + char *cp = header; + + while (*cp && *cp != ':') + *cp++ = tolower(*cp); + + if (!*cp) { + log_reason ("Syntax error in type map --- no ':'", r->filename, r); + return NULL; + } + + do ++cp; while (*cp && isspace (*cp)); + + if (!*cp) { + log_reason ("Syntax error in type map --- no header body", + r->filename, r); + return NULL; + } + + return cp; +} + +int read_type_map (negotiation_state *neg, char *map_name) +{ + request_rec *r = neg->r; + FILE *map = pfopen (neg->pool, map_name, "r"); + + char buffer[MAX_STRING_LEN]; + enum header_state hstate; + struct var_rec mime_info; + + if (map == NULL) { + log_reason("cannot access type map file", map_name, r); + return FORBIDDEN; + } + + clean_var_rec (&mime_info); + + do { + hstate = get_header_line (buffer, MAX_STRING_LEN, map); + + if (hstate == header_seen) { + char *body = lcase_header_name_return_body (buffer, neg->r); + + if (body == NULL) return SERVER_ERROR; + + strip_paren_comments (body); + + if (!strncmp (buffer, "uri:", 4)) { + mime_info.file_name = get_token (neg->pool, &body, 0); + } + else if (!strncmp (buffer, "content-type:", 13)) { + struct accept_rec accept_info; + + get_entry (neg->pool, &accept_info, body); + set_mime_fields (&mime_info, &accept_info); + } + else if (!strncmp (buffer, "content-length:", 15)) { + mime_info.bytes = atoi(body); + } + else if (!strncmp (buffer, "content-language:", 17)) { + mime_info.content_languages = + do_languages_line(neg->pool, &body); + } + else if (!strncmp (buffer, "content-encoding:", 17)) { + mime_info.content_encoding = get_token (neg->pool, &body, 0); + str_tolower (mime_info.content_encoding); + } + else if (!strncmp (buffer, "description:", 12)) { + mime_info.description = get_token (neg->pool, &body, 0); + } + } else { + if (mime_info.type_quality > 0 && *mime_info.file_name) + { + void *new_var = push_array (neg->avail_vars); + memcpy (new_var, (void *)&mime_info, sizeof (var_rec)); + } + + + clean_var_rec(&mime_info); + } + } while (hstate != header_eof); + + pfclose (neg->pool, map); + return OK; +} + +/***************************************************************** + * + * Same, except we use a filtered directory listing as the map... + */ + +int read_types_multi (negotiation_state *neg) +{ + request_rec *r = neg->r; + + char *filp; + int prefix_len; + DIR *dirp; + struct DIR_TYPE *dir_entry; + struct var_rec mime_info; + struct accept_rec accept_info; + void *new_var; + + clean_var_rec (&mime_info); + + if (!(filp = strrchr (r->filename, '/'))) return DECLINED; /* Weird... */ + + if (strncmp(r->filename, "proxy:", 6) == 0) + return DECLINED; + + ++filp; + prefix_len = strlen (filp); + + dirp = opendir (neg->dir_name); /* Not pool protected; sigh... */ + + if (dirp == NULL) { + log_reason("cannot read directory for multi", neg->dir_name, r); + return FORBIDDEN; + } + + while ((dir_entry = readdir (dirp))) { + + request_rec *sub_req; + + /* Do we have a match? */ + + if (strncmp (dir_entry->d_name, filp, prefix_len)) continue; + if (dir_entry->d_name[prefix_len] != '.') continue; + + /* Yep. See if it's something which we have access to, and + * which has a known type and encoding (as opposed to something + * which we'll be slapping default_type on later). + */ + + sub_req = sub_req_lookup_file (dir_entry->d_name, r); + + /* If it has a handler, we'll pretend it's a CGI script, + * since that's a good indication of the sort of thing it + * might be doing. + */ + if (sub_req->handler && !sub_req->content_type) + sub_req->content_type = CGI_MAGIC_TYPE; + + if (sub_req->status != HTTP_OK || !sub_req->content_type) { + destroy_sub_req(sub_req); + continue; + } + + /* If it's a map file, we use that instead of the map + * we're building... + */ + + if (((sub_req->content_type) && + !strcmp (sub_req->content_type, MAP_FILE_MAGIC_TYPE)) || + ((sub_req->handler) && + !strcmp (sub_req->handler, "type-map"))) { + closedir(dirp); + + neg->avail_vars->nelts = 0; + return read_type_map (neg, sub_req->filename); + } + + /* Have reasonable variant --- gather notes. + */ + + mime_info.sub_req = sub_req; + mime_info.file_name = pstrdup(neg->pool, dir_entry->d_name); + if (sub_req->content_encoding) { + mime_info.content_encoding = sub_req->content_encoding; + str_tolower(mime_info.content_encoding); + } + if (sub_req->content_languages) { + int i; + mime_info.content_languages = sub_req->content_languages; + if (mime_info.content_languages) + for (i = 0; i < mime_info.content_languages->nelts; ++i) + str_tolower(((char**) + (mime_info.content_languages->elts))[i]); + } + + get_entry (neg->pool, &accept_info, sub_req->content_type); + set_mime_fields (&mime_info, &accept_info); + + new_var = push_array (neg->avail_vars); + memcpy (new_var, (void *)&mime_info, sizeof (var_rec)); + + clean_var_rec(&mime_info); + } + + closedir(dirp); + return OK; +} + + +/***************************************************************** + * And now for the code you've been waiting for... actually + * finding a match to the client's requirements. + */ + +/* Matching MIME types ... the star/star and foo/star commenting conventions + * are implemented here. (You know what I mean by star/star, but just + * try mentioning those three characters in a C comment). Using strcmp() + * is legit, because everything has already been smashed to lowercase. + * + * Note also that if we get an exact match on the media type, we update + * level_matched for use in level_cmp below... + * + * We also give a value for mime_stars, which is used later. It should + * be 1 for star/star, 2 for type/star and 3 for type/subtype. + */ + +int mime_match (accept_rec *accept, var_rec *avail) +{ + char *accept_type = accept->type_name; + char *avail_type = avail->type_name; + int len = strlen(accept_type); + + if (accept_type[0] == '*') { /* Anything matches star/star */ + if (avail->mime_stars < 1) + avail->mime_stars = 1; + return 1; + } + else if ((accept_type[len - 1] == '*') && + !strncmp (accept_type, avail_type, len - 2)) { + if (avail->mime_stars < 2) + avail->mime_stars = 2; + return 1; + } + else if (!strcmp (accept_type, avail_type) + || (!strcmp (accept_type, "text/html") + && (!strcmp(avail_type, INCLUDES_MAGIC_TYPE) + || !strcmp(avail_type, INCLUDES_MAGIC_TYPE3)))) { + if (accept->level >= avail->level) { + avail->level_matched = avail->level; + avail->mime_stars = 3; + return 1; + } + } + + return OK; +} + +/* This code implements a piece of the tie-breaking algorithm between + * variants of equal quality. This piece is the treatment of variants + * of the same base media type, but different levels. What we want to + * return is the variant at the highest level that the client explicitly + * claimed to accept. + * + * If all the variants available are at a higher level than that, or if + * the client didn't say anything specific about this media type at all + * and these variants just got in on a wildcard, we prefer the lowest + * level, on grounds that that's the one that the client is least likely + * to choke on. + * + * (This is all motivated by treatment of levels in HTML --- we only + * want to give level 3 to browsers that explicitly ask for it; browsers + * that don't, including HTTP/0.9 browsers that only get the implicit + * "Accept: * / *" [space added to avoid confusing cpp --- no, that + * syntax doesn't really work] should get HTML2 if available). + * + * (Note that this code only comes into play when we are choosing among + * variants of equal quality, where the draft standard gives us a fair + * bit of leeway about what to do. It ain't specified by the standard; + * rather, it is a choice made by this server about what to do in cases + * where the standard does not specify a unique course of action). + */ + +int level_cmp (var_rec *var1, var_rec *var2) +{ + /* Levels are only comparable between matching media types */ + + if (var1->is_pseudo_html && !var2->is_pseudo_html) + return 0; + + if (!var1->is_pseudo_html && strcmp (var1->type_name, var2->type_name)) + return 0; + + /* Take highest level that matched, if either did match. */ + + if (var1->level_matched > var2->level_matched) return 1; + if (var1->level_matched < var2->level_matched) return -1; + + /* Neither matched. Take lowest level, if there's a difference. */ + + if (var1->level < var2->level) return 1; + if (var1->level > var2->level) return -1; + + /* Tied */ + + return 0; +} + +/* Finding languages. The main entry point is set_language_quality() + * which is called for each variant. It sets two elements in the + * variant record: + * language_quality - the 'q' value of the 'best' matching language + * from Accept-Language: header (HTTP/1.1) + * lang_index - Pre HTTP/1.1 language priority, using + * position of language on the Accept-Language: + * header, if present, else LanguagePriority + * directive order. + * + * When we do the variant checking for best variant, we use language + * quality first, and if a tie, language_index next (this only + * applies when _not_ using the network algorithm). If using + * network algorithm, lang_index is never used. + * + * set_language_quality() calls find_lang_index() and find_default_index() + * to set lang_index. + */ + +int find_lang_index (array_header *accept_langs, char *lang) +{ + accept_rec *accs; + int i; + + if (!lang) + return -1; + + accs = (accept_rec *)accept_langs->elts; + + for (i = 0; i < accept_langs->nelts; ++i) + if (!strncmp (lang, accs[i].type_name, strlen(accs[i].type_name))) + return i; + + return -1; +} + +/* This function returns the priority of a given language + * according to LanguagePriority. It is used in case of a tie + * between several languages. + */ + +int find_default_index (neg_dir_config *conf, char *lang) +{ + array_header *arr; + int nelts; + char **elts; + int i; + + if (!lang) + return -1; + + arr = conf->language_priority; + nelts = arr->nelts; + elts = (char **) arr->elts; + + for (i = 0; i < nelts; ++i) + if (!strcasecmp (elts[i], lang)) + return i; + + return -1; +} + +/* set_default_lang_quality() sets the quality we apply to variants + * which have no language assigned to them. If none of the variants + * have a language, we are not negotiating on language, so all are + * acceptable, and we set the default q value to 1.0. However if + * some of the variants have languages, we set this default to 0.001. + * The value of this default will be applied to all variants with + * no explicit language -- which will have the effect of making them + * acceptable, but only if no variants with an explicit language + * are acceptable. The default q value set here is assigned to variants + * with no language type in set_language_quality(). + * + * Note that if using the transparent negotiation network algorythm, + * we don't use this fiddle. + */ + +void set_default_lang_quality(negotiation_state *neg) +{ + var_rec *avail_recs = (var_rec *)neg->avail_vars->elts; + int j; + + if (!neg->use_transparent_neg) + for (j = 0; j < neg->avail_vars->nelts; ++j) { + var_rec *variant = &avail_recs[j]; + if (variant->content_languages && + variant->content_languages->nelts) { + neg->default_lang_quality = 0.001; + return; + } + } + + neg->default_lang_quality = 1.0; +} + +/* Set the language_quality value in the variant record. Also + * assigns lang_index for back-compat. + * + * To find the language_quality value, we look for the 'q' value + * of the 'best' matching language on the Accept-Language: + * header. The'best' match is the language on Accept-Language: + * header which matches the language of this variant either fully, + * or as far as the prefix marker (-). If two or more languages + * match, use the longest string from the Accept-Language: header + * (see HTTP/1.1 [14.4]) + * + * When a variant has multiple languages, we find the 'best' + * match for each variant language tag as above, then select the + * one with the highest q value. Because both the accept-header + * and variant can have multiple languages, we now have a hairy + * loop-within-a-loop here. + * + * If the variant has no language and we have no Accept-Language + * items, leave the quality at 1.0 and return. + * + * If the variant has no language, we use the default as set by + * set_default_lang_quality() (1.0 if we are not negotiating on + * language, 0.001 if we are). + * + * Following the setting of the language quality, we drop through to + * set the old 'lang_index'. This is set based on either the order + * of the languages on the Accept-Language header, or the + * order on the LanguagePriority directive. This is only used + * in the negotiation if the language qualities tie. + */ + +void set_language_quality(negotiation_state *neg, var_rec *variant) +{ + int i; + int naccept = neg->accept_langs->nelts; + int index; + neg_dir_config *conf = NULL; + char *firstlang; + + if (naccept == 0) + conf = (neg_dir_config *) get_module_config (neg->r->per_dir_config, + &negotiation_module); + + if (naccept == 0 && (!variant->content_languages || + !variant->content_languages->nelts)) + return; /* no accept-language and no variant lang */ + + if (!variant->content_languages || !variant->content_languages->nelts) { + /* This variant has no content-language, so use the default + * quality factor for variants with no content-language + * (previously set by set_default_lang_quality()). */ + variant->lang_quality = neg->default_lang_quality; + + if (naccept == 0) + return; /* no accept-language items */ + + } + else if (naccept) { + /* Variant has one (or more) languages, and we have one (or more) + * language ranges on the Accept-Language header. Look for + * the best match. We do this by going through each language + * on the variant description looking for a match on the + * Accept-Language header. The best match is the longest matching + * language on the header. The final result is the best q value + * from all the languages on the variant description. + */ + int j; + float fiddle_q = 0.0; + accept_rec *accs = (accept_rec *)neg->accept_langs->elts; + accept_rec *best = NULL, *star = NULL; + char *p; + + for (j = 0; j < variant->content_languages->nelts; ++j) { + char *lang; /* language from variant description */ + accept_rec *bestthistag = NULL; + int prefixlen = 0; + int longest_lang_range_len = 0; + int len; + /* lang is the variant's language-tag, which is the one + * we are allowed to use the prefix of in HTTP/1.1 + */ + lang = ((char **)(variant->content_languages->elts))[j]; + p = strchr(lang, '-'); /* find prefix part (if any) */ + if (p) + prefixlen = p - lang; + + /* now find the best (i.e. longest) matching Accept-Language + * header language. We put the best match for this tag in + * bestthistag. We cannot update the overall best (based on + * q value) because the best match for this tag is the longest + * language item on the accept header, not necessarily the + * highest q. + */ + for (i = 0; i < neg->accept_langs->nelts; ++i) { + if (!strcmp(accs[i].type_name, "*")) { + if (!star) + star = &accs[i]; + continue; + } + + /* Find language. We match if either the variant language + * tag exactly matches, or the prefix of the tag up to the + * '-' character matches the whole of the language in the + * Accept-Language header. We only use this accept-language + * item as the best match for the current tag if it + * is longer than the previous best match */ + if ((!strcmp (lang, accs[i].type_name) || + (prefixlen && + !strncmp(lang, accs[i].type_name, prefixlen) && + (accs[i].type_name[prefixlen] == '\0'))) && + ((len = strlen(accs[i].type_name)) > + longest_lang_range_len)) { + longest_lang_range_len = len; + bestthistag = &accs[i]; + } + + if (! bestthistag) { + /* The next bit is a fiddle. Some browsers might be + * configured to send more specific language ranges + * than desirable. For example, an Accept-Language of + * en-US should never match variants with languages en + * or en-GB. But US English speakers might pick en-US + * as their language choice. So this fiddle checks if + * the language range has a prefix, and if so, it + * matches variants which match that prefix with a + * priority of 0.001. So a request for en-US would + * match variants of types en and en-GB, but at much + * lower priority than matches of en-US directly, or + * of any other language listed on the Accept-Language + * header + */ + if ((p = strchr(accs[i].type_name, '-'))) { + int plen = p - accs[i].type_name; + if (!strncmp(lang, accs[i].type_name, plen)) + fiddle_q = 0.001; + } + } + } + /* Finished looking at Accept-Language headers, the best + * (longest) match is in bestthistag, or NULL if no match + */ + if (!best || + (bestthistag && bestthistag->quality > best->quality)) + best = bestthistag; + } + + variant->lang_quality = best ? best->quality : + (star ? star->quality : fiddle_q); + } + + /* Now set the old lang_index field. Since this is old + * stuff anyway, don't both with handling multiple languages + * per variant, just use the first one assigned to it + */ + index = 0; + if (variant->content_languages && variant->content_languages->nelts) + firstlang = ((char**)variant->content_languages->elts)[0]; + else + firstlang = ""; + if (naccept == 0) /* Client doesn't care */ + index = find_default_index (conf, firstlang); + else /* Client has Accept-Language */ + index = find_lang_index (neg->accept_langs, firstlang); + variant->lang_index = index; + + return; +} + +/* Determining the content length --- if the map didn't tell us, + * we have to do a stat() and remember for next time. + * + * Grump. For Apache, even the first stat here may well be + * redundant (for multiviews) with a stat() done by the sub_req + * machinery. At some point, that ought to be fixed. + */ + +int find_content_length(negotiation_state *neg, var_rec *variant) +{ + struct stat statb; + + if (variant->bytes == 0) { + char *fullname = make_full_path (neg->pool, neg->dir_name, + variant->file_name); + + if (stat (fullname, &statb) >= 0) variant->bytes = statb.st_size; + } + + return variant->bytes; +} + +/* For a given variant, find the best matching Accept: header + * and assign the Accept: header's quality value to the + * accept_type_quality field of the variant, for later use in + * determining the best matching variant. + */ + +void set_accept_quality(negotiation_state *neg, var_rec *variant) +{ + int i; + accept_rec *accept_recs = (accept_rec *)neg->accepts->elts; + float q = 0.0; + int q_definite = 1; + + /* if no Accept: header, leave quality alone (will + * remain at the default value of 1) */ + if (!neg->accepts || neg->accepts->nelts == 0) + return; + + /* + * Go through each of the ranges on the Accept: header, + * looking for the 'best' match with this variant's + * content-type. We use the best match's quality + * value (from the Accept: header) for this variant's + * accept_type_quality field. + * + * The best match is determined like this: + * type/type is better than type/ * is better than * / * + * if match is type/type, use the level mime param if available + */ + for (i = 0; i < neg->accepts->nelts; ++i) { + + accept_rec *type = &accept_recs[i]; + int prev_mime_stars; + + prev_mime_stars = variant->mime_stars; + + if (!mime_match(type, variant)) + continue; /* didn't match the content type at all */ + else + /* did match - see if there were less or more stars than + * in previous match + */ + if (prev_mime_stars == variant->mime_stars) + continue; /* more stars => not as good a match */ + + /* Check maxbytes -- not in HTTP/1.1 or Holtman */ + + if (type->max_bytes > 0 + && (find_content_length(neg, variant) + > type->max_bytes)) + continue; + + /* If we are allowed to mess with the q-values, + * make wildcards very low, so we have a low chance + * of ending up with them if there's something better. + */ + + if (!neg->accept_q && variant->mime_stars == 1) q = 0.01; + else if (!neg->accept_q && variant->mime_stars == 2) q = 0.02; + else q = type->quality; + + q_definite = (variant->mime_stars == 3); + } + variant->accept_type_quality = q; + variant->definite=variant->definite && q_definite; + + /* if the _best_ quality we got for this variant was 0.0, + * eliminate it now */ +} + +/* For a given variant, find the 'q' value of the charset given + * on the Accept-Charset line. If not charsets are listed, + * assume value of '1'. + */ + +void set_charset_quality(negotiation_state *neg, var_rec *variant) +{ + int i; + accept_rec *accept_recs = (accept_rec *)neg->accept_charsets->elts; + char *charset = variant->content_charset; + accept_rec *star = NULL; + + /* if no Accept-Charset: header, leave quality alone (will + * remain at the default value of 1) */ + if (!neg->accept_charsets || neg->accept_charsets->nelts == 0) + return; + + if (charset == NULL || !*charset) charset = "iso-8859-1"; + + /* + * Go through each of the items on the Accept-Charset: header, + * looking for a match with this variant's charset. If none + * match, charset is unacceptable, so set quality to 0. + */ + for (i = 0; i < neg->accept_charsets->nelts; ++i) { + + accept_rec *type = &accept_recs[i]; + + if (!strcmp(type->type_name, charset)) { + variant->charset_quality = type->quality; + return; + } else + if (strcmp(type->type_name, "*") == 0) { + star = type; + } + } + /* No explicit match */ + if (star) { + variant->charset_quality = star->quality; + return; + } + /* If this variant is in charset iso-8859-1, the default is 1.0 */ + if (strcmp(charset, "iso-8859-1") == 0) { + variant->charset_quality = 1.0; + } else { + variant->charset_quality = 0.0; + } +} + +/* For a given variant, find the best matching Accept: header + * and assign the Accept: header's quality value to the + * accept_type_quality field of the variant, for later use in + * determining the best matching variant. + */ + +/* is_identity_encoding is included for back-compat, but does anyone + * use 7bit, 8bin or binary in their var files?? + */ + +int is_identity_encoding (char *enc) +{ + return (!enc || !enc[0] || !strcmp (enc, "7bit") || !strcmp (enc, "8bit") + || !strcmp (enc, "binary")); +} + +void set_encoding_quality(negotiation_state *neg, var_rec *variant) +{ + int i; + accept_rec *accept_recs = (accept_rec *)neg->accept_encodings->elts; + char *enc = variant->content_encoding; + + if (!enc || is_identity_encoding(enc)) + return; + + + /* if no Accept: header, leave quality alone (will + * remain at the default value of 1) */ + if (neg->accept_encodings->nelts == 0) { + /* If we had an empty Accept-Encoding header, assume that + * no encodings are acceptable, else all encodings are ok */ + variant->encoding_quality = neg->have_accept_header ? 0 : 1; + return; + } + + /* Go through each of the encodings on the Accept-Encoding: header, + * looking for a match with our encoding + */ + for (i = 0; i < neg->accept_encodings->nelts; ++i) { + char *name = accept_recs[i].type_name; + + if (!strcmp(name, enc)) { + variant->encoding_quality = 1; + return; + } + } + + /* Encoding not found on Accept-Encoding: header, so it is + * _not_ acceptable */ + variant->encoding_quality = 0; +} + +/* Possible results of the network algorithm */ +enum algorithm_results { + na_not_applied = -1, /* net algorithm not used */ + na_choice = 1, /* choose variant */ + na_list /* list variants */ +}; + +/* + * This is a heavily-rewritten 'best_match' function. For a start, it + * now returns an int, which has one of the three values: na_not_applied, + * na_choice or na_list, which give the result of the network algorithm + * (if it was not applied, the return value is na_not_applied). + * The best variable is returned in *pbest. It also has two possible + * algorithms for determining the best match: the network algorithm, + * and the standard Apache algorithm. These are split out into + * separate functions (is_variant_better_na() and is_variant_better()). + * + * Previously, best_match iterated first through the content_types + * in the Accept: header, then checked each variant, and eliminated + * those that didn't match the variant's type. We cannot do this because + * we need full information, including language, charset, etc + * quality for _every_ variant, for the Alternates: header, + * and (possibly) the human-readable choice responses or 406 errors. + * + * After the 'best' (if any) is determined, the overall result of + * the negotiation is obtained. If the network algorithm was not + * in use, the result is na_not_applied. Else the result is + * na_list if 'short accept header' is in use, else na_list + * if _no_ best match was found, or na_choice if a best match + * was found. + */ + +/* Firstly, the negotiation 'network algorithm' from Holtman. + */ + +int is_variant_better_na(negotiation_state *neg, var_rec *variant, var_rec *best, float *p_bestq) +{ + float bestq = *p_bestq, q; + + /* Note: Encoding is not negotiated in the Holtman + * transparent neg draft, so we ignored it here. But + * it does mean we could return encodings the UA + * or proxy cannot handle. Eek. */ + + q = variant->accept_type_quality * + variant->type_quality * + variant->charset_quality * + variant->lang_quality; + +#ifdef NEG_DEBUG + fprintf(stderr, "Variant: file=%s type=%s lang=%s acceptq=%1.3f langq=%1.3f typeq=%1.3f q=%1.3f definite=%d\n", + variant->file_name ? variant->file_name : "", + variant->type_name ? variant->type_name : "", + variant->content_languages ? merge_string_array(neg->pool, variant->content_languages, ",") : "", + variant->accept_type_quality, + variant->lang_quality, + variant->type_quality, + q, + variant->definite + ); +#endif + + if (q > bestq) { + *p_bestq = q; + return 1; + } + if (q == bestq) { + /* If the best variant's charset is ISO-8859-1 and this variant has + the same charset quality, then we prefer this variant */ + if (variant->charset_quality == best->charset_quality && + (best->content_charset == NULL || *best->content_charset == 0 || + strcmp(best->content_charset, "iso-8859-1") == 0)) { + *p_bestq = q; + return 1; + } + } + return 0; +} + +/* Negotiation algorithm as used by previous versions of Apache + * (just about). + */ + +float is_variant_better(negotiation_state *neg, var_rec *variant, var_rec *best, float *p_bestq) +{ + float bestq = *p_bestq, q; + int levcmp; + + /* + * For non-transparent negotiation, server can choose how + * to handle the negotiation. We'll use the following in + * order: content-type, language, content-type level, charset, + * content length. + * + * For each check, we have three possible outcomes: + * This variant is worse than current best: return 0 + * This variant is better than the current best: + * assign this variant's q to *p_bestq, and return 1 + * This variant is just as desirable as the current best: + * drop through to the next test. + * + * This code is written in this long-winded way to allow future + * customisation, either by the addition of additional + * checks, or to allow the order of the checks to be determined + * by configuration options (e.g. we might prefer to check + * language quality _before_ content type). + */ + + /* First though, eliminate this variant if it is not + * acceptable by type, charset, encoding or language. + */ + + if (variant->encoding_quality == 0 || + variant->lang_quality == 0 || + variant->type_quality == 0 || + variant->charset_quality == 0 || + variant->accept_type_quality == 0) + return 0; /* don't consider unacceptables */ + + q = variant->accept_type_quality * variant->type_quality; + if (q == 0.0 || q < bestq) return 0; + if (q > bestq || !best) { + *p_bestq = q; + return 1; + } + + /* language */ + if (variant->lang_quality < best->lang_quality) + return 0; + if (variant->lang_quality > best->lang_quality) { + *p_bestq = q; + return 1; + } + + /* if language qualities were equal, try the LanguagePriority + * stuff */ + if (best->lang_index != -1 && variant->lang_index > best->lang_index) + return 0; + if (variant->lang_index != -1 && + (variant->lang_index < best->lang_index || best->lang_index == -1)) { + *p_bestq = q; + return 1; + } + + /* content-type level (text/html only?) */ + levcmp = level_cmp (variant, best); + if (levcmp == -1) return 0; + if (levcmp == 1) { + *p_bestq = q; + return 1; + } + + /* encoding -- can only be 1 or 0, and if 0 we eliminated this + * variant at the start of this function. However we + * prefer variants with no encoding over those with encoding */ + if (!*best->content_encoding && *variant->content_encoding) + return 0; + if (*best->content_encoding && !*variant->content_encoding) { + *p_bestq = q; + return 1; + } + + + /* charset */ + if (variant->charset_quality < best->charset_quality) + return 0; + /* If the best variant's charset is ISO-8859-1 and this variant has + the same charset quality, then we prefer this variant */ + if (variant->charset_quality > best->charset_quality || + (variant->charset_quality == best->charset_quality && + (best->content_charset == NULL || *best->content_charset == 0 || + strcmp(best->content_charset, "iso-8859-1") == 0))) { + *p_bestq = q; + return 1; + } + + + /* content length if all else equal */ + if (find_content_length(neg, variant) + >= + find_content_length(neg, best)) + return 0; + + /* ok, to get here means every thing turned out equal, except + * we have a shorter content length, so use this variant */ + *p_bestq = q; + return 1; +} + +int best_match(negotiation_state *neg, var_rec **pbest) +{ + int j; + var_rec *best = NULL; + float bestq = 0.0; + enum algorithm_results algorithm_result = na_not_applied; + + var_rec *avail_recs = (var_rec *)neg->avail_vars->elts; + + set_default_lang_quality(neg); + + /* + * Find the 'best' variant + */ + + for (j = 0; j < neg->avail_vars->nelts; ++j) { + + var_rec *variant = &avail_recs[j]; + + /* Find all the relevant 'quality' values from the + * Accept... headers, and store in the variant + */ + set_accept_quality(neg, variant); + set_language_quality(neg, variant); + set_encoding_quality(neg, variant); + set_charset_quality(neg, variant); + + /* Now find out if this variant is better than the current + * best, either using the network algorithm, or Apache's + * internal server-driven algorithm. Presumably other + * server-driven algorithms are possible, and could be + * implemented here. + */ + + if (neg->use_transparent_neg) { + if (is_variant_better_na(neg, variant, best, &bestq)) + best = variant; + } + else { + if (is_variant_better(neg, variant, best, &bestq)) + best = variant; + } + } + + /* We now either have a best variant, or no best variant + */ + if (neg->use_transparent_neg) { + if (neg->short_accept_headers) + algorithm_result = na_list; + else { + /* From Holtman, result is: + * If variant & URI are not neigbors, list_ua or list_os + * Else + * If UA can do trans neg + * IF best is definite && best q > 0, choice_ua + * ELSE list_ua + * ELSE + * IF best q > 0, choose_os + * ELSE list_os (or forward_os on proxy) + */ + + /* assume variant and URI are neigbors (since URI in + * var map must be in same directory) */ + + if(neg->use_transparent_neg) + algorithm_result = (best && best->definite) && (bestq>0) + ? na_choice : na_list; + else + algorithm_result = bestq>0 ? na_choice : na_list; + } + } + + *pbest = best; + return algorithm_result; +} + +/* + * Sets the Alternates and Vary headers, used if we are going to + * return 406 Not Acceptable status, a 300 Multiple Choice status, + * or a Choice response. + * + * 'type' is the result of the network algorithm, if applied. + * We do different things if the network algorithm was not applied + * (type == na_not_applied): no Alternates header, and Vary: + * does not include 'negotiate'. + * + * We should also add a max-age lifetime for the Alternates header, + * but how long we we give it? Presumably this should be + * configurable in the map file. + */ + +void set_neg_headers(request_rec *r, negotiation_state *neg, int na_result) +{ + int j; + var_rec *avail_recs = (var_rec *)neg->avail_vars->elts; + char *sample_type = NULL; + char *sample_language = NULL; + char *sample_encoding = NULL; + char *sample_charset = NULL; + int vary_by_type = 0; + int vary_by_language = 0; + int vary_by_charset = 0; + int vary_by_encoding = 0; + array_header *hdrs; + + /* Put headers into err_headers_out, new send_http_header() + * outputs both headers_out and err_headers_out */ + hdrs = r->err_headers_out; + + for (j = 0; j < neg->avail_vars->nelts; ++j) { + + var_rec *variant = &avail_recs[j]; + char *rec; + char qstr[6]; + long len; + char lenstr[22]; /* enough for 2^64 */ + + ap_snprintf(qstr, sizeof(qstr), "%1.3f", variant->type_quality); + + /* Strip trailing zeros (saves those valuable network bytes) */ + if (qstr[4] == '0') { + qstr[4] = '\0'; + if (qstr[3] == '0') { + qstr[3] = '\0'; + if (qstr[2] == '0') { + qstr[1] = '\0'; + } + } + } + + rec = pstrcat(r->pool, "{\"", variant->file_name, "\" ", qstr, NULL); + if (variant->type_name) { + if (*variant->type_name) + rec = pstrcat(r->pool, rec, " {type ", + variant->type_name, "}", NULL); + if (!sample_type) sample_type = variant->type_name; + else if (strcmp(sample_type, variant->type_name)) + vary_by_type = 1; + } + if (variant->content_languages && variant->content_languages->nelts) { + char *langs = + merge_string_array (r->pool, variant->content_languages, ","); + rec = pstrcat(r->pool, rec, " {language ", langs, "}", NULL); + if (!sample_language) sample_language = langs; + else if (strcmp(sample_language, langs)) + vary_by_language = 1; + } + if (variant->content_encoding) { + if (!sample_encoding) sample_encoding = variant->content_encoding; + else if (strcmp(sample_encoding, variant->content_encoding)) + vary_by_encoding = 1; + } + if (variant->content_charset) { + if (*variant->content_charset) + rec = pstrcat(r->pool, rec, " {charset ", + variant->content_charset, "}", NULL); + if (!sample_charset) sample_charset = variant->content_charset; + else if (strcmp(sample_charset, variant->content_charset)) + vary_by_charset = 1; + } + if ((len = find_content_length(neg, variant)) != 0) { + ap_snprintf(lenstr, sizeof(lenstr), "%ld", len); + rec = pstrcat(r->pool, rec, " {length ", lenstr, "}", NULL); + } + + rec = pstrcat(r->pool, rec, "}", NULL); + + if (na_result != na_not_applied) + table_merge(hdrs, "Alternates", rec); + } + + if (na_result != na_not_applied) + table_merge(hdrs, "Vary", "negotiate"); + if (vary_by_type) + table_merge(hdrs, "Vary", "accept"); + if (vary_by_language) + table_merge(hdrs, "Vary", "accept-language"); + if (vary_by_charset) + table_merge(hdrs, "Vary", "accept-charset"); + if (vary_by_encoding && na_result == na_not_applied) + table_merge(hdrs, "Vary", "accept-encoding"); +} + +/********************************************************************** + * + * Return an HTML list of variants. This is output as part of the + * 300 or 406 status body. + */ + +char *make_variant_list (request_rec *r, negotiation_state *neg) +{ + int i; + char *t; + + t = pstrdup(r->pool, "Available variants:\n
      \n"); + for (i = 0; i < neg->avail_vars->nelts; ++i) { + var_rec *variant = &((var_rec *)neg->avail_vars->elts)[i]; + char *filename = variant->file_name ? variant->file_name : ""; + array_header *languages = variant->content_languages; + char *description = variant->description ? variant->description : ""; + + /* The format isn't very neat, and it would be nice to make + * the tags human readable (eg replace 'language en' with + * 'English'). */ + t = pstrcat(r->pool, t, "
    • ", + filename, " ", description, NULL); + if (variant->type_name && *variant->type_name) + t = pstrcat(r->pool, t, ", type ", variant->type_name, NULL); + if (languages && languages->nelts) + t = pstrcat(r->pool, t, ", language ", + merge_string_array(r->pool, languages, ", "), + NULL); + if (variant->content_charset && *variant->content_charset) + t = pstrcat(r->pool, t, ", charset ", variant->content_charset, NULL); + t = pstrcat(r->pool, t, "\n", NULL); + } + t = pstrcat(r->pool, t, "
    \n", NULL); + + return t; +} + +void store_variant_list (request_rec *r, negotiation_state *neg) +{ + if (r->main == NULL) { + table_set (r->notes, "variant-list", make_variant_list (r, neg)); + } else { + table_set (r->main->notes, "variant-list", make_variant_list (r->main, neg)); + } +} + +/* Called if we got a "Choice" response from the network algorithm. + * It checks the result of the chosen variant to see if it + * is itself negotiated (if so, return error VARIANT_ALSO_VARIES). + * Otherwise, add the appropriate headers to the current response. + */ + +int setup_choice_response(request_rec *r, negotiation_state *neg, var_rec *variant) +{ + request_rec *sub_req; + char *sub_vary; + + if (!variant->sub_req) { + int status; + + sub_req = sub_req_lookup_file(variant->file_name, r); + status = sub_req->status; + if (status != HTTP_OK && status != HTTP_MULTIPLE_CHOICES) { + destroy_sub_req(sub_req); + return status; + } + variant->sub_req = sub_req; + } + else + sub_req = variant->sub_req; + + + /* The network algorithm told us to return a "Choice" + * response. This is the normal variant response, with + * some extra headers. First, ensure that the chosen + * variant did not itself return a "List" or "Choice" response. + * If not, set the appropriate headers, and fall through to + * the normal variant handling + */ + + if ((sub_req->status == HTTP_MULTIPLE_CHOICES) || + (table_get(sub_req->err_headers_out, "Alternates")) || + (table_get(sub_req->err_headers_out, "Content-Location"))) + return VARIANT_ALSO_VARIES; + + if ((sub_vary = table_get(sub_req->err_headers_out, "Vary")) != NULL) + table_set(r->err_headers_out, "Variant-Vary", sub_vary); + table_set(r->err_headers_out, "Content-Location", variant->file_name); + set_neg_headers(r, neg, na_choice); /* add Alternates and Vary */ + /* to do: add Expires */ + + return 0; +} + +/**************************************************************** + * + * Executive... + */ + +int handle_map_file (request_rec *r) +{ + negotiation_state *neg = parse_accept_headers (r); + var_rec *best; + int res; + int na_result; + + char *udir; + + if ((res = read_type_map (neg, r->filename))) return res; + + maybe_add_default_encodings(neg, 0); + + na_result = best_match(neg, &best); + + /* na_result is one of + * na_not_applied: we didn't use the network algorithm + * na_choice: return a "Choice" response + * na_list: return a "List" response (no variant chosen) + */ + + if (na_result == na_list) { + set_neg_headers(r, neg, na_list); + store_variant_list (r, neg); + return MULTIPLE_CHOICES; + } + + if (!best) { + log_reason ("no acceptable variant", r->filename, r); + + set_neg_headers(r, neg, na_result); + store_variant_list (r, neg); + return NOT_ACCEPTABLE; + } + + if (na_result == na_choice) + if ((res = setup_choice_response(r, neg, best)) != 0) + return res; + + /* Make sure caching works - Vary should handle HTTP/1.1, but for + * HTTP/1.0, we can't allow caching at all. NB that we merge the + * header in case some other module negotiates on something else. + */ + if (!do_cache_negotiated_docs(r->server) && (r->proto_num < 1001)) + r->no_cache = 1; + + if (na_result == na_not_applied) + set_neg_headers(r, neg, na_not_applied); + + if (r->path_info && *r->path_info) { + r->uri[find_path_info(r->uri, r->path_info)] = '\0'; + } + udir = make_dirstr (r->pool, r->uri, count_dirs (r->uri)); + udir = escape_uri(r->pool, udir); + internal_redirect(pstrcat(r->pool, udir, best->file_name, r->path_info, + NULL), r); + return OK; +} + +int handle_multi (request_rec *r) +{ + negotiation_state *neg; + var_rec *best, *avail_recs; + request_rec *sub_req; + int res; + int j; + int na_result; /* result of network algorithm */ + + if (r->finfo.st_mode != 0 || !(allow_options (r) & OPT_MULTI)) + return DECLINED; + + neg = parse_accept_headers (r); + + if ((res = read_types_multi (neg))) { +return_from_multi: + /* free all allocated memory from subrequests */ + avail_recs = (var_rec *)neg->avail_vars->elts; + for (j = 0; j < neg->avail_vars->nelts; ++j) { + var_rec *variant = &avail_recs[j]; + if (variant->sub_req) { + destroy_sub_req(variant->sub_req); + } + } + return res; + } + if (neg->avail_vars->nelts == 0) return DECLINED; + + maybe_add_default_encodings(neg, + r->method_number != M_GET + || r->args || r->path_info); + + na_result = best_match(neg, &best); + if (na_result == na_list) { + /* + * Network algorithm tols us to output a "List" response. + * This is output at a 300 status code, which we will + * return. The list of variants will be stored in r->notes + * under the name "variants-list". + */ + set_neg_headers(r, neg, na_list); /* set Alternates: and Vary: */ + + store_variant_list (r, neg); + res = MULTIPLE_CHOICES; + goto return_from_multi; + } + + if (!best) { + log_reason ("no acceptable variant", r->filename, r); + + set_neg_headers (r, neg, na_result); + store_variant_list (r, neg); + res = NOT_ACCEPTABLE; + goto return_from_multi; + } + + if (na_result == na_choice) + if ((res = setup_choice_response(r, neg, best)) != 0) { + goto return_from_multi; + } + + if (! (sub_req = best->sub_req)) { + /* We got this out of a map file, so we don't actually have + * a sub_req structure yet. Get one now. + */ + + sub_req = sub_req_lookup_file (best->file_name, r); + if (sub_req->status != HTTP_OK) { + res = sub_req->status; + destroy_sub_req(sub_req); + goto return_from_multi; + } + } + + /* BLETCH --- don't multi-resolve non-ordinary files */ + + if (!S_ISREG(sub_req->finfo.st_mode)) { + res = NOT_FOUND; + goto return_from_multi; + } + + /* Otherwise, use it. */ + + if (!do_cache_negotiated_docs(r->server) && (r->proto_num < 1001)) + r->no_cache = 1; + + if (na_result == na_not_applied) + set_neg_headers(r, neg, na_not_applied); + + r->filename = sub_req->filename; + r->handler = sub_req->handler; + r->content_type = sub_req->content_type; + r->content_encoding = sub_req->content_encoding; + r->content_languages = sub_req->content_languages; + r->content_language = sub_req->content_language; + r->finfo = sub_req->finfo; + r->per_dir_config = sub_req->per_dir_config; + /* copy output headers from subrequest, but leave negotiation headers */ + r->notes = overlay_tables(r->pool, sub_req->notes, r->notes); + r->headers_out = overlay_tables(r->pool, sub_req->headers_out, + r->headers_out); + r->err_headers_out = overlay_tables(r->pool, sub_req->err_headers_out, + r->err_headers_out); + r->subprocess_env = overlay_tables(r->pool, sub_req->subprocess_env, + r->subprocess_env); + avail_recs = (var_rec *)neg->avail_vars->elts; + for (j = 0; j < neg->avail_vars->nelts; ++j) { + var_rec *variant = &avail_recs[j]; + if (variant != best && variant->sub_req) { + destroy_sub_req(variant->sub_req); + } + } + return OK; +} + +handler_rec negotiation_handlers[] = { +{ MAP_FILE_MAGIC_TYPE, handle_map_file }, +{ "type-map", handle_map_file }, +{ NULL } +}; + +module negotiation_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + create_neg_dir_config, /* dir config creater */ + merge_neg_dir_configs, /* dir merger --- default is to override */ + NULL, /* server config */ + NULL, /* merge server config */ + negotiation_cmds, /* command table */ + negotiation_handlers, /* handlers */ + NULL, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + handle_multi, /* type_checker */ + NULL, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_rewrite.c b/APACHE_1_2_X/src/modules/standard/mod_rewrite.c new file mode 100644 index 00000000000..cb14372f98e --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_rewrite.c @@ -0,0 +1,3294 @@ + +/* ==================================================================== + * Copyright (c) 1996,1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + + +/* +** mod_rewrite.c -- The Main Module Code +** _ _ _ +** _ __ ___ ___ __| | _ __ _____ ___ __(_) |_ ___ +** | '_ ` _ \ / _ \ / _` | | '__/ _ \ \ /\ / / '__| | __/ _ \ +** | | | | | | (_) | (_| | | | | __/\ V V /| | | | || __/ +** |_| |_| |_|\___/ \__,_|___|_| \___| \_/\_/ |_| |_|\__\___| +** |_____| +** +** URL Rewriting Module, Version 3.0.5 (16-Apr-1997) +** +** This module uses a rule-based rewriting engine (based on a +** regular-expression parser) to rewrite requested URLs on the fly. +** +** It supports an unlimited number of additional rule conditions (which can +** operate on a lot of variables, even on HTTP headers) for granular +** matching and even external database lookups (either via plain text +** tables, DBM hash files or even external processes) for advanced URL +** substitution. +** +** It operates on the full URLs (including the PATH_INFO part) both in +** per-server context (httpd.conf) and per-dir context (.htaccess) and even +** can generate QUERY_STRING parts on result. The rewriting result finally +** can lead to internal subprocessing, external request redirection or even +** to internal proxy throughput. +** +** The documentation and latest release can be found on +** http://www.engelschall.com/sw/mod_rewrite/ +** +** Copyright (c) 1996-1997 Ralf S. Engelschall, All rights reserved. +** +** Written for The Apache Group by +** Ralf S. Engelschall +** rse@engelschall.com +** www.engelschall.com +*/ + + + + + /* from the underlaying Unix system ... */ +#include +#include +#include +#include +#include +#include +#include +#include + + /* from the Apache server ... */ +#include "httpd.h" +#include "http_config.h" +#include "http_request.h" +#include "http_core.h" +#include "http_log.h" + + /* now our own stuff ... */ +#include "mod_rewrite.h" + + + + +/* +** +-------------------------------------------------------+ +** | | +** | static module configuration +** | | +** +-------------------------------------------------------+ +*/ + + +/* +** +** our interface to the Apache server kernel +** +** keep in mind: +** +** o Runtime logic of a request is as following: +** +** while(request or subrequest) { +** foreach(stage #1...#9) { +** foreach(module) { (**) +** try to run hook +** } +** } +** } +** +** o the order of modules at (**) is the inverted order as +** given in the "Configuration" file, i.e. the last module +** specified is the first one called for each hook! +** The core module is always the last! +** +** o there are two different types of result checking and +** continue processing: +** for hook #1,#4,#5,#6,#8: +** hook run loop stops on first modules which gives +** back a result != DECLINED, i.e. it usually returns OK +** which says "OK, module has handled this _stage_" and for #1 +** this have not to mean "Ok, the filename is now valid". +** for hook #2,#3,#7,#9: +** all hooks are run, independend of result +** +** o at the last stage, the core module always +** - says "BAD_REQUEST" if r->filename does not begin with "/" +** - prefix URL with document_root or replaced server_root +** with document_root and sets r->filename +** - always return a "OK" independed if the file really exists +** or not! +** +*/ + + /* the table of commands we provide */ +static command_rec command_table[] = { + { "RewriteEngine", cmd_rewriteengine, NULL, OR_FILEINFO, FLAG, + "On or Off to enable or disable (default) the whole rewriting engine" }, + { "RewriteOptions", cmd_rewriteoptions, NULL, OR_FILEINFO, ITERATE, + "List of option strings to set" }, + { "RewriteBase", cmd_rewritebase, NULL, OR_FILEINFO, TAKE1, + "the base URL of the per-directory context" }, + { "RewriteCond", cmd_rewritecond, NULL, OR_FILEINFO, RAW_ARGS, + "a input string and a to be applied regexp-pattern" }, + { "RewriteRule", cmd_rewriterule, NULL, OR_FILEINFO, RAW_ARGS, + "a URL-applied regexp-pattern and a substitution URL" }, + { "RewriteMap", cmd_rewritemap, NULL, RSRC_CONF, TAKE2, + "a mapname and a filename" }, + { "RewriteLog", cmd_rewritelog, NULL, RSRC_CONF, TAKE1, + "the filename of the rewriting logfile" }, + { "RewriteLogLevel", cmd_rewriteloglevel, NULL, RSRC_CONF, TAKE1, + "the level of the rewriting logfile verbosity (0=none, 1=std, .., 9=max)" }, + { NULL } +}; + + /* the table of content handlers we provide */ +static handler_rec handler_table[] = { + { "redirect-handler", handler_redirect }, + { NULL } +}; + + /* the main config structure */ +module rewrite_module = { + STANDARD_MODULE_STUFF, + + init_module, /* module initializer */ + + config_perdir_create, /* create per-dir config structures */ + config_perdir_merge, /* merge per-dir config structures */ + config_server_create, /* create per-server config structures */ + config_server_merge, /* merge per-server config structures */ + command_table, /* table of config file commands */ + + handler_table, /* [#8] table of MIME-typed-dispatched request action handlers */ + + hook_uri2file, /* [#1] URI to filename translation */ + + NULL, /* [#4] check_user_id: get and validate user id from the HTTP request */ + NULL, /* [#5] check_auth: check if the user is ok _here_ */ + NULL, /* [#2] check_access: check access by host address, etc. */ + + hook_mimetype, /* [#6] determine MIME type */ + + hook_fixup, /* [#7] pre-run fixups */ + NULL, /* [#9] log a transaction */ + NULL /* [#3] header parser */ +}; + + /* the cache */ +cache *cachep; + + /* whether proxy module is available or not */ +static int proxy_available; + + /* the txt mapfile parsing stuff */ +#define MAPFILE_PATTERN "^([^ \t]+)[ \t]+([^ \t]+).*$" +#define MAPFILE_OUTPUT "$1,$2" +static regex_t *lookup_map_txtfile_regexp = NULL; +static regmatch_t lookup_map_txtfile_regmatch[10]; + + + + +/* +** +-------------------------------------------------------+ +** | | +** | configuration directive handling +** | | +** +-------------------------------------------------------+ +*/ + + +/* +** +** per-server configuration structure handling +** +*/ + +static void *config_server_create(pool *p, server_rec *s) +{ + rewrite_server_conf *a; + + a = (rewrite_server_conf *)pcalloc(p, sizeof(rewrite_server_conf)); + + a->state = ENGINE_DISABLED; + a->options = OPTION_NONE; + a->rewritelogfile = NULL; + a->rewritelogfp = -1; + a->rewriteloglevel = 1; + a->rewritemaps = make_array(p, 2, sizeof(rewritemap_entry)); + a->rewriteconds = make_array(p, 2, sizeof(rewritecond_entry)); + a->rewriterules = make_array(p, 2, sizeof(rewriterule_entry)); + + return (void *)a; +} + +static void *config_server_merge(pool *p, void *basev, void *overridesv) +{ + rewrite_server_conf *a, *base, *overrides; + + a = (rewrite_server_conf *)pcalloc(p, sizeof(rewrite_server_conf)); + base = (rewrite_server_conf *)basev; + overrides = (rewrite_server_conf *)overridesv; + + a->state = overrides->state; + a->options = overrides->options; + a->rewritelogfile = base->rewritelogfile != NULL ? base->rewritelogfile : overrides->rewritelogfile; + a->rewritelogfp = base->rewritelogfp != -1 ? base->rewritelogfp : overrides->rewritelogfp; + a->rewriteloglevel = overrides->rewriteloglevel; + + if (a->options & OPTION_INHERIT) { + a->rewritemaps = append_arrays(p, overrides->rewritemaps, base->rewritemaps); + a->rewriteconds = append_arrays(p, overrides->rewriteconds, base->rewriteconds); + a->rewriterules = append_arrays(p, overrides->rewriterules, base->rewriterules); + } + else { + a->rewritemaps = overrides->rewritemaps; + a->rewriteconds = overrides->rewriteconds; + a->rewriterules = overrides->rewriterules; + } + + return (void *)a; +} + + +/* +** +** per-directory configuration structure handling +** +*/ + +static void *config_perdir_create(pool *p, char *path) +{ + rewrite_perdir_conf *a; + + a = (rewrite_perdir_conf *)pcalloc(p, sizeof(rewrite_perdir_conf)); + + a->state = ENGINE_DISABLED; + a->options = OPTION_NONE; + a->baseurl = NULL; + a->rewriteconds = make_array(p, 2, sizeof(rewritecond_entry)); + a->rewriterules = make_array(p, 2, sizeof(rewriterule_entry)); + + if (path == NULL) + a->directory = NULL; + else { + /* make sure it has a trailing slash */ + if (path[strlen(path)-1] == '/') + a->directory = pstrdup(p, path); + else + a->directory = pstrcat(p, path, "/", NULL); + } + + return (void *)a; +} + +static void *config_perdir_merge(pool *p, void *basev, void *overridesv) +{ + rewrite_perdir_conf *a, *base, *overrides; + + a = (rewrite_perdir_conf *)pcalloc(p, sizeof(rewrite_perdir_conf)); + base = (rewrite_perdir_conf *)basev; + overrides = (rewrite_perdir_conf *)overridesv; + + a->state = overrides->state; + a->options = overrides->options; + a->directory = overrides->directory; + a->baseurl = overrides->baseurl; + + if (a->options & OPTION_INHERIT) { + a->rewriteconds = append_arrays(p, overrides->rewriteconds, base->rewriteconds); + a->rewriterules = append_arrays(p, overrides->rewriterules, base->rewriterules); + } + else { + a->rewriteconds = overrides->rewriteconds; + a->rewriterules = overrides->rewriterules; + } + + return (void *)a; +} + + +/* +** +** the configuration commands +** +*/ + +static const char *cmd_rewriteengine(cmd_parms *cmd, rewrite_perdir_conf *dconf, int flag) +{ + rewrite_server_conf *sconf; + + sconf = (rewrite_server_conf *)get_module_config(cmd->server->module_config, &rewrite_module); + if (cmd->path == NULL) /* is server command */ + sconf->state = (flag ? ENGINE_ENABLED : ENGINE_DISABLED); + else /* is per-directory command */ + dconf->state = (flag ? ENGINE_ENABLED : ENGINE_DISABLED); + + return NULL; +} + +static const char *cmd_rewriteoptions(cmd_parms *cmd, rewrite_perdir_conf *dconf, char *option) +{ + rewrite_server_conf *sconf; + const char *err; + + sconf = (rewrite_server_conf *)get_module_config(cmd->server->module_config, &rewrite_module); + if (cmd->path == NULL) /* is server command */ + err = cmd_rewriteoptions_setoption(cmd->pool, &(sconf->options), option); + else /* is per-directory command */ + err = cmd_rewriteoptions_setoption(cmd->pool, &(dconf->options), option); + + return err; +} + +static const char *cmd_rewriteoptions_setoption(pool *p, int *options, char *name) +{ + if (strcasecmp(name, "inherit") == 0) + *options |= OPTION_INHERIT; + else + return pstrcat(p, "RewriteOptions: unknown option '", name, "'\n", NULL); + return NULL; +} + +static const char *cmd_rewritelog(cmd_parms *cmd, void *dconf, char *a1) +{ + rewrite_server_conf *sconf; + + sconf = (rewrite_server_conf *)get_module_config(cmd->server->module_config, &rewrite_module); + sconf->rewritelogfile = a1; + + return NULL; +} + +static const char *cmd_rewriteloglevel(cmd_parms *cmd, void *dconf, char *a1) +{ + rewrite_server_conf *sconf; + + sconf = (rewrite_server_conf *)get_module_config(cmd->server->module_config, &rewrite_module); + sconf->rewriteloglevel = atoi(a1); + + return NULL; +} + +static const char *cmd_rewritemap(cmd_parms *cmd, void *dconf, char *a1, char *a2) +{ + rewrite_server_conf *sconf; + rewritemap_entry *new; + struct stat st; + + sconf = (rewrite_server_conf *)get_module_config(cmd->server->module_config, &rewrite_module); + new = push_array(sconf->rewritemaps); + + new->name = a1; + if (strncmp(a2, "txt:", 4) == 0) { + new->type = MAPTYPE_TXT; + new->datafile = a2+4; + new->checkfile = a2+4; + } + else if (strncmp(a2, "dbm:", 4) == 0) { +#ifdef HAS_NDBM_LIB + new->type = MAPTYPE_DBM; + new->datafile = a2+4; + new->checkfile = pstrcat(cmd->pool, a2+4, NDBM_FILE_SUFFIX, NULL); +#else + return pstrdup(cmd->pool, "RewriteMap: cannot use NDBM mapfile, because no NDBM support compiled in"); +#endif + } + else if (strncmp(a2, "prg:", 4) == 0) { + new->type = MAPTYPE_PRG; + new->datafile = a2+4; + new->checkfile = a2+4; + } + else { + new->type = MAPTYPE_TXT; + new->datafile = a2; + new->checkfile = a2; + } + new->fpin = 0; + new->fpout = 0; + + if (new->checkfile) + if (stat(new->checkfile, &st) == -1) + return pstrcat(cmd->pool, "RewriteMap: map file or program not found:", new->checkfile, NULL); + + return NULL; +} + +static const char *cmd_rewritebase(cmd_parms *cmd, rewrite_perdir_conf *dconf, char *a1) +{ + if (cmd->path == NULL || dconf == NULL) + return "RewriteBase: only valid in per-directory config files"; + if (a1[0] != '/') + return "RewriteBase: argument is not a valid URL"; + if (a1[0] == '\0') + return "RewriteBase: empty URL not allowed"; + + dconf->baseurl = pstrdup(cmd->pool, a1); + + return NULL; +} + +static const char *cmd_rewritecond(cmd_parms *cmd, rewrite_perdir_conf *dconf, char *str) +{ + rewrite_server_conf *sconf; + rewritecond_entry *new; + regex_t *regexp; + char *a1; + char *a2; + char *a3; + char *cp; + const char *err; + int rc; + + sconf = (rewrite_server_conf *)get_module_config(cmd->server->module_config, &rewrite_module); + + /* make a new entry in the internal temporary rewrite rule list */ + if (cmd->path == NULL) /* is server command */ + new = push_array(sconf->rewriteconds); + else /* is per-directory command */ + new = push_array(dconf->rewriteconds); + + /* parse the argument line ourself */ + if (parseargline(str, &a1, &a2, &a3)) + return pstrcat(cmd->pool, "RewriteCond: bad argument line '", str, "'\n", NULL); + + /* arg1: the input string */ + new->input = pstrdup(cmd->pool, a1); + + /* arg3: optional flags field + (this have to be first parsed, because we need to + know if the regex should be compiled with ICASE!) */ + new->flags = CONDFLAG_NONE; + if (a3 != NULL) { + if ((err = cmd_rewritecond_parseflagfield(cmd->pool, new, a3)) != NULL) + return err; + } + + /* arg2: the pattern + try to compile the regexp to test if is ok */ + cp = a2; + if (cp[0] == '!') { + new->flags |= CONDFLAG_NOTMATCH; + cp++; + } + + /* now be careful: Under the POSIX regex library + we can compile the pattern for case-insensitive matching, + under the old V8 library we have to do it self via a hack */ + if (new->flags & CONDFLAG_NOCASE) + rc = ((regexp = pregcomp(cmd->pool, cp, REG_EXTENDED|REG_ICASE)) == NULL); + else + rc = ((regexp = pregcomp(cmd->pool, cp, REG_EXTENDED)) == NULL); + if (rc) + return pstrcat(cmd->pool, "RewriteCond: cannot compile regular expression '", a2, "'\n", NULL); + new->pattern = pstrdup(cmd->pool, cp); + new->regexp = regexp; + + return NULL; +} + +static const char *cmd_rewritecond_parseflagfield(pool *p, rewritecond_entry *cfg, char *str) +{ + char *cp; + char *cp1; + char *cp2; + char *cp3; + char *key; + char *val; + const char *err; + + if (str[0] != '[' || str[strlen(str)-1] != ']') + return pstrdup(p, "RewriteCond: bad flag delimiters"); + + cp = str+1; + str[strlen(str)-1] = ','; /* for simpler parsing */ + for ( ; *cp != '\0'; ) { + /* skip whitespaces */ + for ( ; (*cp == ' ' || *cp == '\t') && *cp != '\0'; cp++) + ; + if (*cp == '\0') + break; + cp1 = cp; + if ((cp2 = strchr(cp, ',')) != NULL) { + cp = cp2+1; + for ( ; (*(cp2-1) == ' ' || *(cp2-1) == '\t'); cp2--) + ; + *cp2 = '\0'; + if ((cp3 = strchr(cp1, '=')) != NULL) { + *cp3 = '\0'; + key = cp1; + val = cp3+1; + } + else { + key = cp1; + val = ""; + } + if ((err = cmd_rewritecond_setflag(p, cfg, key, val)) != NULL) + return err; + } + else + break; + } + + return NULL; +} + +static const char *cmd_rewritecond_setflag(pool *p, rewritecond_entry *cfg, char *key, char *val) +{ + if ( strcasecmp(key, "nocase") == 0 + || strcasecmp(key, "NC") == 0 ) { + cfg->flags |= CONDFLAG_NOCASE; + } + else if ( strcasecmp(key, "ornext") == 0 + || strcasecmp(key, "OR") == 0 ) { + cfg->flags |= CONDFLAG_ORNEXT; + } + else { + return pstrcat(p, "RewriteCond: unknown flag '", key, "'\n", NULL); + } + return NULL; +} + +/* NON static */ +const char *cmd_rewriterule(cmd_parms *cmd, rewrite_perdir_conf *dconf, char *str) +{ + rewrite_server_conf *sconf; + rewriterule_entry *new; + regex_t *regexp; + char *a1; + char *a2; + char *a3; + char *cp; + const char *err; + + sconf = (rewrite_server_conf *)get_module_config(cmd->server->module_config, &rewrite_module); + + /* make a new entry in the internal rewrite rule list */ + if (cmd->path == NULL) /* is server command */ + new = push_array(sconf->rewriterules); + else /* is per-directory command */ + new = push_array(dconf->rewriterules); + + /* parse the argument line ourself */ + if (parseargline(str, &a1, &a2, &a3)) + return pstrcat(cmd->pool, "RewriteRule: bad argument line '", str, "'\n", NULL); + + /* arg1: the pattern + try to compile the regexp to test if is ok */ + new->flags = RULEFLAG_NONE; + cp = a1; + if (cp[0] == '!') { + new->flags |= RULEFLAG_NOTMATCH; + cp++; + } + if ((regexp = pregcomp(cmd->pool, cp, REG_EXTENDED)) == NULL) + return pstrcat(cmd->pool, "RewriteRule: cannot compile regular expression '", a1, "'\n", NULL); + new->pattern = pstrdup(cmd->pool, cp); + new->regexp = regexp; + + /* arg2: the output string + replace the $ by \ which is needed by the currently + used Regular Expression library */ + new->output = pstrdup(cmd->pool, a2); + + /* arg3: optional flags field */ + new->forced_mimetype = NULL; + new->forced_responsecode = HTTP_MOVED_TEMPORARILY; + new->env[0] = NULL; + new->skip = 0; + if (a3 != NULL) { + if ((err = cmd_rewriterule_parseflagfield(cmd->pool, new, a3)) != NULL) + return err; + } + + /* now, if the server or per-dir config holds an + array of RewriteCond entries, we take it for us + and clear the array */ + if (cmd->path == NULL) { /* is server command */ + new->rewriteconds = sconf->rewriteconds; + sconf->rewriteconds = make_array(cmd->pool, 2, sizeof(rewritecond_entry)); + } + else { /* is per-directory command */ + new->rewriteconds = dconf->rewriteconds; + dconf->rewriteconds = make_array(cmd->pool, 2, sizeof(rewritecond_entry)); + } + + return NULL; +} + +static const char *cmd_rewriterule_parseflagfield(pool *p, rewriterule_entry *cfg, char *str) +{ + char *cp; + char *cp1; + char *cp2; + char *cp3; + char *key; + char *val; + const char *err; + + if (str[0] != '[' || str[strlen(str)-1] != ']') + return pstrdup(p, "RewriteRule: bad flag delimiters"); + + cp = str+1; + str[strlen(str)-1] = ','; /* for simpler parsing */ + for ( ; *cp != '\0'; ) { + /* skip whitespaces */ + for ( ; (*cp == ' ' || *cp == '\t') && *cp != '\0'; cp++) + ; + if (*cp == '\0') + break; + cp1 = cp; + if ((cp2 = strchr(cp, ',')) != NULL) { + cp = cp2+1; + for ( ; (*(cp2-1) == ' ' || *(cp2-1) == '\t'); cp2--) + ; + *cp2 = '\0'; + if ((cp3 = strchr(cp1, '=')) != NULL) { + *cp3 = '\0'; + key = cp1; + val = cp3+1; + } + else { + key = cp1; + val = ""; + } + if ((err = cmd_rewriterule_setflag(p, cfg, key, val)) != NULL) + return err; + } + else + break; + } + + return NULL; +} + +static const char *cmd_rewriterule_setflag(pool *p, rewriterule_entry *cfg, char *key, char *val) +{ + int status = 0; + int i; + + if ( strcasecmp(key, "redirect") == 0 + || strcasecmp(key, "R") == 0 ) { + cfg->flags |= RULEFLAG_FORCEREDIRECT; + if (strlen(val) > 0) { + if (strcasecmp(val, "permanent") == 0) + status = HTTP_MOVED_PERMANENTLY; + else if (strcasecmp(val, "temp") == 0) + status = HTTP_MOVED_TEMPORARILY; + else if (strcasecmp(val, "seeother") == 0) + status = HTTP_SEE_OTHER; + else if (isdigit(*val)) + status = atoi(val); + if (!is_HTTP_REDIRECT(status)) + return pstrdup(p, "RewriteRule: invalid HTTP response code for flag 'R'"); + cfg->forced_responsecode = status; + } + } + else if ( strcasecmp(key, "last") == 0 + || strcasecmp(key, "L") == 0 ) { + cfg->flags |= RULEFLAG_LASTRULE; + } + else if ( strcasecmp(key, "next") == 0 + || strcasecmp(key, "N") == 0 ) { + cfg->flags |= RULEFLAG_NEWROUND; + } + else if ( strcasecmp(key, "chain") == 0 + || strcasecmp(key, "C") == 0 ) { + cfg->flags |= RULEFLAG_CHAIN; + } + else if ( strcasecmp(key, "type") == 0 + || strcasecmp(key, "T") == 0 ) { + cfg->forced_mimetype = pstrdup(p, val); + } + else if ( strcasecmp(key, "env") == 0 + || strcasecmp(key, "E") == 0 ) { + for (i = 0; (cfg->env[i] != NULL) && (i < MAX_ENV_FLAGS); i++) + ; + if (i < MAX_ENV_FLAGS) { + cfg->env[i] = pstrdup(p, val); + cfg->env[i+1] = NULL; + } + else + return pstrdup(p, "RewriteRule: to much environment flags 'E'"); + } + else if ( strcasecmp(key, "nosubreq") == 0 + || strcasecmp(key, "NS") == 0 ) { + cfg->flags |= RULEFLAG_IGNOREONSUBREQ; + } + else if ( strcasecmp(key, "proxy") == 0 + || strcasecmp(key, "P") == 0 ) { + cfg->flags |= RULEFLAG_PROXY; + } + else if ( strcasecmp(key, "passthrough") == 0 + || strcasecmp(key, "PT") == 0 ) { + cfg->flags |= RULEFLAG_PASSTHROUGH; + } + else if ( strcasecmp(key, "skip") == 0 + || strcasecmp(key, "S") == 0 ) { + cfg->skip = atoi(val); + } + else if ( strcasecmp(key, "forbidden") == 0 + || strcasecmp(key, "F") == 0 ) { + cfg->flags |= RULEFLAG_FORBIDDEN; + } + else if ( strcasecmp(key, "gone") == 0 + || strcasecmp(key, "G") == 0 ) { + cfg->flags |= RULEFLAG_GONE; + } + else { + return pstrcat(p, "RewriteRule: unknown flag '", key, "'\n", NULL); + } + return NULL; +} + + +/* +** +** module initialisation +** [called from read_config() after all +** config commands were already called] +** +*/ + +static void init_module(server_rec *s, pool *p) +{ + /* step through the servers and + - open eachs rewriting logfile + - open the RewriteMap prg:xxx programs */ + for (; s; s = s->next) { + open_rewritelog(s, p); + run_rewritemap_programs(s, p); + } + + /* create the lookup cache */ + cachep = init_cache(p); + + /* check if proxy module is available */ + proxy_available = is_proxy_available(s); + + /* precompile a static pattern + for the txt mapfile parsing */ + lookup_map_txtfile_regexp = pregcomp(p, MAPFILE_PATTERN, REG_EXTENDED); +} + + + + +/* +** +-------------------------------------------------------+ +** | | +** | runtime hooks +** | | +** +-------------------------------------------------------+ +*/ + + +/* +** +** URI-to-filename hook +** +** [used for the rewriting engine triggered by +** the per-server 'RewriteRule' directives] +** +*/ + +static int hook_uri2file(request_rec *r) +{ + void *sconf; + rewrite_server_conf *conf; + char *var; + char *thisserver, *thisport, *thisurl; + char buf[512]; + char docroot[512]; + char *cp, *cp2; + struct stat finfo; + int n; + int l; + + /* + * retrieve the config structures + */ + sconf = r->server->module_config; + conf = (rewrite_server_conf *)get_module_config(sconf, &rewrite_module); + + /* + * only do something under runtime if the engine is really enabled, + * else return immediately! + */ + if (conf->state == ENGINE_DISABLED) + return DECLINED; + + /* + * add the SCRIPT_URL variable to the env. this is a bit complicated + * due to the fact that apache uses subrequests and internal redirects + */ + + if (r->main == NULL) { + var = pstrcat(r->pool, "REDIRECT_", ENVVAR_SCRIPT_URL, NULL); + var = table_get(r->subprocess_env, var); + if (var == NULL) + table_set(r->subprocess_env, ENVVAR_SCRIPT_URL, pstrdup(r->pool, r->uri)); + else + table_set(r->subprocess_env, ENVVAR_SCRIPT_URL, pstrdup(r->pool, var)); + } + else { + var = table_get(r->main->subprocess_env, ENVVAR_SCRIPT_URL); + table_set(r->subprocess_env, ENVVAR_SCRIPT_URL, pstrdup(r->pool, var)); + } + + /* + * create the SCRIPT_URI variable for the env + */ + + /* add the canonical URI of this URL */ + thisserver = r->server->server_hostname; +#ifdef APACHE_SSL + if (((!r->connection->client->ssl) && (r->server->port == DEFAULT_PORT)) || + ((r->connection->client->ssl) && (r->server->port == 443))) +#else + if (r->server->port == DEFAULT_PORT) +#endif + thisport = ""; + else { + ap_snprintf(buf, sizeof(buf), ":%u", r->server->port); + thisport = pstrdup(r->pool, buf); + } + thisurl = table_get(r->subprocess_env, ENVVAR_SCRIPT_URL); + + /* set the variable */ +#ifdef APACHE_SSL + var = pstrcat(r->pool, http_method(r), "://", thisserver, thisport, thisurl, NULL); +#else + var = pstrcat(r->pool, "http://", thisserver, thisport, thisurl, NULL); +#endif + table_set(r->subprocess_env, ENVVAR_SCRIPT_URI, pstrdup(r->pool, var)); + + + /* if filename was not initially set, + we start with the requested URI */ + if (r->filename == NULL) { + r->filename = pstrdup(r->pool, r->uri); + rewritelog(r, 2, "init rewrite engine with requested uri %s", r->filename); + } + + /* + * now apply the rules ... + */ + if (apply_rewrite_list(r, conf->rewriterules, NULL)) { + + if (strlen(r->filename) > 6 && + strncmp(r->filename, "proxy:", 6) == 0) { + /* it should be go on as an internal proxy request */ + + /* check if the proxy module is enabled, so + we can actually use it! */ + if (!proxy_available) + return FORBIDDEN; + + /* make sure the QUERY_STRING and + PATH_INFO parts get incorporated */ + r->filename = pstrcat(r->pool, r->filename, + r->path_info ? r->path_info : "", + r->args ? "?" : NULL, r->args, + NULL); + + /* now make sure the request gets handled by the + proxy handler */ + r->proxyreq = 1; + r->handler = "proxy-server"; + + rewritelog(r, 1, "go-ahead with proxy request %s [OK]", r->filename); + return OK; + } + else if ( (strlen(r->filename) > 7 && + strncmp(r->filename, "http://", 7) == 0) + || (strlen(r->filename) > 8 && + strncmp(r->filename, "https://", 8) == 0) + || (strlen(r->filename) > 9 && + strncmp(r->filename, "gopher://", 9) == 0) + || (strlen(r->filename) > 6 && + strncmp(r->filename, "ftp://", 6) == 0) ) { + /* it was finally rewritten to a remote URL */ + + /* skip 'scheme:' */ + for (cp = r->filename; *cp != ':' && *cp != '\0'; cp++) + ; + /* skip '://' */ + cp += 3; + /* skip host part */ + for ( ; *cp != '/' && *cp != '\0'; cp++) + ; + if (*cp != '\0') { + rewritelog(r, 1, "escaping %s for redirect", r->filename); + cp2 = escape_uri(r->pool, cp); + *cp = '\0'; + r->filename = pstrcat(r->pool, r->filename, cp2, NULL); + } + + /* append the QUERY_STRING part */ + if (r->args != NULL) + r->filename = pstrcat(r->pool, r->filename, "?", r->args, NULL); + + /* determine HTTP redirect response code */ + if (is_HTTP_REDIRECT(r->status)) { + n = r->status; + r->status = HTTP_OK; /* make Apache kernel happy */ + } + else + n = REDIRECT; + + /* now do the redirection */ + table_set(r->headers_out, "Location", r->filename); + rewritelog(r, 1, "redirect to %s [REDIRECT/%d]", r->filename, n); + return n; + } + else if (strlen(r->filename) > 10 && + strncmp(r->filename, "forbidden:", 10) == 0) { + /* This URLs is forced to be forbidden for the requester */ + return FORBIDDEN; + } + else if (strlen(r->filename) > 5 && + strncmp(r->filename, "gone:", 5) == 0) { + /* This URLs is forced to be gone */ + return HTTP_GONE; + } + else if (strlen(r->filename) > 12 && + strncmp(r->filename, "passthrough:", 12) == 0) { + /* Hack because of underpowered API: passing the current + rewritten filename through to other URL-to-filename handlers + just as it were the requested URL. This is to enable + post-processing by mod_alias, etc. which always act on + r->uri! The difference here is: We do not try to + add the document root */ + r->uri = pstrdup(r->pool, r->filename+12); + return DECLINED; + } + else { + /* it was finally rewritten to a local path */ + + /* expand "/~user" prefix */ + r->filename = expand_tildepaths(r, r->filename); + + rewritelog(r, 2, "local path result: %s", r->filename); + + /* the filename has to start with a slash! */ + if (r->filename[0] != '/') + return BAD_REQUEST; + + /* if there is no valid prefix, we have + to emulate the translator from the core and + prefix the filename with document_root + + NOTICE: + We cannot leave out the prefix_stat because + - when we always prefix with document_root + then no absolute path can be created, e.g. via + emulating a ScriptAlias directive, etc. + - when we always NOT prefix with document_root + then the files under document_root have to + be references directly and document_root + gets never used and will be a dummy parameter - + this is also bad + + BUT: + Under real Unix systems this is no problem, + because we only do stat() on the first directory + and this gets cached by the kernel for along time! + */ + n = prefix_stat(r->filename, &finfo); + if (n == 0) { + if ((cp = document_root(r)) != NULL) { + strncpy(docroot, cp, sizeof(docroot)-1); + EOS_PARANOIA(docroot); + + /* always NOT have a trailing slash */ + l = strlen(docroot); + if (docroot[l-1] == '/') { + docroot[l-1] = '\0'; + } + if (r->server->path && !strncmp(r->filename, r->server->path, r->server->pathlen)) + r->filename = pstrcat(r->pool, docroot, (r->filename + r->server->pathlen), NULL); + else + r->filename = pstrcat(r->pool, docroot, r->filename, NULL); + rewritelog(r, 2, "prefixed with document_root to %s", r->filename); + } + } + + rewritelog(r, 1, "go-ahead with %s [OK]", r->filename); + return OK; + } + } + else { + rewritelog(r, 1, "pass through %s", r->filename); + return DECLINED; + } +} + + +/* +** +** MIME-type hook +** +** [used to support the forced-MIME-type feature] +** +*/ + +static int hook_mimetype(request_rec *r) +{ + char *t; + + /* now check if we have to force a MIME-type */ + t = table_get(r->notes, REWRITE_FORCED_MIMETYPE_NOTEVAR); + if (t == NULL) + return DECLINED; + else { + rewritelog(r, 1, "force filename %s to have MIME-type '%s'", r->filename, t); + r->content_type = t; + return OK; + } +} + + +/* +** +** Fixup hook +** +** [used for the rewriting engine triggered by +** the per-directory 'RewriteRule' directives] +** +*/ + +static int hook_fixup(request_rec *r) +{ + rewrite_perdir_conf *dconf; + char *cp; + char *cp2; + char *prefix; + int l; + int n; + + dconf = (rewrite_perdir_conf *)get_module_config(r->per_dir_config, &rewrite_module); + + /* if there is no per-dir config we return immediately */ + if (dconf == NULL) + return DECLINED; + + /* we shouldn't do anything in subrequests */ + if (r->main != NULL) + return DECLINED; + + /* if there are no real (i.e. no RewriteRule directives!) + per-dir config of us, we return also immediately */ + if (dconf->directory == NULL) + return DECLINED; + + /* + * only do something under runtime if the engine is really enabled, + * for this directory, else return immediately! + */ + if (!(allow_options(r) & (OPT_SYM_LINKS | OPT_SYM_OWNER))) { + /* FollowSymLinks is mandatory! */ + log_reason("Options FollowSymLinks or SymLinksIfOwnerMatch is off which implies that RewriteRule directive is forbidden", r->filename, r); + return FORBIDDEN; + } + else { + /* FollowSymLinks is given, but the user can + still turn off the rewriting engine */ + if (dconf->state == ENGINE_DISABLED) + return DECLINED; + } + + /* + * now apply the rules ... + */ + if (apply_rewrite_list(r, dconf->rewriterules, dconf->directory)) { + + if (strlen(r->filename) > 6 && + strncmp(r->filename, "proxy:", 6) == 0) { + /* it should go on as an internal proxy request */ + + /* make sure the QUERY_STRING and + PATH_INFO parts get incorporated */ + r->filename = pstrcat(r->pool, r->filename, + /* r->path_info was already + appended by the rewriting engine + because of the per-dir context! */ + r->args ? "?" : NULL, r->args, + NULL); + + /* now make sure the request gets handled by the + proxy handler */ + r->proxyreq = 1; + r->handler = "proxy-server"; + + rewritelog(r, 1, "[per-dir %s] go-ahead with proxy request %s [OK]", dconf->directory, r->filename); + return OK; + } + else if ( (strlen(r->filename) > 7 && + strncmp(r->filename, "http://", 7) == 0) + || (strlen(r->filename) > 8 && + strncmp(r->filename, "https://", 8) == 0) + || (strlen(r->filename) > 9 && + strncmp(r->filename, "gopher://", 9) == 0) + || (strlen(r->filename) > 6 && + strncmp(r->filename, "ftp://", 6) == 0) ) { + /* it was finally rewritten to a remote URL */ + + /* because we are in a per-dir context + first try to replace the directory with its base-URL + if there is a base-URL available */ + if (dconf->baseurl != NULL) { + /* skip 'scheme:' */ + for (cp = r->filename; *cp != ':' && *cp != '\0'; cp++) + ; + /* skip '://' */ + cp += 3; + if ((cp = strchr(cp, '/')) != NULL) { + rewritelog(r, 2, "[per-dir %s] trying to replace prefix %s with %s", dconf->directory, dconf->directory, dconf->baseurl); + cp2 = subst_prefix_path(r, cp, dconf->directory, dconf->baseurl); + if (strcmp(cp2, cp) != 0) { + *cp = '\0'; + r->filename = pstrcat(r->pool, r->filename, cp2, NULL); + } + } + } + + /* now prepare the redirect... */ + + /* skip 'scheme:' */ + for (cp = r->filename; *cp != ':' && *cp != '\0'; cp++) + ; + /* skip '://' */ + cp += 3; + /* skip host part */ + for ( ; *cp != '/' && *cp != '\0'; cp++) + ; + if (*cp != '\0') { + rewritelog(r, 1, "[per-dir %s] escaping %s for redirect", dconf->directory, r->filename); + cp2 = escape_uri(r->pool, cp); + *cp = '\0'; + r->filename = pstrcat(r->pool, r->filename, cp2, NULL); + } + + /* append the QUERY_STRING part */ + if (r->args != NULL) + r->filename = pstrcat(r->pool, r->filename, "?", r->args, NULL); + + /* determine HTTP redirect response code */ + if (is_HTTP_REDIRECT(r->status)) { + n = r->status; + r->status = HTTP_OK; /* make Apache kernel happy */ + } + else + n = REDIRECT; + + /* now do the redirection */ + table_set(r->headers_out, "Location", r->filename); + rewritelog(r, 1, "[per-dir %s] redirect to %s [REDIRECT/%d]", dconf->directory, r->filename, n); + return n; + } + else if (strlen(r->filename) > 10 && + strncmp(r->filename, "forbidden:", 10) == 0) { + /* This URLs is forced to be forbidden for the requester */ + return FORBIDDEN; + } + else if (strlen(r->filename) > 5 && + strncmp(r->filename, "gone:", 5) == 0) { + /* This URLs is forced to be gone */ + return HTTP_GONE; + } + else { + /* it was finally rewritten to a local path */ + + /* if someone used the PASSTHROUGH flag in per-dir + context we just ignore it. It is only useful + in per-server context */ + if (strlen(r->filename) > 12 && + strncmp(r->filename, "passthrough:", 12) == 0) { + r->filename = pstrdup(r->pool, r->filename+12); + } + + /* the filename has to start with a slash! */ + if (r->filename[0] != '/') + return BAD_REQUEST; + + /* if there is a valid base-URL then substitute + the per-dir prefix with this base-URL if the + current filename still is inside this per-dir + context. If not then treat the result as a + plain URL */ + if (dconf->baseurl != NULL) { + rewritelog(r, 2, "[per-dir %s] trying to replace prefix %s with %s", dconf->directory, dconf->directory, dconf->baseurl); + r->filename = subst_prefix_path(r, r->filename, dconf->directory, dconf->baseurl); + } + else { + /* if no explicit base-URL exists we assume + that the directory prefix is also a valid URL + for this webserver and only try to remove the + document_root if it is prefix */ + + if ((cp = document_root(r)) != NULL) { + prefix = pstrdup(r->pool, cp); + /* always NOT have a trailing slash */ + l = strlen(prefix); + if (prefix[l-1] == '/') { + prefix[l-1] = '\0'; + l--; + } + if (strncmp(r->filename, prefix, l) == 0) { + rewritelog(r, 2, "[per-dir %s] strip document_root prefix: %s -> %s", dconf->directory, r->filename, r->filename+l); + r->filename = pstrdup(r->pool, r->filename+l); + } + } + } + + /* now initiate the internal redirect */ + rewritelog(r, 1, "[per-dir %s] internal redirect with %s [INTERNAL REDIRECT]", dconf->directory, r->filename); + r->filename = pstrcat(r->pool, "redirect:", r->filename, NULL); + r->handler = "redirect-handler"; + return OK; + } + } + else { + rewritelog(r, 1, "[per-dir %s] pass through %s", dconf->directory, r->filename); + return DECLINED; + } +} + + +/* +** +** Content-Handlers +** +** [used for redirect support] +** +*/ + +static int handler_redirect(request_rec *r) +{ + /* just make sure that we are really meant! */ + if (strncmp(r->filename, "redirect:", 9) != 0) + return DECLINED; + + /* now do the internal redirect */ + internal_redirect(pstrcat(r->pool, r->filename+9, + r->args ? "?" : NULL, r->args, NULL), r); + + /* and return gracefully */ + return OK; +} + + + + +/* +** +-------------------------------------------------------+ +** | | +** | rewriting engine +** | | +** +-------------------------------------------------------+ +*/ + + +static int apply_rewrite_list(request_rec *r, array_header *rewriterules, char *perdir) +{ + rewriterule_entry *entries; + rewriterule_entry *p; + int i; + int changed; + int rc; + int s; + + entries = (rewriterule_entry *)rewriterules->elts; + changed = 0; + loop: + for (i = 0; i < rewriterules->nelts; i++) { + p = &entries[i]; + + /* ignore this rule on subrequests if we are explicitly asked to do so + or this is a proxy throughput or a forced redirect rule */ + if (r->main != NULL && + (p->flags & RULEFLAG_IGNOREONSUBREQ || + p->flags & RULEFLAG_PROXY || + p->flags & RULEFLAG_FORCEREDIRECT )) + continue; + + /* apply the current rule */ + rc = apply_rewrite_rule(r, p, perdir); + if (rc) { + if (rc != 2) /* not a match-only rule */ + changed = 1; + if (p->flags & RULEFLAG_PASSTHROUGH) { + rewritelog(r, 2, "forcing '%s' to get passed through to next URI-to-filename handler", r->filename); + r->filename = pstrcat(r->pool, "passthrough:", r->filename, NULL); + changed = 1; + break; + } + if (p->flags & RULEFLAG_FORBIDDEN) { + rewritelog(r, 2, "forcing '%s' to be forbidden", r->filename); + r->filename = pstrcat(r->pool, "forbidden:", r->filename, NULL); + changed = 1; + break; + } + if (p->flags & RULEFLAG_GONE) { + rewritelog(r, 2, "forcing '%s' to be gone", r->filename); + r->filename = pstrcat(r->pool, "gone:", r->filename, NULL); + changed = 1; + break; + } + if (p->flags & RULEFLAG_PROXY) + break; + if (p->flags & RULEFLAG_LASTRULE) + break; + if (p->flags & RULEFLAG_NEWROUND) + goto loop; + + /* if we are forced to skip N next rules, do it now */ + if (p->skip > 0) { + s = p->skip; + while ( i < rewriterules->nelts + && s > 0) { + i++; + p = &entries[i]; + s--; + } + } + } + else { + /* if current rule is chained with next rule(s), + skip all this next rule(s) */ + while ( i < rewriterules->nelts + && p->flags & RULEFLAG_CHAIN) { + i++; + p = &entries[i]; + } + } + } + return changed; +} + +static int apply_rewrite_rule(request_rec *r, rewriterule_entry *p, char *perdir) +{ + char *uri; + char *output; + int flags; + char newuri[MAX_STRING_LEN]; + char env[MAX_STRING_LEN]; + char port[32]; + char env2[MAX_STRING_LEN]; + regex_t *regexp; + regmatch_t regmatch[10]; + int rc; + int prefixstrip; + int i; + int failed; + array_header *rewriteconds; + rewritecond_entry *conds; + rewritecond_entry *c; + + uri = r->filename; + regexp = p->regexp; + output = p->output; + flags = p->flags; + + if (perdir != NULL && r->path_info != NULL && r->path_info[0] != '\0') { + rewritelog(r, 3, "[per-dir %s] add path-info postfix: %s -> %s%s", perdir, uri, uri, r->path_info); + uri = pstrcat(r->pool, uri, r->path_info, NULL); + } + + prefixstrip = 0; + if (perdir != NULL) { + /* this is a per-directory match */ + if ( strlen(uri) >= strlen(perdir) + && strncmp(uri, perdir, strlen(perdir)) == 0) { + rewritelog(r, 3, "[per-dir %s] strip per-dir prefix: %s -> %s", perdir, uri, uri+strlen(perdir)); + uri = uri+strlen(perdir); + prefixstrip = 1; + } + } + + if (perdir != NULL) + rewritelog(r, 3, "[per-dir %s] applying pattern '%s' to uri '%s'", perdir, p->pattern, uri); + + rc = (regexec(regexp, uri, regexp->re_nsub+1, regmatch, 0) == 0); /* try to match the pattern */ + if (( rc && !(p->flags & RULEFLAG_NOTMATCH)) || + (!rc && (p->flags & RULEFLAG_NOTMATCH)) ) { + + /* ok, the pattern matched, but we now additionally have to check + for any preconditions which have to be also true. We do this + at this very late stage to avoid unnessesary checks which + slow down the rewriting engine!! */ + rewriteconds = p->rewriteconds; + conds = (rewritecond_entry *)rewriteconds->elts; + failed = 0; + for (i = 0; i < rewriteconds->nelts; i++) { + c = &conds[i]; + rc = apply_rewrite_cond(r, c, perdir); + if (c->flags & CONDFLAG_ORNEXT) { + /* there is a "or" flag */ + if (rc == 0) { + /* one cond is false, but another can be true... */ + continue; + } + else { + /* one true cond is enough, so skip the other conds + of the "ornext" chained conds */ + while ( i < rewriteconds->nelts + && c->flags & CONDFLAG_ORNEXT) { + i++; + c = &conds[i]; + } + continue; + } + } + else { + /* no "or" flag, so a single fail means total fail */ + if (rc == 0) { /* failed */ + failed = 1; + break; + } + } + } + if (failed) + return 0; /* if any condition fails this complete rule fails */ + + /* if this is a pure matching rule we return immediately */ + if (strcmp(output, "-") == 0) + return 2; + + /* if this is a forced proxy request ... */ + if (p->flags & RULEFLAG_PROXY) { + if (p->flags & RULEFLAG_NOTMATCH) { + output = pstrcat(r->pool, "proxy:", output, NULL); + strncpy(newuri, output, sizeof(newuri)-1); + EOS_PARANOIA(newuri); + expand_variables_inbuffer(r, newuri, sizeof(newuri));/* expand %{...} */ + expand_map_lookups(r, newuri, sizeof(newuri)); /* expand ${...} */ + } + else { + output = pstrcat(r->pool, "proxy:", output, NULL); + strncpy(newuri, pregsub(r->pool, output, uri, regexp->re_nsub+1, regmatch), sizeof(newuri)-1); /* substitute in output */ + EOS_PARANOIA(newuri); + for (i = 0; p->env[i] != NULL; i++) { + strncpy(env2, p->env[i], sizeof(env2)-1); + EOS_PARANOIA(env2); + strncpy(env, pregsub(r->pool, env2, uri, regexp->re_nsub+1, regmatch), sizeof(env)-1); /* substitute in output */ + EOS_PARANOIA(env); + add_env_variable(r, env); + } + expand_variables_inbuffer(r, newuri, sizeof(newuri)); /* expand %{...} */ + expand_map_lookups(r, newuri, sizeof(newuri)); /* expand ${...} */ + } + if (perdir == NULL) + rewritelog(r, 2, "rewrite %s -> %s", r->filename, newuri); + else + rewritelog(r, 2, "[per-dir %s] rewrite %s -> %s", perdir, r->filename, newuri); + r->filename = pstrdup(r->pool, newuri); + return 1; + } + + /* if this is a implicit redirect in a per-dir rule */ + i = strlen(output); + if (perdir != NULL + && ( (i > 7 && strncmp(output, "http://", 7) == 0) + || (i > 8 && strncmp(output, "https://", 8) == 0) + || (i > 9 && strncmp(output, "gopher://", 9) == 0) + || (i > 6 && strncmp(output, "ftp://", 6) == 0) ) ) { + if (p->flags & RULEFLAG_NOTMATCH) { + strncpy(newuri, output, sizeof(newuri)-1); + EOS_PARANOIA(newuri); + expand_variables_inbuffer(r, newuri, sizeof(newuri));/* expand %{...} */ + expand_map_lookups(r, newuri, sizeof(newuri)); /* expand ${...} */ + } + else { + strncpy(newuri, pregsub(r->pool, output, uri, regexp->re_nsub+1, regmatch), sizeof(newuri)-1); /* substitute in output */ + EOS_PARANOIA(newuri); + for (i = 0; p->env[i] != NULL; i++) { + strncpy(env2, p->env[i], sizeof(env2)-1); + EOS_PARANOIA(env2); + strncpy(env, pregsub(r->pool, env2, uri, regexp->re_nsub+1, regmatch), sizeof(env)-1); /* substitute in output */ + EOS_PARANOIA(env); + add_env_variable(r, env); + } + expand_variables_inbuffer(r, newuri, sizeof(newuri));/* expand %{...} */ + expand_map_lookups(r, newuri, sizeof(newuri)); /* expand ${...} */ + } + rewritelog(r, 2, "[per-dir %s] redirect %s -> %s", perdir, r->filename, newuri); + r->filename = pstrdup(r->pool, newuri); + return 1; + } + + /* add the previously stripped perdir prefix + if the new URI is not a new one (i.e. + prefixed by a slash which means that is + no for this per-dir context) */ + if (prefixstrip && output[0] != '/') { + rewritelog(r, 3, "[per-dir %s] add per-dir prefix: %s -> %s%s", perdir, output, perdir, output); + output = pstrcat(r->pool, perdir, output, NULL); + } + + if (p->flags & RULEFLAG_NOTMATCH) { + /* just overtake the URI */ + strncpy(newuri, output, sizeof(newuri)-1); + EOS_PARANOIA(newuri); + } + else { + /* substitute in output */ + strncpy(newuri, pregsub(r->pool, output, uri, regexp->re_nsub+1, regmatch), sizeof(newuri)-1); /* substitute in output */ + EOS_PARANOIA(newuri); + for (i = 0; p->env[i] != NULL; i++) { + strncpy(env2, p->env[i], sizeof(env2)-1); + EOS_PARANOIA(env2); + strncpy(env, pregsub(r->pool, env2, uri, regexp->re_nsub+1, regmatch), sizeof(env)-1); /* substitute in output */ + EOS_PARANOIA(env); + add_env_variable(r, env); + } + } + expand_variables_inbuffer(r, newuri, sizeof(newuri)); /* expand %{...} */ + expand_map_lookups(r, newuri, sizeof(newuri)); /* expand ${...} */ + + if (perdir == NULL) + rewritelog(r, 2, "rewrite %s -> %s", uri, newuri); + else + rewritelog(r, 2, "[per-dir %s] rewrite %s -> %s", perdir, uri, newuri); + + r->filename = pstrdup(r->pool, newuri); + + /* reduce http[s]://[:] */ + reduce_uri(r); + + /* split out on-the-fly generated QUERY_STRING '....?xxxxx&xxxx...' */ + splitout_queryargs(r); + + /* if a MIME-type should be later forced for this URL, then remember this */ + if (p->forced_mimetype != NULL) { + table_set(r->notes, REWRITE_FORCED_MIMETYPE_NOTEVAR, p->forced_mimetype); + if (perdir == NULL) + rewritelog(r, 2, "remember %s to have MIME-type '%s'", r->filename, p->forced_mimetype); + else + rewritelog(r, 2, "[per-dir %s] remember %s to have MIME-type '%s'", perdir, r->filename, p->forced_mimetype); + } + + /* if we are forced to do a explicit redirect by [R] flag + and the current URL still is not a fully qualified one we + finally prefix it with http[s]:// explicitly */ + if (flags & RULEFLAG_FORCEREDIRECT) { + if ( !(strlen(r->filename) > 7 && + strncmp(r->filename, "http://", 7) == 0) + && !(strlen(r->filename) > 8 && + strncmp(r->filename, "https://", 8) == 0) + && !(strlen(r->filename) > 9 && + strncmp(r->filename, "gopher://", 9) == 0) + && !(strlen(r->filename) > 6 && + strncmp(r->filename, "ftp://", 6) == 0) ) { + +#ifdef APACHE_SSL + if ((!r->connection->client->ssl && r->server->port == DEFAULT_PORT) || + ( r->connection->client->ssl && r->server->port == 443) ) +#else + if (r->server->port == DEFAULT_PORT) +#endif + port[0] = '\0'; + else + ap_snprintf(port, sizeof(port), ":%u", r->server->port); + if (r->filename[0] == '/') +#ifdef APACHE_SSL + ap_snprintf(newuri, sizeof(newuri), "%s://%s%s%s", http_method(r), r->server->server_hostname, port, r->filename); +#else + ap_snprintf(newuri, sizeof(newuri), "http://%s%s%s", r->server->server_hostname, port, r->filename); +#endif + else +#ifdef APACHE_SSL + ap_snprintf(newuri, sizeof(newuri), "%s://%s%s/%s", http_method(r), r->server->server_hostname, port, r->filename); +#else + ap_snprintf(newuri, sizeof(newuri), "http://%s%s/%s", r->server->server_hostname, port, r->filename); +#endif + if (perdir == NULL) + rewritelog(r, 2, "prepare forced redirect %s -> %s", r->filename, newuri); + else + rewritelog(r, 2, "[per-dir %s] prepare forced redirect %s -> %s", perdir, r->filename, newuri); + r->filename = pstrdup(r->pool, newuri); + r->status = p->forced_responsecode; + return 1; + } + } + + return 1; + } + return 0; +} + +static int apply_rewrite_cond(request_rec *r, rewritecond_entry *p, char *perdir) +{ + char *input; + int rc; + struct stat sb; + request_rec *rsub; + + /* first, we have to expand the input string to match */ + input = expand_variables(r, p->input); + + rc = 0; + if (strcmp(p->pattern, "-f") == 0) { + if (stat(input, &sb) == 0) + if (S_ISREG(sb.st_mode)) + rc = 1; + } + else if (strcmp(p->pattern, "-s") == 0) { + if (stat(input, &sb) == 0) + if (S_ISREG(sb.st_mode) && sb.st_size > 0) + rc = 1; + } + else if (strcmp(p->pattern, "-l") == 0) { +#ifndef __EMX__ +/* OS/2 dosen't support links. */ + if (stat(input, &sb) == 0) + if (S_ISLNK(sb.st_mode)) + rc = 1; +#endif + } + else if (strcmp(p->pattern, "-d") == 0) { + if (stat(input, &sb) == 0) + if (S_ISDIR(sb.st_mode)) + rc = 1; + } + else if (strcmp(p->pattern, "-U") == 0) { + /* avoid infinite subrequest recursion */ + if (strlen(input) > 0 /* nonempty path, and */ + && ( r->main == NULL /* - either not in a subrequest */ + || ( r->main->uri != NULL /* - or in a subrequest...*/ + && r->uri != NULL /* ...and then URIs aren't NULL... */ + /* ...and sub and main URIs differ */ + && strcmp(r->main->uri, r->uri) != 0) ) ) { + + /* run a URI-based subrequest */ + rsub = sub_req_lookup_uri(input, r); + + /* URI exists for any result up to 3xx, redirects allowed */ + if (rsub->status < 400) + rc = 1; + + /* log it */ + rewritelog(r, 5, "RewriteCond URI (-U) check: path=%s -> status=%d", input, rsub->status); + + /* cleanup by destroying the subrequest */ + destroy_sub_req(rsub); + } + } + else if (strcmp(p->pattern, "-F") == 0) { + /* avoid infinite subrequest recursion */ + if (strlen(input) > 0 /* nonempty path, and */ + && ( r->main == NULL /* - either not in a subrequest */ + || ( r->main->uri != NULL /* - or in a subrequest...*/ + && r->uri != NULL /* ...and then URIs aren't NULL... */ + /* ...and sub and main URIs differ */ + && strcmp(r->main->uri, r->uri) != 0) ) ) { + + /* process a file-based subrequest: + this differs from -U in that no path translation is done. */ + rsub = sub_req_lookup_file(input, r); + + /* file exists for any result up to 2xx, no redirects */ + if (rsub->status < 300 && + /* double-check that file exists since default result is 200 */ + stat(rsub->filename, &sb) == 0) + rc = 1; + + /* log it */ + rewritelog(r, 5, "RewriteCond file (-F) check: path=%s -> file=%s status=%d", input, rsub->filename, rsub->status); + + /* cleanup by destroying the subrequest */ + destroy_sub_req(rsub); + } + } + else if (strlen(p->pattern) > 1 && *(p->pattern) == '>') { + rc = (compare_lexicography(input, p->pattern+1) == 1 ? 1 : 0); + } + else if (strlen(p->pattern) > 1 && *(p->pattern) == '<') { + rc = (compare_lexicography(input, p->pattern+1) == -1 ? 1 : 0); + } + else if (strlen(p->pattern) > 1 && *(p->pattern) == '=') { + rc = (strcmp(input, p->pattern+1) == 0 ? 1 : 0); + } + else { + /* it is really a regexp pattern, so apply it */ + rc = (regexec(p->regexp, input, 0, NULL, 0) == 0); + } + + /* if this is a non-matching regexp, just negate the result */ + if (p->flags & CONDFLAG_NOTMATCH) + rc = !rc; + + rewritelog(r, 4, "RewriteCond: input='%s' pattern='%s' => %s", input, p->pattern, rc ? "matched" : "not-matched"); + + /* end just return the result */ + return rc; +} + + + + +/* +** +-------------------------------------------------------+ +** | | +** | URL transformation functions +** | | +** +-------------------------------------------------------+ +*/ + + +/* +** +** split out a QUERY_STRING part from +** the current URI string +** +*/ + +static void splitout_queryargs(request_rec *r) +{ + char *q; + char *olduri; + + q = strchr(r->filename, '?'); + if (q != NULL) { + olduri = pstrdup(r->pool, r->filename); + *q++ = '\0'; + r->args = pstrcat(r->pool, q, "&", r->args, NULL); + if (r->args[strlen(r->args)-1] == '&') + r->args[strlen(r->args)-1] = '\0'; + rewritelog(r, 3, "split uri=%s -> uri=%s, args=%s", olduri, r->filename, r->args); + } + return; +} + + +/* +** +** strip 'http[s]://ourhost/' from URI +** +*/ + +static void reduce_uri(request_rec *r) +{ + char *cp; + unsigned short port; + char *portp; + char *hostp; + char *url; + char c; + char host[LONG_STRING_LEN]; + char buf[MAX_STRING_LEN]; + char *olduri; + +#ifdef APACHE_SSL + if ( (!r->connection->client->ssl && + strncmp(r->filename, "http://", 7) == 0) + || (r->connection->client->ssl && + strncmp(r->filename, "https://", 8) == 0)) { +#else + if (strncmp(r->filename, "http://", 7) == 0) { +#endif + /* there was really a rewrite to a remote path */ + + olduri = pstrdup(r->pool, r->filename); /* save for logging */ + + /* cut the hostname and port out of the URI */ +#ifdef APACHE_SSL + strncpy(buf, r->filename+strlen(http_method(r))+3, sizeof(buf)-1); +#else + strncpy(buf, r->filename+7, sizeof(buf)-1); +#endif + EOS_PARANOIA(buf); + hostp = buf; + for (cp = hostp; *cp != '\0' && *cp != '/' && *cp != ':'; cp++) + ; + if (*cp == ':') { + /* set host */ + *cp++ = '\0'; + strncpy(host, hostp, sizeof(host)-1); + EOS_PARANOIA(host); + /* set port */ + portp = cp; + for (; *cp != '\0' && *cp != '/'; cp++) + ; + c = *cp; + *cp = '\0'; + port = atoi(portp); + *cp = c; + /* set remaining url */ + url = cp; + } + else if (*cp == '/') { + /* set host */ + *cp = '\0'; + strncpy(host, hostp, sizeof(host)-1); + EOS_PARANOIA(host); + *cp = '/'; + /* set port */ + port = DEFAULT_PORT; + /* set remaining url */ + url = cp; + } + else { + /* set host */ + strncpy(host, hostp, sizeof(host)-1); + EOS_PARANOIA(host); + /* set port */ + port = DEFAULT_PORT; + /* set remaining url */ + url = "/"; + } + + /* now check whether we could reduce it to a local path... */ + if (is_this_our_host(r, host) && port == r->server->port) { + /* this is our host, so only the URL remains */ + r->filename = pstrdup(r->pool, url); + rewritelog(r, 3, "reduce %s -> %s", olduri, r->filename); + } + } + return; +} + + +/* +** +** Expand tilde-paths (~user) through +** Unix /etc/passwd database information +** +*/ + +static char *expand_tildepaths(request_rec *r, char *uri) +{ + char user[LONG_STRING_LEN]; + struct passwd *pw; + char *newuri; + int i, j; + + newuri = uri; + if (uri != NULL && strlen(uri) > 2 && uri[0] == '/' && uri[1] == '~') { + /* cut out the username */ + for (j = 0, i = 2; j < sizeof(user)-1 && uri[i] != '\0' && + ( (uri[i] >= '0' && uri[i] <= '9') + || (uri[i] >= 'a' && uri[i] <= 'z') + || (uri[i] >= 'A' && uri[i] <= 'Z')); ) + user[j++] = uri[i++]; + user[j] = '\0'; + + /* lookup username in systems passwd file */ + if ((pw = getpwnam(user)) != NULL) { + /* ok, user was found, so expand the ~user string */ + if (uri[i] != '\0') { + /* ~user/anything... has to be expanded */ + if (pw->pw_dir[strlen(pw->pw_dir)-1] == '/') + pw->pw_dir[strlen(pw->pw_dir)-1] = '\0'; + newuri = pstrcat(r->pool, pw->pw_dir, uri+i, NULL); + } + else { + /* only ~user has to be expanded */ + newuri = pstrdup(r->pool, pw->pw_dir); + } + } + } + return newuri; +} + + +/* +** +** mapfile expansion support +** i.e. expansion of MAP lookup directives +** ${:} in RewriteRule rhs +** +*/ + +#define limit_length(n) (n > LONG_STRING_LEN-1 ? LONG_STRING_LEN-1 : n) + +static void expand_map_lookups(request_rec *r, char *uri, int uri_len) +{ + char newuri[MAX_STRING_LEN]; + char *cpI; + char *cpIE; + char *cpO; + char *cpT; + char *cpT2; + char mapname[LONG_STRING_LEN]; + char mapkey[LONG_STRING_LEN]; + char defaultvalue[LONG_STRING_LEN]; + int n; + + cpI = uri; + cpIE = cpI+strlen(cpI); + cpO = newuri; + while (cpI < cpIE) { + if (cpI+6 < cpIE && strncmp(cpI, "${", 2) == 0) { + /* missing delimiter -> take it as plain text */ + if ( strchr(cpI+2, ':') == NULL + || strchr(cpI+2, '}') == NULL) { + memcpy(cpO, cpI, 2); + cpO += 2; + cpI += 2; + continue; + } + cpI += 2; + + cpT = strchr(cpI, ':'); + n = cpT-cpI; + memcpy(mapname, cpI, limit_length(n)); + mapname[limit_length(n)] = '\0'; + cpI += n+1; + + cpT2 = strchr(cpI, '|'); + cpT = strchr(cpI, '}'); + if (cpT2 != NULL && cpT2 < cpT) { + n = cpT2-cpI; + memcpy(mapkey, cpI, limit_length(n)); + mapkey[limit_length(n)] = '\0'; + cpI += n+1; + + n = cpT-cpI; + memcpy(defaultvalue, cpI, limit_length(n)); + defaultvalue[limit_length(n)] = '\0'; + cpI += n+1; + } + else { + n = cpT-cpI; + memcpy(mapkey, cpI, limit_length(n)); + mapkey[limit_length(n)] = '\0'; + cpI += n+1; + + defaultvalue[0] = '\0'; + } + + cpT = lookup_map(r, mapname, mapkey); + if (cpT != NULL) { + n = strlen(cpT); + if (cpO + n >= newuri + sizeof(newuri)) { + log_printf(r->server, "insufficient space in expand_map_lookups, aborting"); + return; + } + memcpy(cpO, cpT, n); + cpO += n; + } + else { + n = strlen(defaultvalue); + if (cpO + n >= newuri + sizeof(newuri)) { + log_printf(r->server, "insufficient space in expand_map_lookups, aborting"); + return; + } + memcpy(cpO, defaultvalue, n); + cpO += n; + } + } + else { + cpT = strstr(cpI, "${"); + if (cpT == NULL) + cpT = cpI+strlen(cpI); + n = cpT-cpI; + if (cpO + n >= newuri + sizeof(newuri)) { + log_printf(r->server, "insufficient space in expand_map_lookups, aborting"); + return; + } + memcpy(cpO, cpI, n); + cpO += n; + cpI += n; + } + } + *cpO = '\0'; + strncpy(uri, newuri, uri_len-1); + uri[uri_len-1] = '\0'; + return; +} + +#undef limit_length + + + +/* +** +-------------------------------------------------------+ +** | | +** | DBM hashfile support +** | | +** +-------------------------------------------------------+ +*/ + + +static char *lookup_map(request_rec *r, char *name, char *key) +{ + void *sconf; + rewrite_server_conf *conf; + array_header *rewritemaps; + rewritemap_entry *entries; + rewritemap_entry *s; + char *value; + struct stat st; + int i; + + /* get map configuration */ + sconf = r->server->module_config; + conf = (rewrite_server_conf *)get_module_config(sconf, &rewrite_module); + rewritemaps = conf->rewritemaps; + + entries = (rewritemap_entry *)rewritemaps->elts; + for (i = 0; i < rewritemaps->nelts; i++) { + s = &entries[i]; + if (strcmp(s->name, name) == 0) { + if (s->type == MAPTYPE_TXT) { + stat(s->checkfile, &st); /* existence was checked at startup! */ + value = get_cache_string(cachep, s->name, CACHEMODE_TS, st.st_mtime, key); + if (value == NULL) { + rewritelog(r, 6, "cache lookup FAILED, forcing new map lookup"); + if ((value = lookup_map_txtfile(r, s->datafile, key)) != NULL) { + rewritelog(r, 5, "map lookup OK: map=%s key=%s[txt] -> val=%s", s->name, key, value); + set_cache_string(cachep, s->name, CACHEMODE_TS, st.st_mtime, key, value); + return value; + } + else { + rewritelog(r, 5, "map lookup FAILED: map=%s[txt] key=%s", s->name, key); + return NULL; + } + } + else { + rewritelog(r, 5, "cache lookup OK: map=%s[txt] key=%s -> val=%s", s->name, key, value); + return value; + } + } + else if (s->type == MAPTYPE_DBM) { +#if HAS_NDBM_LIB + stat(s->checkfile, &st); /* existence was checked at startup! */ + value = get_cache_string(cachep, s->name, CACHEMODE_TS, st.st_mtime, key); + if (value == NULL) { + rewritelog(r, 6, "cache lookup FAILED, forcing new map lookup"); + if ((value = lookup_map_dbmfile(r, s->datafile, key)) != NULL) { + rewritelog(r, 5, "map lookup OK: map=%s[dbm] key=%s -> val=%s", s->name, key, value); + set_cache_string(cachep, s->name, CACHEMODE_TS, st.st_mtime, key, value); + return value; + } + else { + rewritelog(r, 5, "map lookup FAILED: map=%s[dbm] key=%s", s->name, key); + return NULL; + } + } + else { + rewritelog(r, 5, "cache lookup OK: map=%s[dbm] key=%s -> val=%s", s->name, key, value); + return value; + } +#else + return NULL; +#endif + } + else if (s->type == MAPTYPE_PRG) { + if ((value = lookup_map_program(r, s->fpin, s->fpout, key)) != NULL) { + rewritelog(r, 5, "map lookup OK: map=%s key=%s -> val=%s", s->name, key, value); + return value; + } + else { + rewritelog(r, 5, "map lookup FAILED: map=%s key=%s", s->name, key); + } + } + } + } + return NULL; +} + + +static char *lookup_map_txtfile(request_rec *r, char *file, char *key) +{ + FILE *fp = NULL; + char line[1024]; + char output[1024]; + char result[1024]; + char *value = NULL; + char *cpT; + char *curkey; + char *curval; + + if ((fp = pfopen(r->pool, file, "r")) == NULL) + return NULL; + + strncpy(output, MAPFILE_OUTPUT, sizeof(output)-1); + EOS_PARANOIA(output); + while (fgets(line, sizeof(line), fp) != NULL) { + if (line[strlen(line)-1] == '\n') + line[strlen(line)-1] = '\0'; + if (regexec(lookup_map_txtfile_regexp, line, lookup_map_txtfile_regexp->re_nsub+1, lookup_map_txtfile_regmatch, 0) == 0) { + strncpy(result, pregsub(r->pool, output, line, lookup_map_txtfile_regexp->re_nsub+1, lookup_map_txtfile_regmatch), sizeof(result)-1); /* substitute in output */ + EOS_PARANOIA(result); + cpT = strchr(result, ','); + *cpT = '\0'; + curkey = result; + curval = cpT+1; + + if (strcmp(curkey, key) == 0) { + value = pstrdup(r->pool, curval); + break; + } + } + } + pfclose(r->pool, fp); + return value; +} + +#if HAS_NDBM_LIB +static char *lookup_map_dbmfile(request_rec *r, char *file, char *key) +{ + DBM *dbmfp = NULL; + datum dbmkey; + datum dbmval; + char *value = NULL; + char buf[MAX_STRING_LEN]; + + dbmkey.dptr = key; + dbmkey.dsize = (strlen(key) < sizeof(buf) - 1 ? strlen(key) : sizeof(buf)-1); + if ((dbmfp = dbm_open(file, O_RDONLY, 0666)) != NULL) { + dbmval = dbm_fetch(dbmfp, dbmkey); + if (dbmval.dptr != NULL) { + memcpy(buf, dbmval.dptr, dbmval.dsize); + buf[dbmval.dsize] = '\0'; + value = pstrdup(r->pool, buf); + } + dbm_close(dbmfp); + } + return value; +} +#endif + +static char *lookup_map_program(request_rec *r, int fpin, int fpout, char *key) +{ + char buf[LONG_STRING_LEN]; + char c; + int i; + + /* lock the channel */ + fd_lock(fpin); + + /* write out the request key */ + write(fpin, key, strlen(key)); + write(fpin, "\n", 1); + + /* read in the response value */ + i = 0; + while (read(fpout, &c, 1) == 1 && (i < LONG_STRING_LEN-1)) { + if (c == '\n') + break; + buf[i++] = c; + } + buf[i] = '\0'; + + /* unlock the channel */ + fd_unlock(fpin); + + if (strcasecmp(buf, "NULL") == 0) + return NULL; + else + return pstrdup(r->pool, buf); +} + + + + +/* +** +-------------------------------------------------------+ +** | | +** | rewriting logfile support +** | | +** +-------------------------------------------------------+ +*/ + + +static void open_rewritelog(server_rec *s, pool *p) +{ + rewrite_server_conf *conf; + char *fname; + FILE *fp; + static int rewritelog_flags = ( O_WRONLY|O_APPEND|O_CREAT ); + static mode_t rewritelog_mode = ( S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH ); + + conf = get_module_config(s->module_config, &rewrite_module); + + if (conf->rewritelogfile == NULL) + return; + if (*(conf->rewritelogfile) == '\0') + return; + if (conf->rewritelogfp > 0) + return; /* virtual log shared w/main server */ + + fname = server_root_relative(p, conf->rewritelogfile); + + if (*conf->rewritelogfile == '|') { + if (!spawn_child(p, rewritelog_child, (void *)(conf->rewritelogfile+1), + kill_after_timeout, &fp, NULL)) { + perror("spawn_child"); + fprintf (stderr, "mod_rewrite: could not fork child for RewriteLog process\n"); + exit (1); + } + conf->rewritelogfp = fileno(fp); + } + else if (*conf->rewritelogfile != '\0') { + if ((conf->rewritelogfp = popenf(p, fname, rewritelog_flags, rewritelog_mode)) < 0) { + perror("open"); + fprintf(stderr, "mod_rewrite: could not open RewriteLog file %s.\n", fname); + exit(1); + } + } + return; +} + +/* Child process code for 'RewriteLog "|..."' */ +static void rewritelog_child(void *cmd) +{ + cleanup_for_exec(); + signal(SIGHUP, SIG_IGN); +#ifdef __EMX__ + /* OS/2 needs a '/' */ + execl(SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); +#else + execl(SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL); +#endif + exit(1); +} + +static void rewritelog(request_rec *r, int level, const char *text, ...) +{ + rewrite_server_conf *conf; + conn_rec *connect; + char *str1; + static char str2[HUGE_STRING_LEN]; + static char str3[HUGE_STRING_LEN]; + static char type[20]; + static char redir[20]; + va_list ap; + int i; + request_rec *req; + char *ruser; + + va_start(ap, text); + conf = get_module_config(r->server->module_config, &rewrite_module); + connect = r->connection; + + if (conf->rewritelogfp <0) + return; + if (conf->rewritelogfile == NULL) + return; + if (*(conf->rewritelogfile) == '\0') + return; + + if (level > conf->rewriteloglevel) + return; + + if (connect->user == NULL) { + ruser = "-"; + } + else if (strlen (connect->user) != 0) { + ruser = connect->user; + } + else { + ruser = "\"\""; + } + + str1 = pstrcat(r->pool, get_remote_host(connect, r->server->module_config, REMOTE_NAME), " ", + (connect->remote_logname != NULL ? connect->remote_logname : "-"), " ", + ruser, NULL); + ap_vsnprintf(str2, sizeof(str2), text, ap); + + if (r->main == NULL) + strcpy(type, "initial"); + else + strcpy(type, "subreq"); + + for (i = 0, req = r->prev; req != NULL; req = req->prev) + ; + if (i == 0) + redir[0] = '\0'; + else + ap_snprintf(redir, sizeof(redir), "/redir#%d", i); + + ap_snprintf(str3, sizeof(str3), "%s %s [%s/sid#%x][rid#%x/%s%s] (%d) %s\n", str1, current_logtime(r), r->server->server_hostname, (unsigned int)(r->server), (unsigned int)r, type, redir, level, str2); + + fd_lock(conf->rewritelogfp); + write(conf->rewritelogfp, str3, strlen(str3)); + fd_unlock(conf->rewritelogfp); + + va_end(ap); + return; +} + +static char *current_logtime(request_rec *r) +{ + int timz; + struct tm *t; + char tstr[80]; + char sign; + + t = get_gmtoff(&timz); + sign = (timz < 0 ? '-' : '+'); + if(timz < 0) + timz = -timz; + + strftime(tstr, 80, "[%d/%b/%Y:%H:%M:%S ", t); + ap_snprintf(tstr + strlen(tstr), 80-strlen(tstr), "%c%.2d%.2d]", sign, timz/60, timz%60); + return pstrdup(r->pool, tstr); +} + + + + +/* +** +-------------------------------------------------------+ +** | | +** | program map support +** | | +** +-------------------------------------------------------+ +*/ + +static void run_rewritemap_programs(server_rec *s, pool *p) +{ + rewrite_server_conf *conf; + char *fname; + FILE *fpin; + FILE *fpout; + array_header *rewritemaps; + rewritemap_entry *entries; + rewritemap_entry *map; + int i; + int rc; + + conf = get_module_config(s->module_config, &rewrite_module); + + rewritemaps = conf->rewritemaps; + entries = (rewritemap_entry *)rewritemaps->elts; + for (i = 0; i < rewritemaps->nelts; i++) { + map = &entries[i]; + if (map->type != MAPTYPE_PRG) + continue; + if (map->datafile == NULL || + *(map->datafile) == '\0' || + map->fpin > 0 || + map->fpout > 0 ) + continue; + fname = server_root_relative(p, map->datafile); + fpin = NULL; + fpout = NULL; + rc = spawn_child(p, rewritemap_program_child, (void *)map->datafile, kill_after_timeout, &fpin, &fpout); + if (rc == 0 || fpin == NULL || fpout == NULL) { + perror("spawn_child"); + fprintf(stderr, "mod_rewrite: could not fork child for RewriteMap process\n"); + exit(1); + } + map->fpin = fileno(fpin); + map->fpout = fileno(fpout); + } + return; +} + +/* child process code */ +static void rewritemap_program_child(void *cmd) +{ + cleanup_for_exec(); + signal(SIGHUP, SIG_IGN); +#ifdef __EMX__ + /* OS/2 needs a '/' */ + execl(SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); +#else + execl(SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL); +#endif + exit(1); +} + + + + +/* +** +-------------------------------------------------------+ +** | | +** | environment variable support +** | | +** +-------------------------------------------------------+ +*/ + + +static void expand_variables_inbuffer(request_rec *r, char *buf, int buf_len) +{ + char *newbuf; + newbuf = expand_variables(r, buf); + if (strcmp(newbuf, buf) != 0) { + strncpy(buf, newbuf, buf_len-1); + buf[buf_len-1] = '\0'; + } + return; +} + +static char *expand_variables(request_rec *r, char *str) +{ + char output[MAX_STRING_LEN]; + char input[MAX_STRING_LEN]; + char *cp; + char *cp2; + char *cp3; + int expanded; + + strncpy(input, str, sizeof(input)-1); + EOS_PARANOIA(input); + output[0] = '\0'; + expanded = 0; + for (cp = input; cp < input+MAX_STRING_LEN; ) { + if ((cp2 = strstr(cp, "%{")) != NULL) { + if ((cp3 = strstr(cp2, "}")) != NULL) { + *cp2 = '\0'; + strncpy(&output[strlen(output)], cp, sizeof(output)-strlen(output)-1); + + cp2 += 2; + *cp3 = '\0'; + strncpy(&output[strlen(output)], lookup_variable(r, cp2), sizeof(output)-strlen(output)-1); + + cp = cp3+1; + expanded = 1; + continue; + } + } + strncpy(&output[strlen(output)], cp, sizeof(output)-strlen(output)-1); + EOS_PARANOIA(output); + break; + } + return expanded ? pstrdup(r->pool, output) : str; +} + +static char *lookup_variable(request_rec *r, char *var) +{ + char *result; + char resultbuf[LONG_STRING_LEN]; + time_t tc; + struct tm *tm; + request_rec *rsub; + struct passwd *pw; + struct group *gr; + struct stat finfo; + + result = NULL; + + /* HTTP headers */ + if (strcasecmp(var, "HTTP_USER_AGENT") == 0) { + result = lookup_header(r, "User-Agent"); + } + else if (strcasecmp(var, "HTTP_REFERER") == 0) { + result = lookup_header(r, "Referer"); + } + else if (strcasecmp(var, "HTTP_COOKIE") == 0) { + result = lookup_header(r, "Cookie"); + } + else if (strcasecmp(var, "HTTP_FORWARDED") == 0) { + result = lookup_header(r, "Forwarded"); + } + else if (strcasecmp(var, "HTTP_HOST") == 0) { + result = lookup_header(r, "Host"); + } + else if (strcasecmp(var, "HTTP_PROXY_CONNECTION") == 0) { + result = lookup_header(r, "Proxy-Connection"); + } + else if (strcasecmp(var, "HTTP_ACCEPT") == 0) { + result = lookup_header(r, "Accept"); + } + /* all other headers from which we are still not know about */ + else if (strlen(var) > 5 && strncasecmp(var, "HTTP:", 5) == 0) { + result = lookup_header(r, var+5); + } + + /* connection stuff */ + else if (strcasecmp(var, "REMOTE_ADDR") == 0) { + result = r->connection->remote_ip; + } + else if (strcasecmp(var, "REMOTE_HOST") == 0) { + result = (char *)get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME); + } + else if (strcasecmp(var, "REMOTE_USER") == 0) { + result = r->connection->user; + } + else if (strcasecmp(var, "REMOTE_IDENT") == 0) { + result = (char *)get_remote_logname(r); + } + + /* request stuff */ + else if (strcasecmp(var, "THE_REQUEST") == 0) { /* non-standard */ + result = r->the_request; + } + else if (strcasecmp(var, "REQUEST_METHOD") == 0) { + result = r->method; + } + else if (strcasecmp(var, "REQUEST_URI") == 0) { /* non-standard */ + result = r->uri; + } + else if (strcasecmp(var, "SCRIPT_FILENAME") == 0 || + strcasecmp(var, "REQUEST_FILENAME") == 0 ) { + result = r->filename; + } + else if (strcasecmp(var, "PATH_INFO") == 0) { + result = r->path_info; + } + else if (strcasecmp(var, "QUERY_STRING") == 0) { + result = r->args; + } + else if (strcasecmp(var, "AUTH_TYPE") == 0) { + result = r->connection->auth_type; + } + else if (strcasecmp(var, "IS_SUBREQ") == 0) { /* non-standard */ + result = (r->main != NULL ? "true" : "false"); + } + + /* internal server stuff */ + else if (strcasecmp(var, "DOCUMENT_ROOT") == 0) { + result = document_root(r); + } + else if (strcasecmp(var, "SERVER_ADMIN") == 0) { + result = r->server->server_admin; + } + else if (strcasecmp(var, "SERVER_NAME") == 0) { + result = r->server->server_hostname; + } + else if (strcasecmp(var, "SERVER_PORT") == 0) { + ap_snprintf(resultbuf, sizeof(resultbuf), "%u", r->server->port); + result = resultbuf; + } + else if (strcasecmp(var, "SERVER_PROTOCOL") == 0) { + result = r->protocol; + } + else if (strcasecmp(var, "SERVER_SOFTWARE") == 0) { + result = pstrdup(r->pool, SERVER_VERSION); + } + else if (strcasecmp(var, "API_VERSION") == 0) { /* non-standard */ + ap_snprintf(resultbuf, sizeof(resultbuf), "%d", MODULE_MAGIC_NUMBER); + result = resultbuf; + } + + /* underlaying Unix system stuff */ + else if (strcasecmp(var, "TIME_YEAR") == 0) { + tc = time(NULL); + tm = localtime(&tc); + ap_snprintf(resultbuf, sizeof(resultbuf), "%02d%02d", (tm->tm_year / 100) + 19, tm->tm_year % 100); + result = resultbuf; + } +#define MKTIMESTR(format, tmfield) \ + tc = time(NULL); \ + tm = localtime(&tc); \ + ap_snprintf(resultbuf, sizeof(resultbuf), format, tm->tmfield); \ + result = resultbuf; + else if (strcasecmp(var, "TIME_MON") == 0) { + MKTIMESTR("%02d", tm_mon+1) + } + else if (strcasecmp(var, "TIME_DAY") == 0) { + MKTIMESTR("%02d", tm_mday) + } + else if (strcasecmp(var, "TIME_HOUR") == 0) { + MKTIMESTR("%02d", tm_hour) + } + else if (strcasecmp(var, "TIME_MIN") == 0) { + MKTIMESTR("%02d", tm_min) + } + else if (strcasecmp(var, "TIME_SEC") == 0) { + MKTIMESTR("%02d", tm_sec) + } + else if (strcasecmp(var, "TIME_WDAY") == 0) { + MKTIMESTR("%d", tm_wday) + } + else if (strcasecmp(var, "TIME") == 0) { + tc = time(NULL); + tm = localtime(&tc); + ap_snprintf(resultbuf, sizeof(resultbuf), "%02d%02d%02d%02d%02d%02d%02d", + (tm->tm_year / 100) + 19, (tm->tm_year % 100), + tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + result = resultbuf; + rewritelog(r, 1, "RESULT='%s'", result); + } + + /* all other env-variables from the parent Apache process */ + else if (strlen(var) > 4 && strncasecmp(var, "ENV:", 4) == 0) { + /* first try the internal Apache notes structure */ + result = table_get(r->notes, var+4); + /* second try the internal Apache env structure */ + if (result == NULL) + result = table_get(r->subprocess_env, var+4); + /* third try the external OS env */ + if (result == NULL) + result = getenv(var+4); + } + +#define LOOKAHEAD(subrecfunc) \ + if ( \ + /* filename is safe to use */ \ + r->filename != NULL \ + /* - and we're either not in a subrequest */ \ + && ( r->main == NULL \ + /* - or in a subrequest where paths are non-NULL... */ \ + || ( r->main->uri != NULL && r->uri != NULL \ + /* ...and sub and main paths differ */ \ + && strcmp(r->main->uri, r->uri) != 0))) { \ + /* process a file-based subrequest */ \ + rsub = subrecfunc(r->filename, r); \ + /* now recursively lookup the variable in the sub_req */ \ + result = lookup_variable(rsub, var+5); \ + /* copy it up to our scope before we destroy the sub_req's pool */ \ + result = pstrdup(r->pool, result); \ + /* cleanup by destroying the subrequest */ \ + destroy_sub_req(rsub); \ + /* log it */ \ + rewritelog(r, 5, "lookahead: path=%s var=%s -> val=%s", r->filename, var+5, result); \ + /* return ourself to prevent re-pstrdup */ \ + return result; \ + } + + /* look-ahead for parameter through URI-based sub-request */ + else if (strlen(var) > 5 && strncasecmp(var, "LA-U:", 5) == 0) { + LOOKAHEAD(sub_req_lookup_uri) + } + /* look-ahead for parameter through file-based sub-request */ + else if (strlen(var) > 5 && strncasecmp(var, "LA-F:", 5) == 0) { + LOOKAHEAD(sub_req_lookup_file) + } + + /* file stuff */ + else if (strcasecmp(var, "SCRIPT_USER") == 0) { + result = pstrdup(r->pool, ""); + if (r->finfo.st_mode != 0) { + if ((pw = getpwuid(r->finfo.st_uid)) != NULL) { + result = pstrdup(r->pool, pw->pw_name); + } + } + else { + if (stat(r->filename, &finfo) == 0) { + if ((pw = getpwuid(finfo.st_uid)) != NULL) { + result = pstrdup(r->pool, pw->pw_name); + } + } + } + } + else if (strcasecmp(var, "SCRIPT_GROUP") == 0) { + result = pstrdup(r->pool, ""); + if (r->finfo.st_mode != 0) { + if ((gr = getgrgid(r->finfo.st_gid)) != NULL) { + result = pstrdup(r->pool, gr->gr_name); + } + } + else { + if (stat(r->filename, &finfo) == 0) { + if ((gr = getgrgid(finfo.st_gid)) != NULL) { + result = pstrdup(r->pool, gr->gr_name); + } + } + } + } + + if (result == NULL) + return pstrdup(r->pool, ""); + else + return pstrdup(r->pool, result); +} + +static char *lookup_header(request_rec *r, const char *name) +{ + array_header *hdrs_arr; + table_entry *hdrs; + int i; + + hdrs_arr = table_elts(r->headers_in); + hdrs = (table_entry *)hdrs_arr->elts; + for (i = 0; i < hdrs_arr->nelts; ++i) { + if (hdrs[i].key == NULL) + continue; + if (strcasecmp(hdrs[i].key, name) == 0) + return hdrs[i].val; + } + return NULL; +} + + + + +/* +** +-------------------------------------------------------+ +** | | +** | caching support +** | | +** +-------------------------------------------------------+ +*/ + + +static cache *init_cache(pool *p) +{ + cache *c; + + c = (cache *)palloc(p, sizeof(cache)); + c->pool = make_sub_pool(p); + c->lists = make_array(c->pool, 2, sizeof(cachelist)); + return c; +} + +static void set_cache_string(cache *c, char *res, int mode, time_t time, char *key, char *value) +{ + cacheentry ce; + + ce.time = time; + ce.key = key; + ce.value = value; + store_cache_string(c, res, &ce); + return; +} + +static char *get_cache_string(cache *c, char *res, int mode, time_t time, char *key) +{ + cacheentry *ce; + + ce = retrieve_cache_string(c, res, key); + if (ce == NULL) + return NULL; + if (mode & CACHEMODE_TS) { + if (time != ce->time) + return NULL; + } + else if (mode & CACHEMODE_TTL) { + if (time > ce->time) + return NULL; + } + return pstrdup(c->pool, ce->value); +} + +static void store_cache_string(cache *c, char *res, cacheentry *ce) +{ + int i; + int j; + cachelist *l; + cacheentry *e; + int found_list; + + found_list = 0; + /* first try to edit an existing entry */ + for (i = 0; i < c->lists->nelts; i++) { + l = &(((cachelist *)c->lists->elts)[i]); + if (strcmp(l->resource, res) == 0) { + found_list = 1; + for (j = 0; j < l->entries->nelts; j++) { + e = &(((cacheentry *)l->entries->elts)[j]); + if (strcmp(e->key, ce->key) == 0) { + e->time = ce->time; + e->value = pstrdup(c->pool, ce->value); + return; + } + } + } + } + + /* create a needed new list */ + if (!found_list) { + l = push_array(c->lists); + l->resource = pstrdup(c->pool, res); + l->entries = make_array(c->pool, 2, sizeof(cacheentry)); + } + + /* create the new entry */ + for (i = 0; i < c->lists->nelts; i++) { + l = &(((cachelist *)c->lists->elts)[i]); + if (strcmp(l->resource, res) == 0) { + e = push_array(l->entries); + e->time = ce->time; + e->key = pstrdup(c->pool, ce->key); + e->value = pstrdup(c->pool, ce->value); + return; + } + } + + /* not reached, but when it is no problem... */ + return; +} + +static cacheentry *retrieve_cache_string(cache *c, char *res, char *key) +{ + int i; + int j; + cachelist *l; + cacheentry *e; + + for (i = 0; i < c->lists->nelts; i++) { + l = &(((cachelist *)c->lists->elts)[i]); + if (strcmp(l->resource, res) == 0) { + for (j = 0; j < l->entries->nelts; j++) { + e = &(((cacheentry *)l->entries->elts)[j]); + if (strcmp(e->key, key) == 0) { + return e; + } + } + } + } + return NULL; +} + + + + +/* +** +-------------------------------------------------------+ +** | | +** | misc functions +** | | +** +-------------------------------------------------------+ +*/ + +static char *subst_prefix_path(request_rec *r, char *input, char *match, char *subst) +{ + char matchbuf[LONG_STRING_LEN]; + char substbuf[LONG_STRING_LEN]; + char *output; + int l; + + output = input; + + /* first create a match string which always has a trailing slash */ + strncpy(matchbuf, match, sizeof(matchbuf)-1); + EOS_PARANOIA(matchbuf); + l = strlen(matchbuf); + if (matchbuf[l-1] != '/') { + matchbuf[l] = '/'; + matchbuf[l+1] = '\0'; + l++; + } + /* now compare the prefix */ + if (strncmp(input, matchbuf, l) == 0) { + rewritelog(r, 5, "strip matching prefix: %s -> %s", output, output+l); + output = pstrdup(r->pool, output+l); + + /* and now add the base-URL as replacement prefix */ + strncpy(substbuf, subst, sizeof(substbuf)-1); + EOS_PARANOIA(substbuf); + l = strlen(substbuf); + if (substbuf[l-1] != '/') { + substbuf[l] = '/'; + substbuf[l+1] = '\0'; + l++; + } + if (output[0] == '/') { + rewritelog(r, 4, "add subst prefix: %s -> %s%s", output, substbuf, output+1); + output = pstrcat(r->pool, substbuf, output+1, NULL); + } + else { + rewritelog(r, 4, "add subst prefix: %s -> %s%s", output, substbuf, output); + output = pstrcat(r->pool, substbuf, output, NULL); + } + } + return output; +} + + +/* +** +** own command line parser which don't have the '\\' problem +** +*/ + +static int parseargline(char *str, char **a1, char **a2, char **a3) +{ + char *cp; + int isquoted; + +#define SKIP_WHITESPACE(cp) \ + for ( ; *cp == ' ' || *cp == '\t'; ) \ + cp++; + +#define CHECK_QUOTATION(cp,isquoted) \ + isquoted = 0; \ + if (*cp == '"') { \ + isquoted = 1; \ + cp++; \ + } + +#define DETERMINE_NEXTSTRING(cp,isquoted) \ + for ( ; *cp != '\0'; cp++) { \ + if ( (isquoted && (*cp == ' ' || *cp == '\t')) \ + || (*cp == '\\' && (*(cp+1) == ' ' || *(cp+1) == '\t'))) { \ + cp++; \ + continue; \ + } \ + if ( (!isquoted && (*cp == ' ' || *cp == '\t')) \ + || (isquoted && *cp == '"') ) \ + break; \ + } + + cp = str; + SKIP_WHITESPACE(cp); + + /* determine first argument */ + CHECK_QUOTATION(cp, isquoted); + *a1 = cp; + DETERMINE_NEXTSTRING(cp, isquoted); + if (*cp == '\0') + return 1; + *cp++ = '\0'; + + SKIP_WHITESPACE(cp); + + /* determine second argument */ + CHECK_QUOTATION(cp, isquoted); + *a2 = cp; + DETERMINE_NEXTSTRING(cp, isquoted); + if (*cp == '\0') { + *cp++ = '\0'; + *a3 = NULL; + return 0; + } + *cp++ = '\0'; + + SKIP_WHITESPACE(cp); + + /* again check if there are only two arguments */ + if (*cp == '\0') { + *cp++ = '\0'; + *a3 = NULL; + return 0; + } + + /* determine second argument */ + CHECK_QUOTATION(cp, isquoted); + *a3 = cp; + DETERMINE_NEXTSTRING(cp, isquoted); + *cp++ = '\0'; + + return 0; +} + + +static void add_env_variable(request_rec *r, char *s) +{ + char var[MAX_STRING_LEN]; + char val[MAX_STRING_LEN]; + char *cp; + int n; + + if ((cp = strchr(s, ':')) != NULL) { + n = ((cp-s) > MAX_STRING_LEN-1 ? MAX_STRING_LEN-1 : (cp-s)); + memcpy(var, s, n); + var[n] = '\0'; + strncpy(val, cp+1, sizeof(val)-1); + EOS_PARANOIA(val); + table_set(r->subprocess_env, pstrdup(r->pool, var), pstrdup(r->pool, val)); + rewritelog(r, 5, "setting env variable '%s' to '%s'", var, val); + } +} + + + +/* +** +** stat() for only the prefix of a path +** +*/ + +static int prefix_stat(const char *path, struct stat *sb) +{ + char curpath[LONG_STRING_LEN]; + char *cp; + + strncpy(curpath, path, sizeof(curpath)-1); + EOS_PARANOIA(curpath); + if (curpath[0] != '/') + return 0; + if ((cp = strchr(curpath+1, '/')) != NULL) + *cp = '\0'; + if (stat(curpath, sb) == 0) + return 1; + else + return 0; +} + + +/* +** +** special DNS lookup functions +** +*/ + +static int is_this_our_host(request_rec *r, char *testhost) +{ + char **cppHNLour; + char **cppHNLtest; + char *ourhostname; + char *ourhostip; + const char *names; + char *name; + int i, j; + server_addr_rec *sar; + + /* we can check: + r-> + char *hostname Host, as set by full URI or Host: + int hostlen Length of http://host:port in full URI + r->server-> + int is_virtual 0=main, 1=ip-virtual, 2=non-ip-virtual + char *server_hostname used on compare to r->hostname + inet_ntoa(r->connection->local_addr.sin_addr) + used on compare to r->hostname + unsigned short port for redirects + char *path name of ServerPath + int pathlen len of ServerPath + char *names Wildcarded names for ServerAlias servers + r->server->addrs-> + struct in_addr host_addr The bound address, for this server + short host_port The bound port, for this server + char *virthost The name given in + */ + + ourhostname = r->server->server_hostname; + ourhostip = inet_ntoa(r->connection->local_addr.sin_addr); + + /* just a simple common case */ + if (strcmp(testhost, ourhostname) == 0 || + strcmp(testhost, ourhostip) == 0 ) + return YES; + + /* now the complicated cases */ + if (!r->server->is_virtual) { + /* main servers */ + + /* check for the alternative IP addresses */ + if ((cppHNLour = resolv_ipaddr_list(r, ourhostname)) == NULL) + return NO; + if ((cppHNLtest = resolv_ipaddr_list(r, testhost)) == NULL) + return NO; + for (i = 0; cppHNLtest[i] != NULL; i++) { + for (j = 0; cppHNLour[j] != NULL; j++) { + if (strcmp(cppHNLtest[i], cppHNLour[j]) == 0) { + return YES; + } + } + } + } + else if (r->server->is_virtual) { + /* virtual servers */ + + /* check for the names supplied in the VirtualHost directive */ + for(sar = r->server->addrs; sar != NULL; sar = sar->next) { + if(strcasecmp(sar->virthost, testhost) == 0) + return YES; + } + + /* check for the virtual-server aliases */ + if (r->server->names != NULL && r->server->names[0] != '\0') { + names = r->server->names; + while (*names != '\0') { + name = getword_conf(r->pool, &names); + if ((is_matchexp(name) && !strcasecmp_match(testhost, name)) || + (strcasecmp(testhost, name) == 0) ) { + return YES; + } + } + } + } + return NO; +} + +static int isaddr(char *host) +{ + char *cp; + + /* Null pointers and empty strings + are not addresses. */ + if (host == NULL) + return NO; + if (*host == '\0') + return NO; + /* Make sure it has only digits and dots. */ + for (cp = host; *cp; cp++) { + if (!isdigit(*cp) && *cp != '.') + return NO; + } + /* If it has a trailing dot, + don't treat it as an address. */ + if (*(cp-1) == '.') + return NO; + return YES; +} + +static char **resolv_ipaddr_list(request_rec *r, char *name) +{ + char **cppHNL; + struct hostent *hep; + int i; + + if (isaddr(name)) + hep = gethostbyaddr(name, sizeof(struct in_addr), AF_INET); + else + hep = gethostbyname(name); + if (hep == NULL) + return NULL; + for (i = 0; hep->h_addr_list[i]; i++) + ; + cppHNL = (char **)palloc(r->pool, sizeof(char *)*(i+1)); + for (i = 0; hep->h_addr_list[i]; i++) + cppHNL[i] = pstrdup(r->pool, inet_ntoa(*((struct in_addr *)(hep->h_addr_list[i]))) ); + cppHNL[i] = NULL; + return cppHNL; +} + + +/* +** +** check if proxy module is available +** i.e. if it is compiled in and turned on +** +*/ + +static int is_proxy_available(server_rec *s) +{ + extern module *preloaded_modules[]; + command_rec *c; + int n; + + for (n = 0; preloaded_modules[n] != NULL; n++) { + for (c = preloaded_modules[n]->cmds; c && c->name; ++c) { + if (strcmp(c->name, "ProxyRequests") == 0) { + return 1; + } + } + } + return 0; +} + + +/* +** +** File locking +** +*/ + +#ifdef USE_FCNTL +static struct flock lock_it; +static struct flock unlock_it; +#endif + +static void fd_lock(int fd) +{ + int rc; + +#ifdef USE_FCNTL + lock_it.l_whence = SEEK_SET; /* from current point */ + lock_it.l_start = 0; /* -"- */ + lock_it.l_len = 0; /* until end of file */ + lock_it.l_type = F_WRLCK; /* set exclusive/write lock */ + lock_it.l_pid = 0; /* pid not actually interesting */ + + while ( ((rc = fcntl(fd, F_SETLKW, &lock_it)) < 0) + && (errno == EINTR) ) + continue; +#endif +#ifdef USE_FLOCK + while ( ((rc = flock(fd, LOCK_EX)) < 0) + && (errno == EINTR) ) + continue; +#endif + + if (rc < 0) { +#ifdef USE_FLOCK + perror("flock"); +#else + perror("fcntl"); +#endif + fprintf(stderr, "Error getting lock. Exiting!"); + exit(1); + } + return; +} + +static void fd_unlock(int fd) +{ + int rc; + +#ifdef USE_FCNTL + unlock_it.l_whence = SEEK_SET; /* from current point */ + unlock_it.l_start = 0; /* -"- */ + unlock_it.l_len = 0; /* until end of file */ + unlock_it.l_type = F_UNLCK; /* unlock */ + unlock_it.l_pid = 0; /* pid not actually interesting */ + + rc = fcntl(fd, F_SETLKW, &unlock_it); +#endif +#ifdef USE_FLOCK + rc = flock(fd, LOCK_UN); +#endif + + if (rc < 0) { +#ifdef USE_FLOCK + perror("flock"); +#else + perror("fcntl"); +#endif + fprintf(stderr, "Error freeing lock. Exiting!"); + exit(1); + } +} + +/* +** +** Lexicographic Compare +** +*/ + +int compare_lexicography(char *cpNum1, char *cpNum2) +{ + int i; + int n1, n2; + + n1 = strlen(cpNum1); + n2 = strlen(cpNum2); + if (n1 > n2) + return 1; + if (n1 < n2) + return -1; + for (i = 0; i < n1; i++) { + if (cpNum1[i] > cpNum2[i]) + return 1; + if (cpNum1[i] < cpNum2[i]) + return -1; + } + return 0; +} + + +/*EOF*/ diff --git a/APACHE_1_2_X/src/modules/standard/mod_rewrite.h b/APACHE_1_2_X/src/modules/standard/mod_rewrite.h new file mode 100644 index 00000000000..c8bec8b537a --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_rewrite.h @@ -0,0 +1,396 @@ + +/* ==================================================================== + * Copyright (c) 1996,1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + + +#ifndef _MOD_REWRITE_H +#define _MOD_REWRITE_H 1 + +/* +** mod_rewrite.h -- Common Header File +** _ _ _ +** _ __ ___ ___ __| | _ __ _____ ___ __(_) |_ ___ +** | '_ ` _ \ / _ \ / _` | | '__/ _ \ \ /\ / / '__| | __/ _ \ +** | | | | | | (_) | (_| | | | | __/\ V V /| | | | || __/ +** |_| |_| |_|\___/ \__,_|___|_| \___| \_/\_/ |_| |_|\__\___| +** |_____| +** +** URL Rewriting Module, Version 3.0.5 (16-Apr-1997) +** +** This module uses a rule-based rewriting engine (based on a +** regular-expression parser) to rewrite requested URLs on the fly. +** +** It supports an unlimited number of additional rule conditions (which can +** operate on a lot of variables, even on HTTP headers) for granular +** matching and even external database lookups (either via plain text +** tables, DBM hash files or even external processes) for advanced URL +** substitution. +** +** It operates on the full URLs (including the PATH_INFO part) both in +** per-server context (httpd.conf) and per-dir context (.htaccess) and even +** can generate QUERY_STRING parts on result. The rewriting result finally +** can lead to internal subprocessing, external request redirection or even +** to internal proxy throughput. +** +** The documentation and latest release can be found on +** http://www.engelschall.com/sw/mod_rewrite/ +** +** Copyright (c) 1996-1997 Ralf S. Engelschall, All rights reserved. +** +** Written for The Apache Group by +** Ralf S. Engelschall +** rse@engelschall.com +** www.engelschall.com +*/ + + + + + /* The NDBM support: + We support only NDBM files. + But we have to stat the file for the mtime, + so we also need to know the file extension */ +#if HAS_NDBM_LIB +#include +#if (__FreeBSD__) +#define NDBM_FILE_SUFFIX ".db" +#else +#define NDBM_FILE_SUFFIX ".pag" +#endif +#endif + + + /* The locking support: + Try to determine whether we should use fcntl() or flock(). + Would be better conf.h could provide this... :-( */ +#if defined(USE_FCNTL_SERIALIZED_ACCEPT) +#define USE_FCNTL 1 +#include +#endif +#if defined(USE_FLOCK_SERIALIZED_ACCEPT) +#define USE_FLOCK 1 +#include +#endif +#if !defined(USE_FCNTL) && !defined(USE_FLOCK) +#define USE_FLOCK 1 +#ifndef MPE +#include +#endif +#ifndef LOCK_UN +#undef USE_FLOCK +#define USE_FCNTL 1 +#include +#endif +#endif +#ifdef AIX +#undef USE_FLOCK +#define USE_FCNTL 1 +#include +#endif + + + + +/* +** +** Some defines +** +*/ + +#define ENVVAR_SCRIPT_URL "SCRIPT_URL" +#define ENVVAR_SCRIPT_URI "SCRIPT_URI" + +#ifndef SUPPORT_DBM_REWRITEMAP +#define SUPPORT_DBM_REWRITEMAP 0 +#endif + +#define REWRITE_FORCED_MIMETYPE_NOTEVAR "rewrite-forced-mimetype" + +#define CONDFLAG_NONE 1<<0 +#define CONDFLAG_NOCASE 1<<1 +#define CONDFLAG_NOTMATCH 1<<2 +#define CONDFLAG_ORNEXT 1<<3 + +#define RULEFLAG_NONE 1<<0 +#define RULEFLAG_FORCEREDIRECT 1<<1 +#define RULEFLAG_LASTRULE 1<<2 +#define RULEFLAG_NEWROUND 1<<3 +#define RULEFLAG_CHAIN 1<<4 +#define RULEFLAG_IGNOREONSUBREQ 1<<5 +#define RULEFLAG_NOTMATCH 1<<6 +#define RULEFLAG_PROXY 1<<7 +#define RULEFLAG_PASSTHROUGH 1<<8 +#define RULEFLAG_FORBIDDEN 1<<9 +#define RULEFLAG_GONE 1<<10 + +#define MAPTYPE_TXT 1<<0 +#define MAPTYPE_DBM 1<<1 +#define MAPTYPE_PRG 1<<2 + +#define ENGINE_DISABLED 1<<0 +#define ENGINE_ENABLED 1<<1 + +#define OPTION_NONE 1<<0 +#define OPTION_INHERIT 1<<1 + +#define CACHEMODE_TS 1<<0 +#define CACHEMODE_TTL 1<<1 + +#ifndef FALSE +#define FALSE 0 +#define TRUE !FALSE +#endif + +#ifndef NO +#define NO FALSE +#define YES TRUE +#endif + +#ifndef LONG_STRING_LEN +#define LONG_STRING_LEN 2048 +#endif + +#define MAX_ENV_FLAGS 5 + +#define EOS_PARANOIA(ca) ca[sizeof(ca)-1] = '\0' + + +/* +** +** our private data structures we handle with +** +*/ + + /* the list structures for holding the mapfile information + and the rewrite rules */ + +typedef struct { + char *name; /* the name of the map */ + char *datafile; /* the file which contains the data of the map */ + char *checkfile; /* the file which stays for existence of the map */ + int type; /* the type of the map */ + int fpin; /* in filepointer for program maps */ + int fpout; /* out filepointer for program maps */ +} rewritemap_entry; + +typedef struct { + char *input; /* Input string of RewriteCond */ + char *pattern; /* the RegExp pattern string */ + regex_t *regexp; + int flags; /* Flags which control the match */ +} rewritecond_entry; + +typedef struct { + array_header *rewriteconds; /* the corresponding RewriteCond entries */ + char *pattern; /* the RegExp pattern string */ + regex_t *regexp; /* the RegExp pattern compilation */ + char *output; /* the Substitution string */ + int flags; /* Flags which control the substitution */ + char *forced_mimetype; /* forced MIME type of substitution */ + int forced_responsecode; /* forced HTTP redirect response status */ + char *env[MAX_ENV_FLAGS+1];/* added environment variables */ + int skip; /* number of next rules to skip */ +} rewriterule_entry; + + + /* the per-server or per-virtual-server configuration + statically generated once on startup for every server */ + +typedef struct { + int state; /* the RewriteEngine state */ + int options; /* the RewriteOption state */ + char *rewritelogfile; /* the RewriteLog filename */ + int rewritelogfp; /* the RewriteLog open filepointer */ + int rewriteloglevel; /* the RewriteLog level of verbosity */ + array_header *rewritemaps; /* the RewriteMap entries */ + array_header *rewriteconds; /* the RewriteCond entries (temporary) */ + array_header *rewriterules; /* the RewriteRule entries */ +} rewrite_server_conf; + + + /* the per-directory configuration + individually generated on-the-fly by Apache server for current request */ + +typedef struct { + int state; /* the RewriteEngine state */ + int options; /* the RewriteOption state */ + array_header *rewriteconds; /* the RewriteCond entries (temporary) */ + array_header *rewriterules; /* the RewriteRule entries */ + char *directory; /* the directory where it applies */ + char *baseurl; /* the base-URL where it applies */ +} rewrite_perdir_conf; + + + /* the cache structures */ + +typedef struct cacheentry { + time_t time; + char *key; + char *value; +} cacheentry; + +typedef struct cachelist { + char *resource; + array_header *entries; +} cachelist; + +typedef struct cache { + pool *pool; + array_header *lists; +} cache; + + +/* +** +** forward declarations +** +*/ + + /* config structure handling */ +static void *config_server_create(pool *p, server_rec *s); +static void *config_server_merge (pool *p, void *basev, void *overridesv); +static void *config_perdir_create(pool *p, char *path); +static void *config_perdir_merge (pool *p, void *basev, void *overridesv); + + /* config directive handling */ +static const char *cmd_rewriteengine (cmd_parms *cmd, rewrite_perdir_conf *dconf, int flag); +static const char *cmd_rewriteoptions (cmd_parms *cmd, rewrite_perdir_conf *dconf, char *option); +static const char *cmd_rewriteoptions_setoption(pool *p, int *options, char *name); +static const char *cmd_rewritelog (cmd_parms *cmd, void *dconf, char *a1); +static const char *cmd_rewriteloglevel(cmd_parms *cmd, void *dconf, char *a1); +static const char *cmd_rewritemap (cmd_parms *cmd, void *dconf, char *a1, char *a2); + +static const char *cmd_rewritebase(cmd_parms *cmd, rewrite_perdir_conf *dconf, char *a1); + +static const char *cmd_rewritecond (cmd_parms *cmd, rewrite_perdir_conf *dconf, char *str); +static const char *cmd_rewritecond_parseflagfield(pool *p, rewritecond_entry *new, char *str); +static const char *cmd_rewritecond_setflag (pool *p, rewritecond_entry *cfg, char *key, char *val); + +extern const char *cmd_rewriterule (cmd_parms *cmd, rewrite_perdir_conf *dconf, char *str); +static const char *cmd_rewriterule_parseflagfield(pool *p, rewriterule_entry *new, char *str); +static const char *cmd_rewriterule_setflag (pool *p, rewriterule_entry *cfg, char *key, char *val); + + /* initialisation */ +static void init_module(server_rec *s, pool *p); + + /* runtime hooks */ +static int hook_uri2file (request_rec *r); +static int hook_mimetype (request_rec *r); +static int hook_fixup (request_rec *r); +static int handler_redirect(request_rec *r); + + /* rewriting engine */ +static int apply_rewrite_list(request_rec *r, array_header *rewriterules, char *perdir); +static int apply_rewrite_rule(request_rec *r, rewriterule_entry *p, char *perdir); +static int apply_rewrite_cond(request_rec *r, rewritecond_entry *p, char *perdir); + + /* URI transformation function */ +static void splitout_queryargs(request_rec *r); +static void reduce_uri(request_rec *r); +static char *expand_tildepaths(request_rec *r, char *uri); +static void expand_map_lookups(request_rec *r, char *uri, int uri_len); + + /* DBM hashfile support functions */ +static char *lookup_map(request_rec *r, char *name, char *key); +static char *lookup_map_txtfile(request_rec *r, char *file, char *key); +#if HAS_NDBM_LIB +static char *lookup_map_dbmfile(request_rec *r, char *file, char *key); +#endif +static char *lookup_map_program(request_rec *r, int fpin, int fpout, char *key); + + /* rewriting logfile support */ +static void open_rewritelog(server_rec *s, pool *p); +static void rewritelog_child(void *cmd); +static void rewritelog(request_rec *r, int level, const char *text, ...); +static char *current_logtime(request_rec *r); + + /* program map support */ +static void run_rewritemap_programs(server_rec *s, pool *p); +static void rewritemap_program_child(void *cmd); + + /* env variable support */ +static void expand_variables_inbuffer(request_rec *r, char *buf, int buf_len); +static char *expand_variables(request_rec *r, char *str); +static char *lookup_variable(request_rec *r, char *var); +static char *lookup_header(request_rec *r, const char *name); + + /* caching functions */ +static cache *init_cache(pool *p); +static char *get_cache_string(cache *c, char *res, int mode, time_t mtime, char *key); +static void set_cache_string(cache *c, char *res, int mode, time_t mtime, char *key, char *value); +static cacheentry *retrieve_cache_string(cache *c, char *res, char *key); +static void store_cache_string(cache *c, char *res, cacheentry *ce); + + /* misc functions */ +static char *subst_prefix_path(request_rec *r, char *input, char *match, char *subst); +static int parseargline(char *str, char **a1, char **a2, char **a3); +static int prefix_stat(const char *path, struct stat *sb); +static void add_env_variable(request_rec *r, char *s); + + /* DNS functions */ +static int is_this_our_host(request_rec *r, char *testhost); +static int isaddr(char *host); +static char **resolv_ipaddr_list(request_rec *r, char *name); + + /* Proxy Module check */ +static int is_proxy_available(server_rec *s); + + /* File locking */ +static void fd_lock(int fd); +static void fd_unlock(int fd); + + /* Lexicographic Comparison */ +int compare_lexicography(char *cpNum1, char *cpNum2); + +#endif /* _MOD_REWRITE_H */ + +/*EOF*/ diff --git a/APACHE_1_2_X/src/modules/standard/mod_status.c b/APACHE_1_2_X/src/modules/standard/mod_status.c new file mode 100644 index 00000000000..da0073a59a3 --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_status.c @@ -0,0 +1,636 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* Status Module. Display lots of internal data about how Apache is + * performing and the state of all children processes. + * + * To enable this, add the following lines into any config file: + * + * + * SetHandler server-status + * + * + * You may want to protect this location by password or domain so no one + * else can look at it. Then you can access the statistics with a URL like: + * + * http://your_server_name/server-status + * + * /server-status - Returns page using tables + * /server-status?notable - Returns page for browsers without table support + * /server-status?refresh - Returns page with 1 second refresh + * /server-status?refresh=6 - Returns page with refresh every 6 seconds + * /server-status?auto - Returns page with data for automatic parsing + * + * Mark Cox, mark@ukweb.com, November 1995 + * + * 12.11.95 Initial version for www.telescope.org + * 13.3.96 Updated to remove rprintf's [Mark] + * 18.3.96 Added CPU usage, process information, and tidied [Ben Laurie] + * 18.3.96 Make extra Scoreboard variables #definable + * 25.3.96 Make short report have full precision [Ben Laurie suggested] + * 25.3.96 Show uptime better [Mark/Ben Laurie] + * 29.3.96 Better HTML and explanation [Mark/Rob Hartill suggested] + * 09.4.96 Added message for non-STATUS compiled version + * 18.4.96 Added per child and per slot counters [Jim Jagielski] + * 01.5.96 Table format, cleanup, even more spiffy data [Chuck Murcko/Jim J.] + * 18.5.96 Adapted to use new rprintf() routine, incidentally fixing a missing + * piece in short reports [Ben Laurie] + * 21.5.96 Additional Status codes (DNS and LOGGING only enabled if + extended STATUS is enabled) [George Burgyan/Jim J.] */ + +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_protocol.h" +#include "http_main.h" +#include "util_script.h" +#include +#include "scoreboard.h" + +#ifdef NEXT +#include +#endif + +#define STATUS_MAXLINE 64 + +#define KBYTE 1024 +#define MBYTE 1048576L +#define GBYTE 1073741824L + +module status_module; + +/* Format the number of bytes nicely */ + +void format_byte_out(request_rec *r,unsigned long bytes) +{ + if (bytes < (5 * KBYTE)) + rprintf(r,"%d B",(int)bytes); + else if (bytes < (MBYTE / 2)) + rprintf(r,"%.1f kB",(float)bytes/KBYTE); + else if (bytes < (GBYTE / 2)) + rprintf(r,"%.1f MB",(float)bytes/MBYTE); + else + rprintf(r,"%.1f GB",(float)bytes/GBYTE); +} + +void format_kbyte_out(request_rec *r,unsigned long kbytes) +{ + if (kbytes < KBYTE) + rprintf(r,"%d kB",(int)kbytes); + else if (kbytes < MBYTE) + rprintf(r,"%.1f MB",(float)kbytes/KBYTE); + else + rprintf(r,"%.1f GB",(float)kbytes/MBYTE); +} + +void show_time(request_rec *r,time_t tsecs) +{ + long days,hrs,mins,secs; + char buf[100]; + char *s; + + secs=tsecs%60; + tsecs/=60; + mins=tsecs%60; + tsecs/=60; + hrs=tsecs%24; + days=tsecs/24; + s=buf; + *s='\0'; + if(days) + rprintf(r," %ld day%s",days,days==1?"":"s"); + if(hrs) + rprintf(r," %ld hour%s",hrs,hrs==1?"":"s"); + if(mins) + rprintf(r," %ld minute%s",mins,mins==1?"":"s"); + if(secs) + rprintf(r," %ld second%s",secs,secs==1?"":"s"); +} + +#if defined(SUNOS4) +double +difftime(time1, time0) + time_t time1, time0; +{ + return(time1 - time0); +} +#endif + +/* Main handler for x-httpd-status requests */ + +/* ID values for command table */ + +#define STAT_OPT_END -1 +#define STAT_OPT_REFRESH 0 +#define STAT_OPT_NOTABLE 1 +#define STAT_OPT_AUTO 2 + +struct stat_opt +{ + int id; + char *form_data_str; + char *hdr_out_str; +}; + +int status_handler (request_rec *r) +{ + struct stat_opt options[] = /* see #defines above */ + { + { STAT_OPT_REFRESH, "refresh", "Refresh" }, + { STAT_OPT_NOTABLE, "notable", NULL }, + { STAT_OPT_AUTO, "auto", NULL }, + { STAT_OPT_END, NULL, NULL } + }; + char *loc; + time_t nowtime=time(NULL); + time_t up_time; + int i,res; + int ready=0; + int busy=0; +#if defined(STATUS) + unsigned long count=0; + unsigned long lres,bytes; + unsigned long my_lres,my_bytes,conn_bytes; + unsigned short conn_lres; + unsigned long bcount=0; + unsigned long kbcount=0; +#ifdef NEXT + float tick=HZ; +#else + float tick=sysconf(_SC_CLK_TCK); +#endif +#endif /* STATUS */ + int short_report=0; + int no_table_report=0; + server_rec *server = r->server; + short_score score_record; + char status[]="??????????"; + char stat_buffer[HARD_SERVER_LIMIT]; + clock_t tu,ts,tcu,tcs; + + tu=ts=tcu=tcs=0; + + status[SERVER_DEAD]='.'; /* We don't want to assume these are in */ + status[SERVER_READY]='_'; /* any particular order in scoreboard.h */ + status[SERVER_STARTING]='S'; + status[SERVER_BUSY_READ]='R'; + status[SERVER_BUSY_WRITE]='W'; + status[SERVER_BUSY_KEEPALIVE]='K'; + status[SERVER_BUSY_LOG]='L'; + status[SERVER_BUSY_DNS]='D'; + status[SERVER_GRACEFUL]='G'; + + if (r->method_number != M_GET) return NOT_IMPLEMENTED; + r->content_type = "text/html"; + + /* + * Simple table-driven form data set parser that lets you alter the header + */ + + if (r->args) + { + i = 0; + while (options[i].id != STAT_OPT_END) + { + if ((loc = strstr(r->args,options[i].form_data_str)) != NULL) + { + switch (options[i].id) + { + case STAT_OPT_REFRESH: + if(*(loc + strlen(options[i].form_data_str)) == '=') + table_set(r->headers_out,options[i].hdr_out_str, + loc+strlen(options[i].hdr_out_str)+1); + else + table_set(r->headers_out,options[i].hdr_out_str,"1"); + break; + case STAT_OPT_NOTABLE: + no_table_report = 1; + break; + case STAT_OPT_AUTO: + r->content_type = "text/plain"; + short_report = 1; + break; + } + } + i++; + } + } + + send_http_header(r); + + if (r->header_only) + return 0; + + sync_scoreboard_image(); + for (i = 0; i=KBYTE) { + kbcount += (bcount >> 10); + bcount = bcount & 0x3ff; + } + } +#endif /* STATUS */ + } + + up_time=nowtime-restart_time; + + hard_timeout("send status info", r); + + if (!short_report) + { + rputs("\nApache Status\n\n",r); + rputs("

    Apache Server Status for ",r); + rvputs(r,server->server_hostname,"

    \n\n",NULL); + rvputs(r,"Current Time: ",asctime(localtime(&nowtime)),"
    \n",NULL); + rvputs(r,"Restart Time: ",asctime(localtime(&restart_time)),"
    \n", + NULL); + rputs("Server uptime: ",r); + show_time(r,up_time); + rputs("
    \n",r); + } + +#if defined(STATUS) + if (short_report) + { + rprintf(r,"Total Accesses: %lu\nTotal kBytes: %lu\n",count,kbcount); + +#ifndef __EMX__ + /* Allow for OS/2 not having CPU stats */ + if(ts || tu || tcu || tcs) + rprintf(r,"CPULoad: %g\n",(tu+ts+tcu+tcs)/tick/up_time*100.); +#endif + + rprintf(r,"Uptime: %ld\n",(long)(up_time)); + if (up_time>0) + rprintf(r,"ReqPerSec: %g\n",(float)count/(float)up_time); + + if (up_time>0) + rprintf(r,"BytesPerSec: %g\n",KBYTE*(float)kbcount/(float)up_time); + + if (count>0) + rprintf(r,"BytesPerReq: %g\n",KBYTE*(float)kbcount/(float)count); + } else /* !short_report */ + { + rprintf(r,"Total accesses: %lu - Total Traffic: ", count); + format_kbyte_out(r,kbcount); + +#ifndef __EMX__ + /* Allow for OS/2 not having CPU stats */ + rputs("
    \n",r); + rprintf(r,"CPU Usage: u%g s%g cu%g cs%g", + tu/tick,ts/tick,tcu/tick,tcs/tick); + + if(ts || tu || tcu || tcs) + rprintf(r," - %.3g%% CPU load",(tu+ts+tcu+tcs)/tick/up_time*100.); +#endif + + rputs("
    \n",r); + + if (up_time>0) + rprintf(r,"%.3g requests/sec - ", + (float)count/(float)up_time); + + if (up_time>0) + { + format_byte_out(r,KBYTE*(float)kbcount/(float)up_time); + rputs("/second - ",r); + } + + if (count>0) + { + format_byte_out(r,KBYTE*(float)kbcount/(float)count); + rputs("/request",r); + } + + rputs("
    \n",r); + } /* short_report */ +#endif /* STATUS */ + + if (!short_report) + rprintf(r,"\n%d requests currently being processed, %d idle servers\n" + ,busy,ready); + else + rprintf(r,"BusyServers: %d\nIdleServers: %d\n",busy,ready); + + /* send the scoreboard 'table' out */ + + if(!short_report) + rputs("
    ",r);
    +    else
    +        rputs("Scoreboard: ",r);
    +
    +    for (i = 0; i\n",r);
    +	rputs("Scoreboard Key: 
    \n",r); + rputs("\"_\" Waiting for Connection, \n",r); + rputs("\"S\" Starting up, \n",r); + rputs("\"R\" Reading Request,
    \n",r); + rputs("\"W\" Sending Reply, \n",r); + rputs("\"K\" Keepalive (read), \n",r); + rputs("\"D\" DNS Lookup,
    \n",r); + rputs("\"L\" Logging, \n",r); + rputs("\"G\" Gracefully finishing, \n",r); + rputs("\".\" Open slot with no current process

    \n",r); + } + +#if defined(STATUS) + if (!short_report) + if(no_table_report) + rputs("


    Server Details

    \n\n",r); + else +#ifdef __EMX__ + /* Allow for OS/2 not having CPU stats */ + rputs("

    \n\n\n\n",r); +#else + rputs("

    \n\n

    SrvPIDAccM\nSSConnChildSlotHostVHostRequest
    \n\n",r); +#endif + + + for (i = 0; iServer %d (%d): %d|%lu|%lu [", + i,(int)score_record.pid,(int)conn_lres,my_lres,lres); + + switch (score_record.status) + { + case SERVER_READY: + rputs("Ready",r); + break; + case SERVER_STARTING: + rputs("Starting",r); + break; + case SERVER_BUSY_READ: + rputs("Read",r); + break; + case SERVER_BUSY_WRITE: + rputs("Write",r); + break; + case SERVER_BUSY_KEEPALIVE: + rputs("Keepalive",r); + break; + case SERVER_BUSY_LOG: + rputs("Logging",r); + break; + case SERVER_BUSY_DNS: + rputs("DNS lookup",r); + break; + case SERVER_DEAD: + rputs("Dead",r); + break; + case SERVER_GRACEFUL: + rputs("Graceful",r); + break; + default: + rputs("?STATE?",r); + break; + } +#ifdef __EMX__ + /* Allow for OS/2 not having CPU stats */ + rprintf(r,"]\n %s (", +#else + + rprintf(r,"] u%g s%g cu%g cs%g\n %s (", + score_record.times.tms_utime/tick, + score_record.times.tms_stime/tick, + score_record.times.tms_cutime/tick, + score_record.times.tms_cstime/tick, +#endif + asctime(localtime(&score_record.last_used))); + format_byte_out(r,conn_bytes); + rputs("|",r); + format_byte_out(r,my_bytes); + rputs("|",r); + format_byte_out(r,bytes); + rputs(")\n",r); + rprintf(r," %s {%s}
    \n\n", + score_record.client, + escape_html(r->pool, score_record.request)); + } + else /* !no_table_report */ + { + rprintf(r,"
    \n\n", + score_record.client, score_record.vhost, + escape_html(r->pool, score_record.request)); + } /* no_table_report */ + } /* !short_report */ + } /* if () */ + } /* for () */ + + if (!(short_report || no_table_report)) + { +#ifdef __EMX__ + rputs("
    SrvPIDAccMCPU\nSSConnChildSlotHostVHostRequest
    %d%d%d/%lu/%lu", + i,(int)score_record.pid,(int)conn_lres,my_lres,lres); + + switch (score_record.status) + { + case SERVER_READY: + rputs("_",r); + break; + case SERVER_STARTING: + rputs("S",r); + break; + case SERVER_BUSY_READ: + rputs("R",r); + break; + case SERVER_BUSY_WRITE: + rputs("W",r); + break; + case SERVER_BUSY_KEEPALIVE: + rputs("K",r); + break; + case SERVER_BUSY_LOG: + rputs("L",r); + break; + case SERVER_BUSY_DNS: + rputs("D",r); + break; + case SERVER_DEAD: + rputs(".",r); + break; + case SERVER_GRACEFUL: + rputs("G",r); + break; + default: + rputs("?",r); + break; + } +#ifdef __EMX__ + /* Allow for OS/2 not having CPU stats */ + rprintf(r,"\n%.0f", +#else + rprintf(r,"\n%.2f%.0f", + (score_record.times.tms_utime + + score_record.times.tms_stime + + score_record.times.tms_cutime + + score_record.times.tms_cstime)/tick, +#endif + difftime(nowtime, score_record.last_used)); + rprintf(r,"%-1.1f%-2.2f%-2.2f\n", + (float)conn_bytes/KBYTE, (float)my_bytes/MBYTE, + (float)bytes/MBYTE); + rprintf(r,"%s%s%s
    \n \ +


    \ +\n \ +
    SrvServer number\n \ +
    PIDOS process ID\n \ +
    AccNumber of accesses this connection / this child / this slot\n \ +
    MMode of operation\n \ +
    SSSeconds since beginning of most recent request\n \ +
    ConnKilobytes transferred this connection\n \ +
    ChildMegabytes transferred this child\n \ +
    SlotTotal megabytes transferred this slot\n \ +
    \n",r); +#else + rputs("\n \ +
    \ +\n \ +
    SrvServer number\n \ +
    PIDOS process ID\n \ +
    AccNumber of accesses this connection / this child / this slot\n \ +
    MMode of operation\n \ +
    CPUCPU usage, number of seconds\n \ +
    SSSeconds since beginning of most recent request\n \ +
    ConnKilobytes transferred this connection\n \ +
    ChildMegabytes transferred this child\n \ +
    SlotTotal megabytes transferred this slot\n \ +
    \n",r); +#endif + } + +#else /* !defined(STATUS) */ + + rputs("
    To obtain a full report with current status information and",r); + rputs(" DNS and LOGGING status codes \n",r); + rputs("you need to recompile Apache after adding the line
    ",r);
    +    rputs("Rule STATUS=yes
    into the file Configuration\n",r); + +#endif /* STATUS */ + + if (!short_report) + rputs("\n",r); + + kill_timeout(r); + return 0; +} + +handler_rec status_handlers[] = +{ +{ STATUS_MAGIC_TYPE, status_handler }, +{ "server-status", status_handler }, +{ NULL } +}; + +module status_module = +{ + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + NULL, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + NULL, /* server config */ + NULL, /* merge server config */ + NULL, /* command table */ + status_handlers, /* handlers */ + NULL, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_userdir.c b/APACHE_1_2_X/src/modules/standard/mod_userdir.c new file mode 100644 index 00000000000..d3edf652798 --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_userdir.c @@ -0,0 +1,211 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * mod_userdir... implement the UserDir command. Broken away from the + * Alias stuff for a couple of good and not-so-good reasons: + * + * 1) It shows a real minimal working example of how to do something like + * this. + * 2) I know people who are actually interested in changing this *particular* + * aspect of server functionality without changing the rest of it. That's + * what this whole modular arrangement is supposed to be good at... + * + * Modified by Alexei Kosut to support the following constructs + * (server running at www.foo.com, request for /~bar/one/two.html) + * + * UserDir public_html -> ~bar/public_html/one/two.html + * UserDir /usr/web -> /usr/web/bar/one/two.html + * UserDir /home/ * /www -> /home/bar/www/one/two.html + * NOTE: theses ^ ^ space only added allow it to work in a comment, ignore + * UserDir http://x/users -> (302) http://x/users/bar/one/two.html + * UserDir http://x/ * /y -> (302) http://x/bar/y/one/two.html + * NOTE: here also ^ ^ + * + * In addition, you can use multiple entries, to specify alternate + * user directories (a la Directory Index). For example: + * + * UserDir public_html /usr/web http://www.xyz.com/users + * + */ + +#include "httpd.h" +#include "http_config.h" + +module userdir_module; + +/* + * Sever config for this module is a little unconventional... + * It's just one string anyway, so why pretend? + */ + +void *create_userdir_config (pool *dummy, server_rec *s) { + return (void*)DEFAULT_USER_DIR; +} + +const char *set_user_dir (cmd_parms *cmd, void *dummy, char *arg) +{ + void *server_conf = cmd->server->module_config; + + set_module_config (server_conf, &userdir_module, pstrdup (cmd->pool, arg)); + return NULL; +} + +command_rec userdir_cmds[] = { +{ "UserDir", set_user_dir, NULL, RSRC_CONF, RAW_ARGS, + "the public subdirectory in users' home directories, or 'disabled'" }, +{ NULL } +}; + +int translate_userdir (request_rec *r) +{ + void *server_conf = r->server->module_config; + const char *userdirs = (char *)get_module_config(server_conf, + &userdir_module); + char *name = r->uri; + const char *w, *dname, *redirect; + char *x = NULL; + + if (userdirs == NULL || !strcasecmp(userdirs, "disabled") || + (name[0] != '/') || (name[1] != '~')) { + return DECLINED; + } + + while (*userdirs) { + const char *userdir = getword_conf (r->pool, &userdirs); + char *filename = NULL; + + dname = name + 2; + w = getword(r->pool, &dname, '/'); + + if (!strcmp(w, "")) + return DECLINED; + + /* The 'dname' funny business involves backing it up to capture + * the '/' delimiting the "/~user" part from the rest of the URL, + * in case there was one (the case where there wasn't being just + * "GET /~user HTTP/1.0", for which we don't want to tack on a + * '/' onto the filename). + */ + + if (dname[-1] == '/') --dname; + + if (strchr(userdir, '*')) + x = getword(r->pool, &userdir, '*'); + +#ifdef __EMX__ + /* Add support for OS/2 drive letters */ + if ((userdir[0] == '/') || (userdir[1] == ':') || (userdir[0] == '\0')) { +#else + if ((userdir[0] == '/') || (userdir[0] == '\0')) { +#endif + if (x) { + if (strchr(x, ':')) { + redirect = pstrcat(r->pool, x, w, userdir, dname, NULL); + table_set (r->headers_out, "Location", redirect); + return REDIRECT; + } + else + filename = pstrcat (r->pool, x, w, userdir, NULL); + } + else + filename = pstrcat (r->pool, userdir, "/", w, NULL); + } + else if (strchr(userdir, ':')) { + redirect = pstrcat(r->pool, userdir, "/", w, dname, NULL); + table_set (r->headers_out, "Location", redirect); + return REDIRECT; + } + else { + struct passwd *pw; + if((pw=getpwnam(w))) +#ifdef __EMX__ + /* Need to manually add user name for OS/2 */ + filename = pstrcat (r->pool, pw->pw_dir, w, "/", userdir, NULL); +#else + filename = pstrcat (r->pool, pw->pw_dir, "/", userdir, NULL); +#endif + + } + + /* Now see if it exists, or we're at the last entry. If we are at the + last entry, then use the filename generated (if there is one) anyway, + in the hope that some handler might handle it. This can be used, for + example, to run a CGI script for the user. + */ + if (filename && (!*userdirs || stat(filename, &r->finfo) != -1)) { + r->filename = pstrcat(r->pool, filename, dname, NULL); + return OK; + } + } + + return DECLINED; +} + +module userdir_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + NULL, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + create_userdir_config, /* server config */ + NULL, /* merge server config */ + userdir_cmds, /* command table */ + NULL, /* handlers */ + translate_userdir, /*filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/modules/standard/mod_usertrack.c b/APACHE_1_2_X/src/modules/standard/mod_usertrack.c new file mode 100644 index 00000000000..a205aa52a50 --- /dev/null +++ b/APACHE_1_2_X/src/modules/standard/mod_usertrack.c @@ -0,0 +1,326 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* User Tracking Module (Was mod_cookies.c) + * + * This Apache module is designed to track users paths through a site. + * It uses the client-side state ("Cookie") protocol developed by Netscape. + * It is known to work on Netscape browsers, Microsoft Internet + * Explorer and others currently being developed. + * + * Each time a page is requested we look to see if the browser is sending + * us a Cookie: header that we previously generated. + * + * If we don't find one then the user hasn't been to this site since + * starting their browser or their browser doesn't support cookies. So + * we generate a unique Cookie for the transaction and send it back to + * the browser (via a "Set-Cookie" header) + * Future requests from the same browser should keep the same Cookie line. + * + * By matching up all the requests with the same cookie you can + * work out exactly what path a user took through your site. To log + * the cookie use the " %{Cookie}n " directive in a custom access log; + * + * Example 1 : If you currently use the standard Log file format (CLF) + * and use the command "TransferLog somefilename", add the line + * LogFormat "%h %l %u %t \"%r\" %s %b %{Cookie}n" + * to your config file. + * + * Example 2 : If you used to use the old "CookieLog" directive, you + * can emulate it by adding the following command to your config file + * CustomLog filename "%{Cookie}n \"%r\" %t" + * + * Notes: + * 1. This code now logs the initial transaction (the one that created + * the cookie to start with). + * 2. This module has been designed to not interfere with other Cookies + * your site may be using; just avoid sending out cookies with + * the name "Apache=" or things will get confused. + * 3. If you want you can modify the Set-Cookie line so that the Cookie + * never expires. You would then get the same Cookie each time the + * user revisits your site. + * + * Mark Cox, mark@ukweb.com, 6 July 95 + * + * This file replaces mod_cookies.c + */ + +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include + +module usertrack_module; + +typedef struct { + int always; + time_t expires; +} cookie_log_state; + +/* Define this to allow post-2000 cookies. Cookies use two-digit dates, + * so it might be dicey. (Netscape does it correctly, but others may not) + */ +#define MILLENIAL_COOKIES + +/* Make Cookie: Now we have to generate something that is going to be + * pretty unique. We can base it on the pid, time, hostip */ + +#define COOKIE_NAME "Apache=" + +void make_cookie(request_rec *r) +{ + cookie_log_state *cls = get_module_config (r->server->module_config, + &usertrack_module); +#ifdef MPE + clock_t mpe_times; + struct tms mpe_tms; +#else + struct timeval tv; + struct timezone tz = { 0 , 0 }; +#endif + /* 1024 == hardcoded constants */ + char *new_cookie = palloc( r->pool, 1024); + char *cookiebuf = palloc( r->pool, 1024); + char *dot; + const char *rname = pstrdup(r->pool, + get_remote_host(r->connection, r->per_dir_config, + REMOTE_NAME)); + + if ((dot = strchr(rname,'.'))) *dot='\0'; /* First bit of hostname */ + +#ifdef MPE +/* MPE lacks gettimeofday(), so we must use time() to obtain the epoch + seconds, and then times() to obtain CPU clock ticks (milliseconds). + Combine this together to obtain a hopefully unique cookie ID. */ + + mpe_times=times(&mpe_tms); + + ap_snprintf(cookiebuf, 1024, "%s%d%ld%ld", rname, (int)getpid(), + (long)time(NULL), (long)mpe_tms.tms_utime); +#else + gettimeofday(&tv, &tz); + + ap_snprintf(cookiebuf, 1024, "%s%d%ld%d", rname, (int)getpid(), + (long)tv.tv_sec, (int)tv.tv_usec/1000); +#endif + + if (cls->expires) { + static const char *const days[7]= + {"Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; + struct tm *tms; + time_t when = time(NULL) + cls->expires; + +#ifndef MILLENIAL_COOKIES + /* Only two-digit date string, so we can't trust "00" or more. + * Therefore, we knock it all back to just before midnight on + * 1/1/2000 (which is 946684799) + */ + + if (when > 946684799) + when = 946684799; +#endif + tms = gmtime(&when); + + /* Cookie with date; as strftime '%a, %d-%h-%y %H:%M:%S GMT' */ + ap_snprintf(new_cookie, 1024, + "%s%s; path=/; expires=%s, %.2d-%s-%.2d %.2d:%.2d:%.2d GMT", + COOKIE_NAME, cookiebuf, days[tms->tm_wday], + tms->tm_mday, month_snames[tms->tm_mon], + (tms->tm_year >= 100) ? tms->tm_year - 100 : tms->tm_year, + tms->tm_hour, tms->tm_min, tms->tm_sec); + } + else + ap_snprintf(new_cookie, 1024, "%s%s; path=/", COOKIE_NAME, cookiebuf); + + table_set(r->headers_out,"Set-Cookie",new_cookie); + table_set(r->notes, "cookie", cookiebuf); /* log first time */ + return; +} + +int spot_cookie(request_rec *r) +{ + int *enable = (int *)get_module_config(r->per_dir_config, + &usertrack_module); + char *cookie; + char *value; + + if (!*enable) return DECLINED; + + if ((cookie = table_get (r->headers_in, "Cookie"))) + if ((value=strstr(cookie,COOKIE_NAME))) { + char *cookiebuf, *cookieend; + + value+=strlen(COOKIE_NAME); + cookiebuf=pstrdup( r->pool, value ); + cookieend=strchr(cookiebuf,';'); + if (cookieend) *cookieend='\0'; /* Ignore anything after a ; */ + + /* Set the cookie in a note, for logging */ + table_set(r->notes, "cookie", cookiebuf); + + return DECLINED; /* Theres already a cookie, no new one */ + } + make_cookie(r); + return OK; /* We set our cookie */ +} + +void *make_cookie_log_state (pool *p, server_rec *s) +{ + cookie_log_state *cls = + (cookie_log_state *)palloc (p, sizeof (cookie_log_state)); + + cls->expires = 0; + + return (void *)cls; +} + +void *make_cookie_dir (pool *p, char *d) { + return (void *)pcalloc(p, sizeof(int)); +} + +const char *set_cookie_enable (cmd_parms *cmd, int *c, int arg) +{ + *c = arg; + return NULL; +} + +const char *set_cookie_exp (cmd_parms *parms, void *dummy, const char *arg) +{ + cookie_log_state *cls = get_module_config (parms->server->module_config, + &usertrack_module); + time_t factor, modifier = 0; + time_t num = 0; + char *word; + + /* The simple case first - all numbers (we assume) */ + if (isdigit(arg[0]) && isdigit(arg[strlen(arg)-1])) { + cls->expires = atol(arg); + return NULL; + } + + /* The harder case - stolen from mod_expires + * CookieExpires "[plus] { }*" + */ + + word = getword_conf( parms->pool, &arg ); + if ( !strncasecmp( word, "plus", 1 ) ) { + word = getword_conf( parms->pool, &arg ); + }; + + /* { }* */ + while ( word[0] ) { + /* */ + if ( strchr("0123456789", word[0]) != NULL ) + num = atoi( word ); + else + return "bad expires code, numeric value expected."; + + /* */ + word = getword_conf( parms->pool, &arg ); + if (!word[0] ) + return "bad expires code, missing "; + + factor = 0; + if ( !strncasecmp( word, "years", 1 ) ) + factor = 60*60*24*365; + else if ( !strncasecmp( word, "months", 2 ) ) + factor = 60*60*24*30; + else if ( !strncasecmp( word, "weeks", 1 ) ) + factor = 60*60*24*7; + else if ( !strncasecmp( word, "days", 1 ) ) + factor = 60*60*24; + else if ( !strncasecmp( word, "hours", 1 ) ) + factor = 60*60; + else if ( !strncasecmp( word, "minutes", 2 ) ) + factor = 60; + else if ( !strncasecmp( word, "seconds", 1 ) ) + factor = 1; + else + return "bad expires code, unrecognized type"; + + modifier = modifier + factor * num; + + /* next */ + word = getword_conf( parms->pool, &arg ); + } + + cls->expires = modifier; + + return NULL; +} + +command_rec cookie_log_cmds[] = { +{ "CookieExpires", set_cookie_exp, NULL, RSRC_CONF, TAKE1, + "an expiry date code" }, +{ "CookieTracking", set_cookie_enable, NULL, OR_FILEINFO, FLAG, + "whether or not to enable cookies" }, +{ NULL } +}; + +module usertrack_module = { + STANDARD_MODULE_STUFF, + NULL, /* initializer */ + make_cookie_dir, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + make_cookie_log_state, /* server config */ + NULL, /* merge server configs */ + cookie_log_cmds, /* command table */ + NULL, /* handlers */ + NULL, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + spot_cookie, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +}; diff --git a/APACHE_1_2_X/src/regex/.cvsignore b/APACHE_1_2_X/src/regex/.cvsignore new file mode 100644 index 00000000000..b99cd824e2d --- /dev/null +++ b/APACHE_1_2_X/src/regex/.cvsignore @@ -0,0 +1,3 @@ +*.ih +re + diff --git a/APACHE_1_2_X/src/regex/COPYRIGHT b/APACHE_1_2_X/src/regex/COPYRIGHT new file mode 100644 index 00000000000..d43362fbfc9 --- /dev/null +++ b/APACHE_1_2_X/src/regex/COPYRIGHT @@ -0,0 +1,20 @@ +Copyright 1992, 1993, 1994 Henry Spencer. All rights reserved. +This software is not subject to any license of the American Telephone +and Telegraph Company or of the Regents of the University of California. + +Permission is granted to anyone to use this software for any purpose on +any computer system, and to alter it and redistribute it, subject +to the following restrictions: + +1. The author is not responsible for the consequences of use of this + software, no matter how awful, even if they arise from flaws in it. + +2. The origin of this software must not be misrepresented, either by + explicit claim or by omission. Since few users ever read sources, + credits must appear in the documentation. + +3. Altered versions must be plainly marked as such, and must not be + misrepresented as being the original software. Since few users + ever read sources, credits must appear in the documentation. + +4. This notice may not be removed or altered. diff --git a/APACHE_1_2_X/src/regex/Makefile b/APACHE_1_2_X/src/regex/Makefile new file mode 100644 index 00000000000..e4ea0154bea --- /dev/null +++ b/APACHE_1_2_X/src/regex/Makefile @@ -0,0 +1,133 @@ +SHELL = /bin/sh + +# You probably want to take -DREDEBUG out of CFLAGS, and put something like +# -O in, *after* testing (-DREDEBUG strengthens testing by enabling a lot of +# internal assertion checking and some debugging facilities). +# Put -Dconst= in for a pre-ANSI compiler. +# Do not take -DPOSIX_MISTAKE out. +# REGCFLAGS isn't important to you (it's for my use in some special contexts). +CFLAGS=-I. -DPOSIX_MISTAKE $(AUX_CFLAGS) + +# If you have a pre-ANSI compiler, put -o into MKHFLAGS. If you want +# the Berkeley __P macro, put -b in. +MKHFLAGS= + +# Flags for linking but not compiling, if any. +LDFLAGS= + +# Extra libraries for linking, if any. +LIBS= + +# Internal stuff, should not need changing. +OBJPRODN=regcomp.o regexec.o regerror.o regfree.o +OBJS=$(OBJPRODN) split.o debug.o main.o +H=cclass.h cname.h regex2.h utils.h +REGSRC=regcomp.c regerror.c regexec.c regfree.c +ALLSRC=$(REGSRC) engine.c debug.c main.c split.c + +# Stuff that matters only if you're trying to lint the package. +LINTFLAGS=-I. -Dstatic= -Dconst= -DREDEBUG +LINTC=regcomp.c regexec.c regerror.c regfree.c debug.c main.c +JUNKLINT=possible pointer alignment|null effect + +# arrangements to build forward-reference header files +.SUFFIXES: .ih .h +.c.ih: + sh ./mkh $(MKHFLAGS) -p $< >$@ + +default: r + +lib: purge $(OBJPRODN) + rm -f libregex.a + ar crv libregex.a $(OBJPRODN) + $(RANLIB) libregex.a + +purge: + rm -f *.o + +# stuff to build regex.h +REGEXH=regex.h +REGEXHSRC=regex2.h $(REGSRC) +$(REGEXH): $(REGEXHSRC) mkh + sh ./mkh $(MKHFLAGS) -i _REGEX_H_ $(REGEXHSRC) >regex.tmp + cmp -s regex.tmp regex.h 2>/dev/null || cp regex.tmp regex.h + rm -f regex.tmp + +# dependencies +$(OBJPRODN) debug.o: utils.h regex.h regex2.h +regcomp.o: cclass.h cname.h regcomp.ih +regexec.o: engine.c engine.ih +regerror.o: regerror.ih +debug.o: debug.ih +main.o: main.ih + +# tester +re: $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@ + +# regression test +r: re tests + ./re &1 | egrep -v '$(JUNKLINT)' | tee lint + +fullprint: + ti README WHATSNEW notes todo | list + ti *.h | list + list *.c + list regex.3 regex.7 + +print: + ti README WHATSNEW notes todo | list + ti *.h | list + list reg*.c engine.c + + +mf.tmp: Makefile + sed '/^REGEXH=/s/=.*/=regex.h/' Makefile | sed '/#DEL$$/d' >$@ + +DTRH=cclass.h cname.h regex2.h utils.h +PRE=COPYRIGHT README WHATSNEW +POST=mkh regex.3 regex.7 tests $(DTRH) $(ALLSRC) fake/*.[ch] +FILES=$(PRE) Makefile $(POST) +DTR=$(PRE) Makefile=mf.tmp $(POST) +dtr: $(FILES) mf.tmp + makedtr $(DTR) >$@ + rm mf.tmp + +cio: $(FILES) + cio $(FILES) + +rdf: $(FILES) + rcsdiff -c $(FILES) 2>&1 | p + +# various forms of cleanup +tidy: + rm -f junk* core core.* *.core dtr *.tmp lint + +clean: tidy + rm -f *.o *.s *.ih re libregex.a + +# don't do this one unless you know what you're doing +spotless: clean + rm -f mkh regex.h diff --git a/APACHE_1_2_X/src/regex/README b/APACHE_1_2_X/src/regex/README new file mode 100644 index 00000000000..cea9b67b666 --- /dev/null +++ b/APACHE_1_2_X/src/regex/README @@ -0,0 +1,32 @@ +alpha3.4 release. +Thu Mar 17 23:17:18 EST 1994 +henry@zoo.toronto.edu + +See WHATSNEW for change listing. + +installation notes: +-------- +Read the comments at the beginning of Makefile before running. + +Utils.h contains some things that just might have to be modified on +some systems, as well as a nested include (ugh) of . + +The "fake" directory contains quick-and-dirty fakes for some header +files and routines that old systems may not have. Note also that +-DUSEBCOPY will make utils.h substitute bcopy() for memmove(). + +After that, "make r" will build regcomp.o, regexec.o, regfree.o, +and regerror.o (the actual routines), bundle them together into a test +program, and run regression tests on them. No output is good output. + +"make lib" builds just the .o files for the actual routines (when +you're happy with testing and have adjusted CFLAGS for production), +and puts them together into libregex.a. You can pick up either the +library or *.o ("make lib" makes sure there are no other .o files left +around to confuse things). + +Main.c, debug.c, split.c are used for regression testing but are not part +of the RE routines themselves. + +Regex.h goes in /usr/include. All other .h files are internal only. +-------- diff --git a/APACHE_1_2_X/src/regex/WHATSNEW b/APACHE_1_2_X/src/regex/WHATSNEW new file mode 100644 index 00000000000..6e82e1dae0c --- /dev/null +++ b/APACHE_1_2_X/src/regex/WHATSNEW @@ -0,0 +1,92 @@ +New in alpha3.4: The complex bug alluded to below has been fixed (in a +slightly kludgey temporary way that may hurt efficiency a bit; this is +another "get it out the door for 4.4" release). The tests at the end of +the tests file have accordingly been uncommented. The primary sign of +the bug was that something like a?b matching ab matched b rather than ab. +(The bug was essentially specific to this exact situation, else it would +have shown up earlier.) + +New in alpha3.3: The definition of word boundaries has been altered +slightly, to more closely match the usual programming notion that "_" +is an alphabetic. Stuff used for pre-ANSI systems is now in a subdir, +and the makefile no longer alludes to it in mysterious ways. The +makefile has generally been cleaned up some. Fixes have been made +(again!) so that the regression test will run without -DREDEBUG, at +the cost of weaker checking. A workaround for a bug in some folks' + has been added. And some more things have been added to +tests, including a couple right at the end which are commented out +because the code currently flunks them (complex bug; fix coming). +Plus the usual minor cleanup. + +New in alpha3.2: Assorted bits of cleanup and portability improvement +(the development base is now a BSDI system using GCC instead of an ancient +Sun system, and the newer compiler exposed some glitches). Fix for a +serious bug that affected REs using many [] (including REG_ICASE REs +because of the way they are implemented), *sometimes*, depending on +memory-allocation patterns. The header-file prototypes no longer name +the parameters, avoiding possible name conflicts. The possibility that +some clot has defined CHAR_MIN as (say) `-128' instead of `(-128)' is +now handled gracefully. "uchar" is no longer used as an internal type +name (too many people have the same idea). Still the same old lousy +performance, alas. + +New in alpha3.1: Basically nothing, this release is just a bookkeeping +convenience. Stay tuned. + +New in alpha3.0: Performance is no better, alas, but some fixes have been +made and some functionality has been added. (This is basically the "get +it out the door in time for 4.4" release.) One bug fix: regfree() didn't +free the main internal structure (how embarrassing). It is now possible +to put NULs in either the RE or the target string, using (resp.) a new +REG_PEND flag and the old REG_STARTEND flag. The REG_NOSPEC flag to +regcomp() makes all characters ordinary, so you can match a literal +string easily (this will become more useful when performance improves!). +There are now primitives to match beginnings and ends of words, although +the syntax is disgusting and so is the implementation. The REG_ATOI +debugging interface has changed a bit. And there has been considerable +internal cleanup of various kinds. + +New in alpha2.3: Split change list out of README, and moved flags notes +into Makefile. Macro-ized the name of regex(7) in regex(3), since it has +to change for 4.4BSD. Cleanup work in engine.c, and some new regression +tests to catch tricky cases thereof. + +New in alpha2.2: Out-of-date manpages updated. Regerror() acquires two +small extensions -- REG_ITOA and REG_ATOI -- which avoid debugging kludges +in my own test program and might be useful to others for similar purposes. +The regression test will now compile (and run) without REDEBUG. The +BRE \$ bug is fixed. Most uses of "uchar" are gone; it's all chars now. +Char/uchar parameters are now written int/unsigned, to avoid possible +portability problems with unpromoted parameters. Some unsigned casts have +been introduced to minimize portability problems with shifting into sign +bits. + +New in alpha2.1: Lots of little stuff, cleanup and fixes. The one big +thing is that regex.h is now generated, using mkh, rather than being +supplied in the distribution; due to circularities in dependencies, +you have to build regex.h explicitly by "make h". The two known bugs +have been fixed (and the regression test now checks for them), as has a +problem with assertions not being suppressed in the absence of REDEBUG. +No performance work yet. + +New in alpha2: Backslash-anything is an ordinary character, not an +error (except, of course, for the handful of backslashed metacharacters +in BREs), which should reduce script breakage. The regression test +checks *where* null strings are supposed to match, and has generally +been tightened up somewhat. Small bug fixes in parameter passing (not +harmful, but technically errors) and some other areas. Debugging +invoked by defining REDEBUG rather than not defining NDEBUG. + +New in alpha+3: full prototyping for internal routines, using a little +helper program, mkh, which extracts prototypes given in stylized comments. +More minor cleanup. Buglet fix: it's CHAR_BIT, not CHAR_BITS. Simple +pre-screening of input when a literal string is known to be part of the +RE; this does wonders for performance. + +New in alpha+2: minor bits of cleanup. Notably, the number "32" for the +word width isn't hardwired into regexec.c any more, the public header +file prototypes the functions if __STDC__ is defined, and some small typos +in the manpages have been fixed. + +New in alpha+1: improvements to the manual pages, and an important +extension, the REG_STARTEND option to regexec(). diff --git a/APACHE_1_2_X/src/regex/cclass.h b/APACHE_1_2_X/src/regex/cclass.h new file mode 100644 index 00000000000..727cbb92552 --- /dev/null +++ b/APACHE_1_2_X/src/regex/cclass.h @@ -0,0 +1,31 @@ +/* character-class table */ +static struct cclass { + char *name; + char *chars; + char *multis; +} cclasses[] = { + { "alnum", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ +0123456789", "" }, + { "alpha", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", + "" }, + { "blank", " \t", "" }, + { "cntrl", "\007\b\t\n\v\f\r\1\2\3\4\5\6\16\17\20\21\22\23\24\ +\25\26\27\30\31\32\33\34\35\36\37\177", "" }, + { "digit", "0123456789", "" }, + { "graph", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ +0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + "" }, + { "lower", "abcdefghijklmnopqrstuvwxyz", + "" }, + { "print", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ +0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ ", + "" }, + { "punct", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + "" }, + { "space", "\t\n\v\f\r ", "" }, + { "upper", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "" }, + { "xdigit", "0123456789ABCDEFabcdef", + "" }, + { NULL, 0, "" } +}; diff --git a/APACHE_1_2_X/src/regex/cname.h b/APACHE_1_2_X/src/regex/cname.h new file mode 100644 index 00000000000..ff116e55e23 --- /dev/null +++ b/APACHE_1_2_X/src/regex/cname.h @@ -0,0 +1,102 @@ +/* character-name table */ +static struct cname { + char *name; + char code; +} cnames[] = { + { "NUL", '\0' }, + { "SOH", '\001' }, + { "STX", '\002' }, + { "ETX", '\003' }, + { "EOT", '\004' }, + { "ENQ", '\005' }, + { "ACK", '\006' }, + { "BEL", '\007' }, + { "alert", '\007' }, + { "BS", '\010' }, + { "backspace", '\b' }, + { "HT", '\011' }, + { "tab", '\t' }, + { "LF", '\012' }, + { "newline", '\n' }, + { "VT", '\013' }, + { "vertical-tab", '\v' }, + { "FF", '\014' }, + { "form-feed", '\f' }, + { "CR", '\015' }, + { "carriage-return", '\r' }, + { "SO", '\016' }, + { "SI", '\017' }, + { "DLE", '\020' }, + { "DC1", '\021' }, + { "DC2", '\022' }, + { "DC3", '\023' }, + { "DC4", '\024' }, + { "NAK", '\025' }, + { "SYN", '\026' }, + { "ETB", '\027' }, + { "CAN", '\030' }, + { "EM", '\031' }, + { "SUB", '\032' }, + { "ESC", '\033' }, + { "IS4", '\034' }, + { "FS", '\034' }, + { "IS3", '\035' }, + { "GS", '\035' }, + { "IS2", '\036' }, + { "RS", '\036' }, + { "IS1", '\037' }, + { "US", '\037' }, + { "space", ' ' }, + { "exclamation-mark", '!' }, + { "quotation-mark", '"' }, + { "number-sign", '#' }, + { "dollar-sign", '$' }, + { "percent-sign", '%' }, + { "ampersand", '&' }, + { "apostrophe", '\'' }, + { "left-parenthesis", '(' }, + { "right-parenthesis", ')' }, + { "asterisk", '*' }, + { "plus-sign", '+' }, + { "comma", ',' }, + { "hyphen", '-' }, + { "hyphen-minus", '-' }, + { "period", '.' }, + { "full-stop", '.' }, + { "slash", '/' }, + { "solidus", '/' }, + { "zero", '0' }, + { "one", '1' }, + { "two", '2' }, + { "three", '3' }, + { "four", '4' }, + { "five", '5' }, + { "six", '6' }, + { "seven", '7' }, + { "eight", '8' }, + { "nine", '9' }, + { "colon", ':' }, + { "semicolon", ';' }, + { "less-than-sign", '<' }, + { "equals-sign", '=' }, + { "greater-than-sign", '>' }, + { "question-mark", '?' }, + { "commercial-at", '@' }, + { "left-square-bracket", '[' }, + { "backslash", '\\' }, + { "reverse-solidus", '\\' }, + { "right-square-bracket", ']' }, + { "circumflex", '^' }, + { "circumflex-accent", '^' }, + { "underscore", '_' }, + { "low-line", '_' }, + { "grave-accent", '`' }, + { "left-brace", '{' }, + { "left-curly-bracket", '{' }, + { "vertical-line", '|' }, + { "right-brace", '}' }, + { "right-curly-bracket", '}' }, + { "tilde", '~' }, + { "DEL", '\177' }, + { NULL, 0 } +}; diff --git a/APACHE_1_2_X/src/regex/debug.c b/APACHE_1_2_X/src/regex/debug.c new file mode 100644 index 00000000000..c0feaeb1694 --- /dev/null +++ b/APACHE_1_2_X/src/regex/debug.c @@ -0,0 +1,242 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "regex2.h" +#include "debug.ih" + +/* + - regprint - print a regexp for debugging + == void regprint(regex_t *r, FILE *d); + */ +void +regprint(r, d) +regex_t *r; +FILE *d; +{ + register struct re_guts *g = r->re_g; + register int i; + register int c; + register int last; + int nincat[NC]; + + fprintf(d, "%ld states, %d categories", (long)g->nstates, + g->ncategories); + fprintf(d, ", first %ld last %ld", (long)g->firststate, + (long)g->laststate); + if (g->iflags&USEBOL) + fprintf(d, ", USEBOL"); + if (g->iflags&USEEOL) + fprintf(d, ", USEEOL"); + if (g->iflags&BAD) + fprintf(d, ", BAD"); + if (g->nsub > 0) + fprintf(d, ", nsub=%ld", (long)g->nsub); + if (g->must != NULL) + fprintf(d, ", must(%ld) `%*s'", (long)g->mlen, (int)g->mlen, + g->must); + if (g->backrefs) + fprintf(d, ", backrefs"); + if (g->nplus > 0) + fprintf(d, ", nplus %ld", (long)g->nplus); + fprintf(d, "\n"); + s_print(g, d); + for (i = 0; i < g->ncategories; i++) { + nincat[i] = 0; + for (c = CHAR_MIN; c <= CHAR_MAX; c++) + if (g->categories[c] == i) + nincat[i]++; + } + fprintf(d, "cc0#%d", nincat[0]); + for (i = 1; i < g->ncategories; i++) + if (nincat[i] == 1) { + for (c = CHAR_MIN; c <= CHAR_MAX; c++) + if (g->categories[c] == i) + break; + fprintf(d, ", %d=%s", i, regchar(c)); + } + fprintf(d, "\n"); + for (i = 1; i < g->ncategories; i++) + if (nincat[i] != 1) { + fprintf(d, "cc%d\t", i); + last = -1; + for (c = CHAR_MIN; c <= CHAR_MAX+1; c++) /* +1 does flush */ + if (c <= CHAR_MAX && g->categories[c] == i) { + if (last < 0) { + fprintf(d, "%s", regchar(c)); + last = c; + } + } else { + if (last >= 0) { + if (last != c-1) + fprintf(d, "-%s", + regchar(c-1)); + last = -1; + } + } + fprintf(d, "\n"); + } +} + +/* + - s_print - print the strip for debugging + == static void s_print(register struct re_guts *g, FILE *d); + */ +static void +s_print(g, d) +register struct re_guts *g; +FILE *d; +{ + register sop *s; + register cset *cs; + register int i; + register int done = 0; + register sop opnd; + register int col = 0; + register int last; + register sopno offset = 2; +# define GAP() { if (offset % 5 == 0) { \ + if (col > 40) { \ + fprintf(d, "\n\t"); \ + col = 0; \ + } else { \ + fprintf(d, " "); \ + col++; \ + } \ + } else \ + col++; \ + offset++; \ + } + + if (OP(g->strip[0]) != OEND) + fprintf(d, "missing initial OEND!\n"); + for (s = &g->strip[1]; !done; s++) { + opnd = OPND(*s); + switch (OP(*s)) { + case OEND: + fprintf(d, "\n"); + done = 1; + break; + case OCHAR: + if (strchr("\\|()^$.[+*?{}!<> ", (char)opnd) != NULL) + fprintf(d, "\\%c", (char)opnd); + else + fprintf(d, "%s", regchar((char)opnd)); + break; + case OBOL: + fprintf(d, "^"); + break; + case OEOL: + fprintf(d, "$"); + break; + case OBOW: + fprintf(d, "\\{"); + break; + case OEOW: + fprintf(d, "\\}"); + break; + case OANY: + fprintf(d, "."); + break; + case OANYOF: + fprintf(d, "[(%ld)", (long)opnd); + cs = &g->sets[opnd]; + last = -1; + for (i = 0; i < g->csetsize+1; i++) /* +1 flushes */ + if (CHIN(cs, i) && i < g->csetsize) { + if (last < 0) { + fprintf(d, "%s", regchar(i)); + last = i; + } + } else { + if (last >= 0) { + if (last != i-1) + fprintf(d, "-%s", + regchar(i-1)); + last = -1; + } + } + fprintf(d, "]"); + break; + case OBACK_: + fprintf(d, "(\\<%ld>", (long)opnd); + break; + case O_BACK: + fprintf(d, "<%ld>\\)", (long)opnd); + break; + case OPLUS_: + fprintf(d, "(+"); + if (OP(*(s+opnd)) != O_PLUS) + fprintf(d, "<%ld>", (long)opnd); + break; + case O_PLUS: + if (OP(*(s-opnd)) != OPLUS_) + fprintf(d, "<%ld>", (long)opnd); + fprintf(d, "+)"); + break; + case OQUEST_: + fprintf(d, "(?"); + if (OP(*(s+opnd)) != O_QUEST) + fprintf(d, "<%ld>", (long)opnd); + break; + case O_QUEST: + if (OP(*(s-opnd)) != OQUEST_) + fprintf(d, "<%ld>", (long)opnd); + fprintf(d, "?)"); + break; + case OLPAREN: + fprintf(d, "((<%ld>", (long)opnd); + break; + case ORPAREN: + fprintf(d, "<%ld>))", (long)opnd); + break; + case OCH_: + fprintf(d, "<"); + if (OP(*(s+opnd)) != OOR2) + fprintf(d, "<%ld>", (long)opnd); + break; + case OOR1: + if (OP(*(s-opnd)) != OOR1 && OP(*(s-opnd)) != OCH_) + fprintf(d, "<%ld>", (long)opnd); + fprintf(d, "|"); + break; + case OOR2: + fprintf(d, "|"); + if (OP(*(s+opnd)) != OOR2 && OP(*(s+opnd)) != O_CH) + fprintf(d, "<%ld>", (long)opnd); + break; + case O_CH: + if (OP(*(s-opnd)) != OOR1) + fprintf(d, "<%ld>", (long)opnd); + fprintf(d, ">"); + break; + default: + fprintf(d, "!%ld(%ld)!", OP(*s), opnd); + break; + } + if (!done) + GAP(); + } +} + +/* + - regchar - make a character printable + == static char *regchar(int ch); + */ +static char * /* -> representation */ +regchar(ch) +int ch; +{ + static char buf[10]; + + if (isprint(ch) || ch == ' ') + sprintf(buf, "%c", ch); + else + sprintf(buf, "\\%o", ch); + return(buf); +} diff --git a/APACHE_1_2_X/src/regex/engine.c b/APACHE_1_2_X/src/regex/engine.c new file mode 100644 index 00000000000..f3b36b3e01b --- /dev/null +++ b/APACHE_1_2_X/src/regex/engine.c @@ -0,0 +1,1019 @@ +/* + * The matching engine and friends. This file is #included by regexec.c + * after suitable #defines of a variety of macros used herein, so that + * different state representations can be used without duplicating masses + * of code. + */ + +#ifdef SNAMES +#define matcher smatcher +#define fast sfast +#define slow sslow +#define dissect sdissect +#define backref sbackref +#define step sstep +#define print sprint +#define at sat +#define match smat +#endif +#ifdef LNAMES +#define matcher lmatcher +#define fast lfast +#define slow lslow +#define dissect ldissect +#define backref lbackref +#define step lstep +#define print lprint +#define at lat +#define match lmat +#endif + +/* another structure passed up and down to avoid zillions of parameters */ +struct match { + struct re_guts *g; + int eflags; + regmatch_t *pmatch; /* [nsub+1] (0 element unused) */ + char *offp; /* offsets work from here */ + char *beginp; /* start of string -- virtual NUL precedes */ + char *endp; /* end of string -- virtual NUL here */ + char *coldp; /* can be no match starting before here */ + char **lastpos; /* [nplus+1] */ + STATEVARS; + states st; /* current states */ + states fresh; /* states for a fresh start */ + states tmp; /* temporary */ + states empty; /* empty set of states */ +}; + +#include "engine.ih" + +#ifdef REDEBUG +#define SP(t, s, c) print(m, t, s, c, stdout) +#define AT(t, p1, p2, s1, s2) at(m, t, p1, p2, s1, s2) +#define NOTE(str) { if (m->eflags®_TRACE) printf("=%s\n", (str)); } +#else +#define SP(t, s, c) /* nothing */ +#define AT(t, p1, p2, s1, s2) /* nothing */ +#define NOTE(s) /* nothing */ +#endif + +/* + - matcher - the actual matching engine + == static int matcher(register struct re_guts *g, char *string, \ + == size_t nmatch, regmatch_t pmatch[], int eflags); + */ +static int /* 0 success, REG_NOMATCH failure */ +matcher(g, string, nmatch, pmatch, eflags) +register struct re_guts *g; +char *string; +size_t nmatch; +regmatch_t pmatch[]; +int eflags; +{ + register char *endp; + register int i; + struct match mv; + register struct match *m = &mv; + register char *dp; + register const sopno gf = g->firststate+1; /* +1 for OEND */ + register const sopno gl = g->laststate; + char *start; + char *stop; + + /* simplify the situation where possible */ + if (g->cflags®_NOSUB) + nmatch = 0; + if (eflags®_STARTEND) { + start = string + pmatch[0].rm_so; + stop = string + pmatch[0].rm_eo; + } else { + start = string; + stop = start + strlen(start); + } + if (stop < start) + return(REG_INVARG); + + /* prescreening; this does wonders for this rather slow code */ + if (g->must != NULL) { + for (dp = start; dp < stop; dp++) + if (*dp == g->must[0] && stop - dp >= g->mlen && + memcmp(dp, g->must, (size_t)g->mlen) == 0) + break; + if (dp == stop) /* we didn't find g->must */ + return(REG_NOMATCH); + } + + /* match struct setup */ + m->g = g; + m->eflags = eflags; + m->pmatch = NULL; + m->lastpos = NULL; + m->offp = string; + m->beginp = start; + m->endp = stop; + STATESETUP(m, 4); + SETUP(m->st); + SETUP(m->fresh); + SETUP(m->tmp); + SETUP(m->empty); + CLEAR(m->empty); + + /* this loop does only one repetition except for backrefs */ + for (;;) { + endp = fast(m, start, stop, gf, gl); + if (endp == NULL) { /* a miss */ + STATETEARDOWN(m); + return(REG_NOMATCH); + } + if (nmatch == 0 && !g->backrefs) + break; /* no further info needed */ + + /* where? */ + assert(m->coldp != NULL); + for (;;) { + NOTE("finding start"); + endp = slow(m, m->coldp, stop, gf, gl); + if (endp != NULL) + break; + assert(m->coldp < m->endp); + m->coldp++; + } + if (nmatch == 1 && !g->backrefs) + break; /* no further info needed */ + + /* oh my, he wants the subexpressions... */ + if (m->pmatch == NULL) + m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) * + sizeof(regmatch_t)); + if (m->pmatch == NULL) { + STATETEARDOWN(m); + return(REG_ESPACE); + } + for (i = 1; i <= m->g->nsub; i++) + m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1; + if (!g->backrefs && !(m->eflags®_BACKR)) { + NOTE("dissecting"); + dp = dissect(m, m->coldp, endp, gf, gl); + } else { + if (g->nplus > 0 && m->lastpos == NULL) + m->lastpos = (char **)malloc((g->nplus+1) * + sizeof(char *)); + if (g->nplus > 0 && m->lastpos == NULL) { + free(m->pmatch); + STATETEARDOWN(m); + return(REG_ESPACE); + } + NOTE("backref dissect"); + dp = backref(m, m->coldp, endp, gf, gl, (sopno)0); + } + if (dp != NULL) + break; + + /* uh-oh... we couldn't find a subexpression-level match */ + assert(g->backrefs); /* must be back references doing it */ + assert(g->nplus == 0 || m->lastpos != NULL); + for (;;) { + if (dp != NULL || endp <= m->coldp) + break; /* defeat */ + NOTE("backoff"); + endp = slow(m, m->coldp, endp-1, gf, gl); + if (endp == NULL) + break; /* defeat */ + /* try it on a shorter possibility */ +#ifndef NDEBUG + for (i = 1; i <= m->g->nsub; i++) { + assert(m->pmatch[i].rm_so == -1); + assert(m->pmatch[i].rm_eo == -1); + } +#endif + NOTE("backoff dissect"); + dp = backref(m, m->coldp, endp, gf, gl, (sopno)0); + } + assert(dp == NULL || dp == endp); + if (dp != NULL) /* found a shorter one */ + break; + + /* despite initial appearances, there is no match here */ + NOTE("false alarm"); + start = m->coldp + 1; /* recycle starting later */ + assert(start <= stop); + } + + /* fill in the details if requested */ + if (nmatch > 0) { + pmatch[0].rm_so = m->coldp - m->offp; + pmatch[0].rm_eo = endp - m->offp; + } + if (nmatch > 1) { + assert(m->pmatch != NULL); + for (i = 1; i < nmatch; i++) + if (i <= m->g->nsub) + pmatch[i] = m->pmatch[i]; + else { + pmatch[i].rm_so = -1; + pmatch[i].rm_eo = -1; + } + } + + if (m->pmatch != NULL) + free((char *)m->pmatch); + if (m->lastpos != NULL) + free((char *)m->lastpos); + STATETEARDOWN(m); + return(0); +} + +/* + - dissect - figure out what matched what, no back references + == static char *dissect(register struct match *m, char *start, \ + == char *stop, sopno startst, sopno stopst); + */ +static char * /* == stop (success) always */ +dissect(m, start, stop, startst, stopst) +register struct match *m; +char *start; +char *stop; +sopno startst; +sopno stopst; +{ + register int i; + register sopno ss; /* start sop of current subRE */ + register sopno es; /* end sop of current subRE */ + register char *sp; /* start of string matched by it */ + register char *stp; /* string matched by it cannot pass here */ + register char *rest; /* start of rest of string */ + register char *tail; /* string unmatched by rest of RE */ + register sopno ssub; /* start sop of subsubRE */ + register sopno esub; /* end sop of subsubRE */ + register char *ssp; /* start of string matched by subsubRE */ + register char *sep; /* end of string matched by subsubRE */ + register char *oldssp; /* previous ssp */ + register char *dp; + + AT("diss", start, stop, startst, stopst); + sp = start; + for (ss = startst; ss < stopst; ss = es) { + /* identify end of subRE */ + es = ss; + switch (OP(m->g->strip[es])) { + case OPLUS_: + case OQUEST_: + es += OPND(m->g->strip[es]); + break; + case OCH_: + while (OP(m->g->strip[es]) != O_CH) + es += OPND(m->g->strip[es]); + break; + } + es++; + + /* figure out what it matched */ + switch (OP(m->g->strip[ss])) { + case OEND: + assert(nope); + break; + case OCHAR: + sp++; + break; + case OBOL: + case OEOL: + case OBOW: + case OEOW: + break; + case OANY: + case OANYOF: + sp++; + break; + case OBACK_: + case O_BACK: + assert(nope); + break; + /* cases where length of match is hard to find */ + case OQUEST_: + stp = stop; + for (;;) { + /* how long could this one be? */ + rest = slow(m, sp, stp, ss, es); + assert(rest != NULL); /* it did match */ + /* could the rest match the rest? */ + tail = slow(m, rest, stop, es, stopst); + if (tail == stop) + break; /* yes! */ + /* no -- try a shorter match for this one */ + stp = rest - 1; + assert(stp >= sp); /* it did work */ + } + ssub = ss + 1; + esub = es - 1; + /* did innards match? */ + if (slow(m, sp, rest, ssub, esub) != NULL) { + dp = dissect(m, sp, rest, ssub, esub); + assert(dp == rest); + } else /* no */ + assert(sp == rest); + sp = rest; + break; + case OPLUS_: + stp = stop; + for (;;) { + /* how long could this one be? */ + rest = slow(m, sp, stp, ss, es); + assert(rest != NULL); /* it did match */ + /* could the rest match the rest? */ + tail = slow(m, rest, stop, es, stopst); + if (tail == stop) + break; /* yes! */ + /* no -- try a shorter match for this one */ + stp = rest - 1; + assert(stp >= sp); /* it did work */ + } + ssub = ss + 1; + esub = es - 1; + ssp = sp; + oldssp = ssp; + for (;;) { /* find last match of innards */ + sep = slow(m, ssp, rest, ssub, esub); + if (sep == NULL || sep == ssp) + break; /* failed or matched null */ + oldssp = ssp; /* on to next try */ + ssp = sep; + } + if (sep == NULL) { + /* last successful match */ + sep = ssp; + ssp = oldssp; + } + assert(sep == rest); /* must exhaust substring */ + assert(slow(m, ssp, sep, ssub, esub) == rest); + dp = dissect(m, ssp, sep, ssub, esub); + assert(dp == sep); + sp = rest; + break; + case OCH_: + stp = stop; + for (;;) { + /* how long could this one be? */ + rest = slow(m, sp, stp, ss, es); + assert(rest != NULL); /* it did match */ + /* could the rest match the rest? */ + tail = slow(m, rest, stop, es, stopst); + if (tail == stop) + break; /* yes! */ + /* no -- try a shorter match for this one */ + stp = rest - 1; + assert(stp >= sp); /* it did work */ + } + ssub = ss + 1; + esub = ss + OPND(m->g->strip[ss]) - 1; + assert(OP(m->g->strip[esub]) == OOR1); + for (;;) { /* find first matching branch */ + if (slow(m, sp, rest, ssub, esub) == rest) + break; /* it matched all of it */ + /* that one missed, try next one */ + assert(OP(m->g->strip[esub]) == OOR1); + esub++; + assert(OP(m->g->strip[esub]) == OOR2); + ssub = esub + 1; + esub += OPND(m->g->strip[esub]); + if (OP(m->g->strip[esub]) == OOR2) + esub--; + else + assert(OP(m->g->strip[esub]) == O_CH); + } + dp = dissect(m, sp, rest, ssub, esub); + assert(dp == rest); + sp = rest; + break; + case O_PLUS: + case O_QUEST: + case OOR1: + case OOR2: + case O_CH: + assert(nope); + break; + case OLPAREN: + i = OPND(m->g->strip[ss]); + assert(0 < i && i <= m->g->nsub); + m->pmatch[i].rm_so = sp - m->offp; + break; + case ORPAREN: + i = OPND(m->g->strip[ss]); + assert(0 < i && i <= m->g->nsub); + m->pmatch[i].rm_eo = sp - m->offp; + break; + default: /* uh oh */ + assert(nope); + break; + } + } + + assert(sp == stop); + return(sp); +} + +/* + - backref - figure out what matched what, figuring in back references + == static char *backref(register struct match *m, char *start, \ + == char *stop, sopno startst, sopno stopst, sopno lev); + */ +static char * /* == stop (success) or NULL (failure) */ +backref(m, start, stop, startst, stopst, lev) +register struct match *m; +char *start; +char *stop; +sopno startst; +sopno stopst; +sopno lev; /* PLUS nesting level */ +{ + register int i; + register sopno ss; /* start sop of current subRE */ + register char *sp; /* start of string matched by it */ + register sopno ssub; /* start sop of subsubRE */ + register sopno esub; /* end sop of subsubRE */ + register char *ssp; /* start of string matched by subsubRE */ + register char *dp; + register size_t len; + register int hard; + register sop s; + register regoff_t offsave; + register cset *cs; + + AT("back", start, stop, startst, stopst); + sp = start; + + /* get as far as we can with easy stuff */ + hard = 0; + for (ss = startst; !hard && ss < stopst; ss++) + switch (OP(s = m->g->strip[ss])) { + case OCHAR: + if (sp == stop || *sp++ != (char)OPND(s)) + return(NULL); + break; + case OANY: + if (sp == stop) + return(NULL); + sp++; + break; + case OANYOF: + cs = &m->g->sets[OPND(s)]; + if (sp == stop || !CHIN(cs, *sp++)) + return(NULL); + break; + case OBOL: + if ( (sp == m->beginp && !(m->eflags®_NOTBOL)) || + (sp < m->endp && *(sp-1) == '\n' && + (m->g->cflags®_NEWLINE)) ) + { /* yes */ } + else + return(NULL); + break; + case OEOL: + if ( (sp == m->endp && !(m->eflags®_NOTEOL)) || + (sp < m->endp && *sp == '\n' && + (m->g->cflags®_NEWLINE)) ) + { /* yes */ } + else + return(NULL); + break; + case OBOW: + if (( (sp == m->beginp && !(m->eflags®_NOTBOL)) || + (sp < m->endp && *(sp-1) == '\n' && + (m->g->cflags®_NEWLINE)) || + (sp > m->beginp && + !ISWORD(*(sp-1))) ) && + (sp < m->endp && ISWORD(*sp)) ) + { /* yes */ } + else + return(NULL); + break; + case OEOW: + if (( (sp == m->endp && !(m->eflags®_NOTEOL)) || + (sp < m->endp && *sp == '\n' && + (m->g->cflags®_NEWLINE)) || + (sp < m->endp && !ISWORD(*sp)) ) && + (sp > m->beginp && ISWORD(*(sp-1))) ) + { /* yes */ } + else + return(NULL); + break; + case O_QUEST: + break; + case OOR1: /* matches null but needs to skip */ + ss++; + s = m->g->strip[ss]; + do { + assert(OP(s) == OOR2); + ss += OPND(s); + } while (OP(s = m->g->strip[ss]) != O_CH); + /* note that the ss++ gets us past the O_CH */ + break; + default: /* have to make a choice */ + hard = 1; + break; + } + if (!hard) { /* that was it! */ + if (sp != stop) + return(NULL); + return(sp); + } + ss--; /* adjust for the for's final increment */ + + /* the hard stuff */ + AT("hard", sp, stop, ss, stopst); + s = m->g->strip[ss]; + switch (OP(s)) { + case OBACK_: /* the vilest depths */ + i = OPND(s); + assert(0 < i && i <= m->g->nsub); + if (m->pmatch[i].rm_eo == -1) + return(NULL); + assert(m->pmatch[i].rm_so != -1); + len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so; + assert(stop - m->beginp >= len); + if (sp > stop - len) + return(NULL); /* not enough left to match */ + ssp = m->offp + m->pmatch[i].rm_so; + if (memcmp(sp, ssp, len) != 0) + return(NULL); + while (m->g->strip[ss] != SOP(O_BACK, i)) + ss++; + return(backref(m, sp+len, stop, ss+1, stopst, lev)); + break; + case OQUEST_: /* to null or not */ + dp = backref(m, sp, stop, ss+1, stopst, lev); + if (dp != NULL) + return(dp); /* not */ + return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev)); + break; + case OPLUS_: + assert(m->lastpos != NULL); + assert(lev+1 <= m->g->nplus); + m->lastpos[lev+1] = sp; + return(backref(m, sp, stop, ss+1, stopst, lev+1)); + break; + case O_PLUS: + if (sp == m->lastpos[lev]) /* last pass matched null */ + return(backref(m, sp, stop, ss+1, stopst, lev-1)); + /* try another pass */ + m->lastpos[lev] = sp; + dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev); + if (dp == NULL) + return(backref(m, sp, stop, ss+1, stopst, lev-1)); + else + return(dp); + break; + case OCH_: /* find the right one, if any */ + ssub = ss + 1; + esub = ss + OPND(s) - 1; + assert(OP(m->g->strip[esub]) == OOR1); + for (;;) { /* find first matching branch */ + dp = backref(m, sp, stop, ssub, esub, lev); + if (dp != NULL) + return(dp); + /* that one missed, try next one */ + if (OP(m->g->strip[esub]) == O_CH) + return(NULL); /* there is none */ + esub++; + assert(OP(m->g->strip[esub]) == OOR2); + ssub = esub + 1; + esub += OPND(m->g->strip[esub]); + if (OP(m->g->strip[esub]) == OOR2) + esub--; + else + assert(OP(m->g->strip[esub]) == O_CH); + } + break; + case OLPAREN: /* must undo assignment if rest fails */ + i = OPND(s); + assert(0 < i && i <= m->g->nsub); + offsave = m->pmatch[i].rm_so; + m->pmatch[i].rm_so = sp - m->offp; + dp = backref(m, sp, stop, ss+1, stopst, lev); + if (dp != NULL) + return(dp); + m->pmatch[i].rm_so = offsave; + return(NULL); + break; + case ORPAREN: /* must undo assignment if rest fails */ + i = OPND(s); + assert(0 < i && i <= m->g->nsub); + offsave = m->pmatch[i].rm_eo; + m->pmatch[i].rm_eo = sp - m->offp; + dp = backref(m, sp, stop, ss+1, stopst, lev); + if (dp != NULL) + return(dp); + m->pmatch[i].rm_eo = offsave; + return(NULL); + break; + default: /* uh oh */ + assert(nope); + break; + } + + /* "can't happen" */ + assert(nope); + /* NOTREACHED */ + return( NULL ); +} + +/* + - fast - step through the string at top speed + == static char *fast(register struct match *m, char *start, \ + == char *stop, sopno startst, sopno stopst); + */ +static char * /* where tentative match ended, or NULL */ +fast(m, start, stop, startst, stopst) +register struct match *m; +char *start; +char *stop; +sopno startst; +sopno stopst; +{ + register states st = m->st; + register states fresh = m->fresh; + register states tmp = m->tmp; + register char *p = start; + register int c = (start == m->beginp) ? OUT : *(start-1); + register int lastc; /* previous c */ + register int flagch; + register int i; + register char *coldp; /* last p after which no match was underway */ + + CLEAR(st); + SET1(st, startst); + st = step(m->g, startst, stopst, st, NOTHING, st); + ASSIGN(fresh, st); + SP("start", st, *p); + coldp = NULL; + for (;;) { + /* next character */ + lastc = c; + c = (p == m->endp) ? OUT : *p; + if (EQ(st, fresh)) + coldp = p; + + /* is there an EOL and/or BOL between lastc and c? */ + flagch = '\0'; + i = 0; + if ( (lastc == '\n' && m->g->cflags®_NEWLINE) || + (lastc == OUT && !(m->eflags®_NOTBOL)) ) { + flagch = BOL; + i = m->g->nbol; + } + if ( (c == '\n' && m->g->cflags®_NEWLINE) || + (c == OUT && !(m->eflags®_NOTEOL)) ) { + flagch = (flagch == BOL) ? BOLEOL : EOL; + i += m->g->neol; + } + if (i != 0) { + for (; i > 0; i--) + st = step(m->g, startst, stopst, st, flagch, st); + SP("boleol", st, c); + } + + /* how about a word boundary? */ + if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) && + (c != OUT && ISWORD(c)) ) { + flagch = BOW; + } + if ( (lastc != OUT && ISWORD(lastc)) && + (flagch == EOL || (c != OUT && !ISWORD(c))) ) { + flagch = EOW; + } + if (flagch == BOW || flagch == EOW) { + st = step(m->g, startst, stopst, st, flagch, st); + SP("boweow", st, c); + } + + /* are we done? */ + if (ISSET(st, stopst) || p == stop) + break; /* NOTE BREAK OUT */ + + /* no, we must deal with this character */ + ASSIGN(tmp, st); + ASSIGN(st, fresh); + assert(c != OUT); + st = step(m->g, startst, stopst, tmp, c, st); + SP("aft", st, c); + assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st)); + p++; + } + + assert(coldp != NULL); + m->coldp = coldp; + if (ISSET(st, stopst)) + return(p+1); + else + return(NULL); +} + +/* + - slow - step through the string more deliberately + == static char *slow(register struct match *m, char *start, \ + == char *stop, sopno startst, sopno stopst); + */ +static char * /* where it ended */ +slow(m, start, stop, startst, stopst) +register struct match *m; +char *start; +char *stop; +sopno startst; +sopno stopst; +{ + register states st = m->st; + register states empty = m->empty; + register states tmp = m->tmp; + register char *p = start; + register int c = (start == m->beginp) ? OUT : *(start-1); + register int lastc; /* previous c */ + register int flagch; + register int i; + register char *matchp; /* last p at which a match ended */ + + AT("slow", start, stop, startst, stopst); + CLEAR(st); + SET1(st, startst); + SP("sstart", st, *p); + st = step(m->g, startst, stopst, st, NOTHING, st); + matchp = NULL; + for (;;) { + /* next character */ + lastc = c; + c = (p == m->endp) ? OUT : *p; + + /* is there an EOL and/or BOL between lastc and c? */ + flagch = '\0'; + i = 0; + if ( (lastc == '\n' && m->g->cflags®_NEWLINE) || + (lastc == OUT && !(m->eflags®_NOTBOL)) ) { + flagch = BOL; + i = m->g->nbol; + } + if ( (c == '\n' && m->g->cflags®_NEWLINE) || + (c == OUT && !(m->eflags®_NOTEOL)) ) { + flagch = (flagch == BOL) ? BOLEOL : EOL; + i += m->g->neol; + } + if (i != 0) { + for (; i > 0; i--) + st = step(m->g, startst, stopst, st, flagch, st); + SP("sboleol", st, c); + } + + /* how about a word boundary? */ + if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) && + (c != OUT && ISWORD(c)) ) { + flagch = BOW; + } + if ( (lastc != OUT && ISWORD(lastc)) && + (flagch == EOL || (c != OUT && !ISWORD(c))) ) { + flagch = EOW; + } + if (flagch == BOW || flagch == EOW) { + st = step(m->g, startst, stopst, st, flagch, st); + SP("sboweow", st, c); + } + + /* are we done? */ + if (ISSET(st, stopst)) + matchp = p; + if (EQ(st, empty) || p == stop) + break; /* NOTE BREAK OUT */ + + /* no, we must deal with this character */ + ASSIGN(tmp, st); + ASSIGN(st, empty); + assert(c != OUT); + st = step(m->g, startst, stopst, tmp, c, st); + SP("saft", st, c); + assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st)); + p++; + } + + return(matchp); +} + + +/* + - step - map set of states reachable before char to set reachable after + == static states step(register struct re_guts *g, sopno start, sopno stop, \ + == register states bef, int ch, register states aft); + == #define BOL (OUT+1) + == #define EOL (BOL+1) + == #define BOLEOL (BOL+2) + == #define NOTHING (BOL+3) + == #define BOW (BOL+4) + == #define EOW (BOL+5) + == #define CODEMAX (BOL+5) // highest code used + == #define NONCHAR(c) ((c) > CHAR_MAX) + == #define NNONCHAR (CODEMAX-CHAR_MAX) + */ +static states +step(g, start, stop, bef, ch, aft) +register struct re_guts *g; +sopno start; /* start state within strip */ +sopno stop; /* state after stop state within strip */ +register states bef; /* states reachable before */ +int ch; /* character or NONCHAR code */ +register states aft; /* states already known reachable after */ +{ + register cset *cs; + register sop s; + register sopno pc; + register onestate here; /* note, macros know this name */ + register sopno look; + register int i; + + for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) { + s = g->strip[pc]; + switch (OP(s)) { + case OEND: + assert(pc == stop-1); + break; + case OCHAR: + /* only characters can match */ + assert(!NONCHAR(ch) || ch != (char)OPND(s)); + if (ch == (char)OPND(s)) + FWD(aft, bef, 1); + break; + case OBOL: + if (ch == BOL || ch == BOLEOL) + FWD(aft, bef, 1); + break; + case OEOL: + if (ch == EOL || ch == BOLEOL) + FWD(aft, bef, 1); + break; + case OBOW: + if (ch == BOW) + FWD(aft, bef, 1); + break; + case OEOW: + if (ch == EOW) + FWD(aft, bef, 1); + break; + case OANY: + if (!NONCHAR(ch)) + FWD(aft, bef, 1); + break; + case OANYOF: + cs = &g->sets[OPND(s)]; + if (!NONCHAR(ch) && CHIN(cs, ch)) + FWD(aft, bef, 1); + break; + case OBACK_: /* ignored here */ + case O_BACK: + FWD(aft, aft, 1); + break; + case OPLUS_: /* forward, this is just an empty */ + FWD(aft, aft, 1); + break; + case O_PLUS: /* both forward and back */ + FWD(aft, aft, 1); + i = ISSETBACK(aft, OPND(s)); + BACK(aft, aft, OPND(s)); + if (!i && ISSETBACK(aft, OPND(s))) { + /* oho, must reconsider loop body */ + pc -= OPND(s) + 1; + INIT(here, pc); + } + break; + case OQUEST_: /* two branches, both forward */ + FWD(aft, aft, 1); + FWD(aft, aft, OPND(s)); + break; + case O_QUEST: /* just an empty */ + FWD(aft, aft, 1); + break; + case OLPAREN: /* not significant here */ + case ORPAREN: + FWD(aft, aft, 1); + break; + case OCH_: /* mark the first two branches */ + FWD(aft, aft, 1); + assert(OP(g->strip[pc+OPND(s)]) == OOR2); + FWD(aft, aft, OPND(s)); + break; + case OOR1: /* done a branch, find the O_CH */ + if (ISSTATEIN(aft, here)) { + for (look = 1; + OP(s = g->strip[pc+look]) != O_CH; + look += OPND(s)) + assert(OP(s) == OOR2); + FWD(aft, aft, look); + } + break; + case OOR2: /* propagate OCH_'s marking */ + FWD(aft, aft, 1); + if (OP(g->strip[pc+OPND(s)]) != O_CH) { + assert(OP(g->strip[pc+OPND(s)]) == OOR2); + FWD(aft, aft, OPND(s)); + } + break; + case O_CH: /* just empty */ + FWD(aft, aft, 1); + break; + default: /* ooooops... */ + assert(nope); + break; + } + } + + return(aft); +} + +#ifdef REDEBUG +/* + - print - print a set of states + == #ifdef REDEBUG + == static void print(struct match *m, char *caption, states st, \ + == int ch, FILE *d); + == #endif + */ +static void +print(m, caption, st, ch, d) +struct match *m; +char *caption; +states st; +int ch; +FILE *d; +{ + register struct re_guts *g = m->g; + register int i; + register int first = 1; + + if (!(m->eflags®_TRACE)) + return; + + fprintf(d, "%s", caption); + if (ch != '\0') + fprintf(d, " %s", pchar(ch)); + for (i = 0; i < g->nstates; i++) + if (ISSET(st, i)) { + fprintf(d, "%s%d", (first) ? "\t" : ", ", i); + first = 0; + } + fprintf(d, "\n"); +} + +/* + - at - print current situation + == #ifdef REDEBUG + == static void at(struct match *m, char *title, char *start, char *stop, \ + == sopno startst, sopno stopst); + == #endif + */ +static void +at(m, title, start, stop, startst, stopst) +struct match *m; +char *title; +char *start; +char *stop; +sopno startst; +sopno stopst; +{ + if (!(m->eflags®_TRACE)) + return; + + printf("%s %s-", title, pchar(*start)); + printf("%s ", pchar(*stop)); + printf("%ld-%ld\n", (long)startst, (long)stopst); +} + +#ifndef PCHARDONE +#define PCHARDONE /* never again */ +/* + - pchar - make a character printable + == #ifdef REDEBUG + == static char *pchar(int ch); + == #endif + * + * Is this identical to regchar() over in debug.c? Well, yes. But a + * duplicate here avoids having a debugging-capable regexec.o tied to + * a matching debug.o, and this is convenient. It all disappears in + * the non-debug compilation anyway, so it doesn't matter much. + */ +static char * /* -> representation */ +pchar(ch) +int ch; +{ + static char pbuf[10]; + + if (isprint(ch) || ch == ' ') + sprintf(pbuf, "%c", ch); + else + sprintf(pbuf, "\\%o", ch); + return(pbuf); +} +#endif +#endif + +#undef matcher +#undef fast +#undef slow +#undef dissect +#undef backref +#undef step +#undef print +#undef at +#undef match diff --git a/APACHE_1_2_X/src/regex/main.c b/APACHE_1_2_X/src/regex/main.c new file mode 100644 index 00000000000..657338a2c19 --- /dev/null +++ b/APACHE_1_2_X/src/regex/main.c @@ -0,0 +1,510 @@ +#include +#include +#include +#include +#include +#include + +#include "main.ih" + +char *progname; +int debug = 0; +int line = 0; +int status = 0; + +int copts = REG_EXTENDED; +int eopts = 0; +regoff_t startoff = 0; +regoff_t endoff = 0; + + +extern int split(); +extern void regprint(); + +/* + - main - do the simple case, hand off to regress() for regression + */ +int main(argc, argv) +int argc; +char *argv[]; +{ + regex_t re; +# define NS 10 + regmatch_t subs[NS]; + char erbuf[100]; + int err; + size_t len; + int c; + int errflg = 0; + register int i; + extern int optind; + extern char *optarg; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "c:e:S:E:x")) != EOF) + switch (c) { + case 'c': /* compile options */ + copts = options('c', optarg); + break; + case 'e': /* execute options */ + eopts = options('e', optarg); + break; + case 'S': /* start offset */ + startoff = (regoff_t)atoi(optarg); + break; + case 'E': /* end offset */ + endoff = (regoff_t)atoi(optarg); + break; + case 'x': /* Debugging. */ + debug++; + break; + case '?': + default: + errflg++; + break; + } + if (errflg) { + fprintf(stderr, "usage: %s ", progname); + fprintf(stderr, "[-c copt][-C][-d] [re]\n"); + exit(2); + } + + if (optind >= argc) { + regress(stdin); + exit(status); + } + + err = regcomp(&re, argv[optind++], copts); + if (err) { + len = regerror(err, &re, erbuf, sizeof(erbuf)); + fprintf(stderr, "error %s, %d/%d `%s'\n", + eprint(err), len, sizeof(erbuf), erbuf); + exit(status); + } + regprint(&re, stdout); + + if (optind >= argc) { + regfree(&re); + exit(status); + } + + if (eopts®_STARTEND) { + subs[0].rm_so = startoff; + subs[0].rm_eo = strlen(argv[optind]) - endoff; + } + err = regexec(&re, argv[optind], (size_t)NS, subs, eopts); + if (err) { + len = regerror(err, &re, erbuf, sizeof(erbuf)); + fprintf(stderr, "error %s, %d/%d `%s'\n", + eprint(err), len, sizeof(erbuf), erbuf); + exit(status); + } + if (!(copts®_NOSUB)) { + len = (int)(subs[0].rm_eo - subs[0].rm_so); + if (subs[0].rm_so != -1) { + if (len != 0) + printf("match `%.*s'\n", (int)len, + argv[optind] + subs[0].rm_so); + else + printf("match `'@%.1s\n", + argv[optind] + subs[0].rm_so); + } + for (i = 1; i < NS; i++) + if (subs[i].rm_so != -1) + printf("(%d) `%.*s'\n", i, + (int)(subs[i].rm_eo - subs[i].rm_so), + argv[optind] + subs[i].rm_so); + } + exit(status); +} + +/* + - regress - main loop of regression test + == void regress(FILE *in); + */ +void +regress(in) +FILE *in; +{ + char inbuf[1000]; +# define MAXF 10 + char *f[MAXF]; + int nf; + int i; + char erbuf[100]; + size_t ne; + char *badpat = "invalid regular expression"; +# define SHORT 10 + char *bpname = "REG_BADPAT"; + regex_t re; + + while (fgets(inbuf, sizeof(inbuf), in) != NULL) { + line++; + if (inbuf[0] == '#' || inbuf[0] == '\n') + continue; /* NOTE CONTINUE */ + inbuf[strlen(inbuf)-1] = '\0'; /* get rid of stupid \n */ + if (debug) + fprintf(stdout, "%d:\n", line); + nf = split(inbuf, f, MAXF, "\t\t"); + if (nf < 3) { + fprintf(stderr, "bad input, line %d\n", line); + exit(1); + } + for (i = 0; i < nf; i++) + if (strcmp(f[i], "\"\"") == 0) + f[i] = ""; + if (nf <= 3) + f[3] = NULL; + if (nf <= 4) + f[4] = NULL; + try(f[0], f[1], f[2], f[3], f[4], options('c', f[1])); + if (opt('&', f[1])) /* try with either type of RE */ + try(f[0], f[1], f[2], f[3], f[4], + options('c', f[1]) &~ REG_EXTENDED); + } + + ne = regerror(REG_BADPAT, (regex_t *)NULL, erbuf, sizeof(erbuf)); + if (strcmp(erbuf, badpat) != 0 || ne != strlen(badpat)+1) { + fprintf(stderr, "end: regerror() test gave `%s' not `%s'\n", + erbuf, badpat); + status = 1; + } + ne = regerror(REG_BADPAT, (regex_t *)NULL, erbuf, (size_t)SHORT); + if (strncmp(erbuf, badpat, SHORT-1) != 0 || erbuf[SHORT-1] != '\0' || + ne != strlen(badpat)+1) { + fprintf(stderr, "end: regerror() short test gave `%s' not `%.*s'\n", + erbuf, SHORT-1, badpat); + status = 1; + } + ne = regerror(REG_ITOA|REG_BADPAT, (regex_t *)NULL, erbuf, sizeof(erbuf)); + if (strcmp(erbuf, bpname) != 0 || ne != strlen(bpname)+1) { + fprintf(stderr, "end: regerror() ITOA test gave `%s' not `%s'\n", + erbuf, bpname); + status = 1; + } + re.re_endp = bpname; + ne = regerror(REG_ATOI, &re, erbuf, sizeof(erbuf)); + if (atoi(erbuf) != (int)REG_BADPAT) { + fprintf(stderr, "end: regerror() ATOI test gave `%s' not `%ld'\n", + erbuf, (long)REG_BADPAT); + status = 1; + } else if (ne != strlen(erbuf)+1) { + fprintf(stderr, "end: regerror() ATOI test len(`%s') = %ld\n", + erbuf, (long)REG_BADPAT); + status = 1; + } +} + +/* + - try - try it, and report on problems + == void try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts); + */ +void +try(f0, f1, f2, f3, f4, opts) +char *f0; +char *f1; +char *f2; +char *f3; +char *f4; +int opts; /* may not match f1 */ +{ + regex_t re; +# define NSUBS 10 + regmatch_t subs[NSUBS]; +# define NSHOULD 15 + char *should[NSHOULD]; + int nshould; + char erbuf[100]; + int err; + int len; + char *type = (opts & REG_EXTENDED) ? "ERE" : "BRE"; + register int i; + char *grump; + char f0copy[1000]; + char f2copy[1000]; + + strcpy(f0copy, f0); + re.re_endp = (opts®_PEND) ? f0copy + strlen(f0copy) : NULL; + fixstr(f0copy); + err = regcomp(&re, f0copy, opts); + if (err != 0 && (!opt('C', f1) || err != efind(f2))) { + /* unexpected error or wrong error */ + len = regerror(err, &re, erbuf, sizeof(erbuf)); + fprintf(stderr, "%d: %s error %s, %d/%d `%s'\n", + line, type, eprint(err), len, + sizeof(erbuf), erbuf); + status = 1; + } else if (err == 0 && opt('C', f1)) { + /* unexpected success */ + fprintf(stderr, "%d: %s should have given REG_%s\n", + line, type, f2); + status = 1; + err = 1; /* so we won't try regexec */ + } + + if (err != 0) { + regfree(&re); + return; + } + + strcpy(f2copy, f2); + fixstr(f2copy); + + if (options('e', f1)®_STARTEND) { + if (strchr(f2, '(') == NULL || strchr(f2, ')') == NULL) + fprintf(stderr, "%d: bad STARTEND syntax\n", line); + subs[0].rm_so = strchr(f2, '(') - f2 + 1; + subs[0].rm_eo = strchr(f2, ')') - f2; + } + err = regexec(&re, f2copy, NSUBS, subs, options('e', f1)); + + if (err != 0 && (f3 != NULL || err != REG_NOMATCH)) { + /* unexpected error or wrong error */ + len = regerror(err, &re, erbuf, sizeof(erbuf)); + fprintf(stderr, "%d: %s exec error %s, %d/%d `%s'\n", + line, type, eprint(err), len, + sizeof(erbuf), erbuf); + status = 1; + } else if (err != 0) { + /* nothing more to check */ + } else if (f3 == NULL) { + /* unexpected success */ + fprintf(stderr, "%d: %s exec should have failed\n", + line, type); + status = 1; + err = 1; /* just on principle */ + } else if (opts®_NOSUB) { + /* nothing more to check */ + } else if ((grump = check(f2, subs[0], f3)) != NULL) { + fprintf(stderr, "%d: %s %s\n", line, type, grump); + status = 1; + err = 1; + } + + if (err != 0 || f4 == NULL) { + regfree(&re); + return; + } + + for (i = 1; i < NSHOULD; i++) + should[i] = NULL; + nshould = split(f4, should+1, NSHOULD-1, ","); + if (nshould == 0) { + nshould = 1; + should[1] = ""; + } + for (i = 1; i < NSUBS; i++) { + grump = check(f2, subs[i], should[i]); + if (grump != NULL) { + fprintf(stderr, "%d: %s $%d %s\n", line, + type, i, grump); + status = 1; + err = 1; + } + } + + regfree(&re); +} + +/* + - options - pick options out of a regression-test string + == int options(int type, char *s); + */ +int +options(type, s) +int type; /* 'c' compile, 'e' exec */ +char *s; +{ + register char *p; + register int o = (type == 'c') ? copts : eopts; + register char *legal = (type == 'c') ? "bisnmp" : "^$#tl"; + + for (p = s; *p != '\0'; p++) + if (strchr(legal, *p) != NULL) + switch (*p) { + case 'b': + o &= ~REG_EXTENDED; + break; + case 'i': + o |= REG_ICASE; + break; + case 's': + o |= REG_NOSUB; + break; + case 'n': + o |= REG_NEWLINE; + break; + case 'm': + o &= ~REG_EXTENDED; + o |= REG_NOSPEC; + break; + case 'p': + o |= REG_PEND; + break; + case '^': + o |= REG_NOTBOL; + break; + case '$': + o |= REG_NOTEOL; + break; + case '#': + o |= REG_STARTEND; + break; + case 't': /* trace */ + o |= REG_TRACE; + break; + case 'l': /* force long representation */ + o |= REG_LARGE; + break; + case 'r': /* force backref use */ + o |= REG_BACKR; + break; + } + return(o); +} + +/* + - opt - is a particular option in a regression string? + == int opt(int c, char *s); + */ +int /* predicate */ +opt(c, s) +int c; +char *s; +{ + return(strchr(s, c) != NULL); +} + +/* + - fixstr - transform magic characters in strings + == void fixstr(register char *p); + */ +void +fixstr(p) +register char *p; +{ + if (p == NULL) + return; + + for (; *p != '\0'; p++) + if (*p == 'N') + *p = '\n'; + else if (*p == 'T') + *p = '\t'; + else if (*p == 'S') + *p = ' '; + else if (*p == 'Z') + *p = '\0'; +} + +/* + - check - check a substring match + == char *check(char *str, regmatch_t sub, char *should); + */ +char * /* NULL or complaint */ +check(str, sub, should) +char *str; +regmatch_t sub; +char *should; +{ + register int len; + register int shlen; + register char *p; + static char grump[500]; + register char *at = NULL; + + if (should != NULL && strcmp(should, "-") == 0) + should = NULL; + if (should != NULL && should[0] == '@') { + at = should + 1; + should = ""; + } + + /* check rm_so and rm_eo for consistency */ + if (sub.rm_so > sub.rm_eo || (sub.rm_so == -1 && sub.rm_eo != -1) || + (sub.rm_so != -1 && sub.rm_eo == -1) || + (sub.rm_so != -1 && sub.rm_so < 0) || + (sub.rm_eo != -1 && sub.rm_eo < 0) ) { + sprintf(grump, "start %ld end %ld", (long)sub.rm_so, + (long)sub.rm_eo); + return(grump); + } + + /* check for no match */ + if (sub.rm_so == -1 && should == NULL) + return(NULL); + if (sub.rm_so == -1) + return("did not match"); + + /* check for in range */ + if (sub.rm_eo > strlen(str)) { + sprintf(grump, "start %ld end %ld, past end of string", + (long)sub.rm_so, (long)sub.rm_eo); + return(grump); + } + + len = (int)(sub.rm_eo - sub.rm_so); + shlen = (int)strlen(should); + p = str + sub.rm_so; + + /* check for not supposed to match */ + if (should == NULL) { + sprintf(grump, "matched `%.*s'", len, p); + return(grump); + } + + /* check for wrong match */ + if (len != shlen || strncmp(p, should, (size_t)shlen) != 0) { + sprintf(grump, "matched `%.*s' instead", len, p); + return(grump); + } + if (shlen > 0) + return(NULL); + + /* check null match in right place */ + if (at == NULL) + return(NULL); + shlen = strlen(at); + if (shlen == 0) + shlen = 1; /* force check for end-of-string */ + if (strncmp(p, at, shlen) != 0) { + sprintf(grump, "matched null at `%.20s'", p); + return(grump); + } + return(NULL); +} + +/* + - eprint - convert error number to name + == static char *eprint(int err); + */ +static char * +eprint(err) +int err; +{ + static char epbuf[100]; + size_t len; + + len = regerror(REG_ITOA|err, (regex_t *)NULL, epbuf, sizeof(epbuf)); + assert(len <= sizeof(epbuf)); + return(epbuf); +} + +/* + - efind - convert error name to number + == static int efind(char *name); + */ +static int +efind(name) +char *name; +{ + static char efbuf[100]; + regex_t re; + + sprintf(efbuf, "REG_%s", name); + assert(strlen(efbuf) < sizeof(efbuf)); + re.re_endp = efbuf; + (void) regerror(REG_ATOI, &re, efbuf, sizeof(efbuf)); + return(atoi(efbuf)); +} diff --git a/APACHE_1_2_X/src/regex/mkh b/APACHE_1_2_X/src/regex/mkh new file mode 100644 index 00000000000..252b246c7bd --- /dev/null +++ b/APACHE_1_2_X/src/regex/mkh @@ -0,0 +1,76 @@ +#! /bin/sh +# mkh - pull headers out of C source +PATH=/bin:/usr/bin ; export PATH + +# egrep pattern to pick out marked lines +egrep='^ =([ ]|$)' + +# Sed program to process marked lines into lines for the header file. +# The markers have already been removed. Two things are done here: removal +# of backslashed newlines, and some fudging of comments. The first is done +# because -o needs to have prototypes on one line to strip them down. +# Getting comments into the output is tricky; we turn C++-style // comments +# into /* */ comments, after altering any existing */'s to avoid trouble. +peel=' /\\$/N + /\\\n[ ]*/s///g + /\/\//s;\*/;* /;g + /\/\//s;//\(.*\);/*\1 */;' + +for a +do + case "$a" in + -o) # old (pre-function-prototype) compiler + # add code to comment out argument lists + peel="$peel + "'/^\([^#\/][^\/]*[a-zA-Z0-9_)]\)(\(.*\))/s;;\1(/*\2*/);' + shift + ;; + -b) # funny Berkeley __P macro + peel="$peel + "'/^\([^#\/][^\/]*[a-zA-Z0-9_)]\)(\(.*\))/s;;\1 __P((\2));' + shift + ;; + -s) # compiler doesn't like `static foo();' + # add code to get rid of the `static' + peel="$peel + "'/^static[ ][^\/]*[a-zA-Z0-9_)](.*)/s;static.;;' + shift + ;; + -p) # private declarations + egrep='^ ==([ ]|$)' + shift + ;; + -i) # wrap in #ifndef, argument is name + ifndef="$2" + shift ; shift + ;; + *) break + ;; + esac +done + +if test " $ifndef" != " " +then + echo "#ifndef $ifndef" + echo "#define $ifndef /* never again */" +fi +echo "/* ========= begin header generated by $0 ========= */" +echo '#ifdef __cplusplus' +echo 'extern "C" {' +echo '#endif' +for f +do + echo + echo "/* === $f === */" + egrep "$egrep" $f | sed 's/^ ==*[ ]//;s/^ ==*$//' | sed "$peel" + echo +done +echo '#ifdef __cplusplus' +echo '}' +echo '#endif' +echo "/* ========= end header generated by $0 ========= */" +if test " $ifndef" != " " +then + echo "#endif" +fi +exit 0 diff --git a/APACHE_1_2_X/src/regex/regcomp.c b/APACHE_1_2_X/src/regex/regcomp.c new file mode 100644 index 00000000000..c3a7b1ae1fe --- /dev/null +++ b/APACHE_1_2_X/src/regex/regcomp.c @@ -0,0 +1,1546 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "regex2.h" + +#include "cclass.h" +#include "cname.h" + +/* + * parse structure, passed up and down to avoid global variables and + * other clumsinesses + */ +struct parse { + char *next; /* next character in RE */ + char *end; /* end of string (-> NUL normally) */ + int error; /* has an error been seen? */ + sop *strip; /* malloced strip */ + sopno ssize; /* malloced strip size (allocated) */ + sopno slen; /* malloced strip length (used) */ + int ncsalloc; /* number of csets allocated */ + struct re_guts *g; +# define NPAREN 10 /* we need to remember () 1-9 for back refs */ + sopno pbegin[NPAREN]; /* -> ( ([0] unused) */ + sopno pend[NPAREN]; /* -> ) ([0] unused) */ +}; + +#include "regcomp.ih" + +static char nuls[10]; /* place to point scanner in event of error */ + +/* + * macros for use with parse structure + * BEWARE: these know that the parse structure is named `p' !!! + */ +#define PEEK() (*p->next) +#define PEEK2() (*(p->next+1)) +#define MORE() (p->next < p->end) +#define MORE2() (p->next+1 < p->end) +#define SEE(c) (MORE() && PEEK() == (c)) +#define SEETWO(a, b) (MORE() && MORE2() && PEEK() == (a) && PEEK2() == (b)) +#define EAT(c) ((SEE(c)) ? (NEXT1(), 1) : 0) +#define EATTWO(a, b) ((SEETWO(a, b)) ? (NEXT2(), 1) : 0) +#define NEXT1() (p->next++) +#define NEXT2() (p->next += 2) +#define NEXTn(n) (p->next += (n)) +#define GETNEXT() (*p->next++) +#define SETERROR(e) seterr(p, (e)) +#define REQUIRE(co, e) ((void)((co) || SETERROR(e))) +#define MUSTSEE(c, e) (REQUIRE(MORE() && PEEK() == (c), e)) +#define MUSTEAT(c, e) (REQUIRE(MORE() && GETNEXT() == (c), e)) +#define MUSTNOTSEE(c, e) (REQUIRE(!MORE() || PEEK() != (c), e)) +#define EMIT(op, sopnd) doemit(p, (sop)(op), (size_t)(sopnd)) +#define INSERT(op, pos) doinsert(p, (sop)(op), HERE()-(pos)+1, pos) +#define AHEAD(pos) dofwd(p, pos, HERE()-(pos)) +#define ASTERN(sop, pos) EMIT(sop, HERE()-pos) +#define HERE() (p->slen) +#define THERE() (p->slen - 1) +#define THERETHERE() (p->slen - 2) +#define DROP(n) (p->slen -= (n)) + +#ifndef NDEBUG +static int never = 0; /* for use in asserts; shuts lint up */ +#else +#define never 0 /* some s have bugs too */ +#endif + +/* + - regcomp - interface for parser and compilation + = extern int regcomp(regex_t *, const char *, int); + = #define REG_BASIC 0000 + = #define REG_EXTENDED 0001 + = #define REG_ICASE 0002 + = #define REG_NOSUB 0004 + = #define REG_NEWLINE 0010 + = #define REG_NOSPEC 0020 + = #define REG_PEND 0040 + = #define REG_DUMP 0200 + */ +int /* 0 success, otherwise REG_something */ +regcomp(preg, pattern, cflags) +regex_t *preg; +const char *pattern; +int cflags; +{ + struct parse pa; + register struct re_guts *g; + register struct parse *p = &pa; + register int i; + register size_t len; +#ifdef REDEBUG +# define GOODFLAGS(f) (f) +#else +# define GOODFLAGS(f) ((f)&~REG_DUMP) +#endif + + cflags = GOODFLAGS(cflags); + if ((cflags®_EXTENDED) && (cflags®_NOSPEC)) + return(REG_INVARG); + + if (cflags®_PEND) { + if (preg->re_endp < pattern) + return(REG_INVARG); + len = preg->re_endp - pattern; + } else + len = strlen((char *)pattern); + + /* do the mallocs early so failure handling is easy */ + g = (struct re_guts *)malloc(sizeof(struct re_guts) + + (NC-1)*sizeof(cat_t)); + if (g == NULL) + return(REG_ESPACE); + p->ssize = len/(size_t)2*(size_t)3 + (size_t)1; /* ugh */ + p->strip = (sop *)malloc(p->ssize * sizeof(sop)); + p->slen = 0; + if (p->strip == NULL) { + free((char *)g); + return(REG_ESPACE); + } + + /* set things up */ + p->g = g; + p->next = (char *)pattern; /* convenience; we do not modify it */ + p->end = p->next + len; + p->error = 0; + p->ncsalloc = 0; + for (i = 0; i < NPAREN; i++) { + p->pbegin[i] = 0; + p->pend[i] = 0; + } + g->csetsize = NC; + g->sets = NULL; + g->setbits = NULL; + g->ncsets = 0; + g->cflags = cflags; + g->iflags = 0; + g->nbol = 0; + g->neol = 0; + g->must = NULL; + g->mlen = 0; + g->nsub = 0; + g->ncategories = 1; /* category 0 is "everything else" */ + g->categories = &g->catspace[-(CHAR_MIN)]; + (void) memset((char *)g->catspace, 0, NC*sizeof(cat_t)); + g->backrefs = 0; + + /* do it */ + EMIT(OEND, 0); + g->firststate = THERE(); + if (cflags®_EXTENDED) + p_ere(p, OUT); + else if (cflags®_NOSPEC) + p_str(p); + else + p_bre(p, OUT, OUT); + EMIT(OEND, 0); + g->laststate = THERE(); + + /* tidy up loose ends and fill things in */ + categorize(p, g); + stripsnug(p, g); + findmust(p, g); + g->nplus = pluscount(p, g); + g->magic = MAGIC2; + preg->re_nsub = g->nsub; + preg->re_g = g; + preg->re_magic = MAGIC1; +#ifndef REDEBUG + /* not debugging, so can't rely on the assert() in regexec() */ + if (g->iflags&BAD) + SETERROR(REG_ASSERT); +#endif + + /* win or lose, we're done */ + if (p->error != 0) /* lose */ + regfree(preg); + return(p->error); +} + +/* + - p_ere - ERE parser top level, concatenation and alternation + == static void p_ere(register struct parse *p, int stop); + */ +static void +p_ere(p, stop) +register struct parse *p; +int stop; /* character this ERE should end at */ +{ + register char c; + register sopno prevback = 0; + register sopno prevfwd = 0; + register sopno conc; + register int first = 1; /* is this the first alternative? */ + + for (;;) { + /* do a bunch of concatenated expressions */ + conc = HERE(); + while (MORE() && (c = PEEK()) != '|' && c != stop) + p_ere_exp(p); + REQUIRE(HERE() != conc, REG_EMPTY); /* require nonempty */ + + if (!EAT('|')) + break; /* NOTE BREAK OUT */ + + if (first) { + INSERT(OCH_, conc); /* offset is wrong */ + prevfwd = conc; + prevback = conc; + first = 0; + } + ASTERN(OOR1, prevback); + prevback = THERE(); + AHEAD(prevfwd); /* fix previous offset */ + prevfwd = HERE(); + EMIT(OOR2, 0); /* offset is very wrong */ + } + + if (!first) { /* tail-end fixups */ + AHEAD(prevfwd); + ASTERN(O_CH, prevback); + } + + assert(!MORE() || SEE(stop)); +} + +/* + - p_ere_exp - parse one subERE, an atom possibly followed by a repetition op + == static void p_ere_exp(register struct parse *p); + */ +static void +p_ere_exp(p) +register struct parse *p; +{ + register char c; + register sopno pos; + register int count; + register int count2; + register sopno subno; + int wascaret = 0; + + assert(MORE()); /* caller should have ensured this */ + c = GETNEXT(); + + pos = HERE(); + switch (c) { + case '(': + REQUIRE(MORE(), REG_EPAREN); + p->g->nsub++; + subno = p->g->nsub; + if (subno < NPAREN) + p->pbegin[subno] = HERE(); + EMIT(OLPAREN, subno); + if (!SEE(')')) + p_ere(p, ')'); + if (subno < NPAREN) { + p->pend[subno] = HERE(); + assert(p->pend[subno] != 0); + } + EMIT(ORPAREN, subno); + MUSTEAT(')', REG_EPAREN); + break; +#ifndef POSIX_MISTAKE + case ')': /* happens only if no current unmatched ( */ + /* + * You may ask, why the ifndef? Because I didn't notice + * this until slightly too late for 1003.2, and none of the + * other 1003.2 regular-expression reviewers noticed it at + * all. So an unmatched ) is legal POSIX, at least until + * we can get it fixed. + */ + SETERROR(REG_EPAREN); + break; +#endif + case '^': + EMIT(OBOL, 0); + p->g->iflags |= USEBOL; + p->g->nbol++; + wascaret = 1; + break; + case '$': + EMIT(OEOL, 0); + p->g->iflags |= USEEOL; + p->g->neol++; + break; + case '|': + SETERROR(REG_EMPTY); + break; + case '*': + case '+': + case '?': + SETERROR(REG_BADRPT); + break; + case '.': + if (p->g->cflags®_NEWLINE) + nonnewline(p); + else + EMIT(OANY, 0); + break; + case '[': + p_bracket(p); + break; + case '\\': + REQUIRE(MORE(), REG_EESCAPE); + c = GETNEXT(); + ordinary(p, c); + break; + case '{': /* okay as ordinary except if digit follows */ + REQUIRE(!MORE() || !isdigit(PEEK()), REG_BADRPT); + /* FALLTHROUGH */ + default: + ordinary(p, c); + break; + } + + if (!MORE()) + return; + c = PEEK(); + /* we call { a repetition if followed by a digit */ + if (!( c == '*' || c == '+' || c == '?' || + (c == '{' && MORE2() && isdigit(PEEK2())) )) + return; /* no repetition, we're done */ + NEXT1(); + + REQUIRE(!wascaret, REG_BADRPT); + switch (c) { + case '*': /* implemented as +? */ + /* this case does not require the (y|) trick, noKLUDGE */ + INSERT(OPLUS_, pos); + ASTERN(O_PLUS, pos); + INSERT(OQUEST_, pos); + ASTERN(O_QUEST, pos); + break; + case '+': + INSERT(OPLUS_, pos); + ASTERN(O_PLUS, pos); + break; + case '?': + /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */ + INSERT(OCH_, pos); /* offset slightly wrong */ + ASTERN(OOR1, pos); /* this one's right */ + AHEAD(pos); /* fix the OCH_ */ + EMIT(OOR2, 0); /* offset very wrong... */ + AHEAD(THERE()); /* ...so fix it */ + ASTERN(O_CH, THERETHERE()); + break; + case '{': + count = p_count(p); + if (EAT(',')) { + if (isdigit(PEEK())) { + count2 = p_count(p); + REQUIRE(count <= count2, REG_BADBR); + } else /* single number with comma */ + count2 = INFINITY; + } else /* just a single number */ + count2 = count; + repeat(p, pos, count, count2); + if (!EAT('}')) { /* error heuristics */ + while (MORE() && PEEK() != '}') + NEXT1(); + REQUIRE(MORE(), REG_EBRACE); + SETERROR(REG_BADBR); + } + break; + } + + if (!MORE()) + return; + c = PEEK(); + if (!( c == '*' || c == '+' || c == '?' || + (c == '{' && MORE2() && isdigit(PEEK2())) ) ) + return; + SETERROR(REG_BADRPT); +} + +/* + - p_str - string (no metacharacters) "parser" + == static void p_str(register struct parse *p); + */ +static void +p_str(p) +register struct parse *p; +{ + REQUIRE(MORE(), REG_EMPTY); + while (MORE()) + ordinary(p, GETNEXT()); +} + +/* + - p_bre - BRE parser top level, anchoring and concatenation + == static void p_bre(register struct parse *p, register int end1, \ + == register int end2); + * Giving end1 as OUT essentially eliminates the end1/end2 check. + * + * This implementation is a bit of a kludge, in that a trailing $ is first + * taken as an ordinary character and then revised to be an anchor. The + * only undesirable side effect is that '$' gets included as a character + * category in such cases. This is fairly harmless; not worth fixing. + * The amount of lookahead needed to avoid this kludge is excessive. + */ +static void +p_bre(p, end1, end2) +register struct parse *p; +register int end1; /* first terminating character */ +register int end2; /* second terminating character */ +{ + register sopno start = HERE(); + register int first = 1; /* first subexpression? */ + register int wasdollar = 0; + + if (EAT('^')) { + EMIT(OBOL, 0); + p->g->iflags |= USEBOL; + p->g->nbol++; + } + while (MORE() && !SEETWO(end1, end2)) { + wasdollar = p_simp_re(p, first); + first = 0; + } + if (wasdollar) { /* oops, that was a trailing anchor */ + DROP(1); + EMIT(OEOL, 0); + p->g->iflags |= USEEOL; + p->g->neol++; + } + + REQUIRE(HERE() != start, REG_EMPTY); /* require nonempty */ +} + +/* + - p_simp_re - parse a simple RE, an atom possibly followed by a repetition + == static int p_simp_re(register struct parse *p, int starordinary); + */ +static int /* was the simple RE an unbackslashed $? */ +p_simp_re(p, starordinary) +register struct parse *p; +int starordinary; /* is a leading * an ordinary character? */ +{ + register int c; + register int count; + register int count2; + register sopno pos; + register int i; + register sopno subno; +# define BACKSL (1<g->cflags®_NEWLINE) + nonnewline(p); + else + EMIT(OANY, 0); + break; + case '[': + p_bracket(p); + break; + case BACKSL|'{': + SETERROR(REG_BADRPT); + break; + case BACKSL|'(': + p->g->nsub++; + subno = p->g->nsub; + if (subno < NPAREN) + p->pbegin[subno] = HERE(); + EMIT(OLPAREN, subno); + /* the MORE here is an error heuristic */ + if (MORE() && !SEETWO('\\', ')')) + p_bre(p, '\\', ')'); + if (subno < NPAREN) { + p->pend[subno] = HERE(); + assert(p->pend[subno] != 0); + } + EMIT(ORPAREN, subno); + REQUIRE(EATTWO('\\', ')'), REG_EPAREN); + break; + case BACKSL|')': /* should not get here -- must be user */ + case BACKSL|'}': + SETERROR(REG_EPAREN); + break; + case BACKSL|'1': + case BACKSL|'2': + case BACKSL|'3': + case BACKSL|'4': + case BACKSL|'5': + case BACKSL|'6': + case BACKSL|'7': + case BACKSL|'8': + case BACKSL|'9': + i = (c&~BACKSL) - '0'; + assert(i < NPAREN); + if (p->pend[i] != 0) { + assert(i <= p->g->nsub); + EMIT(OBACK_, i); + assert(p->pbegin[i] != 0); + assert(OP(p->strip[p->pbegin[i]]) == OLPAREN); + assert(OP(p->strip[p->pend[i]]) == ORPAREN); + (void) dupl(p, p->pbegin[i]+1, p->pend[i]); + EMIT(O_BACK, i); + } else + SETERROR(REG_ESUBREG); + p->g->backrefs = 1; + break; + case '*': + REQUIRE(starordinary, REG_BADRPT); + /* FALLTHROUGH */ + default: + ordinary(p, c &~ BACKSL); + break; + } + + if (EAT('*')) { /* implemented as +? */ + /* this case does not require the (y|) trick, noKLUDGE */ + INSERT(OPLUS_, pos); + ASTERN(O_PLUS, pos); + INSERT(OQUEST_, pos); + ASTERN(O_QUEST, pos); + } else if (EATTWO('\\', '{')) { + count = p_count(p); + if (EAT(',')) { + if (MORE() && isdigit(PEEK())) { + count2 = p_count(p); + REQUIRE(count <= count2, REG_BADBR); + } else /* single number with comma */ + count2 = INFINITY; + } else /* just a single number */ + count2 = count; + repeat(p, pos, count, count2); + if (!EATTWO('\\', '}')) { /* error heuristics */ + while (MORE() && !SEETWO('\\', '}')) + NEXT1(); + REQUIRE(MORE(), REG_EBRACE); + SETERROR(REG_BADBR); + } + } else if (c == (unsigned char)'$') /* $ (but not \$) ends it */ + return(1); + + return(0); +} + +/* + - p_count - parse a repetition count + == static int p_count(register struct parse *p); + */ +static int /* the value */ +p_count(p) +register struct parse *p; +{ + register int count = 0; + register int ndigits = 0; + + while (MORE() && isdigit(PEEK()) && count <= DUPMAX) { + count = count*10 + (GETNEXT() - '0'); + ndigits++; + } + + REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR); + return(count); +} + +/* + - p_bracket - parse a bracketed character list + == static void p_bracket(register struct parse *p); + * + * Note a significant property of this code: if the allocset() did SETERROR, + * no set operations are done. + */ +static void +p_bracket(p) +register struct parse *p; +{ + register cset *cs = allocset(p); + register int invert = 0; + + /* Dept of Truly Sickening Special-Case Kludges */ + if (p->next + 5 < p->end && strncmp(p->next, "[:<:]]", 6) == 0) { + EMIT(OBOW, 0); + NEXTn(6); + return; + } + if (p->next + 5 < p->end && strncmp(p->next, "[:>:]]", 6) == 0) { + EMIT(OEOW, 0); + NEXTn(6); + return; + } + + if (EAT('^')) + invert++; /* make note to invert set at end */ + if (EAT(']')) + CHadd(cs, ']'); + else if (EAT('-')) + CHadd(cs, '-'); + while (MORE() && PEEK() != ']' && !SEETWO('-', ']')) + p_b_term(p, cs); + if (EAT('-')) + CHadd(cs, '-'); + MUSTEAT(']', REG_EBRACK); + + if (p->error != 0) /* don't mess things up further */ + return; + + if (p->g->cflags®_ICASE) { + register int i; + register int ci; + + for (i = p->g->csetsize - 1; i >= 0; i--) + if (CHIN(cs, i) && isalpha(i)) { + ci = othercase(i); + if (ci != i) + CHadd(cs, ci); + } + if (cs->multis != NULL) + mccase(p, cs); + } + if (invert) { + register int i; + + for (i = p->g->csetsize - 1; i >= 0; i--) + if (CHIN(cs, i)) + CHsub(cs, i); + else + CHadd(cs, i); + if (p->g->cflags®_NEWLINE) + CHsub(cs, '\n'); + if (cs->multis != NULL) + mcinvert(p, cs); + } + + assert(cs->multis == NULL); /* xxx */ + + if (nch(p, cs) == 1) { /* optimize singleton sets */ + ordinary(p, firstch(p, cs)); + freeset(p, cs); + } else + EMIT(OANYOF, freezeset(p, cs)); +} + +/* + - p_b_term - parse one term of a bracketed character list + == static void p_b_term(register struct parse *p, register cset *cs); + */ +static void +p_b_term(p, cs) +register struct parse *p; +register cset *cs; +{ + register char c; + register char start, finish; + register int i; + + /* classify what we've got */ + switch ((MORE()) ? PEEK() : '\0') { + case '[': + c = (MORE2()) ? PEEK2() : '\0'; + break; + case '-': + SETERROR(REG_ERANGE); + return; /* NOTE RETURN */ + break; + default: + c = '\0'; + break; + } + + switch (c) { + case ':': /* character class */ + NEXT2(); + REQUIRE(MORE(), REG_EBRACK); + c = PEEK(); + REQUIRE(c != '-' && c != ']', REG_ECTYPE); + p_b_cclass(p, cs); + REQUIRE(MORE(), REG_EBRACK); + REQUIRE(EATTWO(':', ']'), REG_ECTYPE); + break; + case '=': /* equivalence class */ + NEXT2(); + REQUIRE(MORE(), REG_EBRACK); + c = PEEK(); + REQUIRE(c != '-' && c != ']', REG_ECOLLATE); + p_b_eclass(p, cs); + REQUIRE(MORE(), REG_EBRACK); + REQUIRE(EATTWO('=', ']'), REG_ECOLLATE); + break; + default: /* symbol, ordinary character, or range */ +/* xxx revision needed for multichar stuff */ + start = p_b_symbol(p); + if (SEE('-') && MORE2() && PEEK2() != ']') { + /* range */ + NEXT1(); + if (EAT('-')) + finish = '-'; + else + finish = p_b_symbol(p); + } else + finish = start; +/* xxx what about signed chars here... */ + REQUIRE(start <= finish, REG_ERANGE); + for (i = start; i <= finish; i++) + CHadd(cs, i); + break; + } +} + +/* + - p_b_cclass - parse a character-class name and deal with it + == static void p_b_cclass(register struct parse *p, register cset *cs); + */ +static void +p_b_cclass(p, cs) +register struct parse *p; +register cset *cs; +{ + register char *sp = p->next; + register struct cclass *cp; + register size_t len; + register char *u; + register char c; + + while (MORE() && isalpha(PEEK())) + NEXT1(); + len = p->next - sp; + for (cp = cclasses; cp->name != NULL; cp++) + if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0') + break; + if (cp->name == NULL) { + /* oops, didn't find it */ + SETERROR(REG_ECTYPE); + return; + } + + u = cp->chars; + while ((c = *u++) != '\0') + CHadd(cs, c); + for (u = cp->multis; *u != '\0'; u += strlen(u) + 1) + MCadd(p, cs, u); +} + +/* + - p_b_eclass - parse an equivalence-class name and deal with it + == static void p_b_eclass(register struct parse *p, register cset *cs); + * + * This implementation is incomplete. xxx + */ +static void +p_b_eclass(p, cs) +register struct parse *p; +register cset *cs; +{ + register char c; + + c = p_b_coll_elem(p, '='); + CHadd(cs, c); +} + +/* + - p_b_symbol - parse a character or [..]ed multicharacter collating symbol + == static char p_b_symbol(register struct parse *p); + */ +static char /* value of symbol */ +p_b_symbol(p) +register struct parse *p; +{ + register char value; + + REQUIRE(MORE(), REG_EBRACK); + if (!EATTWO('[', '.')) + return(GETNEXT()); + + /* collating symbol */ + value = p_b_coll_elem(p, '.'); + REQUIRE(EATTWO('.', ']'), REG_ECOLLATE); + return(value); +} + +/* + - p_b_coll_elem - parse a collating-element name and look it up + == static char p_b_coll_elem(register struct parse *p, int endc); + */ +static char /* value of collating element */ +p_b_coll_elem(p, endc) +register struct parse *p; +int endc; /* name ended by endc,']' */ +{ + register char *sp = p->next; + register struct cname *cp; + register int len; + + while (MORE() && !SEETWO(endc, ']')) + NEXT1(); + if (!MORE()) { + SETERROR(REG_EBRACK); + return(0); + } + len = p->next - sp; + for (cp = cnames; cp->name != NULL; cp++) + if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0') + return(cp->code); /* known name */ + if (len == 1) + return(*sp); /* single character */ + SETERROR(REG_ECOLLATE); /* neither */ + return(0); +} + +/* + - othercase - return the case counterpart of an alphabetic + == static char othercase(int ch); + */ +static char /* if no counterpart, return ch */ +othercase(ch) +int ch; +{ + assert(isalpha(ch)); + if (isupper(ch)) + return(tolower(ch)); + else if (islower(ch)) + return(toupper(ch)); + else /* peculiar, but could happen */ + return(ch); +} + +/* + - bothcases - emit a dualcase version of a two-case character + == static void bothcases(register struct parse *p, int ch); + * + * Boy, is this implementation ever a kludge... + */ +static void +bothcases(p, ch) +register struct parse *p; +int ch; +{ + register char *oldnext = p->next; + register char *oldend = p->end; + char bracket[3]; + + assert(othercase(ch) != ch); /* p_bracket() would recurse */ + p->next = bracket; + p->end = bracket+2; + bracket[0] = ch; + bracket[1] = ']'; + bracket[2] = '\0'; + p_bracket(p); + assert(p->next == bracket+2); + p->next = oldnext; + p->end = oldend; +} + +/* + - ordinary - emit an ordinary character + == static void ordinary(register struct parse *p, register int ch); + */ +static void +ordinary(p, ch) +register struct parse *p; +register int ch; +{ + register cat_t *cap = p->g->categories; + + if ((p->g->cflags®_ICASE) && isalpha(ch) && othercase(ch) != ch) + bothcases(p, ch); + else { + EMIT(OCHAR, (unsigned char)ch); + if (cap[ch] == 0) + cap[ch] = p->g->ncategories++; + } +} + +/* + - nonnewline - emit REG_NEWLINE version of OANY + == static void nonnewline(register struct parse *p); + * + * Boy, is this implementation ever a kludge... + */ +static void +nonnewline(p) +register struct parse *p; +{ + register char *oldnext = p->next; + register char *oldend = p->end; + char bracket[4]; + + p->next = bracket; + p->end = bracket+3; + bracket[0] = '^'; + bracket[1] = '\n'; + bracket[2] = ']'; + bracket[3] = '\0'; + p_bracket(p); + assert(p->next == bracket+3); + p->next = oldnext; + p->end = oldend; +} + +/* + - repeat - generate code for a bounded repetition, recursively if needed + == static void repeat(register struct parse *p, sopno start, int from, int to); + */ +static void +repeat(p, start, from, to) +register struct parse *p; +sopno start; /* operand from here to end of strip */ +int from; /* repeated from this number */ +int to; /* to this number of times (maybe INFINITY) */ +{ + register sopno finish = HERE(); +# define N 2 +# define INF 3 +# define REP(f, t) ((f)*8 + (t)) +# define MAP(n) (((n) <= 1) ? (n) : ((n) == INFINITY) ? INF : N) + register sopno copy; + + if (p->error != 0) /* head off possible runaway recursion */ + return; + + assert(from <= to); + + switch (REP(MAP(from), MAP(to))) { + case REP(0, 0): /* must be user doing this */ + DROP(finish-start); /* drop the operand */ + break; + case REP(0, 1): /* as x{1,1}? */ + case REP(0, N): /* as x{1,n}? */ + case REP(0, INF): /* as x{1,}? */ + /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */ + INSERT(OCH_, start); /* offset is wrong... */ + repeat(p, start+1, 1, to); + ASTERN(OOR1, start); + AHEAD(start); /* ... fix it */ + EMIT(OOR2, 0); + AHEAD(THERE()); + ASTERN(O_CH, THERETHERE()); + break; + case REP(1, 1): /* trivial case */ + /* done */ + break; + case REP(1, N): /* as x?x{1,n-1} */ + /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */ + INSERT(OCH_, start); + ASTERN(OOR1, start); + AHEAD(start); + EMIT(OOR2, 0); /* offset very wrong... */ + AHEAD(THERE()); /* ...so fix it */ + ASTERN(O_CH, THERETHERE()); + copy = dupl(p, start+1, finish+1); + assert(copy == finish+4); + repeat(p, copy, 1, to-1); + break; + case REP(1, INF): /* as x+ */ + INSERT(OPLUS_, start); + ASTERN(O_PLUS, start); + break; + case REP(N, N): /* as xx{m-1,n-1} */ + copy = dupl(p, start, finish); + repeat(p, copy, from-1, to-1); + break; + case REP(N, INF): /* as xx{n-1,INF} */ + copy = dupl(p, start, finish); + repeat(p, copy, from-1, to); + break; + default: /* "can't happen" */ + SETERROR(REG_ASSERT); /* just in case */ + break; + } +} + +/* + - seterr - set an error condition + == static int seterr(register struct parse *p, int e); + */ +static int /* useless but makes type checking happy */ +seterr(p, e) +register struct parse *p; +int e; +{ + if (p->error == 0) /* keep earliest error condition */ + p->error = e; + p->next = nuls; /* try to bring things to a halt */ + p->end = nuls; + return(0); /* make the return value well-defined */ +} + +/* + - allocset - allocate a set of characters for [] + == static cset *allocset(register struct parse *p); + */ +static cset * +allocset(p) +register struct parse *p; +{ + register int no = p->g->ncsets++; + register size_t nc; + register size_t nbytes; + register cset *cs; + register size_t css = (size_t)p->g->csetsize; + register int i; + + if (no >= p->ncsalloc) { /* need another column of space */ + p->ncsalloc += CHAR_BIT; + nc = p->ncsalloc; + assert(nc % CHAR_BIT == 0); + nbytes = nc / CHAR_BIT * css; + if (p->g->sets == NULL) + p->g->sets = (cset *)malloc(nc * sizeof(cset)); + else + p->g->sets = (cset *)realloc((char *)p->g->sets, + nc * sizeof(cset)); + if (p->g->setbits == NULL) + p->g->setbits = (uch *)malloc(nbytes); + else { + p->g->setbits = (uch *)realloc((char *)p->g->setbits, + nbytes); + /* xxx this isn't right if setbits is now NULL */ + for (i = 0; i < no; i++) + p->g->sets[i].ptr = p->g->setbits + css*(i/CHAR_BIT); + } + if (p->g->sets != NULL && p->g->setbits != NULL) + (void) memset((char *)p->g->setbits + (nbytes - css), + 0, css); + else { + no = 0; + SETERROR(REG_ESPACE); + /* caller's responsibility not to do set ops */ + } + } + + assert(p->g->sets != NULL); /* xxx */ + cs = &p->g->sets[no]; + cs->ptr = p->g->setbits + css*((no)/CHAR_BIT); + cs->mask = 1 << ((no) % CHAR_BIT); + cs->hash = 0; + cs->smultis = 0; + cs->multis = NULL; + + return(cs); +} + +/* + - freeset - free a now-unused set + == static void freeset(register struct parse *p, register cset *cs); + */ +static void +freeset(p, cs) +register struct parse *p; +register cset *cs; +{ + register int i; + register cset *top = &p->g->sets[p->g->ncsets]; + register size_t css = (size_t)p->g->csetsize; + + for (i = 0; i < css; i++) + CHsub(cs, i); + if (cs == top-1) /* recover only the easy case */ + p->g->ncsets--; +} + +/* + - freezeset - final processing on a set of characters + == static int freezeset(register struct parse *p, register cset *cs); + * + * The main task here is merging identical sets. This is usually a waste + * of time (although the hash code minimizes the overhead), but can win + * big if REG_ICASE is being used. REG_ICASE, by the way, is why the hash + * is done using addition rather than xor -- all ASCII [aA] sets xor to + * the same value! + */ +static int /* set number */ +freezeset(p, cs) +register struct parse *p; +register cset *cs; +{ + register uch h = cs->hash; + register int i; + register cset *top = &p->g->sets[p->g->ncsets]; + register cset *cs2; + register size_t css = (size_t)p->g->csetsize; + + /* look for an earlier one which is the same */ + for (cs2 = &p->g->sets[0]; cs2 < top; cs2++) + if (cs2->hash == h && cs2 != cs) { + /* maybe */ + for (i = 0; i < css; i++) + if (!!CHIN(cs2, i) != !!CHIN(cs, i)) + break; /* no */ + if (i == css) + break; /* yes */ + } + + if (cs2 < top) { /* found one */ + freeset(p, cs); + cs = cs2; + } + + return((int)(cs - p->g->sets)); +} + +/* + - firstch - return first character in a set (which must have at least one) + == static int firstch(register struct parse *p, register cset *cs); + */ +static int /* character; there is no "none" value */ +firstch(p, cs) +register struct parse *p; +register cset *cs; +{ + register int i; + register size_t css = (size_t)p->g->csetsize; + + for (i = 0; i < css; i++) + if (CHIN(cs, i)) + return((char)i); + assert(never); + return(0); /* arbitrary */ +} + +/* + - nch - number of characters in a set + == static int nch(register struct parse *p, register cset *cs); + */ +static int +nch(p, cs) +register struct parse *p; +register cset *cs; +{ + register int i; + register size_t css = (size_t)p->g->csetsize; + register int n = 0; + + for (i = 0; i < css; i++) + if (CHIN(cs, i)) + n++; + return(n); +} + +/* + - mcadd - add a collating element to a cset + == static void mcadd(register struct parse *p, register cset *cs, \ + == register char *cp); + */ +static void +mcadd(p, cs, cp) +register struct parse *p; +register cset *cs; +register char *cp; +{ + register size_t oldend = cs->smultis; + + cs->smultis += strlen(cp) + 1; + if (cs->multis == NULL) + cs->multis = malloc(cs->smultis); + else + cs->multis = realloc(cs->multis, cs->smultis); + if (cs->multis == NULL) { + SETERROR(REG_ESPACE); + return; + } + + (void) strcpy(cs->multis + oldend - 1, cp); + cs->multis[cs->smultis - 1] = '\0'; +} + + +/* + - mcinvert - invert the list of collating elements in a cset + == static void mcinvert(register struct parse *p, register cset *cs); + * + * This would have to know the set of possibilities. Implementation + * is deferred. + */ +static void +mcinvert(p, cs) +register struct parse *p; +register cset *cs; +{ + assert(cs->multis == NULL); /* xxx */ +} + +/* + - mccase - add case counterparts of the list of collating elements in a cset + == static void mccase(register struct parse *p, register cset *cs); + * + * This would have to know the set of possibilities. Implementation + * is deferred. + */ +static void +mccase(p, cs) +register struct parse *p; +register cset *cs; +{ + assert(cs->multis == NULL); /* xxx */ +} + +/* + - isinsets - is this character in any sets? + == static int isinsets(register struct re_guts *g, int c); + */ +static int /* predicate */ +isinsets(g, c) +register struct re_guts *g; +int c; +{ + register uch *col; + register int i; + register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT; + register unsigned uc = (unsigned char)c; + + for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize) + if (col[uc] != 0) + return(1); + return(0); +} + +/* + - samesets - are these two characters in exactly the same sets? + == static int samesets(register struct re_guts *g, int c1, int c2); + */ +static int /* predicate */ +samesets(g, c1, c2) +register struct re_guts *g; +int c1; +int c2; +{ + register uch *col; + register int i; + register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT; + register unsigned uc1 = (unsigned char)c1; + register unsigned uc2 = (unsigned char)c2; + + for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize) + if (col[uc1] != col[uc2]) + return(0); + return(1); +} + +/* + - categorize - sort out character categories + == static void categorize(struct parse *p, register struct re_guts *g); + */ +static void +categorize(p, g) +struct parse *p; +register struct re_guts *g; +{ + register cat_t *cats = g->categories; + register int c; + register int c2; + register cat_t cat; + + /* avoid making error situations worse */ + if (p->error != 0) + return; + + for (c = CHAR_MIN; c <= CHAR_MAX; c++) + if (cats[c] == 0 && isinsets(g, c)) { + cat = g->ncategories++; + cats[c] = cat; + for (c2 = c+1; c2 <= CHAR_MAX; c2++) + if (cats[c2] == 0 && samesets(g, c, c2)) + cats[c2] = cat; + } +} + +/* + - dupl - emit a duplicate of a bunch of sops + == static sopno dupl(register struct parse *p, sopno start, sopno finish); + */ +static sopno /* start of duplicate */ +dupl(p, start, finish) +register struct parse *p; +sopno start; /* from here */ +sopno finish; /* to this less one */ +{ + register sopno ret = HERE(); + register sopno len = finish - start; + + assert(finish >= start); + if (len == 0) + return(ret); + enlarge(p, p->ssize + len); /* this many unexpected additions */ + assert(p->ssize >= p->slen + len); + (void) memcpy((char *)(p->strip + p->slen), + (char *)(p->strip + start), (size_t)len*sizeof(sop)); + p->slen += len; + return(ret); +} + +/* + - doemit - emit a strip operator + == static void doemit(register struct parse *p, sop op, size_t opnd); + * + * It might seem better to implement this as a macro with a function as + * hard-case backup, but it's just too big and messy unless there are + * some changes to the data structures. Maybe later. + */ +static void +doemit(p, op, opnd) +register struct parse *p; +sop op; +size_t opnd; +{ + /* avoid making error situations worse */ + if (p->error != 0) + return; + + /* deal with oversize operands ("can't happen", more or less) */ + assert(opnd < 1<slen >= p->ssize) + enlarge(p, (p->ssize+1) / 2 * 3); /* +50% */ + assert(p->slen < p->ssize); + + /* finally, it's all reduced to the easy case */ + p->strip[p->slen++] = SOP(op, opnd); +} + +/* + - doinsert - insert a sop into the strip + == static void doinsert(register struct parse *p, sop op, size_t opnd, sopno pos); + */ +static void +doinsert(p, op, opnd, pos) +register struct parse *p; +sop op; +size_t opnd; +sopno pos; +{ + register sopno sn; + register sop s; + register int i; + + /* avoid making error situations worse */ + if (p->error != 0) + return; + + sn = HERE(); + EMIT(op, opnd); /* do checks, ensure space */ + assert(HERE() == sn+1); + s = p->strip[sn]; + + /* adjust paren pointers */ + assert(pos > 0); + for (i = 1; i < NPAREN; i++) { + if (p->pbegin[i] >= pos) { + p->pbegin[i]++; + } + if (p->pend[i] >= pos) { + p->pend[i]++; + } + } + + memmove((char *)&p->strip[pos+1], (char *)&p->strip[pos], + (HERE()-pos-1)*sizeof(sop)); + p->strip[pos] = s; +} + +/* + - dofwd - complete a forward reference + == static void dofwd(register struct parse *p, sopno pos, sop value); + */ +static void +dofwd(p, pos, value) +register struct parse *p; +register sopno pos; +sop value; +{ + /* avoid making error situations worse */ + if (p->error != 0) + return; + + assert(value < 1<strip[pos] = OP(p->strip[pos]) | value; +} + +/* + - enlarge - enlarge the strip + == static void enlarge(register struct parse *p, sopno size); + */ +static void +enlarge(p, size) +register struct parse *p; +register sopno size; +{ + register sop *sp; + + if (p->ssize >= size) + return; + + sp = (sop *)realloc(p->strip, size*sizeof(sop)); + if (sp == NULL) { + SETERROR(REG_ESPACE); + return; + } + p->strip = sp; + p->ssize = size; +} + +/* + - stripsnug - compact the strip + == static void stripsnug(register struct parse *p, register struct re_guts *g); + */ +static void +stripsnug(p, g) +register struct parse *p; +register struct re_guts *g; +{ + g->nstates = p->slen; + g->strip = (sop *)realloc((char *)p->strip, p->slen * sizeof(sop)); + if (g->strip == NULL) { + SETERROR(REG_ESPACE); + g->strip = p->strip; + } +} + +/* + - findmust - fill in must and mlen with longest mandatory literal string + == static void findmust(register struct parse *p, register struct re_guts *g); + * + * This algorithm could do fancy things like analyzing the operands of | + * for common subsequences. Someday. This code is simple and finds most + * of the interesting cases. + * + * Note that must and mlen got initialized during setup. + */ +static void +findmust(p, g) +struct parse *p; +register struct re_guts *g; +{ + register sop *scan; + sop *start = NULL; + register sop *newstart = NULL; + register sopno newlen; + register sop s; + register char *cp; + register sopno i; + + /* avoid making error situations worse */ + if (p->error != 0) + return; + + /* find the longest OCHAR sequence in strip */ + newlen = 0; + scan = g->strip + 1; + do { + s = *scan++; + switch (OP(s)) { + case OCHAR: /* sequence member */ + if (newlen == 0) /* new sequence */ + newstart = scan - 1; + newlen++; + break; + case OPLUS_: /* things that don't break one */ + case OLPAREN: + case ORPAREN: + break; + case OQUEST_: /* things that must be skipped */ + case OCH_: + scan--; + do { + scan += OPND(s); + s = *scan; + /* assert() interferes w debug printouts */ + if (OP(s) != O_QUEST && OP(s) != O_CH && + OP(s) != OOR2) { + g->iflags |= BAD; + return; + } + } while (OP(s) != O_QUEST && OP(s) != O_CH); + /* fallthrough */ + default: /* things that break a sequence */ + if (newlen > g->mlen) { /* ends one */ + start = newstart; + g->mlen = newlen; + } + newlen = 0; + break; + } + } while (OP(s) != OEND); + + if (g->mlen == 0) /* there isn't one */ + return; + + /* turn it into a character string */ + g->must = malloc((size_t)g->mlen + 1); + if (g->must == NULL) { /* argh; just forget it */ + g->mlen = 0; + return; + } + cp = g->must; + scan = start; + for (i = g->mlen; i > 0; i--) { + while (OP(s = *scan++) != OCHAR) + continue; + assert(cp < g->must + g->mlen); + *cp++ = (char)OPND(s); + } + assert(cp == g->must + g->mlen); + *cp++ = '\0'; /* just on general principles */ +} + +/* + - pluscount - count + nesting + == static sopno pluscount(register struct parse *p, register struct re_guts *g); + */ +static sopno /* nesting depth */ +pluscount(p, g) +struct parse *p; +register struct re_guts *g; +{ + register sop *scan; + register sop s; + register sopno plusnest = 0; + register sopno maxnest = 0; + + if (p->error != 0) + return(0); /* there may not be an OEND */ + + scan = g->strip + 1; + do { + s = *scan++; + switch (OP(s)) { + case OPLUS_: + plusnest++; + break; + case O_PLUS: + if (plusnest > maxnest) + maxnest = plusnest; + plusnest--; + break; + } + } while (OP(s) != OEND); + if (plusnest != 0) + g->iflags |= BAD; + return(maxnest); +} diff --git a/APACHE_1_2_X/src/regex/regerror.c b/APACHE_1_2_X/src/regex/regerror.c new file mode 100644 index 00000000000..850b0e61b57 --- /dev/null +++ b/APACHE_1_2_X/src/regex/regerror.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "regerror.ih" + +/* + = #define REG_NOMATCH 1 + = #define REG_BADPAT 2 + = #define REG_ECOLLATE 3 + = #define REG_ECTYPE 4 + = #define REG_EESCAPE 5 + = #define REG_ESUBREG 6 + = #define REG_EBRACK 7 + = #define REG_EPAREN 8 + = #define REG_EBRACE 9 + = #define REG_BADBR 10 + = #define REG_ERANGE 11 + = #define REG_ESPACE 12 + = #define REG_BADRPT 13 + = #define REG_EMPTY 14 + = #define REG_ASSERT 15 + = #define REG_INVARG 16 + = #define REG_ATOI 255 // convert name to number (!) + = #define REG_ITOA 0400 // convert number to name (!) + */ +static struct rerr { + int code; + char *name; + char *explain; +} rerrs[] = { + { REG_NOMATCH, "REG_NOMATCH", "regexec() failed to match" }, + { REG_BADPAT, "REG_BADPAT", "invalid regular expression" }, + { REG_ECOLLATE, "REG_ECOLLATE", "invalid collating element" }, + { REG_ECTYPE, "REG_ECTYPE", "invalid character class" }, + { REG_EESCAPE, "REG_EESCAPE", "trailing backslash (\\)" }, + { REG_ESUBREG, "REG_ESUBREG", "invalid backreference number" }, + { REG_EBRACK, "REG_EBRACK", "brackets ([ ]) not balanced" }, + { REG_EPAREN, "REG_EPAREN", "parentheses not balanced" }, + { REG_EBRACE, "REG_EBRACE", "braces not balanced" }, + { REG_BADBR, "REG_BADBR", "invalid repetition count(s)" }, + { REG_ERANGE, "REG_ERANGE", "invalid character range" }, + { REG_ESPACE, "REG_ESPACE", "out of memory" }, + { REG_BADRPT, "REG_BADRPT", "repetition-operator operand invalid" }, + { REG_EMPTY, "REG_EMPTY", "empty (sub)expression" }, + { REG_ASSERT, "REG_ASSERT", "\"can't happen\" -- you found a bug" }, + { REG_INVARG, "REG_INVARG", "invalid argument to regex routine" }, + { 0, "", "*** unknown regexp error code ***" } +}; + +/* + - regerror - the interface to error numbers + = extern size_t regerror(int, const regex_t *, char *, size_t); + */ +/* ARGSUSED */ +size_t +regerror(errcode, preg, errbuf, errbuf_size) +int errcode; +const regex_t *preg; +char *errbuf; +size_t errbuf_size; +{ + register struct rerr *r; + register size_t len; + register int target = errcode &~ REG_ITOA; + register char *s; + char convbuf[50]; + + if (errcode == REG_ATOI) + s = regatoi(preg, convbuf); + else { + for (r = rerrs; r->code != 0; r++) + if (r->code == target) + break; + + if (errcode®_ITOA) { + if (r->code != 0) + (void) strcpy(convbuf, r->name); + else + sprintf(convbuf, "REG_0x%x", target); + assert(strlen(convbuf) < sizeof(convbuf)); + s = convbuf; + } else + s = r->explain; + } + + len = strlen(s) + 1; + if (errbuf_size > 0) { + if (errbuf_size > len) + (void) strcpy(errbuf, s); + else { + (void) strncpy(errbuf, s, errbuf_size-1); + errbuf[errbuf_size-1] = '\0'; + } + } + + return(len); +} + +/* + - regatoi - internal routine to implement REG_ATOI + == static char *regatoi(const regex_t *preg, char *localbuf); + */ +static char * +regatoi(preg, localbuf) +const regex_t *preg; +char *localbuf; +{ + register struct rerr *r; + + for (r = rerrs; r->code != 0; r++) + if (strcmp(r->name, preg->re_endp) == 0) + break; + if (r->code == 0) + return("0"); + + sprintf(localbuf, "%d", r->code); + return(localbuf); +} diff --git a/APACHE_1_2_X/src/regex/regex.3 b/APACHE_1_2_X/src/regex/regex.3 new file mode 100644 index 00000000000..100c8a7f71c --- /dev/null +++ b/APACHE_1_2_X/src/regex/regex.3 @@ -0,0 +1,502 @@ +.TH REGEX 3 "17 May 1993" +.BY "Henry Spencer" +.de ZR +.\" one other place knows this name: the SEE ALSO section +.IR regex (7) \\$1 +.. +.SH NAME +regcomp, regexec, regerror, regfree \- regular-expression library +.SH SYNOPSIS +.ft B +.\".na +#include +.br +#include +.HP 10 +int regcomp(regex_t\ *preg, const\ char\ *pattern, int\ cflags); +.HP +int\ regexec(const\ regex_t\ *preg, const\ char\ *string, +size_t\ nmatch, regmatch_t\ pmatch[], int\ eflags); +.HP +size_t\ regerror(int\ errcode, const\ regex_t\ *preg, +char\ *errbuf, size_t\ errbuf_size); +.HP +void\ regfree(regex_t\ *preg); +.\".ad +.ft +.SH DESCRIPTION +These routines implement POSIX 1003.2 regular expressions (``RE''s); +see +.ZR . +.I Regcomp +compiles an RE written as a string into an internal form, +.I regexec +matches that internal form against a string and reports results, +.I regerror +transforms error codes from either into human-readable messages, +and +.I regfree +frees any dynamically-allocated storage used by the internal form +of an RE. +.PP +The header +.I +declares two structure types, +.I regex_t +and +.IR regmatch_t , +the former for compiled internal forms and the latter for match reporting. +It also declares the four functions, +a type +.IR regoff_t , +and a number of constants with names starting with ``REG_''. +.PP +.I Regcomp +compiles the regular expression contained in the +.I pattern +string, +subject to the flags in +.IR cflags , +and places the results in the +.I regex_t +structure pointed to by +.IR preg . +.I Cflags +is the bitwise OR of zero or more of the following flags: +.IP REG_EXTENDED \w'REG_EXTENDED'u+2n +Compile modern (``extended'') REs, +rather than the obsolete (``basic'') REs that +are the default. +.IP REG_BASIC +This is a synonym for 0, +provided as a counterpart to REG_EXTENDED to improve readability. +.IP REG_NOSPEC +Compile with recognition of all special characters turned off. +All characters are thus considered ordinary, +so the ``RE'' is a literal string. +This is an extension, +compatible with but not specified by POSIX 1003.2, +and should be used with +caution in software intended to be portable to other systems. +REG_EXTENDED and REG_NOSPEC may not be used +in the same call to +.IR regcomp . +.IP REG_ICASE +Compile for matching that ignores upper/lower case distinctions. +See +.ZR . +.IP REG_NOSUB +Compile for matching that need only report success or failure, +not what was matched. +.IP REG_NEWLINE +Compile for newline-sensitive matching. +By default, newline is a completely ordinary character with no special +meaning in either REs or strings. +With this flag, +`[^' bracket expressions and `.' never match newline, +a `^' anchor matches the null string after any newline in the string +in addition to its normal function, +and the `$' anchor matches the null string before any newline in the +string in addition to its normal function. +.IP REG_PEND +The regular expression ends, +not at the first NUL, +but just before the character pointed to by the +.I re_endp +member of the structure pointed to by +.IR preg . +The +.I re_endp +member is of type +.IR const\ char\ * . +This flag permits inclusion of NULs in the RE; +they are considered ordinary characters. +This is an extension, +compatible with but not specified by POSIX 1003.2, +and should be used with +caution in software intended to be portable to other systems. +.PP +When successful, +.I regcomp +returns 0 and fills in the structure pointed to by +.IR preg . +One member of that structure +(other than +.IR re_endp ) +is publicized: +.IR re_nsub , +of type +.IR size_t , +contains the number of parenthesized subexpressions within the RE +(except that the value of this member is undefined if the +REG_NOSUB flag was used). +If +.I regcomp +fails, it returns a non-zero error code; +see DIAGNOSTICS. +.PP +.I Regexec +matches the compiled RE pointed to by +.I preg +against the +.IR string , +subject to the flags in +.IR eflags , +and reports results using +.IR nmatch , +.IR pmatch , +and the returned value. +The RE must have been compiled by a previous invocation of +.IR regcomp . +The compiled form is not altered during execution of +.IR regexec , +so a single compiled RE can be used simultaneously by multiple threads. +.PP +By default, +the NUL-terminated string pointed to by +.I string +is considered to be the text of an entire line, minus any terminating +newline. +The +.I eflags +argument is the bitwise OR of zero or more of the following flags: +.IP REG_NOTBOL \w'REG_STARTEND'u+2n +The first character of +the string +is not the beginning of a line, so the `^' anchor should not match before it. +This does not affect the behavior of newlines under REG_NEWLINE. +.IP REG_NOTEOL +The NUL terminating +the string +does not end a line, so the `$' anchor should not match before it. +This does not affect the behavior of newlines under REG_NEWLINE. +.IP REG_STARTEND +The string is considered to start at +\fIstring\fR\ + \fIpmatch\fR[0].\fIrm_so\fR +and to have a terminating NUL located at +\fIstring\fR\ + \fIpmatch\fR[0].\fIrm_eo\fR +(there need not actually be a NUL at that location), +regardless of the value of +.IR nmatch . +See below for the definition of +.IR pmatch +and +.IR nmatch . +This is an extension, +compatible with but not specified by POSIX 1003.2, +and should be used with +caution in software intended to be portable to other systems. +Note that a non-zero \fIrm_so\fR does not imply REG_NOTBOL; +REG_STARTEND affects only the location of the string, +not how it is matched. +.PP +See +.ZR +for a discussion of what is matched in situations where an RE or a +portion thereof could match any of several substrings of +.IR string . +.PP +Normally, +.I regexec +returns 0 for success and the non-zero code REG_NOMATCH for failure. +Other non-zero error codes may be returned in exceptional situations; +see DIAGNOSTICS. +.PP +If REG_NOSUB was specified in the compilation of the RE, +or if +.I nmatch +is 0, +.I regexec +ignores the +.I pmatch +argument (but see below for the case where REG_STARTEND is specified). +Otherwise, +.I pmatch +points to an array of +.I nmatch +structures of type +.IR regmatch_t . +Such a structure has at least the members +.I rm_so +and +.IR rm_eo , +both of type +.I regoff_t +(a signed arithmetic type at least as large as an +.I off_t +and a +.IR ssize_t ), +containing respectively the offset of the first character of a substring +and the offset of the first character after the end of the substring. +Offsets are measured from the beginning of the +.I string +argument given to +.IR regexec . +An empty substring is denoted by equal offsets, +both indicating the character following the empty substring. +.PP +The 0th member of the +.I pmatch +array is filled in to indicate what substring of +.I string +was matched by the entire RE. +Remaining members report what substring was matched by parenthesized +subexpressions within the RE; +member +.I i +reports subexpression +.IR i , +with subexpressions counted (starting at 1) by the order of their opening +parentheses in the RE, left to right. +Unused entries in the array\(emcorresponding either to subexpressions that +did not participate in the match at all, or to subexpressions that do not +exist in the RE (that is, \fIi\fR\ > \fIpreg\fR\->\fIre_nsub\fR)\(emhave both +.I rm_so +and +.I rm_eo +set to \-1. +If a subexpression participated in the match several times, +the reported substring is the last one it matched. +(Note, as an example in particular, that when the RE `(b*)+' matches `bbb', +the parenthesized subexpression matches each of the three `b's and then +an infinite number of empty strings following the last `b', +so the reported substring is one of the empties.) +.PP +If REG_STARTEND is specified, +.I pmatch +must point to at least one +.I regmatch_t +(even if +.I nmatch +is 0 or REG_NOSUB was specified), +to hold the input offsets for REG_STARTEND. +Use for output is still entirely controlled by +.IR nmatch ; +if +.I nmatch +is 0 or REG_NOSUB was specified, +the value of +.IR pmatch [0] +will not be changed by a successful +.IR regexec . +.PP +.I Regerror +maps a non-zero +.I errcode +from either +.I regcomp +or +.I regexec +to a human-readable, printable message. +If +.I preg +is non-NULL, +the error code should have arisen from use of +the +.I regex_t +pointed to by +.IR preg , +and if the error code came from +.IR regcomp , +it should have been the result from the most recent +.I regcomp +using that +.IR regex_t . +.RI ( Regerror +may be able to supply a more detailed message using information +from the +.IR regex_t .) +.I Regerror +places the NUL-terminated message into the buffer pointed to by +.IR errbuf , +limiting the length (including the NUL) to at most +.I errbuf_size +bytes. +If the whole message won't fit, +as much of it as will fit before the terminating NUL is supplied. +In any case, +the returned value is the size of buffer needed to hold the whole +message (including terminating NUL). +If +.I errbuf_size +is 0, +.I errbuf +is ignored but the return value is still correct. +.PP +If the +.I errcode +given to +.I regerror +is first ORed with REG_ITOA, +the ``message'' that results is the printable name of the error code, +e.g. ``REG_NOMATCH'', +rather than an explanation thereof. +If +.I errcode +is REG_ATOI, +then +.I preg +shall be non-NULL and the +.I re_endp +member of the structure it points to +must point to the printable name of an error code; +in this case, the result in +.I errbuf +is the decimal digits of +the numeric value of the error code +(0 if the name is not recognized). +REG_ITOA and REG_ATOI are intended primarily as debugging facilities; +they are extensions, +compatible with but not specified by POSIX 1003.2, +and should be used with +caution in software intended to be portable to other systems. +Be warned also that they are considered experimental and changes are possible. +.PP +.I Regfree +frees any dynamically-allocated storage associated with the compiled RE +pointed to by +.IR preg . +The remaining +.I regex_t +is no longer a valid compiled RE +and the effect of supplying it to +.I regexec +or +.I regerror +is undefined. +.PP +None of these functions references global variables except for tables +of constants; +all are safe for use from multiple threads if the arguments are safe. +.SH IMPLEMENTATION CHOICES +There are a number of decisions that 1003.2 leaves up to the implementor, +either by explicitly saying ``undefined'' or by virtue of them being +forbidden by the RE grammar. +This implementation treats them as follows. +.PP +See +.ZR +for a discussion of the definition of case-independent matching. +.PP +There is no particular limit on the length of REs, +except insofar as memory is limited. +Memory usage is approximately linear in RE size, and largely insensitive +to RE complexity, except for bounded repetitions. +See BUGS for one short RE using them +that will run almost any system out of memory. +.PP +A backslashed character other than one specifically given a magic meaning +by 1003.2 (such magic meanings occur only in obsolete [``basic''] REs) +is taken as an ordinary character. +.PP +Any unmatched [ is a REG_EBRACK error. +.PP +Equivalence classes cannot begin or end bracket-expression ranges. +The endpoint of one range cannot begin another. +.PP +RE_DUP_MAX, the limit on repetition counts in bounded repetitions, is 255. +.PP +A repetition operator (?, *, +, or bounds) cannot follow another +repetition operator. +A repetition operator cannot begin an expression or subexpression +or follow `^' or `|'. +.PP +`|' cannot appear first or last in a (sub)expression or after another `|', +i.e. an operand of `|' cannot be an empty subexpression. +An empty parenthesized subexpression, `()', is legal and matches an +empty (sub)string. +An empty string is not a legal RE. +.PP +A `{' followed by a digit is considered the beginning of bounds for a +bounded repetition, which must then follow the syntax for bounds. +A `{' \fInot\fR followed by a digit is considered an ordinary character. +.PP +`^' and `$' beginning and ending subexpressions in obsolete (``basic'') +REs are anchors, not ordinary characters. +.SH SEE ALSO +grep(1), regex(7) +.PP +POSIX 1003.2, sections 2.8 (Regular Expression Notation) +and +B.5 (C Binding for Regular Expression Matching). +.SH DIAGNOSTICS +Non-zero error codes from +.I regcomp +and +.I regexec +include the following: +.PP +.nf +.ta \w'REG_ECOLLATE'u+3n +REG_NOMATCH regexec() failed to match +REG_BADPAT invalid regular expression +REG_ECOLLATE invalid collating element +REG_ECTYPE invalid character class +REG_EESCAPE \e applied to unescapable character +REG_ESUBREG invalid backreference number +REG_EBRACK brackets [ ] not balanced +REG_EPAREN parentheses ( ) not balanced +REG_EBRACE braces { } not balanced +REG_BADBR invalid repetition count(s) in { } +REG_ERANGE invalid character range in [ ] +REG_ESPACE ran out of memory +REG_BADRPT ?, *, or + operand invalid +REG_EMPTY empty (sub)expression +REG_ASSERT ``can't happen''\(emyou found a bug +REG_INVARG invalid argument, e.g. negative-length string +.fi +.SH HISTORY +Written by Henry Spencer at University of Toronto, +henry@zoo.toronto.edu. +.SH BUGS +This is an alpha release with known defects. +Please report problems. +.PP +There is one known functionality bug. +The implementation of internationalization is incomplete: +the locale is always assumed to be the default one of 1003.2, +and only the collating elements etc. of that locale are available. +.PP +The back-reference code is subtle and doubts linger about its correctness +in complex cases. +.PP +.I Regexec +performance is poor. +This will improve with later releases. +.I Nmatch +exceeding 0 is expensive; +.I nmatch +exceeding 1 is worse. +.I Regexec +is largely insensitive to RE complexity \fIexcept\fR that back +references are massively expensive. +RE length does matter; in particular, there is a strong speed bonus +for keeping RE length under about 30 characters, +with most special characters counting roughly double. +.PP +.I Regcomp +implements bounded repetitions by macro expansion, +which is costly in time and space if counts are large +or bounded repetitions are nested. +An RE like, say, +`((((a{1,100}){1,100}){1,100}){1,100}){1,100}' +will (eventually) run almost any existing machine out of swap space. +.PP +There are suspected problems with response to obscure error conditions. +Notably, +certain kinds of internal overflow, +produced only by truly enormous REs or by multiply nested bounded repetitions, +are probably not handled well. +.PP +Due to a mistake in 1003.2, things like `a)b' are legal REs because `)' is +a special character only in the presence of a previous unmatched `('. +This can't be fixed until the spec is fixed. +.PP +The standard's definition of back references is vague. +For example, does +`a\e(\e(b\e)*\e2\e)*d' match `abbbd'? +Until the standard is clarified, +behavior in such cases should not be relied on. +.PP +The implementation of word-boundary matching is a bit of a kludge, +and bugs may lurk in combinations of word-boundary matching and anchoring. diff --git a/APACHE_1_2_X/src/regex/regex.7 b/APACHE_1_2_X/src/regex/regex.7 new file mode 100644 index 00000000000..d89012bda1d --- /dev/null +++ b/APACHE_1_2_X/src/regex/regex.7 @@ -0,0 +1,233 @@ +.TH REGEX 7 "7 Feb 1994" +.BY "Henry Spencer" +.SH NAME +regex \- POSIX 1003.2 regular expressions +.SH DESCRIPTION +Regular expressions (``RE''s), +as defined in POSIX 1003.2, come in two forms: +modern REs (roughly those of +.IR egrep ; +1003.2 calls these ``extended'' REs) +and obsolete REs (roughly those of +.IR ed ; +1003.2 ``basic'' REs). +Obsolete REs mostly exist for backward compatibility in some old programs; +they will be discussed at the end. +1003.2 leaves some aspects of RE syntax and semantics open; +`\(dg' marks decisions on these aspects that +may not be fully portable to other 1003.2 implementations. +.PP +A (modern) RE is one\(dg or more non-empty\(dg \fIbranches\fR, +separated by `|'. +It matches anything that matches one of the branches. +.PP +A branch is one\(dg or more \fIpieces\fR, concatenated. +It matches a match for the first, followed by a match for the second, etc. +.PP +A piece is an \fIatom\fR possibly followed +by a single\(dg `*', `+', `?', or \fIbound\fR. +An atom followed by `*' matches a sequence of 0 or more matches of the atom. +An atom followed by `+' matches a sequence of 1 or more matches of the atom. +An atom followed by `?' matches a sequence of 0 or 1 matches of the atom. +.PP +A \fIbound\fR is `{' followed by an unsigned decimal integer, +possibly followed by `,' +possibly followed by another unsigned decimal integer, +always followed by `}'. +The integers must lie between 0 and RE_DUP_MAX (255\(dg) inclusive, +and if there are two of them, the first may not exceed the second. +An atom followed by a bound containing one integer \fIi\fR +and no comma matches +a sequence of exactly \fIi\fR matches of the atom. +An atom followed by a bound +containing one integer \fIi\fR and a comma matches +a sequence of \fIi\fR or more matches of the atom. +An atom followed by a bound +containing two integers \fIi\fR and \fIj\fR matches +a sequence of \fIi\fR through \fIj\fR (inclusive) matches of the atom. +.PP +An atom is a regular expression enclosed in `()' (matching a match for the +regular expression), +an empty set of `()' (matching the null string)\(dg, +a \fIbracket expression\fR (see below), `.' +(matching any single character), `^' (matching the null string at the +beginning of a line), `$' (matching the null string at the +end of a line), a `\e' followed by one of the characters +`^.[$()|*+?{\e' +(matching that character taken as an ordinary character), +a `\e' followed by any other character\(dg +(matching that character taken as an ordinary character, +as if the `\e' had not been present\(dg), +or a single character with no other significance (matching that character). +A `{' followed by a character other than a digit is an ordinary +character, not the beginning of a bound\(dg. +It is illegal to end an RE with `\e'. +.PP +A \fIbracket expression\fR is a list of characters enclosed in `[]'. +It normally matches any single character from the list (but see below). +If the list begins with `^', +it matches any single character +(but see below) \fInot\fR from the rest of the list. +If two characters in the list are separated by `\-', this is shorthand +for the full \fIrange\fR of characters between those two (inclusive) in the +collating sequence, +e.g. `[0-9]' in ASCII matches any decimal digit. +It is illegal\(dg for two ranges to share an +endpoint, e.g. `a-c-e'. +Ranges are very collating-sequence-dependent, +and portable programs should avoid relying on them. +.PP +To include a literal `]' in the list, make it the first character +(following a possible `^'). +To include a literal `\-', make it the first or last character, +or the second endpoint of a range. +To use a literal `\-' as the first endpoint of a range, +enclose it in `[.' and `.]' to make it a collating element (see below). +With the exception of these and some combinations using `[' (see next +paragraphs), all other special characters, including `\e', lose their +special significance within a bracket expression. +.PP +Within a bracket expression, a collating element (a character, +a multi-character sequence that collates as if it were a single character, +or a collating-sequence name for either) +enclosed in `[.' and `.]' stands for the +sequence of characters of that collating element. +The sequence is a single element of the bracket expression's list. +A bracket expression containing a multi-character collating element +can thus match more than one character, +e.g. if the collating sequence includes a `ch' collating element, +then the RE `[[.ch.]]*c' matches the first five characters +of `chchcc'. +.PP +Within a bracket expression, a collating element enclosed in `[=' and +`=]' is an equivalence class, standing for the sequences of characters +of all collating elements equivalent to that one, including itself. +(If there are no other equivalent collating elements, +the treatment is as if the enclosing delimiters were `[.' and `.]'.) +For example, if o and \o'o^' are the members of an equivalence class, +then `[[=o=]]', `[[=\o'o^'=]]', and `[o\o'o^']' are all synonymous. +An equivalence class may not\(dg be an endpoint +of a range. +.PP +Within a bracket expression, the name of a \fIcharacter class\fR enclosed +in `[:' and `:]' stands for the list of all characters belonging to that +class. +Standard character class names are: +.PP +.RS +.nf +.ta 3c 6c 9c +alnum digit punct +alpha graph space +blank lower upper +cntrl print xdigit +.fi +.RE +.PP +These stand for the character classes defined in +.IR ctype (3). +A locale may provide others. +A character class may not be used as an endpoint of a range. +.PP +There are two special cases\(dg of bracket expressions: +the bracket expressions `[[:<:]]' and `[[:>:]]' match the null string at +the beginning and end of a word respectively. +A word is defined as a sequence of +word characters +which is neither preceded nor followed by +word characters. +A word character is an +.I alnum +character (as defined by +.IR ctype (3)) +or an underscore. +This is an extension, +compatible with but not specified by POSIX 1003.2, +and should be used with +caution in software intended to be portable to other systems. +.PP +In the event that an RE could match more than one substring of a given +string, +the RE matches the one starting earliest in the string. +If the RE could match more than one substring starting at that point, +it matches the longest. +Subexpressions also match the longest possible substrings, subject to +the constraint that the whole match be as long as possible, +with subexpressions starting earlier in the RE taking priority over +ones starting later. +Note that higher-level subexpressions thus take priority over +their lower-level component subexpressions. +.PP +Match lengths are measured in characters, not collating elements. +A null string is considered longer than no match at all. +For example, +`bb*' matches the three middle characters of `abbbc', +`(wee|week)(knights|nights)' matches all ten characters of `weeknights', +when `(.*).*' is matched against `abc' the parenthesized subexpression +matches all three characters, and +when `(a*)*' is matched against `bc' both the whole RE and the parenthesized +subexpression match the null string. +.PP +If case-independent matching is specified, +the effect is much as if all case distinctions had vanished from the +alphabet. +When an alphabetic that exists in multiple cases appears as an +ordinary character outside a bracket expression, it is effectively +transformed into a bracket expression containing both cases, +e.g. `x' becomes `[xX]'. +When it appears inside a bracket expression, all case counterparts +of it are added to the bracket expression, so that (e.g.) `[x]' +becomes `[xX]' and `[^x]' becomes `[^xX]'. +.PP +No particular limit is imposed on the length of REs\(dg. +Programs intended to be portable should not employ REs longer +than 256 bytes, +as an implementation can refuse to accept such REs and remain +POSIX-compliant. +.PP +Obsolete (``basic'') regular expressions differ in several respects. +`|', `+', and `?' are ordinary characters and there is no equivalent +for their functionality. +The delimiters for bounds are `\e{' and `\e}', +with `{' and `}' by themselves ordinary characters. +The parentheses for nested subexpressions are `\e(' and `\e)', +with `(' and `)' by themselves ordinary characters. +`^' is an ordinary character except at the beginning of the +RE or\(dg the beginning of a parenthesized subexpression, +`$' is an ordinary character except at the end of the +RE or\(dg the end of a parenthesized subexpression, +and `*' is an ordinary character if it appears at the beginning of the +RE or the beginning of a parenthesized subexpression +(after a possible leading `^'). +Finally, there is one new type of atom, a \fIback reference\fR: +`\e' followed by a non-zero decimal digit \fId\fR +matches the same sequence of characters +matched by the \fId\fRth parenthesized subexpression +(numbering subexpressions by the positions of their opening parentheses, +left to right), +so that (e.g.) `\e([bc]\e)\e1' matches `bb' or `cc' but not `bc'. +.SH SEE ALSO +regex(3) +.PP +POSIX 1003.2, section 2.8 (Regular Expression Notation). +.SH BUGS +Having two kinds of REs is a botch. +.PP +The current 1003.2 spec says that `)' is an ordinary character in +the absence of an unmatched `('; +this was an unintentional result of a wording error, +and change is likely. +Avoid relying on it. +.PP +Back references are a dreadful botch, +posing major problems for efficient implementations. +They are also somewhat vaguely defined +(does +`a\e(\e(b\e)*\e2\e)*d' match `abbbd'?). +Avoid using them. +.PP +1003.2's specification of case-independent matching is vague. +The ``one case implies all cases'' definition given above +is current consensus among implementors as to the right interpretation. +.PP +The syntax for word boundaries is incredibly ugly. diff --git a/APACHE_1_2_X/src/regex/regex.h b/APACHE_1_2_X/src/regex/regex.h new file mode 100644 index 00000000000..dde954d8332 --- /dev/null +++ b/APACHE_1_2_X/src/regex/regex.h @@ -0,0 +1,73 @@ +#ifndef _REGEX_H_ +#define _REGEX_H_ /* never again */ +/* ========= begin header generated by ./mkh ========= */ +#ifdef __cplusplus +extern "C" { +#endif + +/* === regex2.h === */ +typedef off_t regoff_t; +typedef struct { + int re_magic; + size_t re_nsub; /* number of parenthesized subexpressions */ + const char *re_endp; /* end pointer for REG_PEND */ + struct re_guts *re_g; /* none of your business :-) */ +} regex_t; +typedef struct { + regoff_t rm_so; /* start of match */ + regoff_t rm_eo; /* end of match */ +} regmatch_t; + + +/* === regcomp.c === */ +extern int regcomp(regex_t *, const char *, int); +#define REG_BASIC 0000 +#define REG_EXTENDED 0001 +#define REG_ICASE 0002 +#define REG_NOSUB 0004 +#define REG_NEWLINE 0010 +#define REG_NOSPEC 0020 +#define REG_PEND 0040 +#define REG_DUMP 0200 + + +/* === regerror.c === */ +#define REG_NOMATCH 1 +#define REG_BADPAT 2 +#define REG_ECOLLATE 3 +#define REG_ECTYPE 4 +#define REG_EESCAPE 5 +#define REG_ESUBREG 6 +#define REG_EBRACK 7 +#define REG_EPAREN 8 +#define REG_EBRACE 9 +#define REG_BADBR 10 +#define REG_ERANGE 11 +#define REG_ESPACE 12 +#define REG_BADRPT 13 +#define REG_EMPTY 14 +#define REG_ASSERT 15 +#define REG_INVARG 16 +#define REG_ATOI 255 /* convert name to number (!) */ +#define REG_ITOA 0400 /* convert number to name (!) */ +extern size_t regerror(int, const regex_t *, char *, size_t); + + +/* === regexec.c === */ +extern int regexec(const regex_t *, const char *, size_t, regmatch_t [], int); +#define REG_NOTBOL 00001 +#define REG_NOTEOL 00002 +#define REG_STARTEND 00004 +#define REG_TRACE 00400 /* tracing of execution */ +#define REG_LARGE 01000 /* force large representation */ +#define REG_BACKR 02000 /* force use of backref code */ + + +/* === regfree.c === */ +extern void regfree(regex_t *); + +#ifdef __cplusplus +} +#endif +/* ========= end header generated by ./mkh ========= */ +#endif diff --git a/APACHE_1_2_X/src/regex/regex2.h b/APACHE_1_2_X/src/regex/regex2.h new file mode 100644 index 00000000000..6ec57b2ed4e --- /dev/null +++ b/APACHE_1_2_X/src/regex/regex2.h @@ -0,0 +1,132 @@ +/* + * First, the stuff that ends up in the outside-world include file + = typedef off_t regoff_t; + = typedef struct { + = int re_magic; + = size_t re_nsub; // number of parenthesized subexpressions + = const char *re_endp; // end pointer for REG_PEND + = struct re_guts *re_g; // none of your business :-) + = } regex_t; + = typedef struct { + = regoff_t rm_so; // start of match + = regoff_t rm_eo; // end of match + = } regmatch_t; + */ +/* + * internals of regex_t + */ +#define MAGIC1 ((('r'^0200)<<8) | 'e') + +/* + * The internal representation is a *strip*, a sequence of + * operators ending with an endmarker. (Some terminology etc. is a + * historical relic of earlier versions which used multiple strips.) + * Certain oddities in the representation are there to permit running + * the machinery backwards; in particular, any deviation from sequential + * flow must be marked at both its source and its destination. Some + * fine points: + * + * - OPLUS_ and O_PLUS are *inside* the loop they create. + * - OQUEST_ and O_QUEST are *outside* the bypass they create. + * - OCH_ and O_CH are *outside* the multi-way branch they create, while + * OOR1 and OOR2 are respectively the end and the beginning of one of + * the branches. Note that there is an implicit OOR2 following OCH_ + * and an implicit OOR1 preceding O_CH. + * + * In state representations, an operator's bit is on to signify a state + * immediately *preceding* "execution" of that operator. + */ +typedef unsigned long sop; /* strip operator */ +typedef long sopno; +#define OPRMASK 0xf8000000 +#define OPDMASK 0x07ffffff +#define OPSHIFT ((unsigned)27) +#define OP(n) ((n)&OPRMASK) +#define OPND(n) ((n)&OPDMASK) +#define SOP(op, opnd) ((op)|(opnd)) +/* operators meaning operand */ +/* (back, fwd are offsets) */ +#define OEND (1< uch [csetsize] */ + uch mask; /* bit within array */ + uch hash; /* hash code */ + size_t smultis; + char *multis; /* -> char[smulti] ab\0cd\0ef\0\0 */ +} cset; +/* note that CHadd and CHsub are unsafe, and CHIN doesn't yield 0/1 */ +#define CHadd(cs, c) ((cs)->ptr[(uch)(c)] |= (cs)->mask, (cs)->hash += (c)) +#define CHsub(cs, c) ((cs)->ptr[(uch)(c)] &= ~(cs)->mask, (cs)->hash -= (c)) +#define CHIN(cs, c) ((cs)->ptr[(uch)(c)] & (cs)->mask) +#define MCadd(p, cs, cp) mcadd(p, cs, cp) /* regcomp() internal fns */ + +/* stuff for character categories */ +typedef unsigned char cat_t; + +/* + * main compiled-expression structure + */ +struct re_guts { + int magic; +# define MAGIC2 ((('R'^0200)<<8)|'E') + sop *strip; /* malloced area for strip */ + int csetsize; /* number of bits in a cset vector */ + int ncsets; /* number of csets in use */ + cset *sets; /* -> cset [ncsets] */ + uch *setbits; /* -> uch[csetsize][ncsets/CHAR_BIT] */ + int cflags; /* copy of regcomp() cflags argument */ + sopno nstates; /* = number of sops */ + sopno firststate; /* the initial OEND (normally 0) */ + sopno laststate; /* the final OEND */ + int iflags; /* internal flags */ +# define USEBOL 01 /* used ^ */ +# define USEEOL 02 /* used $ */ +# define BAD 04 /* something wrong */ + int nbol; /* number of ^ used */ + int neol; /* number of $ used */ + int ncategories; /* how many character categories */ + cat_t *categories; /* ->catspace[-CHAR_MIN] */ + char *must; /* match must contain this string */ + int mlen; /* length of must */ + size_t nsub; /* copy of re_nsub */ + int backrefs; /* does it use back references? */ + sopno nplus; /* how deep does it nest +s? */ + /* catspace must be last */ + cat_t catspace[1]; /* actually [NC] */ +}; + +/* misc utilities */ +#define OUT (CHAR_MAX+1) /* a non-character value */ +#define ISWORD(c) (isalnum(c) || (c) == '_') diff --git a/APACHE_1_2_X/src/regex/regexec.c b/APACHE_1_2_X/src/regex/regexec.c new file mode 100644 index 00000000000..63bb1c37130 --- /dev/null +++ b/APACHE_1_2_X/src/regex/regexec.c @@ -0,0 +1,140 @@ +/* + * the outer shell of regexec() + * + * This file includes engine.c *twice*, after muchos fiddling with the + * macros that code uses. This lets the same code operate on two different + * representations for state sets. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "regex2.h" + +#ifndef NDEBUG +static int nope = 0; /* for use in asserts; shuts lint up */ +#endif + +/* macros for manipulating states, small version */ +#define states long +#define states1 states /* for later use in regexec() decision */ +#define CLEAR(v) ((v) = 0) +#define SET0(v, n) ((v) &= ~(1 << (n))) +#define SET1(v, n) ((v) |= 1 << (n)) +#define ISSET(v, n) ((v) & (1 << (n))) +#define ASSIGN(d, s) ((d) = (s)) +#define EQ(a, b) ((a) == (b)) +#define STATEVARS int dummy /* dummy version */ +#define STATESETUP(m, n) /* nothing */ +#define STATETEARDOWN(m) /* nothing */ +#define SETUP(v) ((v) = 0) +#define onestate int +#define INIT(o, n) ((o) = (unsigned)1 << (n)) +#define INC(o) ((o) <<= 1) +#define ISSTATEIN(v, o) ((v) & (o)) +/* some abbreviations; note that some of these know variable names! */ +/* do "if I'm here, I can also be there" etc without branches */ +#define FWD(dst, src, n) ((dst) |= ((unsigned)(src)&(here)) << (n)) +#define BACK(dst, src, n) ((dst) |= ((unsigned)(src)&(here)) >> (n)) +#define ISSETBACK(v, n) ((v) & ((unsigned)here >> (n))) +/* function names */ +#define SNAMES /* engine.c looks after details */ + +#include "engine.c" + +/* now undo things */ +#undef states +#undef CLEAR +#undef SET0 +#undef SET1 +#undef ISSET +#undef ASSIGN +#undef EQ +#undef STATEVARS +#undef STATESETUP +#undef STATETEARDOWN +#undef SETUP +#undef onestate +#undef INIT +#undef INC +#undef ISSTATEIN +#undef FWD +#undef BACK +#undef ISSETBACK +#undef SNAMES + +/* macros for manipulating states, large version */ +#define states char * +#define CLEAR(v) memset(v, 0, m->g->nstates) +#define SET0(v, n) ((v)[n] = 0) +#define SET1(v, n) ((v)[n] = 1) +#define ISSET(v, n) ((v)[n]) +#define ASSIGN(d, s) memcpy(d, s, m->g->nstates) +#define EQ(a, b) (memcmp(a, b, m->g->nstates) == 0) +#define STATEVARS int vn; char *space +#define STATESETUP(m, nv) { (m)->space = malloc((nv)*(m)->g->nstates); \ + if ((m)->space == NULL) return(REG_ESPACE); \ + (m)->vn = 0; } +#define STATETEARDOWN(m) { free((m)->space); } +#define SETUP(v) ((v) = &m->space[m->vn++ * m->g->nstates]) +#define onestate int +#define INIT(o, n) ((o) = (n)) +#define INC(o) ((o)++) +#define ISSTATEIN(v, o) ((v)[o]) +/* some abbreviations; note that some of these know variable names! */ +/* do "if I'm here, I can also be there" etc without branches */ +#define FWD(dst, src, n) ((dst)[here+(n)] |= (src)[here]) +#define BACK(dst, src, n) ((dst)[here-(n)] |= (src)[here]) +#define ISSETBACK(v, n) ((v)[here - (n)]) +/* function names */ +#define LNAMES /* flag */ + +#include "engine.c" + +/* + - regexec - interface for matching + = extern int regexec(const regex_t *, const char *, size_t, \ + = regmatch_t [], int); + = #define REG_NOTBOL 00001 + = #define REG_NOTEOL 00002 + = #define REG_STARTEND 00004 + = #define REG_TRACE 00400 // tracing of execution + = #define REG_LARGE 01000 // force large representation + = #define REG_BACKR 02000 // force use of backref code + * + * We put this here so we can exploit knowledge of the state representation + * when choosing which matcher to call. Also, by this point the matchers + * have been prototyped. + */ +int /* 0 success, REG_NOMATCH failure */ +regexec(preg, string, nmatch, pmatch, eflags) +const regex_t *preg; +const char *string; +size_t nmatch; +regmatch_t pmatch[]; +int eflags; +{ + register struct re_guts *g = preg->re_g; +#ifdef REDEBUG +# define GOODFLAGS(f) (f) +#else +# define GOODFLAGS(f) ((f)&(REG_NOTBOL|REG_NOTEOL|REG_STARTEND)) +#endif + + if (preg->re_magic != MAGIC1 || g->magic != MAGIC2) + return(REG_BADPAT); + assert(!(g->iflags&BAD)); + if (g->iflags&BAD) /* backstop for no-debug case */ + return(REG_BADPAT); + eflags = GOODFLAGS(eflags); + + if (g->nstates <= CHAR_BIT*sizeof(states1) && !(eflags®_LARGE)) + return(smatcher(g, (char *)string, nmatch, pmatch, eflags)); + else + return(lmatcher(g, (char *)string, nmatch, pmatch, eflags)); +} diff --git a/APACHE_1_2_X/src/regex/regfree.c b/APACHE_1_2_X/src/regex/regfree.c new file mode 100644 index 00000000000..9a6acf1733a --- /dev/null +++ b/APACHE_1_2_X/src/regex/regfree.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include + +#include "utils.h" +#include "regex2.h" + +/* + - regfree - free everything + = extern void regfree(regex_t *); + */ +void +regfree(preg) +regex_t *preg; +{ + register struct re_guts *g; + + if (preg->re_magic != MAGIC1) /* oops */ + return; /* nice to complain, but hard */ + + g = preg->re_g; + if (g == NULL || g->magic != MAGIC2) /* oops again */ + return; + preg->re_magic = 0; /* mark it invalid */ + g->magic = 0; /* mark it invalid */ + + if (g->strip != NULL) + free((char *)g->strip); + if (g->sets != NULL) + free((char *)g->sets); + if (g->setbits != NULL) + free((char *)g->setbits); + if (g->must != NULL) + free(g->must); + free((char *)g); +} diff --git a/APACHE_1_2_X/src/regex/split.c b/APACHE_1_2_X/src/regex/split.c new file mode 100644 index 00000000000..188bdb775b9 --- /dev/null +++ b/APACHE_1_2_X/src/regex/split.c @@ -0,0 +1,316 @@ +#include +#include + +/* + - split - divide a string into fields, like awk split() + = int split(char *string, char *fields[], int nfields, char *sep); + */ +int /* number of fields, including overflow */ +split(string, fields, nfields, sep) +char *string; +char *fields[]; /* list is not NULL-terminated */ +int nfields; /* number of entries available in fields[] */ +char *sep; /* "" white, "c" single char, "ab" [ab]+ */ +{ + register char *p = string; + register char c; /* latest character */ + register char sepc = sep[0]; + register char sepc2; + register int fn; + register char **fp = fields; + register char *sepp; + register int trimtrail; + + /* white space */ + if (sepc == '\0') { + while ((c = *p++) == ' ' || c == '\t') + continue; + p--; + trimtrail = 1; + sep = " \t"; /* note, code below knows this is 2 long */ + sepc = ' '; + } else + trimtrail = 0; + sepc2 = sep[1]; /* now we can safely pick this up */ + + /* catch empties */ + if (*p == '\0') + return(0); + + /* single separator */ + if (sepc2 == '\0') { + fn = nfields; + for (;;) { + *fp++ = p; + fn--; + if (fn == 0) + break; + while ((c = *p++) != sepc) + if (c == '\0') + return(nfields - fn); + *(p-1) = '\0'; + } + /* we have overflowed the fields vector -- just count them */ + fn = nfields; + for (;;) { + while ((c = *p++) != sepc) + if (c == '\0') + return(fn); + fn++; + } + /* not reached */ + } + + /* two separators */ + if (sep[2] == '\0') { + fn = nfields; + for (;;) { + *fp++ = p; + fn--; + while ((c = *p++) != sepc && c != sepc2) + if (c == '\0') { + if (trimtrail && **(fp-1) == '\0') + fn++; + return(nfields - fn); + } + if (fn == 0) + break; + *(p-1) = '\0'; + while ((c = *p++) == sepc || c == sepc2) + continue; + p--; + } + /* we have overflowed the fields vector -- just count them */ + fn = nfields; + while (c != '\0') { + while ((c = *p++) == sepc || c == sepc2) + continue; + p--; + fn++; + while ((c = *p++) != '\0' && c != sepc && c != sepc2) + continue; + } + /* might have to trim trailing white space */ + if (trimtrail) { + p--; + while ((c = *--p) == sepc || c == sepc2) + continue; + p++; + if (*p != '\0') { + if (fn == nfields+1) + *p = '\0'; + fn--; + } + } + return(fn); + } + + /* n separators */ + fn = 0; + for (;;) { + if (fn < nfields) + *fp++ = p; + fn++; + for (;;) { + c = *p++; + if (c == '\0') + return(fn); + sepp = sep; + while ((sepc = *sepp++) != '\0' && sepc != c) + continue; + if (sepc != '\0') /* it was a separator */ + break; + } + if (fn < nfields) + *(p-1) = '\0'; + for (;;) { + c = *p++; + sepp = sep; + while ((sepc = *sepp++) != '\0' && sepc != c) + continue; + if (sepc == '\0') /* it wasn't a separator */ + break; + } + p--; + } + + /* not reached */ +} + +#ifdef TEST_SPLIT + + +/* + * test program + * pgm runs regression + * pgm sep splits stdin lines by sep + * pgm str sep splits str by sep + * pgm str sep n splits str by sep n times + */ +int +main(argc, argv) +int argc; +char *argv[]; +{ + char buf[512]; + register int n; +# define MNF 10 + char *fields[MNF]; + + if (argc > 4) + for (n = atoi(argv[3]); n > 0; n--) { + (void) strcpy(buf, argv[1]); + } + else if (argc > 3) + for (n = atoi(argv[3]); n > 0; n--) { + (void) strcpy(buf, argv[1]); + (void) split(buf, fields, MNF, argv[2]); + } + else if (argc > 2) + dosplit(argv[1], argv[2]); + else if (argc > 1) + while (fgets(buf, sizeof(buf), stdin) != NULL) { + buf[strlen(buf)-1] = '\0'; /* stomp newline */ + dosplit(buf, argv[1]); + } + else + regress(); + + exit(0); +} + +dosplit(string, seps) +char *string; +char *seps; +{ +# define NF 5 + char *fields[NF]; + register int nf; + + nf = split(string, fields, NF, seps); + print(nf, NF, fields); +} + +print(nf, nfp, fields) +int nf; +int nfp; +char *fields[]; +{ + register int fn; + register int bound; + + bound = (nf > nfp) ? nfp : nf; + printf("%d:\t", nf); + for (fn = 0; fn < bound; fn++) + printf("\"%s\"%s", fields[fn], (fn+1 < nf) ? ", " : "\n"); +} + +#define RNF 5 /* some table entries know this */ +struct { + char *str; + char *seps; + int nf; + char *fi[RNF]; +} tests[] = { + "", " ", 0, { "" }, + " ", " ", 2, { "", "" }, + "x", " ", 1, { "x" }, + "xy", " ", 1, { "xy" }, + "x y", " ", 2, { "x", "y" }, + "abc def g ", " ", 5, { "abc", "def", "", "g", "" }, + " a bcd", " ", 4, { "", "", "a", "bcd" }, + "a b c d e f", " ", 6, { "a", "b", "c", "d", "e f" }, + " a b c d ", " ", 6, { "", "a", "b", "c", "d " }, + + "", " _", 0, { "" }, + " ", " _", 2, { "", "" }, + "x", " _", 1, { "x" }, + "x y", " _", 2, { "x", "y" }, + "ab _ cd", " _", 2, { "ab", "cd" }, + " a_b c ", " _", 5, { "", "a", "b", "c", "" }, + "a b c_d e f", " _", 6, { "a", "b", "c", "d", "e f" }, + " a b c d ", " _", 6, { "", "a", "b", "c", "d " }, + + "", " _~", 0, { "" }, + " ", " _~", 2, { "", "" }, + "x", " _~", 1, { "x" }, + "x y", " _~", 2, { "x", "y" }, + "ab _~ cd", " _~", 2, { "ab", "cd" }, + " a_b c~", " _~", 5, { "", "a", "b", "c", "" }, + "a b_c d~e f", " _~", 6, { "a", "b", "c", "d", "e f" }, + "~a b c d ", " _~", 6, { "", "a", "b", "c", "d " }, + + "", " _~-", 0, { "" }, + " ", " _~-", 2, { "", "" }, + "x", " _~-", 1, { "x" }, + "x y", " _~-", 2, { "x", "y" }, + "ab _~- cd", " _~-", 2, { "ab", "cd" }, + " a_b c~", " _~-", 5, { "", "a", "b", "c", "" }, + "a b_c-d~e f", " _~-", 6, { "a", "b", "c", "d", "e f" }, + "~a-b c d ", " _~-", 6, { "", "a", "b", "c", "d " }, + + "", " ", 0, { "" }, + " ", " ", 2, { "", "" }, + "x", " ", 1, { "x" }, + "xy", " ", 1, { "xy" }, + "x y", " ", 2, { "x", "y" }, + "abc def g ", " ", 4, { "abc", "def", "g", "" }, + " a bcd", " ", 3, { "", "a", "bcd" }, + "a b c d e f", " ", 6, { "a", "b", "c", "d", "e f" }, + " a b c d ", " ", 6, { "", "a", "b", "c", "d " }, + + "", "", 0, { "" }, + " ", "", 0, { "" }, + "x", "", 1, { "x" }, + "xy", "", 1, { "xy" }, + "x y", "", 2, { "x", "y" }, + "abc def g ", "", 3, { "abc", "def", "g" }, + "\t a bcd", "", 2, { "a", "bcd" }, + " a \tb\t c ", "", 3, { "a", "b", "c" }, + "a b c d e ", "", 5, { "a", "b", "c", "d", "e" }, + "a b\tc d e f", "", 6, { "a", "b", "c", "d", "e f" }, + " a b c d e f ", "", 6, { "a", "b", "c", "d", "e f " }, + + NULL, NULL, 0, { NULL }, +}; + +regress() +{ + char buf[512]; + register int n; + char *fields[RNF+1]; + register int nf; + register int i; + register int printit; + register char *f; + + for (n = 0; tests[n].str != NULL; n++) { + (void) strcpy(buf, tests[n].str); + fields[RNF] = NULL; + nf = split(buf, fields, RNF, tests[n].seps); + printit = 0; + if (nf != tests[n].nf) { + printf("split `%s' by `%s' gave %d fields, not %d\n", + tests[n].str, tests[n].seps, nf, tests[n].nf); + printit = 1; + } else if (fields[RNF] != NULL) { + printf("split() went beyond array end\n"); + printit = 1; + } else { + for (i = 0; i < nf && i < RNF; i++) { + f = fields[i]; + if (f == NULL) + f = "(NULL)"; + if (strcmp(f, tests[n].fi[i]) != 0) { + printf("split `%s' by `%s', field %d is `%s', not `%s'\n", + tests[n].str, tests[n].seps, + i, fields[i], tests[n].fi[i]); + printit = 1; + } + } + } + if (printit) + print(nf, RNF, fields); + } +} +#endif diff --git a/APACHE_1_2_X/src/regex/tests b/APACHE_1_2_X/src/regex/tests new file mode 100644 index 00000000000..c05846177f5 --- /dev/null +++ b/APACHE_1_2_X/src/regex/tests @@ -0,0 +1,475 @@ +# regular expression test set +# Lines are at least three fields, separated by one or more tabs. "" stands +# for an empty field. First field is an RE. Second field is flags. If +# C flag given, regcomp() is expected to fail, and the third field is the +# error name (minus the leading REG_). +# +# Otherwise it is expected to succeed, and the third field is the string to +# try matching it against. If there is no fourth field, the match is +# expected to fail. If there is a fourth field, it is the substring that +# the RE is expected to match. If there is a fifth field, it is a comma- +# separated list of what the subexpressions should match, with - indicating +# no match for that one. In both the fourth and fifth fields, a (sub)field +# starting with @ indicates that the (sub)expression is expected to match +# a null string followed by the stuff after the @; this provides a way to +# test where null strings match. The character `N' in REs and strings +# is newline, `S' is space, `T' is tab, `Z' is NUL. +# +# The full list of flags: +# - placeholder, does nothing +# b RE is a BRE, not an ERE +# & try it as both an ERE and a BRE +# C regcomp() error expected, third field is error name +# i REG_ICASE +# m ("mundane") REG_NOSPEC +# s REG_NOSUB (not really testable) +# n REG_NEWLINE +# ^ REG_NOTBOL +# $ REG_NOTEOL +# # REG_STARTEND (see below) +# p REG_PEND +# +# For REG_STARTEND, the start/end offsets are those of the substring +# enclosed in (). + +# basics +a & a a +abc & abc abc +abc|de - abc abc +a|b|c - abc a + +# parentheses and perversions thereof +a(b)c - abc abc +a\(b\)c b abc abc +a( C EPAREN +a( b a( a( +a\( - a( a( +a\( bC EPAREN +a\(b bC EPAREN +a(b C EPAREN +a(b b a(b a(b +# gag me with a right parenthesis -- 1003.2 goofed here (my fault, partly) +a) - a) a) +) - ) ) +# end gagging (in a just world, those *should* give EPAREN) +a) b a) a) +a\) bC EPAREN +\) bC EPAREN +a()b - ab ab +a\(\)b b ab ab + +# anchoring and REG_NEWLINE +^abc$ & abc abc +a^b - a^b +a^b b a^b a^b +a$b - a$b +a$b b a$b a$b +^ & abc @abc +$ & abc @ +^$ & "" @ +$^ - "" @ +\($\)\(^\) b "" @ +# stop retching, those are legitimate (although disgusting) +^^ - "" @ +$$ - "" @ +b$ & abNc +b$ &n abNc b +^b$ & aNbNc +^b$ &n aNbNc b +^$ &n aNNb @Nb +^$ n abc +^$ n abcN @ +$^ n aNNb @Nb +\($\)\(^\) bn aNNb @Nb +^^ n^ aNNb @Nb +$$ n aNNb @NN +^a ^ a +a$ $ a +^a ^n aNb +^b ^n aNb b +a$ $n bNa +b$ $n bNa b +a*(^b$)c* - b b +a*\(^b$\)c* b b b + +# certain syntax errors and non-errors +| C EMPTY +| b | | +* C BADRPT +* b * * ++ C BADRPT +? C BADRPT +"" &C EMPTY +() - abc @abc +\(\) b abc @abc +a||b C EMPTY +|ab C EMPTY +ab| C EMPTY +(|a)b C EMPTY +(a|)b C EMPTY +(*a) C BADRPT +(+a) C BADRPT +(?a) C BADRPT +({1}a) C BADRPT +\(\{1\}a\) bC BADRPT +(a|*b) C BADRPT +(a|+b) C BADRPT +(a|?b) C BADRPT +(a|{1}b) C BADRPT +^* C BADRPT +^* b * * +^+ C BADRPT +^? C BADRPT +^{1} C BADRPT +^\{1\} bC BADRPT + +# metacharacters, backslashes +a.c & abc abc +a[bc]d & abd abd +a\*c & a*c a*c +a\\b & a\b a\b +a\\\*b & a\*b a\*b +a\bc & abc abc +a\ &C EESCAPE +a\\bc & a\bc a\bc +\{ bC BADRPT +a\[b & a[b a[b +a[b &C EBRACK +# trailing $ is a peculiar special case for the BRE code +a$ & a a +a$ & a$ +a\$ & a +a\$ & a$ a$ +a\\$ & a +a\\$ & a$ +a\\$ & a\$ +a\\$ & a\ a\ + +# back references, ugh +a\(b\)\2c bC ESUBREG +a\(b\1\)c bC ESUBREG +a\(b*\)c\1d b abbcbbd abbcbbd bb +a\(b*\)c\1d b abbcbd +a\(b*\)c\1d b abbcbbbd +^\(.\)\1 b abc +a\([bc]\)\1d b abcdabbd abbd b +a\(\([bc]\)\2\)*d b abbccd abbccd +a\(\([bc]\)\2\)*d b abbcbd +# actually, this next one probably ought to fail, but the spec is unclear +a\(\(b\)*\2\)*d b abbbd abbbd +# here is a case that no NFA implementation does right +\(ab*\)[ab]*\1 b ababaaa ababaaa a +# check out normal matching in the presence of back refs +\(a\)\1bcd b aabcd aabcd +\(a\)\1bc*d b aabcd aabcd +\(a\)\1bc*d b aabd aabd +\(a\)\1bc*d b aabcccd aabcccd +\(a\)\1bc*[ce]d b aabcccd aabcccd +^\(a\)\1b\(c\)*cd$ b aabcccd aabcccd + +# ordinary repetitions +ab*c & abc abc +ab+c - abc abc +ab?c - abc abc +a\(*\)b b a*b a*b +a\(**\)b b ab ab +a\(***\)b bC BADRPT +*a b *a *a +**a b a a +***a bC BADRPT + +# the dreaded bounded repetitions +{ & { { +{abc & {abc {abc +{1 C BADRPT +{1} C BADRPT +a{b & a{b a{b +a{1}b - ab ab +a\{1\}b b ab ab +a{1,}b - ab ab +a\{1,\}b b ab ab +a{1,2}b - aab aab +a\{1,2\}b b aab aab +a{1 C EBRACE +a\{1 bC EBRACE +a{1a C EBRACE +a\{1a bC EBRACE +a{1a} C BADBR +a\{1a\} bC BADBR +a{,2} - a{,2} a{,2} +a\{,2\} bC BADBR +a{,} - a{,} a{,} +a\{,\} bC BADBR +a{1,x} C BADBR +a\{1,x\} bC BADBR +a{1,x C EBRACE +a\{1,x bC EBRACE +a{300} C BADBR +a\{300\} bC BADBR +a{1,0} C BADBR +a\{1,0\} bC BADBR +ab{0,0}c - abcac ac +ab\{0,0\}c b abcac ac +ab{0,1}c - abcac abc +ab\{0,1\}c b abcac abc +ab{0,3}c - abbcac abbc +ab\{0,3\}c b abbcac abbc +ab{1,1}c - acabc abc +ab\{1,1\}c b acabc abc +ab{1,3}c - acabc abc +ab\{1,3\}c b acabc abc +ab{2,2}c - abcabbc abbc +ab\{2,2\}c b abcabbc abbc +ab{2,4}c - abcabbc abbc +ab\{2,4\}c b abcabbc abbc +((a{1,10}){1,10}){1,10} - a a a,a + +# multiple repetitions +a** &C BADRPT +a++ C BADRPT +a?? C BADRPT +a*+ C BADRPT +a*? C BADRPT +a+* C BADRPT +a+? C BADRPT +a?* C BADRPT +a?+ C BADRPT +a{1}{1} C BADRPT +a*{1} C BADRPT +a+{1} C BADRPT +a?{1} C BADRPT +a{1}* C BADRPT +a{1}+ C BADRPT +a{1}? C BADRPT +a*{b} - a{b} a{b} +a\{1\}\{1\} bC BADRPT +a*\{1\} bC BADRPT +a\{1\}* bC BADRPT + +# brackets, and numerous perversions thereof +a[b]c & abc abc +a[ab]c & abc abc +a[^ab]c & adc adc +a[]b]c & a]c a]c +a[[b]c & a[c a[c +a[-b]c & a-c a-c +a[^]b]c & adc adc +a[^-b]c & adc adc +a[b-]c & a-c a-c +a[b &C EBRACK +a[] &C EBRACK +a[1-3]c & a2c a2c +a[3-1]c &C ERANGE +a[1-3-5]c &C ERANGE +a[[.-.]--]c & a-c a-c +a[1- &C ERANGE +a[[. &C EBRACK +a[[.x &C EBRACK +a[[.x. &C EBRACK +a[[.x.] &C EBRACK +a[[.x.]] & ax ax +a[[.x,.]] &C ECOLLATE +a[[.one.]]b & a1b a1b +a[[.notdef.]]b &C ECOLLATE +a[[.].]]b & a]b a]b +a[[:alpha:]]c & abc abc +a[[:notdef:]]c &C ECTYPE +a[[: &C EBRACK +a[[:alpha &C EBRACK +a[[:alpha:] &C EBRACK +a[[:alpha,:] &C ECTYPE +a[[:]:]]b &C ECTYPE +a[[:-:]]b &C ECTYPE +a[[:alph:]] &C ECTYPE +a[[:alphabet:]] &C ECTYPE +[[:alnum:]]+ - -%@a0X- a0X +[[:alpha:]]+ - -%@aX0- aX +[[:blank:]]+ - aSSTb SST +[[:cntrl:]]+ - aNTb NT +[[:digit:]]+ - a019b 019 +[[:graph:]]+ - Sa%bS a%b +[[:lower:]]+ - AabC ab +[[:print:]]+ - NaSbN aSb +[[:punct:]]+ - S%-&T %-& +[[:space:]]+ - aSNTb SNT +[[:upper:]]+ - aBCd BC +[[:xdigit:]]+ - p0f3Cq 0f3C +a[[=b=]]c & abc abc +a[[= &C EBRACK +a[[=b &C EBRACK +a[[=b= &C EBRACK +a[[=b=] &C EBRACK +a[[=b,=]] &C ECOLLATE +a[[=one=]]b & a1b a1b + +# complexities +a(((b)))c - abc abc +a(b|(c))d - abd abd +a(b*|c)d - abbd abbd +# just gotta have one DFA-buster, of course +a[ab]{20} - aaaaabaaaabaaaabaaaab aaaaabaaaabaaaabaaaab +# and an inline expansion in case somebody gets tricky +a[ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab] - aaaaabaaaabaaaabaaaab aaaaabaaaabaaaabaaaab +# and in case somebody just slips in an NFA... +a[ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab](wee|week)(knights|night) - aaaaabaaaabaaaabaaaabweeknights aaaaabaaaabaaaabaaaabweeknights +# fish for anomalies as the number of states passes 32 +12345678901234567890123456789 - a12345678901234567890123456789b 12345678901234567890123456789 +123456789012345678901234567890 - a123456789012345678901234567890b 123456789012345678901234567890 +1234567890123456789012345678901 - a1234567890123456789012345678901b 1234567890123456789012345678901 +12345678901234567890123456789012 - a12345678901234567890123456789012b 12345678901234567890123456789012 +123456789012345678901234567890123 - a123456789012345678901234567890123b 123456789012345678901234567890123 +# and one really big one, beyond any plausible word width +1234567890123456789012345678901234567890123456789012345678901234567890 - a1234567890123456789012345678901234567890123456789012345678901234567890b 1234567890123456789012345678901234567890123456789012345678901234567890 +# fish for problems as brackets go past 8 +[ab][cd][ef][gh][ij][kl][mn] - xacegikmoq acegikm +[ab][cd][ef][gh][ij][kl][mn][op] - xacegikmoq acegikmo +[ab][cd][ef][gh][ij][kl][mn][op][qr] - xacegikmoqy acegikmoq +[ab][cd][ef][gh][ij][kl][mn][op][q] - xacegikmoqy acegikmoq + +# subtleties of matching +abc & xabcy abc +a\(b\)?c\1d b acd +aBc i Abc Abc +a[Bc]*d i abBCcd abBCcd +0[[:upper:]]1 &i 0a1 0a1 +0[[:lower:]]1 &i 0A1 0A1 +a[^b]c &i abc +a[^b]c &i aBc +a[^b]c &i adc adc +[a]b[c] - abc abc +[a]b[a] - aba aba +[abc]b[abc] - abc abc +[abc]b[abd] - abd abd +a(b?c)+d - accd accd +(wee|week)(knights|night) - weeknights weeknights +(we|wee|week|frob)(knights|night|day) - weeknights weeknights +a[bc]d - xyzaaabcaababdacd abd +a[ab]c - aaabc abc +abc s abc abc +a* & b @b + +# Let's have some fun -- try to match a C comment. +# first the obvious, which looks okay at first glance... +/\*.*\*/ - /*x*/ /*x*/ +# but... +/\*.*\*/ - /*x*/y/*z*/ /*x*/y/*z*/ +# okay, we must not match */ inside; try to do that... +/\*([^*]|\*[^/])*\*/ - /*x*/ /*x*/ +/\*([^*]|\*[^/])*\*/ - /*x*/y/*z*/ /*x*/ +# but... +/\*([^*]|\*[^/])*\*/ - /*x**/y/*z*/ /*x**/y/*z*/ +# and a still fancier version, which does it right (I think)... +/\*([^*]|\*+[^*/])*\*+/ - /*x*/ /*x*/ +/\*([^*]|\*+[^*/])*\*+/ - /*x*/y/*z*/ /*x*/ +/\*([^*]|\*+[^*/])*\*+/ - /*x**/y/*z*/ /*x**/ +/\*([^*]|\*+[^*/])*\*+/ - /*x****/y/*z*/ /*x****/ +/\*([^*]|\*+[^*/])*\*+/ - /*x**x*/y/*z*/ /*x**x*/ +/\*([^*]|\*+[^*/])*\*+/ - /*x***x/y/*z*/ /*x***x/y/*z*/ + +# subexpressions +a(b)(c)d - abcd abcd b,c +a(((b)))c - abc abc b,b,b +a(b|(c))d - abd abd b,- +a(b*|c|e)d - abbd abbd bb +a(b*|c|e)d - acd acd c +a(b*|c|e)d - ad ad @d +a(b?)c - abc abc b +a(b?)c - ac ac @c +a(b+)c - abc abc b +a(b+)c - abbbc abbbc bbb +a(b*)c - ac ac @c +(a|ab)(bc([de]+)f|cde) - abcdef abcdef a,bcdef,de +# the regression tester only asks for 9 subexpressions +a(b)(c)(d)(e)(f)(g)(h)(i)(j)k - abcdefghijk abcdefghijk b,c,d,e,f,g,h,i,j +a(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)l - abcdefghijkl abcdefghijkl b,c,d,e,f,g,h,i,j,k +a([bc]?)c - abc abc b +a([bc]?)c - ac ac @c +a([bc]+)c - abc abc b +a([bc]+)c - abcc abcc bc +a([bc]+)bc - abcbc abcbc bc +a(bb+|b)b - abb abb b +a(bbb+|bb+|b)b - abb abb b +a(bbb+|bb+|b)b - abbb abbb bb +a(bbb+|bb+|b)bb - abbb abbb b +(.*).* - abcdef abcdef abcdef +(a*)* - bc @b @b + +# do we get the right subexpression when it is used more than once? +a(b|c)*d - ad ad - +a(b|c)*d - abcd abcd c +a(b|c)+d - abd abd b +a(b|c)+d - abcd abcd c +a(b|c?)+d - ad ad @d +a(b|c?)+d - abcd abcd @d +a(b|c){0,0}d - ad ad - +a(b|c){0,1}d - ad ad - +a(b|c){0,1}d - abd abd b +a(b|c){0,2}d - ad ad - +a(b|c){0,2}d - abcd abcd c +a(b|c){0,}d - ad ad - +a(b|c){0,}d - abcd abcd c +a(b|c){1,1}d - abd abd b +a(b|c){1,1}d - acd acd c +a(b|c){1,2}d - abd abd b +a(b|c){1,2}d - abcd abcd c +a(b|c){1,}d - abd abd b +a(b|c){1,}d - abcd abcd c +a(b|c){2,2}d - acbd acbd b +a(b|c){2,2}d - abcd abcd c +a(b|c){2,4}d - abcd abcd c +a(b|c){2,4}d - abcbd abcbd b +a(b|c){2,4}d - abcbcd abcbcd c +a(b|c){2,}d - abcd abcd c +a(b|c){2,}d - abcbd abcbd b +a(b+|((c)*))+d - abd abd @d,@d,- +a(b+|((c)*))+d - abcd abcd @d,@d,- + +# check out the STARTEND option +[abc] &# a(b)c b +[abc] &# a(d)c +[abc] &# a(bc)d b +[abc] &# a(dc)d c +. &# a()c +b.*c &# b(bc)c bc +b.* &# b(bc)c bc +.*c &# b(bc)c bc + +# plain strings, with the NOSPEC flag +abc m abc abc +abc m xabcy abc +abc m xyz +a*b m aba*b a*b +a*b m ab +"" mC EMPTY + +# cases involving NULs +aZb & a a +aZb &p a +aZb &p# (aZb) aZb +aZ*b &p# (ab) ab +a.b &# (aZb) aZb +a.* &# (aZb)c aZb + +# word boundaries (ick) +[[:<:]]a & a a +[[:<:]]a & ba +[[:<:]]a & -a a +a[[:>:]] & a a +a[[:>:]] & ab +a[[:>:]] & a- a +[[:<:]]a.c[[:>:]] & axcd-dayc-dazce-abc abc +[[:<:]]a.c[[:>:]] & axcd-dayc-dazce-abc-q abc +[[:<:]]a.c[[:>:]] & axc-dayc-dazce-abc axc +[[:<:]]b.c[[:>:]] & a_bxc-byc_d-bzc-q bzc +[[:<:]].x..[[:>:]] & y_xa_-_xb_y-_xc_-axdc _xc_ +[[:<:]]a_b[[:>:]] & x_a_b + +# past problems, and suspected problems +(A[1])|(A[2])|(A[3])|(A[4])|(A[5])|(A[6])|(A[7])|(A[8])|(A[9])|(A[A]) - A1 A1 +abcdefghijklmnop i abcdefghijklmnop abcdefghijklmnop +abcdefghijklmnopqrstuv i abcdefghijklmnopqrstuv abcdefghijklmnopqrstuv +(ALAK)|(ALT[AB])|(CC[123]1)|(CM[123]1)|(GAMC)|(LC[23][EO ])|(SEM[1234])|(SL[ES][12])|(SLWW)|(SLF )|(SLDT)|(VWH[12])|(WH[34][EW])|(WP1[ESN]) - CC11 CC11 +CC[13]1|a{21}[23][EO][123][Es][12]a{15}aa[34][EW]aaaaaaa[X]a - CC11 CC11 +Char \([a-z0-9_]*\)\[.* b Char xyz[k Char xyz[k xyz +a?b - ab ab +-\{0,1\}[0-9]*$ b -5 -5 diff --git a/APACHE_1_2_X/src/regex/utils.h b/APACHE_1_2_X/src/regex/utils.h new file mode 100644 index 00000000000..f271f759b11 --- /dev/null +++ b/APACHE_1_2_X/src/regex/utils.h @@ -0,0 +1,22 @@ +/* utility definitions */ +#ifndef _POSIX2_RE_DUP_MAX +#define _POSIX2_RE_DUP_MAX 255 +#endif + +#define DUPMAX _POSIX2_RE_DUP_MAX /* xxx is this right? */ +#define INFINITY (DUPMAX + 1) +#define NC (CHAR_MAX - CHAR_MIN + 1) +typedef unsigned char uch; + +/* switch off assertions (if not already off) if no REDEBUG */ +#ifndef REDEBUG +#ifndef NDEBUG +#define NDEBUG /* no assertions please */ +#endif +#endif +#include + +/* for old systems with bcopy() but no memmove() */ +#ifdef USEBCOPY +#define memmove(d, s, c) bcopy(s, d, c) +#endif diff --git a/APACHE_1_2_X/src/support/.cvsignore b/APACHE_1_2_X/src/support/.cvsignore new file mode 100644 index 00000000000..48ded15b520 --- /dev/null +++ b/APACHE_1_2_X/src/support/.cvsignore @@ -0,0 +1,9 @@ +Makefile +rotatelogs +htpasswd +htdigest +unescape +inc2shtml +httpd_monitor +suexec +logresolve diff --git a/APACHE_1_2_X/src/support/Makefile.tmpl b/APACHE_1_2_X/src/support/Makefile.tmpl new file mode 100644 index 00000000000..84aebc02014 --- /dev/null +++ b/APACHE_1_2_X/src/support/Makefile.tmpl @@ -0,0 +1,35 @@ +# Apache makefile template (well, suffix). + +# This is combined with the information in the "Configuration" file +# by the configure script to make the actual Makefile. + +CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) +LIBS=$(EXTRA_LIBS) $(LIBS1) +INCLUDES=-I../src -I../src/regex $(INCLUDES1) $(EXTRA_INCLUDES) +LFLAGS=$(LFLAGS1) $(EXTRA_LFLAGS) + +.c.o: + $(CC) -c $(CFLAGS) $(INCLUDES) $< + +TARGETS=htpasswd htdigest httpd_monitor rotatelogs logresolve + +all: $(TARGETS) + +htpasswd: htpasswd.c + $(CC) $(CFLAGS) htpasswd.c -o htpasswd $(LIBS) + +htdigest: htdigest.c + $(CC) $(CFLAGS) htdigest.c -o htdigest + +httpd_monitor: httpd_monitor.c + $(CC) $(INCLUDES) $(CFLAGS) httpd_monitor.c -o httpd_monitor + +rotatelogs: rotatelogs.c + $(CC) $(INCLUDES) $(CFLAGS) rotatelogs.c -o rotatelogs + +logresolve: logresolve.c + $(CC) $(INCLUDES) $(CFLAGS) logresolve.c -o logresolve $(LIBS) + +clean: + rm -f $(TARGETS) + diff --git a/APACHE_1_2_X/src/support/cls.c b/APACHE_1_2_X/src/support/cls.c new file mode 100644 index 00000000000..2c553cec93d --- /dev/null +++ b/APACHE_1_2_X/src/support/cls.c @@ -0,0 +1,165 @@ +#include +#include +#include +#include +#include + +/* + * Compare a string to a mask + * Mask characters: + * @ - uppercase letter + * # - lowercase letter + * & - hex digit + * # - digit + * * - swallow remaining characters + * - exact match for any other character + */ +static int +checkmask(const char *data, const char *mask) +{ + int i, ch, d; + + for (i=0; mask[i] != '\0' && mask[i] != '*'; i++) + { + ch = mask[i]; + d = data[i]; + if (ch == '@') + { + if (!isupper(d)) return 0; + } else if (ch == '$') + { + if (!islower(d)) return 0; + } else if (ch == '#') + { + if (!isdigit(d)) return 0; + } else if (ch == '&') + { + if (!isxdigit(d)) return 0; + } else if (ch != d) return 0; + } + + if (mask[i] == '*') return 1; + else return (data[i] == '\0'); +} + +/* + * Converts 8 hex digits to a time integer + */ +static int +hex2sec(const char *x) +{ + int i, ch; + unsigned int j; + + for (i=0, j=0; i < 8; i++) + { + ch = x[i]; + j <<= 4; + if (isdigit(ch)) j |= ch - '0'; + else if (isupper(ch)) j |= ch - ('A' - 10); + else j |= ch - ('a' - 10); + } + if (j == 0xffffffff) return -1; /* so that it works with 8-byte ints */ + else return j; +} + +int +main(int argc, char **argv) +{ + int i, ver; + DIR *d; + struct dirent *e; + const char *s; + FILE *fp; + char path[FILENAME_MAX+1]; + char line[1035]; + time_t date, lmod, expire; + unsigned int len; + struct tm ts; + char sdate[30], slmod[30], sexpire[30]; + const char time_format[]="%e %b %Y %R"; + + if (argc != 2) + { + printf("Usage: cls directory\n"); + exit(0); + } + + d = opendir(argv[1]); + if (d == NULL) + { + perror("opendir"); + exit(1); + } + + for (;;) + { + e = readdir(d); + if (e == NULL) break; + s = e->d_name; + if (s[0] == '.' || s[0] == '#') continue; + sprintf(path, "%s/%s", argv[1], s); + fp = fopen(path, "r"); + if (fp == NULL) + { + perror("fopen"); + continue; + } + if (fgets(line, 1034, fp) == NULL) + { + perror("fgets"); + fclose(fp); + continue; + } + if (!checkmask(line, "&&&&&&&& &&&&&&&& &&&&&&&& &&&&&&&& &&&&&&&&\n")) + { + fprintf(stderr, "Bad cache file\n"); + fclose(fp); + continue; + } + date = hex2sec(line); + lmod = hex2sec(line+9); + expire = hex2sec(line+18); + ver = hex2sec(line+27); + len = hex2sec(line+35); + if (fgets(line, 1034, fp) == NULL) + { + perror("fgets"); + fclose(fp); + continue; + } + fclose(fp); + i = strlen(line); + if (strncmp(line, "X-URL: ", 7) != 0 || line[i-1] != '\n') + { + fprintf(stderr, "Bad cache file\n"); + continue; + } + line[i-1] = '\0'; + if (date != -1) + { + ts = *gmtime(&date); + strftime(sdate, 30, time_format, &ts); + } else + strcpy(sdate, "-"); + + if (lmod != -1) + { + ts = *gmtime(&lmod); + strftime(slmod, 30, time_format, &ts); + } else + strcpy(slmod, "-"); + + if (expire != -1) + { + ts = *gmtime(&expire); + strftime(sexpire, 30, time_format, &ts); + } else + strcpy(sexpire, "-"); + + printf("%s: %d; %s %s %s\n", line+7, ver, sdate, slmod, sexpire); + } + + closedir(d); + return 0; +} diff --git a/APACHE_1_2_X/src/support/dbmmanage b/APACHE_1_2_X/src/support/dbmmanage new file mode 100644 index 00000000000..8afc45f0045 --- /dev/null +++ b/APACHE_1_2_X/src/support/dbmmanage @@ -0,0 +1,126 @@ +#!/usr/local/bin/perl + +# ==================================================================== +# Copyright (c) 1995-1997 The Apache Group. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# 3. All advertising materials mentioning features or use of this +# software must display the following acknowledgment: +# "This product includes software developed by the Apache Group +# for use in the Apache HTTP server project (http://www.apache.org/)." +# +# 4. The names "Apache Server" and "Apache Group" must not be used to +# endorse or promote products derived from this software without +# prior written permission. +# +# 5. Redistributions of any form whatsoever must retain the following +# acknowledgment: +# "This product includes software developed by the Apache Group +# for use in the Apache HTTP server project (http://www.apache.org/)." +# +# THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY +# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR +# ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. +# ==================================================================== +# +# This software consists of voluntary contributions made by many +# individuals on behalf of the Apache Group and was originally based +# on public domain software written at the National Center for +# Supercomputing Applications, University of Illinois, Urbana-Champaign. +# For more information on the Apache Group and the Apache HTTP server +# project, please see . + + +# usage: dbmmanage +# +# commands: add, delete, view, adduser +# +# no values needed for delete, no keys or values needed for view. +# to change a value, simply use "add". +# adduser encrypts the password: +# dbmmanage adduser +# +# is optional, and may also be supplied to add the user +# to a specified group: +# dbmmanage adduser + +if (scalar(@ARGV) < 2) { + print "Too few arguments.\n"; + exit; +} + +$file=$ARGV[0]; +$command=$ARGV[1]; +$key=$ARGV[2]; +$value=$ARGV[3]; +$group=$ARGV[4]; + +# create a random salt +@range=('0'..'9','a'..'z','A'..'Z'); +srand($$|time); +$salt=$range[rand(int($#range)+1)] . $range[rand(int($#range)+1)]; + +if ($command eq "add") { + dbmopen(%DB, $file, 0664) || die "Error: $!\n"; + $value .= ":$group" if $group ne ""; + $DB{$key} = $value; + dbmclose(%DB); + print "Entry $key added with value $value.\n"; + exit; +} + +if ($command eq "adduser") { + $hash = crypt($value, "$salt"); + dbmopen(%DB, $file, 0664) || die "Error: $!\n"; + $hash .= ":$group" if $group ne ""; + $value .= ":$group" if $group ne ""; + $DB{$key} = $hash; + dbmclose(%DB); + print "User $key added with password $value, encrypted to $hash\n"; + exit; +} + +if ($command eq "delete") { + dbmopen(%DB, $file, 0664) || die "Error: $!\n"; + delete($DB{$key}); + dbmclose(%DB); + exit; +} + +if ($command eq "view") { + dbmopen(%DB, $file, undef) || die "Error: $!\n"; + $return_status = 1; + unless ($key) { + while (($nkey,$val) = each %DB) { + print "$nkey = $val\n"; + } + } else { + $return_status = 0 if defined $DB{$key}; + print "$key = $DB{$key}\n"; + } + dbmclose(%DB); + exit($return_status); +} + +print "Command unrecognized - must be one of: view, add, adduser, delete.\n"; + diff --git a/APACHE_1_2_X/src/support/dbmmanage.new b/APACHE_1_2_X/src/support/dbmmanage.new new file mode 100644 index 00000000000..48d9f26d7ee --- /dev/null +++ b/APACHE_1_2_X/src/support/dbmmanage.new @@ -0,0 +1,140 @@ +#!/usr/local/bin/perl + +# ==================================================================== +# Copyright (c) 1995-1997 The Apache Group. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# 3. All advertising materials mentioning features or use of this +# software must display the following acknowledgment: +# "This product includes software developed by the Apache Group +# for use in the Apache HTTP server project (http://www.apache.org/)." +# +# 4. The names "Apache Server" and "Apache Group" must not be used to +# endorse or promote products derived from this software without +# prior written permission. +# +# 5. Redistributions of any form whatsoever must retain the following +# acknowledgment: +# "This product includes software developed by the Apache Group +# for use in the Apache HTTP server project (http://www.apache.org/)." +# +# THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY +# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR +# ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. +# ==================================================================== +# +# This software consists of voluntary contributions made by many +# individuals on behalf of the Apache Group and was originally based +# on public domain software written at the National Center for +# Supercomputing Applications, University of Illinois, Urbana-Champaign. +# For more information on the Apache Group and the Apache HTTP server +# project, please see . + + +# usage: dbmmanage +# +# commands: add, delete, view, adduser +# +# no values needed for delete, no keys or values needed for view. +# to change a value, simply use "add". +# adduser encrypts the password: +# dbmmanage adduser + +if (@ARGV < 2) { + die "Too few arguments.\ + Usage: dbmmanage [ []]\ + where command is add, delete, view or adduser.\ + No value required for \"delete\", no key or value for \"view\".\ + To change a value, simply use \"add\".\ + \"adduser\" encrypts the value and uses it as the user's password\n"; +} + +($file,$command,$key,$value) = @ARGV; + +$file =~ s/\.db.?$//; # remove ".db" or ".dbX" extension if any +$file =~ s/\.pag$//; # remove ".pag" and ".dir" as well. +$file =~ s/\.dir$//; # these are all common DBM extensions. + +if ($command eq "add") { + dbmopen(%DB, $file, 0664) || die "Error: $!\n"; + $DB{$key} = $value; + dbmclose(%DB); + print "Entry $key added with value $value.\n"; +} elsif ($command eq "adduser") { + srand; # needs to be done only once. + $salt = &compute_salt(0); # change to compute_salt(1) for new crypt() + $hash = crypt($value, $salt); + dbmopen(%DB, $file, 0664) || die "Error: $!\n"; + $DB{$key} = $hash; + dbmclose(%DB); + print "User $key added with password ``$value'', encrypted to $hash\n"; +} elsif ($command eq "delete") { + dbmopen(%DB, $file, 0664) || die "Error: $!\n"; + delete($DB{$key}); + dbmclose(%DB); +} elsif ($command eq "view") { + dbmopen(%DB, $file, undef) || die "Error: $!\n"; + unless ($key) { + while (($nkey,$val) = each %DB) { + print "$nkey = $val\n"; + } + } else { + print "$key = $DB{$key}\n"; + } + dbmclose(%DB); +} else { + print "Command unrecognized - must be one of: view, add, adduser, delete.\n"; +} + +exit(0); + +# if $newstyle is 1, then use new style salt (starts with '_' and contains +# four bytes of iteration count and four bytes of salt). Otherwise, just use +# the traditional two-byte salt. +# see the man page on your system to decide if you have a newer crypt() lib. +# I believe that 4.4BSD derived systems do (at least BSD/OS 2.0 does). +# The new style crypt() allows up to 20 characters of the password to be +# significant rather than only 8. +sub compute_salt { + local($newstyle) = @_; + local($salt); + if ($newstyle) { + $salt = "_" . &randchar(1) . "a.." . &randchar(4); + } else { + $salt = &randchar(2); + } + $salt; +} + +# return $count random characters +sub randchar { + local($count) = @_; + local($str) = ""; + local($enc) = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + while ($count--) { + # 64 = length($enc) in call to rand() below + $str .= substr($enc,int(rand(64)),1); + } + $str; +} diff --git a/APACHE_1_2_X/src/support/dbmmanage.readme b/APACHE_1_2_X/src/support/dbmmanage.readme new file mode 100644 index 00000000000..8ef9e688864 --- /dev/null +++ b/APACHE_1_2_X/src/support/dbmmanage.readme @@ -0,0 +1,7 @@ + +Two versions of the dbmmanage script are included with this release. +One is the old faithful version, which should continue to work if you've +been using it; the other is a newer cut, which can be easily modified to +support the newer extended crypt routines which are present on some +systems (including 4.4BSD derivatives); this newer version is, for the +nonce, experimental... diff --git a/APACHE_1_2_X/src/support/htdigest.c b/APACHE_1_2_X/src/support/htdigest.c new file mode 100644 index 00000000000..9d35b44a948 --- /dev/null +++ b/APACHE_1_2_X/src/support/htdigest.c @@ -0,0 +1,187 @@ +/* + * htdigest.c: simple program for manipulating digest passwd file for Apache + * + * by Alexei Kosut, based on htpasswd.c, by Rob McCool + */ + +#include +#include +#include +#ifdef MPE +#include +#else +#include +#endif +#include +#include +#include + +/* This is probably the easiest way to do it */ +#include "../src/md5c.c" + +#define LF 10 +#define CR 13 + +#define MAX_STRING_LEN 256 + +char *tn; + +char *strd(char *s) { + char *d; + + d=(char *)malloc(strlen(s) + 1); + strcpy(d,s); + return(d); +} + +void getword(char *word, char *line, char stop) { + int x = 0,y; + + for(x=0;((line[x]) && (line[x] != stop));x++) + word[x] = line[x]; + + word[x] = '\0'; + if(line[x]) ++x; + y=0; + + while((line[y++] = line[x++])); +} + +int getline(char *s, int n, FILE *f) { + register int i=0; + + while(1) { + s[i] = (char)fgetc(f); + + if(s[i] == CR) + s[i] = fgetc(f); + + if((s[i] == 0x4) || (s[i] == LF) || (i == (n-1))) { + s[i] = '\0'; + return (feof(f) ? 1 : 0); + } + ++i; + } +} + +void putline(FILE *f,char *l) { + int x; + + for(x=0;l[x];x++) fputc(l[x],f); + fputc('\n',f); +} + + +void add_password(char *user, char *realm, FILE *f) { + char *pw; + MD5_CTX context; + unsigned char digest[16]; + char string[MAX_STRING_LEN]; + unsigned int i; + + pw = strd((char *) getpass("New password:")); + if(strcmp(pw,(char *) getpass("Re-type new password:"))) { + fprintf(stderr,"They don't match, sorry.\n"); + if(tn) + unlink(tn); + exit(1); + } + fprintf(f,"%s:%s:",user,realm); + + /* Do MD5 stuff */ + sprintf(string, "%s:%s:%s", user, realm, pw); + + MD5Init (&context); + MD5Update (&context, (unsigned char *) string, strlen(string)); + MD5Final (digest, &context); + + for (i = 0; i < 16; i++) + fprintf(f, "%02x", digest[i]); + + fprintf(f, "\n"); +} + +void usage() { + fprintf(stderr,"Usage: htdigest [-c] passwordfile realm username\n"); + fprintf(stderr,"The -c flag creates a new file.\n"); + exit(1); +} + +void interrupted() { + fprintf(stderr,"Interrupted.\n"); + if(tn) unlink(tn); + exit(1); +} + +void main(int argc, char *argv[]) { + FILE *tfp,*f; + char user[MAX_STRING_LEN]; + char realm[MAX_STRING_LEN]; + char line[MAX_STRING_LEN]; + char l[MAX_STRING_LEN]; + char w[MAX_STRING_LEN]; + char x[MAX_STRING_LEN]; + char command[MAX_STRING_LEN]; + int found; + + tn = NULL; + signal(SIGINT,(void (*)())interrupted); + if(argc == 5) { + if(strcmp(argv[1],"-c")) + usage(); + if(!(tfp = fopen(argv[2],"w"))) { + fprintf(stderr,"Could not open passwd file %s for writing.\n", + argv[2]); + perror("fopen"); + exit(1); + } + printf("Adding password for %s in realm %s.\n",argv[4], argv[3]); + add_password(argv[4],argv[3],tfp); + fclose(tfp); + exit(0); + } else if(argc != 4) usage(); + + tn = tmpnam(NULL); + if(!(tfp = fopen(tn,"w"))) { + fprintf(stderr,"Could not open temp file.\n"); + exit(1); + } + + if(!(f = fopen(argv[1],"r"))) { + fprintf(stderr, + "Could not open passwd file %s for reading.\n",argv[1]); + fprintf(stderr,"Use -c option to create new one.\n"); + exit(1); + } + strcpy(user,argv[3]); + strcpy(realm,argv[2]); + + found = 0; + while(!(getline(line,MAX_STRING_LEN,f))) { + if(found || (line[0] == '#') || (!line[0])) { + putline(tfp,line); + continue; + } + strcpy(l,line); + getword(w,l,':'); + getword(x,l,':'); + if(strcmp(user,w) || strcmp(realm,x)) { + putline(tfp,line); + continue; + } + else { + printf("Changing password for user %s in realm %s\n",user,realm); + add_password(user,realm,tfp); + found = 1; + } + } + if(!found) { + printf("Adding user %s in realm %s\n",user,realm); + add_password(user,realm,tfp); + } + fclose(f); + fclose(tfp); + sprintf(command,"cp %s %s",tn,argv[1]); + system(command); + unlink(tn); +} diff --git a/APACHE_1_2_X/src/support/htpasswd.1 b/APACHE_1_2_X/src/support/htpasswd.1 new file mode 100644 index 00000000000..a3819ca17c2 --- /dev/null +++ b/APACHE_1_2_X/src/support/htpasswd.1 @@ -0,0 +1,88 @@ +.TH htpasswd 1 "February 1997" +.\" Copyright (c) 1997 The Apache Group. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" 3. All advertising materials mentioning features or use of this +.\" software must display the following acknowledgment: +.\" "This product includes software developed by the Apache Group +.\" for use in the Apache HTTP server project (http://www.apache.org/)." +.\" +.\" 4. The names "Apache Server" and "Apache Group" must not be used to +.\" endorse or promote products derived from this software without +.\" prior written permission. +.\" +.\" 5. Redistributions of any form whatsoever must retain the following +.\" acknowledgment: +.\" "This product includes software developed by the Apache Group +.\" for use in the Apache HTTP server project (http://www.apache.org/)." +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY +.\" EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR +.\" ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +.\" OF THE POSSIBILITY OF SUCH DAMAGE. +.\" ==================================================================== +.\" +.\" This software consists of voluntary contributions made by many +.\" individuals on behalf of the Apache Group and was originally based +.\" on public domain software written at the National Center for +.\" Supercomputing Applications, University of Illinois, Urbana-Champaign. +.\" For more information on the Apache Group and the Apache HTTP server +.\" project, please see . +.SH NAME +htpasswd \- Create and update user authentication files +.SH SYNOPSIS +.B htpasswd +[ +.B \-c +] +.I passwdfile +.I username +.SH DESCRIPTION +.B htpasswd +is used to create and update the flat-files used to store +usernames and password for basic authentication of HTTP users. +Resources available from the +.B httpd +Apache web server can be restricted to just the users listed +in the files created by htpasswd. This program can only be used +when the usernames are stored in a flat-file. To use a +DBM database see +\fBdbmmanage\fP and \fBdbmmanage.new\fP. +.PP +This manual page only lists the command line arguments. For details of +the directives necessary to configure user authentication in httpd see +the Apache manual, which is part of the Apache distribution or can be +found at http://www.apache.org/. +.SH OPTIONS +.IP \-c +Create the \fIpasswdfile\fP. If \fIpasswdfile\fP already exists, it +is deleted first. +.IP \fB\fIpasswdfile\fP +Name of the file to contain the user name and password. If \-c +is given, this file is created if it does not already exist, +or deleted and recreated if it does exist. +.IP \fB\fIusername\fP +The username to create or update in \fBpasswdfile\fP. If +\fIusername\fP does not exist is this file, an entry is added. If it +does exist, the password is changed. +.SH SEE ALSO +httpd(8) diff --git a/APACHE_1_2_X/src/support/htpasswd.c b/APACHE_1_2_X/src/support/htpasswd.c new file mode 100644 index 00000000000..17efe5b004a --- /dev/null +++ b/APACHE_1_2_X/src/support/htpasswd.c @@ -0,0 +1,198 @@ +/* + * htpasswd.c: simple program for manipulating password file for NCSA httpd + * + * Rob McCool + */ + +#include +#include +#include +#ifdef MPE +#include +#else +#include +#endif +#include +#include +#include + +#define LF 10 +#define CR 13 + +#define MAX_STRING_LEN 256 + +char *tn; + +char *strd(char *s) { + char *d; + + d=(char *)malloc(strlen(s) + 1); + strcpy(d,s); + return(d); +} + +void getword(char *word, char *line, char stop) { + int x = 0,y; + + for(x=0;((line[x]) && (line[x] != stop));x++) + word[x] = line[x]; + + word[x] = '\0'; + if(line[x]) ++x; + y=0; + + while((line[y++] = line[x++])); +} + +int getline(char *s, int n, FILE *f) { + register int i=0; + + while(1) { + s[i] = (char)fgetc(f); + + if(s[i] == CR) + s[i] = fgetc(f); + + if((s[i] == 0x4) || (s[i] == LF) || (i == (n-1))) { + s[i] = '\0'; + return (feof(f) ? 1 : 0); + } + ++i; + } +} + +void putline(FILE *f,char *l) { + int x; + + for(x=0;l[x];x++) fputc(l[x],f); + fputc('\n',f); +} + + +/* From local_passwd.c (C) Regents of Univ. of California blah blah */ +static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +void to64(register char *s, register long v, register int n) { + while (--n >= 0) { + *s++ = itoa64[v&0x3f]; + v >>= 6; + } +} + +#ifdef MPE +/* MPE lacks getpass() and a way to suppress stdin echo. So for now, just +issue the prompt and read the results with echo. (Ugh). */ + +char *getpass(const char *prompt) { + +static char password[81]; + +fputs(prompt,stderr); +gets((char *)&password); + +if (strlen((char *)&password) > 8) { + password[8]='\0'; +} + +return (char *)&password; +} +#endif + +void add_password(char *user, FILE *f) { + char *pw, *cpw, salt[3]; + + pw = strd((char *) getpass("New password:")); + if(strcmp(pw,(char *) getpass("Re-type new password:"))) { + fprintf(stderr,"They don't match, sorry.\n"); + if(tn) + unlink(tn); + exit(1); + } + (void)srand((int)time((time_t *)NULL)); + to64(&salt[0],rand(),2); + cpw = crypt(pw,salt); + free(pw); + fprintf(f,"%s:%s\n",user,cpw); +} + +void usage() { + fprintf(stderr,"Usage: htpasswd [-c] passwordfile username\n"); + fprintf(stderr,"The -c flag creates a new file.\n"); + exit(1); +} + +void interrupted() { + fprintf(stderr,"Interrupted.\n"); + if(tn) unlink(tn); + exit(1); +} + +void main(int argc, char *argv[]) { + FILE *tfp,*f; + char user[MAX_STRING_LEN]; + char line[MAX_STRING_LEN]; + char l[MAX_STRING_LEN]; + char w[MAX_STRING_LEN]; + char command[MAX_STRING_LEN]; + int found; + + tn = NULL; + signal(SIGINT,(void (*)())interrupted); + if(argc == 4) { + if(strcmp(argv[1],"-c")) + usage(); + if(!(tfp = fopen(argv[2],"w"))) { + fprintf(stderr,"Could not open passwd file %s for writing.\n", + argv[2]); + perror("fopen"); + exit(1); + } + printf("Adding password for %s.\n",argv[3]); + add_password(argv[3],tfp); + fclose(tfp); + exit(0); + } else if(argc != 3) usage(); + + tn = tmpnam(NULL); + if(!(tfp = fopen(tn,"w"))) { + fprintf(stderr,"Could not open temp file.\n"); + exit(1); + } + + if(!(f = fopen(argv[1],"r"))) { + fprintf(stderr, + "Could not open passwd file %s for reading.\n",argv[1]); + fprintf(stderr,"Use -c option to create new one.\n"); + exit(1); + } + strcpy(user,argv[2]); + + found = 0; + while(!(getline(line,MAX_STRING_LEN,f))) { + if(found || (line[0] == '#') || (!line[0])) { + putline(tfp,line); + continue; + } + strcpy(l,line); + getword(w,l,':'); + if(strcmp(user,w)) { + putline(tfp,line); + continue; + } + else { + printf("Changing password for user %s\n",user); + add_password(user,tfp); + found = 1; + } + } + if(!found) { + printf("Adding user %s\n",user); + add_password(user,tfp); + } + fclose(f); + fclose(tfp); + sprintf(command,"cp %s %s",tn,argv[1]); + system(command); + unlink(tn); +} diff --git a/APACHE_1_2_X/src/support/httpd.8 b/APACHE_1_2_X/src/support/httpd.8 new file mode 100644 index 00000000000..d456e38b101 --- /dev/null +++ b/APACHE_1_2_X/src/support/httpd.8 @@ -0,0 +1,125 @@ +.TH httpd 8 "February 1997" +.\" Copyright (c) 1995-1997 David Robinson. All rights reserved. +.\" Copyright (c) 1997 The Apache Group. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" 3. All advertising materials mentioning features or use of this +.\" software must display the following acknowledgment: +.\" "This product includes software developed by the Apache Group +.\" for use in the Apache HTTP server project (http://www.apache.org/)." +.\" +.\" 4. The names "Apache Server" and "Apache Group" must not be used to +.\" endorse or promote products derived from this software without +.\" prior written permission. +.\" +.\" 5. Redistributions of any form whatsoever must retain the following +.\" acknowledgment: +.\" "This product includes software developed by the Apache Group +.\" for use in the Apache HTTP server project (http://www.apache.org/)." +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY +.\" EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR +.\" ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +.\" OF THE POSSIBILITY OF SUCH DAMAGE. +.\" ==================================================================== +.\" +.\" This software consists of voluntary contributions made by many +.\" individuals on behalf of the Apache Group and was originally based +.\" on public domain software written at the National Center for +.\" Supercomputing Applications, University of Illinois, Urbana-Champaign. +.\" For more information on the Apache Group and the Apache HTTP server +.\" project, please see . +.SH NAME +httpd \- Apache hypertext transfer protocol server +.SH SYNOPSIS +.B httpd +[ +.B \-hlvX? +] [ +.BI \-d " serverroot" +] [ +.BI \-f " config" +] +.SH DESCRIPTION +.B httpd +is the Apache HyperText Transfer Protocol (HTTP) server program. It is +designed to be run as a standalone daemon process. When used like this +is will create a pool of child processes to handle requests. To stop +it, send a TERM signal to the initial (parent) process. The PID of +this process is written to a file as given in the configuration file. +Alternatively +.B httpd +may be invoked by the Internet daemon inetd(8) each +time a connection to the HTTP service is made. +.PP +This manual page only lists the command line arguments. For details +of the directives necessary to configure httpd see the Apache manual, +which is part of the Apache distribution or can be found at +http://www.apache.org/. Paths in this manual may not reflect those +compiled into httpd. +.SH OPTIONS +.TP 12 +.BI \-d " serverroot" +Set the initial value for the ServerRoot directive to \fIserverroot\fP. This +can be overridden by the ServerRoot command in the configuration file. The +default is \fB/usr/local/etc/httpd\fP. +.TP +.BI \-f " config" +Execute the commands in the file \fIconfig\fP on startup. If \fIconfig\fP +does not begin with a /, then it is taken to be a path relative to +the ServerRoot. The default is \fBconf/httpd.conf\fP. +.TP +.B \-h +Output a list of directives together with expected arguments and +places where the directive is valid. +.TP +.B \-l +Output a list of modules compiled into the server. +.TP +.B \-X +Run in single-process mode, for internal debugging purposes only; the daemon +does not detach from the terminal or fork any children. Do NOT use this mode +to provide ordinary web service. +.TP +.B \-v +Print the version of httpd, and then exit. +.TP +.B \-? +Print a list of the httpd options, and then exit. +.SH FILES +.PD 0 +.B /usr/local/etc/httpd/conf/httpd.conf +.br +.B /usr/local/etc/httpd/conf/srm.conf +.br +.B /usr/local/etc/httpd/conf/access.conf +.br +.B /usr/local/etc/httpd/conf/mime.types +.br +.B /usr/local/etc/httpd/logs/error_log +.br +.B /usr/local/etc/httpd/logs/access_log +.br +.B /usr/local/etc/httpd/logs/httpd.pid +.PD +.SH SEE ALSO +.BR inetd (8). diff --git a/APACHE_1_2_X/src/support/httpd_monitor.c b/APACHE_1_2_X/src/support/httpd_monitor.c new file mode 100644 index 00000000000..847a03a77cb --- /dev/null +++ b/APACHE_1_2_X/src/support/httpd_monitor.c @@ -0,0 +1,307 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + + + * simple script to monitor the child Apache processes + * Usage: + * httpd_monitor [ -d serverdir | -f conffile ] [ -s sleep_time ] + * -d/-f options specify server dir or config files, as per + * httpd. + * -s specifies how long to pause between screen updates + * If you choose 0, it might chew up lots of CPU time. + * + * Output explanation.. + * + * s = sleeping but "ready to go" child (this is '_' in mod_status) + * R = active child - writing to client + * W = active child - reading from client + * K = active child - waiting for additional request on kept-alive connection + * D = active child - doing DNS lookup + * L = active child - logging + * _ = dead child (no longer needed) (this is '.' in mod_status) + * t = just starting (this is 'S' in mod_status) + * + * + * Jim Jagielski + * v1.0 Notes: + * This code is much more ugly and complicated than it + * needs to be. + * + * v1.1: + * Minor fixes + * + * v1.2: + * Handles Apache 1.1.* scoreboard format (W/K/D/L states) -- PCS 09Jul96 + */ + +#include +#include +#include +#include +#include "../src/httpd.h" +#include "../src/scoreboard.h" + +#define DEFAULT_SLEEPTIME 2 +#define ASIZE 1024 +#define MAX_PROC HARD_SERVER_LIMIT + +int +main(argc, argv) +int argc; +char **argv; +{ + short_score scoreboard_image; + FILE *afile; + char conf_name[ASIZE]; + char pid_name[ASIZE]; + char score_name[ASIZE]; + char tbuf[ASIZE]; + char *ptmp; + static char kid_stat[] = { '_', 's', 'R', 't', 'W', 'K', 'L', 'D' }; + int achar; + long thepid; + int score_fd; + int sleep_time = DEFAULT_SLEEPTIME; + int last_len = 0; + int kiddies; + int running, dead, total, loop; + short got_config = 0; + struct stat statbuf; + time_t last_time = 0; + extern char *optarg; + extern int optind, opterr; + void lookfor(); + + int usage(); + + /* + * Handle the options. Using getopt() is most probably overkill, + * but let's think about the future! + */ + strcpy(conf_name, HTTPD_ROOT); + while((achar = getopt(argc,argv,"s:d:f:")) != -1) { + switch(achar) { + case 'd': + strcpy(conf_name, optarg); + break; + case 'f': + strcpy(conf_name, optarg); + got_config = 1; + break; + case 's': + sleep_time = atoi(optarg); + break; + case '?': + usage(argv[0]); + } + } + + /* + * Now build the name of the httpd.conf file + */ + if (!got_config) { + strcat(conf_name, "/"); + strcat(conf_name, SERVER_CONFIG_FILE); + } + + /* + * Make sure we have the right file... Barf if not + */ + if (!(afile = fopen(conf_name, "r"))) { + perror("httpd_monitor"); + fprintf(stderr, "Can't open config file: %s\n", conf_name); + exit(1); + } + /* + * now scan thru the ConfigFile to look for the items that + * interest us + */ + lookfor(pid_name, score_name, afile); + fclose(afile); + + /* + * now open the PidFile and then the ScoreBoardFile + */ + if (!(afile = fopen(pid_name, "r"))) { + perror("httpd_monitor"); + fprintf(stderr, "Can't open PIDfile: %s\n", pid_name); + exit(1); + } + fscanf(afile, "%ld", &thepid); + fclose(afile); + + /* + * Enough taters, time for the MEAT! + */ + for(;;sleep(sleep_time)) { + if (stat(score_name, &statbuf)) { + perror("httpd_monitor"); + fprintf(stderr, "Can't stat scoreboard file: %s\n", score_name); + exit(1); + } + if (last_time == statbuf.st_mtime) + continue; /* tricky ;) */ + last_time = statbuf.st_mtime; /* for next time */ + if ((score_fd = open(score_name, 0)) == -1 ) { + perror("httpd_monitor"); + fprintf(stderr, "Can't open scoreboard file: %s\n", score_name); + exit(1); + } + /* + * all that for _this_ + */ + running = dead = total = 0; + ptmp = tbuf; + *ptmp = '\0'; + for(kiddies=0;kiddies strlen(tbuf)) { + for(loop=1;loop<=last_len;loop++) + putchar(' '); + for(loop=1;loop<=last_len;loop++) + putchar('\010'); + } + printf("%s", tbuf); + fflush(stdout); + last_len = strlen(tbuf); + } /* for */ +} + +int +usage(arg) +char *arg; +{ + printf("httpd_monitor: Usage\n"); + printf(" httpd_monitor [ -d config-dir] [ -s sleep-time ]\n"); + printf(" Defaults: config-dir = %s\n", HTTPD_ROOT); + printf(" sleep-time = %d seconds\n", DEFAULT_SLEEPTIME); + exit(0); +} + +/* + * This function uses some hard-wired knowledge about the + * Apache httpd.conf file setup (basically names of the 3 + * parameters we are interested in) + * + * We basically scan thru the file and grab the 3 values we + * need. This could be done better... + */ +void +lookfor(pidname, scorename, thefile) +char *pidname, *scorename; +FILE *thefile; +{ + char line[ASIZE], param[ASIZE], value[ASIZE]; + char sroot[ASIZE], pidfile[ASIZE], scorefile[ASIZE]; + + *sroot = *pidfile = *scorefile = '\0'; + while (!(feof(thefile))) { + fgets(line, ASIZE-1, thefile); + *value = '\0'; /* protect braindead sscanf() */ + sscanf(line, "%s %s", param, value); + if (strcmp(param, "PidFile")==0 && *value) + strcpy(pidfile, value); + if (strcmp(param, "ScoreBoardFile")==0 && *value) + strcpy(scorefile, value); + if (strcmp(param, "ServerRoot")==0 && *value) + strcpy(sroot, value); + } + + /* + * We've reached EOF... we should have encountered the + * ServerRoot line... if not, we bail out + */ + if (!*sroot) { + fprintf(stderr, "Can't find ServerRoot!\n"); + exit(1); + } + + /* + * Not finding PidFile or ScoreBoardFile is OK, since + * we have defaults for them + */ + if (!*pidfile) + strcpy(pidfile, DEFAULT_PIDLOG); + if (!*scorefile) + strcpy(scorefile, DEFAULT_SCOREBOARD); + + /* + * Relative or absolute? Handle both + */ + if (*pidfile == '/') + strcpy(pidname, pidfile); + else { + strcpy(pidname, sroot); + strcat(pidname, "/"); + strcat(pidname, pidfile); + } + if (*scorefile == '/') + strcpy(scorename, scorefile); + else { + strcpy(scorename, sroot); + strcat(scorename, "/"); + strcat(scorename, scorefile); + } +} + diff --git a/APACHE_1_2_X/src/support/log_server_status b/APACHE_1_2_X/src/support/log_server_status new file mode 100755 index 00000000000..4f972591cff --- /dev/null +++ b/APACHE_1_2_X/src/support/log_server_status @@ -0,0 +1,110 @@ +#!/usr/local/bin/perl + +# ==================================================================== +# Copyright (c) 1995-1997 The Apache Group. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# 3. All advertising materials mentioning features or use of this +# software must display the following acknowledgment: +# "This product includes software developed by the Apache Group +# for use in the Apache HTTP server project (http://www.apache.org/)." +# +# 4. The names "Apache Server" and "Apache Group" must not be used to +# endorse or promote products derived from this software without +# prior written permission. +# +# 5. Redistributions of any form whatsoever must retain the following +# acknowledgment: +# "This product includes software developed by the Apache Group +# for use in the Apache HTTP server project (http://www.apache.org/)." +# +# THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY +# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR +# ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. +# ==================================================================== +# +# This software consists of voluntary contributions made by many +# individuals on behalf of the Apache Group and was originally based +# on public domain software written at the National Center for +# Supercomputing Applications, University of Illinois, Urbana-Champaign. +# For more information on the Apache Group and the Apache HTTP server +# project, please see . + + +# Log Server Status +# Mark J Cox, UK Web Ltd 1996, mark@ukweb.com +# +# This script is designed to be run at a frequent interval by something +# like cron. It connects to the server and downloads the status +# information. It reformats the information to a single line and logs +# it to a file. Make sure the directory $wherelog is writable by the +# user who runs this script. +# +require 'sys/socket.ph'; + +$wherelog = "/var/log/graph/"; # Logs will be like "/var/log/graph/960312" +$server = "localhost"; # Name of server, could be "www.foo.com" +$port = "80"; # Port on server +$request = "/status/?auto"; # Request to send + +sub tcp_connect +{ + local($host,$port) =@_; + $sockaddr='S n a4 x8'; + chop($hostname=`hostname`); + $port=(getservbyname($port, 'tcp'))[2] unless $port =~ /^\d+$/; + $me=pack($sockaddr,&AF_INET,0,(gethostbyname($hostname))[4]); + $them=pack($sockaddr,&AF_INET,$port,(gethostbyname($host))[4]); + socket(S,&PF_INET,&SOCK_STREAM,(getprotobyname('tcp'))[2]) || + die "socket: $!"; + bind(S,$me) || return "bind: $!"; + connect(S,$them) || return "connect: $!"; + select(S); + $| = 1; + select(stdout); + return ""; +} + +### Main + +{ + $date=`date +%y%m%d:%H%M%S`; + chop($date); + ($day,$time)=split(/:/,$date); + $res=&tcp_connect($server,$port); + open(OUT,">>$wherelog$day"); + if ($res) { + print OUT "$time:-1:-1:-1:-1:$res\n"; + exit 1; + } + print S "GET $request\n"; + while () { + $requests=$1 if ( m|^BusyServers:\ (\S+)|); + $idle=$1 if ( m|^IdleServers:\ (\S+)|); + $number=$1 if ( m|sses:\ (\S+)|); + $cpu=$1 if (m|^CPULoad:\ (\S+)|); + } + print OUT "$time:$requests:$idle:$number:$cpu\n"; +} + + diff --git a/APACHE_1_2_X/src/support/logresolve.c b/APACHE_1_2_X/src/support/logresolve.c new file mode 100644 index 00000000000..c09cba9760d --- /dev/null +++ b/APACHE_1_2_X/src/support/logresolve.c @@ -0,0 +1,367 @@ +/*** ***\ + logresolve 1.1 + + Tom Rathborne - tomr@uunet.ca - http://www.uunet.ca/~tomr/ + UUNET Canada, April 16, 1995 + + Rewritten by David Robinson. (drtr@ast.cam.ac.uk) + + Usage: logresolve [-s filename] [-c] < access_log > new_log + + Arguments: + -s filename name of a file to record statistics + -c check the DNS for a matching A record for the host. + + Notes: + + To generate meaningful statistics from an HTTPD log file, it's good + to have the domain name of each machine that accessed your site, but + doing this on the fly can slow HTTPD down. + + Compiling NCSA HTTPD with the -DMINIMAL_DNS flag turns IP#->hostname + resolution off. Before running your stats program, just run your log + file through this program (logresolve) and all of your IP numbers will + be resolved into hostnames (where possible). + + logresolve takes an HTTPD access log (in the COMMON log file format, + or any other format that has the IP number/domain name as the first + field for that matter), and outputs the same file with all of the + domain names looked up. Where no domain name can be found, the IP + number is left in. + + To minimize impact on your nameserver, logresolve has its very own + internal hash-table cache. This means that each IP number will only + be looked up the first time it is found in the log file. + + The -c option causes logresolve to apply the same check as httpd + compiled with -DMAXIMUM_DNS; after finding the hostname from the IP + address, it looks up the IP addresses for the hostname and checks + that one of these matches the original address. + +\*** ***/ + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#ifndef MPE +#include +#endif + +static void cgethost(struct in_addr ipnum, char *string, int check); +static int getline(char *s, int n); +static void stats(FILE *output); + + +/* maximum line length */ +#define MAXLINE 1024 + +/* maximum length of a domain name */ +#ifndef MAXDNAME +#define MAXDNAME 256 +#endif + +/* number of buckets in cache hash table */ +#define BUCKETS 256 + +#ifdef MPE +char *strdup (const char *str) +{ + char *dup; + + if(!(dup = (char *)malloc (strlen (str) + 1))) + return NULL; + dup = strcpy (dup, str); + + return dup; +} +#endif + +/* + * struct nsrec - record of nameservice for cache linked list + * + * ipnum - IP number hostname - hostname noname - nonzero if IP number has no + * hostname, i.e. hostname=IP number + */ + +struct nsrec { + struct in_addr ipnum; + char *hostname; + int noname; + struct nsrec *next; +} *nscache[BUCKETS]; + +/* + * statistics - obvious + */ + +/* largeste value for h_errno */ +#define MAX_ERR (NO_ADDRESS) +#define UNKNOWN_ERR (MAX_ERR+1) +#define NO_REVERSE (MAX_ERR+2) + +static int cachehits = 0; +static int cachesize = 0; +static int entries = 0; +static int resolves = 0; +static int withname = 0; +static int errors[MAX_ERR+3]; + +/* + * cgethost - gets hostname by IP address, caching, and adding unresolvable + * IP numbers with their IP number as hostname, setting noname flag + */ + +static void +cgethost(ipnum, string, check) +struct in_addr ipnum; +char *string; +int check; +{ + struct nsrec **current, *new; + struct hostent *hostdata; + char *name; + extern int h_errno; /* some machines don't have this in their headers */ + + current = &nscache[((ipnum.s_addr + (ipnum.s_addr >> 8) + + (ipnum.s_addr >> 16) + (ipnum.s_addr >> 24)) % BUCKETS)]; + + while (*current != NULL && ipnum.s_addr != (*current)->ipnum.s_addr) + current = & (*current)->next; + + if (*current == NULL) + { + cachesize++; + new = (struct nsrec *) malloc(sizeof(struct nsrec)); + if (new == NULL) + { + perror("malloc"); + fprintf(stderr, "Insufficient memory\n"); + exit(1); + } + *current = new; + new->next = NULL; + + new->ipnum = ipnum; + + hostdata = gethostbyaddr((const char *) &ipnum, sizeof(struct in_addr), + AF_INET); + if (hostdata == NULL) + { + if (h_errno > MAX_ERR) errors[UNKNOWN_ERR]++; + else errors[h_errno]++; + new->noname = h_errno; + name = strdup(inet_ntoa(ipnum)); + } else + { + new->noname = 0; + name = strdup(hostdata->h_name); + if (check) + { + if (name == NULL) + { + perror("strdup"); + fprintf(stderr, "Insufficient memory\n"); + exit(1); + } + hostdata = gethostbyname(name); + if (hostdata != NULL) + { + char **hptr; + + for (hptr=hostdata->h_addr_list; *hptr != NULL; hptr++) + if(((struct in_addr *)(*hptr))->s_addr == ipnum.s_addr) + break; + if (*hptr == NULL) hostdata = NULL; + } + if (hostdata == NULL) + { + fprintf(stderr, "Bad host: %s != %s\n", name, + inet_ntoa(ipnum)); + new->noname = NO_REVERSE; + free(name); + name = strdup(inet_ntoa(ipnum)); + errors[NO_REVERSE]++; + } + } + } + new->hostname = name; + if (new->hostname == NULL) + { + perror("strdup"); + fprintf(stderr, "Insufficient memory\n"); + exit(1); + } + } else + cachehits++; + + strcpy(string, (*current)->hostname); +} + +/* + * prints various statistics to output + */ + +static void +stats(output) +FILE *output; +{ + int i; + char *ipstring; + struct nsrec *current; + char *errstring[MAX_ERR+3]; + + for (i=0; i < MAX_ERR+3; i++) errstring[i] = "Unknown error"; + errstring[HOST_NOT_FOUND] = "Host not found"; + errstring[TRY_AGAIN] = "Try again"; + errstring[NO_RECOVERY] = "Non recoverable error"; + errstring[NO_DATA] = "No data record"; + errstring[NO_ADDRESS] = "No address"; + errstring[NO_REVERSE] = "No reverse entry"; + + fprintf(output, "logresolve Statistics:\n"); + + fprintf(output, "Entries: %d\n", entries); + fprintf(output, " With name : %d\n", withname); + fprintf(output, " Resolves : %d\n", resolves); + if (errors[HOST_NOT_FOUND]) + fprintf(output, " - Not found : %d\n", errors[HOST_NOT_FOUND]); + if (errors[TRY_AGAIN]) + fprintf(output, " - Try again : %d\n", errors[TRY_AGAIN]); + if (errors[NO_DATA]) + fprintf(output, " - No data : %d\n", errors[NO_DATA]); + if (errors[NO_ADDRESS]) + fprintf(output, " - No address: %d\n", errors[NO_ADDRESS]); + if (errors[NO_REVERSE]) + fprintf(output, " - No reverse: %d\n", errors[NO_REVERSE]); + fprintf(output, "Cache hits : %d\n", cachehits); + fprintf(output, "Cache size : %d\n", cachesize); + fprintf(output, "Cache buckets : IP number * hostname\n"); + + for (i = 0; i < BUCKETS; i++) + for (current = nscache[i]; current != NULL; current = current->next) + { + ipstring = inet_ntoa(current->ipnum); + if (current->noname == 0) + fprintf(output, " %3d %15s - %s\n", i, ipstring, + current->hostname); + else + { + if (current->noname > MAX_ERR+2) + fprintf(output, " %3d %15s : Unknown error\n", i, + ipstring); + else + fprintf(output, " %3d %15s : %s\n", i, ipstring, + errstring[current->noname]); + } + } +} + + +/* + * gets a line from stdin + */ + +static int +getline(s, n) +char *s; +int n; +{ + char *cp; + + if (!fgets(s, n, stdin)) + return (0); + cp = strchr(s, '\n'); + if (cp) + *cp = '\0'; + return (1); +} + +int +main(argc, argv) +int argc; +char *argv[]; +{ + struct in_addr ipnum; + char *bar, hoststring[MAXDNAME+1], line[MAXLINE], *statfile; + int i, check; + + check = 0; + statfile = NULL; + for (i=1; i < argc; i++) + { + if (strcmp(argv[i], "-c") == 0) check = 1; + else if (strcmp(argv[i], "-s") == 0) + { + if (i == argc-1) + { + fprintf(stderr, "logresolve: missing filename to -s\n"); + exit(1); + } + i++; + statfile = argv[i]; + } + else + { + fprintf(stderr, "Usage: logresolve [-s statfile] [-c] < input > output"); + exit(0); + } + } + + + for (i = 0; i < BUCKETS; i++) nscache[i] = NULL; + for (i=0; i < MAX_ERR+2; i++) errors[i] = 0; + + while (getline(line, MAXLINE)) + { + if (line[0] == '\0') continue; + entries++; + if (!isdigit(line[0])) + { /* short cut */ + puts(line); + withname++; + continue; + } + bar = strchr(line, ' '); + if (bar != NULL) *bar = '\0'; + ipnum.s_addr = inet_addr(line); + if (ipnum.s_addr == 0xffffffffu) + { + if (bar != NULL) *bar = ' '; + puts(line); + withname++; + continue; + } + + resolves++; + + cgethost(ipnum, hoststring, check); + if (bar != NULL) + printf("%s %s\n", hoststring, bar+1); + else + puts(hoststring); + } + + if (statfile != NULL) + { + FILE *fp; + fp = fopen(statfile, "w"); + if (fp == NULL) + { + fprintf(stderr, "logresolve: could not open statistics file '%s'\n" + , statfile); + exit(1); + } + stats(fp); + fclose(fp); + } + + return (0); +} diff --git a/APACHE_1_2_X/src/support/phf_abuse_log.cgi b/APACHE_1_2_X/src/support/phf_abuse_log.cgi new file mode 100755 index 00000000000..9ce2749c571 --- /dev/null +++ b/APACHE_1_2_X/src/support/phf_abuse_log.cgi @@ -0,0 +1,21 @@ +#!/usr/local/bin/perl + +# This script can be used to detect people trying to abuse the security hole which +# existed in A CGI script direstributed with Apache 1.0.3 and earlier versions. +# You can redirect them to here using the "" suggestion in +# httpd.conf. +# +# The format logged to is "[date] remote_addr remote_host [date] referrer user_agent". + +$LOG = "/var/log/phf_log"; + +require "ctime.pl"; +$when = &ctime(time); +$when =~ s/\n//go; +$ENV{HTTP_USER_AGENT} .= " via $ENV{HTTP_VIA}" if($ENV{HTTP_VIA}); + +open(LOG, ">>$LOG") || die "boo hoo, phf_log $!"; +print LOG "[$when] $ENV{REMOTE_ADDR} $ENV{REMOTE_HOST} $ENV{$HTTP_REFERER} $ENV{HTTP_USER_AGENT}\n"; +close(LOG); + +print "Content-type: text/html\r\n\r\nSmile, you're on Candid Camera.\n"; diff --git a/APACHE_1_2_X/src/support/rotatelogs.c b/APACHE_1_2_X/src/support/rotatelogs.c new file mode 100644 index 00000000000..08066923854 --- /dev/null +++ b/APACHE_1_2_X/src/support/rotatelogs.c @@ -0,0 +1,84 @@ +/* + +Simple program to rotate Apache logs without having to kill the server. + +Contributed by Ben Laurie + +12 Mar 1996 + +*/ + +#define BUFSIZE 65536 +#define MAX_PATH 1024 + +#include +#include +#include +#include +#include +#include + +void main(int argc,char **argv) + { + char buf[BUFSIZE],buf2[MAX_PATH]; + time_t tLogEnd; + time_t tRotation; + int nLogFD=-1; + int nRead; + char *szLogRoot; + + if(argc != 3) + { + fprintf(stderr,"%s \n\n",argv[0]); +#ifdef __EMX__ + fprintf(stderr,"Add this:\n\nTransferLog \"|%s.exe /some/where 86400\"\n\n",argv[0]); +#else + fprintf(stderr,"Add this:\n\nTransferLog \"|%s /some/where 86400\"\n\n",argv[0]); +#endif + fprintf(stderr,"to httpd.conf. The generated name will be /some/where.nnnn where nnnn is the\n"); + fprintf(stderr,"system time at which the log nominally starts (N.B. this time will always be a\n"); + fprintf(stderr,"multiple of the rotation time, so you can synchronize cron scripts with it).\n"); + fprintf(stderr,"At the end of each rotation time a new log is started.\n"); + exit(1); + } + + szLogRoot=argv[1]; + tRotation=atoi(argv[2]); + if(tRotation <= 0) + { + fprintf(stderr,"Rotation time must be > 0\n"); + exit(6); + } + + for( ; ; ) + { + nRead=read(0,buf,sizeof buf); + if(nRead == 0) + exit(3); + if(nRead < 0) + if(errno != EINTR) + exit(4); + if(nLogFD >= 0 && (time(NULL) >= tLogEnd || nRead < 0)) + { + close(nLogFD); + nLogFD=-1; + } + if(nLogFD < 0) + { + time_t tLogStart=(time(NULL)/tRotation)*tRotation; + sprintf(buf2,"%s.%010d",szLogRoot,(int)tLogStart); + tLogEnd=tLogStart+tRotation; + nLogFD=open(buf2,O_WRONLY|O_CREAT|O_APPEND,0666); + if(nLogFD < 0) + { + perror(buf2); + exit(2); + } + } + if(write(nLogFD,buf,nRead) != nRead) + { + perror(buf2); + exit(5); + } + } + } diff --git a/APACHE_1_2_X/src/support/suexec.c b/APACHE_1_2_X/src/support/suexec.c new file mode 100644 index 00000000000..18d2327353b --- /dev/null +++ b/APACHE_1_2_X/src/support/suexec.c @@ -0,0 +1,489 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * suexec.c -- "Wrapper" support program for suEXEC behaviour for Apache + * + *********************************************************************** + * + * NOTE! : DO NOT edit this code!!! Unless you know what you are doing, + * editing this code might open up your system in unexpected + * ways to would-be crackers. Every precaution has been taken + * to make this code as safe as possible; alter it at your own + * risk. + * + *********************************************************************** + * + * + */ + + +#include "suexec.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PATH_MAX) +#define AP_MAXPATH PATH_MAX +#elif defined(MAXPATHLEN) +#define AP_MAXPATH MAXPATHLEN +#else +#define AP_MAXPATH 8192 +#endif + +#define AP_ENVBUF 256 + +extern char **environ; +static FILE *log; + +char *safe_env_lst[] = +{ + "AUTH_TYPE", + "CONTENT_LENGTH", + "CONTENT_TYPE", + "DATE_GMT", + "DATE_LOCAL", + "DOCUMENT_NAME", + "DOCUMENT_PATH_INFO", + "DOCUMENT_ROOT", + "DOCUMENT_URI", + "FILEPATH_INFO", + "GATEWAY_INTERFACE", + "LAST_MODIFIED", + "PATH_INFO", + "PATH_TRANSLATED", + "QUERY_STRING", + "QUERY_STRING_UNESCAPED", + "REMOTE_ADDR", + "REMOTE_HOST", + "REMOTE_IDENT", + "REMOTE_PORT", + "REMOTE_USER", + "REDIRECT_QUERY_STRING", + "REDIRECT_STATUS", + "REDIRECT_URL", + "REQUEST_METHOD", + "SCRIPT_FILENAME", + "SCRIPT_NAME", + "SCRIPT_URI", + "SCRIPT_URL", + "SERVER_ADMIN", + "SERVER_NAME", + "SERVER_PORT", + "SERVER_PROTOCOL", + "SERVER_SOFTWARE", + "USER_NAME", + "TZ", + NULL +}; + + +static void err_output(const char *fmt, va_list ap) +{ + time_t timevar; + struct tm *lt; + + if (!log) + if ((log = fopen(LOG_EXEC, "a")) == NULL) { + fprintf(stderr, "failed to open log file\n"); + perror("fopen"); + exit(1); + } + + time(&timevar); + lt = localtime(&timevar); + + fprintf(log, "[%.2d:%.2d:%.2d %.2d-%.2d-%.2d]: ", lt->tm_hour, lt->tm_min, + lt->tm_sec, lt->tm_mday, (lt->tm_mon + 1), lt->tm_year); + + vfprintf(log, fmt, ap); + + fflush(log); + return; +} + +void log_err(const char *fmt, ...) +{ +#ifdef LOG_EXEC + va_list ap; + + va_start(ap, fmt); + err_output(fmt, ap); + va_end(ap); +#endif /* LOG_EXEC */ + return; +} + +void clean_env() +{ + char pathbuf[512]; + char **cleanenv; + char **ep; + int cidx = 0; + int idx; + + + if ((cleanenv = (char **)calloc(AP_ENVBUF, sizeof(char *))) == NULL) { + log_err("failed to malloc env mem\n"); + exit(120); + } + + for (ep = environ; *ep && cidx < AP_ENVBUF; ep++) { + if (!strncmp(*ep, "HTTP_", 5)) { + cleanenv[cidx] = *ep; + cidx++; + } + else { + for (idx = 0; safe_env_lst[idx]; idx++) { + if (!strncmp(*ep, safe_env_lst[idx], strlen(safe_env_lst[idx]))) { + cleanenv[cidx] = *ep; + cidx++; + break; + } + } + } + } + + sprintf(pathbuf, "PATH=%s", SAFE_PATH); + cleanenv[cidx] = strdup(pathbuf); + cleanenv[++cidx] = NULL; + + environ = cleanenv; +} + +int main(int argc, char *argv[]) +{ + int userdir = 0; /* ~userdir flag */ + uid_t uid; /* user information */ + gid_t gid; /* target group placeholder */ + char *target_uname; /* target user name */ + char *target_gname; /* target group name */ + char *target_homedir; /* target home directory */ + char *actual_uname; /* actual user name */ + char *actual_gname; /* actual group name */ + char *prog; /* name of this program */ + char *cmd; /* command to be executed */ + char cwd[AP_MAXPATH]; /* current working directory */ + char dwd[AP_MAXPATH]; /* docroot working directory */ + struct passwd *pw; /* password entry holder */ + struct group *gr; /* group entry holder */ + struct stat dir_info; /* directory info holder */ + struct stat prg_info; /* program info holder */ + + + + /* + * If there are a proper number of arguments, set + * all of them to variables. Otherwise, error out. + */ + prog = argv[0]; + if (argc < 4) { + log_err("too few arguments\n"); + exit(101); + } + target_uname = argv[1]; + target_gname = argv[2]; + cmd = argv[3]; + + /* + * Check existence/validity of the UID of the user + * running this program. Error out if invalid. + */ + uid = getuid(); + if ((pw = getpwuid(uid)) == NULL) { + log_err("invalid uid: (%ld)\n", uid); + exit(102); + } + + /* + * Check to see if the user running this program + * is the user allowed to do so as defined in + * suexec.h. If not the allowed user, error out. + */ + if (strcmp(HTTPD_USER, pw->pw_name)) { + log_err("user mismatch (%s)\n", pw->pw_name); + exit(103); + } + + /* + * Check for a leading '/' (absolute path) in the command to be executed, + * or attempts to back up out of the current directory, + * to protect against attacks. If any are + * found, error out. Naughty naughty crackers. + */ + if ( + (cmd[0] == '/') || + (! strncmp (cmd, "../", 3)) || + (strstr (cmd, "/../") != NULL) + ) { + log_err("invalid command (%s)\n", cmd); + exit(104); + } + + /* + * Check to see if this is a ~userdir request. If + * so, set the flag, and remove the '~' from the + * target username. + */ + if (!strncmp("~", target_uname, 1)) { + target_uname++; + userdir = 1; + } + + /* + * Error out if the target username is invalid. + */ + if ((pw = getpwnam(target_uname)) == NULL) { + log_err("invalid target user name: (%s)\n", target_uname); + exit(105); + } + + /* + * Error out if the target group name is invalid. + */ + if (strspn(target_gname, "1234567890") != strlen(target_gname)) { + if ((gr = getgrnam(target_gname)) == NULL) { + log_err("invalid target group name: (%s)\n", target_gname); + exit(106); + } + gid = gr->gr_gid; + actual_gname = strdup(gr->gr_name); + } + else { + gid = atoi(target_gname); + actual_gname = strdup(target_gname); + } + + /* + * Save these for later since initgroups will hose the struct + */ + uid = pw->pw_uid; + actual_uname = strdup(pw->pw_name); + target_homedir = strdup(pw->pw_dir); + + /* + * Log the transaction here to be sure we have an open log + * before we setuid(). + */ + log_err("uid: (%s/%s) gid: (%s/%s) %s\n", + target_uname, actual_uname, + target_gname, actual_gname, + cmd); + + /* + * Error out if attempt is made to execute as root or as + * a UID less than UID_MIN. Tsk tsk. + */ + if ((uid == 0) || + (uid < UID_MIN)) { + log_err("cannot run as forbidden uid (%d/%s)\n", uid, cmd); + exit(107); + } + + /* + * Error out if attempt is made to execute as root group + * or as a GID less than GID_MIN. Tsk tsk. + */ + if ((gid == 0) || + (gid < GID_MIN)) { + log_err("cannot run as forbidden gid (%d/%s)\n", gid, cmd); + exit(108); + } + + /* + * Change UID/GID here so that the following tests work over NFS. + * + * Initialize the group access list for the target user, + * and setgid() to the target group. If unsuccessful, error out. + */ + if (((setgid(gid)) != 0) || (initgroups(actual_uname,gid) != 0)) { + log_err("failed to setgid (%ld: %s/%s)\n", gid, cwd, cmd); + exit(109); + } + + /* + * setuid() to the target user. Error out on fail. + */ + if ((setuid(uid)) != 0) { + log_err("failed to setuid (%ld: %s/%s)\n", uid, cwd, cmd); + exit(110); + } + + /* + * Get the current working directory, as well as the proper + * document root (dependant upon whether or not it is a + * ~userdir request). Error out if we cannot get either one, + * or if the current working directory is not in the docroot. + * Use chdir()s and getcwd()s to avoid problems with symlinked + * directories. Yuck. + */ + if (getcwd(cwd, AP_MAXPATH) == NULL) { + log_err("cannot get current working directory\n"); + exit(111); + } + + if (userdir) { + if (((chdir(target_homedir)) != 0) || + ((chdir(USERDIR_SUFFIX)) != 0) || + ((getcwd(dwd, AP_MAXPATH)) == NULL) || + ((chdir(cwd)) != 0)) + { + log_err("cannot get docroot information (%s)\n", target_homedir); + exit(112); + } + } + else { + if (((chdir(DOC_ROOT)) != 0) || + ((getcwd(dwd, AP_MAXPATH)) == NULL) || + ((chdir(cwd)) != 0)) + { + log_err("cannot get docroot information (%s)\n", DOC_ROOT); + exit(113); + } + } + + if ((strncmp(cwd, dwd, strlen(dwd))) != 0) { + log_err("command not in docroot (%s/%s)\n", cwd, cmd); + exit(114); + } + + /* + * Stat the cwd and verify it is a directory, or error out. + */ + if (((lstat(cwd, &dir_info)) != 0) || !(S_ISDIR(dir_info.st_mode))) { + log_err("cannot stat directory: (%s)\n", cwd); + exit(115); + } + + /* + * Error out if cwd is writable by others. + */ + if ((dir_info.st_mode & S_IWOTH) || (dir_info.st_mode & S_IWGRP)) { + log_err("directory is writable by others: (%s)\n", cwd); + exit(116); + } + + /* + * Error out if we cannot stat the program. + */ + if (((lstat(cmd, &prg_info)) != 0) || (S_ISLNK(prg_info.st_mode))) { + log_err("cannot stat program: (%s)\n", cmd); + exit(117); + } + + /* + * Error out if the program is writable by others. + */ + if ((prg_info.st_mode & S_IWOTH) || (prg_info.st_mode & S_IWGRP)) { + log_err("file is writable by others: (%s/%s)\n", cwd, cmd); + exit(118); + } + + /* + * Error out if the file is setuid or setgid. + */ + if ((prg_info.st_mode & S_ISUID) || (prg_info.st_mode & S_ISGID)) { + log_err("file is either setuid or setgid: (%s/%s)\n",cwd,cmd); + exit(119); + } + + /* + * Error out if the target name/group is different from + * the name/group of the cwd or the program. + */ + if ((uid != dir_info.st_uid) || + (gid != dir_info.st_gid) || + (uid != prg_info.st_uid) || + (gid != prg_info.st_gid)) + { + log_err("target uid/gid (%ld/%ld) mismatch with directory (%ld/%ld) or program (%ld/%ld)\n", + uid, gid, + dir_info.st_uid, dir_info.st_gid, + prg_info.st_uid, prg_info.st_gid); + exit(120); + } + + clean_env(); + + /* + * Be sure to close the log file so the CGI can't + * mess with it. If the exec fails, it will be reopened + * automatically when log_err is called. + */ + fclose(log); + log = NULL; + + /* + * Execute the command, replacing our image with its own. + */ + execv(cmd, &argv[3]); + + /* + * (I can't help myself...sorry.) + * + * Uh oh. Still here. Where's the kaboom? There was supposed to be an + * EARTH-shattering kaboom! + * + * Oh well, log the failure and error out. + */ + log_err("exec failed (%s)\n", cmd); + exit(255); +} diff --git a/APACHE_1_2_X/src/support/suexec.h b/APACHE_1_2_X/src/support/suexec.h new file mode 100644 index 00000000000..91cbc86950a --- /dev/null +++ b/APACHE_1_2_X/src/support/suexec.h @@ -0,0 +1,137 @@ +/* ==================================================================== + * Copyright (c) 1995-1997 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * suexec.h -- user-definable variables for the suexec wrapper code. + */ + + +#ifndef _SUEXEC_H +#define _SUEXEC_H + +/* + * HTTPD_USER -- Define as the username under which Apache normally + * runs. This is the only user allowed to execute + * this program. + */ +#ifndef HTTPD_USER +#define HTTPD_USER "www" +#endif + +/* + * UID_MIN -- Define this as the lowest UID allowed to be a target user + * for suEXEC. For most systems, 500 or 100 is common. + */ +#ifndef UID_MIN +#define UID_MIN 100 +#endif + +/* + * GID_MIN -- Define this as the lowest GID allowed to be a target group + * for suEXEC. For most systems, 100 is common. + */ +#ifndef GID_MIN +#define GID_MIN 100 +#endif + +/* + * USERDIR_SUFFIX -- Define to be the subdirectory under users' + * home directories where suEXEC access should + * be allowed. All executables under this directory + * will be executable by suEXEC as the user so + * they should be "safe" programs. If you are + * using a "simple" UserDir directive (ie. one + * without a "*" in it) this should be set to + * the same value. suEXEC will not work properly + * in cases where the UserDir directive points to + * a location that is not the same as the user's + * home directory as referenced in the passwd file. + * + * If you have VirtualHosts with a different + * UserDir for each, you will need to define them to + * all reside in one parent directory; then name that + * parent directory here. IF THIS IS NOT DEFINED + * PROPERLY, ~USERDIR CGI REQUESTS WILL NOT WORK! + * See the suEXEC documentation for more detailed + * information. + */ +#ifndef USERDIR_SUFFIX +#define USERDIR_SUFFIX "public_html" +#endif + +/* + * LOG_EXEC -- Define this as a filename if you want all suEXEC + * transactions and errors logged for auditing and + * debugging purposes. + */ +#ifndef LOG_EXEC +#define LOG_EXEC "/usr/local/etc/httpd/logs/cgi.log" /* Need me? */ +#endif + +/* + * DOC_ROOT -- Define as the DocumentRoot set for Apache. This + * will be the only hierarchy (aside from UserDirs) + * that can be used for suEXEC behavior. + */ +#ifndef DOC_ROOT +#define DOC_ROOT "/usr/local/etc/httpd/htdocs" +#endif + +/* + * SAFE_PATH -- Define a safe PATH environment to pass to CGI executables. + * + */ +#ifndef SAFE_PATH +#define SAFE_PATH "/usr/local/bin:/usr/bin:/bin" +#endif + +#endif /* _SUEXEC_H */ diff --git a/APACHE_1_2_X/src/test/cls.c b/APACHE_1_2_X/src/test/cls.c new file mode 100644 index 00000000000..2c553cec93d --- /dev/null +++ b/APACHE_1_2_X/src/test/cls.c @@ -0,0 +1,165 @@ +#include +#include +#include +#include +#include + +/* + * Compare a string to a mask + * Mask characters: + * @ - uppercase letter + * # - lowercase letter + * & - hex digit + * # - digit + * * - swallow remaining characters + * - exact match for any other character + */ +static int +checkmask(const char *data, const char *mask) +{ + int i, ch, d; + + for (i=0; mask[i] != '\0' && mask[i] != '*'; i++) + { + ch = mask[i]; + d = data[i]; + if (ch == '@') + { + if (!isupper(d)) return 0; + } else if (ch == '$') + { + if (!islower(d)) return 0; + } else if (ch == '#') + { + if (!isdigit(d)) return 0; + } else if (ch == '&') + { + if (!isxdigit(d)) return 0; + } else if (ch != d) return 0; + } + + if (mask[i] == '*') return 1; + else return (data[i] == '\0'); +} + +/* + * Converts 8 hex digits to a time integer + */ +static int +hex2sec(const char *x) +{ + int i, ch; + unsigned int j; + + for (i=0, j=0; i < 8; i++) + { + ch = x[i]; + j <<= 4; + if (isdigit(ch)) j |= ch - '0'; + else if (isupper(ch)) j |= ch - ('A' - 10); + else j |= ch - ('a' - 10); + } + if (j == 0xffffffff) return -1; /* so that it works with 8-byte ints */ + else return j; +} + +int +main(int argc, char **argv) +{ + int i, ver; + DIR *d; + struct dirent *e; + const char *s; + FILE *fp; + char path[FILENAME_MAX+1]; + char line[1035]; + time_t date, lmod, expire; + unsigned int len; + struct tm ts; + char sdate[30], slmod[30], sexpire[30]; + const char time_format[]="%e %b %Y %R"; + + if (argc != 2) + { + printf("Usage: cls directory\n"); + exit(0); + } + + d = opendir(argv[1]); + if (d == NULL) + { + perror("opendir"); + exit(1); + } + + for (;;) + { + e = readdir(d); + if (e == NULL) break; + s = e->d_name; + if (s[0] == '.' || s[0] == '#') continue; + sprintf(path, "%s/%s", argv[1], s); + fp = fopen(path, "r"); + if (fp == NULL) + { + perror("fopen"); + continue; + } + if (fgets(line, 1034, fp) == NULL) + { + perror("fgets"); + fclose(fp); + continue; + } + if (!checkmask(line, "&&&&&&&& &&&&&&&& &&&&&&&& &&&&&&&& &&&&&&&&\n")) + { + fprintf(stderr, "Bad cache file\n"); + fclose(fp); + continue; + } + date = hex2sec(line); + lmod = hex2sec(line+9); + expire = hex2sec(line+18); + ver = hex2sec(line+27); + len = hex2sec(line+35); + if (fgets(line, 1034, fp) == NULL) + { + perror("fgets"); + fclose(fp); + continue; + } + fclose(fp); + i = strlen(line); + if (strncmp(line, "X-URL: ", 7) != 0 || line[i-1] != '\n') + { + fprintf(stderr, "Bad cache file\n"); + continue; + } + line[i-1] = '\0'; + if (date != -1) + { + ts = *gmtime(&date); + strftime(sdate, 30, time_format, &ts); + } else + strcpy(sdate, "-"); + + if (lmod != -1) + { + ts = *gmtime(&lmod); + strftime(slmod, 30, time_format, &ts); + } else + strcpy(slmod, "-"); + + if (expire != -1) + { + ts = *gmtime(&expire); + strftime(sexpire, 30, time_format, &ts); + } else + strcpy(sexpire, "-"); + + printf("%s: %d; %s %s %s\n", line+7, ver, sdate, slmod, sexpire); + } + + closedir(d); + return 0; +}