├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── examples ├── mod_coming_soon │ ├── Cargo.toml │ ├── img │ │ └── mountain-mist.jpg │ └── src │ │ └── lib.rs ├── mod_conf │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── mod_hello │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── mod_https_www │ ├── Cargo.toml │ └── src │ │ └── lib.rs └── mod_info_rs │ ├── Cargo.toml │ └── src │ └── lib.rs └── src ├── apr.rs ├── cookie.rs ├── ffi.rs ├── httpd.rs ├── lib.rs └── wrapper.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | 4 | *.sublime-project 5 | *.sublime-workspace 6 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "apache2" 4 | version = "0.0.2" 5 | 6 | [dependencies] 7 | libc = "*" 8 | interpolate_idents = "0.0.4" 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Apache module development with Rust 2 | 3 | This library is intended to make possible and easy writing Apache HTTP Server modules using 4 | the Rust programming language. 5 | 6 | *NOTE: The library is still in early development phase – extensive documentation will be provided soon after the basic features are implemented* 7 | 8 | Here is a small example of what an Apache Rust module code looks like: 9 | 10 | ```rust 11 | #![feature(plugin)] 12 | #![plugin(interpolate_idents)] 13 | 14 | #[macro_use] 15 | extern crate apache2; 16 | 17 | use apache2::{Request, Status}; 18 | 19 | apache2_module!(hello, b"mod_hello\0"); 20 | 21 | 22 | fn hello_handler(r: &mut Request) -> Result { 23 | r.set_content_type("text/plain; charset=utf-8"); 24 | 25 | try!(r.write("Hello Ciao Здравейте")); 26 | 27 | Ok(Status::OK) 28 | } 29 | ``` 30 | -------------------------------------------------------------------------------- /examples/mod_coming_soon/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "mod_coming_soon" 4 | version = "0.0.2" 5 | 6 | [lib] 7 | name = "mod_coming_soon" 8 | crate-type = ["dylib"] 9 | 10 | [dependencies] 11 | interpolate_idents = "*" 12 | 13 | [dependencies.apache2] 14 | path = "../.." 15 | -------------------------------------------------------------------------------- /examples/mod_coming_soon/img/mountain-mist.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/majorz/apache2-rs/657e3b833ac59894a3625834ab2c950c26e342a6/examples/mod_coming_soon/img/mountain-mist.jpg -------------------------------------------------------------------------------- /examples/mod_coming_soon/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(plugin)] 2 | #![plugin(interpolate_idents)] 3 | 4 | #[macro_use] 5 | extern crate apache2; 6 | 7 | use apache2::{Request, Status}; 8 | 9 | apache2_module!(coming_soon, b"mod_coming_soon\0"); 10 | 11 | 12 | macro_rules! html_template {() => (" 13 | 14 | 15 | 16 | 17 | PolyDraw / Coming Soon 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 |
32 |

PolyDraw

33 |

Open source software development

