├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md ├── src ├── ext.rs ├── main.rs └── template.html └── todo.md /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | *~ 3 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "aho-corasick" 5 | version = "0.7.6" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | dependencies = [ 8 | "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 9 | ] 10 | 11 | [[package]] 12 | name = "ansi_term" 13 | version = "0.11.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | dependencies = [ 16 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 17 | ] 18 | 19 | [[package]] 20 | name = "atty" 21 | version = "0.2.13" 22 | source = "registry+https://github.com/rust-lang/crates.io-index" 23 | dependencies = [ 24 | "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 25 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 26 | ] 27 | 28 | [[package]] 29 | name = "autocfg" 30 | version = "0.1.7" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | 33 | [[package]] 34 | name = "basic-http-server" 35 | version = "0.8.1" 36 | dependencies = [ 37 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 38 | "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", 39 | "comrak 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", 40 | "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", 41 | "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", 42 | "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 43 | "handlebars 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 44 | "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", 45 | "hyper 0.13.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", 46 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 47 | "mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", 48 | "mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 49 | "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 50 | "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", 51 | "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", 52 | "tokio 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 53 | "tokio-fs 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 54 | ] 55 | 56 | [[package]] 57 | name = "bitflags" 58 | version = "1.2.1" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | 61 | [[package]] 62 | name = "block-buffer" 63 | version = "0.7.3" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | dependencies = [ 66 | "block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 67 | "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 68 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 69 | "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", 70 | ] 71 | 72 | [[package]] 73 | name = "block-padding" 74 | version = "0.1.5" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | dependencies = [ 77 | "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 78 | ] 79 | 80 | [[package]] 81 | name = "byte-tools" 82 | version = "0.3.1" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | 85 | [[package]] 86 | name = "byteorder" 87 | version = "1.3.2" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | 90 | [[package]] 91 | name = "bytes" 92 | version = "0.4.12" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | dependencies = [ 95 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 96 | "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 97 | ] 98 | 99 | [[package]] 100 | name = "cfg-if" 101 | version = "0.1.10" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | 104 | [[package]] 105 | name = "clap" 106 | version = "2.33.0" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | dependencies = [ 109 | "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 110 | "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", 111 | "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 112 | "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 113 | "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 114 | "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 115 | "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 116 | ] 117 | 118 | [[package]] 119 | name = "cloudabi" 120 | version = "0.0.3" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | dependencies = [ 123 | "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 124 | ] 125 | 126 | [[package]] 127 | name = "comrak" 128 | version = "0.6.2" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | dependencies = [ 131 | "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", 132 | "entities 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 133 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 134 | "pest 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 135 | "pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 136 | "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 137 | "twoway 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 138 | "typed-arena 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 139 | "unicode_categories 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 140 | ] 141 | 142 | [[package]] 143 | name = "crossbeam-channel" 144 | version = "0.3.9" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | dependencies = [ 147 | "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", 148 | ] 149 | 150 | [[package]] 151 | name = "crossbeam-deque" 152 | version = "0.7.2" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | dependencies = [ 155 | "crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 156 | "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 157 | ] 158 | 159 | [[package]] 160 | name = "crossbeam-epoch" 161 | version = "0.8.0" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | dependencies = [ 164 | "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 165 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 166 | "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 167 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 168 | "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", 169 | "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 170 | ] 171 | 172 | [[package]] 173 | name = "crossbeam-queue" 174 | version = "0.1.2" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | dependencies = [ 177 | "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", 178 | ] 179 | 180 | [[package]] 181 | name = "crossbeam-utils" 182 | version = "0.6.6" 183 | source = "registry+https://github.com/rust-lang/crates.io-index" 184 | dependencies = [ 185 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 186 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 187 | ] 188 | 189 | [[package]] 190 | name = "crossbeam-utils" 191 | version = "0.7.0" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | dependencies = [ 194 | "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 195 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 196 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 197 | ] 198 | 199 | [[package]] 200 | name = "derive_more" 201 | version = "0.15.0" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | dependencies = [ 204 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 205 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 206 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 207 | "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 208 | "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 209 | "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", 210 | ] 211 | 212 | [[package]] 213 | name = "digest" 214 | version = "0.8.1" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | dependencies = [ 217 | "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", 218 | ] 219 | 220 | [[package]] 221 | name = "entities" 222 | version = "1.0.1" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | 225 | [[package]] 226 | name = "env_logger" 227 | version = "0.6.2" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | dependencies = [ 230 | "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", 231 | "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 232 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 233 | "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 234 | "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 235 | ] 236 | 237 | [[package]] 238 | name = "fake-simd" 239 | version = "0.1.2" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | 242 | [[package]] 243 | name = "fnv" 244 | version = "1.0.6" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | 247 | [[package]] 248 | name = "fuchsia-zircon" 249 | version = "0.3.3" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | dependencies = [ 252 | "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 253 | "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 254 | ] 255 | 256 | [[package]] 257 | name = "fuchsia-zircon-sys" 258 | version = "0.3.3" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | 261 | [[package]] 262 | name = "futures-channel-preview" 263 | version = "0.3.0-alpha.19" 264 | source = "registry+https://github.com/rust-lang/crates.io-index" 265 | dependencies = [ 266 | "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 267 | "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 268 | ] 269 | 270 | [[package]] 271 | name = "futures-core-preview" 272 | version = "0.3.0-alpha.19" 273 | source = "registry+https://github.com/rust-lang/crates.io-index" 274 | 275 | [[package]] 276 | name = "futures-executor-preview" 277 | version = "0.3.0-alpha.19" 278 | source = "registry+https://github.com/rust-lang/crates.io-index" 279 | dependencies = [ 280 | "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 281 | "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 282 | "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 283 | ] 284 | 285 | [[package]] 286 | name = "futures-io-preview" 287 | version = "0.3.0-alpha.19" 288 | source = "registry+https://github.com/rust-lang/crates.io-index" 289 | 290 | [[package]] 291 | name = "futures-preview" 292 | version = "0.3.0-alpha.19" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | dependencies = [ 295 | "futures-channel-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 296 | "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 297 | "futures-executor-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 298 | "futures-io-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 299 | "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 300 | "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 301 | ] 302 | 303 | [[package]] 304 | name = "futures-sink-preview" 305 | version = "0.3.0-alpha.19" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | 308 | [[package]] 309 | name = "futures-util-preview" 310 | version = "0.3.0-alpha.19" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | dependencies = [ 313 | "futures-channel-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 314 | "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 315 | "futures-io-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 316 | "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 317 | "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 318 | "pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", 319 | "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 320 | ] 321 | 322 | [[package]] 323 | name = "generic-array" 324 | version = "0.12.3" 325 | source = "registry+https://github.com/rust-lang/crates.io-index" 326 | dependencies = [ 327 | "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", 328 | ] 329 | 330 | [[package]] 331 | name = "h2" 332 | version = "0.2.0-alpha.3" 333 | source = "registry+https://github.com/rust-lang/crates.io-index" 334 | dependencies = [ 335 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 336 | "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 337 | "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 338 | "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 339 | "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 340 | "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", 341 | "indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 342 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 343 | "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 344 | "string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 345 | "tokio-codec 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 346 | "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 347 | "tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 348 | ] 349 | 350 | [[package]] 351 | name = "handlebars" 352 | version = "1.1.0" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | dependencies = [ 355 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 356 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 357 | "pest 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 358 | "pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 359 | "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 360 | "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 361 | "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", 362 | "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", 363 | "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", 364 | ] 365 | 366 | [[package]] 367 | name = "heck" 368 | version = "0.3.1" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | dependencies = [ 371 | "unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", 372 | ] 373 | 374 | [[package]] 375 | name = "hermit-abi" 376 | version = "0.1.3" 377 | source = "registry+https://github.com/rust-lang/crates.io-index" 378 | dependencies = [ 379 | "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 380 | ] 381 | 382 | [[package]] 383 | name = "http" 384 | version = "0.1.19" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | dependencies = [ 387 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 388 | "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 389 | "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 390 | ] 391 | 392 | [[package]] 393 | name = "http-body" 394 | version = "0.2.0-alpha.3" 395 | source = "registry+https://github.com/rust-lang/crates.io-index" 396 | dependencies = [ 397 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 398 | "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", 399 | ] 400 | 401 | [[package]] 402 | name = "httparse" 403 | version = "1.3.4" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | 406 | [[package]] 407 | name = "humantime" 408 | version = "1.3.0" 409 | source = "registry+https://github.com/rust-lang/crates.io-index" 410 | dependencies = [ 411 | "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 412 | ] 413 | 414 | [[package]] 415 | name = "hyper" 416 | version = "0.13.0-alpha.4" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | dependencies = [ 419 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 420 | "futures-channel-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 421 | "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 422 | "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 423 | "h2 0.2.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)", 424 | "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", 425 | "http-body 0.2.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)", 426 | "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", 427 | "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 428 | "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 429 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 430 | "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", 431 | "pin-project 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", 432 | "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", 433 | "tokio 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 434 | "tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 435 | "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 436 | "tokio-net 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 437 | "tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 438 | "tokio-timer 0.3.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 439 | "tower-make 0.3.0-alpha.2a (registry+https://github.com/rust-lang/crates.io-index)", 440 | "tower-service 0.3.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)", 441 | "want 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 442 | ] 443 | 444 | [[package]] 445 | name = "indexmap" 446 | version = "1.3.0" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | dependencies = [ 449 | "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 450 | ] 451 | 452 | [[package]] 453 | name = "iovec" 454 | version = "0.1.4" 455 | source = "registry+https://github.com/rust-lang/crates.io-index" 456 | dependencies = [ 457 | "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 458 | ] 459 | 460 | [[package]] 461 | name = "itoa" 462 | version = "0.4.4" 463 | source = "registry+https://github.com/rust-lang/crates.io-index" 464 | 465 | [[package]] 466 | name = "kernel32-sys" 467 | version = "0.2.2" 468 | source = "registry+https://github.com/rust-lang/crates.io-index" 469 | dependencies = [ 470 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 471 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 472 | ] 473 | 474 | [[package]] 475 | name = "lazy_static" 476 | version = "1.4.0" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | dependencies = [ 479 | "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 480 | ] 481 | 482 | [[package]] 483 | name = "libc" 484 | version = "0.2.65" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | 487 | [[package]] 488 | name = "lock_api" 489 | version = "0.3.1" 490 | source = "registry+https://github.com/rust-lang/crates.io-index" 491 | dependencies = [ 492 | "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 493 | ] 494 | 495 | [[package]] 496 | name = "log" 497 | version = "0.4.8" 498 | source = "registry+https://github.com/rust-lang/crates.io-index" 499 | dependencies = [ 500 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 501 | ] 502 | 503 | [[package]] 504 | name = "maplit" 505 | version = "1.0.2" 506 | source = "registry+https://github.com/rust-lang/crates.io-index" 507 | 508 | [[package]] 509 | name = "maybe-uninit" 510 | version = "2.0.0" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | 513 | [[package]] 514 | name = "memchr" 515 | version = "2.2.1" 516 | source = "registry+https://github.com/rust-lang/crates.io-index" 517 | 518 | [[package]] 519 | name = "memoffset" 520 | version = "0.5.3" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | dependencies = [ 523 | "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 524 | ] 525 | 526 | [[package]] 527 | name = "mime" 528 | version = "0.3.14" 529 | source = "registry+https://github.com/rust-lang/crates.io-index" 530 | 531 | [[package]] 532 | name = "mime_guess" 533 | version = "2.0.1" 534 | source = "registry+https://github.com/rust-lang/crates.io-index" 535 | dependencies = [ 536 | "mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", 537 | "unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", 538 | ] 539 | 540 | [[package]] 541 | name = "mio" 542 | version = "0.6.19" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | dependencies = [ 545 | "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 546 | "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 547 | "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 548 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 549 | "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 550 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 551 | "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 552 | "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", 553 | "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 554 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 555 | ] 556 | 557 | [[package]] 558 | name = "mio-uds" 559 | version = "0.6.7" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | dependencies = [ 562 | "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 563 | "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 564 | "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", 565 | ] 566 | 567 | [[package]] 568 | name = "miow" 569 | version = "0.2.1" 570 | source = "registry+https://github.com/rust-lang/crates.io-index" 571 | dependencies = [ 572 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 573 | "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", 574 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 575 | "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 576 | ] 577 | 578 | [[package]] 579 | name = "net2" 580 | version = "0.2.33" 581 | source = "registry+https://github.com/rust-lang/crates.io-index" 582 | dependencies = [ 583 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 584 | "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 585 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 586 | ] 587 | 588 | [[package]] 589 | name = "num_cpus" 590 | version = "1.11.0" 591 | source = "registry+https://github.com/rust-lang/crates.io-index" 592 | dependencies = [ 593 | "hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 594 | "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 595 | ] 596 | 597 | [[package]] 598 | name = "opaque-debug" 599 | version = "0.2.3" 600 | source = "registry+https://github.com/rust-lang/crates.io-index" 601 | 602 | [[package]] 603 | name = "parking_lot" 604 | version = "0.9.0" 605 | source = "registry+https://github.com/rust-lang/crates.io-index" 606 | dependencies = [ 607 | "lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 608 | "parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", 609 | "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 610 | ] 611 | 612 | [[package]] 613 | name = "parking_lot_core" 614 | version = "0.6.2" 615 | source = "registry+https://github.com/rust-lang/crates.io-index" 616 | dependencies = [ 617 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 618 | "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 619 | "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 620 | "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", 621 | "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 622 | "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 623 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 624 | ] 625 | 626 | [[package]] 627 | name = "percent-encoding" 628 | version = "2.1.0" 629 | source = "registry+https://github.com/rust-lang/crates.io-index" 630 | 631 | [[package]] 632 | name = "pest" 633 | version = "2.1.2" 634 | source = "registry+https://github.com/rust-lang/crates.io-index" 635 | dependencies = [ 636 | "ucd-trie 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 637 | ] 638 | 639 | [[package]] 640 | name = "pest_derive" 641 | version = "2.1.0" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | dependencies = [ 644 | "pest 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 645 | "pest_generator 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 646 | ] 647 | 648 | [[package]] 649 | name = "pest_generator" 650 | version = "2.1.1" 651 | source = "registry+https://github.com/rust-lang/crates.io-index" 652 | dependencies = [ 653 | "pest 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 654 | "pest_meta 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 655 | "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 656 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 657 | "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", 658 | ] 659 | 660 | [[package]] 661 | name = "pest_meta" 662 | version = "2.1.2" 663 | source = "registry+https://github.com/rust-lang/crates.io-index" 664 | dependencies = [ 665 | "maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 666 | "pest 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 667 | "sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 668 | ] 669 | 670 | [[package]] 671 | name = "pin-project" 672 | version = "0.4.5" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | dependencies = [ 675 | "pin-project-internal 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", 676 | ] 677 | 678 | [[package]] 679 | name = "pin-project-internal" 680 | version = "0.4.5" 681 | source = "registry+https://github.com/rust-lang/crates.io-index" 682 | dependencies = [ 683 | "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 684 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 685 | "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", 686 | ] 687 | 688 | [[package]] 689 | name = "pin-utils" 690 | version = "0.1.0-alpha.4" 691 | source = "registry+https://github.com/rust-lang/crates.io-index" 692 | 693 | [[package]] 694 | name = "proc-macro2" 695 | version = "0.4.30" 696 | source = "registry+https://github.com/rust-lang/crates.io-index" 697 | dependencies = [ 698 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 699 | ] 700 | 701 | [[package]] 702 | name = "proc-macro2" 703 | version = "1.0.6" 704 | source = "registry+https://github.com/rust-lang/crates.io-index" 705 | dependencies = [ 706 | "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 707 | ] 708 | 709 | [[package]] 710 | name = "quick-error" 711 | version = "1.2.2" 712 | source = "registry+https://github.com/rust-lang/crates.io-index" 713 | 714 | [[package]] 715 | name = "quote" 716 | version = "0.6.13" 717 | source = "registry+https://github.com/rust-lang/crates.io-index" 718 | dependencies = [ 719 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 720 | ] 721 | 722 | [[package]] 723 | name = "quote" 724 | version = "1.0.2" 725 | source = "registry+https://github.com/rust-lang/crates.io-index" 726 | dependencies = [ 727 | "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 728 | ] 729 | 730 | [[package]] 731 | name = "redox_syscall" 732 | version = "0.1.56" 733 | source = "registry+https://github.com/rust-lang/crates.io-index" 734 | 735 | [[package]] 736 | name = "regex" 737 | version = "1.3.1" 738 | source = "registry+https://github.com/rust-lang/crates.io-index" 739 | dependencies = [ 740 | "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", 741 | "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 742 | "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", 743 | "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 744 | ] 745 | 746 | [[package]] 747 | name = "regex-syntax" 748 | version = "0.6.12" 749 | source = "registry+https://github.com/rust-lang/crates.io-index" 750 | 751 | [[package]] 752 | name = "rustc_version" 753 | version = "0.2.3" 754 | source = "registry+https://github.com/rust-lang/crates.io-index" 755 | dependencies = [ 756 | "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 757 | ] 758 | 759 | [[package]] 760 | name = "ryu" 761 | version = "1.0.2" 762 | source = "registry+https://github.com/rust-lang/crates.io-index" 763 | 764 | [[package]] 765 | name = "same-file" 766 | version = "1.0.5" 767 | source = "registry+https://github.com/rust-lang/crates.io-index" 768 | dependencies = [ 769 | "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 770 | ] 771 | 772 | [[package]] 773 | name = "scopeguard" 774 | version = "1.0.0" 775 | source = "registry+https://github.com/rust-lang/crates.io-index" 776 | 777 | [[package]] 778 | name = "semver" 779 | version = "0.9.0" 780 | source = "registry+https://github.com/rust-lang/crates.io-index" 781 | dependencies = [ 782 | "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 783 | ] 784 | 785 | [[package]] 786 | name = "semver-parser" 787 | version = "0.7.0" 788 | source = "registry+https://github.com/rust-lang/crates.io-index" 789 | 790 | [[package]] 791 | name = "serde" 792 | version = "1.0.102" 793 | source = "registry+https://github.com/rust-lang/crates.io-index" 794 | dependencies = [ 795 | "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", 796 | ] 797 | 798 | [[package]] 799 | name = "serde_derive" 800 | version = "1.0.102" 801 | source = "registry+https://github.com/rust-lang/crates.io-index" 802 | dependencies = [ 803 | "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 804 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 805 | "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", 806 | ] 807 | 808 | [[package]] 809 | name = "serde_json" 810 | version = "1.0.41" 811 | source = "registry+https://github.com/rust-lang/crates.io-index" 812 | dependencies = [ 813 | "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 814 | "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 815 | "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", 816 | ] 817 | 818 | [[package]] 819 | name = "sha-1" 820 | version = "0.8.1" 821 | source = "registry+https://github.com/rust-lang/crates.io-index" 822 | dependencies = [ 823 | "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", 824 | "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 825 | "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 826 | "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 827 | ] 828 | 829 | [[package]] 830 | name = "slab" 831 | version = "0.4.2" 832 | source = "registry+https://github.com/rust-lang/crates.io-index" 833 | 834 | [[package]] 835 | name = "smallvec" 836 | version = "0.6.13" 837 | source = "registry+https://github.com/rust-lang/crates.io-index" 838 | dependencies = [ 839 | "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 840 | ] 841 | 842 | [[package]] 843 | name = "spin" 844 | version = "0.5.2" 845 | source = "registry+https://github.com/rust-lang/crates.io-index" 846 | 847 | [[package]] 848 | name = "string" 849 | version = "0.2.1" 850 | source = "registry+https://github.com/rust-lang/crates.io-index" 851 | dependencies = [ 852 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 853 | ] 854 | 855 | [[package]] 856 | name = "strsim" 857 | version = "0.8.0" 858 | source = "registry+https://github.com/rust-lang/crates.io-index" 859 | 860 | [[package]] 861 | name = "structopt" 862 | version = "0.2.18" 863 | source = "registry+https://github.com/rust-lang/crates.io-index" 864 | dependencies = [ 865 | "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", 866 | "structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", 867 | ] 868 | 869 | [[package]] 870 | name = "structopt-derive" 871 | version = "0.2.18" 872 | source = "registry+https://github.com/rust-lang/crates.io-index" 873 | dependencies = [ 874 | "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 875 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 876 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 877 | "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", 878 | ] 879 | 880 | [[package]] 881 | name = "syn" 882 | version = "0.15.44" 883 | source = "registry+https://github.com/rust-lang/crates.io-index" 884 | dependencies = [ 885 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 886 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 887 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 888 | ] 889 | 890 | [[package]] 891 | name = "syn" 892 | version = "1.0.8" 893 | source = "registry+https://github.com/rust-lang/crates.io-index" 894 | dependencies = [ 895 | "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 896 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 897 | "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 898 | ] 899 | 900 | [[package]] 901 | name = "termcolor" 902 | version = "1.0.5" 903 | source = "registry+https://github.com/rust-lang/crates.io-index" 904 | dependencies = [ 905 | "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 906 | ] 907 | 908 | [[package]] 909 | name = "textwrap" 910 | version = "0.11.0" 911 | source = "registry+https://github.com/rust-lang/crates.io-index" 912 | dependencies = [ 913 | "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 914 | ] 915 | 916 | [[package]] 917 | name = "thread_local" 918 | version = "0.3.6" 919 | source = "registry+https://github.com/rust-lang/crates.io-index" 920 | dependencies = [ 921 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 922 | ] 923 | 924 | [[package]] 925 | name = "time" 926 | version = "0.1.42" 927 | source = "registry+https://github.com/rust-lang/crates.io-index" 928 | dependencies = [ 929 | "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 930 | "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", 931 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 932 | ] 933 | 934 | [[package]] 935 | name = "tokio" 936 | version = "0.2.0-alpha.6" 937 | source = "registry+https://github.com/rust-lang/crates.io-index" 938 | dependencies = [ 939 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 940 | "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 941 | "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 942 | "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 943 | "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 944 | "tokio-codec 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 945 | "tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 946 | "tokio-fs 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 947 | "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 948 | "tokio-macros 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 949 | "tokio-net 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 950 | "tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 951 | "tokio-timer 0.3.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 952 | "tracing-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 953 | ] 954 | 955 | [[package]] 956 | name = "tokio-codec" 957 | version = "0.2.0-alpha.6" 958 | source = "registry+https://github.com/rust-lang/crates.io-index" 959 | dependencies = [ 960 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 961 | "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 962 | "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 963 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 964 | "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 965 | ] 966 | 967 | [[package]] 968 | name = "tokio-executor" 969 | version = "0.2.0-alpha.6" 970 | source = "registry+https://github.com/rust-lang/crates.io-index" 971 | dependencies = [ 972 | "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", 973 | "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 974 | "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 975 | "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", 976 | "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 977 | "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 978 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 979 | "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 980 | "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 981 | "tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 982 | "tracing 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 983 | ] 984 | 985 | [[package]] 986 | name = "tokio-fs" 987 | version = "0.2.0-alpha.6" 988 | source = "registry+https://github.com/rust-lang/crates.io-index" 989 | dependencies = [ 990 | "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 991 | "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 992 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 993 | "tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 994 | "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 995 | "tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 996 | ] 997 | 998 | [[package]] 999 | name = "tokio-io" 1000 | version = "0.2.0-alpha.6" 1001 | source = "registry+https://github.com/rust-lang/crates.io-index" 1002 | dependencies = [ 1003 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 1004 | "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 1005 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1006 | "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 1007 | "pin-project 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", 1008 | ] 1009 | 1010 | [[package]] 1011 | name = "tokio-macros" 1012 | version = "0.2.0-alpha.6" 1013 | source = "registry+https://github.com/rust-lang/crates.io-index" 1014 | dependencies = [ 1015 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1016 | "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", 1017 | ] 1018 | 1019 | [[package]] 1020 | name = "tokio-net" 1021 | version = "0.2.0-alpha.6" 1022 | source = "registry+https://github.com/rust-lang/crates.io-index" 1023 | dependencies = [ 1024 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 1025 | "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", 1026 | "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 1027 | "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 1028 | "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 1029 | "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 1030 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1031 | "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 1032 | "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", 1033 | "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", 1034 | "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 1035 | "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 1036 | "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 1037 | "tokio-codec 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 1038 | "tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 1039 | "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 1040 | "tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 1041 | "tracing 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 1042 | ] 1043 | 1044 | [[package]] 1045 | name = "tokio-sync" 1046 | version = "0.2.0-alpha.6" 1047 | source = "registry+https://github.com/rust-lang/crates.io-index" 1048 | dependencies = [ 1049 | "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 1050 | "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 1051 | "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 1052 | "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 1053 | ] 1054 | 1055 | [[package]] 1056 | name = "tokio-timer" 1057 | version = "0.3.0-alpha.6" 1058 | source = "registry+https://github.com/rust-lang/crates.io-index" 1059 | dependencies = [ 1060 | "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", 1061 | "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 1062 | "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", 1063 | "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 1064 | "tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 1065 | "tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 1066 | ] 1067 | 1068 | [[package]] 1069 | name = "tower-make" 1070 | version = "0.3.0-alpha.2a" 1071 | source = "registry+https://github.com/rust-lang/crates.io-index" 1072 | dependencies = [ 1073 | "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", 1074 | "tower-service 0.3.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)", 1075 | ] 1076 | 1077 | [[package]] 1078 | name = "tower-service" 1079 | version = "0.3.0-alpha.2" 1080 | source = "registry+https://github.com/rust-lang/crates.io-index" 1081 | 1082 | [[package]] 1083 | name = "tracing" 1084 | version = "0.1.10" 1085 | source = "registry+https://github.com/rust-lang/crates.io-index" 1086 | dependencies = [ 1087 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 1088 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1089 | "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 1090 | "tracing-attributes 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 1091 | "tracing-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 1092 | ] 1093 | 1094 | [[package]] 1095 | name = "tracing-attributes" 1096 | version = "0.1.5" 1097 | source = "registry+https://github.com/rust-lang/crates.io-index" 1098 | dependencies = [ 1099 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1100 | "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", 1101 | ] 1102 | 1103 | [[package]] 1104 | name = "tracing-core" 1105 | version = "0.1.7" 1106 | source = "registry+https://github.com/rust-lang/crates.io-index" 1107 | dependencies = [ 1108 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1109 | "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 1110 | ] 1111 | 1112 | [[package]] 1113 | name = "try-lock" 1114 | version = "0.2.2" 1115 | source = "registry+https://github.com/rust-lang/crates.io-index" 1116 | 1117 | [[package]] 1118 | name = "twoway" 1119 | version = "0.2.1" 1120 | source = "registry+https://github.com/rust-lang/crates.io-index" 1121 | dependencies = [ 1122 | "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 1123 | "unchecked-index 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 1124 | ] 1125 | 1126 | [[package]] 1127 | name = "typed-arena" 1128 | version = "1.7.0" 1129 | source = "registry+https://github.com/rust-lang/crates.io-index" 1130 | 1131 | [[package]] 1132 | name = "typenum" 1133 | version = "1.11.2" 1134 | source = "registry+https://github.com/rust-lang/crates.io-index" 1135 | 1136 | [[package]] 1137 | name = "ucd-trie" 1138 | version = "0.1.2" 1139 | source = "registry+https://github.com/rust-lang/crates.io-index" 1140 | 1141 | [[package]] 1142 | name = "unchecked-index" 1143 | version = "0.2.2" 1144 | source = "registry+https://github.com/rust-lang/crates.io-index" 1145 | 1146 | [[package]] 1147 | name = "unicase" 1148 | version = "2.6.0" 1149 | source = "registry+https://github.com/rust-lang/crates.io-index" 1150 | dependencies = [ 1151 | "version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", 1152 | ] 1153 | 1154 | [[package]] 1155 | name = "unicode-segmentation" 1156 | version = "1.6.0" 1157 | source = "registry+https://github.com/rust-lang/crates.io-index" 1158 | 1159 | [[package]] 1160 | name = "unicode-width" 1161 | version = "0.1.6" 1162 | source = "registry+https://github.com/rust-lang/crates.io-index" 1163 | 1164 | [[package]] 1165 | name = "unicode-xid" 1166 | version = "0.1.0" 1167 | source = "registry+https://github.com/rust-lang/crates.io-index" 1168 | 1169 | [[package]] 1170 | name = "unicode-xid" 1171 | version = "0.2.0" 1172 | source = "registry+https://github.com/rust-lang/crates.io-index" 1173 | 1174 | [[package]] 1175 | name = "unicode_categories" 1176 | version = "0.1.1" 1177 | source = "registry+https://github.com/rust-lang/crates.io-index" 1178 | 1179 | [[package]] 1180 | name = "vec_map" 1181 | version = "0.8.1" 1182 | source = "registry+https://github.com/rust-lang/crates.io-index" 1183 | 1184 | [[package]] 1185 | name = "version_check" 1186 | version = "0.9.1" 1187 | source = "registry+https://github.com/rust-lang/crates.io-index" 1188 | 1189 | [[package]] 1190 | name = "walkdir" 1191 | version = "2.2.9" 1192 | source = "registry+https://github.com/rust-lang/crates.io-index" 1193 | dependencies = [ 1194 | "same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 1195 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 1196 | "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 1197 | ] 1198 | 1199 | [[package]] 1200 | name = "want" 1201 | version = "0.3.0" 1202 | source = "registry+https://github.com/rust-lang/crates.io-index" 1203 | dependencies = [ 1204 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1205 | "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 1206 | ] 1207 | 1208 | [[package]] 1209 | name = "winapi" 1210 | version = "0.2.8" 1211 | source = "registry+https://github.com/rust-lang/crates.io-index" 1212 | 1213 | [[package]] 1214 | name = "winapi" 1215 | version = "0.3.8" 1216 | source = "registry+https://github.com/rust-lang/crates.io-index" 1217 | dependencies = [ 1218 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1219 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1220 | ] 1221 | 1222 | [[package]] 1223 | name = "winapi-build" 1224 | version = "0.1.1" 1225 | source = "registry+https://github.com/rust-lang/crates.io-index" 1226 | 1227 | [[package]] 1228 | name = "winapi-i686-pc-windows-gnu" 1229 | version = "0.4.0" 1230 | source = "registry+https://github.com/rust-lang/crates.io-index" 1231 | 1232 | [[package]] 1233 | name = "winapi-util" 1234 | version = "0.1.2" 1235 | source = "registry+https://github.com/rust-lang/crates.io-index" 1236 | dependencies = [ 1237 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 1238 | ] 1239 | 1240 | [[package]] 1241 | name = "winapi-x86_64-pc-windows-gnu" 1242 | version = "0.4.0" 1243 | source = "registry+https://github.com/rust-lang/crates.io-index" 1244 | 1245 | [[package]] 1246 | name = "wincolor" 1247 | version = "1.0.2" 1248 | source = "registry+https://github.com/rust-lang/crates.io-index" 1249 | dependencies = [ 1250 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 1251 | "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 1252 | ] 1253 | 1254 | [[package]] 1255 | name = "ws2_32-sys" 1256 | version = "0.2.1" 1257 | source = "registry+https://github.com/rust-lang/crates.io-index" 1258 | dependencies = [ 1259 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 1260 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 1261 | ] 1262 | 1263 | [metadata] 1264 | "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" 1265 | "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 1266 | "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" 1267 | "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" 1268 | "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 1269 | "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" 1270 | "checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" 1271 | "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" 1272 | "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" 1273 | "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" 1274 | "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 1275 | "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" 1276 | "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 1277 | "checksum comrak 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ea4c29f52463abf5c7a3ae33dd9b404e2031af82f547cfe65bfac17ba785ea2e" 1278 | "checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" 1279 | "checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca" 1280 | "checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac" 1281 | "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" 1282 | "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" 1283 | "checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" 1284 | "checksum derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a141330240c921ec6d074a3e188a7c7ef95668bb95e7d44fa0e5778ec2a7afe" 1285 | "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" 1286 | "checksum entities 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" 1287 | "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" 1288 | "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" 1289 | "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" 1290 | "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 1291 | "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 1292 | "checksum futures-channel-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "d5e5f4df964fa9c1c2f8bddeb5c3611631cacd93baf810fc8bb2fb4b495c263a" 1293 | "checksum futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "b35b6263fb1ef523c3056565fa67b1d16f0a8604ff12b11b08c25f28a734c60a" 1294 | "checksum futures-executor-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "75236e88bd9fe88e5e8bfcd175b665d0528fe03ca4c5207fabc028c8f9d93e98" 1295 | "checksum futures-io-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "f4914ae450db1921a56c91bde97a27846287d062087d4a652efc09bb3a01ebda" 1296 | "checksum futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "3b1dce2a0267ada5c6ff75a8ba864b4e679a9e2aa44262af7a3b5516d530d76e" 1297 | "checksum futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "86f148ef6b69f75bb610d4f9a2336d4fc88c4b5b67129d1a340dd0fd362efeec" 1298 | "checksum futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "5ce968633c17e5f97936bd2797b6e38fb56cf16a7422319f7ec2e30d3c470e8d" 1299 | "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" 1300 | "checksum h2 0.2.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0f107db1419ef8271686187b1a5d47c6431af4a7f4d98b495e7b7fc249bb0a78" 1301 | "checksum handlebars 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d82e5750d8027a97b9640e3fefa66bbaf852a35228e1c90790efd13c4b09c166" 1302 | "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" 1303 | "checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120" 1304 | "checksum http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "d7e06e336150b178206af098a055e3621e8336027e2b4d126bda0bc64824baaf" 1305 | "checksum http-body 0.2.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1f3aef6f3de2bd8585f5b366f3f550b5774500b4764d00cf00f903c95749eec3" 1306 | "checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" 1307 | "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" 1308 | "checksum hyper 0.13.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2d05aa523087ac0b9d8b93dd80d5d482a697308ed3b0dca7b0667511a7fa7cdc" 1309 | "checksum indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d7b3ea5827fcb9d4fda14bf4da5f136f0db2ae9c8f4bd4e2d1c6fde4e6db2" 1310 | "checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" 1311 | "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" 1312 | "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 1313 | "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 1314 | "checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" 1315 | "checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc" 1316 | "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 1317 | "checksum maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" 1318 | "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" 1319 | "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" 1320 | "checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" 1321 | "checksum mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "dd1d63acd1b78403cc0c325605908475dd9b9a3acbf65ed8bcab97e27014afcf" 1322 | "checksum mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a0ed03949aef72dbdf3116a383d7b38b4768e6f960528cd6a6044aa9ed68599" 1323 | "checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" 1324 | "checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" 1325 | "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" 1326 | "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" 1327 | "checksum num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "155394f924cdddf08149da25bfb932d226b4a593ca7468b08191ff6335941af5" 1328 | "checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" 1329 | "checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" 1330 | "checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" 1331 | "checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 1332 | "checksum pest 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e4fb201c5c22a55d8b24fef95f78be52738e5e1361129be1b5e862ecdb6894a" 1333 | "checksum pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" 1334 | "checksum pest_generator 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9fcf299b5712d06ee128a556c94709aaa04512c4dffb8ead07c5c998447fc0" 1335 | "checksum pest_meta 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "df43fd99896fd72c485fe47542c7b500e4ac1e8700bf995544d1317a60ded547" 1336 | "checksum pin-project 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c5fce7042b4e4338a3f868e563fff394709c3ff62cf6908d407dd9e2caff96ed" 1337 | "checksum pin-project-internal 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7644b4721cc27235f667e735da8732f5b781c442157315674c0cb7f28b4cabf3" 1338 | "checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" 1339 | "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" 1340 | "checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" 1341 | "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" 1342 | "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" 1343 | "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" 1344 | "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" 1345 | "checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" 1346 | "checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" 1347 | "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 1348 | "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" 1349 | "checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" 1350 | "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" 1351 | "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 1352 | "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 1353 | "checksum serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4b39bd9b0b087684013a792c59e3e07a46a01d2322518d8a1104641a0b1be0" 1354 | "checksum serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "ca13fc1a832f793322228923fbb3aba9f3f44444898f835d31ad1b74fa0a2bf8" 1355 | "checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" 1356 | "checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68" 1357 | "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 1358 | "checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" 1359 | "checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 1360 | "checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" 1361 | "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 1362 | "checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" 1363 | "checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" 1364 | "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" 1365 | "checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92" 1366 | "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" 1367 | "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 1368 | "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" 1369 | "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" 1370 | "checksum tokio 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1f17f5d6ab0f35c1506678b28fb1798bdf74fcb737e9843c7b17b73e426eba38" 1371 | "checksum tokio-codec 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9f5d22fd1e84bd4045d28813491cb7d7caae34d45c80517c2213f09a85e8787a" 1372 | "checksum tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9ee9ceecf69145923834ea73f32ba40c790fd877b74a7817dd0b089f1eb9c7c8" 1373 | "checksum tokio-fs 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bf85e16971e06e680c622e0c1b455be94b086275c5ddcd6d4a83a2bfbb83cda" 1374 | "checksum tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "112784d5543df30660b04a72ca423bfbd90e8bb32f94dcf610f15401218b22c5" 1375 | "checksum tokio-macros 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "86b616374bcdadd95974e1f0dfca07dc913f1163c53840c0d664aca35114964e" 1376 | "checksum tokio-net 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a441682cd32f3559383112c4a7f372f5c9fa1950c5cf8c8dd05274a2ce8c2654" 1377 | "checksum tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4f1aaeb685540f7407ea0e27f1c9757d258c7c6bf4e3eb19da6fc59b747239d2" 1378 | "checksum tokio-timer 0.3.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b97c1587fe71018eb245a4a9daa13a5a3b681bbc1f7fdadfe24720e141472c13" 1379 | "checksum tower-make 0.3.0-alpha.2a (registry+https://github.com/rust-lang/crates.io-index)" = "316d47dd40cde4ac5d88110eaf9a10a4e2a68612d9c056cd2aa24e37dcb484cd" 1380 | "checksum tower-service 0.3.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "63ff37396cd966ce43bea418bfa339f802857495f797dafa00bea5b7221ebdfa" 1381 | "checksum tracing 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ff4e4f59e752cb3beb5b61c6d5e11191c7946231ba84faec2902c9efdd8691c5" 1382 | "checksum tracing-attributes 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a4263b12c3d3c403274493eb805966093b53214124796552d674ca1dd5d27c2b" 1383 | "checksum tracing-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bc913647c520c959b6d21e35ed8fa6984971deca9f0a2fcb8c51207e0c56af1d" 1384 | "checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" 1385 | "checksum twoway 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6b40075910de3a912adbd80b5d8bad6ad10a23eeb1f5bf9d4006839e899ba5bc" 1386 | "checksum typed-arena 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b2228007eba4120145f785df0f6c92ea538f5a3635a612ecf4e334c8c1446d" 1387 | "checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" 1388 | "checksum ucd-trie 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8f00ed7be0c1ff1e24f46c3d2af4859f7e863672ba3a6e92e7cff702bf9f06c2" 1389 | "checksum unchecked-index 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eeba86d422ce181a719445e51872fa30f1f7413b62becb52e95ec91aa262d85c" 1390 | "checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" 1391 | "checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" 1392 | "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" 1393 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 1394 | "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" 1395 | "checksum unicode_categories 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" 1396 | "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" 1397 | "checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" 1398 | "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" 1399 | "checksum want 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 1400 | "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 1401 | "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" 1402 | "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 1403 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1404 | "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" 1405 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1406 | "checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" 1407 | "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" 1408 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "basic-http-server" 3 | version = "0.8.1" 4 | authors = ["Brian Anderson "] 5 | license = "MIT/Apache-2.0" 6 | description = "A simple static HTTP file server, for learning and local development" 7 | homepage = "https://github.com/brson/basic-http-server" 8 | repository = "https://github.com/brson/basic-http-server" 9 | readme = "README.md" 10 | edition = "2018" 11 | 12 | [dependencies] 13 | bytes = "0.4.12" 14 | clap = "2.33.0" 15 | comrak = "0.6.2" 16 | derive_more = "0.15.0" 17 | env_logger = "0.6.2" 18 | futures-preview = "0.3.0-alpha.19" 19 | handlebars = "1.1.0" 20 | http = "0.1.19" 21 | hyper = { version = "0.13.0-alpha.4", features = ["unstable-stream"] } 22 | log = "0.4.8" 23 | mime = "0.3.14" 24 | mime_guess = "2.0.1" 25 | percent-encoding = "2.1.0" 26 | serde = { version = "1.0.102", features = ["derive"] } 27 | tokio = "0.2.0-alpha.6" 28 | tokio-fs = "0.2.0-alpha.6" 29 | structopt = "0.2.18" 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `basic-http-server` 2 | 3 | A simple static HTTP server, for learning and local development. 4 | 5 | `basic-http-server` is designed for two purposes: 6 | 7 | - _as a teaching tool_. It is a simple and well-commented example of 8 | basic [`tokio`], [`hyper`], and asynchronous Rust programming, 9 | with `async` / `await`. 10 | 11 | - _for local development_. It serves static HTML content, and with the `-x` 12 | flag, provides convenience features useful for creating developer 13 | documentation, including markdown rendering and directory listing. 14 | 15 | The entire reference source for setting up a `hyper` HTTP server is contained in 16 | [`main.rs`]. The [`ext.rs`] file contains developer extensions. 17 | 18 | [`tokio`]: https://github.com/tokio-rs/tokio 19 | [`hyper`]: https://github.com/hyperium/hyper 20 | [`main.rs`]: src/main.rs 21 | [`ext.rs`]: src/ext.rs 22 | 23 | 24 | ## Developer extensions 25 | 26 | When passed the `-x` flag, `basic-http-server` enables additional conveniences 27 | useful for developing documentation locally. Those extensions are: 28 | 29 | - Rendering files with the ".md" extension as Markdown. 30 | 31 | - Listing directories when no "index.html" file is found. 32 | 33 | - Serving common source code files as "text/plain" so they are 34 | rendered in the browser. 35 | 36 | This makes `basic-http-server` useful for the following scenarios: 37 | 38 | - Previewing markdown content. Draft your `README.md` changes and view them 39 | locally before pushing to GitHub. 40 | 41 | - Navigating to local documentation, including Rust API documentation. Just run 42 | `basic-http-server -x` in your project directory, and use the directory 43 | listing to navigate to `target/doc`, then find the crates to read from there 44 | (`cargo doc` doesn't put an `index.html` file in `target/doc`). 45 | 46 | 47 | ## Installation and Use 48 | 49 | **Note that `basic-http-server` is not production-ready and should not be 50 | exposed to the internet. It is a learning and development tool.** 51 | 52 | Install with `cargo install`: 53 | 54 | ```sh 55 | $ cargo install basic-http-server 56 | $ basic-http-server 57 | ``` 58 | 59 | To turn on the developer extensions, pass `-x`: 60 | 61 | ```sh 62 | $ basic-http-server -x 63 | ``` 64 | 65 | To increase logging verbosity use `RUST_LOG`: 66 | 67 | ```sh 68 | RUST_LOG=basic_http_server=trace basic-http-server -x 69 | ``` 70 | 71 | Command line arguments: 72 | 73 | ``` 74 | USAGE: 75 | basic-http-server [FLAGS] [OPTIONS] [ARGS] 76 | 77 | FLAGS: 78 | -x Enable developer extensions 79 | -h, --help Prints help information 80 | -V, --version Prints version information 81 | 82 | OPTIONS: 83 | -a, --addr Sets the IP:PORT combination (default "127.0.0.1:4000") 84 | 85 | ARGS: 86 | ROOT Sets the root directory (default ".") 87 | 88 | ``` 89 | 90 | 91 | ## License 92 | 93 | MIT/Apache-2.0 94 | -------------------------------------------------------------------------------- /src/ext.rs: -------------------------------------------------------------------------------- 1 | //! Developer extensions for basic-http-server 2 | //! 3 | //! This code is not as clean and well-documented as main.rs, 4 | //! but could still be a useful read. 5 | 6 | use super::{Config, HtmlCfg}; 7 | use comrak::ComrakOptions; 8 | use futures::{future, StreamExt}; 9 | use http::{Request, Response, StatusCode}; 10 | use hyper::{header, Body}; 11 | use log::{trace, warn}; 12 | use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS}; 13 | use std::error::Error as StdError; 14 | use std::ffi::OsStr; 15 | use std::fmt::Write; 16 | use std::io; 17 | use std::path::{Path, PathBuf}; 18 | use tokio_fs::DirEntry; 19 | 20 | /// The entry point to extensions. Extensions are given both the request and the 21 | /// response result from regular file serving, and have the opportunity to 22 | /// replace the response with their own response. 23 | pub async fn serve( 24 | config: Config, 25 | req: Request, 26 | resp: super::Result>, 27 | ) -> super::Result> { 28 | trace!("checking extensions"); 29 | 30 | if !config.use_extensions { 31 | return resp; 32 | } 33 | 34 | let path = super::local_path_for_request(&req.uri(), &config.root_dir)?; 35 | let file_ext = path.extension().and_then(OsStr::to_str).unwrap_or(""); 36 | 37 | if file_ext == "md" { 38 | trace!("using markdown extension"); 39 | return Ok(md_path_to_html(&path).await?); 40 | } 41 | 42 | match resp { 43 | Ok(mut resp) => { 44 | // Serve source code as plain text to render them in the browser 45 | maybe_convert_mime_type_to_text(&req, &mut resp); 46 | Ok(resp) 47 | } 48 | Err(super::Error::Io(e)) => { 49 | // If the requested file was not found, then try doing a directory listing. 50 | if e.kind() == io::ErrorKind::NotFound { 51 | let list_dir_resp = maybe_list_dir(&config.root_dir, &path).await?; 52 | trace!("using directory list extension"); 53 | if let Some(f) = list_dir_resp { 54 | Ok(f) 55 | } else { 56 | Err(super::Error::from(e)) 57 | } 58 | } else { 59 | Err(super::Error::from(e)) 60 | } 61 | } 62 | r => r, 63 | } 64 | } 65 | 66 | /// Load a markdown file, render to HTML, and return the response. 67 | async fn md_path_to_html(path: &Path) -> Result> { 68 | // Render Markdown like GitHub 69 | let mut options = ComrakOptions::default(); 70 | options.ext_autolink = true; 71 | options.ext_header_ids = None; 72 | options.ext_table = true; 73 | options.ext_strikethrough = true; 74 | options.ext_tagfilter = true; 75 | options.ext_tasklist = true; 76 | options.github_pre_lang = true; 77 | options.ext_header_ids = Some("user-content-".to_string()); 78 | 79 | let buf = tokio::fs::read(path).await?; 80 | let s = String::from_utf8(buf).map_err(|_| Error::MarkdownUtf8)?; 81 | let html = comrak::markdown_to_html(&s, &options); 82 | let cfg = HtmlCfg { 83 | title: String::new(), 84 | body: html, 85 | }; 86 | let html = super::render_html(cfg)?; 87 | 88 | Response::builder() 89 | .status(StatusCode::OK) 90 | .header(header::CONTENT_LENGTH, html.len() as u64) 91 | .header(header::CONTENT_TYPE, mime::TEXT_HTML.as_ref()) 92 | .body(Body::from(html)) 93 | .map_err(Error::from) 94 | } 95 | 96 | fn maybe_convert_mime_type_to_text(req: &Request, resp: &mut Response) { 97 | let path = req.uri().path(); 98 | let file_name = path.rsplit('/').next(); 99 | if let Some(file_name) = file_name { 100 | let mut do_convert = false; 101 | 102 | let ext = file_name.rsplit('.').next(); 103 | if let Some(ext) = ext { 104 | if TEXT_EXTENSIONS.contains(&ext) { 105 | do_convert = true; 106 | } 107 | } 108 | 109 | if TEXT_FILES.contains(&file_name) { 110 | do_convert = true; 111 | } 112 | 113 | if do_convert { 114 | use http::header::HeaderValue; 115 | let val = 116 | HeaderValue::from_str(mime::TEXT_PLAIN.as_ref()).expect("mime is valid header"); 117 | resp.headers_mut().insert(header::CONTENT_TYPE, val); 118 | } 119 | } 120 | } 121 | 122 | #[rustfmt::skip] 123 | static TEXT_EXTENSIONS: &[&'static str] = &[ 124 | "c", 125 | "cc", 126 | "cpp", 127 | "csv", 128 | "fst", 129 | "h", 130 | "java", 131 | "md", 132 | "mk", 133 | "proto", 134 | "py", 135 | "rb", 136 | "rs", 137 | "rst", 138 | "sh", 139 | "toml", 140 | "yml", 141 | ]; 142 | 143 | #[rustfmt::skip] 144 | static TEXT_FILES: &[&'static str] = &[ 145 | ".gitattributes", 146 | ".gitignore", 147 | ".mailmap", 148 | "AUTHORS", 149 | "CODE_OF_CONDUCT", 150 | "CONTRIBUTING", 151 | "COPYING", 152 | "COPYRIGHT", 153 | "Cargo.lock", 154 | "LICENSE", 155 | "LICENSE-APACHE", 156 | "LICENSE-MIT", 157 | "Makefile", 158 | "rust-toolchain", 159 | ]; 160 | 161 | /// Try to treat the path as a directory and list the contents as HTML. 162 | async fn maybe_list_dir(root_dir: &Path, path: &Path) -> Result>> { 163 | let meta = tokio::fs::metadata(path).await?; 164 | if meta.is_dir() { 165 | Ok(Some(list_dir(&root_dir, path).await?)) 166 | } else { 167 | Ok(None) 168 | } 169 | } 170 | 171 | /// List the contents of a directory as HTML. 172 | async fn list_dir(root_dir: &Path, path: &Path) -> Result> { 173 | let up_dir = path.join(".."); 174 | let path = path.to_owned(); 175 | let dents = tokio::fs::read_dir(path).await?; 176 | let dents = dents.filter_map(|dent| match dent { 177 | Ok(dent) => future::ready(Some(dent)), 178 | Err(e) => { 179 | warn!("directory entry error: {}", e); 180 | future::ready(None) 181 | } 182 | }); 183 | let paths = dents.map(|dent| DirEntry::path(&dent)); 184 | let mut paths: Vec<_> = paths.collect().await; 185 | paths.sort(); 186 | let paths = Some(up_dir).into_iter().chain(paths); 187 | let paths: Vec<_> = paths.collect(); 188 | let html = make_dir_list_body(&root_dir, &paths)?; 189 | let resp = super::html_str_to_response(html, StatusCode::OK)?; 190 | Ok(resp) 191 | } 192 | 193 | fn make_dir_list_body(root_dir: &Path, paths: &[PathBuf]) -> Result { 194 | let mut buf = String::new(); 195 | 196 | writeln!(buf, "
").map_err(Error::WriteInDirList)?; 197 | 198 | let dot_dot = OsStr::new(".."); 199 | 200 | for path in paths { 201 | let full_url = path 202 | .strip_prefix(root_dir) 203 | .map_err(Error::StripPrefixInDirList)?; 204 | let maybe_dot_dot = || { 205 | if path.ends_with("..") { 206 | Some(dot_dot) 207 | } else { 208 | None 209 | } 210 | }; 211 | if let Some(file_name) = path.file_name().or_else(maybe_dot_dot) { 212 | if let Some(file_name) = file_name.to_str() { 213 | if let Some(full_url) = full_url.to_str() { 214 | // %-encode filenames 215 | // https://url.spec.whatwg.org/#fragment-percent-encode-set 216 | const FRAGMENT_SET: &AsciiSet = 217 | &CONTROLS.add(b' ').add(b'"').add(b'<').add(b'>').add(b'`'); 218 | const PATH_SET: &AsciiSet = 219 | &FRAGMENT_SET.add(b'#').add(b'?').add(b'{').add(b'}'); 220 | let full_url = utf8_percent_encode(full_url, &PATH_SET); 221 | 222 | // TODO: Make this a relative URL 223 | writeln!(buf, "", full_url, file_name) 224 | .map_err(Error::WriteInDirList)?; 225 | } else { 226 | warn!("non-unicode url: {}", full_url.to_string_lossy()); 227 | } 228 | } else { 229 | warn!("non-unicode path: {}", file_name.to_string_lossy()); 230 | } 231 | } else { 232 | warn!("path without file name: {}", path.display()); 233 | } 234 | } 235 | 236 | writeln!(buf, "
").map_err(Error::WriteInDirList)?; 237 | 238 | let cfg = HtmlCfg { 239 | title: String::new(), 240 | body: buf, 241 | }; 242 | 243 | Ok(super::render_html(cfg)?) 244 | } 245 | 246 | pub type Result = std::result::Result; 247 | 248 | #[derive(Debug, Display)] 249 | pub enum Error { 250 | // blanket "pass-through" error types 251 | #[display(fmt = "engine error")] 252 | Engine(Box), 253 | 254 | #[display(fmt = "HTTP error")] 255 | Http(http::Error), 256 | 257 | #[display(fmt = "I/O error")] 258 | Io(io::Error), 259 | 260 | // custom "semantic" error types 261 | #[display(fmt = "markdown is not UTF-8")] 262 | MarkdownUtf8, 263 | 264 | #[display(fmt = "failed to strip prefix in directory listing")] 265 | StripPrefixInDirList(std::path::StripPrefixError), 266 | 267 | #[display(fmt = "formatting error while creating directory listing")] 268 | WriteInDirList(std::fmt::Error), 269 | } 270 | 271 | impl StdError for Error { 272 | fn source(&self) -> Option<&(dyn StdError + 'static)> { 273 | use Error::*; 274 | 275 | match self { 276 | Engine(e) => Some(e), 277 | Io(e) => Some(e), 278 | Http(e) => Some(e), 279 | MarkdownUtf8 => None, 280 | StripPrefixInDirList(e) => Some(e), 281 | WriteInDirList(e) => Some(e), 282 | } 283 | } 284 | } 285 | 286 | impl From for Error { 287 | fn from(e: super::Error) -> Error { 288 | Error::Engine(Box::new(e)) 289 | } 290 | } 291 | 292 | impl From for Error { 293 | fn from(e: http::Error) -> Error { 294 | Error::Http(e) 295 | } 296 | } 297 | 298 | impl From for Error { 299 | fn from(e: io::Error) -> Error { 300 | Error::Io(e) 301 | } 302 | } 303 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | //! A simple HTTP server, for learning and local development. 2 | 3 | #[macro_use] 4 | extern crate derive_more; 5 | 6 | use bytes::BytesMut; 7 | use env_logger::{Builder, Env}; 8 | use futures::future; 9 | use futures::stream::StreamExt; 10 | use futures::FutureExt; 11 | use handlebars::Handlebars; 12 | use http::header::{HeaderMap, HeaderValue}; 13 | use http::status::StatusCode; 14 | use http::Uri; 15 | use hyper::service::{make_service_fn, service_fn}; 16 | use hyper::{header, Body, Method, Request, Response, Server}; 17 | use log::{debug, error, info, trace, warn}; 18 | use percent_encoding::percent_decode_str; 19 | use serde::Serialize; 20 | use std::error::Error as StdError; 21 | use std::io; 22 | use std::net::SocketAddr; 23 | use std::path::{Path, PathBuf}; 24 | use structopt::StructOpt; 25 | use tokio::codec::{BytesCodec, FramedRead}; 26 | use tokio::fs::File; 27 | use tokio::runtime::Runtime; 28 | 29 | // Developer extensions. These are contained in their own module so that the 30 | // principle HTTP server behavior is not obscured. 31 | mod ext; 32 | 33 | fn main() { 34 | // Set up error handling immediately 35 | if let Err(e) = run() { 36 | log_error_chain(&e); 37 | } 38 | } 39 | 40 | /// Basic error reporting, including the "cause chain". This is used both by the 41 | /// top-level error reporting and to report internal server errors. 42 | fn log_error_chain(mut e: &dyn StdError) { 43 | error!("error: {}", e); 44 | while let Some(source) = e.source() { 45 | error!("caused by: {}", source); 46 | e = source; 47 | } 48 | } 49 | 50 | /// The configuration object, parsed from command line options. 51 | #[derive(Clone, StructOpt)] 52 | #[structopt(about = "A basic HTTP file server")] 53 | pub struct Config { 54 | /// The IP:PORT combination. 55 | #[structopt( 56 | name = "ADDR", 57 | short = "a", 58 | long = "addr", 59 | parse(try_from_str), 60 | default_value = "127.0.0.1:4000" 61 | )] 62 | addr: SocketAddr, 63 | 64 | /// The root directory for serving files. 65 | #[structopt(name = "ROOT", parse(from_os_str), default_value = ".")] 66 | root_dir: PathBuf, 67 | 68 | /// Enable developer extensions. 69 | #[structopt(short = "x")] 70 | use_extensions: bool, 71 | } 72 | 73 | fn run() -> Result<()> { 74 | // Initialize logging, and log the "info" level for this crate only, unless 75 | // the environment contains `RUST_LOG`. 76 | let env = Env::new().default_filter_or("basic_http_server=info"); 77 | Builder::from_env(env) 78 | .default_format_module_path(false) 79 | .default_format_timestamp(false) 80 | .init(); 81 | 82 | // Create the configuration from the command line arguments. It 83 | // includes the IP address and port to listen on and the path to use 84 | // as the HTTP server's root directory. 85 | let config = Config::from_args(); 86 | 87 | // Display the configuration to be helpful 88 | info!("basic-http-server {}", env!("CARGO_PKG_VERSION")); 89 | info!("addr: http://{}", config.addr); 90 | info!("root dir: {}", config.root_dir.display()); 91 | info!("extensions: {}", config.use_extensions); 92 | 93 | // Create the MakeService object that creates a new Hyper service for every 94 | // connection. Both these closures need to return a Future of Result, and we 95 | // use two different mechanisms to achieve that. 96 | let make_service = make_service_fn(|_| { 97 | let config = config.clone(); 98 | 99 | let service = service_fn(move |req| { 100 | let config = config.clone(); 101 | 102 | // Handle the request, returning a Future of Response, 103 | // and map it to a Future of Result of Response. 104 | serve(config, req).map(Ok::<_, Error>) 105 | }); 106 | 107 | // Convert the concrete (non-future) service function to a Future of Result. 108 | future::ok::<_, Error>(service) 109 | }); 110 | 111 | // Create a Hyper Server, binding to an address, and use 112 | // our service builder. 113 | let server = Server::bind(&config.addr).serve(make_service); 114 | 115 | // Create a Tokio runtime and block on Hyper forever. 116 | let rt = Runtime::new()?; 117 | rt.block_on(server)?; 118 | 119 | Ok(()) 120 | } 121 | 122 | /// Create an HTTP Response future for each Request. 123 | /// 124 | /// Errors are turned into an appropriate HTTP error response, and never 125 | /// propagated upward for hyper to deal with. 126 | async fn serve(config: Config, req: Request) -> Response { 127 | // Serve the requested file. 128 | let resp = serve_or_error(config, req).await; 129 | 130 | // Transform internal errors to error responses. 131 | let resp = transform_error(resp); 132 | 133 | resp 134 | } 135 | 136 | /// Handle all types of requests, but don't deal with transforming internal 137 | /// errors to HTTP error responses. 138 | async fn serve_or_error(config: Config, req: Request) -> Result> { 139 | // This server only supports the GET method. Return an appropriate 140 | // response otherwise. 141 | if let Some(resp) = handle_unsupported_request(&req) { 142 | return resp; 143 | } 144 | 145 | // Serve the requested file. 146 | let resp = serve_file(&req, &config.root_dir).await; 147 | 148 | // Give developer extensions an opportunity to post-process the request/response pair. 149 | let resp = ext::serve(config, req, resp).await; 150 | 151 | resp 152 | } 153 | 154 | /// Serve static files from a root directory. 155 | async fn serve_file(req: &Request, root_dir: &PathBuf) -> Result> { 156 | // First, try to do a redirect. If that doesn't happen, then find the path 157 | // to the static file we want to serve - which may be `index.html` for 158 | // directories - and send a response containing that file. 159 | let maybe_redir_resp = try_dir_redirect(req, &root_dir)?; 160 | 161 | if let Some(redir_resp) = maybe_redir_resp { 162 | return Ok(redir_resp); 163 | } 164 | 165 | let path = local_path_with_maybe_index(req.uri(), &root_dir)?; 166 | 167 | Ok(respond_with_file(path).await?) 168 | } 169 | 170 | /// Try to do a 302 redirect for directories. 171 | /// 172 | /// If we get a URL without trailing "/" that can be mapped to a directory, then 173 | /// return a 302 redirect to the path with the trailing "/". 174 | /// 175 | /// Without this we couldn't correctly return the contents of `index.html` for a 176 | /// directory - for the purpose of building absolute URLs from relative URLs, 177 | /// agents appear to only treat paths with trailing "/" as directories, so we 178 | /// have to redirect to the proper directory URL first. 179 | /// 180 | /// In other words, if we returned the contents of `index.html` for URL `docs` 181 | /// then all the relative links in that file would be broken, but that is not 182 | /// the case for URL `docs/`. 183 | /// 184 | /// This seems to match the behavior of other static web servers. 185 | fn try_dir_redirect(req: &Request, root_dir: &PathBuf) -> Result>> { 186 | if req.uri().path().ends_with("/") { 187 | return Ok(None); 188 | } 189 | 190 | debug!("path does not end with /"); 191 | 192 | let path = local_path_for_request(req.uri(), root_dir)?; 193 | 194 | if !path.is_dir() { 195 | return Ok(None); 196 | } 197 | 198 | let mut new_loc = req.uri().path().to_string(); 199 | new_loc.push_str("/"); 200 | if let Some(query) = req.uri().query() { 201 | new_loc.push_str("?"); 202 | new_loc.push_str(query); 203 | } 204 | 205 | info!("redirecting {} to {}", req.uri(), new_loc); 206 | Response::builder() 207 | .status(StatusCode::FOUND) 208 | .header(header::LOCATION, new_loc) 209 | .body(Body::empty()) 210 | .map(Some) 211 | .map_err(Error::from) 212 | } 213 | 214 | /// Construct a 200 response with the file as the body, streaming it to avoid 215 | /// loading it fully into memory. 216 | /// 217 | /// If the I/O here fails then an error future will be returned, and `serve` 218 | /// will convert it into the appropriate HTTP error response. 219 | async fn respond_with_file(path: PathBuf) -> Result> { 220 | let mime_type = file_path_mime(&path); 221 | 222 | let file = File::open(path).await?; 223 | 224 | let meta = file.metadata().await?; 225 | let len = meta.len(); 226 | 227 | // Here's the streaming code. How to do this isn't documented in the 228 | // Tokio/Hyper API docs. Codecs are how Tokio creates Streams; a FramedRead 229 | // turns an AsyncRead plus a Decoder into a Stream; and BytesCodec is a 230 | // Decoder. FramedRead though creates a Stream> and Hyper's 231 | // Body wants a Stream>, and BytesMut::freeze will give us a 232 | // Bytes. 233 | 234 | let codec = BytesCodec::new(); 235 | let stream = FramedRead::new(file, codec); 236 | let stream = stream.map(|b| b.map(BytesMut::freeze)); 237 | let body = Body::wrap_stream(stream); 238 | 239 | let resp = Response::builder() 240 | .status(StatusCode::OK) 241 | .header(header::CONTENT_LENGTH, len as u64) 242 | .header(header::CONTENT_TYPE, mime_type.as_ref()) 243 | .body(body)?; 244 | 245 | Ok(resp) 246 | } 247 | 248 | /// Get a MIME type based on the file extension. 249 | /// 250 | /// If the extension is unknown then return "application/octet-stream". 251 | fn file_path_mime(file_path: &Path) -> mime::Mime { 252 | mime_guess::from_path(file_path).first_or_octet_stream() 253 | } 254 | 255 | /// Find the local path for a request URI, converting directories to the 256 | /// `index.html` file. 257 | fn local_path_with_maybe_index(uri: &Uri, root_dir: &Path) -> Result { 258 | local_path_for_request(uri, root_dir).map(|mut p: PathBuf| { 259 | if p.is_dir() { 260 | p.push("index.html"); 261 | debug!("trying {} for directory URL", p.display()); 262 | } else { 263 | trace!("trying path as from URL"); 264 | } 265 | p 266 | }) 267 | } 268 | 269 | /// Map the request's URI to a local path 270 | fn local_path_for_request(uri: &Uri, root_dir: &Path) -> Result { 271 | debug!("raw URI: {}", uri); 272 | 273 | let request_path = uri.path(); 274 | 275 | debug!("raw URI to path: {}", request_path); 276 | 277 | // Trim off the url parameters starting with '?' 278 | let end = request_path.find('?').unwrap_or(request_path.len()); 279 | let request_path = &request_path[0..end]; 280 | 281 | // Convert %-encoding to actual values 282 | let decoded = percent_decode_str(&request_path); 283 | let request_path = if let Ok(p) = decoded.decode_utf8() { 284 | p 285 | } else { 286 | error!("non utf-8 URL: {}", request_path); 287 | return Err(Error::UriNotUtf8); 288 | }; 289 | 290 | // Append the requested path to the root directory 291 | let mut path = root_dir.to_owned(); 292 | if request_path.starts_with('/') { 293 | path.push(&request_path[1..]); 294 | } else { 295 | warn!("found non-absolute path {}", request_path); 296 | return Err(Error::UriNotAbsolute); 297 | } 298 | 299 | debug!("URL · path : {} · {}", uri, path.display()); 300 | 301 | Ok(path) 302 | } 303 | 304 | /// Create an error response if the request contains unsupported methods, 305 | /// headers, etc. 306 | fn handle_unsupported_request(req: &Request) -> Option>> { 307 | get_unsupported_request_message(req) 308 | .map(|unsup| make_error_response_from_code_and_headers(unsup.code, unsup.headers)) 309 | } 310 | 311 | /// Description of an unsupported request. 312 | struct Unsupported { 313 | code: StatusCode, 314 | headers: HeaderMap, 315 | } 316 | 317 | /// Create messages for unsupported requests. 318 | fn get_unsupported_request_message(req: &Request) -> Option { 319 | use std::iter::FromIterator; 320 | 321 | // https://tools.ietf.org/html/rfc7231#section-6.5.5 322 | if req.method() != Method::GET { 323 | return Some(Unsupported { 324 | code: StatusCode::METHOD_NOT_ALLOWED, 325 | headers: HeaderMap::from_iter(vec![(header::ALLOW, HeaderValue::from_static("GET"))]), 326 | }); 327 | } 328 | 329 | None 330 | } 331 | 332 | /// Turn any errors into an HTTP error response. 333 | fn transform_error(resp: Result>) -> Response { 334 | match resp { 335 | Ok(r) => r, 336 | Err(e) => { 337 | let resp = make_error_response(e); 338 | match resp { 339 | Ok(r) => r, 340 | Err(e) => { 341 | // Last-ditch error reporting if even making the error response failed. 342 | error!("unexpected internal error: {}", e); 343 | Response::new(Body::from(format!("unexpected internal error: {}", e))) 344 | } 345 | } 346 | } 347 | } 348 | } 349 | 350 | /// Convert an error to an HTTP error response future, with correct response code. 351 | fn make_error_response(e: Error) -> Result> { 352 | let resp = match e { 353 | Error::Io(e) => make_io_error_response(e)?, 354 | Error::Ext(ext::Error::Io(e)) => make_io_error_response(e)?, 355 | e => make_internal_server_error_response(e)?, 356 | }; 357 | Ok(resp) 358 | } 359 | 360 | /// Convert an error into a 500 internal server error, and log it. 361 | fn make_internal_server_error_response(err: Error) -> Result> { 362 | log_error_chain(&err); 363 | let resp = make_error_response_from_code(StatusCode::INTERNAL_SERVER_ERROR)?; 364 | Ok(resp) 365 | } 366 | 367 | /// Handle the one special IO error (file not found) by returning a 404, otherwise 368 | /// return a 500. 369 | fn make_io_error_response(error: io::Error) -> Result> { 370 | let resp = match error.kind() { 371 | io::ErrorKind::NotFound => { 372 | debug!("{}", error); 373 | make_error_response_from_code(StatusCode::NOT_FOUND)? 374 | } 375 | _ => make_internal_server_error_response(Error::Io(error))?, 376 | }; 377 | Ok(resp) 378 | } 379 | 380 | /// Make an error response given an HTTP status code. 381 | fn make_error_response_from_code(status: StatusCode) -> Result> { 382 | make_error_response_from_code_and_headers(status, HeaderMap::new()) 383 | } 384 | 385 | /// Make an error response given an HTTP status code and response headers. 386 | fn make_error_response_from_code_and_headers( 387 | status: StatusCode, 388 | headers: HeaderMap, 389 | ) -> Result> { 390 | let body = render_error_html(status)?; 391 | let resp = html_str_to_response_with_headers(body, status, headers)?; 392 | Ok(resp) 393 | } 394 | 395 | /// Make an HTTP response from a HTML string. 396 | fn html_str_to_response(body: String, status: StatusCode) -> Result> { 397 | html_str_to_response_with_headers(body, status, HeaderMap::new()) 398 | } 399 | 400 | /// Make an HTTP response from a HTML string and response headers. 401 | fn html_str_to_response_with_headers( 402 | body: String, 403 | status: StatusCode, 404 | headers: HeaderMap, 405 | ) -> Result> { 406 | let mut builder = Response::builder(); 407 | 408 | builder.headers_mut().map(|h| h.extend(headers)); 409 | 410 | builder 411 | .status(status) 412 | .header(header::CONTENT_LENGTH, body.len()) 413 | .header(header::CONTENT_TYPE, mime::TEXT_HTML.as_ref()) 414 | .body(Body::from(body)) 415 | .map_err(Error::from) 416 | } 417 | 418 | /// A handlebars HTML template. 419 | static HTML_TEMPLATE: &str = include_str!("template.html"); 420 | 421 | /// The data for the handlebars HTML template. Handlebars will use serde to get 422 | /// the data out of the struct and mapped onto the template. 423 | #[derive(Serialize)] 424 | struct HtmlCfg { 425 | title: String, 426 | body: String, 427 | } 428 | 429 | /// Render an HTML page with handlebars, the template and the configuration data. 430 | fn render_html(cfg: HtmlCfg) -> Result { 431 | let reg = Handlebars::new(); 432 | let rendered = reg 433 | .render_template(HTML_TEMPLATE, &cfg) 434 | .map_err(Error::TemplateRender)?; 435 | Ok(rendered) 436 | } 437 | 438 | /// Render an HTML page from an HTTP status code 439 | fn render_error_html(status: StatusCode) -> Result { 440 | render_html(HtmlCfg { 441 | title: format!("{}", status), 442 | body: String::new(), 443 | }) 444 | } 445 | 446 | /// A custom `Result` typedef 447 | pub type Result = std::result::Result; 448 | 449 | /// The basic-http-server error type. 450 | /// 451 | /// This is divided into two types of errors: "semantic" errors and "blanket" 452 | /// errors. Semantic errors are custom to the local application semantics and 453 | /// are usually preferred, since they add context and meaning to the error 454 | /// chain. They don't require boilerplate `From` implementations, but do require 455 | /// `map_err` to create when they have interior `causes`. 456 | /// 457 | /// Blanket errors are just wrappers around other types, like `Io(io::Error)`. 458 | /// These are common errors that occur in many places so are easier to code and 459 | /// maintain, since e.g. every occurrence of an I/O error doesn't need to be 460 | /// given local semantics. 461 | /// 462 | /// The criteria of when to use which type of error variant, and their pros and 463 | /// cons, aren't obvious. 464 | /// 465 | /// These errors use `derive(Display)` from the `derive-more` crate to reduce 466 | /// boilerplate. 467 | #[derive(Debug, Display)] 468 | pub enum Error { 469 | // blanket "pass-through" error types 470 | #[display(fmt = "Extension error")] 471 | Ext(ext::Error), 472 | 473 | #[display(fmt = "HTTP error")] 474 | Http(http::Error), 475 | 476 | #[display(fmt = "Hyper error")] 477 | Hyper(hyper::Error), 478 | 479 | #[display(fmt = "I/O error")] 480 | Io(io::Error), 481 | 482 | // custom "semantic" error types 483 | #[display(fmt = "failed to parse IP address")] 484 | AddrParse(std::net::AddrParseError), 485 | 486 | #[display(fmt = "failed to render template")] 487 | TemplateRender(handlebars::TemplateRenderError), 488 | 489 | #[display(fmt = "requested URI is not an absolute path")] 490 | UriNotAbsolute, 491 | 492 | #[display(fmt = "requested URI is not UTF-8")] 493 | UriNotUtf8, 494 | } 495 | 496 | impl StdError for Error { 497 | fn source(&self) -> Option<&(dyn StdError + 'static)> { 498 | use Error::*; 499 | 500 | match self { 501 | Ext(e) => Some(e), 502 | Io(e) => Some(e), 503 | Http(e) => Some(e), 504 | Hyper(e) => Some(e), 505 | AddrParse(e) => Some(e), 506 | TemplateRender(e) => Some(e), 507 | UriNotAbsolute => None, 508 | UriNotUtf8 => None, 509 | } 510 | } 511 | } 512 | 513 | impl From for Error { 514 | fn from(e: ext::Error) -> Error { 515 | Error::Ext(e) 516 | } 517 | } 518 | 519 | impl From for Error { 520 | fn from(e: http::Error) -> Error { 521 | Error::Http(e) 522 | } 523 | } 524 | 525 | impl From for Error { 526 | fn from(e: hyper::Error) -> Error { 527 | Error::Hyper(e) 528 | } 529 | } 530 | 531 | impl From for Error { 532 | fn from(e: io::Error) -> Error { 533 | Error::Io(e) 534 | } 535 | } 536 | -------------------------------------------------------------------------------- /src/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{title}} 7 | 8 | 16 | 17 | 22 | 23 | 24 |
25 |

{{title}}

26 | 27 | {{{body}}} 28 | 29 |
30 | 31 | -------------------------------------------------------------------------------- /todo.md: -------------------------------------------------------------------------------- 1 | - add --public flag to automatically find the public ip address 2 | - add --https-only flag 3 | - add authentication 4 | - add flag to allow html in markdown 5 | - it seems github allows html? in some cases? investigate 6 | - fix h1/title to work with reader view 7 | - what happens if content-type ends up incorrect? 8 | - teach ext to do syntax highlighting 9 | - production-readiness 10 | - benchmark with ab / h2load 11 | - consider behavior under resource exhastion 12 | - what kind of resource limits need to be considered? 13 | - handling too many open file handles 14 | - handling too many connections 15 | - preventing oom 16 | - stress testing 17 | - add structopt-toml support 18 | - test conformance with h2spec / (what about http 1?) 19 | - handle more request / response headers 20 | - use more status codes 21 | - deal with accept request header 22 | - accept / content-type 23 | - content-type charsets 24 | - etag and header method? 25 | - make_error_response should find io errors to any recursive depth 26 | - make plain path links, [index.html], work 27 | - rst support 28 | - add a way to explicitly request an index listing 29 | - markdown 30 | - display README.md for dirs by default 31 | - strip -- comments from top of md files 32 | - with -x, check missing .html files for .md instead 33 | - make errors semantic 34 | - make errors carry URLs 35 | - async is_dir 36 | - add context to errors 37 | - prevent responding files outside of root_dir 38 | - catch and report panic 39 | - error on binding bound socket / port 40 | --------------------------------------------------------------------------------