34 | 35 |
COMING SOON
36 | 37 |
in
38 | 39 |
40 |
26
41 |
days
42 |
43 | 44 |
45 |
46 |
47 | In the meantime, please sign the international petition against 48 |
49 | 50 |
LIVE ORGAN HARVESTING
51 | 52 |
from Falun Gong practitioners in China!
53 |
54 | 55 | 56 | 61 |
62 |
63 | 64 | 73 | 74 | 75 | ")} 76 | 77 | 78 | fn coming_soon_handler(r: &mut Request) -> Result { 79 | if get!(r.handler()) != "coming-soon" || get!(r.uri()) != "/" { 80 | return Ok(Status::DECLINED) 81 | } 82 | 83 | r.set_content_type("text/html"); 84 | 85 | try!(r.write(format!( 86 | html_template!(), 87 | STYLESHEET 88 | ))); 89 | 90 | Ok(Status::OK) 91 | } 92 | 93 | 94 | const STYLESHEET: &'static str = " 95 | html, body { 96 | height: 100%; 97 | width: 100%; 98 | margin: 0; 99 | } 100 | 101 | body { 102 | display: block; 103 | font-family: 'Roboto Condensed', sans-serif; 104 | background-image: url(https://www.polydraw.com/img/mountain-mist.jpg); 105 | background-size: cover; 106 | background-repeat: no-repeat; 107 | background-attachment: fixed; 108 | background-position: right bottom; 109 | } 110 | 111 | main { 112 | display: block; 113 | position: relative; 114 | top: 50%; 115 | margin: 0 auto; 116 | -webkit-transform: translateY(-50%); 117 | -ms-transform: translateY(-50%); 118 | transform: translateY(-50%); 119 | } 120 | 121 | h1 { 122 | display: block; 123 | width: 60%; 124 | margin: 0 auto; 125 | font-family: 'Fira Sans', sans-serif; 126 | font-weight: 500; 127 | font-size: 3.5em; 128 | color: white; 129 | text-align: center; 130 | } 131 | 132 | h2 { 133 | display: block; 134 | width: 70%; 135 | margin: -0.2em auto 0; 136 | font-family: 'Fira Sans', sans-serif; 137 | font-weight: 300; 138 | font-size: 1.2em; 139 | color: #5b5b5b; 140 | text-align: center; 141 | } 142 | 143 | .coming-soon { 144 | display: block; 145 | width: 40%; 146 | margin: 2.5em auto .1em; 147 | font-size: 1.5em; 148 | color: white; 149 | text-align: center; 150 | } 151 | 152 | .in { 153 | display: block; 154 | font-family: 'Fira Sans', sans-serif; 155 | font-weight: 300; 156 | font-size: .8em; 157 | font-style: italic; 158 | color: white; 159 | text-align: center; 160 | } 161 | 162 | .timer { 163 | display: block; 164 | width: 7em; 165 | text-align: center; 166 | border-style: solid none solid none; 167 | border-color: #e6e6e6; 168 | border-width: 1px; 169 | margin: 0 auto 1em; 170 | } 171 | 172 | .timer .number { 173 | display: block; 174 | font-family: 'Khand', sans-serif; 175 | font-size: 4em; 176 | font-weight: bold; 177 | color: white; 178 | text-align: center; 179 | } 180 | 181 | .timer .days { 182 | display: block; 183 | font-family: 'Khand', sans-serif; 184 | font-size: 1.5em; 185 | color: white; 186 | text-align: center; 187 | margin: -1em auto 0; 188 | } 189 | 190 | .urgent-call { 191 | margin: 3% auto 0; 192 | } 193 | 194 | .urgent-call .description { 195 | display: block; 196 | width: 100%; 197 | padding-top: 1em; 198 | padding-bottom: 1em; 199 | background: -webkit-linear-gradient(left, rgba(86,86,107,0), rgba(86,86,107,.4), rgba(86,86,107,0)); 200 | background: linear-gradient(to right,rgba(86,86,107,0),rgba(86,86,107,.4),rgba(86,86,107,0)); 201 | } 202 | 203 | .urgent-call .first, .urgent-call .second, .urgent-call .third { 204 | margin: 0 auto; 205 | width: 90%; 206 | color: white; 207 | font-size: 1em; 208 | text-align: center; 209 | } 210 | 211 | .urgent-call .first { 212 | margin-bottom: 0.5em; 213 | } 214 | 215 | .urgent-call .second { 216 | width: 100%; 217 | color: #f36c69; 218 | font-family: 'Khand', sans-serif; 219 | font-weight: bold; 220 | font-size: 1.2em; 221 | text-shadow: 0px 1px 9px rgba(0, 0, 0, 0.35); 222 | letter-spacing: 0.1em; 223 | } 224 | 225 | .urgent-call .third { 226 | margin-top: 0.15em; 227 | } 228 | 229 | .petition .button { 230 | display: block; 231 | width: 120px; 232 | margin: 1em auto 0; 233 | padding: 3px 6px; 234 | background: #829776; 235 | color: #ffffff; 236 | font-family: 'Fira Sans', sans-serif; 237 | font-size: .85em; 238 | font-weight: 300; 239 | text-align: center; 240 | text-decoration: none; 241 | border: solid #ffffff 1px; 242 | border-radius: 3px; 243 | } 244 | 245 | .petition .button:hover { 246 | background: #4d6b3c; 247 | } 248 | 249 | 250 | footer { 251 | display: table; 252 | position: fixed; 253 | width: 96%; 254 | bottom: 0; 255 | padding-left: 2%; 256 | padding-right: 2%; 257 | } 258 | 259 | .social { 260 | display: block; 261 | vertical-align: middle; 262 | float: right; 263 | } 264 | 265 | .social a { 266 | display: inline-block; 267 | width: 28px; 268 | height: 28px; 269 | background-repeat: no-repeat; 270 | opacity: .5; 271 | margin-left: .5em; 272 | } 273 | 274 | .social a:hover { 275 | opacity: .9; 276 | } 277 | 278 | .social a.facebook { 279 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAMAAABF0y+mAAAAG1BMVEUAAADY2NjY2NjY2NjY2NhGRkZqamqFhYWtra1jMrL/AAAACXRSTlMAPGaw//////9HdVBWAAAAp0lEQVQoz42TQRLDIAwDVyb/f3GxegAGmJC0PhkWge0RYoYQxuvGSGKkTu9wohW3vQj2yAQoR4Zwh3fWaYAODEJwQWNltqAKEJXShSV71dVWGJCJLuy6+MxFEKwN8uGSPGraml+uaG9s9RuqvVX8FLvSgqJ5PPysdPASP5SP1AS5O2IuEkHRcfCuCFSOt1Y3J5wGkW5O8IFmDg/daTPYH9Z8N/X5O3wBpdI+PxtA6DIAAAAASUVORK5CYII=); 280 | } 281 | 282 | .social a.twitter { 283 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAMAAABF0y+mAAAAJFBMVEUAAADY2NjV1dXY2NjY2NjY2NjY2NhHR0empqaQkJBtbW3Dw8PQfCyMAAAADHRSTlMAPPVmwKD////////J66Z0AAAA5UlEQVQoz32T0ZKFIAxDT1qc/f+/3VFo9wFQXL23D+oQGpJQxVXCCHJdmB+lFQCq17yDclsoonXYx9NZ+dPy7PQbBEBro/MFw0gwUPJSKRAUewOJiqEbZu5QAUyITQBbVgAPwHUA5OHQO6N4zOMsAFpKW89lAw8FgLW+6XB1Hz9KcuY6XuEjt12XqBKn2bGwgMcpfe7a/XFRYQ+uUzRY9wdE7/DfCdX0cZp5l2jt5FI46QC5F5M4Fl31e/AOmW9oDbB+c89S9klI7POYkIvf4aJd05do5Y6IZTQhYjqsqvE/yLff4Q+6BFspw2Tr1AAAAABJRU5ErkJggg==); 284 | } 285 | 286 | .social a.github { 287 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAMAAABF0y+mAAAAJFBMVEUAAADY2NjY2NjY2NjY2NjY2NhHR0ebm5u3t7dYWFh3d3dqampwrbVmAAAADHRSTlMAPGbxsP////////80TrKnAAAA4UlEQVQoz32TwW7DMAxDH+ns/z94tbhDpDRBi+lkSCBN0bR4lxAh98YcVgxAaec51NKNIj1eANjmyR+AA8CLZxmqkR8zwAQMEl9KAsExQy+RXaPqxXEBl9gidnZDowGu0olxvBvqcUTSOgmGKlhudeU6JJWLbmmWXwXs04Ga1UaqVK/z9LsuT9+2/XxxovWkFwB2pjfI7ZaB8L6Q53aFdw44UqZb8dyek0R4WMUa5iybIEvNuv83XqBnDLqqgiH59p7JmYTwCd0TE3KLaHPWO315ZiV1jyZUFLUdl2D99x3+AND/ZE+Y11fiAAAAAElFTkSuQmCC); 288 | } 289 | 290 | @media all and (max-width: 319px) { 291 | main { 292 | margin: auto 0; 293 | } 294 | 295 | h1 { 296 | margin: -7% auto 0; 297 | font-size: 1.6em; 298 | } 299 | 300 | h2 { 301 | margin: 0 auto; 302 | font-size: .8em; 303 | } 304 | 305 | .coming-soon { 306 | margin: .7em auto 0; 307 | font-size: .8em; 308 | } 309 | 310 | .in { 311 | font-size: .7em; 312 | } 313 | 314 | .timer { 315 | width: 3em; 316 | margin: 0 auto .2em; 317 | } 318 | 319 | .timer .number { 320 | font-size: 2em; 321 | } 322 | 323 | .timer .days { 324 | font-size: .75em; 325 | } 326 | 327 | .urgent-call { 328 | margin: 0 auto; 329 | } 330 | 331 | .urgent-call .description { 332 | font-size: 0.7em; 333 | } 334 | 335 | .petition .button { 336 | width: 120px; 337 | margin: 1em auto 0; 338 | padding: 3px; 339 | font-size: .6em; 340 | } 341 | } 342 | 343 | @media all and (min-width: 320px) and (max-width: 460px) { 344 | h1 { 345 | margin: 0 auto; 346 | font-size: 2.5em; 347 | } 348 | 349 | h2 { 350 | margin: 0 auto 2em; 351 | font-size: .9em; 352 | } 353 | 354 | .coming-soon { 355 | margin: 0 auto; 356 | font-size: 1.3em; 357 | } 358 | 359 | .timer { 360 | width: 5em; 361 | margin: 0 auto 1em; 362 | } 363 | 364 | .timer .number { 365 | font-size: 2.8em; 366 | } 367 | 368 | .timer .days { 369 | font-size: 1.1em; 370 | } 371 | 372 | .urgent-call .description { 373 | font-size: .85em; 374 | } 375 | 376 | .petition .button { 377 | width: 100px; 378 | margin: 1em auto 0; 379 | font-size: .6em; 380 | } 381 | } 382 | 383 | @media all and (min-width: 1600px) { 384 | h1 { 385 | font-size: 5em; 386 | } 387 | 388 | h2 { 389 | font-size: 1.7em; 390 | } 391 | 392 | .coming-soon { 393 | font-size: 2.25em; 394 | } 395 | 396 | .in { 397 | font-size: 1.2em; 398 | } 399 | 400 | .timer { 401 | width: 10em; 402 | margin: 0.5em auto 2em; 403 | } 404 | 405 | .timer .number { 406 | font-size: 5em; 407 | } 408 | 409 | .timer .days { 410 | font-size: 2.25em; 411 | } 412 | 413 | .urgent-call .description { 414 | } 415 | 416 | .urgent-call .first, .urgent-call .third { 417 | font-size: 1.5em; 418 | } 419 | 420 | .urgent-call .second { 421 | font-size: 1.8em; 422 | } 423 | 424 | .petition .button { 425 | width: 180px; 426 | margin: 1em auto 0; 427 | padding: 5px; 428 | font-size: 1.2em; 429 | } 430 | } 431 | "; 432 | -------------------------------------------------------------------------------- /examples/mod_conf/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "mod_conf" 4 | version = "0.0.2" 5 | 6 | [lib] 7 | name = "mod_conf" 8 | crate-type = ["dylib"] 9 | 10 | [dependencies] 11 | interpolate_idents = "*" 12 | 13 | [dependencies.apache2] 14 | path = "../.." 15 | -------------------------------------------------------------------------------- /examples/mod_conf/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(convert)] 2 | #![feature(plugin)] 3 | #![plugin(interpolate_idents)] 4 | 5 | #[macro_use] 6 | extern crate apache2; 7 | 8 | use apache2::{Request, Status, Pool, CmdParms, BoolType, StringType, RSRC_CONF, ACCESS_CONF}; 9 | 10 | 11 | apache2_module!( 12 | conf, b"mod_conf\0", 13 | config { 14 | directory { 15 | DirectoryConfig { 16 | dir_var: StringType 17 | }, 18 | create_dir_config, 19 | merge_dir_config 20 | }, 21 | server { 22 | ServerConfig { 23 | enabled: BoolType, 24 | string_var: StringType 25 | }, 26 | create_server_config, 27 | merge_server_config 28 | }, [ 29 | (FLAG, b"EnabledVar\0", enabled_var, RSRC_CONF, b"Example flag\0"), 30 | (TAKE1, b"StringVar\0", string_var, RSRC_CONF, b"Example string directive\0"), 31 | (TAKE1, b"DirVar\0", dir_var, ACCESS_CONF, b"Directory string directive\0") 32 | ] 33 | } 34 | ); 35 | 36 | 37 | fn create_server_config<'a>(pool: &mut Pool) -> ServerConfig<'a> { 38 | let mut config = ServerConfig::new(pool).unwrap(); 39 | 40 | config.set_enabled(false); 41 | 42 | config 43 | } 44 | 45 | 46 | fn merge_server_config<'a>(pool: &mut Pool, base_conf: &'a ServerConfig, new_conf: &'a ServerConfig) -> ServerConfig<'a> { 47 | let mut config = create_server_config(pool); 48 | 49 | config.set_enabled(new_conf.enabled() || base_conf.enabled()); 50 | 51 | config.set_string_var( 52 | new_conf.string_var().unwrap_or( 53 | base_conf.string_var().unwrap_or("") 54 | ) 55 | ); 56 | 57 | config 58 | } 59 | 60 | 61 | fn create_dir_config<'a>(pool: &mut Pool, _: Option<&'a str>) -> DirectoryConfig<'a> { 62 | DirectoryConfig::new(pool).unwrap() 63 | } 64 | 65 | 66 | fn merge_dir_config<'a>(pool: &mut Pool, base_conf: &'a DirectoryConfig, new_conf: &'a DirectoryConfig) -> DirectoryConfig<'a> { 67 | let mut config = create_dir_config(pool, None); 68 | 69 | config.set_dir_var( 70 | format!( 71 | "{}{}", base_conf.dir_var().unwrap_or(""), new_conf.dir_var().unwrap_or("") 72 | ).as_str() 73 | ); 74 | 75 | config 76 | } 77 | 78 | 79 | fn enabled_var(parms: &mut CmdParms, _: Option, on: bool) -> Result<(), ()> { 80 | let mut config = get_server_config_from_parms(parms); 81 | 82 | config.set_enabled(on); 83 | 84 | Ok(()) 85 | } 86 | 87 | 88 | fn string_var<'a>(parms: &mut CmdParms, _: Option, w: &'a str) -> Result<(), ()> { 89 | let mut config = get_server_config_from_parms(parms); 90 | 91 | config.set_string_var(w); 92 | 93 | Ok(()) 94 | } 95 | 96 | 97 | fn dir_var<'a>(_: &mut CmdParms, mconfig: Option, w: &'a str) -> Result<(), ()> { 98 | let mut config = mconfig.unwrap(); 99 | 100 | config.set_dir_var(w); 101 | 102 | Ok(()) 103 | } 104 | 105 | 106 | fn unwrap_str<'a>(wrapped: Option<&'a str>) -> &'a str { 107 | wrapped.unwrap_or("--") 108 | } 109 | 110 | 111 | fn conf_handler(r: &mut Request) -> Result { 112 | if get!(r.handler()) != "conf" { 113 | return Ok(Status::DECLINED) 114 | } 115 | 116 | let server_config = get_server_config_from_request(r); 117 | 118 | r.set_content_type("text/plain; charset=utf-8"); 119 | 120 | let enabled = server_config.enabled(); 121 | try!(r.write(format!("EnabledVar: {}\n", enabled))); 122 | 123 | let string_var = unwrap_str(server_config.string_var()); 124 | try!(r.write(format!("StringVar: {}\n", string_var))); 125 | 126 | let dir_config = get_dir_config_from_request(r); 127 | 128 | let dir_var = unwrap_str(dir_config.dir_var()); 129 | try!(r.write(format!("DirVar: {}\n", dir_var))); 130 | 131 | Ok(Status::OK) 132 | } 133 | -------------------------------------------------------------------------------- /examples/mod_hello/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "mod_hello" 4 | version = "0.0.2" 5 | 6 | [lib] 7 | name = "mod_hello" 8 | crate-type = ["dylib"] 9 | 10 | [dependencies] 11 | interpolate_idents = "*" 12 | 13 | [dependencies.apache2] 14 | path = "../.." 15 | -------------------------------------------------------------------------------- /examples/mod_hello/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(plugin)] 2 | #![plugin(interpolate_idents)] 3 | 4 | #[macro_use] 5 | extern crate apache2; 6 | 7 | use apache2::{Request, Status}; 8 | 9 | apache2_module!(hello, b"mod_hello\0"); 10 | 11 | 12 | fn hello_handler(r: &mut Request) -> Result { 13 | r.set_content_type("text/plain; charset=utf-8"); 14 | 15 | try!(r.write("Hello Ciao Здравейте")); 16 | 17 | Ok(Status::OK) 18 | } 19 | -------------------------------------------------------------------------------- /examples/mod_https_www/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "mod_https_www" 4 | version = "0.0.2" 5 | 6 | [lib] 7 | name = "mod_https_www" 8 | crate-type = ["dylib"] 9 | 10 | [dependencies] 11 | interpolate_idents = "*" 12 | 13 | [dependencies.apache2] 14 | path = "../.." 15 | -------------------------------------------------------------------------------- /examples/mod_https_www/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(plugin)] 2 | #![feature(collections)] 3 | #![plugin(interpolate_idents)] 4 | 5 | #[macro_use] 6 | extern crate apache2; 7 | 8 | use apache2::{HookOrder, Request, Status}; 9 | 10 | apache2_module!(https_www, b"mod_https_www\0", handlers { 11 | (https_www_handler, translate_name, HookOrder::MIDDLE) 12 | }); 13 | 14 | 15 | fn https_www_handler(r: &mut Request) -> Result { 16 | let scheme = r.http_scheme().unwrap(); 17 | let hostname = r.hostname().unwrap(); 18 | 19 | let already_www = &hostname[..4] == "www."; 20 | let already_https = scheme == "https"; 21 | 22 | if already_www && already_https { 23 | return Ok(Status::DECLINED); 24 | }; 25 | 26 | let full_hostname = if already_www { 27 | String::from_str(hostname) 28 | } else { 29 | format!("www.{}", hostname) 30 | }; 31 | 32 | let uri = r.unparsed_uri().unwrap(); 33 | 34 | let location = format!("https://{}{}", full_hostname, uri); 35 | 36 | try!( 37 | r.headers_out().unwrap().set("Location", location) 38 | ); 39 | 40 | r.set_status(apache2::Status::HTTP_MOVED_PERMANENTLY); 41 | 42 | Ok(Status::DONE) 43 | } 44 | -------------------------------------------------------------------------------- /examples/mod_info_rs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "mod_info_rs" 4 | version = "0.0.2" 5 | 6 | [lib] 7 | name = "mod_info_rs" 8 | crate-type = ["dylib"] 9 | 10 | [dependencies] 11 | interpolate_idents = "*" 12 | 13 | [dependencies.apache2] 14 | path = "../.." 15 | -------------------------------------------------------------------------------- /examples/mod_info_rs/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(plugin)] 2 | #![plugin(interpolate_idents)] 3 | 4 | #[macro_use] 5 | extern crate apache2; 6 | 7 | use apache2::{Request, Status, server_banner, server_description, server_built, show_mpm, 8 | apr_version_string, apu_version_string, Cookie, time_now}; 9 | 10 | apache2_module!(info_rs, b"mod_info_rs\0"); 11 | 12 | fn unwrap_str<'a>(wrapped: Option<&'a str>) -> &'a str { 13 | wrapped.unwrap_or("--") 14 | } 15 | 16 | fn info_rs_handler(r: &mut Request) -> Result { 17 | if get!(r.handler()) != "server-info-rs" { 18 | return Ok(Status::DECLINED) 19 | } 20 | 21 | r.set_content_type("text/html"); 22 | 23 | r.set_last_modified(time_now()); 24 | 25 | try!(r.write("Apache Info")); 26 | 27 | try!(r.write("

Apache Server Information

")); 28 | 29 | let server_name = try!( 30 | r.escape_html( 31 | unwrap_str(r.server_name()) 32 | ) 33 | ); 34 | let server_port = r.server_port(); 35 | let local_ip = unwrap_str(get!(r.connection()).local_ip()); 36 | try!(r.write(format!("

Server: {}:{} (via {})

", server_name, server_port, local_ip))); 37 | 38 | let description = unwrap_str(server_description()); 39 | let banner = unwrap_str(server_banner()); 40 | try!(r.write(format!("

Server Description/Banner: {} / {}

", description, banner))); 41 | 42 | let mmp = unwrap_str(show_mpm()); 43 | try!(r.write(format!("

Server MPM: {}

", mmp))); 44 | 45 | let built = unwrap_str(server_built()); 46 | try!(r.write(format!("

Server Built: {}

", built))); 47 | 48 | let apr_version = unwrap_str(apr_version_string()); 49 | try!(r.write(format!("

Server loaded APR Version: {}

", apr_version))); 50 | 51 | let apu_version = unwrap_str(apu_version_string()); 52 | try!(r.write(format!("

Server loaded APU Version: {}

", apu_version))); 53 | 54 | let document_root = unwrap_str(r.document_root()); 55 | try!(r.write(format!("

Document Root: {}

", document_root))); 56 | 57 | try!(r.write("
")); 58 | 59 | try!(r.write("

Current Request Information

")); 60 | 61 | let client_ip = unwrap_str(get!(r.connection()).client_ip()); 62 | try!(r.write(format!("

Client IP: {}

", client_ip))); 63 | 64 | let useragent_ip = unwrap_str(r.useragent_ip()); 65 | try!(r.write(format!("

Useragent IP: {}

", useragent_ip))); 66 | 67 | let hostname = unwrap_str(r.hostname()); 68 | try!(r.write(format!("

Hostname: {}

", hostname))); 69 | 70 | let the_request = unwrap_str(r.the_request()); 71 | try!(r.write(format!("

Request: {}

", the_request))); 72 | 73 | let protocol = unwrap_str(r.protocol()); 74 | try!(r.write(format!("

Protocol: {}

", protocol))); 75 | 76 | let http_scheme = unwrap_str(r.http_scheme()); 77 | try!(r.write(format!("

HTTP Scheme: {}

", http_scheme))); 78 | 79 | try!(r.write(format!("

HTTP/0.9: {:?}

", r.assbackwards()))); 80 | 81 | let method = unwrap_str(r.method()); 82 | try!(r.write(format!("

Method: {}

", method))); 83 | 84 | let unparsed_uri = unwrap_str(r.unparsed_uri()); 85 | try!(r.write(format!("

Unparsed URI: {}

", unparsed_uri))); 86 | 87 | let uri = unwrap_str(r.uri()); 88 | try!(r.write(format!("

URI: {}

", uri))); 89 | 90 | let args = unwrap_str(r.args()); 91 | try!(r.write(format!("

Request Args: {}

", args))); 92 | 93 | let content_type = unwrap_str(r.content_type()); 94 | try!(r.write(format!("

Content Type: {}

", content_type))); 95 | 96 | let content_encoding = unwrap_str(r.content_encoding()); 97 | try!(r.write(format!("

Content Encoding: {}

", content_encoding))); 98 | 99 | try!(r.write(format!("

Content Length: {}

", r.clength()))); 100 | 101 | try!(r.write(format!("

Is Initial Request: {}

", r.is_initial_req()))); 102 | 103 | let context_document_root = unwrap_str(r.context_document_root()); 104 | try!(r.write(format!("

Context Document Root: {}

", context_document_root))); 105 | 106 | let context_prefix = unwrap_str(r.context_prefix()); 107 | try!(r.write(format!("

Context Prefix: {}

", context_prefix))); 108 | 109 | let range = unwrap_str(r.range()); 110 | try!(r.write(format!("

Range: {}

", range))); 111 | 112 | let handler = unwrap_str(r.handler()); 113 | try!(r.write(format!("

Handler: {}

", handler))); 114 | 115 | let path_info = unwrap_str(r.path_info()); 116 | try!(r.write(format!("

Path Info: {}

", path_info))); 117 | 118 | let filename = unwrap_str(r.filename()); 119 | try!(r.write(format!("

Filename: {}

", filename))); 120 | 121 | let canonical_filename = unwrap_str(r.canonical_filename()); 122 | try!(r.write(format!("

Canonical Filename: {}

", canonical_filename))); 123 | 124 | let request_time = try!(r.rfc822_date(r.request_time())); 125 | try!(r.write(format!("

Request Time: {} / {}

", request_time, r.request_time()))); 126 | 127 | let mtime = try!(r.rfc822_date(r.mtime())); 128 | try!(r.write(format!("

Last modified time: {} / {}

", mtime, r.mtime()))); 129 | 130 | let log_id = unwrap_str(r.log_id()); 131 | try!(r.write(format!("

Log ID: {}

", log_id))); 132 | 133 | let user = unwrap_str(r.user()); 134 | try!(r.write(format!("

User: {}

", user))); 135 | 136 | try!(r.write(format!("

Some Auth Required: {}

", r.some_auth_required()))); 137 | 138 | let ap_auth_type = unwrap_str(r.ap_auth_type()); 139 | try!(r.write(format!("

Auth Type: {}

", ap_auth_type))); 140 | 141 | let auth_name = unwrap_str(r.auth_name()); 142 | try!(r.write(format!("

Auth Name: {}

", auth_name))); 143 | 144 | let basic_auth_pw = unwrap_str(r.basic_auth_pw()); 145 | try!(r.write(format!("

Basic Auth PW: {}

", basic_auth_pw))); 146 | 147 | try!(r.write(format!("

Default Port: {}

", r.default_port()))); 148 | 149 | try!(r.write(format!("

ProxyReq: {}

", r.proxyreq()))); 150 | 151 | let key = "sample_cookie"; 152 | let val = "info_rs"; 153 | match r.cookie(key) { 154 | None => { 155 | let mut cookie = Cookie::new(key, val); 156 | cookie.expires = Some(time_now() + 1000000 * 30); 157 | 158 | r.set_cookie(cookie); 159 | try!(r.write(format!("

New Cookie – {}: {}

", key, val))); 160 | }, 161 | Some(stored) => { 162 | try!(r.write(format!("

Cookie – {}: {}

", key, stored))); 163 | } 164 | }; 165 | 166 | try!(r.write("

Request Headers

")); 167 | 168 | let headers_in = get!(r.headers_in()); 169 | 170 | for (key, val) in headers_in.iter() { 171 | try!(r.write(format!("

{}: {}

", key, unwrap_str(val)))); 172 | } 173 | 174 | try!(r.write("

Headers Out

")); 175 | 176 | let headers_out = get!(r.headers_out()); 177 | 178 | for (key, val) in headers_out.iter() { 179 | try!(r.write(format!("

{}: {}

", key, unwrap_str(val)))); 180 | } 181 | 182 | try!(r.write("

Err Headers Out

")); 183 | 184 | let err_headers_out = get!(r.err_headers_out()); 185 | 186 | for (key, val) in err_headers_out.iter() { 187 | try!(r.write(format!("

{}: {}

", key, unwrap_str(val)))); 188 | } 189 | 190 | try!(r.write("

Notes

")); 191 | 192 | let notes = get!(r.notes()); 193 | 194 | for (key, val) in notes.iter() { 195 | try!(r.write(format!("

{}: {}

", key, unwrap_str(val)))); 196 | } 197 | 198 | try!(r.write("

Subprocess Environment

")); 199 | 200 | let subprocess_env = get!(r.subprocess_env()); 201 | 202 | for (key, val) in subprocess_env.iter() { 203 | try!(r.write(format!("

{}: {}

", key, unwrap_str(val)))); 204 | } 205 | 206 | try!(r.write("

Request API check

")); 207 | 208 | let original = "Բարեւ, Héébee, გამარჯობა, Witôjze, Здраво, Ciao"; 209 | let encoded = try!(r.base64_encode(original)); 210 | let plain = try!(r.base64_decode(encoded)); 211 | try!(r.write(format!("

Original Text: {}

", original))); 212 | try!(r.write(format!("

Base64 Encoded: {}

", encoded))); 213 | try!(r.write(format!("

Base64 Decoded: {}

", plain))); 214 | 215 | let original_url = "http://foo.bar/1 2 3 & 4 + 5"; 216 | let encoded_url = try!(r.escape_urlencoded(original_url)); 217 | let plain_url = try!(r.unescape_urlencoded(encoded_url)); 218 | try!(r.write(format!("

Original URL: {}

", original_url))); 219 | try!(r.write(format!("

Encoded URL: {}

", encoded_url))); 220 | try!(r.write(format!("

Decoded URL: {}

", plain_url))); 221 | 222 | let date = try!(r.rfc822_date(0)); 223 | try!(r.write(format!("

RFC 822 Date: {}

", date))); 224 | 225 | try!(r.write("")); 226 | 227 | Ok(Status::OK) 228 | } 229 | -------------------------------------------------------------------------------- /src/apr.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_camel_case_types)] 2 | 3 | use std::ffi::CString; 4 | use std::marker::PhantomData; 5 | 6 | use ffi; 7 | 8 | use wrapper::{Wrapper, from_char_ptr, WrappedType, FromRaw}; 9 | 10 | 11 | pub enum HookOrder { 12 | REALLY_FIRST, // run this hook first, before ANYTHING 13 | FIRST, // run this hook first 14 | MIDDLE, // run this hook somewhere 15 | LAST, // run this hook after every other hook which is defined 16 | REALLY_LAST // run this hook last, after EVERYTHING 17 | } 18 | 19 | impl Into<::libc::c_int> for HookOrder { 20 | fn into(self) -> ::libc::c_int { 21 | match self { 22 | HookOrder::REALLY_FIRST => ffi::APR_HOOK_REALLY_FIRST, 23 | HookOrder::FIRST => ffi::APR_HOOK_FIRST, 24 | HookOrder::MIDDLE => ffi::APR_HOOK_MIDDLE, 25 | HookOrder::LAST => ffi::APR_HOOK_LAST, 26 | HookOrder::REALLY_LAST => ffi::APR_HOOK_REALLY_LAST 27 | } 28 | } 29 | } 30 | 31 | 32 | pub type Table = Wrapper; 33 | 34 | 35 | impl Table { 36 | pub fn get<'a, T: Into>>(&self, key: T) -> Option<&'a str> { 37 | let key = match CString::new(key) { 38 | Ok(s) => s, 39 | Err(_) => return None 40 | }; 41 | 42 | from_char_ptr( 43 | unsafe { ffi::apr_table_get(self.ptr, key.as_ptr()) } 44 | ) 45 | } 46 | 47 | pub fn set>, U: Into>>(&mut self, key: T, val: U) -> Result<(), ()> { 48 | let key = match CString::new(key) { 49 | Ok(s) => s, 50 | Err(_) => return Err(()) 51 | }; 52 | 53 | let val = match CString::new(val) { 54 | Ok(s) => s, 55 | Err(_) => return Err(()) 56 | }; 57 | 58 | unsafe { 59 | ffi::apr_table_set( 60 | self.ptr, 61 | key.as_ptr(), 62 | val.as_ptr() 63 | ) 64 | }; 65 | 66 | Ok(()) 67 | } 68 | 69 | pub fn add>, U: Into>>(&mut self, key: T, val: U) -> Result<(), ()> { 70 | let key = match CString::new(key) { 71 | Ok(s) => s, 72 | Err(_) => return Err(()) 73 | }; 74 | 75 | let val = match CString::new(val) { 76 | Ok(s) => s, 77 | Err(_) => return Err(()) 78 | }; 79 | 80 | unsafe { 81 | ffi::apr_table_add( 82 | self.ptr, 83 | key.as_ptr(), 84 | val.as_ptr() 85 | ) 86 | }; 87 | 88 | Ok(()) 89 | } 90 | 91 | pub fn iter(&self) -> TableIter { 92 | let ptr = unsafe { ffi::apr_table_elts(self.ptr) }; 93 | let raw: &ffi::apr_array_header_t = unsafe { &*ptr }; 94 | 95 | TableIter { 96 | array_header: raw, 97 | next_idx: 0 98 | } 99 | } 100 | } 101 | 102 | pub type Pool = Wrapper; 103 | 104 | pub struct TableIter<'a> { 105 | pub array_header: &'a ffi::apr_array_header_t, 106 | pub next_idx: usize, 107 | } 108 | 109 | impl<'a> Iterator for TableIter<'a> { 110 | type Item = (&'a str, Option<&'a str>); 111 | 112 | fn next(&mut self) -> Option<(&'a str, Option<&'a str>)> { 113 | if self.next_idx != self.array_header.nelts as usize { 114 | let mut elts = self.array_header.elts as *const ffi::apr_table_entry_t; 115 | 116 | elts = unsafe { elts.offset(self.next_idx as isize) }; 117 | self.next_idx += 1; 118 | 119 | let key = from_char_ptr(unsafe { (*elts).key }).unwrap(); 120 | let val_result = from_char_ptr(unsafe { (*elts).val }); 121 | 122 | Some((key, val_result)) 123 | } else { 124 | None 125 | } 126 | } 127 | 128 | fn size_hint(&self) -> (usize, Option) { 129 | let rem = self.array_header.nelts as usize - self.next_idx; 130 | (rem, Some(rem)) 131 | } 132 | } 133 | 134 | pub struct ArrayHeaderIter { 135 | pub phantom: PhantomData, 136 | pub array_header: *mut ffi::apr_array_header_t, 137 | pub next_idx: usize, 138 | } 139 | 140 | impl::wrapped_type>> Iterator for ArrayHeaderIter { 141 | type Item = T; 142 | 143 | fn next(&mut self) -> Option { 144 | if self.array_header.is_null() { 145 | return None; 146 | } 147 | let array_header: &ffi::apr_array_header_t = unsafe { &*self.array_header }; 148 | if self.next_idx != array_header.nelts as usize { 149 | let mut elt = array_header.elts as *const T::wrapped_type; 150 | 151 | elt = unsafe { elt.offset(self.next_idx as isize)}; 152 | self.next_idx += 1; 153 | 154 | T::from_raw(elt as *mut ::wrapped_type) 155 | } else { 156 | None 157 | } 158 | } 159 | 160 | fn size_hint(&self) -> (usize, Option) { 161 | if self.array_header.is_null() { 162 | return (0, None); 163 | } 164 | let array_header: &ffi::apr_array_header_t = unsafe { &*self.array_header }; 165 | let rem = array_header.nelts as usize - self.next_idx; 166 | (rem, Some(rem)) 167 | } 168 | } 169 | 170 | 171 | pub fn apr_version_string<'a>() -> Option<&'a str> { 172 | from_char_ptr( 173 | unsafe { ffi::apr_version_string() } 174 | ) 175 | } 176 | 177 | pub fn apu_version_string<'a>() -> Option<&'a str> { 178 | from_char_ptr( 179 | unsafe { ffi::apu_version_string() } 180 | ) 181 | } 182 | 183 | pub fn time_now() -> i64 { 184 | unsafe { 185 | ffi::apr_time_now() 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/cookie.rs: -------------------------------------------------------------------------------- 1 | use httpd::Request; 2 | 3 | 4 | #[derive(PartialEq, Clone, Debug)] 5 | pub struct Cookie<'a> { 6 | pub name: &'a str, 7 | pub value: &'a str, 8 | pub expires: Option, 9 | pub max_age: Option, 10 | pub domain: Option<&'a str>, 11 | pub path: Option<&'a str>, 12 | pub secure: bool, 13 | pub httponly: bool, 14 | } 15 | 16 | impl<'a> Cookie<'a> { 17 | pub fn new(name: &'a str, value: &'a str) -> Cookie<'a> { 18 | Cookie::<'a> { 19 | name: name, 20 | value: value, 21 | expires: None, 22 | max_age: None, 23 | domain: None, 24 | path: Some("/"), 25 | secure: false, 26 | httponly: false, 27 | } 28 | } 29 | 30 | pub fn attrs(&self, r: &Request) -> String { 31 | let mut res = String::new(); 32 | 33 | if self.httponly { 34 | res.push_str(";HttpOnly"); 35 | } 36 | 37 | if self.secure { 38 | res.push_str(";Secure"); 39 | } 40 | 41 | match self.path { 42 | Some(ref s) => res.push_str(format!(";Path={}", s).as_ref()), 43 | None => {} 44 | } 45 | 46 | match self.domain { 47 | Some(ref s) => res.push_str(format!(";Domain={}", s).as_ref()), 48 | None => {} 49 | } 50 | 51 | match self.max_age { 52 | Some(n) => res.push_str(format!(";Max-Age={}", n).as_ref()), 53 | None => {} 54 | } 55 | 56 | match self.expires { 57 | Some(ref t) => { 58 | match r.rfc822_date(*t) { 59 | Ok(s) => res.push_str(format!(";Expires={}", s).as_ref()), 60 | Err(_) => {} 61 | } 62 | }, 63 | None => {} 64 | } 65 | 66 | if res.len() > 0 { 67 | res.remove(0); 68 | } 69 | 70 | res 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/ffi.rs: -------------------------------------------------------------------------------- 1 | #![allow(raw_pointer_derive)] 2 | #![allow(non_camel_case_types)] 3 | 4 | use std::mem; 5 | 6 | use libc::{c_void, c_char, c_uchar, c_short, c_ushort, c_int, c_uint, c_long, c_ulong}; 7 | 8 | 9 | // APACHE PORTABLE RUNTIME 10 | 11 | pub const APR_RFC822_DATE_LEN: apr_size_t = 30; 12 | 13 | // run this hook first, before ANYTHING 14 | pub const APR_HOOK_REALLY_FIRST: c_int = -10; 15 | // run this hook first 16 | pub const APR_HOOK_FIRST: c_int = 0; 17 | // run this hook somewhere 18 | pub const APR_HOOK_MIDDLE: c_int = 10; 19 | // run this hook after every other hook which is defined 20 | pub const APR_HOOK_LAST: c_int = 20; 21 | // run this hook last, after EVERYTHING 22 | pub const APR_HOOK_REALLY_LAST: c_int = 30; 23 | 24 | pub type sockaddr_in = c_void; 25 | pub type sockaddr_in6 = c_void; 26 | pub type sockaddr_storage = c_void; 27 | pub type conn_state_t = c_void; 28 | 29 | pub type apr_byte_t = c_uchar; 30 | pub type apr_int16_t = c_short; 31 | pub type apr_uint16_t = c_ushort; 32 | pub type apr_int32_t = c_int; 33 | pub type apr_uint32_t = c_uint; 34 | pub type apr_int64_t = c_long; 35 | pub type apr_uint64_t = c_ulong; 36 | pub type apr_size_t = c_ulong; 37 | pub type apr_ssize_t = c_long; 38 | pub type apr_off_t = c_long; 39 | pub type apr_socklen_t = c_uint; 40 | pub type apr_ino_t = c_ulong; 41 | pub type apr_uintptr_t = apr_uint64_t; 42 | pub type apr_status_t = c_int; 43 | pub type apr_signum_t = c_int; 44 | pub type apr_read_type_e = c_uint; 45 | pub type apr_bucket_is_metadata_t = c_uint; 46 | pub type apr_filetype_e = c_uint; 47 | pub type apr_uid_t = c_uint; 48 | pub type apr_gid_t = c_uint; 49 | pub type apr_dev_t = c_ulong; 50 | pub type apr_fileperms_t = apr_int32_t; 51 | pub type apr_time_t = apr_int64_t; 52 | pub type apr_interval_time_t = apr_int64_t; 53 | pub type apr_port_t = apr_uint16_t; 54 | 55 | #[repr(C)] 56 | #[derive(Copy, Clone)] 57 | pub struct apr_array_header_t { 58 | pub pool: *mut apr_pool_t, 59 | pub elt_size: c_int, 60 | pub nelts: c_int, 61 | pub nalloc: c_int, 62 | pub elts: *mut c_char, 63 | } 64 | 65 | #[repr(C)] 66 | #[derive(Copy, Clone)] 67 | pub struct apr_table_entry_t { 68 | pub key: *mut c_char, 69 | pub val: *mut c_char, 70 | pub key_checksum: apr_uint32_t, 71 | } 72 | 73 | #[repr(C)] 74 | #[derive(Copy, Clone)] 75 | pub struct apr_bucket_brigade { 76 | pub p: *mut apr_pool_t, 77 | pub list: apr_bucket_list, 78 | pub bucket_alloc: *mut apr_bucket_alloc_t, 79 | } 80 | 81 | #[repr(C)] 82 | #[derive(Copy, Clone)] 83 | pub struct apr_bucket_list { 84 | pub next: *mut apr_bucket, 85 | pub prev: *mut apr_bucket, 86 | } 87 | 88 | #[repr(C)] 89 | #[derive(Copy, Clone)] 90 | pub struct apr_bucket { 91 | pub link: apr_bucket_list, 92 | pub _type: *const apr_bucket_type_t, 93 | pub length: apr_size_t, 94 | pub start: apr_off_t, 95 | pub data: *mut c_void, 96 | pub free: Option ()>, 97 | pub list: *mut apr_bucket_alloc_t, 98 | } 99 | 100 | #[repr(C)] 101 | #[derive(Copy, Clone)] 102 | pub struct apr_bucket_type_t { 103 | pub name: *const c_char, 104 | pub num_func: c_int, 105 | pub is_metadata: apr_bucket_is_metadata_t, 106 | 107 | pub destroy: Option ()>, 110 | 111 | pub read: Option apr_status_t>, 117 | 118 | pub setaside: Option apr_status_t>, 122 | 123 | pub split: Option apr_status_t>, 127 | 128 | pub copy: Option apr_status_t>, 132 | } 133 | 134 | #[repr(C)] 135 | #[derive(Copy, Clone)] 136 | pub struct apr_uri_t { 137 | pub scheme: *mut c_char, 138 | pub hostinfo: *mut c_char, 139 | pub user: *mut c_char, 140 | pub password: *mut c_char, 141 | pub hostname: *mut c_char, 142 | pub port_str: *mut c_char, 143 | pub path: *mut c_char, 144 | pub query: *mut c_char, 145 | pub fragment: *mut c_char, 146 | pub hostent: *mut hostent, 147 | pub port: apr_port_t, 148 | pub _bindgen_bitfield_1_: c_uint, 149 | } 150 | 151 | #[repr(C)] 152 | #[derive(Copy, Clone)] 153 | pub struct apr_sockaddr_t { 154 | pub pool: *mut apr_pool_t, 155 | pub hostname: *mut c_char, 156 | pub servname: *mut c_char, 157 | pub port: apr_port_t, 158 | pub family: apr_int32_t, 159 | pub salen: apr_socklen_t, 160 | pub ipaddr_len: c_int, 161 | pub addr_str_len: c_int, 162 | pub ipaddr_ptr: *mut c_void, 163 | pub next: *mut apr_sockaddr_t, 164 | pub sa: apr_sockaddr_sa_t, 165 | } 166 | 167 | #[repr(C)] 168 | #[derive(Copy, Clone)] 169 | pub struct apr_sockaddr_sa_t { 170 | pub _bindgen_data_: [u64; 16usize], 171 | } 172 | impl apr_sockaddr_sa_t { 173 | pub unsafe fn sin(&mut self) -> *mut sockaddr_in { 174 | let raw: *mut u8 = mem::transmute(&self._bindgen_data_); 175 | mem::transmute(raw.offset(0)) 176 | } 177 | pub unsafe fn sin6(&mut self) -> *mut sockaddr_in6 { 178 | let raw: *mut u8 = mem::transmute(&self._bindgen_data_); 179 | mem::transmute(raw.offset(0)) 180 | } 181 | pub unsafe fn sas(&mut self) -> *mut sockaddr_storage { 182 | let raw: *mut u8 = mem::transmute(&self._bindgen_data_); 183 | mem::transmute(raw.offset(0)) 184 | } 185 | } 186 | 187 | #[repr(C)] 188 | #[derive(Copy, Clone)] 189 | pub struct apr_finfo_t { 190 | pub pool: *mut apr_pool_t, 191 | pub valid: apr_int32_t, 192 | pub protection: apr_fileperms_t, 193 | pub filetype: apr_filetype_e, 194 | pub user: apr_uid_t, 195 | pub group: apr_gid_t, 196 | pub inode: apr_ino_t, 197 | pub device: apr_dev_t, 198 | pub nlink: apr_int32_t, 199 | pub size: apr_off_t, 200 | pub csize: apr_off_t, 201 | pub atime: apr_time_t, 202 | pub mtime: apr_time_t, 203 | pub ctime: apr_time_t, 204 | pub fname: *const c_char, 205 | pub name: *const c_char, 206 | pub filehand: *mut apr_file_t, 207 | } 208 | 209 | #[derive(Copy, Clone)] 210 | pub enum hostent { } 211 | 212 | #[derive(Copy, Clone)] 213 | pub enum apr_bucket_alloc_t { } 214 | 215 | #[derive(Copy, Clone)] 216 | pub enum apr_pool_t { } 217 | 218 | #[derive(Copy, Clone)] 219 | pub enum apr_table_t { } 220 | 221 | #[derive(Copy, Clone)] 222 | pub enum apr_thread_mutex_t { } 223 | 224 | #[derive(Copy, Clone)] 225 | pub enum apr_thread_t { } 226 | 227 | #[derive(Copy, Clone)] 228 | pub enum apr_file_t { } 229 | 230 | extern "C" { 231 | pub fn apr_version_string() -> *const c_char; 232 | pub fn apu_version_string() -> *const c_char; 233 | 234 | pub fn apr_table_get(t: *const apr_table_t, key: *const c_char) -> *const c_char; 235 | pub fn apr_table_set(t: *mut apr_table_t, key: *const c_char, val: *const c_char) -> (); 236 | pub fn apr_table_add(t: *mut apr_table_t, key: *const c_char, val: *const c_char) -> (); 237 | 238 | pub fn apr_table_elts(t: *const apr_table_t) -> *const apr_array_header_t; 239 | 240 | pub fn apr_pstrmemdup(p: *mut apr_pool_t, s: *const c_char, n: apr_size_t) -> *mut c_char; 241 | pub fn apr_palloc(p: *mut apr_pool_t, size: apr_size_t) -> *mut c_void; 242 | pub fn apr_pcalloc(p: *mut apr_pool_t, size: apr_size_t) -> *mut c_void; 243 | 244 | pub fn apr_base64_encode_len(len: c_int) -> c_int; 245 | pub fn apr_base64_encode(coded_dst: *mut c_char, plain_src: *const c_char, len_plain_src: c_int) -> c_int; 246 | pub fn apr_base64_decode_len(coded_src: *const c_char) -> c_int; 247 | pub fn apr_base64_decode(plain_dst: *mut c_char, coded_src: *const c_char) -> c_int; 248 | 249 | pub fn apr_time_now() -> apr_time_t; 250 | pub fn apr_rfc822_date(date_str: *mut c_char, t: apr_time_t) -> apr_status_t; 251 | } 252 | 253 | pub fn strdup>>(pool: *mut apr_pool_t, data: T) -> *mut c_char { 254 | let bytes = data.into(); 255 | 256 | unsafe { 257 | apr_pstrmemdup( 258 | pool, 259 | bytes.as_ptr() as *const c_char, 260 | bytes.len() as apr_size_t 261 | ) 262 | } 263 | } 264 | 265 | // APACHE HTTPD 266 | 267 | pub const MODULE_MAGIC_COOKIE: c_ulong = 0x41503234u64; /* "AP24" */ 268 | 269 | pub const MODULE_MAGIC_NUMBER_MAJOR: c_int = 20120211; 270 | pub const MODULE_MAGIC_NUMBER_MINOR: c_int = 36; 271 | 272 | pub const OK: c_int = 0; 273 | pub const DECLINED: c_int = -1; 274 | pub const DONE: c_int = -2; 275 | pub const SUSPENDED: c_int = -3; 276 | 277 | pub const HTTP_CONTINUE: c_int = 100; 278 | pub const HTTP_SWITCHING_PROTOCOLS: c_int = 101; 279 | pub const HTTP_PROCESSING: c_int = 102; 280 | pub const HTTP_OK: c_int = 200; 281 | pub const HTTP_CREATED: c_int = 201; 282 | pub const HTTP_ACCEPTED: c_int = 202; 283 | pub const HTTP_NON_AUTHORITATIVE: c_int = 203; 284 | pub const HTTP_NO_CONTENT: c_int = 204; 285 | pub const HTTP_RESET_CONTENT: c_int = 205; 286 | pub const HTTP_PARTIAL_CONTENT: c_int = 206; 287 | pub const HTTP_MULTI_STATUS: c_int = 207; 288 | pub const HTTP_ALREADY_REPORTED: c_int = 208; 289 | pub const HTTP_IM_USED: c_int = 226; 290 | pub const HTTP_MULTIPLE_CHOICES: c_int = 300; 291 | pub const HTTP_MOVED_PERMANENTLY: c_int = 301; 292 | pub const HTTP_MOVED_TEMPORARILY: c_int = 302; 293 | pub const HTTP_SEE_OTHER: c_int = 303; 294 | pub const HTTP_NOT_MODIFIED: c_int = 304; 295 | pub const HTTP_USE_PROXY: c_int = 305; 296 | pub const HTTP_TEMPORARY_REDIRECT: c_int = 307; 297 | pub const HTTP_PERMANENT_REDIRECT: c_int = 308; 298 | pub const HTTP_BAD_REQUEST: c_int = 400; 299 | pub const HTTP_UNAUTHORIZED: c_int = 401; 300 | pub const HTTP_PAYMENT_REQUIRED: c_int = 402; 301 | pub const HTTP_FORBIDDEN: c_int = 403; 302 | pub const HTTP_NOT_FOUND: c_int = 404; 303 | pub const HTTP_METHOD_NOT_ALLOWED: c_int = 405; 304 | pub const HTTP_NOT_ACCEPTABLE: c_int = 406; 305 | pub const HTTP_PROXY_AUTHENTICATION_REQUIRED: c_int = 407; 306 | pub const HTTP_REQUEST_TIME_OUT: c_int = 408; 307 | pub const HTTP_CONFLICT: c_int = 409; 308 | pub const HTTP_GONE: c_int = 410; 309 | pub const HTTP_LENGTH_REQUIRED: c_int = 411; 310 | pub const HTTP_PRECONDITION_FAILED: c_int = 412; 311 | pub const HTTP_REQUEST_ENTITY_TOO_LARGE: c_int = 413; 312 | pub const HTTP_REQUEST_URI_TOO_LARGE: c_int = 414; 313 | pub const HTTP_UNSUPPORTED_MEDIA_TYPE: c_int = 415; 314 | pub const HTTP_RANGE_NOT_SATISFIABLE: c_int = 416; 315 | pub const HTTP_EXPECTATION_FAILED: c_int = 417; 316 | pub const HTTP_IM_A_TEAPOT: c_int = 418; 317 | pub const HTTP_UNPROCESSABLE_ENTITY: c_int = 422; 318 | pub const HTTP_LOCKED: c_int = 423; 319 | pub const HTTP_FAILED_DEPENDENCY: c_int = 424; 320 | pub const HTTP_UPGRADE_REQUIRED: c_int = 426; 321 | pub const HTTP_PRECONDITION_REQUIRED: c_int = 428; 322 | pub const HTTP_TOO_MANY_REQUESTS: c_int = 429; 323 | pub const HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE: c_int = 431; 324 | pub const HTTP_INTERNAL_SERVER_ERROR: c_int = 500; 325 | pub const HTTP_NOT_IMPLEMENTED: c_int = 501; 326 | pub const HTTP_BAD_GATEWAY: c_int = 502; 327 | pub const HTTP_SERVICE_UNAVAILABLE: c_int = 503; 328 | pub const HTTP_GATEWAY_TIME_OUT: c_int = 504; 329 | pub const HTTP_VERSION_NOT_SUPPORTED: c_int = 505; 330 | pub const HTTP_VARIANT_ALSO_VARIES: c_int = 506; 331 | pub const HTTP_INSUFFICIENT_STORAGE: c_int = 507; 332 | pub const HTTP_LOOP_DETECTED: c_int = 508; 333 | pub const HTTP_NOT_EXTENDED: c_int = 510; 334 | pub const HTTP_NETWORK_AUTHENTICATION_REQUIRED: c_int = 511; 335 | 336 | pub const PROXYREQ_NONE: c_int = 0; 337 | pub const PROXYREQ_PROXY: c_int = 1; 338 | pub const PROXYREQ_REVERSE: c_int = 2; 339 | pub const PROXYREQ_RESPONSE: c_int = 3; 340 | 341 | pub const RAW_ARGS: c_uint = 0; 342 | pub const TAKE1: c_uint = 1; 343 | pub const TAKE2: c_uint = 2; 344 | pub const ITERATE: c_uint = 3; 345 | pub const ITERATE2: c_uint = 4; 346 | pub const FLAG: c_uint = 5; 347 | pub const NO_ARGS: c_uint = 6; 348 | pub const TAKE12: c_uint = 7; 349 | pub const TAKE3: c_uint = 8; 350 | pub const TAKE23: c_uint = 9; 351 | pub const TAKE123: c_uint = 10; 352 | pub const TAKE13: c_uint = 11; 353 | pub const TAKE_ARGV: c_uint = 12; 354 | 355 | pub const OR_NONE: c_int = 0; 356 | pub const OR_LIMIT: c_int = 1; 357 | pub const OR_OPTIONS: c_int = 2; 358 | pub const OR_FILEINFO: c_int = 4; 359 | pub const OR_AUTHCFG: c_int = 8; 360 | pub const OR_INDEXES: c_int = 16; 361 | pub const OR_UNSET: c_int = 32; 362 | pub const ACCESS_CONF: c_int = 64; 363 | pub const RSRC_CONF: c_int = 128; 364 | pub const EXEC_ON_READ: c_int = 256; 365 | pub const NONFATAL_OVERRIDE: c_int = 512; 366 | pub const NONFATAL_UNKNOWN: c_int = 1024; 367 | pub const NONFATAL_ALL: c_int = NONFATAL_OVERRIDE | NONFATAL_UNKNOWN; 368 | pub const OR_ALL: c_int = OR_LIMIT | OR_OPTIONS | OR_FILEINFO | OR_AUTHCFG | OR_INDEXES; 369 | 370 | #[repr(C)] 371 | #[derive(Copy, Clone)] 372 | pub struct request_rec { 373 | pub pool: *mut apr_pool_t, 374 | pub connection: *mut conn_rec, 375 | pub server: *mut server_rec, 376 | pub next: *mut request_rec, 377 | pub prev: *mut request_rec, 378 | pub main: *mut request_rec, 379 | pub the_request: *mut c_char, 380 | pub assbackwards: c_int, 381 | pub proxyreq: c_int, 382 | pub header_only: c_int, 383 | pub proto_num: c_int, 384 | pub protocol: *mut c_char, 385 | pub hostname: *const c_char, 386 | pub request_time: apr_time_t, 387 | pub status_line: *const c_char, 388 | pub status: c_int, 389 | pub method_number: c_int, 390 | pub method: *const c_char, 391 | pub allowed: apr_int64_t, 392 | pub allowed_xmethods: *mut apr_array_header_t, 393 | pub allowed_methods: *mut ap_method_list_t, 394 | pub sent_bodyct: apr_off_t, 395 | pub bytes_sent: apr_off_t, 396 | pub mtime: apr_time_t, 397 | pub range: *const c_char, 398 | pub clength: apr_off_t, 399 | pub chunked: c_int, 400 | pub read_body: c_int, 401 | pub read_chunked: c_int, 402 | pub expecting_100: c_uint, 403 | pub kept_body: *mut apr_bucket_brigade, 404 | pub body_table: *mut apr_table_t, 405 | pub remaining: apr_off_t, 406 | pub read_length: apr_off_t, 407 | pub headers_in: *mut apr_table_t, 408 | pub headers_out: *mut apr_table_t, 409 | pub err_headers_out: *mut apr_table_t, 410 | pub subprocess_env: *mut apr_table_t, 411 | pub notes: *mut apr_table_t, 412 | pub content_type: *const c_char, 413 | pub handler: *const c_char, 414 | pub content_encoding: *const c_char, 415 | pub content_languages: *mut apr_array_header_t, 416 | pub vlist_validator: *mut c_char, 417 | pub user: *mut c_char, 418 | pub ap_auth_type: *mut c_char, 419 | pub unparsed_uri: *mut c_char, 420 | pub uri: *mut c_char, 421 | pub filename: *mut c_char, 422 | pub canonical_filename: *mut c_char, 423 | pub path_info: *mut c_char, 424 | pub args: *mut c_char, 425 | pub used_path_info: c_int, 426 | pub eos_sent: c_int, 427 | pub per_dir_config: *mut ap_conf_vector_t, 428 | pub request_config: *mut ap_conf_vector_t, 429 | pub log: *const ap_logconf, 430 | pub log_id: *const c_char, 431 | pub htaccess: *const htaccess_result, 432 | pub output_filters: *mut ap_filter_t, 433 | pub input_filters: *mut ap_filter_t, 434 | pub proto_output_filters: *mut ap_filter_t, 435 | pub proto_input_filters: *mut ap_filter_t, 436 | pub no_cache: c_int, 437 | pub no_local_copy: c_int, 438 | pub invoke_mtx: *mut apr_thread_mutex_t, 439 | pub parsed_uri: apr_uri_t, 440 | pub finfo: apr_finfo_t, 441 | pub useragent_addr: *mut apr_sockaddr_t, 442 | pub useragent_ip: *mut c_char, 443 | pub trailers_in: *mut apr_table_t, 444 | pub trailers_out: *mut apr_table_t, 445 | } 446 | 447 | #[repr(C)] 448 | #[derive(Copy, Clone)] 449 | pub struct conn_rec { 450 | pub pool: *mut apr_pool_t, 451 | pub base_server: *mut server_rec, 452 | pub vhost_lookup_data: *mut c_void, 453 | pub local_addr: *mut apr_sockaddr_t, 454 | pub client_addr: *mut apr_sockaddr_t, 455 | pub client_ip: *mut c_char, 456 | pub remote_host: *mut c_char, 457 | pub remote_logname: *mut c_char, 458 | pub local_ip: *mut c_char, 459 | pub local_host: *mut c_char, 460 | pub id: c_long, 461 | pub conn_config: *mut ap_conf_vector_t, 462 | pub notes: *mut apr_table_t, 463 | pub input_filters: *mut ap_filter_t, 464 | pub output_filters: *mut ap_filter_t, 465 | pub sbh: *mut c_void, 466 | pub bucket_alloc: *mut apr_bucket_alloc_t, 467 | pub cs: *mut conn_state_t, 468 | pub data_in_input_filters: c_int, 469 | pub data_in_output_filters: c_int, 470 | pub _bindgen_bitfield_1_: c_uint, 471 | pub _bindgen_bitfield_2_: c_int, 472 | pub aborted: c_uint, 473 | pub keepalive: ap_conn_keepalive_e, 474 | pub keepalives: c_int, 475 | pub log: *const ap_logconf, 476 | pub log_id: *const c_char, 477 | pub current_thread: *mut apr_thread_t, 478 | } 479 | 480 | #[repr(C)] 481 | #[derive(Copy, Clone)] 482 | pub struct server_rec { 483 | pub process: *mut process_rec, 484 | pub next: *mut server_rec, 485 | pub error_fname: *mut c_char, 486 | pub error_log: *mut apr_file_t, 487 | pub log: ap_logconf, 488 | pub module_config: *mut ap_conf_vector_t, 489 | pub lookup_defaults: *mut ap_conf_vector_t, 490 | pub defn_name: *const c_char, 491 | pub defn_line_number: c_uint, 492 | pub is_virtual: c_char, 493 | pub port: apr_port_t, 494 | pub server_scheme: *const c_char, 495 | pub server_admin: *mut c_char, 496 | pub server_hostname: *mut c_char, 497 | pub addrs: *mut server_addr_rec, 498 | pub timeout: apr_interval_time_t, 499 | pub keep_alive_timeout: apr_interval_time_t, 500 | pub keep_alive_max: c_int, 501 | pub keep_alive: c_int, 502 | pub names: *mut apr_array_header_t, 503 | pub wild_names: *mut apr_array_header_t, 504 | pub path: *const c_char, 505 | pub pathlen: c_int, 506 | pub limit_req_line: c_int, 507 | pub limit_req_fieldsize: c_int, 508 | pub limit_req_fields: c_int, 509 | pub context: *mut c_void, 510 | } 511 | 512 | #[repr(C)] 513 | #[derive(Copy, Clone)] 514 | pub struct ap_logconf { 515 | pub module_levels: *mut c_char, 516 | pub level: c_int, 517 | } 518 | 519 | #[repr(C)] 520 | #[derive(Copy, Clone)] 521 | pub struct module { 522 | pub version: c_int, 523 | pub minor_version: c_int, 524 | pub module_index: c_int, 525 | pub name: *const c_char, 526 | pub dynamic_load_handle: *mut c_void, 527 | pub next: *mut module, 528 | pub magic: c_ulong, 529 | pub rewrite_args: Option, 530 | pub create_dir_config: Option, 531 | pub merge_dir_config: Option, 532 | pub create_server_config: Option, 533 | pub merge_server_config: Option, 534 | pub cmds: *const command_rec, 535 | pub register_hooks: Option 536 | } 537 | 538 | #[repr(C)] 539 | #[derive(Copy, Clone)] 540 | pub struct cmd_func { 541 | pub _bindgen_data_: [u64; 1usize], 542 | } 543 | impl cmd_func { 544 | pub unsafe fn no_args(&mut self) -> *mut Option { 545 | mem::transmute(&self._bindgen_data_) 546 | } 547 | 548 | pub unsafe fn raw_args(&mut self) -> *mut Option { 549 | mem::transmute(&self._bindgen_data_) 550 | } 551 | 552 | pub unsafe fn take_argv(&mut self) -> *mut Option { 553 | mem::transmute(&self._bindgen_data_) 554 | } 555 | 556 | pub unsafe fn take1(&mut self) -> *mut Option { 557 | mem::transmute(&self._bindgen_data_) 558 | } 559 | 560 | pub unsafe fn take2(&mut self) -> *mut Option { 561 | mem::transmute(&self._bindgen_data_) 562 | } 563 | 564 | pub unsafe fn take3(&mut self) -> *mut Option { 565 | mem::transmute(&self._bindgen_data_) 566 | } 567 | 568 | pub unsafe fn flag(&mut self) -> *mut Option { 569 | mem::transmute(&self._bindgen_data_) 570 | } 571 | } 572 | 573 | #[repr(C)] 574 | #[derive(Copy, Clone)] 575 | pub struct command_rec { 576 | pub name: *const c_char, 577 | pub func: cmd_func, 578 | pub cmd_data: *mut c_void, 579 | pub req_override: c_int, 580 | pub args_how: cmd_how, 581 | pub errmsg: *const c_char, 582 | } 583 | 584 | 585 | #[repr(C)] 586 | #[derive(Copy, Clone)] 587 | pub struct cmd_parms { 588 | pub info: *mut c_void, 589 | pub _override: c_int, 590 | pub override_opts: c_int, 591 | pub override_list: *mut apr_table_t, 592 | pub limited: apr_int64_t, 593 | pub limited_xmethods: *mut apr_array_header_t, 594 | pub xlimited: *mut ap_method_list_t, 595 | pub config_file: *mut ap_configfile_t, 596 | pub directive: *mut ap_directive_t, 597 | pub pool: *mut apr_pool_t, 598 | pub temp_pool: *mut apr_pool_t, 599 | pub server: *mut server_rec, 600 | pub path: *mut c_char, 601 | pub cmd: *const command_rec, 602 | pub context: *mut ap_conf_vector_t, 603 | pub err_directive: *const ap_directive_t, 604 | } 605 | 606 | #[repr(C)] 607 | #[derive(Copy, Clone)] 608 | pub struct ap_list_provider_names_t { 609 | pub provider_name: *const c_char, 610 | } 611 | 612 | #[repr(C)] 613 | #[derive(Copy, Clone)] 614 | pub struct ap_list_provider_groups_t { 615 | pub provider_group: *const c_char, 616 | pub provider_version: *const c_char, 617 | } 618 | 619 | #[repr(C)] 620 | #[derive(Copy, Clone)] 621 | pub struct ap_method_list_t { 622 | pub method_mask: apr_int64_t, 623 | pub method_list: *mut apr_array_header_t, 624 | } 625 | 626 | #[repr(C)] 627 | #[derive(Copy, Clone)] 628 | pub struct ap_configfile_t { 629 | pub getch: Option apr_status_t>, 633 | 634 | pub getstr: Option apr_status_t>, 639 | 640 | pub close: Option apr_status_t>, 641 | 642 | pub param: *mut c_void, 643 | pub name: *const c_char, 644 | pub line_number: c_uint, 645 | } 646 | 647 | #[repr(C)] 648 | #[derive(Copy, Clone)] 649 | pub struct ap_directive_t { 650 | pub directive: *const c_char, 651 | pub args: *const c_char, 652 | pub next: *mut ap_directive_t, 653 | pub first_child: *mut ap_directive_t, 654 | pub parent: *mut ap_directive_t, 655 | pub data: *mut c_void, 656 | pub filename: *const c_char, 657 | pub line_num: c_int, 658 | pub last: *mut ap_directive_t, 659 | } 660 | 661 | #[repr(C)] 662 | #[derive(Copy, Clone)] 663 | pub struct htaccess_result { 664 | pub dir: *const c_char, 665 | pub _override: c_int, 666 | pub override_opts: c_int, 667 | pub override_list: *mut apr_table_t, 668 | pub htaccess: *mut ap_conf_vector_t, 669 | pub next: *const htaccess_result, 670 | } 671 | 672 | #[repr(C)] 673 | #[derive(Copy, Clone)] 674 | pub struct process_rec { 675 | pub pool: *mut apr_pool_t, 676 | pub pconf: *mut apr_pool_t, 677 | pub short_name: *const c_char, 678 | pub argv: *const *const c_char, 679 | pub argc: c_int, 680 | } 681 | 682 | #[repr(C)] 683 | #[derive(Copy, Clone)] 684 | pub struct server_addr_rec { 685 | pub next: *mut server_addr_rec, 686 | pub virthost: *mut c_char, 687 | pub host_addr: *mut apr_sockaddr_t, 688 | pub host_port: apr_port_t, 689 | } 690 | 691 | #[repr(C)] 692 | #[derive(Copy, Clone)] 693 | pub struct ap_filter_t { 694 | pub frec: *mut ap_filter_rec_t, 695 | pub ctx: *mut c_void, 696 | pub next: *mut ap_filter_t, 697 | pub r: *mut request_rec, 698 | pub c: *mut conn_rec, 699 | } 700 | 701 | #[repr(C)] 702 | #[derive(Copy, Clone)] 703 | pub struct ap_filter_rec_t { 704 | pub name: *const c_char, 705 | pub filter_func: ap_filter_func, 706 | pub filter_init_func: Option, 707 | pub next: *mut ap_filter_rec_t, 708 | pub providers: *mut ap_filter_provider_t, 709 | pub ftype: ap_filter_type, 710 | pub debug: c_int, 711 | pub proto_flags: c_uint, 712 | } 713 | 714 | #[repr(C)] 715 | #[derive(Copy, Clone)] 716 | pub struct ap_filter_func { 717 | pub _bindgen_data_: [u64; 1usize], 718 | } 719 | impl ap_filter_func { 720 | pub unsafe fn out_func(&mut self) -> *mut Option { 721 | let raw: *mut u8 = mem::transmute(&self._bindgen_data_); 722 | mem::transmute(raw.offset(0)) 723 | } 724 | pub unsafe fn in_func(&mut self) -> *mut Option { 725 | let raw: *mut u8 = mem::transmute(&self._bindgen_data_); 726 | mem::transmute(raw.offset(0)) 727 | } 728 | } 729 | 730 | #[derive(Copy, Clone)] 731 | pub enum ap_conf_vector_t { } 732 | 733 | #[derive(Copy, Clone)] 734 | pub enum ap_filter_provider_t { } 735 | 736 | pub type cmd_how = c_uint; 737 | 738 | pub type ap_conn_keepalive_e = c_uint; 739 | 740 | pub type ap_filter_type = c_uint; 741 | 742 | pub type ap_input_mode_t = c_uint; 743 | 744 | pub type ap_init_filter_func = extern "C" fn(f: *mut ap_filter_t) -> c_int; 745 | 746 | pub type ap_out_filter_func = extern "C" fn( 747 | f: *mut ap_filter_t, 748 | b: *mut apr_bucket_brigade 749 | ) -> apr_status_t; 750 | 751 | pub type ap_in_filter_func = extern "C" fn( 752 | f: *mut ap_filter_t, 753 | b: *mut apr_bucket_brigade, 754 | mode: ap_input_mode_t, 755 | block: apr_read_type_e, 756 | readbytes: apr_off_t 757 | ) -> apr_status_t; 758 | 759 | pub type rewrite_args_fn = extern "C" fn( 760 | process: *mut process_rec 761 | ); 762 | 763 | pub type create_dir_config_fn = extern "C" fn(p: *mut apr_pool_t, dir: *mut c_char) -> *mut c_void; 764 | pub type merge_config_fn = extern "C" fn(p: *mut apr_pool_t, base_conf: *mut c_void, new_conf: *mut c_void) -> *mut c_void; 765 | pub type create_server_config_fn = extern "C" fn(p: *mut apr_pool_t, s: *mut server_rec) -> *mut c_void; 766 | 767 | pub type register_hooks_fn = extern "C" fn(p: *mut apr_pool_t); 768 | 769 | pub type no_args_fn = extern "C" fn(parms: *mut cmd_parms, mconfig: *mut c_void) -> *const c_char; 770 | pub type raw_args_fn = extern "C" fn(parms: *mut cmd_parms, mconfig: *mut c_void, args: *const c_char) -> *const c_char; 771 | pub type take_argv_fn = extern "C" fn(parms: *mut cmd_parms, mconfig: *mut c_void, argc: c_int, argv: *const *mut c_char) -> *const c_char; 772 | pub type take1_fn = extern "C" fn(parms: *mut cmd_parms, mconfig: *mut c_void, w: *const c_char) -> *const c_char; 773 | pub type take2_fn = extern "C" fn(parms: *mut cmd_parms, mconfig: *mut c_void, w: *const c_char, w2: *const c_char) -> *const c_char; 774 | pub type take3_fn = extern "C" fn(parms: *mut cmd_parms, mconfig: *mut c_void, w: *const c_char, w2: *const c_char, w3: *const c_char) -> *const c_char; 775 | pub type flag_fn = extern "C" fn(parms: *mut cmd_parms, mconfig: *mut c_void, on: c_int) -> *const c_char; 776 | 777 | pub type hook_handler_fn = extern "C" fn(r: *mut request_rec) -> c_int; 778 | pub type hook_pre_config_fn = extern "C" fn(conf: *mut apr_pool_t, log: *mut apr_pool_t, temp: *mut apr_pool_t) -> c_int; 779 | pub type hook_check_config_fn = extern "C" fn(conf: *mut apr_pool_t, log: *mut apr_pool_t, temp: *mut apr_pool_t, s: *mut server_rec) -> c_int; 780 | pub type hook_test_config_fn = extern "C" fn(conf: *mut apr_pool_t, s: *mut server_rec) -> c_int; 781 | pub type hook_post_config_fn = extern "C" fn(conf: *mut apr_pool_t, log: *mut apr_pool_t, temp: *mut apr_pool_t, s: *mut server_rec) -> c_int; 782 | 783 | 784 | extern "C" { 785 | pub fn ap_get_server_banner() -> *const c_char; 786 | pub fn ap_get_server_description() -> *const c_char; 787 | pub fn ap_get_server_built() -> *const c_char; 788 | 789 | pub fn ap_show_mpm() -> *const c_char; 790 | 791 | pub fn ap_escape_html2(p: *mut apr_pool_t, s: *const c_char, toasc: c_int) -> *mut c_char; 792 | 793 | pub fn ap_rwrite(buf: *const c_void, nbyte: c_int, r: *const request_rec) -> c_int; 794 | pub fn ap_set_content_type(r: *const request_rec, ct: *const c_char) -> (); 795 | pub fn ap_get_basic_auth_pw(r: *const request_rec, pw: *mut *const c_char) -> c_int; 796 | 797 | pub fn ap_context_document_root(r: *const request_rec) -> *const c_char; 798 | pub fn ap_context_prefix(r: *const request_rec) -> *const c_char; 799 | 800 | pub fn ap_run_http_scheme(r: *const request_rec) -> *const c_char; 801 | pub fn ap_run_default_port(r: *const request_rec) -> apr_port_t; 802 | 803 | pub fn ap_is_initial_req(r: *const request_rec) -> c_int; 804 | 805 | pub fn ap_some_auth_required(r: *const request_rec) -> c_int; 806 | 807 | pub fn ap_cookie_read(r: *const request_rec, name: *const c_char, val: *mut *const c_char, remove: c_int) -> apr_status_t; 808 | pub fn ap_cookie_write(r: *const request_rec, name: *const c_char, val: *const c_char, attrs: *const c_char, maxage: c_int, ...) -> apr_status_t; 809 | 810 | pub fn ap_escape_urlencoded(p: *mut apr_pool_t, s: *const c_char) -> *mut c_char; 811 | pub fn ap_unescape_urlencoded(query: *mut c_char) -> c_int; 812 | 813 | pub fn ap_document_root(r: *const request_rec) -> *const c_char; 814 | pub fn ap_get_server_name(r: *const request_rec) -> *const c_char; 815 | pub fn ap_get_server_port(r: *const request_rec) -> apr_port_t; 816 | pub fn ap_auth_name(r: *const request_rec) -> *const c_char; 817 | 818 | pub fn ap_set_last_modified(r: *mut request_rec) -> (); 819 | pub fn ap_update_mtime(r: *mut request_rec, dependency_mtime: apr_time_t) -> (); 820 | 821 | pub fn ap_get_module_config(cv: *const ap_conf_vector_t, m: *const module) -> *mut c_void; 822 | pub fn ap_set_module_config(cv: *mut ap_conf_vector_t, m: *const module, val: *mut c_void) -> (); 823 | 824 | pub fn ap_register_provider(pool: *mut apr_pool_t, provider_group: *const c_char, provider_name: *const c_char, provider_version: *const c_char, provider: *const c_void) -> apr_status_t; 825 | pub fn ap_lookup_provider(provider_group: *const c_char, provider_name: *const c_char, provider_version: *const c_char) -> *mut c_void; 826 | pub fn ap_list_provider_names(pool: *mut apr_pool_t, provider_group: *const c_char, provider_version: *const c_char) -> *mut apr_array_header_t; 827 | pub fn ap_list_provider_groups(pool: *mut apr_pool_t) -> *mut apr_array_header_t; 828 | 829 | pub fn ap_hook_handler(f: Option, pre: *const *const c_char, succ: *const *const c_char, order: c_int); 830 | pub fn ap_hook_pre_config(f: Option, pre: *const *const c_char, succ: *const *const c_char, order: c_int); 831 | pub fn ap_hook_check_config(f: Option, pre: *const *const c_char, succ: *const *const c_char, order: c_int); 832 | pub fn ap_hook_test_config(f: Option, pre: *const *const c_char, succ: *const *const c_char, order: c_int); 833 | pub fn ap_hook_post_config(f: Option, pre: *const *const c_char, succ: *const *const c_char, order: c_int); 834 | pub fn ap_hook_create_request(f: Option, pre: *const *const c_char, succ: *const *const c_char, order: c_int); 835 | pub fn ap_hook_translate_name(f: Option, pre: *const *const c_char, succ: *const *const c_char, order: c_int); 836 | pub fn ap_hook_map_to_storage(f: Option, pre: *const *const c_char, succ: *const *const c_char, order: c_int); 837 | pub fn ap_hook_check_user_id(f: Option, pre: *const *const c_char, succ: *const *const c_char, order: c_int); 838 | pub fn ap_hook_fixups(f: Option, pre: *const *const c_char, succ: *const *const c_char, order: c_int); 839 | pub fn ap_hook_type_checker(f: Option, pre: *const *const c_char, succ: *const *const c_char, order: c_int); 840 | pub fn ap_hook_access_checker(f: Option, pre: *const *const c_char, succ: *const *const c_char, order: c_int); 841 | pub fn ap_hook_access_checker_ex(f: Option, pre: *const *const c_char, succ: *const *const c_char, order: c_int); 842 | pub fn ap_hook_auth_checker(f: Option, pre: *const *const c_char, succ: *const *const c_char, order: c_int); 843 | pub fn ap_hook_insert_error_filter(f: Option, pre: *const *const c_char, succ: *const *const c_char, order: c_int); 844 | pub fn ap_hook_log_transaction(f: Option, pre: *const *const c_char, succ: *const *const c_char, order: c_int); 845 | } 846 | -------------------------------------------------------------------------------- /src/httpd.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_camel_case_types)] 2 | #![allow(unused_unsafe)] 3 | 4 | use libc::{c_void, c_int, c_char}; 5 | 6 | use std::{fmt, ptr}; 7 | use std::ffi::CString; 8 | use std::marker::PhantomData; 9 | 10 | use ffi; 11 | 12 | use wrapper::{Wrapper, from_char_ptr, FromRaw}; 13 | 14 | use apr::{Table, Pool, ArrayHeaderIter}; 15 | use cookie::Cookie; 16 | 17 | 18 | macro_rules! field { 19 | ($that:ident, $field:ident) => { 20 | unsafe { (*$that.ptr).$field } 21 | }; 22 | } 23 | 24 | macro_rules! set_field { 25 | ($that:ident, $field:ident, $value:expr) => { 26 | unsafe { (*$that.ptr).$field = $value } 27 | }; 28 | } 29 | 30 | macro_rules! option_getter { 31 | ($name:ident, $wrapped:ident) => { 32 | pub fn $name(&self) -> Option<$wrapped> { 33 | $wrapped::from_raw(field!(self, $name)) 34 | } 35 | } 36 | } 37 | 38 | macro_rules! type_getter { 39 | ($name:ident, $restype:ident) => { 40 | pub fn $name(&self) -> $restype { 41 | field!(self, $name) as $restype 42 | } 43 | } 44 | } 45 | 46 | macro_rules! into_getter { 47 | ($name:ident, $restype:ident) => { 48 | pub fn $name(&self) -> $restype { 49 | field!(self, $name).into() 50 | } 51 | } 52 | } 53 | 54 | macro_rules! str_getter { 55 | ($name:ident) => { 56 | pub fn $name<'a>(&self) -> Option<&'a str> { 57 | from_char_ptr(field!(self, $name)) 58 | } 59 | } 60 | } 61 | 62 | macro_rules! bool_getter { 63 | ($name:ident) => { 64 | pub fn $name(&self) -> bool { 65 | field!(self, $name) != 0 66 | } 67 | } 68 | } 69 | 70 | pub enum Status { 71 | // non-HTTP status codes returned by hooks 72 | OK, // Module has handled this stage. 73 | DECLINED, // Module declines to handle 74 | DONE, // Module has served the response completely 75 | // - it's safe to die() with no more output 76 | SUSPENDED, // Module will handle the remainder of the request. 77 | // The core will never invoke the request again, 78 | 79 | HTTP_CONTINUE, 80 | HTTP_SWITCHING_PROTOCOLS, 81 | HTTP_PROCESSING, 82 | HTTP_OK, 83 | HTTP_CREATED, 84 | HTTP_ACCEPTED, 85 | HTTP_NON_AUTHORITATIVE, 86 | HTTP_NO_CONTENT, 87 | HTTP_RESET_CONTENT, 88 | HTTP_PARTIAL_CONTENT, 89 | HTTP_MULTI_STATUS, 90 | HTTP_ALREADY_REPORTED, 91 | HTTP_IM_USED, 92 | HTTP_MULTIPLE_CHOICES, 93 | HTTP_MOVED_PERMANENTLY, 94 | HTTP_MOVED_TEMPORARILY, 95 | HTTP_SEE_OTHER, 96 | HTTP_NOT_MODIFIED, 97 | HTTP_USE_PROXY, 98 | HTTP_TEMPORARY_REDIRECT, 99 | HTTP_PERMANENT_REDIRECT, 100 | HTTP_BAD_REQUEST, 101 | HTTP_UNAUTHORIZED, 102 | HTTP_PAYMENT_REQUIRED, 103 | HTTP_FORBIDDEN, 104 | HTTP_NOT_FOUND, 105 | HTTP_METHOD_NOT_ALLOWED, 106 | HTTP_NOT_ACCEPTABLE, 107 | HTTP_PROXY_AUTHENTICATION_REQUIRED, 108 | HTTP_REQUEST_TIME_OUT, 109 | HTTP_CONFLICT, 110 | HTTP_GONE, 111 | HTTP_LENGTH_REQUIRED, 112 | HTTP_PRECONDITION_FAILED, 113 | HTTP_REQUEST_ENTITY_TOO_LARGE, 114 | HTTP_REQUEST_URI_TOO_LARGE, 115 | HTTP_UNSUPPORTED_MEDIA_TYPE, 116 | HTTP_RANGE_NOT_SATISFIABLE, 117 | HTTP_EXPECTATION_FAILED, 118 | HTTP_IM_A_TEAPOT, 119 | HTTP_UNPROCESSABLE_ENTITY, 120 | HTTP_LOCKED, 121 | HTTP_FAILED_DEPENDENCY, 122 | HTTP_UPGRADE_REQUIRED, 123 | HTTP_PRECONDITION_REQUIRED, 124 | HTTP_TOO_MANY_REQUESTS, 125 | HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, 126 | HTTP_INTERNAL_SERVER_ERROR, 127 | HTTP_NOT_IMPLEMENTED, 128 | HTTP_BAD_GATEWAY, 129 | HTTP_SERVICE_UNAVAILABLE, 130 | HTTP_GATEWAY_TIME_OUT, 131 | HTTP_VERSION_NOT_SUPPORTED, 132 | HTTP_VARIANT_ALSO_VARIES, 133 | HTTP_INSUFFICIENT_STORAGE, 134 | HTTP_LOOP_DETECTED, 135 | HTTP_NOT_EXTENDED, 136 | HTTP_NETWORK_AUTHENTICATION_REQUIRED, 137 | } 138 | 139 | impl Into for Status { 140 | fn into(self) -> c_int { 141 | match self { 142 | Status::OK => ffi::OK, 143 | Status::DECLINED => ffi::DECLINED, 144 | Status::DONE => ffi::DONE, 145 | Status::SUSPENDED => ffi::SUSPENDED, 146 | 147 | Status::HTTP_CONTINUE => ffi::HTTP_CONTINUE, 148 | Status::HTTP_SWITCHING_PROTOCOLS => ffi::HTTP_SWITCHING_PROTOCOLS, 149 | Status::HTTP_PROCESSING => ffi::HTTP_PROCESSING, 150 | Status::HTTP_OK => ffi::HTTP_OK, 151 | Status::HTTP_CREATED => ffi::HTTP_CREATED, 152 | Status::HTTP_ACCEPTED => ffi::HTTP_ACCEPTED, 153 | Status::HTTP_NON_AUTHORITATIVE => ffi::HTTP_NON_AUTHORITATIVE, 154 | Status::HTTP_NO_CONTENT => ffi::HTTP_NO_CONTENT, 155 | Status::HTTP_RESET_CONTENT => ffi::HTTP_RESET_CONTENT, 156 | Status::HTTP_PARTIAL_CONTENT => ffi::HTTP_PARTIAL_CONTENT, 157 | Status::HTTP_MULTI_STATUS => ffi::HTTP_MULTI_STATUS, 158 | Status::HTTP_ALREADY_REPORTED => ffi::HTTP_ALREADY_REPORTED, 159 | Status::HTTP_IM_USED => ffi::HTTP_IM_USED, 160 | Status::HTTP_MULTIPLE_CHOICES => ffi::HTTP_MULTIPLE_CHOICES, 161 | Status::HTTP_MOVED_PERMANENTLY => ffi::HTTP_MOVED_PERMANENTLY, 162 | Status::HTTP_MOVED_TEMPORARILY => ffi::HTTP_MOVED_TEMPORARILY, 163 | Status::HTTP_SEE_OTHER => ffi::HTTP_SEE_OTHER, 164 | Status::HTTP_NOT_MODIFIED => ffi::HTTP_NOT_MODIFIED, 165 | Status::HTTP_USE_PROXY => ffi::HTTP_USE_PROXY, 166 | Status::HTTP_TEMPORARY_REDIRECT => ffi::HTTP_TEMPORARY_REDIRECT, 167 | Status::HTTP_PERMANENT_REDIRECT => ffi::HTTP_PERMANENT_REDIRECT, 168 | Status::HTTP_BAD_REQUEST => ffi::HTTP_BAD_REQUEST, 169 | Status::HTTP_UNAUTHORIZED => ffi::HTTP_UNAUTHORIZED, 170 | Status::HTTP_PAYMENT_REQUIRED => ffi::HTTP_PAYMENT_REQUIRED, 171 | Status::HTTP_FORBIDDEN => ffi::HTTP_FORBIDDEN, 172 | Status::HTTP_NOT_FOUND => ffi::HTTP_NOT_FOUND, 173 | Status::HTTP_METHOD_NOT_ALLOWED => ffi::HTTP_METHOD_NOT_ALLOWED, 174 | Status::HTTP_NOT_ACCEPTABLE => ffi::HTTP_NOT_ACCEPTABLE, 175 | Status::HTTP_PROXY_AUTHENTICATION_REQUIRED => ffi::HTTP_PROXY_AUTHENTICATION_REQUIRED, 176 | Status::HTTP_REQUEST_TIME_OUT => ffi::HTTP_REQUEST_TIME_OUT, 177 | Status::HTTP_CONFLICT => ffi::HTTP_CONFLICT, 178 | Status::HTTP_GONE => ffi::HTTP_GONE, 179 | Status::HTTP_LENGTH_REQUIRED => ffi::HTTP_LENGTH_REQUIRED, 180 | Status::HTTP_PRECONDITION_FAILED => ffi::HTTP_PRECONDITION_FAILED, 181 | Status::HTTP_REQUEST_ENTITY_TOO_LARGE => ffi::HTTP_REQUEST_ENTITY_TOO_LARGE, 182 | Status::HTTP_REQUEST_URI_TOO_LARGE => ffi::HTTP_REQUEST_URI_TOO_LARGE, 183 | Status::HTTP_UNSUPPORTED_MEDIA_TYPE => ffi::HTTP_UNSUPPORTED_MEDIA_TYPE, 184 | Status::HTTP_RANGE_NOT_SATISFIABLE => ffi::HTTP_RANGE_NOT_SATISFIABLE, 185 | Status::HTTP_EXPECTATION_FAILED => ffi::HTTP_EXPECTATION_FAILED, 186 | Status::HTTP_IM_A_TEAPOT => ffi::HTTP_IM_A_TEAPOT, 187 | Status::HTTP_UNPROCESSABLE_ENTITY => ffi::HTTP_UNPROCESSABLE_ENTITY, 188 | Status::HTTP_LOCKED => ffi::HTTP_LOCKED, 189 | Status::HTTP_FAILED_DEPENDENCY => ffi::HTTP_FAILED_DEPENDENCY, 190 | Status::HTTP_UPGRADE_REQUIRED => ffi::HTTP_UPGRADE_REQUIRED, 191 | Status::HTTP_PRECONDITION_REQUIRED => ffi::HTTP_PRECONDITION_REQUIRED, 192 | Status::HTTP_TOO_MANY_REQUESTS => ffi::HTTP_TOO_MANY_REQUESTS, 193 | Status::HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE => ffi::HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, 194 | Status::HTTP_INTERNAL_SERVER_ERROR => ffi::HTTP_INTERNAL_SERVER_ERROR, 195 | Status::HTTP_NOT_IMPLEMENTED => ffi::HTTP_NOT_IMPLEMENTED, 196 | Status::HTTP_BAD_GATEWAY => ffi::HTTP_BAD_GATEWAY, 197 | Status::HTTP_SERVICE_UNAVAILABLE => ffi::HTTP_SERVICE_UNAVAILABLE, 198 | Status::HTTP_GATEWAY_TIME_OUT => ffi::HTTP_GATEWAY_TIME_OUT, 199 | Status::HTTP_VERSION_NOT_SUPPORTED => ffi::HTTP_VERSION_NOT_SUPPORTED, 200 | Status::HTTP_VARIANT_ALSO_VARIES => ffi::HTTP_VARIANT_ALSO_VARIES, 201 | Status::HTTP_INSUFFICIENT_STORAGE => ffi::HTTP_INSUFFICIENT_STORAGE, 202 | Status::HTTP_LOOP_DETECTED => ffi::HTTP_LOOP_DETECTED, 203 | Status::HTTP_NOT_EXTENDED => ffi::HTTP_NOT_EXTENDED, 204 | Status::HTTP_NETWORK_AUTHENTICATION_REQUIRED => ffi::HTTP_NETWORK_AUTHENTICATION_REQUIRED, 205 | } 206 | } 207 | } 208 | 209 | 210 | 211 | impl Into for c_int { 212 | fn into(self) -> Status { 213 | match self { 214 | ffi::OK => Status::OK, 215 | ffi::DECLINED => Status::DECLINED, 216 | ffi::DONE => Status::DONE, 217 | ffi::SUSPENDED => Status::SUSPENDED, 218 | 219 | ffi::HTTP_CONTINUE => Status::HTTP_CONTINUE, 220 | ffi::HTTP_SWITCHING_PROTOCOLS => Status::HTTP_SWITCHING_PROTOCOLS, 221 | ffi::HTTP_PROCESSING => Status::HTTP_PROCESSING, 222 | ffi::HTTP_OK => Status::HTTP_OK, 223 | ffi::HTTP_CREATED => Status::HTTP_CREATED, 224 | ffi::HTTP_ACCEPTED => Status::HTTP_ACCEPTED, 225 | ffi::HTTP_NON_AUTHORITATIVE => Status::HTTP_NON_AUTHORITATIVE, 226 | ffi::HTTP_NO_CONTENT => Status::HTTP_NO_CONTENT, 227 | ffi::HTTP_RESET_CONTENT => Status::HTTP_RESET_CONTENT, 228 | ffi::HTTP_PARTIAL_CONTENT => Status::HTTP_PARTIAL_CONTENT, 229 | ffi::HTTP_MULTI_STATUS => Status::HTTP_MULTI_STATUS, 230 | ffi::HTTP_ALREADY_REPORTED => Status::HTTP_ALREADY_REPORTED, 231 | ffi::HTTP_IM_USED => Status::HTTP_IM_USED, 232 | ffi::HTTP_MULTIPLE_CHOICES => Status::HTTP_MULTIPLE_CHOICES, 233 | ffi::HTTP_MOVED_PERMANENTLY => Status::HTTP_MOVED_PERMANENTLY, 234 | ffi::HTTP_MOVED_TEMPORARILY => Status::HTTP_MOVED_TEMPORARILY, 235 | ffi::HTTP_SEE_OTHER => Status::HTTP_SEE_OTHER, 236 | ffi::HTTP_NOT_MODIFIED => Status::HTTP_NOT_MODIFIED, 237 | ffi::HTTP_USE_PROXY => Status::HTTP_USE_PROXY, 238 | ffi::HTTP_TEMPORARY_REDIRECT => Status::HTTP_TEMPORARY_REDIRECT, 239 | ffi::HTTP_PERMANENT_REDIRECT => Status::HTTP_PERMANENT_REDIRECT, 240 | ffi::HTTP_BAD_REQUEST => Status::HTTP_BAD_REQUEST, 241 | ffi::HTTP_UNAUTHORIZED => Status::HTTP_UNAUTHORIZED, 242 | ffi::HTTP_PAYMENT_REQUIRED => Status::HTTP_PAYMENT_REQUIRED, 243 | ffi::HTTP_FORBIDDEN => Status::HTTP_FORBIDDEN, 244 | ffi::HTTP_NOT_FOUND => Status::HTTP_NOT_FOUND, 245 | ffi::HTTP_METHOD_NOT_ALLOWED => Status::HTTP_METHOD_NOT_ALLOWED, 246 | ffi::HTTP_NOT_ACCEPTABLE => Status::HTTP_NOT_ACCEPTABLE, 247 | ffi::HTTP_PROXY_AUTHENTICATION_REQUIRED => Status::HTTP_PROXY_AUTHENTICATION_REQUIRED, 248 | ffi::HTTP_REQUEST_TIME_OUT => Status::HTTP_REQUEST_TIME_OUT, 249 | ffi::HTTP_CONFLICT => Status::HTTP_CONFLICT, 250 | ffi::HTTP_GONE => Status::HTTP_GONE, 251 | ffi::HTTP_LENGTH_REQUIRED => Status::HTTP_LENGTH_REQUIRED, 252 | ffi::HTTP_PRECONDITION_FAILED => Status::HTTP_PRECONDITION_FAILED, 253 | ffi::HTTP_REQUEST_ENTITY_TOO_LARGE => Status::HTTP_REQUEST_ENTITY_TOO_LARGE, 254 | ffi::HTTP_REQUEST_URI_TOO_LARGE => Status::HTTP_REQUEST_URI_TOO_LARGE, 255 | ffi::HTTP_UNSUPPORTED_MEDIA_TYPE => Status::HTTP_UNSUPPORTED_MEDIA_TYPE, 256 | ffi::HTTP_RANGE_NOT_SATISFIABLE => Status::HTTP_RANGE_NOT_SATISFIABLE, 257 | ffi::HTTP_EXPECTATION_FAILED => Status::HTTP_EXPECTATION_FAILED, 258 | ffi::HTTP_IM_A_TEAPOT => Status::HTTP_IM_A_TEAPOT, 259 | ffi::HTTP_UNPROCESSABLE_ENTITY => Status::HTTP_UNPROCESSABLE_ENTITY, 260 | ffi::HTTP_LOCKED => Status::HTTP_LOCKED, 261 | ffi::HTTP_FAILED_DEPENDENCY => Status::HTTP_FAILED_DEPENDENCY, 262 | ffi::HTTP_UPGRADE_REQUIRED => Status::HTTP_UPGRADE_REQUIRED, 263 | ffi::HTTP_PRECONDITION_REQUIRED => Status::HTTP_PRECONDITION_REQUIRED, 264 | ffi::HTTP_TOO_MANY_REQUESTS => Status::HTTP_TOO_MANY_REQUESTS, 265 | ffi::HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE => Status::HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, 266 | ffi::HTTP_INTERNAL_SERVER_ERROR => Status::HTTP_INTERNAL_SERVER_ERROR, 267 | ffi::HTTP_NOT_IMPLEMENTED => Status::HTTP_NOT_IMPLEMENTED, 268 | ffi::HTTP_BAD_GATEWAY => Status::HTTP_BAD_GATEWAY, 269 | ffi::HTTP_SERVICE_UNAVAILABLE => Status::HTTP_SERVICE_UNAVAILABLE, 270 | ffi::HTTP_GATEWAY_TIME_OUT => Status::HTTP_GATEWAY_TIME_OUT, 271 | ffi::HTTP_VERSION_NOT_SUPPORTED => Status::HTTP_VERSION_NOT_SUPPORTED, 272 | ffi::HTTP_VARIANT_ALSO_VARIES => Status::HTTP_VARIANT_ALSO_VARIES, 273 | ffi::HTTP_INSUFFICIENT_STORAGE => Status::HTTP_INSUFFICIENT_STORAGE, 274 | ffi::HTTP_LOOP_DETECTED => Status::HTTP_LOOP_DETECTED, 275 | ffi::HTTP_NOT_EXTENDED => Status::HTTP_NOT_EXTENDED, 276 | ffi::HTTP_NETWORK_AUTHENTICATION_REQUIRED => Status::HTTP_NETWORK_AUTHENTICATION_REQUIRED, 277 | 278 | _ => Status::DECLINED 279 | } 280 | } 281 | } 282 | 283 | pub enum ProxyReq { 284 | NONE, // No proxy 285 | PROXY, // Standard proxy 286 | REVERSE, // Reverse proxy 287 | RESPONSE, // Origin response 288 | } 289 | 290 | impl Into for c_int { 291 | fn into(self) -> ProxyReq { 292 | match self { 293 | ffi::PROXYREQ_NONE => ProxyReq::NONE, 294 | ffi::PROXYREQ_PROXY => ProxyReq::PROXY, 295 | ffi::PROXYREQ_REVERSE => ProxyReq::REVERSE, 296 | ffi::PROXYREQ_RESPONSE => ProxyReq::RESPONSE, 297 | _ => panic!("Unknown ProxyReq type") 298 | } 299 | } 300 | } 301 | 302 | impl fmt::Display for ProxyReq { 303 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 304 | let display = match *self { 305 | ProxyReq::NONE => "No proxy", 306 | ProxyReq::PROXY => "Standard proxy", 307 | ProxyReq::REVERSE => "Reverse proxy", 308 | ProxyReq::RESPONSE => "Origin response" 309 | }; 310 | 311 | write!(f, "{}", display) 312 | } 313 | } 314 | 315 | 316 | pub type Request = Wrapper; 317 | 318 | 319 | impl Request { 320 | option_getter!(pool, Pool); 321 | 322 | option_getter!(connection, Conn); 323 | 324 | option_getter!(server, Server); 325 | 326 | str_getter!(the_request); 327 | 328 | bool_getter!(assbackwards); 329 | 330 | into_getter!(proxyreq, ProxyReq); 331 | 332 | bool_getter!(header_only); 333 | 334 | pub fn set_header_only(&mut self, header_only: bool) { 335 | set_field!(self, header_only, header_only as c_int); 336 | } 337 | 338 | str_getter!(protocol); 339 | 340 | str_getter!(hostname); 341 | 342 | type_getter!(request_time, i64); 343 | 344 | str_getter!(status_line); 345 | 346 | into_getter!(status, Status); 347 | 348 | pub fn set_status(&mut self, status: Status) { 349 | set_field!(self, status, status.into()); 350 | } 351 | 352 | str_getter!(method); 353 | 354 | type_getter!(mtime, i64); 355 | 356 | pub fn set_last_modified(&mut self, mtime: i64) { 357 | unsafe { 358 | ffi::ap_update_mtime(self.ptr, mtime); 359 | ffi::ap_set_last_modified(self.ptr); 360 | } 361 | } 362 | 363 | str_getter!(range); 364 | 365 | type_getter!(clength, i64); 366 | 367 | option_getter!(headers_in, Table); 368 | 369 | option_getter!(headers_out, Table); 370 | 371 | option_getter!(err_headers_out, Table); 372 | 373 | option_getter!(subprocess_env, Table); 374 | 375 | option_getter!(notes, Table); 376 | 377 | str_getter!(content_type); 378 | 379 | pub fn set_content_type>>(&self, ct: T) { 380 | let c_str = ffi::strdup(field!(self, pool), ct); 381 | 382 | unsafe { 383 | ffi::ap_set_content_type( 384 | self.ptr, 385 | c_str 386 | ); 387 | }; 388 | } 389 | 390 | str_getter!(handler); 391 | 392 | str_getter!(content_encoding); 393 | 394 | str_getter!(vlist_validator); 395 | 396 | str_getter!(user); 397 | 398 | str_getter!(ap_auth_type); 399 | 400 | str_getter!(unparsed_uri); 401 | 402 | str_getter!(uri); 403 | 404 | str_getter!(filename); 405 | 406 | str_getter!(canonical_filename); 407 | 408 | str_getter!(path_info); 409 | 410 | str_getter!(args); 411 | 412 | option_getter!(per_dir_config, ConfVector); 413 | 414 | option_getter!(request_config, ConfVector); 415 | 416 | str_getter!(log_id); 417 | 418 | str_getter!(useragent_ip); 419 | 420 | pub fn write>>(&self, data: T) -> Result<(), ()> { 421 | let c_str_buf = match CString::new(data) { 422 | Ok(s) => s, 423 | Err(_) => return Err(()) 424 | }; 425 | 426 | let sent = unsafe { 427 | ffi::ap_rwrite( 428 | c_str_buf.as_ptr() as *mut c_void, 429 | c_str_buf.to_bytes().len() as i32, 430 | self.ptr 431 | ) 432 | }; 433 | 434 | match sent { 435 | -1 => Err(()), 436 | _ => Ok(()) 437 | } 438 | } 439 | 440 | pub fn escape_html<'a, T: Into>>(&self, s: T) -> Result<&'a str, ()> { 441 | let c_str = match CString::new(s) { 442 | Ok(s) => s, 443 | Err(_) => return Err(()) 444 | }; 445 | 446 | let escaped = unsafe { 447 | ffi::ap_escape_html2( 448 | field!(self, pool), 449 | c_str.as_ptr(), 450 | 0 451 | ) 452 | }; 453 | 454 | from_char_ptr(escaped).ok_or(()) 455 | } 456 | 457 | pub fn escape_urlencoded<'a, T: Into>>(&self, s: T) -> Result<&'a str, ()> { 458 | let c_str = match CString::new(s) { 459 | Ok(s) => s, 460 | Err(_) => return Err(()) 461 | }; 462 | 463 | let escaped = unsafe { 464 | ffi::ap_escape_urlencoded(field!(self, pool), c_str.as_ptr()) 465 | }; 466 | 467 | from_char_ptr(escaped).ok_or(()) 468 | } 469 | 470 | pub fn unescape_urlencoded<'a, T: Into>>(&self, query: T) -> Result<&'a str, ()> { 471 | let c_str = ffi::strdup(field!(self, pool), query); 472 | 473 | let res = unsafe { 474 | ffi::ap_unescape_urlencoded(c_str) 475 | }; 476 | 477 | if res != 0 { 478 | return Err(()); 479 | }; 480 | 481 | from_char_ptr(c_str).ok_or(()) 482 | } 483 | 484 | pub fn server_name<'a>(&self) -> Option<&'a str> { 485 | from_char_ptr( 486 | unsafe { ffi::ap_get_server_name(self.ptr) } 487 | ) 488 | } 489 | 490 | pub fn server_port(&self) -> u16 { 491 | unsafe { ffi::ap_get_server_port(self.ptr) } 492 | } 493 | 494 | pub fn document_root<'a>(&self) -> Option<&'a str> { 495 | from_char_ptr( 496 | unsafe { ffi::ap_document_root(self.ptr) } 497 | ) 498 | } 499 | 500 | pub fn auth_name<'a>(&self) -> Option<&'a str> { 501 | from_char_ptr( 502 | unsafe { ffi::ap_auth_name(self.ptr) } 503 | ) 504 | } 505 | 506 | pub fn basic_auth_pw<'a>(&self) -> Option<&'a str> { 507 | let mut pw: *const c_char = ptr::null_mut(); 508 | 509 | unsafe { 510 | ffi::ap_get_basic_auth_pw(self.ptr, &mut pw); 511 | } 512 | 513 | from_char_ptr(pw) 514 | 515 | } 516 | 517 | pub fn context_document_root<'a>(&self) -> Option<&'a str> { 518 | from_char_ptr( 519 | unsafe { ffi::ap_context_document_root(self.ptr) } 520 | ) 521 | } 522 | 523 | pub fn context_prefix<'a>(&self) -> Option<&'a str> { 524 | from_char_ptr( 525 | unsafe { ffi::ap_context_prefix(self.ptr) } 526 | ) 527 | } 528 | 529 | pub fn http_scheme<'a>(&self) -> Option<&'a str> { 530 | from_char_ptr( 531 | unsafe { ffi::ap_run_http_scheme(self.ptr) } 532 | ) 533 | } 534 | 535 | pub fn default_port(&self) -> u16 { 536 | unsafe { ffi::ap_run_default_port(self.ptr) } 537 | } 538 | 539 | pub fn is_initial_req(&self) -> bool { 540 | unsafe { ffi::ap_is_initial_req(self.ptr) == 1 } 541 | } 542 | 543 | pub fn some_auth_required(&self) -> bool { 544 | unsafe { ffi::ap_some_auth_required(self.ptr) == 1 } 545 | } 546 | 547 | pub fn cookie<'a, T: Into>>(&self, name: T) -> Option<&'a str> { 548 | let c_str_name = ffi::strdup(field!(self, pool), name); 549 | let mut val: *const c_char = ptr::null_mut(); 550 | 551 | unsafe { 552 | ffi::ap_cookie_read(self.ptr, c_str_name, &mut val, 0); 553 | } 554 | 555 | from_char_ptr(val) 556 | } 557 | 558 | pub fn set_cookie(&self, cookie: Cookie) { 559 | let c_str_name = ffi::strdup(field!(self, pool), cookie.name); 560 | let c_str_val = ffi::strdup(field!(self, pool), cookie.value); 561 | let c_str_attrs = ffi::strdup(field!(self, pool), cookie.attrs(&self)); 562 | 563 | let null: *const ffi::apr_table_t = ptr::null(); 564 | 565 | unsafe { 566 | ffi::ap_cookie_write(self.ptr, c_str_name, c_str_val, c_str_attrs, 0, 567 | field!(self, headers_out), null); 568 | } 569 | } 570 | 571 | pub fn base64_encode<'a, T: Into>>(&self, plain: T) -> Result<&'a str, ()> { 572 | let c_str_plain: CString = match CString::new(plain) { 573 | Ok(val) => val, 574 | Err(_) => return Err(()) 575 | }; 576 | 577 | let plain_len: c_int = c_str_plain.to_bytes().len() as c_int; 578 | 579 | let mut encoded_len: c_int = unsafe { 580 | ffi::apr_base64_encode_len(plain_len) 581 | }; 582 | 583 | if encoded_len == 0 { 584 | return Err(()); 585 | }; 586 | 587 | let encoded: *mut c_char = unsafe { 588 | ffi::apr_palloc(field!(self, pool), encoded_len as ffi::apr_size_t) as *mut c_char 589 | }; 590 | 591 | encoded_len = unsafe { 592 | ffi::apr_base64_encode(encoded, c_str_plain.as_ptr(), plain_len) 593 | }; 594 | 595 | if encoded_len == 0 { 596 | return Err(()); 597 | }; 598 | 599 | from_char_ptr(encoded).ok_or(()) 600 | } 601 | 602 | pub fn base64_decode<'a, T: Into>>(&self, encoded: T) -> Result<&'a str, ()> { 603 | let c_str_encoded: CString = match CString::new(encoded) { 604 | Ok(val) => val, 605 | Err(_) => return Err(()) 606 | }; 607 | 608 | let mut plain_len: c_int = unsafe { 609 | ffi::apr_base64_decode_len(c_str_encoded.as_ptr()) 610 | }; 611 | 612 | if plain_len == 0 { 613 | return Err(()); 614 | }; 615 | 616 | let plain: *mut c_char = unsafe { 617 | ffi::apr_palloc(field!(self, pool), plain_len as ffi::apr_size_t) as *mut c_char 618 | }; 619 | 620 | plain_len = unsafe { 621 | ffi::apr_base64_decode(plain, c_str_encoded.as_ptr()) 622 | }; 623 | 624 | if plain_len == 0 { 625 | return Err(()); 626 | }; 627 | 628 | from_char_ptr(plain).ok_or(()) 629 | } 630 | 631 | pub fn rfc822_date<'a>(&self, t: i64) -> Result<&'a str, ()> { 632 | let date: *mut c_char = unsafe { 633 | ffi::apr_palloc(field!(self, pool), ffi::APR_RFC822_DATE_LEN) as *mut c_char 634 | }; 635 | 636 | unsafe { 637 | ffi::apr_rfc822_date(date, t); 638 | } 639 | 640 | from_char_ptr(date).ok_or(()) 641 | } 642 | } 643 | 644 | pub type Conn = Wrapper; 645 | 646 | 647 | impl Conn { 648 | str_getter!(client_ip); 649 | 650 | str_getter!(remote_host); 651 | 652 | str_getter!(remote_logname); 653 | 654 | str_getter!(local_ip); 655 | 656 | str_getter!(local_host); 657 | 658 | str_getter!(log_id); 659 | } 660 | 661 | 662 | pub type Server = Wrapper; 663 | 664 | 665 | impl Server { 666 | option_getter!(module_config, ConfVector); 667 | } 668 | 669 | 670 | pub type CmdParms = Wrapper; 671 | 672 | 673 | impl CmdParms { 674 | option_getter!(server, Server); 675 | 676 | option_getter!(pool, Pool); 677 | } 678 | 679 | 680 | pub type Module = Wrapper; 681 | 682 | 683 | pub type ConfVector = Wrapper; 684 | 685 | 686 | pub type ListProviderGroup = Wrapper; 687 | 688 | 689 | impl ListProviderGroup { 690 | str_getter!(provider_group); 691 | 692 | str_getter!(provider_version); 693 | } 694 | 695 | 696 | pub type ListProviderName = Wrapper; 697 | 698 | 699 | impl ListProviderName { 700 | str_getter!(provider_name); 701 | } 702 | 703 | 704 | pub fn list_provider_groups(pool: &mut Pool) -> ArrayHeaderIter { 705 | let ptr = unsafe { ffi::ap_list_provider_groups(pool.ptr) }; 706 | 707 | ArrayHeaderIter:: { 708 | phantom: PhantomData, 709 | array_header: ptr, 710 | next_idx: 0 711 | } 712 | } 713 | 714 | pub fn list_provider_names>>(pool: &mut Pool, provider_group: T, provider_version: T) -> ArrayHeaderIter { 715 | let provider_group = ffi::strdup(pool.ptr, provider_group); 716 | let provider_version = ffi::strdup(pool.ptr, provider_version); 717 | 718 | let ptr = unsafe { ffi::ap_list_provider_names(pool.ptr, provider_group, provider_version) }; 719 | 720 | ArrayHeaderIter:: { 721 | phantom: PhantomData, 722 | array_header: ptr, 723 | next_idx: 0 724 | } 725 | } 726 | 727 | pub fn server_banner<'a>() -> Option<&'a str> { 728 | from_char_ptr( 729 | unsafe { ffi::ap_get_server_banner() } 730 | ) 731 | } 732 | 733 | pub fn server_description<'a>() -> Option<&'a str> { 734 | from_char_ptr( 735 | unsafe { ffi::ap_get_server_description() } 736 | ) 737 | } 738 | 739 | pub fn server_built<'a>() -> Option<&'a str> { 740 | from_char_ptr( 741 | unsafe { ffi::ap_get_server_built() } 742 | ) 743 | } 744 | 745 | pub fn show_mpm<'a>() -> Option<&'a str> { 746 | from_char_ptr( 747 | unsafe { ffi::ap_show_mpm() } 748 | ) 749 | } 750 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(plugin)] 2 | #![plugin(interpolate_idents)] 3 | 4 | extern crate libc; 5 | 6 | pub mod ffi; 7 | pub mod apr; 8 | pub mod httpd; 9 | pub mod wrapper; 10 | pub mod cookie; 11 | 12 | pub use libc::{c_void, c_char, c_int}; 13 | 14 | pub use httpd::{Request, Status, ProxyReq, CmdParms, Server, server_banner, server_description, 15 | server_built, show_mpm, ConfVector, list_provider_groups, list_provider_names}; 16 | 17 | pub use apr::{apr_version_string, apu_version_string, HookOrder, Pool, time_now}; 18 | 19 | pub use cookie::Cookie; 20 | 21 | pub use wrapper::{WrappedType, from_char_ptr, FromRaw}; 22 | 23 | pub use ffi::{OR_NONE, OR_LIMIT, OR_OPTIONS, OR_FILEINFO, OR_AUTHCFG, OR_INDEXES, OR_UNSET, 24 | ACCESS_CONF, RSRC_CONF, EXEC_ON_READ, NONFATAL_OVERRIDE, NONFATAL_UNKNOWN, NONFATAL_ALL, OR_ALL, 25 | RAW_ARGS, TAKE1, TAKE2, ITERATE, ITERATE2, FLAG, NO_ARGS, TAKE12, TAKE3, TAKE23, TAKE123, 26 | TAKE13, TAKE_ARGV}; 27 | 28 | 29 | pub type StringType<'a> = &'a str; 30 | pub type CStringType = *const c_char; 31 | 32 | pub type BoolType = bool; 33 | pub type CBoolType = c_int; 34 | 35 | 36 | #[macro_export] 37 | macro_rules! get { 38 | ($expr:expr) => (match $expr { 39 | Some(val) => val, 40 | None => { 41 | return std::result::Result::Err(std::convert::From::from(())) 42 | } 43 | }) 44 | } 45 | 46 | 47 | #[macro_export] 48 | macro_rules! apache2_module { 49 | ($name:ident, $mod_name:expr) => { 50 | apache2_module!($name, $mod_name, config {}); 51 | }; 52 | 53 | ($name:ident, $mod_name:expr, config $config:tt) => { 54 | interpolate_idents! { 55 | apache2_module!($name, $mod_name, config $config, handlers { 56 | ([$name _handler], handler, $crate::HookOrder::MIDDLE) 57 | }); 58 | } 59 | }; 60 | 61 | ($name:ident, $mod_name:expr, handlers $handlers:tt) => { 62 | apache2_module!($name, $mod_name, config {}, handlers $handlers); 63 | }; 64 | 65 | ($name:ident, $mod_name:expr, config $config:tt, handlers $handlers:tt) => { 66 | use $crate::wrapper::FromRaw; 67 | 68 | _declare_config_struct!($name, $config); 69 | 70 | _declare_config_wrappers!($name, $config); 71 | 72 | _declare_directives!($name, $config); 73 | 74 | _declare_module!($name, $mod_name, $config); 75 | 76 | _declare_handlers!($name, $handlers); 77 | } 78 | } 79 | 80 | 81 | #[macro_export] 82 | macro_rules! _declare_module { 83 | ($name:ident, $mod_name:expr, $config:tt) => { 84 | interpolate_idents! { 85 | _declare_module_impl!( 86 | [$name _module], 87 | $mod_name, 88 | _extract_create_dir_config_name!($config), 89 | _extract_merge_dir_config_name!($config), 90 | _extract_create_server_config_name!($config), 91 | _extract_merge_server_config_name!($config), 92 | &[$name _directives], 93 | Some([$name _hooks]) 94 | ); 95 | } 96 | } 97 | } 98 | 99 | 100 | #[macro_export] 101 | macro_rules! _declare_module_impl { 102 | ( 103 | $module:ident, 104 | $mod_name:expr, 105 | $create_dir_config:expr, 106 | $merge_dir_config:expr, 107 | $create_server_config:expr, 108 | $merge_server_config:expr, 109 | $cmds:expr, 110 | $register_hooks:expr 111 | ) => { 112 | #[allow(unused_unsafe)] 113 | #[no_mangle] 114 | pub static mut $module: $crate::ffi::module = $crate::ffi::module { 115 | version: $crate::ffi::MODULE_MAGIC_NUMBER_MAJOR, 116 | minor_version: $crate::ffi::MODULE_MAGIC_NUMBER_MINOR, 117 | module_index: -1, 118 | name: $mod_name as *const u8 as *const $crate::c_char, 119 | dynamic_load_handle: 0 as *mut $crate::c_void, 120 | next: 0 as *mut $crate::ffi::module, 121 | magic: $crate::ffi::MODULE_MAGIC_COOKIE, 122 | rewrite_args: None, 123 | create_dir_config: $create_dir_config, 124 | merge_dir_config: $merge_dir_config, 125 | create_server_config: $create_server_config, 126 | merge_server_config: $merge_server_config, 127 | cmds: unsafe { $cmds as *const $crate::ffi::command_rec }, 128 | register_hooks: $register_hooks 129 | }; 130 | } 131 | } 132 | 133 | 134 | #[macro_export] 135 | macro_rules! _declare_config_struct { 136 | ($name:ident, {}) => {}; 137 | 138 | ($name:ident, { server $server:tt, $directives:tt }) => { 139 | _declare_config_struct_from_server!($name, $server); 140 | }; 141 | 142 | ($name:ident, { directory $directory:tt, server $server:tt, $directives:tt }) => { 143 | _declare_config_struct_from_server!($name, $server); 144 | 145 | _declare_config_struct_from_directory!($name, $directory); 146 | }; 147 | 148 | ($name:ident, { directory $directory:tt, $directives:tt }) => { 149 | _declare_config_struct_from_directory!($name, $directory); 150 | } 151 | } 152 | 153 | 154 | #[macro_export] 155 | macro_rules! _declare_config_struct_from_server { 156 | ($name:ident, { $config_struct:ident $fields:tt, $create_server_config:ident }) => { 157 | _declare_config_struct_impl!($name, $config_struct $fields); 158 | 159 | _declare_get_config!($name, $config_struct, get_server_config); 160 | 161 | _declare_get_server_config_from_parms!($config_struct); 162 | 163 | _declare_get_server_config_from_request!($config_struct); 164 | }; 165 | 166 | ($name:ident, { $config_struct:ident $fields:tt, $create_server_config:ident, $merge_server_config:ident }) => { 167 | _declare_config_struct_from_server!($name, {$config_struct $fields, $create_server_config}); 168 | } 169 | } 170 | 171 | 172 | #[macro_export] 173 | macro_rules! _declare_config_struct_from_directory { 174 | ($name:ident, { $config_struct:ident $fields:tt, $create_dir_config:ident }) => { 175 | _declare_config_struct_impl!($name, $config_struct $fields); 176 | 177 | _declare_get_config!($name, $config_struct, get_dir_config); 178 | 179 | _declare_get_dir_config_from_request!($config_struct); 180 | }; 181 | 182 | ($name:ident, { $config_struct:ident $fields:tt, $create_dir_config:ident, $merge_dir_config:ident }) => { 183 | _declare_config_struct_from_directory!($name, {$config_struct $fields, $create_dir_config}); 184 | } 185 | } 186 | 187 | 188 | #[macro_export] 189 | macro_rules! _declare_config_struct_impl { 190 | ($name:ident, $struct_name:ident { $($field_name:ident: $field_type:ident),* }) => { 191 | #[repr(C)] 192 | interpolate_idents! { 193 | pub struct [C $struct_name] { 194 | $( 195 | pub $field_name: $crate::[C $field_type] 196 | ),* 197 | } 198 | } 199 | 200 | pub struct $struct_name<'a> { 201 | pub raw: &'a mut <$struct_name<'a> as $crate::WrappedType>::wrapped_type, 202 | pub pool: *mut $crate::ffi::apr_pool_t 203 | } 204 | 205 | impl<'a> $struct_name<'a> { 206 | pub fn new(pool: &mut Pool) -> Option { 207 | let c_config = unsafe { 208 | $crate::ffi::apr_pcalloc( 209 | pool.ptr, 210 | std::mem::size_of::<<$struct_name<'a> as $crate::WrappedType>::wrapped_type>() as $crate::ffi::apr_size_t 211 | ) as *mut <$struct_name<'a> as $crate::WrappedType>::wrapped_type 212 | }; 213 | 214 | $struct_name::from_raw(pool, c_config) 215 | } 216 | 217 | pub fn from_raw( 218 | pool: &mut Pool, 219 | ptr: *mut <$struct_name<'a> as $crate::WrappedType>::wrapped_type 220 | ) -> Option { 221 | if ptr.is_null() { 222 | None 223 | } else { 224 | let raw: &mut <$struct_name<'a> as $crate::WrappedType>::wrapped_type = unsafe { &mut *ptr }; 225 | Some( 226 | $struct_name { 227 | raw: raw, 228 | pool: pool.ptr 229 | } 230 | ) 231 | } 232 | } 233 | 234 | $( 235 | _declare_config_wrapper_method!($field_name, $field_type); 236 | )* 237 | } 238 | 239 | interpolate_idents! { 240 | impl<'a> $crate::WrappedType for $struct_name<'a> { 241 | type wrapped_type = [C $struct_name]; 242 | } 243 | } 244 | } 245 | } 246 | 247 | 248 | #[macro_export] 249 | macro_rules! _declare_get_config { 250 | ($name:ident, $struct_name:ident, $get_config_fn:ident) => { 251 | interpolate_idents! { 252 | pub fn $get_config_fn<'a>( 253 | pool: &mut $crate::Pool, 254 | conf_vector: &$crate::ConfVector 255 | ) -> $struct_name<'a> { 256 | let config = unsafe { 257 | $crate::ffi::ap_get_module_config(conf_vector.ptr, &[$name _module]) as *mut [C $struct_name] 258 | }; 259 | 260 | $struct_name::from_raw(pool, config).unwrap() 261 | } 262 | } 263 | } 264 | } 265 | 266 | 267 | #[macro_export] 268 | macro_rules! _declare_get_server_config_from_parms { 269 | ($struct_name:ident) => { 270 | pub fn get_server_config_from_parms<'a>(parms: &mut $crate::CmdParms) -> $struct_name<'a> { 271 | get_server_config( 272 | &mut parms.pool().unwrap(), 273 | &parms.server().unwrap().module_config().unwrap() 274 | ) 275 | } 276 | } 277 | } 278 | 279 | 280 | #[macro_export] 281 | macro_rules! _declare_get_server_config_from_request { 282 | ($struct_name:ident) => { 283 | pub fn get_server_config_from_request<'a>(r: &mut $crate::Request) -> $struct_name<'a> { 284 | get_server_config( 285 | &mut r.pool().unwrap(), 286 | &r.server().unwrap().module_config().unwrap() 287 | ) 288 | } 289 | } 290 | } 291 | 292 | 293 | #[macro_export] 294 | macro_rules! _declare_get_dir_config_from_request { 295 | ($struct_name:ident) => { 296 | pub fn get_dir_config_from_request<'a>(r: &mut $crate::Request) -> $struct_name<'a> { 297 | get_dir_config( 298 | &mut r.pool().unwrap(), 299 | &r.per_dir_config().unwrap() 300 | ) 301 | } 302 | } 303 | } 304 | 305 | 306 | #[macro_export] 307 | macro_rules! _declare_config_wrapper_method { 308 | ($field_name:ident, StringType) => { 309 | pub fn $field_name(&self) -> Option { 310 | $crate::from_char_ptr(self.raw.$field_name) 311 | } 312 | 313 | interpolate_idents! { 314 | pub fn [set_ $field_name](&mut self, value: StringType) { 315 | self.raw.$field_name = $crate::ffi::strdup(self.pool, value); 316 | } 317 | } 318 | }; 319 | 320 | ($field_name:ident, BoolType) => { 321 | pub fn $field_name(&self) -> BoolType { 322 | self.raw.$field_name != 0 323 | } 324 | 325 | interpolate_idents! { 326 | pub fn [set_ $field_name](&mut self, value: BoolType) { 327 | match value { 328 | true => { self.raw.$field_name = 1; }, 329 | false => { self.raw.$field_name = 0; }, 330 | } 331 | } 332 | } 333 | } 334 | } 335 | 336 | #[macro_export] 337 | macro_rules! _extract_create_server_config_name { 338 | ({}) => { 339 | None 340 | }; 341 | 342 | ({ server $server:tt, $directives:tt }) => { 343 | _extract_create_server_config_name_from_server!($server) 344 | }; 345 | 346 | ({ directory $directory:tt, server $server:tt, $directives:tt }) => { 347 | _extract_create_server_config_name_from_server!($server) 348 | }; 349 | 350 | ({ directory $directory:tt, $directives:tt }) => { 351 | None 352 | } 353 | } 354 | 355 | 356 | #[macro_export] 357 | macro_rules! _extract_create_server_config_name_from_server { 358 | ({ $config_struct:ident $fields:tt, $create_server_config:ident }) => { 359 | interpolate_idents! { 360 | Some([c_ $create_server_config]) 361 | } 362 | }; 363 | 364 | ({ $config_struct:ident $fields:tt, $create_server_config:ident, $merge_server_config:ident }) => { 365 | _extract_create_server_config_name_from_server!({$config_struct $fields, $create_server_config}) 366 | } 367 | } 368 | 369 | 370 | #[macro_export] 371 | macro_rules! _extract_merge_server_config_name { 372 | ({}) => { 373 | None 374 | }; 375 | 376 | ({ server $server:tt, $directives:tt }) => { 377 | _extract_merge_server_config_name_from_server!($server) 378 | }; 379 | 380 | ({ directory $directory:tt, server $server:tt, $directives:tt }) => { 381 | _extract_merge_server_config_name_from_server!($server) 382 | }; 383 | 384 | ({ directory $directory:tt, $directives:tt }) => { 385 | None 386 | } 387 | } 388 | 389 | 390 | #[macro_export] 391 | macro_rules! _extract_merge_server_config_name_from_server { 392 | ({ $config_struct:ident $fields:tt, $create_server_config:ident }) => { 393 | None 394 | }; 395 | 396 | ({ $config_struct:ident $fields:tt, $create_server_config:ident, $merge_server_config:ident }) => { 397 | interpolate_idents! { 398 | Some([c_ $merge_server_config]) 399 | } 400 | } 401 | } 402 | 403 | 404 | #[macro_export] 405 | macro_rules! _extract_create_dir_config_name { 406 | ({}) => { 407 | None 408 | }; 409 | 410 | ({ server $server:tt, $directives:tt }) => { 411 | None 412 | }; 413 | 414 | ({ directory $directory:tt, server $server:tt, $directives:tt }) => { 415 | _extract_create_dir_config_name_from_directory!($directory) 416 | }; 417 | 418 | ({ directory $directory:tt, $directives:tt }) => { 419 | _extract_create_dir_config_name_from_directory!($directory) 420 | } 421 | } 422 | 423 | 424 | #[macro_export] 425 | macro_rules! _extract_create_dir_config_name_from_directory { 426 | ({ $config_struct:ident $fields:tt, $create_dir_config:ident }) => { 427 | interpolate_idents! { 428 | Some([c_ $create_dir_config]) 429 | } 430 | }; 431 | 432 | ({ $config_struct:ident $fields:tt, $create_dir_config:ident, $merge_dir_config:ident }) => { 433 | _extract_create_dir_config_name_from_directory!({$config_struct $fields, $create_dir_config}); 434 | } 435 | } 436 | 437 | 438 | #[macro_export] 439 | macro_rules! _extract_merge_dir_config_name { 440 | ({}) => { 441 | None 442 | }; 443 | 444 | ({ server $server:tt, $directives:tt }) => { 445 | None 446 | }; 447 | 448 | ({ directory $directory:tt, server $server:tt, $directives:tt }) => { 449 | _extract_merge_dir_config_name_from_directory!($directory) 450 | }; 451 | 452 | ({ directory $directory:tt, $directives:tt }) => { 453 | _extract_merge_dir_config_name_from_directory!($directory) 454 | } 455 | } 456 | 457 | 458 | #[macro_export] 459 | macro_rules! _extract_merge_dir_config_name_from_directory { 460 | ({ $config_struct:ident $fields:tt, $create_dir_config:ident }) => { 461 | None 462 | }; 463 | 464 | ({ $config_struct:ident $fields:tt, $create_dir_config:ident, $merge_dir_config:ident }) => { 465 | interpolate_idents! { 466 | Some([c_ $merge_dir_config]) 467 | } 468 | } 469 | } 470 | 471 | 472 | #[macro_export] 473 | macro_rules! _declare_directives { 474 | ($name:ident, {}) => { 475 | _declare_directives_impl!($name); 476 | }; 477 | 478 | ($name:ident, { server $server:tt, $directives:tt }) => { 479 | _declare_directives_impl!($name, {}, $directives); 480 | }; 481 | 482 | ($name:ident, { directory $directory:tt, server $server:tt, $directives:tt }) => { 483 | _declare_directives_impl!($name, $directory, $directives); 484 | }; 485 | 486 | ($name:ident, { directory $directory:tt, $directives:tt }) => { 487 | _declare_directives_impl!($name, $directory, $directives); 488 | } 489 | } 490 | 491 | 492 | #[macro_export] 493 | macro_rules! _declare_directives_impl { 494 | ($name:ident) => { 495 | interpolate_idents! { 496 | _declare_directive_array!([$name _directives]); 497 | } 498 | }; 499 | 500 | ($name:ident, $directory:tt, $directives:tt) => { 501 | interpolate_idents! { 502 | _declare_directive_array!([$name _directives], $directives); 503 | } 504 | 505 | _declare_directive_wrappers!($directory, $directives); 506 | } 507 | } 508 | 509 | 510 | #[macro_export] 511 | macro_rules! _declare_config_wrappers { 512 | ($name:ident, {}) => {}; 513 | 514 | ($name:ident, { server $server:tt, $directives:tt }) => { 515 | _declare_server_config_wrappers_from_server!($name, $server); 516 | }; 517 | 518 | ($name:ident, { directory $directory:tt, server $server:tt, $directives:tt }) => { 519 | _declare_server_config_wrappers_from_server!($name, $server); 520 | 521 | _declare_dir_config_wrappers_from_directory!($name, $directory); 522 | }; 523 | 524 | ($name:ident, { directory $directory:tt, $directives:tt }) => { 525 | _declare_dir_config_wrappers_from_directory!($name, $directory); 526 | } 527 | } 528 | 529 | 530 | #[macro_export] 531 | macro_rules! _declare_server_config_wrappers_from_server { 532 | ($name:ident, { $config_struct:ident $fields:tt, $create_server_config:ident }) => { 533 | _declare_create_server_config!($name, $config_struct, $create_server_config); 534 | }; 535 | 536 | ($name:ident, { $config_struct:ident $fields:tt, $create_server_config:ident, $merge_server_config:ident }) => { 537 | _declare_create_server_config!($name, $config_struct, $create_server_config); 538 | 539 | _declare_merge_config!($name, $config_struct, $merge_server_config); 540 | } 541 | } 542 | 543 | 544 | #[macro_export] 545 | macro_rules! _declare_create_server_config { 546 | ($name:ident, $config_struct:ident, $create_server_config:ident) => { 547 | interpolate_idents! { 548 | extern "C" fn [c_ $create_server_config]( 549 | p: *mut $crate::ffi::apr_pool_t, 550 | _: *mut $crate::ffi::server_rec 551 | ) -> *mut $crate::c_void { 552 | let mut pool = Pool::from_raw(p).unwrap(); 553 | 554 | let config = $create_server_config(&mut pool); 555 | 556 | config.raw as *mut [C $config_struct] as *mut $crate::c_void 557 | } 558 | } 559 | } 560 | } 561 | 562 | 563 | #[macro_export] 564 | macro_rules! _declare_dir_config_wrappers_from_directory { 565 | ($name:ident, { $config_struct:ident $fields:tt, $create_dir_config:ident }) => { 566 | _declare_create_dir_config!($name, $config_struct, $create_dir_config); 567 | }; 568 | 569 | ($name:ident, { $config_struct:ident $fields:tt, $create_dir_config:ident, $merge_dir_config:ident }) => { 570 | _declare_create_dir_config!($name, $config_struct, $create_dir_config); 571 | 572 | _declare_merge_config!($name, $config_struct, $merge_dir_config); 573 | } 574 | } 575 | 576 | 577 | #[macro_export] 578 | macro_rules! _declare_create_dir_config { 579 | ($name:ident, $config_struct:ident, $create_dir_config:ident) => { 580 | interpolate_idents! { 581 | extern "C" fn [c_ $create_dir_config]( 582 | p: *mut $crate::ffi::apr_pool_t, 583 | dir: *mut $crate::c_char 584 | ) -> *mut $crate::c_void { 585 | let mut pool = Pool::from_raw(p).unwrap(); 586 | let directory = $crate::from_char_ptr(dir); 587 | 588 | let config = $create_dir_config(&mut pool, directory); 589 | 590 | config.raw as *mut [C $config_struct] as *mut $crate::c_void 591 | } 592 | } 593 | } 594 | } 595 | 596 | 597 | #[macro_export] 598 | macro_rules! _declare_merge_config { 599 | ($name:ident, $config_struct:ident, $merge_config:ident) => { 600 | interpolate_idents! { 601 | extern "C" fn [c_ $merge_config]( 602 | p: *mut $crate::ffi::apr_pool_t, 603 | base_conf: *mut $crate::c_void, 604 | new_conf: *mut $crate::c_void 605 | ) -> *mut $crate::c_void { 606 | let mut pool = Pool::from_raw(p).unwrap(); 607 | let base_conf = $config_struct::from_raw(&mut pool, base_conf as *mut [C $config_struct]).unwrap(); 608 | let new_conf = $config_struct::from_raw(&mut pool, new_conf as *mut [C $config_struct]).unwrap(); 609 | 610 | let config = $merge_config(&mut pool, &base_conf, &new_conf); 611 | 612 | config.raw as *mut [C $config_struct] as *mut $crate::c_void 613 | } 614 | } 615 | } 616 | } 617 | 618 | 619 | #[macro_export] 620 | macro_rules! _declare_directive_array { 621 | ($directives_name:ident) => { 622 | _declare_directive_array!($directives_name, [ ]); 623 | }; 624 | 625 | ($directives_name:ident, [ ]) => { 626 | static mut $directives_name: [$crate::ffi::command_rec; 1] = [ 627 | _null_command_rec!() 628 | ]; 629 | }; 630 | 631 | ($directives_name:ident, [ $cmd1:tt ]) => { 632 | _declare_directive_array!($directives_name, 2, [ $cmd1 ]); 633 | }; 634 | 635 | ($directives_name:ident, [ $cmd1:tt, $cmd2:tt ]) => { 636 | _declare_directive_array!($directives_name, 3, [ $cmd1, $cmd2 ]); 637 | }; 638 | 639 | ($directives_name:ident, [ $cmd1:tt, $cmd2:tt, $cmd3:tt ]) => { 640 | _declare_directive_array!($directives_name, 4, [ $cmd1, $cmd2, $cmd3 ]); 641 | }; 642 | 643 | ($directives_name:ident, [ $cmd1:tt, $cmd2:tt, $cmd3:tt, $cmd4:tt ]) => { 644 | _declare_directive_array!($directives_name, 5, [ $cmd1, $cmd2, $cmd3, $cmd4 ]); 645 | }; 646 | 647 | ($directives_name:ident, [ $cmd1:tt, $cmd2:tt, $cmd3:tt, $cmd4:tt, $cmd5:tt ]) => { 648 | _declare_directive_array!($directives_name, 6, [ $cmd1, $cmd2, $cmd3, $cmd4, $cmd5 ]); 649 | }; 650 | 651 | ($directives_name:ident, [ $cmd1:tt, $cmd2:tt, $cmd3:tt, $cmd4:tt, $cmd5:tt, $cmd6:tt ]) => { 652 | _declare_directive_array!($directives_name, 7, [ $cmd1, $cmd2, $cmd3, $cmd4, $cmd5, $cmd6 ]); 653 | }; 654 | 655 | ($directives_name:ident, [ $cmd1:tt, $cmd2:tt, $cmd3:tt, $cmd4:tt, $cmd5:tt, $cmd6:tt, $cmd7:tt ]) => { 656 | _declare_directive_array!($directives_name, 8, [ $cmd1, $cmd2, $cmd3, $cmd4, $cmd5, $cmd6, $cmd7 ]); 657 | }; 658 | 659 | ($directives_name:ident, [ $cmd1:tt, $cmd2:tt, $cmd3:tt, $cmd4:tt, $cmd5:tt, $cmd6:tt, $cmd7:tt, $cmd8:tt ]) => { 660 | _declare_directive_array!($directives_name, 9, [ $cmd1, $cmd2, $cmd3, $cmd4, $cmd5, $cmd6, $cmd7, $cmd8 ]); 661 | }; 662 | 663 | ($directives_name:ident, $cmd_count:expr, [ $($cmd:tt),* ]) => { 664 | static mut $directives_name: [$crate::ffi::command_rec; $cmd_count] = [ 665 | $( _declare_command_rec!($cmd) ),*, 666 | _null_command_rec!() 667 | ]; 668 | } 669 | } 670 | 671 | 672 | #[macro_export] 673 | macro_rules! _null_command_rec { 674 | () => { 675 | _declare_c_command_rec!(0, 0, 0, 0, 0) 676 | } 677 | } 678 | 679 | 680 | #[macro_export] 681 | macro_rules! _declare_command_rec { 682 | (($args_how:ident, $name:expr, $func:ident, $req_override:expr, $errmsg:expr)) => { 683 | interpolate_idents! { 684 | _declare_c_command_rec!($crate::$args_how, $name, [c_ $func], $req_override, $errmsg) 685 | } 686 | } 687 | } 688 | 689 | 690 | #[macro_export] 691 | macro_rules! _declare_c_command_rec { 692 | ($args_how:expr, $name:expr, $cfunc:expr, $req_override:expr, $errmsg:expr) => { 693 | $crate::ffi::command_rec { 694 | name: $name as *const u8 as *const $crate::c_char, 695 | func: $crate::ffi::cmd_func { 696 | _bindgen_data_: [$cfunc as u64] 697 | }, 698 | cmd_data: 0 as *mut $crate::c_void, 699 | req_override: $req_override, 700 | args_how: $args_how, 701 | errmsg: $errmsg as *const u8 as *const $crate::c_char 702 | } 703 | } 704 | } 705 | 706 | 707 | #[macro_export] 708 | macro_rules! _declare_directive_wrappers { 709 | ($directory:tt, [ $(( $args_how:ident, $name:expr, $func:ident, $req_override:expr, $errmsg:expr )),* ]) => { 710 | $( 711 | _declare_directive_c_wrapper!($args_how, $func, $directory); 712 | )* 713 | } 714 | } 715 | 716 | 717 | #[macro_export] 718 | macro_rules! _declare_directive_c_wrapper { 719 | ($args_how:ident, $func:ident, $directory:tt) => { 720 | interpolate_idents! { 721 | _declare_directive_c_wrapper_impl!($args_how, $func, [c_ $func], $directory); 722 | } 723 | } 724 | } 725 | 726 | #[macro_export] 727 | macro_rules! _declare_directive_c_wrapper_impl { 728 | (FLAG, $func:ident, $c_func:ident, $directory:tt) => { 729 | #[allow(unused_variables)] 730 | #[allow(unused_mut)] 731 | extern "C" fn $c_func( 732 | parms: *mut $crate::ffi::cmd_parms, 733 | mconfig: *mut $crate::c_void, 734 | on: $crate::c_int 735 | ) -> *const $crate::c_char { 736 | let mut wrapper = CmdParms::from_raw(parms).unwrap(); 737 | let mut pool = Pool::from_raw(unsafe { (*parms).pool }).unwrap(); 738 | 739 | _call_config_wrapper!($func, &mut wrapper, &mut pool, mconfig, on != 0, $directory).unwrap(); 740 | 741 | std::ptr::null() 742 | } 743 | }; 744 | 745 | (TAKE1, $func:ident, $c_func:ident, $directory:tt) => { 746 | #[allow(unused_variables)] 747 | #[allow(unused_mut)] 748 | extern "C" fn $c_func( 749 | parms: *mut $crate::ffi::cmd_parms, 750 | mconfig: *mut $crate::c_void, 751 | w: *const $crate::c_char 752 | ) -> *const $crate::c_char { 753 | let mut wrapper = CmdParms::from_raw(parms).unwrap(); 754 | let mut pool = Pool::from_raw(unsafe { (*parms).pool }).unwrap(); 755 | 756 | _call_config_wrapper!($func, &mut wrapper, &mut pool, mconfig, $crate::from_char_ptr(w).unwrap(), $directory).unwrap(); 757 | 758 | std::ptr::null() 759 | } 760 | } 761 | } 762 | 763 | 764 | #[macro_export] 765 | macro_rules! _call_config_wrapper { 766 | ($func:ident, $parms:expr, $pool:expr, $mconfig:expr, $arg1:expr, {}) => { 767 | $func($parms, $arg1) 768 | }; 769 | 770 | ($func:ident, $parms:expr, $pool:expr, $mconfig:expr, $arg1:expr, { $config_struct:ident $fields:tt, $create_dir_config:ident }) => { 771 | interpolate_idents! { 772 | $func($parms, $config_struct::from_raw($pool, $mconfig as *mut [C $config_struct]), $arg1) 773 | } 774 | }; 775 | 776 | ($func:ident, $parms:expr, $pool:expr, $mconfig:expr, $arg1:expr, { $config_struct:ident $fields:tt, $create_dir_config:ident, $merge_dir_config:ident }) => { 777 | _call_config_wrapper!($func, $parms, $pool, $mconfig, $arg1, { $config_struct $fields, $create_dir_config }) 778 | } 779 | } 780 | 781 | 782 | #[macro_export] 783 | macro_rules! _declare_handlers { 784 | ($name:ident, $handlers:tt) => { 785 | _declare_hooks_entrypoint!($name, $handlers); 786 | 787 | _declare_handler_wrappers!($handlers); 788 | } 789 | } 790 | 791 | 792 | #[macro_export] 793 | macro_rules! _declare_hooks_entrypoint { 794 | ($name:ident, { $( $handler_data:tt ),* }) => { 795 | interpolate_idents! { 796 | extern "C" fn [$name _hooks](_: *mut $crate::ffi::apr_pool_t) { 797 | $( 798 | _declare_single_hook_entrypoint!($handler_data); 799 | )* 800 | } 801 | } 802 | } 803 | } 804 | 805 | 806 | #[macro_export] 807 | macro_rules! _declare_single_hook_entrypoint { 808 | (( $handler:ident, $hook:ident, $order:expr )) => { 809 | interpolate_idents! { 810 | unsafe { 811 | $crate::ffi::[ap_hook_ $hook](Some([c_ $handler]), std::ptr::null(), std::ptr::null(), $order.into()); 812 | } 813 | } 814 | } 815 | } 816 | 817 | 818 | #[macro_export] 819 | macro_rules! _declare_handler_wrappers { 820 | ({ $( $handler_data:tt ),* }) => { 821 | $( 822 | _declare_single_handler_wrapper!($handler_data); 823 | )* 824 | } 825 | } 826 | 827 | 828 | #[macro_export] 829 | macro_rules! _declare_single_handler_wrapper { 830 | (( $handler:ident, handler, $order:expr )) => { 831 | _declare_hook_handler_wrapper!($handler, $order); 832 | }; 833 | 834 | (( $handler:ident, translate_name, $order:expr )) => { 835 | _declare_hook_handler_wrapper!($handler, $order); 836 | }; 837 | 838 | (( $handler:ident, post_config, $order:expr )) => { 839 | _declare_hook_post_config_wrapper!($handler, $order); 840 | } 841 | } 842 | 843 | 844 | #[macro_export] 845 | macro_rules! _declare_hook_handler_wrapper { 846 | ($handler:ident, $order:expr) => { 847 | interpolate_idents! { 848 | extern "C" fn [c_ $handler](r: *mut $crate::ffi::request_rec) -> $crate::c_int { 849 | match $crate::httpd::Request::from_raw(r) { 850 | None => $crate::httpd::Status::DECLINED.into(), 851 | Some(mut request) => match $handler(&mut request) { 852 | Ok(status) => status, 853 | Err(_) => $crate::httpd::Status::HTTP_INTERNAL_SERVER_ERROR 854 | }.into() 855 | } 856 | } 857 | } 858 | } 859 | } 860 | 861 | 862 | #[macro_export] 863 | macro_rules! _declare_hook_post_config_wrapper { 864 | ($handler:ident, $order:expr) => { 865 | interpolate_idents! { 866 | extern "C" fn [c_ $handler](conf: *mut $crate::ffi::apr_pool_t, log: *mut $crate::ffi::apr_pool_t, temp: *mut $crate::ffi::apr_pool_t, s: *mut $crate::ffi::server_rec) -> $crate::c_int { 867 | let conf = $crate::Pool::from_raw(conf); 868 | let log = $crate::Pool::from_raw(log); 869 | let temp = $crate::Pool::from_raw(temp); 870 | let s = $crate::Server::from_raw(s); 871 | 872 | if conf.is_none() || log.is_none() || temp.is_none() || s.is_none() { 873 | $crate::httpd::Status::DECLINED.into() 874 | } else { 875 | match $handler(&mut conf.unwrap(), &mut log.unwrap(), &mut temp.unwrap(), &mut s.unwrap()) { 876 | Ok(status) => status, 877 | Err(_) => $crate::Status::HTTP_INTERNAL_SERVER_ERROR 878 | }.into() 879 | } 880 | } 881 | } 882 | } 883 | } 884 | -------------------------------------------------------------------------------- /src/wrapper.rs: -------------------------------------------------------------------------------- 1 | #![allow(raw_pointer_derive)] 2 | 3 | use std::str; 4 | use std::ffi::CStr; 5 | use libc::c_char; 6 | 7 | 8 | pub trait FromRaw: Sized { 9 | fn from_raw(T) -> Option; 10 | } 11 | 12 | #[derive(Copy, Clone)] 13 | pub struct Wrapper { 14 | pub ptr: *mut T 15 | } 16 | 17 | impl FromRaw<*mut T> for Wrapper { 18 | fn from_raw(ptr: *mut T) -> Option> { 19 | if ptr.is_null() { 20 | None 21 | } else { 22 | Some( 23 | Wrapper:: { 24 | ptr: ptr 25 | } 26 | ) 27 | } 28 | } 29 | } 30 | 31 | pub trait WrappedType { 32 | type wrapped_type; 33 | } 34 | 35 | impl WrappedType for Wrapper { 36 | type wrapped_type = T; 37 | } 38 | 39 | #[inline] 40 | pub fn from_char_ptr<'a>(ptr: *const c_char) -> Option<&'a str> { 41 | if ptr.is_null() { 42 | return None; 43 | } 44 | 45 | let slice = unsafe { CStr::from_ptr(ptr) }; 46 | str::from_utf8(slice.to_bytes()).ok() 47 | } 48 | --------------------------------------------------------------------------------