From b3e8f4506b4423cb62b3f165d11cc99ccba6f703 Mon Sep 17 00:00:00 2001 From: Maxim Ivanitskiy Date: Tue, 4 Apr 2023 14:34:17 -0700 Subject: [PATCH] !misc: project refactor and new module structure New crates: - nginx-sys - is a separate crate for nginx bindings - ngx - crate allows to use a higher-level abstractions to build modules in rust - examples - a number of examples how to develop nginx dynamic modules with Rust ngx v0.3.0-beta now has more rust idiomatic code and allows to build modules completely in rust without any C code Co-authored-by: Matthew Yacobucci Elijah Zupancic --- .cargo/audit.toml | 35 + .cargo/config.toml | 8 + .dockerignore | 24 + .fossa.yml | 11 + .github/ISSUE_TEMPLATE/bug_report.md | 29 + .github/ISSUE_TEMPLATE/feature_request.md | 17 + .github/PULL_REQUEST_TEMPLATE.md | 15 + .github/dependabot.yml | 11 + .github/workflows/cargo-audit.yaml | 14 + .github/workflows/ci.yaml | 128 +++ .github/workflows/fossa.yaml | 18 + .gitignore | 260 ++++- CHANGELOG.md | 4 + CODE_OF_CONDUCT.md | 129 +++ CONTRIBUTING.md | 55 + Cargo.lock | 1132 +++++++++++++-------- Cargo.toml | 23 +- Containerfile.debian | 16 + Dockerfile | 47 + GNUmakefile | 92 ++ Makefile | 3 - README.md | 147 ++- SECURITY.md | 22 + WORKSPACE | 0 build/changelog.sh | 52 + build/container.mk | 28 + build/github.mk | 17 + build/release.mk | 48 + examples/Cargo.toml | 34 + examples/README.md | 101 ++ examples/awssig.conf | 50 + examples/awssig.rs | 345 +++++++ examples/awssig_curl_combined.conf | 53 + examples/curl.conf | 31 + examples/curl.rs | 147 +++ examples/httporigdst.conf | 16 + examples/httporigdst.rs | 308 ++++++ nginx-sys/Cargo.toml | 18 + nginx-sys/build.rs | 645 ++++++++++++ nginx-sys/src/lib.rs | 97 ++ nginx-sys/wrapper.h | 11 + nginx.mk | 70 -- ngx-binding/.gitignore | 1 - ngx-binding/Cargo.lock | 756 -------------- ngx-binding/Cargo.toml | 20 - ngx-binding/Makefile | 48 - ngx-binding/build.rs | 74 -- ngx-binding/src/.gitignore | 11 - ngx-binding/src/lib.rs | 8 - ngx-binding/src/log.rs | 37 - ngx-binding/src/nginx.rs | 98 -- ngx-binding/src/nginx_http.rs | 159 --- ngx-binding/wrapper.h | 1 - rustfmt.toml | 1 + src/core/buffer.rs | 93 ++ src/core/mod.rs | 66 ++ src/core/pool.rs | 101 ++ src/core/status.rs | 52 + src/core/string.rs | 101 ++ src/ffi/mod.rs | 1 + src/http/conf.rs | 33 + src/http/mod.rs | 9 + src/http/module.rs | 115 +++ src/http/request.rs | 646 ++++++++++++ src/http/status.rs | 200 ++++ src/lib.rs | 37 + src/log.rs | 29 + tests/log_test.rs | 114 ++- tools/README.md | 3 - tools/rust/Dockerfile | 50 - tools/rust/Makefile | 13 - tools/rust/README.md | 7 - 72 files changed, 5378 insertions(+), 1817 deletions(-) create mode 100644 .cargo/audit.toml create mode 100644 .cargo/config.toml create mode 100644 .dockerignore create mode 100644 .fossa.yml create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/cargo-audit.yaml create mode 100644 .github/workflows/ci.yaml create mode 100644 .github/workflows/fossa.yaml create mode 100644 CHANGELOG.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 Containerfile.debian create mode 100644 Dockerfile create mode 100644 GNUmakefile delete mode 100644 Makefile create mode 100644 SECURITY.md delete mode 100644 WORKSPACE create mode 100755 build/changelog.sh create mode 100644 build/container.mk create mode 100644 build/github.mk create mode 100644 build/release.mk create mode 100644 examples/Cargo.toml create mode 100644 examples/README.md create mode 100644 examples/awssig.conf create mode 100644 examples/awssig.rs create mode 100644 examples/awssig_curl_combined.conf create mode 100644 examples/curl.conf create mode 100644 examples/curl.rs create mode 100644 examples/httporigdst.conf create mode 100644 examples/httporigdst.rs create mode 100644 nginx-sys/Cargo.toml create mode 100644 nginx-sys/build.rs create mode 100644 nginx-sys/src/lib.rs create mode 100644 nginx-sys/wrapper.h delete mode 100644 nginx.mk delete mode 100644 ngx-binding/.gitignore delete mode 100644 ngx-binding/Cargo.lock delete mode 100644 ngx-binding/Cargo.toml delete mode 100644 ngx-binding/Makefile delete mode 100644 ngx-binding/build.rs delete mode 100644 ngx-binding/src/.gitignore delete mode 100644 ngx-binding/src/lib.rs delete mode 100644 ngx-binding/src/log.rs delete mode 100644 ngx-binding/src/nginx.rs delete mode 100644 ngx-binding/src/nginx_http.rs delete mode 100644 ngx-binding/wrapper.h create mode 100644 rustfmt.toml create mode 100644 src/core/buffer.rs create mode 100644 src/core/mod.rs create mode 100644 src/core/pool.rs create mode 100644 src/core/status.rs create mode 100644 src/core/string.rs create mode 100644 src/ffi/mod.rs create mode 100644 src/http/conf.rs create mode 100644 src/http/mod.rs create mode 100644 src/http/module.rs create mode 100644 src/http/request.rs create mode 100644 src/http/status.rs create mode 100644 src/lib.rs create mode 100644 src/log.rs delete mode 100644 tools/README.md delete mode 100644 tools/rust/Dockerfile delete mode 100644 tools/rust/Makefile delete mode 100644 tools/rust/README.md diff --git a/.cargo/audit.toml b/.cargo/audit.toml new file mode 100644 index 0000000..e796859 --- /dev/null +++ b/.cargo/audit.toml @@ -0,0 +1,35 @@ +# audit config file +# +# It may be located in the user home (`~/.cargo/audit.toml`) or in the project +# root (`.cargo/audit.toml`). +# +# All of the options which can be passed via CLI arguments can also be +# permanently specified in this file. +# It may be located in the user home (`~/.cargo/audit.toml`) or in the project +# root (`.cargo/audit.toml`). + +[advisories] +ignore = ["RUSTSEC-2020-0071"] + +# # Advisory Database Configuration +# [database] +# path = "~/.cargo/advisory-db" # Path where advisory git repo will be cloned +# url = "https://github.com/RustSec/advisory-db.git" # URL to git repo +# fetch = true # Perform a `git fetch` before auditing (default: true) +# stale = false # Allow stale advisory DB (i.e. no commits for 90 days, default: false) + +# # Output Configuration +# [output] +# deny = ["unmaintained"] # exit on error if unmaintained dependencies are found +# format = "terminal" # "terminal" (human readable report) or "json" +# quiet = false # Only print information on error +# show_tree = true # Show inverse dependency trees along with advisories (default: true) + +# # Target Configuration +# [target] +# arch = "x86_64" # Ignore advisories for CPU architectures other than this one +# os = "linux" # Ignore advisories for operating systems other than this one + +# [yanked] +# enabled = true # Warn for yanked crates in Cargo.lock (default: true) +# update_index = true # Auto-update the crates.io index (default: true) diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..8d1dff8 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,8 @@ +# +# https://stackoverflow.com/questions/28124221/error-linking-with-cc-failed-exit-code-1 +# +[target.x86_64-apple-darwin] +rustflags = [ + "-C", "link-arg=-undefined", + "-C", "link-arg=dynamic_lookup", +] diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d4fc4b5 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,24 @@ +**/.idea +.cargo +.dockerignore +.fossa.yml +.git +.github +CHANGELOG.md +CODE_OF_CONDUCT.md +CONTRIBUTING.md +Containerfile.debian +Dockerfile +GNUmakefile +LICENSE.txt +README.md +SECURITY.md +build + +.vscode/** + +**/target +target + +.cache/ +.nginx/ diff --git a/.fossa.yml b/.fossa.yml new file mode 100644 index 0000000..ef1059f --- /dev/null +++ b/.fossa.yml @@ -0,0 +1,11 @@ +version: 3 + +project: + id: github.com/nginxinc/ngx-rust + name: ngx-rust + url: github.com/nginxinc/ngx-rust + +paths: + exclude: + - ./cache + - ./nginx diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..a85753e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,29 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. See my project that depends on this project +2. View logs on '....' +3. Run this test I created +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Your environment** +* Version of the repo - a specific commit or tag +* Version of ngx-rust +* Version of Rust +* Version of NGINX (and all dependencies if modified) +* OS and distribution +* Details about containerization, virtualization, or physical environment + +**Additional context** +Add any other context about the problem here. Any log files you want to share. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..6bcce42 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..47781ac --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,15 @@ +### Proposed changes +Describe the use case and detail of the change. If this PR addresses an issue +on GitHub, make sure to include a link to that issue here in this description +(not in the title of the PR). + +### Checklist +Before creating a PR, run through this checklist and mark each as complete. + +- [ ] I have written my commit messages in the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) format. +- [ ] I have read the [CONTRIBUTING](/CONTRIBUTING.md) doc +- [ ] I have added tests (when possible) that prove my fix is effective or that my feature works +- [ ] I have checked that all unit tests pass after adding my changes +- [ ] I have updated necessary documentation +- [ ] I have rebased my branch onto master +- [ ] I will ensure my PR is targeting the main branch and pulling from my branch from my own fork diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..d5c3ffd --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "cargo" + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/workflows/cargo-audit.yaml b/.github/workflows/cargo-audit.yaml new file mode 100644 index 0000000..4974b63 --- /dev/null +++ b/.github/workflows/cargo-audit.yaml @@ -0,0 +1,14 @@ +name: Security audit +on: + push: + paths: + - '**/Cargo.toml' + - '**/Cargo.lock' +jobs: + security_audit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions-rs/audit-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..31fc6f4 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,128 @@ +name: Rust + +on: [ push, pull_request ] + +env: + CARGO_TERM_COLOR: always + +jobs: + test-linux: + name: Test (Linux) + runs-on: ubuntu-latest + steps: + - name: checkout source + uses: actions/checkout@v3 + - name: set up cargo cache + uses: actions/cache@v3 + continue-on-error: false + with: + path: | + .cache/cargo/registry/index/ + .cache/cargo/registry/cache/ + .cache/cargo/git/db/ + key: ${{ runner.os }}-cargo + restore-keys: ${{ runner.os }}-cargo + - name: set up nginx source binary cache + uses: actions/cache@v3 + continue-on-error: false + with: + path: | + .cache/.gnupg + .cache/*.tar.gz + .cache/*.tar.asc + .cache/*.tar.sig + key: nginx-${{ hashFiles('**/nginx-sys/build.rs') }} + restore-keys: nginx- + - name: run tests in container + run: make container-test + + test-macos: + name: Test (MacOS) + runs-on: macos-latest + steps: + - name: install GNU make 4 + run: brew install make openssl + - uses: actions/checkout@v3 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - name: set up cargo cache + uses: actions/cache@v3 + continue-on-error: false + with: + path: | + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + key: ${{ runner.os }}-cargo + restore-keys: ${{ runner.os }}-cargo + - name: set up nginx source binary cache + uses: actions/cache@v3 + continue-on-error: false + with: + path: | + .cache/.gnupg + .cache/*.tar.gz + .cache/*.tar.asc + .cache/*.tar.sig + key: nginx-${{ hashFiles('**/nginx-sys/build.rs') }} + restore-keys: nginx- + - name: run tests + uses: actions-rs/cargo@v1 + with: + command: test + args: --verbose + + fmt: + name: Rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - run: rustup component add rustfmt + - uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check + +# clippy: +# name: Clippy +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v3 +# - uses: actions-rs/toolchain@v1 +# with: +# profile: minimal +# toolchain: stable +# override: true +# - run: rustup component add clippy +# - uses: actions-rs/cargo@v1 +# with: +# command: clippy +# args: -- -D warnings + +# docs: +# name: Docs +# runs-on: ubuntu-latest +# steps: +# - name: Checkout repository +# uses: actions/checkout@v3 +# - name: Install Rust +# uses: actions-rs/toolchain@v1 +# with: +# toolchain: stable +# profile: minimal +# override: true +# - name: Check documentation +# env: +# RUSTDOCFLAGS: -D warnings +# uses: actions-rs/cargo@v1 +# with: +# command: doc +# args: --no-deps --document-private-items diff --git a/.github/workflows/fossa.yaml b/.github/workflows/fossa.yaml new file mode 100644 index 0000000..c242914 --- /dev/null +++ b/.github/workflows/fossa.yaml @@ -0,0 +1,18 @@ +name: License Scanning + +on: + - pull_request + - push + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Run FOSSA scan and upload build data + uses: fossa-contrib/fossa-action@v1 + with: + fossa-api-key: ${{ secrets.FOSSA_API_KEY }} diff --git a/.gitignore b/.gitignore index fe91bc8..0a75edb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,256 @@ -target -.idea -.vscode -nginx +# Created by https://www.toptal.com/developers/gitignore/api/c,rust,intellij+all,visualstudiocode,vim,emacs +# Edit at https://www.toptal.com/developers/gitignore?templates=c,rust,intellij+all,visualstudiocode,vim,emacs + +### C ### +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +### Emacs ### +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile + +# directory configuration +.dir-locals.el + +# network security +/network-security.data + + +### Intellij+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij+all Patch ### +# Ignore everything but code style settings and run configurations +# that are supposed to be shared within teams. + +.idea/* + +!.idea/codeStyles +!.idea/runConfigurations + +### Rust ### +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +# End of https://www.toptal.com/developers/gitignore/api/c,rust,intellij+all,visualstudiocode,vim,emacs + +.vscode/c_cpp_properties.json +.cache/ +.nginx/ +.DS_Store diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..ba81188 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,4 @@ +# Changelog + +All notable changes to this project will be documented in this file. + diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..4547fd8 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,129 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement as listed on the +github project page. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..5242d62 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,55 @@ +# Contributing Guidelines + +The following is a set of guidelines for contributing. We really appreciate that you are considering contributing! + +#### Table Of Contents + +[Ask a Question](#ask-a-question) + +[Contributing](#contributing) + +[Style Guides](#style-guides) + * [Git Style Guide](#git-style-guide) + * [Rust Style Guide](#rust-style-guide) + +[Code of Conduct](CODE_OF_CONDUCT.md) + +## Ask a Question + +Please ask your question on github using discussions. + +## Contributing + +### Report a Bug + +To report a bug, open an issue on GitHub with the label `bug` using the available bug report issue template. Please ensure the issue has not already been reported. + +### Suggest an Enhancement + +To suggest an enhancement, please create an issue on GitHub with the label `enhancement` using the available feature issue template. + +### Open a Pull Request + +* Fork the repo, create a branch, submit a PR when your changes are tested and ready for review. +* Fill in [our pull request template](/.github/PULL_REQUEST_TEMPLATE.md) + +Note: if you’d like to implement a new feature, please consider creating a feature request issue first to start a discussion about the feature. + +## Style Guides + +### Git Style Guide + +* Keep a clean, concise and meaningful git commit history on your branch, rebasing locally and squashing before submitting a PR +* Use the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) format when writing a commit message, so that changelogs can be automatically generated +* Follow the guidelines of writing a good commit message as described [here](https://chris.beams.io/posts/git-commit/) and summarised in the next few points + * In the subject line, use the present tense ("Add feature" not "Added feature") + * In the subject line, use the imperative mood ("Move cursor to..." not "Moves cursor to...") + * Limit the subject line to 72 characters or less + * Reference issues and pull requests liberally after the subject line + * Add more detailed description in the body of the git message (`git commit -a` to give you more space and time in your text editor to write a good message instead of `git commit -am`) + +### Rust Style Guide + +* Rust code should be checked in after `cargo fmt` has been run. +* The code style broadly complies with the [official Rust Style Guide](https://doc.rust-lang.org/style-guide/index.html). +* Where feasible, include unit tests. diff --git a/Cargo.lock b/Cargo.lock index 74c5f79..c751c5a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,748 +1,1078 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] -name = "aho-corasick" -version = "0.6.3" +name = "android_system_properties" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ - "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] -name = "ansi_term" -version = "0.9.0" +name = "autocfg" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] -name = "aster" -version = "0.41.0" +name = "aws-sign-v4" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93df874cdba37261e8d371d427d8ba77c753febe271b8f484349af6dceea0e48" dependencies = [ - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono", + "hex", + "http", + "ring", + "sha256", + "url", ] [[package]] -name = "atty" -version = "0.2.3" +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "bindgen" +version = "0.64.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 1.0.109", + "which", ] [[package]] -name = "base64" +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cexpr" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nom", ] [[package]] -name = "bindgen" -version = "0.30.0" +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" dependencies = [ - "aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cexpr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "clang-sys 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.27.1 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "which 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "iana-time-zone", + "js-sys", + "num-integer", + "num-traits", + "time", + "wasm-bindgen", + "winapi", ] [[package]] -name = "bitflags" -version = "0.7.0" +name = "clang-sys" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +dependencies = [ + "glob", + "libc", + "libloading", +] [[package]] -name = "bitflags" -version = "0.8.2" +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] -name = "bitflags" -version = "0.9.1" +name = "cpufeatures" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" +dependencies = [ + "libc", +] [[package]] -name = "byteorder" -version = "1.1.0" +name = "crc32fast" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] [[package]] -name = "bytes" -version = "0.4.5" +name = "cxx" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" dependencies = [ - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", ] [[package]] -name = "cexpr" -version = "0.2.2" +name = "cxx-build" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" dependencies = [ - "nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn 2.0.13", ] [[package]] -name = "cfg-if" -version = "0.1.2" +name = "cxxbridge-flags" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" [[package]] -name = "clang-sys" -version = "0.19.0" +name = "cxxbridge-macro" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ - "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "libloading 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn 2.0.13", ] [[package]] -name = "clap" -version = "2.27.1" +name = "digest" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array", ] [[package]] -name = "env_logger" -version = "0.4.3" +name = "duct" +version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ae3fc31835f74c2a7ceda3aeede378b0ae2e74c8f1c36559fcc9ae2a4e7d3e" dependencies = [ - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "once_cell", + "os_pipe", + "shared_child", ] [[package]] -name = "fuchsia-zircon" -version = "0.2.1" +name = "either" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "examples" +version = "0.0.0" dependencies = [ - "fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "aws-sign-v4", + "chrono", + "http", + "libc", + "ngx", ] [[package]] -name = "fuchsia-zircon-sys" -version = "0.2.0" +name = "filetime" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys", +] + +[[package]] +name = "flate2" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crc32fast", + "miniz_oxide", ] [[package]] -name = "futures" -version = "0.1.17" +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] [[package]] -name = "futures-cpupool" -version = "0.1.7" +name = "generic-array" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ - "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "typenum", + "version_check", ] [[package]] name = "glob" -version = "0.2.11" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] -name = "httparse" -version = "1.2.3" +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "http" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] [[package]] -name = "hyper" -version = "0.11.7" +name = "iana-time-zone" +version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" dependencies = [ - "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-cpupool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "relay 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows", ] [[package]] -name = "iovec" +name = "iana-time-zone-haiku" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" dependencies = [ - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cxx", + "cxx-build", ] [[package]] -name = "kernel32-sys" -version = "0.2.2" +name = "idna" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi", + "unicode-normalization", ] [[package]] -name = "language-tags" -version = "0.2.2" +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "js-sys" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +dependencies = [ + "wasm-bindgen", +] [[package]] name = "lazy_static" -version = "0.2.11" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lazycell" -version = "0.5.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.33" +version = "0.2.141" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" [[package]] name = "libloading" -version = "0.4.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "winapi", ] [[package]] -name = "log" -version = "0.3.8" +name = "link-cplusplus" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +dependencies = [ + "cc", +] [[package]] -name = "memchr" -version = "1.0.2" +name = "log" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", ] [[package]] -name = "mime" -version = "0.3.5" +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" dependencies = [ - "unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "adler", ] [[package]] -name = "mio" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "nginx-sys" +version = "0.1.0" dependencies = [ - "fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazycell 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "bindgen", + "duct", + "flate2", + "tar", + "ureq", + "which", ] [[package]] -name = "miow" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "ngx" +version = "0.3.0-beta" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bindgen", + "duct", + "flate2", + "nginx-sys", + "tar", + "ureq", + "which", ] [[package]] -name = "net2" -version = "0.2.31" +name = "nom" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr", + "minimal-lexical", ] [[package]] -name = "ngx_rust" -version = "0.1.2" +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ - "bindgen 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "num-traits", ] [[package]] -name = "nom" -version = "3.2.1" +name = "num-traits" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ - "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", ] [[package]] -name = "num_cpus" -version = "1.7.0" +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "os_pipe" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a53dbb20faf34b16087a931834cba2d7a73cc74af2b7ef345a4c8324e2409a12" dependencies = [ - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "windows-sys", ] [[package]] name = "peeking_take_while" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "percent-encoding" -version = "1.0.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] -name = "quasi" -version = "0.32.0" +name = "proc-macro2" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ - "syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-ident", ] [[package]] -name = "quasi_codegen" -version = "0.32.0" +name = "quote" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ - "aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", ] [[package]] -name = "rand" -version = "0.3.18" +name = "redox_syscall" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", ] [[package]] -name = "redox_syscall" -version = "0.1.31" +name = "regex" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +dependencies = [ + "regex-syntax", +] [[package]] -name = "redox_termios" -version = "0.1.1" +name = "regex-syntax" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" dependencies = [ - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", ] [[package]] -name = "regex" -version = "0.2.2" +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustls" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" dependencies = [ - "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log", + "ring", + "sct", + "webpki", ] [[package]] -name = "regex-syntax" -version = "0.4.1" +name = "scratch" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" [[package]] -name = "relay" -version = "0.1.0" +name = "sct" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ - "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "ring", + "untrusted", ] [[package]] -name = "rustc-serialize" -version = "0.3.24" +name = "sha2" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer", + "cfg-if", + "cpufeatures", + "digest", + "opaque-debug", +] [[package]] -name = "safemem" -version = "0.2.0" +name = "sha256" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "328169f167261957e83d82be47f9e36629e257c62308129033d7f7e7c173d180" +dependencies = [ + "hex", + "sha2", +] [[package]] -name = "scoped-tls" -version = "0.1.0" +name = "shared_child" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0d94659ad3c2137fef23ae75b03d5241d633f8acded53d672decfa0e6e0caef" +dependencies = [ + "libc", + "winapi", +] [[package]] -name = "slab" -version = "0.3.0" +name = "shlex" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" [[package]] -name = "slab" -version = "0.4.0" +name = "spin" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] -name = "smallvec" -version = "0.2.1" +name = "syn" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] [[package]] -name = "strsim" -version = "0.6.0" +name = "syn" +version = "2.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] [[package]] -name = "syntex" -version = "0.58.1" +name = "tar" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" dependencies = [ - "syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime", + "libc", + "xattr", ] [[package]] -name = "syntex_errors" -version = "0.58.1" +name = "termcolor" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util", ] [[package]] -name = "syntex_pos" -version = "0.58.1" +name = "time" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" dependencies = [ - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "wasi", + "winapi", ] [[package]] -name = "syntex_syntax" -version = "0.58.1" +name = "tinyvec" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ - "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tinyvec_macros", ] [[package]] -name = "take" -version = "0.1.0" +name = "tinyvec_macros" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] -name = "term" -version = "0.4.6" +name = "typenum" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tinyvec", ] [[package]] -name = "termion" -version = "1.5.1" +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "ureq" +version = "2.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "338b31dd1314f68f3aabf3ed57ab922df95ffcd902476ca7ba3c4ce7b908c46d" dependencies = [ - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "base64", + "flate2", + "log", + "once_cell", + "rustls", + "url", + "webpki", + "webpki-roots", ] [[package]] -name = "textwrap" -version = "0.9.0" +name = "url" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" dependencies = [ - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "form_urlencoded", + "idna", + "percent-encoding", ] [[package]] -name = "thread_local" -version = "0.3.4" +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasm-bindgen" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "wasm-bindgen-macro", ] [[package]] -name = "time" -version = "0.1.38" +name = "wasm-bindgen-backend" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 1.0.109", + "wasm-bindgen-shared", ] [[package]] -name = "tokio-core" -version = "0.1.10" +name = "wasm-bindgen-macro" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ - "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "quote", + "wasm-bindgen-macro-support", ] [[package]] -name = "tokio-io" -version = "0.1.4" +name = "wasm-bindgen-macro-support" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ - "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn 1.0.109", + "wasm-bindgen-backend", + "wasm-bindgen-shared", ] [[package]] -name = "tokio-proto" -version = "0.1.1" +name = "wasm-bindgen-shared" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" + +[[package]] +name = "web-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" dependencies = [ - "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys", + "wasm-bindgen", ] [[package]] -name = "tokio-service" -version = "0.1.0" +name = "webpki" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" dependencies = [ - "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "ring", + "untrusted", ] [[package]] -name = "unicase" -version = "2.1.0" +name = "webpki-roots" +version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" dependencies = [ - "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki", ] [[package]] -name = "unicode-width" -version = "0.1.4" +name = "which" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +dependencies = [ + "either", + "libc", + "once_cell", +] [[package]] -name = "unicode-xid" -version = "0.0.4" +name = "winapi" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] [[package]] -name = "unreachable" -version = "1.0.0" +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi", ] [[package]] -name = "utf8-ranges" -version = "1.0.0" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "vec_map" -version = "0.8.0" +name = "windows" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.0", +] [[package]] -name = "version_check" -version = "0.1.3" +name = "windows-sys" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] [[package]] -name = "void" -version = "1.0.2" +name = "windows-targets" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] [[package]] -name = "which" -version = "1.0.3" +name = "windows-targets" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" dependencies = [ - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", ] [[package]] -name = "winapi" -version = "0.2.8" +name = "windows_aarch64_gnullvm" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] -name = "winapi-build" -version = "0.1.1" +name = "windows_aarch64_gnullvm" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] -name = "ws2_32-sys" -version = "0.2.1" +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "xattr" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[metadata] -"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" -"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" -"checksum aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfdf7355d9db158df68f976ed030ab0f6578af811f5a7bb6dcf221ec24e0e0" -"checksum atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21e50800ec991574876040fff8ee46b136a53e985286fbe6a3bdfe6421b78860" -"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" -"checksum bindgen 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "33024f55a754d920637461adf87fb485702a69bdf7ac1d307b7e18da93bae505" -"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4" -"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" -"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" -"checksum bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d828f97b58cc5de3e40c421d0cf2132d6b2da4ee0e11b8632fa838f0f9333ad6" -"checksum cexpr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cdbb21df6ff3497a61df5059994297f746267020ba38ce237aad9c875f7b4313" -"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" -"checksum clang-sys 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "611ec2e3a7623afd8a8c0d027887b6b55759d894abbf5fe11b9dc11b50d5b49a" -"checksum clap 2.27.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1b8c532887f1a292d17de05ae858a8fe50a301e196f9ef0ddb7ccd0d1d00f180" -"checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" -"checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159" -"checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82" -"checksum futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "118b49cac82e04121117cbd3121ede3147e885627d82c4546b87c702debb90c1" -"checksum futures-cpupool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e86f49cc0d92fe1b97a5980ec32d56208272cbb00f15044ea9e2799dde766fdf" -"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" -"checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07" -"checksum hyper 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)" = "4959ca95f55df4265bff2ad63066147255e6fa733682cf6d1cb5eaff6e53324b" -"checksum iovec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b6e8b9c2247fcf6c6a1151f1156932be5606c9fd6f55a2d7f9fc1cb29386b2f7" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" -"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum lazycell 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b585b7a6811fb03aa10e74b278a0f00f8dd9b45dc681f148bb29fa5cb61859b" -"checksum libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "5ba3df4dcb460b9dfbd070d41c94c19209620c191b0340b929ce748a2bcd42d2" -"checksum libloading 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3f92926a9a4ba7aeeb01f5fba3f0d577147243b6e7fa8261c219cd1d6fbe3b1c" -"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" -"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" -"checksum mime 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e2e00e17be181010a91dbfefb01660b17311059dc8c7f48b9017677721e732bd" -"checksum mio 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0e8411968194c7b139e9105bc4ae7db0bae232af087147e72f0616ebf5fdb9cb" -"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09" -"checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b" -"checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d" -"checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" -"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" -"checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3" -"checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4" -"checksum rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6475140dfd8655aeb72e1fd4b7a1cc1c202be65d71669476e392fe62532b9edd" -"checksum redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509" -"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" -"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" -"checksum relay 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f301bafeb60867c85170031bdb2fcf24c8041f33aee09e7b116a58d4e9f781c5" -"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" -"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" -"checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" -"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" -"checksum slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdeff4cd9ecff59ec7e3744cbca73dfe5ac35c2aedb2cfba8a1c715a18912e9d" -"checksum smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8cbcd6df1e117c2210e13ab5109635ad68a929fcbb8964dc965b76cb5ee013" -"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" -"checksum syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a8f5e3aaa79319573d19938ea38d068056b826db9883a5d47f86c1cecc688f0e" -"checksum syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "867cc5c2d7140ae7eaad2ae9e8bf39cb18a67ca651b7834f88d46ca98faadb9c" -"checksum syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13ad4762fe52abc9f4008e85c4fb1b1fe3aa91ccb99ff4826a439c7c598e1047" -"checksum syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6e0e4dbae163dd98989464c23dd503161b338790640e11537686f2ef0f25c791" -"checksum take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5" -"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" -"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" -"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" -"checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" -"checksum tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "c843a027f7c1df5f81e7734a0df3f67bf329411781ebf36393ce67beef6071e3" -"checksum tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "514aae203178929dbf03318ad7c683126672d4d96eccb77b29603d33c9e25743" -"checksum tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fbb47ae81353c63c487030659494b295f6cb6576242f907f203473b191b0389" -"checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" -"checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a" -"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" -"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" -"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" -"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" -"checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum which 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4be6cfa54dab45266e98b5d7be2f8ce959ddd49abd141a05d52dce4b07f803bb" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" + "libc", +] diff --git a/Cargo.toml b/Cargo.toml index 1124e3a..1ee7bb6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,25 @@ [workspace] members = [ - "ngx-binding" + "nginx-sys", + "examples", ] + +[package] +name = "ngx" +version = "0.3.0-beta" +edition = "2021" +autoexamples = false +license = "Apache-2.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +nginx-sys = { path = "nginx-sys"} + +[build-dependencies] +bindgen = "0.64.0" +which = "4.4.0" +duct = "0.13.6" +ureq = { version = "2.6.2", features = ["tls"] } +flate2 = "1.0.25" +tar = "0.4.38" diff --git a/Containerfile.debian b/Containerfile.debian new file mode 100644 index 0000000..7d8bca4 --- /dev/null +++ b/Containerfile.debian @@ -0,0 +1,16 @@ +FROM rust:slim-bullseye + +RUN set -eux \ + export DEBIAN_FRONTEND=noninteractive; \ + apt-get -qq update; \ + apt-get -qq install --yes --no-install-recommends --no-install-suggests \ + libclang-dev \ + libssl-dev \ + pkg-config \ + git \ + grep \ + gawk \ + gnupg2 \ + sed \ + make; \ + git config --global --add safe.directory /project \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..dad9bfe --- /dev/null +++ b/Dockerfile @@ -0,0 +1,47 @@ +ARG NGX_VERSION=1.23.3 +ARG NGX_DEBUG=false + +# --- builder: build all examples +FROM rust:slim-bullseye as build +ARG NGX_VERSION +ARG NGX_DEBUG +WORKDIR /project +RUN --mount=type=cache,target=/var/cache/apt < /dev/null || command -v grep 2> /dev/null) +SED ?= $(shell command -v gsed 2> /dev/null || command -v sed 2> /dev/null) +AWK ?= $(shell command -v gawk 2> /dev/null || command -v awk 2> /dev/null) +VERSION ?= $(shell $(GREP) -Po '^version\s+=\s+"\K.*?(?=")' $(CURDIR)/Cargo.toml) +CARGO ?= cargo +DOCKER ?= docker +DOCKER_BUILD_FLAGS ?= --load +COMMITSAR_DOCKER := $(DOCKER) run --tty --rm --workdir /src -v "$(CURDIR):/src" aevea/commitsar +COMMITSAR ?= $(shell command -v commitsar 2> /dev/null) +PROJECT_NAME ?= ngx-rust +GITHUB_REPOSITORY ?= nginxinc/$(PROJECT_NAME) +SRC_REPO := https://github.com/$(GITHUB_REPOSITORY) + +RELEASE_BUILD_FLAGS ?= --quiet --release + +Q = $(if $(filter 1,$V),,@) +M = $(shell printf "\033[34;1m▶\033[0m") + +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + FEATURES += --features=linux +endif + +# Use docker based commitsar if it isn't in the path +ifeq ($(COMMITSAR),) + COMMITSAR = $(COMMITSAR_DOCKER) +endif + +.PHONY: help +help: + @$(GREP) --no-filename -E '^[ a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \ + $(AWK) 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-28s\033[0m %s\n", $$1, $$2}' | sort + +.PHONY: clean +clean: clean-cache; $(info $(M) cleaning...) @ ## Cleanup everything + $Q rm -rf $(CURDIR)/target + $Q $(CARGO) clean + +.PHONY: clean-cache +clean-cache: ## Remove all cached dependencies and build artifacts + $(Q) rm -rf $(CACHE_DIR) + +.PHONY: commitsar +commitsar: ## Run git commit linter + $Q $(info $(M) running commitsar...) + $(COMMITSAR) + +target: + $Q mkdir -p $@ + +.PHONY: debug +debug: target/debug ## Build current platform target in debug mode + +target/debug: + $Q echo "$(M) building in debug mode for the current platform" + $Q $(CARGO) build --quiet + +.PHONY: release +release: target/release ## Build current platform target in release mode + +target/release: + $Q echo "$(M) building in release mode for the current platform" + $Q $(CARGO) build $(RELEASE_BUILD_FLAGS) + +.PHONY: test +test: ## Run tests + $Q $(CARGO) test + +.PHONY: format +format: ## Run rustfmt + $Q $(CARGO) fmt + +.PHONY: lint +lint: ## Run clippy + $Q $(CARGO) clippy + +.PHONY: examples-debug +examples-debug: + $Q echo "$(M) building all examples as debug" + $Q $(CARGO) build --quiet --package=examples --examples $(FEATURES) + +include $(CURDIR)/build/container.mk +include $(CURDIR)/build/release.mk +include $(CURDIR)/build/github.mk diff --git a/Makefile b/Makefile deleted file mode 100644 index 47f489a..0000000 --- a/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -clean: - cargo clean - make -C ngx-binding clean diff --git a/README.md b/README.md index 58e8628..4c6c6f8 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,147 @@ -# Rust for NGINX +[![Rust](https://github.com/nginxinc/ngx-rust/actions/workflows/ci.yaml/badge.svg)](https://github.com/nginxinc/ngx-rust/actions/workflows/ci.yaml) -Rust bindings and wrappers for NGINX. Can be used for building dynamic modules and hacking NGINX using rust. +## Project status +This project is still a work in progress and not production ready. -## Production Status +# Description -This version is proof of concept. It has enough binding for building modules for [nginmesh](https://github.com/nginxinc/nginmesh). +This project provides Rust SDK interfaces to the [NGINX](https://nginx.com) proxy allowing the creation of NGINX +dynamic modules completely in Rust. -You still need to write C stub code to build the complete module. Please wait for next version which will remove this restriction. +In short, this SDK allows writing NGINX modules using the Rust language. -## Getting Started +## Build -Add the following dependency to your Cargo manifest... +NGINX modules can be build against a particular version of NGINX. The following environment variables can be used to +specify particular version of NGINX or an NGINX dependency: -```toml -[dependencies] -ngx_rust = "0.1.1" +* `ZLIB_VERSION` (default 1.2.13) - +* `PCRE2_VERSION` (default 10.42) +* `OPENSSL_VERSION` (default 3.0.7) +* `NGX_VERSION` (default 1.23.3) - NGINX OSS version +* `NGX_DEBUG` (default to false)- if set to true, then will compile NGINX `--with-debug` option + +For example, this is how you would compile the [examples](examples) using a specific version of NGINX and enabling +debugging: +``` +NGX_DEBUG=true NGX_VERSION=1.23.0 cargo build --package=examples --examples --release +``` + +To build Linux-only modules, use the "linux" feature: +``` +cargo build --package=examples --examples --features=linux --release ``` -Next, add this to your crate: +After compilation, the modules can be found in the path `target/release/examples/` ( with the `.so` file extension for +Linux or `.dylib` for MacOS). + +Additionally, the folder `.cache/nginx/{NGX_VERSION}/{OS}/` will contain the compiled version of NGINX used to build +the SDK. You can start NGINX directly from this directory if you want to test the module. + +### Mac OS dependencies + +In order to use the optional GNU make build process on MacOS, you will need to install additional tools. This can be +done via [homebrew](https://brew.sh/) with the following command: +``` +brew install make openssl grep +``` + +Additionally, you may need to set up LLVM and clang. Typically, this is done as follows: + +``` +# make sure xcode tools are installed +xcode-select --install +# instal llvm +brew install --with-toolchain llvm +``` + +### Linux dependencies + +See the [Dockerfile](Dockerfile) for dependencies as an example of required packages on Debian Linux. + +### Build example + +Example modules are available in [examples](examples) folder. You can use `cargo build --package=examples --examples` to build these examples. After building, you can find the `.so` or `.dylib` in the `target/debug` folder. Add `--features=linux` to build linux specific modules. **NOTE**: adding the "linux" feature on MacOS will cause a build failure. + +For example (all examples plus linux specific): +`cargo build --packages=examples --examples --features=linux` + +### Docker + +We provide a multistage [Dockerfile](Dockerfile): + + # build all dynamic modules examples and specify NGINX version to use + docker buildx build --build-arg NGX_VERSION=1.23.3 -t ngx-rust . + + # start NGINX using [curl](examples/curl.conf) module example: + docker run --rm -d -p 8000:8000 ngx-rust nginx -c examples/curl.conf + + # test it - you should see 403 Forbidden + curl http://127.0.0.1:8000 -v -H "user-agent: curl" + + + # test it - you should see 404 Not Found + curl http://127.0.0.1:8000 -v -H "user-agent: foo" + +## Usage + +A complete module example using the SDK can be found [here](examples/curl.rs). You can build it with +`cargo build --package=examples --example=curl` then set up NGINX to use it: + +For example: +```nginx +daemon off; +master_process off; + +# unix: +# load_module modules/libcurl.so; + +# error_log logs/error.log debug; +error_log /dev/stdout debug; + +working_directory /tmp/cores/; +worker_rlimit_core 500M; + +events { +} + +http { + access_log /dev/stdout; + server { + listen 8000; + server_name localhost; + location / { + alias /srv/http; + # ... Other config stuff ... -```rust -extern crate ngx_rust; + curl on; + } + } +} ``` -## Building module Example +## Support +This SDK is currently unstable. Right now, our primary goal is collect feedback and stabilize it be before +offering support. Feel free [contributing](CONTRIBUTING.md) by creating issues, PRs, or github discussions. -Please see [istio mixer module](https://github.com/nginxinc/ngx-istio-mixer) for full example. -Currently, it requires much machinery to build the module. +Currently, the only supported platforms are: +* Darwin (Mac OSX) +* Linux platform ## Roadmap +If you have ideas for releases in the future, please suggest them in the github discussions. -Please see [roadmap](https://github.com/nginxinc/ngx-rust/wiki) for future plans. +## Contributing +We welcome pull requests and issues! +Please refer to the [Contributing Guidelines](CONTRIBUTING.md) when doing a PR. -## Limitation +## Authors and acknowledgment +This project uses some great work from [dcoles/nginx-rs](https://github.com/dcoles/nginx-rs), +[arvancloud/nginx-rs](https://github.com/arvancloud/nginx-rs). -Only supports these platforms: -- Darwin (Mac OSX) -- Linux platform +## License +All code in this repository is licensed under the +[Apache License v2 license](LICENSE.txt). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..dd2be6b --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,22 @@ +# Security Policy + +## General Guidance + +We advise users to run the most recent release of the NGINX Rust Module SDK, and we issue software updates to the +most recent release. + +## Support + +The NGINX Rust Module SDK is not officially supported. + +## Reporting a Vulnerability + +The F5 Security Incident Response Team (F5 SIRT) has an email alias that makes it easy to report potential security +vulnerabilities. + +- If you’re an F5 customer with an active support contract, please contact + [F5 Technical Support](https://www.f5.com/services/support). +- If you aren’t an F5 customer, please report any potential or current instances of security vulnerabilities with any + F5 product to the F5 Security Incident Response Team at F5SIRT@f5.com + +For more information visit https://www.f5.com/services/support/report-a-vulnerability diff --git a/WORKSPACE b/WORKSPACE deleted file mode 100644 index e69de29..0000000 diff --git a/build/changelog.sh b/build/changelog.sh new file mode 100755 index 0000000..7b81650 --- /dev/null +++ b/build/changelog.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +# This script generates a changelog for the current version of the project. + +set -o errexit # abort on nonzero exit status +set -o nounset # abort on unbound variable +set -o pipefail # don't hide errors within pipes + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" +EXCLUDED_COMMIT_TYPES="ci|chore" + +pushd . > /dev/null +cd "${SCRIPT_DIR}/.." + +if command -v ggrep > /dev/null; then + GREP=ggrep +else + GREP=grep +fi +if command -v gsed > /dev/null; then + SED=gsed +else + SED=sed +fi + +# if gh is installed, use it to pull the last version number +if command -v gh > /dev/null; then + LAST_RELEASE="$(gh release list --exclude-drafts --exclude-pre-releases --limit 1 | ${GREP} -E 'v[0-9]+\.[0-9]+\.[0-9]+' | cut -f1 | ${GREP} -v "${VERSION}" || true)" +else + LAST_RELEASE="$(git tag --list v* | ${GREP} -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort --version-sort --field-separator=. --reverse | ${GREP} -v "${VERSION}" | head -n1 || true)" +fi + +if [ -z "${LAST_RELEASE}" ]; then + echo "## Initial release ${VERSION}" + git log --format="%s (%h)" | \ + ${GREP} -E -v "^(${EXCLUDED_COMMIT_TYPES}): .*" | \ + ${SED} 's/: /:\t/g1' | \ + column -s " " -t | \ + ${SED} -e 's/^/ * /' +else + LAST_RELEASE_HASH="$(git show --format=%H "${LAST_RELEASE}" | head -n1 | ${SED} -e 's/^tag //')" + + echo "## Changes between ${LAST_RELEASE} [$LAST_RELEASE_HASH] and ${VERSION}:" + git log --format="%s (%h)" "${LAST_RELEASE_HASH}..HEAD" | \ + ${GREP} -E -v "^(${EXCLUDED_COMMIT_TYPES}): .*" | \ + ${SED} 's/: /:\t/g1' | \ + column -s " " -t | \ + ${SED} -e 's/^/ * /' +fi + +echo "" +popd > /dev/null \ No newline at end of file diff --git a/build/container.mk b/build/container.mk new file mode 100644 index 0000000..2fecdcd --- /dev/null +++ b/build/container.mk @@ -0,0 +1,28 @@ +.PHONY: container-debian-build-image +.ONESHELL: container-debian-build-image +container-debian-build-image: +container-debian-build-image: ## Builds a container image for building on Debian Linux + $Q echo "$(M) building debian linux docker build image: $(@)" + $(DOCKER) buildx build $(DOCKER_BUILD_FLAGS) -t debian-ngx-rust-builder -f Containerfile.debian $(CURDIR); + +.PHONY: container-test +container-test: container-debian-build-image ## Run tests inside container + $Q mkdir -p .cache/cargo nginx-sys/.nginx + $(DOCKER) run --rm --volume "$(CURDIR):/project" --workdir /project --env 'CARGO_HOME=/project/.cache/cargo' debian-ngx-rust-builder make test + # Reset permissions on the target directory to the current user + if command -v id > /dev/null; then \ + $(DOCKER) run --rm --volume "$(CURDIR):/project" --workdir /project debian-ngx-rust-builder chown --silent --recursive "$(shell id -u):$(shell id -g)" /project/target /project/.cache /project/nginx-sys/.nginx + fi + +.PHONY: container-shell +container-shell: container-debian-build-image ## Start a shell inside container + $Q mkdir -p .cache/cargo nginx-sys/.nginx + $(DOCKER) run -it --rm --volume "$(CURDIR):/project" --workdir /project --env 'CARGO_HOME=/project/.cache/cargo' debian-ngx-rust-builder bash + # Reset permissions on the target directory to the current user + if command -v id > /dev/null; then \ + $(DOCKER) run --rm --volume "$(CURDIR):/project" --workdir /project debian-ngx-rust-builder chown --silent --recursive "$(shell id -u):$(shell id -g)" /project/target /project/.cache /project/nginx-sys/.nginx + fi + +.PHONY: build-docker +build-docker: ## build docker image with all example modules + $(DOCKER) buildx build $(DOCKER_BUILD_FLAGS) -t $(PROJECT_NAME) . diff --git a/build/github.mk b/build/github.mk new file mode 100644 index 0000000..5d61f4e --- /dev/null +++ b/build/github.mk @@ -0,0 +1,17 @@ +.PHONY: gh-make-release +.ONESHELL: gh-make-release +gh-make-release: +ifndef CI + $(error must be running in CI) +endif +ifneq ($(shell git rev-parse --abbrev-ref HEAD),release-v$(VERSION)) + $(error must be running on release-v$(VERSION) branch) +endif + $(info $(M) updating files with release version [$(GIT_BRANCH)]) @ + git commit -m "ci: update files to version $(VERSION)" Cargo.toml nginx-sys/Cargo.toml + git push origin "release-v$(VERSION)" + git tag -a "v$(VERSION)" -m "ci: tagging v$(VERSION)" + git push origin --tags + gh release create "v$(VERSION)" \ + --title "v$(VERSION)" \ + --notes-file $(CURDIR)/target/dist/release_notes.md \ No newline at end of file diff --git a/build/release.mk b/build/release.mk new file mode 100644 index 0000000..4790a56 --- /dev/null +++ b/build/release.mk @@ -0,0 +1,48 @@ +target/dist: + $Q mkdir -p target/dist + +.PHONY: changelog +.ONESHELL: changelog +changelog: ## Outputs the changes since the last version committed + $Q VERSION="$(VERSION)" $(CURDIR)/build/changelog.sh + +.ONESHELL: target/dist/release_notes.md +target/dist/release_notes.md: target/dist + $(info $(M) building release notes) @ + $Q echo "# Release Notes" > target/dist/release_notes.md + VERSION="$(VERSION)" $(CURDIR)/build/changelog.sh >> target/dist/release_notes.md + +.PHONY: release-notes +release-notes: target/dist/release_notes.md ## Build release notes + +.PHONY: version +version: ## Outputs the current version + $Q echo "Version: $(VERSION)" + +.PHONY: version-update +.ONESHELL: version-update +version-update: ## Prompts for a new version + $(info $(M) updating repository to new version) @ + $Q echo " last committed version: $(LAST_VERSION)" + $Q echo " Cargo.toml file version : $(VERSION)" + read -p " Enter new version in the format (MAJOR.MINOR.PATCH): " version + $Q echo "$$version" | $(GREP) -qE '^[0-9]+\.[0-9]+\.[0-9]+-?.*$$' || \ + (echo "invalid version identifier: $$version" && exit 1) && \ + $(SED) -i "s/^version\s*=.*$$/version = \"$$version\"/" $(CURDIR)/Cargo.toml + $(SED) -i "s/^version\s*=.*$$/version = \"$$version\"/" $(CURDIR)/nginx-sys/Cargo.toml + @ VERSION=$(shell $(GREP) -Po '^version\s+=\s+"\K.*?(?=")' $(CURDIR)/Cargo.toml) + +.PHONY: version-release +.ONESHELL: version-release +version-release: ## Change from a pre-release to full release version + $Q echo "$(VERSION)" | $(GREP) -qE '^[0-9]+\.[0-9]+\.[0-9]+-beta$$' || \ + (echo "invalid version identifier - must contain suffix -beta: $(VERSION)" && exit 1) + export NEW_VERSION="$(shell echo $(VERSION) | $(SED) -e 's/-beta$$//')" + $(SED) -i "s/^version\s*=.*$$/version = \"$$version\"/" $(CURDIR)/Cargo.toml + $(SED) -i "s/^version\s*=.*$$/version = \"$$version\"/" $(CURDIR)/nginx-sys/Cargo.toml + @ VERSION=$(shell $(GREP) -Po '^version\s+=\s+"\K.*?(?=")' $(CURDIR)/Cargo.toml) + +.PHONY: cargo-release +cargo-release: ## Releases a new version to crates.io + $(info $(M) releasing version $(VERSION) to crates.io) @ + $Q $(CARGO) publish \ No newline at end of file diff --git a/examples/Cargo.toml b/examples/Cargo.toml new file mode 100644 index 0000000..7759359 --- /dev/null +++ b/examples/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "examples" +version = "0.0.0" +publish = false +edition = "2021" +license = "Apache-2.0" + +[dev-dependencies] +ngx = { path = "../" } +aws-sign-v4 = "0.2.0" +chrono = "0.4.23" +http = "0.2.9" +libc = "0.2.140" + +[[example]] +name = "curl" +path = "curl.rs" +crate-type = ["cdylib"] + +[[example]] +name = "awssig" +path = "awssig.rs" +crate-type = ["cdylib"] + + + +[[example]] +name = "httporigdst" +path = "httporigdst.rs" +crate-type = ["cdylib"] +required-features = ["linux"] + +[features] +linux = [] diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..a4d7a0f --- /dev/null +++ b/examples/README.md @@ -0,0 +1,101 @@ +# Examples + +## NGINX Destination IP recovery module for HTTP + +This dynamic module recovers original IP address and port number of the destination packet. It is useful, for example, with container sidecars where all outgoing traffic is redirected to a separate container with iptables before reaching the target. + +This module can only be built with the "linux" feature enabled, and will only successfully build on a Linux OS. + +### Dependencies + +This modules uses the Rust crate libc and Linux **getsockopt** socket API. + +### Example Configuration +#### HTTP + +```nginx configuration +load_module "modules/libhttporigdst.so"; + +http { + server { + # use iptables to capture all outgoing traffic and REDIRECT + # to listening port 15501 + listen 15501; + + # binding variables provided by module will lazily activate it + # and store a context + # variables can be used in config + location / { + # Return if no backend is available or proxy_pass + # return 200 "recv'd: $server_addr:$server_port\n\nproxy_pass http://$server_orig_addr:$server_orig_port\n"; + proxy_pass http://$server_orig_addr:$server_orig_port; + } + } +} +``` + +### Embedded Variables + +The following embedded variables are provided: + +* **server_orig_addr** + * Original IP address +* **server_orig_port** + * Original port + +### Usage + +1. Clone the git repository. + ``` + https://github.com/nginxinc/ngx-rust + ``` + +2. Compile the module from the cloned repo. + ``` + cd ${CLONED_DIRECTORY}/ngx-rust + cargo build --package=examples --example=httporigdst --features=linux + ``` + +3. Copy the shared object to the modules directory, /etc/nginx/modules. + ``` + cp ./target/debug/examples/libhttporigdst.so /etc/nginx/modules + ``` + +4. Add the `load_module` directive to your configuration. + ``` + load_module "modules/libhttporigdst.so"; + ``` + +5. Reload NGINX. + ``` + nginx -t && nginx -s reload + ``` + +6. Redirect traffic outbound. + ``` + iptables -t nat -N NGINX_REDIRECT && \ + iptables -t nat -A NGINX_REDIRECT -p tcp -j REDIRECT --to-port 15501 --dport 15001 && \ + iptables -t nat -N NGINX_OUTPUT && \ + iptables -t nat -A OUTPUT -p tcp -j NGINX_OUTPUT && \ + iptables -t nat -A NGINX_OUTPUT -j NGINX_REDIRECT + ``` + +7. Redirect traffic inbound. + ``` + iptables -t nat -N NGINX_IN_REDIRECT && \ + iptables -t nat -A NGINX_IN_REDIRECT -p tcp -j REDIRECT --to-port 15501 --dport 15001 && \ + iptables -t nat -N NGINX_INBOUND && \ + iptables -t nat -A PREROUTING -p tcp -j NGINX_INBOUND && \ + iptables -t nat -A NGINX_INBOUND -p tcp -j NGINX_IN_REDIRECT + ``` + +8. Test with `curl` (this step assumes you've uncommented the return directive). + ``` + curl --output - ${LISTEN_IP}:15001 + recv'd: ${LISTEN_IP}:15501 + + proxy_pass http://${LISTEN_IP}:15001 + ``` +### Caveats + +This module only supports IPv4. diff --git a/examples/awssig.conf b/examples/awssig.conf new file mode 100644 index 0000000..5ff331e --- /dev/null +++ b/examples/awssig.conf @@ -0,0 +1,50 @@ +daemon off; +master_process off; +# worker_processes 1; + +# on linix load a module: +load_module modules/libawssig.so; + +# error_log /dev/stdout debug; +error_log error.log debug; + +# working_directory /tmp/cores/; +# worker_rlimit_core 500M; + +events { } + +http { + server { + listen *:8000; + server_name localhost; + + awssigv4_access_key my-access-key; + awssigv4_secret_key my-secret-key; + awssigv4_s3_bucket my-bucket; + + location / { + awssigv4 on; + proxy_pass http://localhost:8777; + ## (on | off ) to enable aws sig v4 + location /some { + awssigv4 off; + } + ## awssigv4_s3_endpoint if not set then 's3.amazonaws.com' + # awssigv4_s3_endpoint s3.amazonaws.com; + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root html; + } + } + server { + listen 8777; + server_name localhost; + location / { + add_header x-authorization $http_authorization; + add_header x-Amz-Date $http_x_amz_date; + return 204; + } + } +} diff --git a/examples/awssig.rs b/examples/awssig.rs new file mode 100644 index 0000000..e5aa70d --- /dev/null +++ b/examples/awssig.rs @@ -0,0 +1,345 @@ +use http::HeaderMap; +use ngx::ffi::{ + nginx_version, ngx_array_push, ngx_command_t, ngx_conf_t, ngx_http_core_module, ngx_http_handler_pt, + ngx_http_module_t, ngx_http_phases_NGX_HTTP_PRECONTENT_PHASE, ngx_http_request_t, ngx_int_t, ngx_module_t, + ngx_str_t, ngx_uint_t, NGX_CONF_TAKE1, NGX_HTTP_LOC_CONF, NGX_HTTP_MODULE, NGX_HTTP_SRV_CONF, + NGX_RS_HTTP_LOC_CONF_OFFSET, NGX_RS_MODULE_SIGNATURE, +}; +use ngx::{core, core::Status, http::*}; +use ngx::{http_request_handler, ngx_log_debug_http, ngx_modules, ngx_null_command, ngx_string}; +use std::os::raw::{c_char, c_void}; + +struct Module; + +impl HTTPModule for Module { + type MainConf = (); + type SrvConf = (); + type LocConf = ModuleConfig; + + unsafe extern "C" fn postconfiguration(cf: *mut ngx_conf_t) -> ngx_int_t { + let cmcf = ngx_http_conf_get_module_main_conf(cf, &ngx_http_core_module); + + let h = ngx_array_push(&mut (*cmcf).phases[ngx_http_phases_NGX_HTTP_PRECONTENT_PHASE as usize].handlers) + as *mut ngx_http_handler_pt; + if h.is_null() { + return core::Status::NGX_ERROR.into(); + } + // set an phase handler + *h = Some(awssigv4_header_handler); + core::Status::NGX_OK.into() + } +} + +#[derive(Debug, Default)] +struct ModuleConfig { + enable: bool, + access_key: String, + secret_key: String, + s3_bucket: String, + s3_endpoint: String, +} + +#[no_mangle] +static mut ngx_http_awssigv4_commands: [ngx_command_t; 6] = [ + ngx_command_t { + name: ngx_string!("awssigv4"), + type_: (NGX_HTTP_LOC_CONF | NGX_HTTP_SRV_CONF | NGX_CONF_TAKE1) as ngx_uint_t, + set: Some(ngx_http_awssigv4_commands_set_enable), + conf: NGX_RS_HTTP_LOC_CONF_OFFSET, + offset: 0, + post: std::ptr::null_mut(), + }, + ngx_command_t { + name: ngx_string!("awssigv4_access_key"), + type_: (NGX_HTTP_LOC_CONF | NGX_HTTP_SRV_CONF | NGX_CONF_TAKE1) as ngx_uint_t, + set: Some(ngx_http_awssigv4_commands_set_access_key), + conf: NGX_RS_HTTP_LOC_CONF_OFFSET, + offset: 0, + post: std::ptr::null_mut(), + }, + ngx_command_t { + name: ngx_string!("awssigv4_secret_key"), + type_: (NGX_HTTP_LOC_CONF | NGX_HTTP_SRV_CONF | NGX_CONF_TAKE1) as ngx_uint_t, + set: Some(ngx_http_awssigv4_commands_set_secret_key), + conf: NGX_RS_HTTP_LOC_CONF_OFFSET, + offset: 0, + post: std::ptr::null_mut(), + }, + ngx_command_t { + name: ngx_string!("awssigv4_s3_bucket"), + type_: (NGX_HTTP_LOC_CONF | NGX_HTTP_SRV_CONF | NGX_CONF_TAKE1) as ngx_uint_t, + set: Some(ngx_http_awssigv4_commands_set_s3_bucket), + conf: NGX_RS_HTTP_LOC_CONF_OFFSET, + offset: 0, + post: std::ptr::null_mut(), + }, + ngx_command_t { + name: ngx_string!("awssigv4_s3_endpoint"), + type_: (NGX_HTTP_LOC_CONF | NGX_HTTP_SRV_CONF | NGX_CONF_TAKE1) as ngx_uint_t, + set: Some(ngx_http_awssigv4_commands_set_s3_endpoint), + conf: NGX_RS_HTTP_LOC_CONF_OFFSET, + offset: 0, + post: std::ptr::null_mut(), + }, + ngx_null_command!(), +]; + +#[no_mangle] +static ngx_http_awssigv4_module_ctx: ngx_http_module_t = ngx_http_module_t { + preconfiguration: Some(Module::preconfiguration), + postconfiguration: Some(Module::postconfiguration), + create_main_conf: Some(Module::create_main_conf), + init_main_conf: Some(Module::init_main_conf), + create_srv_conf: Some(Module::create_srv_conf), + merge_srv_conf: Some(Module::merge_srv_conf), + create_loc_conf: Some(Module::create_loc_conf), + merge_loc_conf: Some(Module::merge_loc_conf), +}; + +ngx_modules!(ngx_http_awssigv4_module); + +#[no_mangle] +pub static mut ngx_http_awssigv4_module: ngx_module_t = ngx_module_t { + ctx_index: ngx_uint_t::max_value(), + index: ngx_uint_t::max_value(), + name: std::ptr::null_mut(), + spare0: 0, + spare1: 0, + version: nginx_version as ngx_uint_t, + signature: NGX_RS_MODULE_SIGNATURE.as_ptr() as *const c_char, + + ctx: &ngx_http_awssigv4_module_ctx as *const _ as *mut _, + commands: unsafe { &ngx_http_awssigv4_commands[0] as *const _ as *mut _ }, + type_: NGX_HTTP_MODULE as ngx_uint_t, + + init_master: None, + init_module: None, + init_process: None, + init_thread: None, + exit_thread: None, + exit_process: None, + exit_master: None, + + spare_hook0: 0, + spare_hook1: 0, + spare_hook2: 0, + spare_hook3: 0, + spare_hook4: 0, + spare_hook5: 0, + spare_hook6: 0, + spare_hook7: 0, +}; + +impl Merge for ModuleConfig { + fn merge(&mut self, prev: &ModuleConfig) -> Result<(), MergeConfigError> { + if prev.enable { + self.enable = true; + }; + + if self.access_key.is_empty() { + self.access_key = String::from(if !prev.access_key.is_empty() { + &prev.access_key + } else { + "" + }); + } + if self.enable && self.access_key.is_empty() { + return Err(MergeConfigError::NoValue); + } + + if self.secret_key.is_empty() { + self.secret_key = String::from(if !prev.secret_key.is_empty() { + &prev.secret_key + } else { + "" + }); + } + if self.enable && self.secret_key.is_empty() { + return Err(MergeConfigError::NoValue); + } + + if self.s3_bucket.is_empty() { + self.s3_bucket = String::from(if !prev.s3_bucket.is_empty() { + &prev.s3_bucket + } else { + "" + }); + } + if self.enable && self.s3_bucket.is_empty() { + return Err(MergeConfigError::NoValue); + } + + if self.s3_endpoint.is_empty() { + self.s3_endpoint = String::from(if !prev.s3_endpoint.is_empty() { + &prev.s3_endpoint + } else { + "s3.amazonaws.com" + }); + } + Ok(()) + } +} + +#[no_mangle] +extern "C" fn ngx_http_awssigv4_commands_set_enable( + cf: *mut ngx_conf_t, + _cmd: *mut ngx_command_t, + conf: *mut c_void, +) -> *mut c_char { + unsafe { + let conf = &mut *(conf as *mut ModuleConfig); + let args = (*(*cf).args).elts as *mut ngx_str_t; + let val = (*args.add(1)).to_str(); + + // set default value optionally + conf.enable = false; + + if val.len() == 2 && val.eq_ignore_ascii_case("on") { + conf.enable = true; + } else if val.len() == 3 && val.eq_ignore_ascii_case("off") { + conf.enable = false; + } + }; + + std::ptr::null_mut() +} + +#[no_mangle] +extern "C" fn ngx_http_awssigv4_commands_set_access_key( + cf: *mut ngx_conf_t, + _cmd: *mut ngx_command_t, + conf: *mut c_void, +) -> *mut c_char { + unsafe { + let conf = &mut *(conf as *mut ModuleConfig); + let args = (*(*cf).args).elts as *mut ngx_str_t; + conf.access_key = (*args.add(1)).to_string(); + }; + + std::ptr::null_mut() +} + +#[no_mangle] +extern "C" fn ngx_http_awssigv4_commands_set_secret_key( + cf: *mut ngx_conf_t, + _cmd: *mut ngx_command_t, + conf: *mut c_void, +) -> *mut c_char { + unsafe { + let conf = &mut *(conf as *mut ModuleConfig); + let args = (*(*cf).args).elts as *mut ngx_str_t; + conf.secret_key = (*args.add(1)).to_string(); + }; + + std::ptr::null_mut() +} + +#[no_mangle] +extern "C" fn ngx_http_awssigv4_commands_set_s3_bucket( + cf: *mut ngx_conf_t, + _cmd: *mut ngx_command_t, + conf: *mut c_void, +) -> *mut c_char { + unsafe { + let conf = &mut *(conf as *mut ModuleConfig); + let args = (*(*cf).args).elts as *mut ngx_str_t; + conf.s3_bucket = (*args.add(1)).to_string(); + if conf.s3_bucket.len() == 1 { + println!("Validation failed"); + return ngx::core::NGX_CONF_ERROR as _; + } + }; + std::ptr::null_mut() +} + +#[no_mangle] +extern "C" fn ngx_http_awssigv4_commands_set_s3_endpoint( + cf: *mut ngx_conf_t, + _cmd: *mut ngx_command_t, + conf: *mut c_void, +) -> *mut c_char { + unsafe { + let conf = &mut *(conf as *mut ModuleConfig); + let args = (*(*cf).args).elts as *mut ngx_str_t; + conf.s3_endpoint = (*args.add(1)).to_string(); + }; + + std::ptr::null_mut() +} + +http_request_handler!(awssigv4_header_handler, |request: &mut Request| { + // get Module Config from request + let conf = unsafe { request.get_module_loc_conf::(&ngx_http_awssigv4_module) }; + let conf = conf.unwrap(); + ngx_log_debug_http!(request, "AWS signature V4 module {}", { + if conf.enable { + "enabled" + } else { + "disabled" + } + }); + if !conf.enable { + return core::Status::NGX_DECLINED; + } + + // TODO: build url properly from the original URL from client + let method = request.method(); + if !matches!(method, ngx::http::Method::HEAD | ngx::http::Method::GET) { + return HTTPStatus::FORBIDDEN.into(); + } + + let datetime = chrono::Utc::now(); + let uri = match request.unparsed_uri().to_str() { + Ok(v) => format!("https://{}.{}{}", conf.s3_bucket, conf.s3_endpoint, v), + Err(_) => return core::Status::NGX_DECLINED, + }; + + let datetime_now = datetime.format("%Y%m%dT%H%M%SZ"); + let datetime_now = datetime_now.to_string(); + + let signature = { + // NOTE: aws_sign_v4::AwsSign::new() implementation requires a HeaderMap. + // Iterate over requests headers_in and copy into HeaderMap + // Copy only headers that will be used to sign the request + let mut headers = HeaderMap::new(); + for (name, value) in request.headers_in_iterator() { + match name.to_lowercase().as_str() { + "host" => { + headers.insert(http::header::HOST, value.parse().unwrap()); + } + &_ => {} + }; + } + headers.insert("X-Amz-Date", datetime_now.parse().unwrap()); + ngx_log_debug_http!(request, "headers {:?}", headers); + ngx_log_debug_http!(request, "method {:?}", method); + ngx_log_debug_http!(request, "uri {:?}", uri); + ngx_log_debug_http!(request, "datetime_now {:?}", datetime_now); + + let s = aws_sign_v4::AwsSign::new( + method.as_str(), + &uri, + &datetime, + &headers, + "us-east-1", + conf.access_key.as_str(), + conf.secret_key.as_str(), + "s3", + "", + ); + s.sign() + }; + + request.add_header_in("authorization", signature.as_str()); + request.add_header_in("X-Amz-Date", datetime_now.as_str()); + + // done signing, let's print values we have in request.headers_out, request.headers_in + for (name, value) in request.headers_out_iterator() { + ngx_log_debug_http!(request, "headers_out {}: {}", name, value); + } + for (name, value) in request.headers_in_iterator() { + ngx_log_debug_http!(request, "headers_in {}: {}", name, value); + } + + core::Status::NGX_OK +}); diff --git a/examples/awssig_curl_combined.conf b/examples/awssig_curl_combined.conf new file mode 100644 index 0000000..7956e0e --- /dev/null +++ b/examples/awssig_curl_combined.conf @@ -0,0 +1,53 @@ +daemon off; +master_process off; +# worker_processes 1; + +# on linix load a module: +load_module modules/libawssig.so; +load_module modules/libcurl.so; + +# error_log /dev/stdout debug; +error_log error.log debug; + +# working_directory /tmp/cores/; +# worker_rlimit_core 500M; + +events { } + +http { + server { + listen *:8000; + server_name localhost; + + awssigv4_access_key my-access-key; + awssigv4_secret_key my-secret-key; + awssigv4_s3_bucket my-bucket; + + location / { + awssigv4 on; + curl on; + + proxy_pass http://localhost:8777; + ## (on | off ) to enable aws sig v4 + location /some { + awssigv4 off; + } + ## awssigv4_s3_endpoint if not set then 's3.amazonaws.com' + # awssigv4_s3_endpoint s3.amazonaws.com; + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root html; + } + } + server { + listen 8777; + server_name localhost; + location / { + add_header x-authorization $http_authorization; + add_header x-Amz-Date $http_x_amz_date; + return 204; + } + } +} diff --git a/examples/curl.conf b/examples/curl.conf new file mode 100644 index 0000000..603fc15 --- /dev/null +++ b/examples/curl.conf @@ -0,0 +1,31 @@ +daemon off; +master_process off; +# worker_processes 1; + +# on linux load a module: +load_module modules/libcurl.so; + +# on mac os it would be dylib +# load_module modules/libcurl.dylib; + +# error_log /dev/stdout debug; +error_log error.log debug; + +events { } + +http { + server { + listen *:8000; + server_name localhost; + location / { + root html; + index index.html index.htm; + # libcurl module directive: + curl on; + } + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root html; + } + } +} diff --git a/examples/curl.rs b/examples/curl.rs new file mode 100644 index 0000000..d0bbb43 --- /dev/null +++ b/examples/curl.rs @@ -0,0 +1,147 @@ +use ngx::ffi::{ + nginx_version, ngx_array_push, ngx_command_t, ngx_conf_t, ngx_http_core_module, ngx_http_handler_pt, + ngx_http_module_t, ngx_http_phases_NGX_HTTP_ACCESS_PHASE, ngx_http_request_t, ngx_int_t, ngx_module_t, ngx_str_t, + ngx_uint_t, NGX_CONF_TAKE1, NGX_HTTP_LOC_CONF, NGX_HTTP_MODULE, NGX_RS_HTTP_LOC_CONF_OFFSET, + NGX_RS_MODULE_SIGNATURE, +}; +use ngx::http::MergeConfigError; +use ngx::{core, core::Status, http, http::HTTPModule}; +use ngx::{http_request_handler, ngx_log_debug_http, ngx_modules, ngx_null_command, ngx_string}; +use std::os::raw::{c_char, c_void}; + +struct Module; + +impl http::HTTPModule for Module { + type MainConf = (); + type SrvConf = (); + type LocConf = ModuleConfig; + + unsafe extern "C" fn postconfiguration(cf: *mut ngx_conf_t) -> ngx_int_t { + let cmcf = http::ngx_http_conf_get_module_main_conf(cf, &ngx_http_core_module); + + let h = ngx_array_push(&mut (*cmcf).phases[ngx_http_phases_NGX_HTTP_ACCESS_PHASE as usize].handlers) + as *mut ngx_http_handler_pt; + if h.is_null() { + return core::Status::NGX_ERROR.into(); + } + // set an Access phase handler + *h = Some(curl_access_handler); + core::Status::NGX_OK.into() + } +} + +#[derive(Debug, Default)] +struct ModuleConfig { + enable: bool, +} + +#[no_mangle] +static mut ngx_http_curl_commands: [ngx_command_t; 2] = [ + ngx_command_t { + name: ngx_string!("curl"), + type_: (NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1) as ngx_uint_t, + set: Some(ngx_http_curl_commands_set_enable), + conf: NGX_RS_HTTP_LOC_CONF_OFFSET, + offset: 0, + post: std::ptr::null_mut(), + }, + ngx_null_command!(), +]; + +#[no_mangle] +static ngx_http_curl_module_ctx: ngx_http_module_t = ngx_http_module_t { + preconfiguration: Some(Module::preconfiguration), + postconfiguration: Some(Module::postconfiguration), + create_main_conf: Some(Module::create_main_conf), + init_main_conf: Some(Module::init_main_conf), + create_srv_conf: Some(Module::create_srv_conf), + merge_srv_conf: Some(Module::merge_srv_conf), + create_loc_conf: Some(Module::create_loc_conf), + merge_loc_conf: Some(Module::merge_loc_conf), +}; + +ngx_modules!(ngx_http_curl_module); + +#[no_mangle] +pub static mut ngx_http_curl_module: ngx_module_t = ngx_module_t { + ctx_index: ngx_uint_t::max_value(), + index: ngx_uint_t::max_value(), + name: std::ptr::null_mut(), + spare0: 0, + spare1: 0, + version: nginx_version as ngx_uint_t, + signature: NGX_RS_MODULE_SIGNATURE.as_ptr() as *const c_char, + + ctx: &ngx_http_curl_module_ctx as *const _ as *mut _, + commands: unsafe { &ngx_http_curl_commands[0] as *const _ as *mut _ }, + type_: NGX_HTTP_MODULE as ngx_uint_t, + + init_master: None, + init_module: None, + init_process: None, + init_thread: None, + exit_thread: None, + exit_process: None, + exit_master: None, + + spare_hook0: 0, + spare_hook1: 0, + spare_hook2: 0, + spare_hook3: 0, + spare_hook4: 0, + spare_hook5: 0, + spare_hook6: 0, + spare_hook7: 0, +}; + +impl http::Merge for ModuleConfig { + fn merge(&mut self, prev: &ModuleConfig) -> Result<(), MergeConfigError> { + if prev.enable { + self.enable = true; + }; + Ok(()) + } +} + +http_request_handler!(curl_access_handler, |request: &mut http::Request| { + let co = unsafe { request.get_module_loc_conf::(&ngx_http_curl_module) }; + let co = co.expect("module config is none"); + + ngx_log_debug_http!(request, "curl module enabled: {}", co.enable); + + match co.enable { + true => { + if request.user_agent().as_bytes().starts_with(b"curl") { + http::HTTPStatus::FORBIDDEN.into() + } else { + core::Status::NGX_DECLINED + } + } + false => core::Status::NGX_DECLINED, + } +}); + +#[no_mangle] +extern "C" fn ngx_http_curl_commands_set_enable( + cf: *mut ngx_conf_t, + _cmd: *mut ngx_command_t, + conf: *mut c_void, +) -> *mut c_char { + unsafe { + let conf = &mut *(conf as *mut ModuleConfig); + let args = (*(*cf).args).elts as *mut ngx_str_t; + + let val = (*args.add(1)).to_str(); + + // set default value optionally + conf.enable = false; + + if val.len() == 2 && val.eq_ignore_ascii_case("on") { + conf.enable = true; + } else if val.len() == 3 && val.eq_ignore_ascii_case("off") { + conf.enable = false; + } + }; + + std::ptr::null_mut() +} diff --git a/examples/httporigdst.conf b/examples/httporigdst.conf new file mode 100644 index 0000000..6fff8c2 --- /dev/null +++ b/examples/httporigdst.conf @@ -0,0 +1,16 @@ +http { + server { + # use iptables to capture all outgoing traffic and REDIRECT + # to listening port 15501 + listen 15501; + + # binding variables provided by module will lazily activate it + # and store a context + # variables can be used in config + location / { + # Return if no backend is available or proxy_pass + # return 200 "recv'd: $server_addr:$server_port\n\nproxy_pass http://$server_orig_addr:$server_orig_port\n"; + proxy_pass http://$server_orig_addr:$server_orig_port; + } + } +} \ No newline at end of file diff --git a/examples/httporigdst.rs b/examples/httporigdst.rs new file mode 100644 index 0000000..1e62e27 --- /dev/null +++ b/examples/httporigdst.rs @@ -0,0 +1,308 @@ +use ngx::ffi::{ + in_port_t, nginx_version, ngx_conf_t, ngx_connection_local_sockaddr, ngx_http_add_variable, ngx_http_module_t, + ngx_http_request_t, ngx_http_variable_t, ngx_inet_get_port, ngx_int_t, ngx_module_t, ngx_sock_ntop, ngx_str_t, + ngx_uint_t, ngx_variable_value_t, sockaddr, sockaddr_storage, INET_ADDRSTRLEN, NGX_HTTP_MODULE, + NGX_RS_MODULE_SIGNATURE, +}; +use ngx::{core, core::Status, http, http::HTTPModule}; +use ngx::{http_variable_get, ngx_http_null_variable, ngx_log_debug_http, ngx_modules, ngx_null_string, ngx_string}; +use std::os::raw::{c_char, c_int, c_void}; + +const IPV4_STRLEN: usize = INET_ADDRSTRLEN as usize; + +#[derive(Debug)] +struct NgxHttpOrigDstCtx { + orig_dst_addr: ngx_str_t, + orig_dst_port: ngx_str_t, +} + +impl Default for NgxHttpOrigDstCtx { + fn default() -> NgxHttpOrigDstCtx { + NgxHttpOrigDstCtx { + orig_dst_addr: ngx_null_string!(), + orig_dst_port: ngx_null_string!(), + } + } +} + +impl NgxHttpOrigDstCtx { + pub fn save(&mut self, addr: &str, port: in_port_t, pool: &mut core::Pool) -> core::Status { + let addr_data = pool.alloc(IPV4_STRLEN); + if addr_data.is_null() { + return core::Status::NGX_ERROR; + } + unsafe { libc::memcpy(addr_data, addr.as_ptr() as *const c_void, IPV4_STRLEN) }; + self.orig_dst_addr.len = IPV4_STRLEN; + self.orig_dst_addr.data = addr_data as *mut u8; + + let port_str = port.to_string(); + let port_data = pool.alloc(port_str.len()); + if port_data.is_null() { + return core::Status::NGX_ERROR; + } + unsafe { libc::memcpy(port_data, port_str.as_bytes().as_ptr() as *const c_void, port_str.len()) }; + self.orig_dst_port.len = port_str.len(); + self.orig_dst_port.data = port_data as *mut u8; + + core::Status::NGX_OK + } + + pub unsafe fn bind_addr(&self, v: *mut ngx_variable_value_t) { + if self.orig_dst_addr.len == 0 { + (*v).set_not_found(1); + return; + } + + (*v).set_valid(1); + (*v).set_no_cacheable(0); + (*v).set_not_found(0); + (*v).set_len(self.orig_dst_addr.len as u32); + (*v).data = self.orig_dst_addr.data; + } + + pub unsafe fn bind_port(&self, v: *mut ngx_variable_value_t) { + if self.orig_dst_port.len == 0 { + (*v).set_not_found(1); + return; + } + + (*v).set_valid(1); + (*v).set_no_cacheable(0); + (*v).set_not_found(0); + (*v).set_len(self.orig_dst_port.len as u32); + (*v).data = self.orig_dst_port.data; + } +} + +#[no_mangle] +static ngx_http_orig_dst_module_ctx: ngx_http_module_t = ngx_http_module_t { + preconfiguration: Some(Module::preconfiguration), + postconfiguration: Some(Module::postconfiguration), + create_main_conf: Some(Module::create_main_conf), + init_main_conf: Some(Module::init_main_conf), + create_srv_conf: Some(Module::create_srv_conf), + merge_srv_conf: Some(Module::merge_srv_conf), + create_loc_conf: Some(Module::create_loc_conf), + merge_loc_conf: Some(Module::merge_loc_conf), +}; + +ngx_modules!(ngx_http_orig_dst_module); + +#[no_mangle] +pub static mut ngx_http_orig_dst_module: ngx_module_t = ngx_module_t { + ctx_index: ngx_uint_t::max_value(), + index: ngx_uint_t::max_value(), + name: std::ptr::null_mut(), + spare0: 0, + spare1: 0, + version: nginx_version as ngx_uint_t, + signature: NGX_RS_MODULE_SIGNATURE.as_ptr() as *const c_char, + ctx: &ngx_http_orig_dst_module_ctx as *const _ as *mut _, + commands: std::ptr::null_mut(), + type_: NGX_HTTP_MODULE as ngx_uint_t, + + init_master: None, + init_module: None, + init_process: None, + init_thread: None, + exit_thread: None, + exit_process: None, + exit_master: None, + + spare_hook0: 0, + spare_hook1: 0, + spare_hook2: 0, + spare_hook3: 0, + spare_hook4: 0, + spare_hook5: 0, + spare_hook6: 0, + spare_hook7: 0, +}; + +#[no_mangle] +static mut ngx_http_orig_dst_vars: [ngx_http_variable_t; 3] = [ + // ngx_str_t name + // ngx_http_set_variable_pt set_handler + // ngx_http_get_variable_pt get_handler + // uintptr_t data + // ngx_uint_t flags + // ngx_uint_t index + ngx_http_variable_t { + name: ngx_string!("server_orig_addr"), + set_handler: None, + get_handler: Some(ngx_http_orig_dst_addr_variable), + data: 0, + flags: 0, + index: 0, + }, + ngx_http_variable_t { + name: ngx_string!("server_orig_port"), + set_handler: None, + get_handler: Some(ngx_http_orig_dst_port_variable), + data: 0, + flags: 0, + index: 0, + }, + ngx_http_null_variable!(), +]; + +unsafe fn ngx_get_origdst(request: &mut http::Request) -> Result<(String, in_port_t), core::Status> { + let c = request.connection(); + + if (*c).type_ != libc::SOCK_STREAM { + ngx_log_debug_http!(request, "httporigdst: connection is not type SOCK_STREAM"); + return Err(core::Status::NGX_DECLINED); + } + + if ngx_connection_local_sockaddr(c, std::ptr::null_mut(), 0) != core::Status::NGX_OK.into() { + ngx_log_debug_http!(request, "httporigdst: no local sockaddr from connection"); + return Err(core::Status::NGX_ERROR); + } + + let level: c_int; + let optname: c_int; + match (*(*c).local_sockaddr).sa_family as i32 { + libc::AF_INET => { + level = libc::SOL_IP; + optname = libc::SO_ORIGINAL_DST; + } + _ => { + ngx_log_debug_http!(request, "httporigdst: only support IPv4"); + return Err(core::Status::NGX_DECLINED); + } + } + + let mut addr: sockaddr_storage = { std::mem::zeroed() }; + let mut addrlen: libc::socklen_t = std::mem::size_of_val(&addr) as libc::socklen_t; + let rc = libc::getsockopt( + (*c).fd, + level, + optname, + &mut addr as *mut _ as *mut _, + &mut addrlen as *mut u32, + ); + if rc == -1 { + ngx_log_debug_http!(request, "httporigdst: getsockopt failed"); + return Err(core::Status::NGX_DECLINED); + } + let mut ip: Vec = vec![0; IPV4_STRLEN]; + let e = unsafe { + ngx_sock_ntop( + std::ptr::addr_of_mut!(addr) as *mut sockaddr, + std::mem::size_of::() as u32, + ip.as_mut_ptr(), + IPV4_STRLEN, + 0, + ) + }; + if e == 0 { + ngx_log_debug_http!(request, "httporigdst: ngx_sock_ntop failed to convert sockaddr"); + return Err(core::Status::NGX_ERROR); + } + + let port = unsafe { ngx_inet_get_port(std::ptr::addr_of_mut!(addr) as *mut sockaddr) }; + + Ok((String::from_utf8(ip).unwrap(), port)) +} + +http_variable_get!( + ngx_http_orig_dst_addr_variable, + |request: &mut http::Request, v: *mut ngx_variable_value_t, _: usize| { + let ctx = request.get_module_ctx::(&ngx_http_orig_dst_module); + if let Some(obj) = ctx { + ngx_log_debug_http!(request, "httporigdst: found context and binding variable",); + obj.bind_addr(v); + return core::Status::NGX_OK; + } + // lazy initialization: + // get original dest information + // create context + // set context + // bind address + ngx_log_debug_http!(request, "httporigdst: context not found, getting address"); + let r = ngx_get_origdst(request); + match r { + Err(e) => { + return e; + } + Ok((ip, port)) => { + // create context, + // set context + let new_ctx = request.pool().allocate::(Default::default()); + + if new_ctx.is_null() { + return core::Status::NGX_ERROR; + } + + ngx_log_debug_http!(request, "httporigdst: saving ip - {:?}, port - {}", ip, port,); + (*new_ctx).save(&ip, port, &mut request.pool()); + (*new_ctx).bind_addr(v); + request.set_module_ctx(new_ctx as *mut c_void, &ngx_http_orig_dst_module); + } + } + core::Status::NGX_OK + } +); + +http_variable_get!( + ngx_http_orig_dst_port_variable, + |request: &mut http::Request, v: *mut ngx_variable_value_t, _: usize| { + let ctx = request.get_module_ctx::(&ngx_http_orig_dst_module); + if let Some(obj) = ctx { + ngx_log_debug_http!(request, "httporigdst: found context and binding variable",); + obj.bind_port(v); + return core::Status::NGX_OK; + } + // lazy initialization: + // get original dest information + // create context + // set context + // bind port + ngx_log_debug_http!(request, "httporigdst: context not found, getting address"); + let r = ngx_get_origdst(request); + match r { + Err(e) => { + return e; + } + Ok((ip, port)) => { + // create context, + // set context + let new_ctx = request.pool().allocate::(Default::default()); + + if new_ctx.is_null() { + return core::Status::NGX_ERROR; + } + + ngx_log_debug_http!(request, "httporigdst: saving ip - {:?}, port - {}", ip, port,); + (*new_ctx).save(&ip, port, &mut request.pool()); + (*new_ctx).bind_port(v); + request.set_module_ctx(new_ctx as *mut c_void, &ngx_http_orig_dst_module); + } + } + core::Status::NGX_OK + } +); + +struct Module; + +impl HTTPModule for Module { + type MainConf = (); + type SrvConf = (); + type LocConf = (); + + // static ngx_int_t ngx_http_orig_dst_add_variables(ngx_conf_t *cf) + unsafe extern "C" fn preconfiguration(cf: *mut ngx_conf_t) -> ngx_int_t { + for mut v in ngx_http_orig_dst_vars { + if v.name.len == 0 { + break; + } + let var = ngx_http_add_variable(cf, &mut v.name, v.flags); + if var.is_null() { + return core::Status::NGX_ERROR.into(); + } + (*var).get_handler = v.get_handler; + (*var).data = v.data; + } + core::Status::NGX_OK.into() + } +} diff --git a/nginx-sys/Cargo.toml b/nginx-sys/Cargo.toml new file mode 100644 index 0000000..d17233d --- /dev/null +++ b/nginx-sys/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "nginx-sys" +version = "0.1.0" +edition = "2021" +license = "Apache-2.0" + +[lib] +crate-type = ["staticlib","rlib"] + +[dependencies] + +[build-dependencies] +bindgen = "0.64.0" +which = "4.4.0" +duct = "0.13.6" +ureq = { version = "2.6.2", features = ["tls"] } +flate2 = "1.0.25" +tar = "0.4.38" diff --git a/nginx-sys/build.rs b/nginx-sys/build.rs new file mode 100644 index 0000000..22d51b2 --- /dev/null +++ b/nginx-sys/build.rs @@ -0,0 +1,645 @@ +extern crate bindgen; +extern crate duct; + +use duct::cmd; +use flate2::read::GzDecoder; +use std::error::Error as StdError; +use std::ffi::OsString; +use std::fs::{read_to_string, File}; +use std::io::ErrorKind::NotFound; +use std::io::{Error as IoError, Write}; +use std::path::{Path, PathBuf}; +use std::process::Output; +use std::{env, thread}; +use tar::Archive; +use which::which; + +/// The default version of zlib to use if the `ZLIB_VERSION` environment variable is not present +const ZLIB_DEFAULT_VERSION: &str = "1.2.13"; +const ZLIB_GPG_SERVER_AND_KEY_ID: (&str, &str) = ("keyserver.ubuntu.com", "783FCD8E58BCAFBA"); +const ZLIB_DOWNLOAD_URL_PREFIX: &str = "https://www.zlib.net"; +/// The default version of pcre2 to use if the `PCRE2_VERSION` environment variable is not present +const PCRE2_DEFAULT_VERSION: &str = "10.42"; +const PCRE2_GPG_SERVER_AND_KEY_ID: (&str, &str) = ("keyserver.ubuntu.com", "9766E084FB0F43D8"); +const PCRE2_DOWNLOAD_URL_PREFIX: &str = "https://github.com/PCRE2Project/pcre2/releases/download"; +/// The default version of openssl to use if the `OPENSSL_VERSION` environment variable is not present +const OPENSSL_DEFAULT_VERSION: &str = "3.0.7"; +const OPENSSL_GPG_SERVER_AND_KEY_IDS: (&str, &str) = ( + "keys.openpgp.org", + "\ +A21FAB74B0088AA361152586B8EF1A6BA9DA2D5C \ +8657ABB260F056B1E5190839D9C4D26D0E604491 \ +B7C1C14360F353A36862E4D5231C84CDDCC69C45 \ +95A9908DDFA16830BE9FB9003D30A3A9FF1360DC \ +7953AC1FBC3DC8B3B292393ED5E9E43F7DF9EE8C", +); +const OPENSSL_DOWNLOAD_URL_PREFIX: &str = "https://www.openssl.org/source/"; +/// The default version of NGINX to use if the `NGX_VERSION` environment variable is not present +const NGX_DEFAULT_VERSION: &str = "1.23.3"; +const NGX_GPG_SERVER_AND_KEY_ID: (&str, &str) = ("keyserver.ubuntu.com", "A0EA981B66B0D967"); +const NGX_DOWNLOAD_URL_PREFIX: &str = "https://nginx.org/download"; +/// If you are adding another dependency, you will need to add the server/public key tuple below. +const ALL_SERVERS_AND_PUBLIC_KEY_IDS: [(&str, &str); 4] = [ + ZLIB_GPG_SERVER_AND_KEY_ID, + PCRE2_GPG_SERVER_AND_KEY_ID, + OPENSSL_GPG_SERVER_AND_KEY_IDS, + NGX_GPG_SERVER_AND_KEY_ID, +]; +/// List of configure switches specifying the modules to build nginx with +const NGX_BASE_MODULES: [&str; 15] = [ + "--with-compat", + "--with-threads", + "--with-http_addition_module", + "--with-http_auth_request_module", + "--with-http_gunzip_module", + "--with-http_gzip_static_module", + "--with-http_random_index_module", + "--with-http_realip_module", + "--with-http_secure_link_module", + "--with-http_slice_module", + "--with-http_stub_status_module", + "--with-http_sub_module", + "--with-stream", + "--with-stream_realip_module", + "--with-stream_ssl_preread_module", +]; +/// Additional configuration flags to use when building on Linux. +const NGX_LINUX_ADDITIONAL_OPTS: [&str; 5] = [ + "--with-file-aio", + "--with-http_ssl_module", + "--with-stream_ssl_module", + "--with-cc-opt=-g -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC", + "--with-ld-opt=-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie", +]; +const ENV_VARS_TRIGGERING_RECOMPILE: [&str; 9] = [ + "DEBUG", + "OUT_DIR", + "ZLIB_VERSION", + "PCRE2_VERSION", + "OPENSSL_VERSION", + "NGX_VERSION", + "CARGO_CFG_TARGET_OS", + "CARGO_MANIFEST_DIR", + "CARGO_TARGET_TMPDIR", +]; + +/// Function invoked when `cargo build` is executed. +/// This function will download NGINX and all supporting dependencies, verify their integrity, +/// extract them, execute autoconf `configure` for NGINX, compile NGINX and finally install +/// NGINX in a subdirectory with the project. +fn main() -> Result<(), Box> { + // Create .cache directory + let cache_dir = make_cache_dir()?; + // Import GPG keys used to verify dependency tarballs + import_gpg_keys(&cache_dir)?; + // Configure and Compile NGINX + let (_nginx_install_dir, nginx_src_dir) = compile_nginx()?; + // Hint cargo to rebuild if any of the these environment variables values change + // because they will trigger a recompilation of NGINX with different parameters + for var in ENV_VARS_TRIGGERING_RECOMPILE { + println!("cargo:rerun-if-env-changed={var}"); + } + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=wrapper.h"); + // Read autoconf generated makefile for NGINX and generate Rust bindings based on its includes + generate_binding(nginx_src_dir); + Ok(()) +} + +/// Generates Rust bindings for NGINX +fn generate_binding(nginx_source_dir: PathBuf) { + let autoconf_makefile_path = nginx_source_dir.join("objs").join("Makefile"); + let clang_args: Vec = parse_includes_from_makefile(&autoconf_makefile_path) + .into_iter() + .map(|path| format!("-I{}", path.to_string_lossy())) + .collect(); + + let bindings = bindgen::Builder::default() + // Bindings will not compile on Linux without block listing this item + // It is worth investigating why this is + .blocklist_item("IPPORT_RESERVED") + // The input header we would like to generate bindings for. + .header("wrapper.h") + .clang_args(clang_args) + .layout_tests(false) + .generate() + .expect("Unable to generate bindings"); + + // Write the bindings to the $OUT_DIR/bindings.rs file. + let out_dir_env = env::var("OUT_DIR").expect("The required environment variable OUT_DIR was not set"); + let out_path = PathBuf::from(out_dir_env); + bindings + .write_to_file(out_path.join("bindings.rs")) + .expect("Couldn't write bindings!"); +} + +/* +########################################################################### +# NGINX Build Functions - Everything below here is for building NGINX # +########################################################################### + +In order to build Rust bindings for NGINX using the bindgen crate, we need +to do the following: + + 1. Download NGINX source code and all dependencies (zlib, pcre2, openssl) + 2. Verify the integrity of the downloaded files using GPG signatures + 3. Extract the downloaded files + 4. Run autoconf `configure` for NGINX + 5. Compile NGINX + 6. Install NGINX in a subdirectory of the project + 7. Read the autoconf generated makefile for NGINX and configure bindgen + to generate Rust bindings based on the includes in the makefile. + +Additionally, we want to provide the following features as part of the +build process: + * Allow the user to specify the version of NGINX to build + * Allow the user to specify the version of each dependency to build + * Only reconfigure and recompile NGINX if any of the above versions + change or the configuration flags change (like enabling or disabling + the debug mode) + * Not rely on the user having NGINX dependencies installed on their + system (zlib, pcre2, openssl) + * Keep source code and binaries confined to a subdirectory of the + project to avoid having to track files outside of the project + * If GPG is not installed, the build will still continue. However, the + integrity of the downloaded files will not be verified. +*/ + +fn zlib_archive_url() -> String { + let version = env::var("ZLIB_VERSION").unwrap_or_else(|_| ZLIB_DEFAULT_VERSION.to_string()); + format!("{ZLIB_DOWNLOAD_URL_PREFIX}/zlib-{version}.tar.gz") +} + +fn pcre2_archive_url() -> String { + let version = env::var("PCRE2_VERSION").unwrap_or_else(|_| PCRE2_DEFAULT_VERSION.to_string()); + format!("{PCRE2_DOWNLOAD_URL_PREFIX}/pcre2-{version}/pcre2-{version}.tar.gz") +} + +fn openssl_archive_url() -> String { + let version = env::var("OPENSSL_VERSION").unwrap_or_else(|_| OPENSSL_DEFAULT_VERSION.to_string()); + format!("{OPENSSL_DOWNLOAD_URL_PREFIX}/openssl-{version}.tar.gz") +} + +fn nginx_archive_url() -> String { + let version = env::var("NGX_VERSION").unwrap_or_else(|_| NGX_DEFAULT_VERSION.to_string()); + format!("{NGX_DOWNLOAD_URL_PREFIX}/nginx-{version}.tar.gz") +} + +/// Returns a list of tuples containing the URL to a tarball archive and the GPG signature used +/// to validate the integrity of the tarball. +fn all_archives() -> Vec<(String, String)> { + vec![ + (zlib_archive_url(), format!("{}.asc", zlib_archive_url())), + (pcre2_archive_url(), format!("{}.sig", pcre2_archive_url())), + (openssl_archive_url(), format!("{}.asc", openssl_archive_url())), + (nginx_archive_url(), format!("{}.asc", nginx_archive_url())), + ] +} + +fn gpg_path() -> Option { + which::which("gpg").ok() +} + +/// Returns the base path to extract tarball contents into +fn source_output_dir(cache_dir: &Path) -> PathBuf { + env::var("CARGO_TARGET_TMPDIR").map(PathBuf::from).unwrap_or_else(|_| { + cache_dir + .join("src") + .join(format!("{}-{}", env::consts::OS, env::consts::ARCH)) + }) +} + +#[allow(clippy::ptr_arg)] +/// Returns the path to install NGINX to +fn nginx_install_dir(base_dir: &PathBuf) -> PathBuf { + let nginx_version = env::var("NGX_VERSION").unwrap_or_else(|_| NGX_DEFAULT_VERSION.to_string()); + let platform = format!("{}-{}", env::consts::OS, env::consts::ARCH); + base_dir.join("nginx").join(nginx_version).join(platform) +} + +/// Imports all of the required GPG keys into the `.cache/.gnupu` directory in order to +/// validate the integrity of the downloaded tarballs. +fn import_gpg_keys(cache_dir: &Path) -> Result<(), Box> { + if let Some(gpg) = gpg_path() { + // We do not want to mess with the default gpg data for the running user, + // so we store all gpg data with our cache directory. + let gnupghome = cache_dir.join(".gnupg"); + if !gnupghome.exists() { + std::fs::create_dir_all(&gnupghome)?; + } + + let keys_to_import = ALL_SERVERS_AND_PUBLIC_KEY_IDS.iter().filter(|(_, key_id)| { + let key_id_record_file = gnupghome.join(format!("{key_id}.key")); + !key_id_record_file.exists() + }); + + for (server, key_ids) in keys_to_import { + for key_id in key_ids.split_whitespace() { + let output = cmd!( + &gpg, + "--homedir", + &gnupghome, + "--keyserver", + server, + "--recv-keys", + key_id + ) + .stderr_to_stdout() + .stderr_capture() + .run()?; + if !output.status.success() { + return Err(format!( + "Failed to import GPG key {} from server {}: {}", + key_id, + server, + String::from_utf8_lossy(&output.stdout) + ) + .into()); + } + println!("Imported GPG key: {key_id}"); + let key_id_record_file = gnupghome.join(format!("{key_ids}.key")); + File::create(key_id_record_file).expect("Unable to create key id record file"); + } + } + } + Ok(()) +} + +fn make_cache_dir() -> Result> { + let base_dir = env::var("CARGO_MANIFEST_DIR") + .map(PathBuf::from) + .unwrap_or_else(|_| env::current_dir().expect("Failed to get current directory")); + // Choose the parent directory of the manifest directory (nginx-sys) as the cache directory + // Fail if we do not have a parent directory + let cache_dir = base_dir + .parent() + .expect("Failed to find parent directory of manifest directory") + .join(".cache"); + if !cache_dir.exists() { + std::fs::create_dir_all(&cache_dir)?; + } + Ok(cache_dir) +} + +/// Downloads a tarball from the specified URL into the `.cache` directory. +fn download(cache_dir: &Path, url: &str) -> Result> { + fn proceed_with_download(file_path: &Path) -> bool { + // File does not exist or is zero bytes + !file_path.exists() || file_path.metadata().map_or(false, |m| m.len() < 1) + } + let filename = url.split('/').last().unwrap(); + let file_path = cache_dir.join(filename); + if proceed_with_download(&file_path) { + let mut reader = ureq::get(url).call()?.into_reader(); + let mut file = std::fs::File::create(&file_path)?; + std::io::copy(&mut reader, &mut file)?; + } + Ok(file_path) +} + +/// Validates that a file is a valid GPG signature file. +fn verify_signature_file(cache_dir: &Path, signature_path: &Path) -> Result<(), Box> { + if let Some(gpg) = gpg_path() { + let gnupghome = cache_dir.join(".gnupg"); + let output = cmd!(gpg, "--homedir", &gnupghome, "--list-packets", signature_path) + .stderr_to_stdout() + .stdout_capture() + .run()?; + if !output.status.success() { + eprintln!("{}", String::from_utf8_lossy(&output.stdout)); + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::Other, + format!( + "GPG signature file verification failed for signature: {}", + signature_path.display() + ), + ))); + } + } else { + println!("GPG not found, skipping signature file verification"); + } + Ok(()) +} + +/// Validates the integrity of a tarball file against the cryptographic signature associated with +/// the file. +fn verify_archive_signature( + cache_dir: &Path, + archive_path: &Path, + signature_path: &Path, +) -> Result<(), Box> { + if let Some(gpg) = gpg_path() { + let gnupghome = cache_dir.join(".gnupg"); + let output = cmd!(gpg, "--homedir", &gnupghome, "--verify", signature_path, archive_path) + .stderr_to_stdout() + .stdout_capture() + .run()?; + if !output.status.success() { + eprintln!("{}", String::from_utf8_lossy(&output.stdout)); + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::Other, + format!( + "GPG signature verification failed of archive failed [{}]", + archive_path.display() + ), + ))); + } + } else { + println!("GPG not found, skipping signature verification"); + } + Ok(()) +} + +/// Get a given tarball and signature file from a remote URL and copy it to the `.cache` directory. +fn get_archive(cache_dir: &Path, archive_url: &str, signature_url: &str) -> Result> { + let signature_path = download(cache_dir, signature_url)?; + if let Err(e) = verify_signature_file(cache_dir, &signature_path) { + std::fs::remove_file(&signature_path)?; + return Err(e); + } + let archive_path = download(cache_dir, archive_url)?; + match verify_archive_signature(cache_dir, &archive_path, &signature_path) { + Ok(_) => Ok(archive_path), + Err(e) => { + std::fs::remove_file(&archive_path)?; + Err(e) + } + } +} + +/// Extract a tarball into a subdirectory based on the tarball's name under the source base +/// directory. +fn extract_archive( + archive_path: &Path, + extract_output_base_dir: &Path, +) -> Result<(String, PathBuf), Box> { + if !extract_output_base_dir.exists() { + std::fs::create_dir_all(extract_output_base_dir)?; + } + let archive_file = + File::open(archive_path).unwrap_or_else(|_| panic!("Unable to open archive file: {}", archive_path.display())); + let stem = archive_path + .file_name() + .and_then(|s| s.to_str()) + .and_then(|s| s.rsplitn(3, '.').last()) + .expect("Unable to determine archive file name stem"); + let dependency_name = stem + .split_once('-') + .map(|(s, _)| s.to_owned()) + .unwrap_or_else(|| panic!("Unable to determine dependency name based on stem: {stem}")); + + let extract_output_dir = extract_output_base_dir.to_owned(); + let archive_output_dir = extract_output_dir.join(stem); + if !archive_output_dir.exists() { + Archive::new(GzDecoder::new(archive_file)) + .entries()? + .filter_map(|e| e.ok()) + .for_each(|mut entry| { + let path = entry.path().unwrap(); + let stripped_path = path.components().skip(1).collect::(); + entry.unpack(&archive_output_dir.join(stripped_path)).unwrap(); + }); + } else { + println!( + "Archive [{}] already extracted to directory: {}", + stem, + archive_output_dir.display() + ); + } + + Ok((dependency_name, archive_output_dir)) +} + +/// Extract all of the tarballs into subdirectories within the source base directory. +fn extract_all_archives(cache_dir: &Path) -> Result, Box> { + let archives = all_archives(); + let mut sources = Vec::new(); + let extract_output_base_dir = source_output_dir(cache_dir); + if !extract_output_base_dir.exists() { + std::fs::create_dir_all(&extract_output_base_dir)?; + } + for (archive_url, signature_url) in archives { + let archive_path = get_archive(cache_dir, &archive_url, &signature_url)?; + let (name, output_dir) = extract_archive(&archive_path, &extract_output_base_dir)?; + sources.push((name, output_dir)); + } + + Ok(sources) +} + +/// Invoke external processes to run autoconf `configure` to generate a makefile for NGINX and +/// then run `make install`. +fn compile_nginx() -> Result<(PathBuf, PathBuf), Box> { + fn find_dependency_path<'a>(sources: &'a [(String, PathBuf)], name: &str) -> &'a PathBuf { + sources + .iter() + .find(|(n, _)| n == name) + .map(|(_, p)| p) + .unwrap_or_else(|| panic!("Unable to find dependency [{name}] path")) + } + let cache_dir = make_cache_dir()?; + let nginx_install_dir = nginx_install_dir(&cache_dir); + let sources = extract_all_archives(&cache_dir)?; + let zlib_src_dir = find_dependency_path(&sources, "zlib"); + let openssl_src_dir = find_dependency_path(&sources, "openssl"); + let pcre2_src_dir = find_dependency_path(&sources, "pcre2"); + let nginx_src_dir = find_dependency_path(&sources, "nginx"); + let nginx_configure_flags = nginx_configure_flags(&nginx_install_dir, zlib_src_dir, openssl_src_dir, pcre2_src_dir); + let nginx_binary_exists = nginx_install_dir.join("sbin").join("nginx").exists(); + let autoconf_makefile_exists = nginx_src_dir.join("Makefile").exists(); + // We find out how NGINX was configured last time, so that we can compare it to what + // we are going to configure it to this time. If there are no changes, then we can assume + // that we do not need to reconfigure and rebuild NGINX. + let build_info_path = nginx_src_dir.join("last-build-info"); + let current_build_info = build_info(&nginx_configure_flags); + let build_info_no_change = if build_info_path.exists() { + read_to_string(&build_info_path).map_or(false, |s| s == current_build_info) + } else { + false + }; + + println!("NGINX already installed: {nginx_binary_exists}"); + println!("NGINX autoconf makefile already created: {autoconf_makefile_exists}"); + println!("NGINX build info changed: {}", !build_info_no_change); + + if !nginx_binary_exists || !autoconf_makefile_exists || !build_info_no_change { + std::fs::create_dir_all(&nginx_install_dir)?; + configure(nginx_configure_flags, nginx_src_dir)?; + make(nginx_src_dir, "install")?; + let mut output = File::create(build_info_path)?; + // Store the configure flags of the last successful build + output.write_all(current_build_info.as_bytes())?; + } + Ok((nginx_install_dir, nginx_src_dir.to_owned())) +} + +/// Returns the options in which NGINX was built with +fn build_info(nginx_configure_flags: &[String]) -> String { + // Flags should contain strings pointing to OS/platform as well as dependency versions, + // so if any of that changes, it can trigger a rebuild + nginx_configure_flags.join(" ") +} + +/// Generate the flags to use with autoconf `configure` for NGINX based on the downloaded +/// dependencies' paths. Note: the paths differ based on cargo targets because they may be +/// configured differently for different os/platform targets. +fn nginx_configure_flags( + nginx_install_dir: &Path, + zlib_src_dir: &Path, + openssl_src_dir: &Path, + pcre2_src_dir: &Path, +) -> Vec { + fn format_source_path(flag: &str, path: &Path) -> String { + format!( + "{}={}", + flag, + path.as_os_str().to_str().expect("Unable to read source path as string") + ) + } + let modules = || -> Vec { + let mut modules = vec![ + format_source_path("--with-zlib", zlib_src_dir), + format_source_path("--with-pcre", pcre2_src_dir), + format_source_path("--with-openssl", openssl_src_dir), + ]; + for module in NGX_BASE_MODULES { + modules.push(module.to_string()); + } + modules + }; + let mut nginx_opts = vec![format_source_path("--prefix", nginx_install_dir)]; + if env::var("NGX_DEBUG").map_or(false, |s| s == "true") { + println!("Enabling --with-debug"); + nginx_opts.push("--with-debug".to_string()); + } + if env::var("CARGO_CFG_TARGET_OS").map_or(env::consts::OS == "linux", |s| s == "linux") { + for flag in NGX_LINUX_ADDITIONAL_OPTS { + nginx_opts.push(flag.to_string()); + } + } + for flag in modules() { + nginx_opts.push(flag); + } + + nginx_opts +} + +/// Run external process invoking autoconf `configure` for NGINX. +fn configure(nginx_configure_flags: Vec, nginx_src_dir: &Path) -> std::io::Result { + let flags = nginx_configure_flags + .iter() + .map(OsString::from) + .collect::>(); + let configure_executable = nginx_src_dir.join("configure"); + if !configure_executable.exists() { + panic!( + "Unable to find NGINX configure script at: {}", + configure_executable.to_string_lossy() + ); + } + println!( + "Running NGINX configure script with flags: {:?}", + nginx_configure_flags.join(" ") + ); + duct::cmd(configure_executable, flags) + .dir(nginx_src_dir) + .stderr_to_stdout() + .run() +} + +/// Run `make` within the NGINX source directory as an external process. +fn make(nginx_src_dir: &Path, arg: &str) -> std::io::Result { + // Give preference to the binary with the name of gmake if it exists because this is typically + // the GNU 4+ on MacOS (if it is installed via homebrew). + let make_bin_path = match (which("gmake"), which("make")) { + (Ok(path), _) => Ok(path), + (_, Ok(path)) => Ok(path), + _ => Err(IoError::new(NotFound, "Unable to find make in path (gmake or make)")), + }?; + + // Level of concurrency to use when building nginx - cargo nicely provides this information + let num_jobs = match env::var("NUM_JOBS") { + Ok(s) => s.parse::().ok(), + Err(_) => thread::available_parallelism().ok().map(|n| n.get()), + } + .unwrap_or(1); + + /* Use the duct dependency here to merge the output of STDOUT and STDERR into a single stream, + and to provide the combined output as a reader which can be iterated over line-by-line. We + use duct to do this because it is a lot of work to implement this from scratch. */ + cmd!(make_bin_path, "-j", num_jobs.to_string(), arg) + .dir(nginx_src_dir) + .stderr_to_stdout() + .run() +} + +/// Reads through the makefile generated by autoconf and finds all of the includes +/// used to compile nginx. This is used to generate the correct bindings for the +/// nginx source code. +fn parse_includes_from_makefile(nginx_autoconf_makefile_path: &PathBuf) -> Vec { + fn extract_include_part(line: &str) -> &str { + line.strip_suffix('\\').map_or(line, |s| s.trim()) + } + /// Extracts the include path from a line of the autoconf generated makefile. + fn extract_after_i_flag(line: &str) -> Option<&str> { + let mut parts = line.split("-I "); + match parts.next() { + Some(_) => parts.next().map(extract_include_part), + None => None, + } + } + + let mut includes = vec![]; + let makefile_contents = match std::fs::read_to_string(nginx_autoconf_makefile_path) { + Ok(path) => path, + Err(e) => { + panic!( + "Unable to read makefile from path [{}]. Error: {}", + nginx_autoconf_makefile_path.to_string_lossy(), + e + ); + } + }; + + let mut includes_lines = false; + for line in makefile_contents.lines() { + if !includes_lines { + if let Some(stripped) = line.strip_prefix("ALL_INCS") { + includes_lines = true; + if let Some(part) = extract_after_i_flag(stripped) { + includes.push(part); + } + continue; + } + } + + if includes_lines { + if let Some(part) = extract_after_i_flag(line) { + includes.push(part); + } else { + break; + } + } + } + + let makefile_dir = nginx_autoconf_makefile_path + .parent() + .expect("makefile path has no parent") + .parent() + .expect("objs dir has no parent") + .to_path_buf() + .canonicalize() + .expect("Unable to canonicalize makefile path"); + + includes + .into_iter() + .map(PathBuf::from) + .map(|path| { + if path.is_absolute() { + path + } else { + makefile_dir.join(path) + } + }) + .collect() +} diff --git a/nginx-sys/src/lib.rs b/nginx-sys/src/lib.rs new file mode 100644 index 0000000..cf11f1a --- /dev/null +++ b/nginx-sys/src/lib.rs @@ -0,0 +1,97 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(dead_code)] +#![allow(clippy::all)] +#![allow(improper_ctypes)] + +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); + +use std::fmt; +use std::ptr::copy_nonoverlapping; +use std::slice; + +pub fn str_to_uchar(pool: *mut ngx_pool_t, data: &str) -> *mut u_char { + let ptr: *mut u_char = unsafe { ngx_palloc(pool, data.len() as _) as _ }; + unsafe { + copy_nonoverlapping(data.as_ptr(), ptr, data.len()); + } + ptr +} + +impl ngx_str_t { + // convert nginx string to str slice + pub fn to_str(&self) -> &str { + unsafe { + let slice = slice::from_raw_parts(self.data, self.len as usize); + return std::str::from_utf8(slice).unwrap(); + } + } + + // get string + pub fn to_string(&self) -> String { + return String::from(self.to_str()); + } + + /// create from string + pub fn from_string(pool: *mut ngx_pool_t, data: String) -> Self { + ngx_str_t { + data: str_to_uchar(pool, data.as_str()), + len: data.len() as _, + } + } + + /// create from string + pub fn from_str(pool: *mut ngx_pool_t, data: &str) -> Self { + ngx_str_t { + data: str_to_uchar(pool, data), + len: data.len() as _, + } + } +} + +impl From for &[u8] { + fn from(s: ngx_str_t) -> Self { + if s.len == 0 || s.data.is_null() { + return Default::default(); + } + unsafe { slice::from_raw_parts(s.data, s.len as usize) } + } +} + +impl TryFrom for String { + type Error = std::string::FromUtf8Error; + + fn try_from(s: ngx_str_t) -> Result { + let bytes: &[u8] = s.into(); + String::from_utf8(bytes.into()) + } +} + +impl fmt::Display for ngx_str_t { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", String::from_utf8_lossy((*self).into())) + } +} + +impl TryFrom for &str { + type Error = std::str::Utf8Error; + + fn try_from(s: ngx_str_t) -> Result { + std::str::from_utf8(s.into()) + } +} + +pub fn add_to_ngx_table(table: *mut ngx_table_elt_t, pool: *mut ngx_pool_t, key: &str, value: &str) -> Option<()> { + if table.is_null() { + return None; + } + unsafe { table.as_mut() }.map(|table| { + table.hash = 1; + table.key.len = key.len() as _; + table.key.data = str_to_uchar(pool, key); + table.value.len = value.len() as _; + table.value.data = str_to_uchar(pool, value); + table.lowcase_key = str_to_uchar(pool, String::from(key).to_ascii_lowercase().as_str()); + }) +} diff --git a/nginx-sys/wrapper.h b/nginx-sys/wrapper.h new file mode 100644 index 0000000..c53f3c9 --- /dev/null +++ b/nginx-sys/wrapper.h @@ -0,0 +1,11 @@ +#include +#include +#include +#include + +// Define as constants since bindgen can't parse these values +const size_t NGX_RS_HTTP_MAIN_CONF_OFFSET = NGX_HTTP_MAIN_CONF_OFFSET; +const size_t NGX_RS_HTTP_SRV_CONF_OFFSET = NGX_HTTP_SRV_CONF_OFFSET; +const size_t NGX_RS_HTTP_LOC_CONF_OFFSET = NGX_HTTP_LOC_CONF_OFFSET; + +const char *NGX_RS_MODULE_SIGNATURE = NGX_MODULE_SIGNATURE; diff --git a/nginx.mk b/nginx.mk deleted file mode 100644 index f8f5d32..0000000 --- a/nginx.mk +++ /dev/null @@ -1,70 +0,0 @@ -NGINX_VER = 1.13.7 -UNAME_S := $(shell uname -s) -NGX_MODULES = --with-compat --with-threads --with-http_addition_module \ - --with-http_auth_request_module --with-http_gunzip_module --with-http_gzip_static_module \ - --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module \ - --with-http_slice_module --with-http_stub_status_module --with-http_sub_module \ - --with-stream --with-stream_realip_module --with-stream_ssl_preread_module - -ifeq ($(UNAME_S),Linux) - NGINX_SRC = nginx-linux - NGX_OPT= $(NGX_MODULES) \ - --with-file-aio --with-http_ssl_module --with-stream_ssl_module \ - --with-cc-opt='-g -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' \ - --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie' -endif -ifeq ($(UNAME_S),Darwin) - NGINX_SRC = nginx-darwin - NGX_OPT= $(NGX_MODULES) -endif -NGX_DEBUG="--with-debug" -RUST_COMPILER_TAG = 1.21.0 -RUST_TOOL = nginmesh/ngx-rust-tool:${RUST_COMPILER_TAG} -export ROOT_DIR=$(shell dirname $$PWD) -DOCKER_TOOL=docker run -it -v ${ROOT_DIR}:/src -w /src/${MODULE_PROJ_NAME} ${RUST_TOOL} - - -nginx-build: - cd nginx/${NGINX_SRC}; \ - ./configure --prefix=${PWD}/nginx/install $(NGX_OPT); \ - make; \ - make install - - -setup-nginx: - mkdir -p nginx - -nginx-source: setup-nginx - rm -rf nginx/${NGINX_SRC} - wget http://nginx.org/download/nginx-${NGINX_VER}.tar.gz - tar zxf nginx-${NGINX_VER}.tar.gz - mv nginx-${NGINX_VER} ${NGINX_SRC} - mv ${NGINX_SRC} nginx - rm nginx-${NGINX_VER}.tar.gz* - -nginx-configure: - cd nginx/${NGINX_SRC}; \ - ./configure $(NGX_OPT) - - -nginx-setup: nginx-source nginx-configure - -nginx-test: nginx-source nginx-build - - -nginx-module: - cd nginx/${NGINX_SRC}; \ - make modules; - -# need to run inside container -linux-shell: - ${DOCKER_TOOL} /bin/bash - - - -linux-setup: - ${DOCKER_TOOL} make nginx-setup - -linux-module: - ${DOCKER_TOOL} make nginx-module - diff --git a/ngx-binding/.gitignore b/ngx-binding/.gitignore deleted file mode 100644 index da70e20..0000000 --- a/ngx-binding/.gitignore +++ /dev/null @@ -1 +0,0 @@ -nginx \ No newline at end of file diff --git a/ngx-binding/Cargo.lock b/ngx-binding/Cargo.lock deleted file mode 100644 index 2c5358a..0000000 --- a/ngx-binding/Cargo.lock +++ /dev/null @@ -1,756 +0,0 @@ -[root] -name = "ngx-rust" -version = "0.1.2" -dependencies = [ - "bindgen 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aho-corasick" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ansi_term" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "aster" -version = "0.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "atty" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "base64" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bindgen" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cexpr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "clang-sys 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "which 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bitflags" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bitflags" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bitflags" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "byteorder" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bytes" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cexpr" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nom 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cfg-if" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "clang-sys" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", - "libloading 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "clap" -version = "2.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "conv" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "custom_derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "env_logger" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "futures" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "futures-cpupool" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "glob" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "httparse" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "hyper" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-cpupool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "iovec" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "language-tags" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "lazy_static" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "lazycell" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.30" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libloading" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "log" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "magenta" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "magenta-sys" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "memchr" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mime" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicase 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mio" -version = "0.6.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazycell 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miow" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "net2" -version = "0.2.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "nom" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num_cpus" -version = "1.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "percent-encoding" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quasi" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "quasi_codegen" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", - "magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "redox_syscall" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "regex" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex-syntax" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rustc-serialize" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rustc_version" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "safemem" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "scoped-tls" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "semver" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "slab" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "smallvec" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "strsim" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "syntex" -version = "0.58.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syntex_errors" -version = "0.58.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syntex_pos" -version = "0.58.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syntex_syntax" -version = "0.58.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "take" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "term" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "term_size" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "textwrap" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "thread_local" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "time" -version = "0.1.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-core" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-io" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-proto" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-service" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicase" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-segmentation" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-width" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-xid" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unreachable" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "utf8-ranges" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "vec_map" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "which" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[metadata] -"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" -"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" -"checksum aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfdf7355d9db158df68f976ed030ab0f6578af811f5a7bb6dcf221ec24e0e0" -"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159" -"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" -"checksum bindgen 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "33024f55a754d920637461adf87fb485702a69bdf7ac1d307b7e18da93bae505" -"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4" -"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" -"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" -"checksum bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d828f97b58cc5de3e40c421d0cf2132d6b2da4ee0e11b8632fa838f0f9333ad6" -"checksum cexpr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cdbb21df6ff3497a61df5059994297f746267020ba38ce237aad9c875f7b4313" -"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" -"checksum clang-sys 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "611ec2e3a7623afd8a8c0d027887b6b55759d894abbf5fe11b9dc11b50d5b49a" -"checksum clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2267a8fdd4dce6956ba6649e130f62fb279026e5e84b92aa939ac8f85ce3f9f0" -"checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" -"checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" -"checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" -"checksum futures 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a82bdc62350ca9d7974c760e9665102fc9d740992a528c2254aa930e53b783c4" -"checksum futures-cpupool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a283c84501e92cade5ea673a2a7ca44f71f209ccdd302a3e0896f50083d2c5ff" -"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" -"checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07" -"checksum hyper 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "641abc3e3fcf0de41165595f801376e01106bca1fd876dda937730e477ca004c" -"checksum iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29d062ee61fccdf25be172e70f34c9f6efc597e1fb8f6526e8437b2046ab26be" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" -"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" -"checksum lazycell 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b585b7a6811fb03aa10e74b278a0f00f8dd9b45dc681f148bb29fa5cb61859b" -"checksum libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "2370ca07ec338939e356443dac2296f581453c35fe1e3a3ed06023c49435f915" -"checksum libloading 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6b699b2cb9154b7a5c7b8c40fd200bd077791b292556a44ddae07482192123c6" -"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" -"checksum magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf0336886480e671965f794bc9b6fce88503563013d1bfb7a502c81fe3ac527" -"checksum magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40d014c7011ac470ae28e2f76a02bfea4a8480f73e701353b49ad7a8d75f4699" -"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" -"checksum mime 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "153f98dde2b135dece079e5478ee400ae1bab13afa52d66590eacfc40e912435" -"checksum mio 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "dbd91d3bfbceb13897065e97b2ef177a09a438cb33612b2d371bf568819a9313" -"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09" -"checksum nom 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "06989cbd367e06f787a451f3bc67d8c3e0eaa10b461cc01152ffab24261a31b1" -"checksum num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aec53c34f2d0247c5ca5d32cca1478762f301740468ee9ee6dcb7a0dd7a0c584" -"checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" -"checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356" -"checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3" -"checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4" -"checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf" -"checksum redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509" -"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" -"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" -"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" -"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" -"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" -"checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" -"checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" -"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" -"checksum smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8cbcd6df1e117c2210e13ab5109635ad68a929fcbb8964dc965b76cb5ee013" -"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" -"checksum syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a8f5e3aaa79319573d19938ea38d068056b826db9883a5d47f86c1cecc688f0e" -"checksum syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "867cc5c2d7140ae7eaad2ae9e8bf39cb18a67ca651b7834f88d46ca98faadb9c" -"checksum syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13ad4762fe52abc9f4008e85c4fb1b1fe3aa91ccb99ff4826a439c7c598e1047" -"checksum syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6e0e4dbae163dd98989464c23dd503161b338790640e11537686f2ef0f25c791" -"checksum take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5" -"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" -"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209" -"checksum textwrap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f728584ea33b0ad19318e20557cb0a39097751dbb07171419673502f848c7af6" -"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" -"checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" -"checksum tokio-core 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e85d419699ec4b71bfe35bbc25bb8771e52eff0471a7f75c853ad06e200b4f86" -"checksum tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4ab83e7adb5677e42e405fa4ceff75659d93c4d7d7dd22f52fcec59ee9f02af" -"checksum tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fbb47ae81353c63c487030659494b295f6cb6576242f907f203473b191b0389" -"checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" -"checksum unicase 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e01da42520092d0cd2d6ac3ae69eb21a22ad43ff195676b86f8c37f487d6b80" -"checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946" -"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" -"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" -"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" -"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum which 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d238435618c0f298d2d75596c2d4fa7d4ea469c0c1c3ff824737ed50ad5ab61c" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" diff --git a/ngx-binding/Cargo.toml b/ngx-binding/Cargo.toml deleted file mode 100644 index a038c85..0000000 --- a/ngx-binding/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "ngx_rust" -version = "0.1.2" -authors = ["Sehyo Chang sehyo@nginx.com"] - -[lib] -doctest = false -test = true -crate-type = ["staticlib","rlib"] - - -[dev-dependencies] -futures = "0.1.14" -hyper = "0.11.2" -tokio-core = "0.1.9" - -[build-dependencies] -bindgen = "0.30.0" - - diff --git a/ngx-binding/Makefile b/ngx-binding/Makefile deleted file mode 100644 index b16fe55..0000000 --- a/ngx-binding/Makefile +++ /dev/null @@ -1,48 +0,0 @@ -NGINX_VER = 1.13.7 -UNAME_S := $(shell uname -s) -NGX_MODULES = --with-compat --with-threads --with-http_addition_module \ - --with-http_auth_request_module --with-http_gunzip_module --with-http_gzip_static_module \ - --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module \ - --with-http_slice_module --with-http_stub_status_module --with-http_sub_module \ - --with-stream --with-stream_realip_module --with-stream_ssl_preread_module - -ifeq ($(UNAME_S),Linux) - NGINX_SRC = nginx-linux - NGX_OPT= $(NGX_MODULES) \ - --with-file-aio --with-http_ssl_module --with-stream_ssl_module \ - --with-cc-opt='-g -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' \ - --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie' -endif -ifeq ($(UNAME_S),Darwin) - NGINX_SRC = nginx-darwin - NGX_OPT= $(NGX_MODULES) -endif - - -setup-nginx: - mkdir -p nginx - -nginx-source: setup-nginx - rm -rf nginx/${NGINX_SRC} - wget http://nginx.org/download/nginx-${NGINX_VER}.tar.gz - tar zxf nginx-${NGINX_VER}.tar.gz - mv nginx-${NGINX_VER} ${NGINX_SRC} - mv ${NGINX_SRC} nginx - rm nginx-${NGINX_VER}.tar.gz* - -nginx-configure: - cd nginx/${NGINX_SRC}; \ - ./configure $(NGX_OPT) - - -nginx-setup: nginx-source nginx-configure - - -nginx-module: - cd nginx/${NGINX_SRC}; \ - make modules; - - -clean: - rm -rf nginx - rm -f src/bindings.rs diff --git a/ngx-binding/build.rs b/ngx-binding/build.rs deleted file mode 100644 index db19f7f..0000000 --- a/ngx-binding/build.rs +++ /dev/null @@ -1,74 +0,0 @@ -extern crate bindgen; - -use std::process::Command; -use std::process::Output; -use std::env; -use std::io::Result; - -#[cfg(target_os = "macos")] -const NGIX_DIR: &str = "./nginx/nginx-darwin"; - -#[cfg(target_os = "linux")] -const NGIX_DIR: &str = "./nginx/nginx-linux"; - -// perform make with argument -fn make(arg: &str) -> Result { - let current_path = env::current_dir().unwrap(); - let path_name = format!("{}",current_path.display()); - println!("executing make command at {}",path_name); - let result = Command::new("/usr/bin/make") - .args(&[arg]) - .current_dir(path_name) - .output(); - - match result { - Err(e) => { - return Err(e); - }, - - Ok(output) => { - println!("status: {}", output.status); - println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); - println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); - return Ok(output); - } - } -} - - -fn configure() -> Result { - make("nginx-setup") -} - - - - -fn generate_binding() { - let bindings = bindgen::Builder::default() - // The input header we would like to generate - // bindings for. - .header("wrapper.h") - .layout_tests(false) - .clang_arg(format!("-I{}/src/core",NGIX_DIR)) - .clang_arg(format!("-I{}/src/event",NGIX_DIR)) - .clang_arg(format!("-I{}/src/event/modules",NGIX_DIR)) - .clang_arg(format!("-I{}/src/os/unix",NGIX_DIR)) - .clang_arg(format!("-I{}/objs",NGIX_DIR)) - .clang_arg(format!("-I{}/src/http",NGIX_DIR)) - .clang_arg(format!("-I{}/src/http/modules",NGIX_DIR)) - // Finish the builder and generate the bindings. - .generate() - // Unwrap the Result and panic on failure. - .expect("Unable to generate bindings"); - - bindings - .write_to_file("src/bindings.rs") - .expect("Couldn't write bindings!"); -} - -fn main() { - - configure(); - generate_binding(); - -} diff --git a/ngx-binding/src/.gitignore b/ngx-binding/src/.gitignore deleted file mode 100644 index b1dd71c..0000000 --- a/ngx-binding/src/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -bindings.rs -helloworld.rs -helloworld_grpc.rs -route_guide.rs -route_guide_grpc.rs -check.rs -attributes.rs -status.rs -service_grpc.rs -quota.rs -report.rs diff --git a/ngx-binding/src/lib.rs b/ngx-binding/src/lib.rs deleted file mode 100644 index b9e76f5..0000000 --- a/ngx-binding/src/lib.rs +++ /dev/null @@ -1,8 +0,0 @@ - - -pub mod bindings; -pub mod nginx_http; -pub mod nginx; - - -pub mod log; \ No newline at end of file diff --git a/ngx-binding/src/log.rs b/ngx-binding/src/log.rs deleted file mode 100644 index 9949ef7..0000000 --- a/ngx-binding/src/log.rs +++ /dev/null @@ -1,37 +0,0 @@ - -#[macro_export] -macro_rules! ngx_debug { - - ($level:expr,$log:expr,$($arg:tt)*) => { - if (*$log).log_level & $level as usize > 0{ - let c_message = ::std::ffi::CString::new(format!($($arg)*)).unwrap(); - $crate::bindings::ngx_log_error_core($crate::bindings::NGX_LOG_DEBUG as usize, $log, 0, c_message.as_ptr()); - } - } -} - -#[macro_export] -macro_rules! ngx_http_debug { - - ($request:expr,$($arg:tt)*) => { - unsafe { - ngx_debug!($crate::bindings::NGX_LOG_DEBUG_HTTP,(*($request).connection).log,$($arg)*); - } - } -} - - -#[macro_export] -macro_rules! ngx_event_debug { - - ($($arg:tt)*) => { - unsafe { - ngx_debug!($crate::bindings::NGX_LOG_DEBUG_EVENT,(*$crate::bindings::ngx_cycle).log,$($arg)*); - } - } -} - - - - - diff --git a/ngx-binding/src/nginx.rs b/ngx-binding/src/nginx.rs deleted file mode 100644 index c5015c5..0000000 --- a/ngx-binding/src/nginx.rs +++ /dev/null @@ -1,98 +0,0 @@ -/** - * harness to test nginx - */ - -use std::process::Command; -use std::process::Output; -use std::io::Result; -use std::env; -use std::fs; - -const NGINX_INSTALL_PATH: &str = "nginx/install"; -const NGINX_BIN: &str = "sbin/nginx"; -const NGINX_CONFIG: &str = "conf/nginx.conf"; - -pub struct Nginx { - - pub install_path: String // install path -} - - -impl Nginx { - - pub fn new(path: String) -> Nginx { - Nginx { install_path: path } - } - - // create nginx with default - pub fn default() -> Nginx { - let path = env::current_dir().unwrap(); - let install_path = format!("{}/{}",path.display(),NGINX_INSTALL_PATH); - Nginx { install_path: install_path } - } - - - // get bin path - pub fn bin_path(&mut self) -> String { - format!("{}/{}",self.install_path,NGINX_BIN) - } - - - pub fn cmd(&mut self, args: &[&str] ) -> Result { - let bin_path = self.bin_path(); - let result = Command::new(&bin_path) - .args(args) - .output(); - - match result { - Err(e) => { - return Err(e); - }, - - Ok(output) => { - println!("status: {}", output.status); - println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); - println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); - return Ok(output); - } - } - - } - - // complete stop the nginx binary - pub fn stop(&mut self) -> Result { - self.cmd(&["-s","stop"]) - } - - // start the nginx binary - pub fn start(&mut self) -> Result { - self.cmd(&[]) - } - - - // make sure we stop existing nginx and start new master process - // intentinally ignore failure in stop - pub fn restart(&mut self) -> Result { - - self.stop(); - self.start() - } - - - // replace config with another config - pub fn replace_config(&mut self, from: &str) -> Result { - let config_path = format!("{}/{}",self.install_path,NGINX_CONFIG); - println!("copying config from: {} to: {}",from,config_path); // replace with logging - fs::copy(from , config_path) - } - - -} - - - - - - - - diff --git a/ngx-binding/src/nginx_http.rs b/ngx-binding/src/nginx_http.rs deleted file mode 100644 index 2910648..0000000 --- a/ngx-binding/src/nginx_http.rs +++ /dev/null @@ -1,159 +0,0 @@ - -use std::str; -use std::slice; - -use bindings::ngx_http_request_s; -use bindings::ngx_http_headers_in_t; -use bindings::ngx_http_headers_out_t; -use bindings::ngx_list_part_t; -use bindings::ngx_table_elt_t; -use bindings::ngx_list_t; -use bindings::ngx_uint_t; -use bindings::ngx_str_t; -use bindings::ngx_log_t; -use bindings::ngx_log_error_core; -use bindings::NGX_LOG_ERR; -use bindings::ngx_cycle; - - -impl ngx_str_t { - // convert nginx string to str slice - pub fn to_str(&self) -> &str { - - unsafe { - let slice = slice::from_raw_parts(self.data,self.len) ; - return str::from_utf8(slice).unwrap(); - } - - } - - // get string - pub fn to_string(&self) -> String { - return String::from(self.to_str()); - } -} - -impl ngx_http_request_s { - - /* - pub fn scheme(&self) -> char { - unsafe { (*self.schema_start)}; - } - */ - -} - -impl ngx_http_headers_in_t { - - // host - pub fn host_str(&self) -> &str { - unsafe { (*self.host).value.to_str() } - } - - pub fn user_agent_str(&self) -> &str { - unsafe { (*self.user_agent).value.to_str() } - } - - // referrer - pub fn referer_str(&self) -> Option<&str> { - - let referer = self.referer; - - if referer.is_null() { - return None; - } - - return Some(unsafe { (*referer).value.to_str() }); - } - - pub fn headers_iterator(&self) -> NgxListIterator { - list_iterator( &self.headers ) - } - -} - -impl ngx_http_headers_out_t { - - pub fn content_length_str(&self) -> &str { - unsafe { (*self.content_length).value.to_str() } - } - - pub fn server_str(&self) -> &str { - unsafe { (*self.server).value.to_str() } - } - - pub fn headers_iterator(&self) -> NgxListIterator { - list_iterator( &self.headers ) - } - -} - - -pub struct NgxListIterator { - - done: bool , - part: *const ngx_list_part_t, - h: *const ngx_table_elt_t, - i: ngx_uint_t -} - - -// create new http request iterator -pub fn list_iterator(list: *const ngx_list_t) -> NgxListIterator { - - unsafe { - let part: *const ngx_list_part_t = &(*list).part ; - - NgxListIterator { - done: false, - part: part, - h: (*part).elts as *const ngx_table_elt_t, - i: 0 - } - } - -} - -// iterator for ngx_list_t - -impl Iterator for NgxListIterator { - - // type Item = (&str,&str); - // TODO: try to use str instead of string - - type Item = (String,String); - - fn next(&mut self) -> Option { - - unsafe { - if self.done { - return None; - } else { - if self.i >= (*self.part).nelts { - if (*self.part).next.is_null() { - self.done = true; - return None - } - - // loop back - self.part = (*self.part).next; - self.h = (*self.part).elts as *mut ngx_table_elt_t; - self.i = 0; - } - - let header: *const ngx_table_elt_t = self.h.offset(self.i as isize); - - let header_name: ngx_str_t = (*header).key; - - let header_value: ngx_str_t = (*header).value; - - self.i = self.i + 1; - - return Some( (header_name.to_string(),header_value.to_string()) ) ; - - } - } - - } - -} diff --git a/ngx-binding/wrapper.h b/ngx-binding/wrapper.h deleted file mode 100644 index 3cfb3dd..0000000 --- a/ngx-binding/wrapper.h +++ /dev/null @@ -1 +0,0 @@ -#include \ No newline at end of file diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..866c756 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +max_width = 120 \ No newline at end of file diff --git a/src/core/buffer.rs b/src/core/buffer.rs new file mode 100644 index 0000000..4ea72cb --- /dev/null +++ b/src/core/buffer.rs @@ -0,0 +1,93 @@ +use crate::ffi::*; + +use std::slice; + +pub trait Buffer { + fn as_ngx_buf(&self) -> *const ngx_buf_t; + + fn as_ngx_buf_mut(&mut self) -> *mut ngx_buf_t; + + fn as_bytes(&self) -> &[u8] { + let buf = self.as_ngx_buf(); + unsafe { slice::from_raw_parts((*buf).pos, self.len()) } + } + + fn len(&self) -> usize { + let buf = self.as_ngx_buf(); + unsafe { + let pos = (*buf).pos; + let last = (*buf).last; + assert!(last >= pos); + usize::wrapping_sub(last as _, pos as _) + } + } + + fn is_empty(&self) -> bool { + self.len() == 0 + } + + fn set_last_buf(&mut self, last: bool) { + let buf = self.as_ngx_buf_mut(); + unsafe { + (*buf).set_last_buf(if last { 1 } else { 0 }); + } + } + + fn set_last_in_chain(&mut self, last: bool) { + let buf = self.as_ngx_buf_mut(); + unsafe { + (*buf).set_last_in_chain(if last { 1 } else { 0 }); + } + } +} + +pub trait MutableBuffer: Buffer { + fn as_bytes_mut(&mut self) -> &mut [u8] { + let buf = self.as_ngx_buf_mut(); + unsafe { slice::from_raw_parts_mut((*buf).pos, self.len()) } + } +} + +pub struct TemporaryBuffer(*mut ngx_buf_t); + +impl TemporaryBuffer { + pub fn from_ngx_buf(buf: *mut ngx_buf_t) -> TemporaryBuffer { + assert!(!buf.is_null()); + TemporaryBuffer(buf) + } +} + +impl Buffer for TemporaryBuffer { + fn as_ngx_buf(&self) -> *const ngx_buf_t { + self.0 + } + + fn as_ngx_buf_mut(&mut self) -> *mut ngx_buf_t { + self.0 + } +} + +impl MutableBuffer for TemporaryBuffer { + fn as_bytes_mut(&mut self) -> &mut [u8] { + unsafe { slice::from_raw_parts_mut((*self.0).pos, self.len()) } + } +} + +pub struct MemoryBuffer(*mut ngx_buf_t); + +impl MemoryBuffer { + pub fn from_ngx_buf(buf: *mut ngx_buf_t) -> MemoryBuffer { + assert!(!buf.is_null()); + MemoryBuffer(buf) + } +} + +impl Buffer for MemoryBuffer { + fn as_ngx_buf(&self) -> *const ngx_buf_t { + self.0 + } + + fn as_ngx_buf_mut(&mut self) -> *mut ngx_buf_t { + self.0 + } +} diff --git a/src/core/mod.rs b/src/core/mod.rs new file mode 100644 index 0000000..271e23d --- /dev/null +++ b/src/core/mod.rs @@ -0,0 +1,66 @@ +mod buffer; +mod pool; +mod status; +mod string; + +pub use buffer::*; +pub use pool::*; +pub use status::*; +pub use string::*; + +/// Static empty configuration directive initializer for [`ngx_command_t`]. +/// +/// This is typically used to terminate an array of configuration directives. +/// +/// [`ngx_command_t`]: https://nginx.org/en/docs/dev/development_guide.html#config_directives +#[macro_export] +macro_rules! ngx_null_command { + () => { + ngx_command_t { + name: $crate::ngx_null_string!(), + type_: 0, + set: None, + conf: 0, + offset: 0, + post: ::std::ptr::null_mut(), + } + }; +} + +/// Static empty configuration variable initializer for [`ngx_http_variable_t`]. +/// +/// This is typically used to terminate an array of HTTP variable types. +/// +/// [`ngx_http_variable_t`]: https://nginx.org/en/docs/dev/development_guide.html#http_variables +#[macro_export] +macro_rules! ngx_http_null_variable { + () => { + ngx_http_variable_t { + name: $crate::ngx_null_string!(), + set_handler: None, + get_handler: None, + data: 0, + flags: 0, + index: 0, + } + }; +} + +/// Static empty configuration variable initializer for [`ngx_stream_variable_t`]. +/// +/// This is typically used to terminate an array of Stream variable types. +/// +/// [`ngx_stream_variable_t`]: TODO: find appropriate link +#[macro_export] +macro_rules! ngx_stream_null_variable { + () => { + ngx_stream_variable_t { + name: $crate::ngx_null_string!(), + set_handler: None, + get_handler: None, + data: 0, + flags: 0, + index: 0, + } + }; +} diff --git a/src/core/pool.rs b/src/core/pool.rs new file mode 100644 index 0000000..21f9aa9 --- /dev/null +++ b/src/core/pool.rs @@ -0,0 +1,101 @@ +use crate::core::buffer::{Buffer, MemoryBuffer, TemporaryBuffer}; +use crate::ffi::*; + +use std::os::raw::c_void; +use std::{mem, ptr}; + +pub struct Pool(*mut ngx_pool_t); + +impl Pool { + /// # Safety + /// + /// The caller has provided a valid `ngx_pool_t` that points to valid memory and is non-null. + /// A null argument will assert and panic. + pub unsafe fn from_ngx_pool(pool: *mut ngx_pool_t) -> Pool { + assert!(!pool.is_null()); + Pool(pool) + } + + pub fn create_buffer(&mut self, size: usize) -> Option { + let buf = unsafe { ngx_create_temp_buf(self.0, size) }; + if buf.is_null() { + return None; + } + + Some(TemporaryBuffer::from_ngx_buf(buf)) + } + + pub fn create_buffer_from_str(&mut self, str: &str) -> Option { + let mut buffer = self.create_buffer(str.len())?; + unsafe { + let mut buf = buffer.as_ngx_buf_mut(); + ptr::copy_nonoverlapping(str.as_ptr(), (*buf).pos, str.len()); + (*buf).last = (*buf).pos.add(str.len()); + } + Some(buffer) + } + + pub fn create_buffer_from_static_str(&mut self, str: &'static str) -> Option { + let buf = self.calloc_type::(); + if buf.is_null() { + return None; + } + + // We cast away const, but buffers with the memory flag are read-only + let start = str.as_ptr() as *mut u8; + let end = unsafe { start.add(str.len()) }; + + unsafe { + (*buf).start = start; + (*buf).pos = start; + (*buf).last = end; + (*buf).end = end; + (*buf).set_memory(1); + } + + Some(MemoryBuffer::from_ngx_buf(buf)) + } + + unsafe fn add_cleanup_for_value(&mut self, value: *mut T) -> Result<(), ()> { + let cln = ngx_pool_cleanup_add(self.0, 0); + if cln.is_null() { + return Err(()); + } + (*cln).handler = Some(cleanup_type::); + (*cln).data = value as *mut c_void; + + Ok(()) + } + + pub fn alloc(&mut self, size: usize) -> *mut c_void { + unsafe { ngx_palloc(self.0, size) } + } + + pub fn alloc_type(&mut self) -> *mut T { + self.alloc(mem::size_of::()) as *mut T + } + + pub fn calloc(&mut self, size: usize) -> *mut c_void { + unsafe { ngx_pcalloc(self.0, size) } + } + + pub fn calloc_type(&mut self) -> *mut T { + self.calloc(mem::size_of::()) as *mut T + } + + pub fn allocate(&mut self, value: T) -> *mut T { + unsafe { + let p = self.alloc(mem::size_of::()) as *mut T; + ptr::write(p, value); + if self.add_cleanup_for_value(p).is_err() { + ptr::drop_in_place(p); + return ptr::null_mut(); + }; + p + } + } +} + +unsafe extern "C" fn cleanup_type(data: *mut c_void) { + ptr::drop_in_place(data as *mut T); +} diff --git a/src/core/status.rs b/src/core/status.rs new file mode 100644 index 0000000..3b614d2 --- /dev/null +++ b/src/core/status.rs @@ -0,0 +1,52 @@ +use crate::ffi::*; +use std::fmt; + +#[derive(Ord, PartialOrd, Eq, PartialEq)] +pub struct Status(pub ngx_int_t); + +impl Status { + pub fn is_ok(&self) -> bool { + self == &Status::NGX_OK + } +} + +impl fmt::Debug for Status { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } +} + +impl From for ngx_int_t { + fn from(val: Status) -> Self { + val.0 + } +} + +macro_rules! ngx_codes { + ( + $( + $(#[$docs:meta])* + ($konst:ident); + )+ + ) => { + impl Status { + $( + $(#[$docs])* + pub const $konst: Status = Status($konst as ngx_int_t); + )+ + + } + } +} + +ngx_codes! { + (NGX_OK); + (NGX_ERROR); + (NGX_AGAIN); + (NGX_BUSY); + (NGX_DONE); + (NGX_DECLINED); + (NGX_ABORT); +} +pub const NGX_CONF_ERROR: *const () = -1isize as *const (); +// pub const CONF_OK: Status = Status(NGX_CONF_OK as ngx_int_t); diff --git a/src/core/string.rs b/src/core/string.rs new file mode 100644 index 0000000..55ee5a7 --- /dev/null +++ b/src/core/string.rs @@ -0,0 +1,101 @@ +use crate::ffi::*; + +use std::borrow::Cow; +use std::slice; +use std::str::{self, Utf8Error}; + +/// Static string initializer for [`ngx_str_t`]. +/// +/// The resulting byte string is always nul-terminated (just like a C string). +/// +/// [`ngx_str_t`]: https://nginx.org/en/docs/dev/development_guide.html#string_overview +#[macro_export] +macro_rules! ngx_string { + ($s:expr) => {{ + $crate::ffi::ngx_str_t { + len: $s.len() as _, + data: concat!($s, "\0").as_ptr() as *mut u8, + } + }}; +} + +/// Static empty string initializer for [`ngx_str_t`]. +/// +/// [`ngx_str_t`]: https://nginx.org/en/docs/dev/development_guide.html#string_overview +#[macro_export] +macro_rules! ngx_null_string { + () => { + $crate::ffi::ngx_str_t { + len: 0, + data: ::std::ptr::null_mut(), + } + }; +} + +/// Representation of a borrowed [Nginx string]. +/// +/// [Nginx string]: https://nginx.org/en/docs/dev/development_guide.html#string_overview +pub struct NgxStr([u_char]); + +impl NgxStr { + /// Create an [`NgxStr`] from an [`ngx_str_t`]. + /// + /// [`ngx_str_t`]: https://nginx.org/en/docs/dev/development_guide.html#string_overview + /// + /// # Safety + /// + /// The caller has provided a valid `ngx_str_t` with a `data` pointer that points + /// to range of bytes of at least `len` bytes, whose content remains valid and doesn't + /// change for the lifetime of the returned `NgxStr`. + pub unsafe fn from_ngx_str<'a>(str: ngx_str_t) -> &'a NgxStr { + slice::from_raw_parts(str.data, str.len).into() + } + + /// Access the [`NgxStr`] as a byte slice. + pub fn as_bytes(&self) -> &[u8] { + &self.0 + } + + /// Yields a `&str` slice if the [`NgxStr`] contains valid UTF-8. + pub fn to_str(&self) -> Result<&str, Utf8Error> { + str::from_utf8(self.as_bytes()) + } + + /// Converts an [`NgxStr`] into a [`Cow`], replacing invalid UTF-8 sequences. + /// + /// See [`String::from_utf8_lossy`]. + pub fn to_string_lossy(&self) -> Cow { + String::from_utf8_lossy(self.as_bytes()) + } + + /// Returns `true` if the [`NgxStr`] is empty, otherwise `false`. + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + +impl From<&[u8]> for &NgxStr { + fn from(bytes: &[u8]) -> Self { + // SAFETY: An `NgxStr` is identical to a `[u8]` slice, given `u_char` is an alias for `u8`. + unsafe { &*(bytes as *const [u8] as *const NgxStr) } + } +} + +impl From<&str> for &NgxStr { + fn from(s: &str) -> Self { + s.as_bytes().into() + } +} + +impl AsRef<[u8]> for NgxStr { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl Default for &NgxStr { + fn default() -> Self { + // SAFETY: The null `ngx_str_t` is always a valid Nginx string. + unsafe { NgxStr::from_ngx_str(ngx_null_string!()) } + } +} diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs new file mode 100644 index 0000000..887a73e --- /dev/null +++ b/src/ffi/mod.rs @@ -0,0 +1 @@ +pub use nginx_sys::*; diff --git a/src/http/conf.rs b/src/http/conf.rs new file mode 100644 index 0000000..4761bb0 --- /dev/null +++ b/src/http/conf.rs @@ -0,0 +1,33 @@ +use crate::ffi::*; + +use std::os::raw::c_void; + +/// # Safety +/// +/// The caller has provided a valid `ngx_conf_t` that points to valid memory and is non-null. +pub unsafe fn ngx_http_conf_get_module_main_conf( + cf: *mut ngx_conf_t, + module: &ngx_module_t, +) -> *mut ngx_http_core_main_conf_t { + let http_conf_ctx = (*cf).ctx as *mut ngx_http_conf_ctx_t; + *(*http_conf_ctx).main_conf.add(module.ctx_index) as *mut ngx_http_core_main_conf_t +} + +/// # Safety +/// +/// The caller has provided a valid `ngx_conf_t` that points to valid memory and is non-null. +pub unsafe fn ngx_http_conf_get_module_srv_conf(cf: *mut ngx_conf_t, module: &ngx_module_t) -> *mut c_void { + let http_conf_ctx = (*cf).ctx as *mut ngx_http_conf_ctx_t; + *(*http_conf_ctx).srv_conf.add(module.ctx_index) +} + +/// # Safety +/// +/// The caller has provided a valid `ngx_conf_t` that points to valid memory and is non-null. +pub unsafe fn ngx_http_conf_get_module_loc_conf( + cf: *mut ngx_conf_t, + module: &ngx_module_t, +) -> *mut ngx_http_core_loc_conf_t { + let http_conf_ctx = (*cf).ctx as *mut ngx_http_conf_ctx_t; + *(*http_conf_ctx).loc_conf.add(module.ctx_index) as *mut ngx_http_core_loc_conf_t +} diff --git a/src/http/mod.rs b/src/http/mod.rs new file mode 100644 index 0000000..230ce0b --- /dev/null +++ b/src/http/mod.rs @@ -0,0 +1,9 @@ +mod conf; +mod module; +mod request; +mod status; + +pub use conf::*; +pub use module::*; +pub use request::*; +pub use status::*; diff --git a/src/http/module.rs b/src/http/module.rs new file mode 100644 index 0000000..62167dd --- /dev/null +++ b/src/http/module.rs @@ -0,0 +1,115 @@ +use crate::core::NGX_CONF_ERROR; +use crate::core::*; +use crate::ffi::*; + +use core::ptr; +use std::os::raw::{c_char, c_void}; + +#[derive(Debug)] +pub enum MergeConfigError { + /// No value provided for configuration argument + NoValue, +} + +impl std::error::Error for MergeConfigError {} + +impl std::fmt::Display for MergeConfigError { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + MergeConfigError::NoValue => "no value".fmt(fmt), + } + } +} + +pub trait Merge { + fn merge(&mut self, prev: &Self) -> Result<(), MergeConfigError>; +} + +impl Merge for () { + fn merge(&mut self, _prev: &Self) -> Result<(), MergeConfigError> { + Ok(()) + } +} + +pub trait HTTPModule { + type MainConf: Merge + Default; + type SrvConf: Merge + Default; + type LocConf: Merge + Default; + + /// # Safety + /// + /// Callers should provide valid non-null `ngx_conf_t` arguments. Implementers must + /// guard against null inputs or risk runtime errors. + unsafe extern "C" fn preconfiguration(_cf: *mut ngx_conf_t) -> ngx_int_t { + Status::NGX_OK.into() + } + + /// # Safety + /// + /// Callers should provide valid non-null `ngx_conf_t` arguments. Implementers must + /// guard against null inputs or risk runtime errors. + unsafe extern "C" fn postconfiguration(_cf: *mut ngx_conf_t) -> ngx_int_t { + Status::NGX_OK.into() + } + + /// # Safety + /// + /// Callers should provide valid non-null `ngx_conf_t` arguments. Implementers must + /// guard against null inputs or risk runtime errors. + unsafe extern "C" fn create_main_conf(cf: *mut ngx_conf_t) -> *mut c_void { + let mut pool = Pool::from_ngx_pool((*cf).pool); + pool.allocate::(Default::default()) as *mut c_void + } + + /// # Safety + /// + /// Callers should provide valid non-null `ngx_conf_t` arguments. Implementers must + /// guard against null inputs or risk runtime errors. + unsafe extern "C" fn init_main_conf(_cf: *mut ngx_conf_t, _conf: *mut c_void) -> *mut c_char { + ptr::null_mut() + } + + /// # Safety + /// + /// Callers should provide valid non-null `ngx_conf_t` arguments. Implementers must + /// guard against null inputs or risk runtime errors. + unsafe extern "C" fn create_srv_conf(cf: *mut ngx_conf_t) -> *mut c_void { + let mut pool = Pool::from_ngx_pool((*cf).pool); + pool.allocate::(Default::default()) as *mut c_void + } + + /// # Safety + /// + /// Callers should provide valid non-null `ngx_conf_t` arguments. Implementers must + /// guard against null inputs or risk runtime errors. + unsafe extern "C" fn merge_srv_conf(_cf: *mut ngx_conf_t, prev: *mut c_void, conf: *mut c_void) -> *mut c_char { + let prev = &mut *(prev as *mut Self::SrvConf); + let conf = &mut *(conf as *mut Self::SrvConf); + match conf.merge(prev) { + Ok(_) => ptr::null_mut(), + Err(_) => NGX_CONF_ERROR as _, + } + } + + /// # Safety + /// + /// Callers should provide valid non-null `ngx_conf_t` arguments. Implementers must + /// guard against null inputs or risk runtime errors. + unsafe extern "C" fn create_loc_conf(cf: *mut ngx_conf_t) -> *mut c_void { + let mut pool = Pool::from_ngx_pool((*cf).pool); + pool.allocate::(Default::default()) as *mut c_void + } + + /// # Safety + /// + /// Callers should provide valid non-null `ngx_conf_t` arguments. Implementers must + /// guard against null inputs or risk runtime errors. + unsafe extern "C" fn merge_loc_conf(_cf: *mut ngx_conf_t, prev: *mut c_void, conf: *mut c_void) -> *mut c_char { + let prev = &mut *(prev as *mut Self::LocConf); + let conf = &mut *(conf as *mut Self::LocConf); + match conf.merge(prev) { + Ok(_) => ptr::null_mut(), + Err(_) => NGX_CONF_ERROR as _, + } + } +} diff --git a/src/http/request.rs b/src/http/request.rs new file mode 100644 index 0000000..b07bba2 --- /dev/null +++ b/src/http/request.rs @@ -0,0 +1,646 @@ +use crate::core::*; +use crate::ffi::*; +use crate::http::status::*; +use crate::ngx_null_string; +use std::fmt; +use std::os::raw::c_void; + +use std::error::Error; +use std::str::FromStr; + +/// Define a static request handler. +/// +/// Handlers are expected to take a single [`Request`] argument and return a [`Status`]. +#[macro_export] +macro_rules! http_request_handler { + ( $name: ident, $handler: expr ) => { + #[no_mangle] + extern "C" fn $name(r: *mut ngx_http_request_t) -> ngx_int_t { + let status: Status = $handler(unsafe { &mut $crate::http::Request::from_ngx_http_request(r) }); + status.0 + } + }; +} + +/// Define a static post subrequest handler. +/// +/// Handlers are expected to take a single [`Request`] argument and return a [`Status`]. +#[macro_export] +macro_rules! http_subrequest_handler { + ( $name: ident, $handler: expr ) => { + #[no_mangle] + unsafe extern "C" fn $name(r: *mut ngx_http_request_t, data: *mut c_void, rc: ngx_int_t) -> ngx_int_t { + $handler(r, data, rc) + } + }; +} + +/// Define a static variable setter. +/// +/// The set handler allows setting the property referenced by the variable. +/// The set handler expects a [`Request`], [`mut ngx_variable_valut_t`], and a [`usize`]. +/// Variables: https://nginx.org/en/docs/dev/development_guide.html#http_variables +#[macro_export] +macro_rules! http_variable_set { + ( $name: ident, $handler: expr ) => { + #[no_mangle] + unsafe extern "C" fn $name(r: *mut ngx_http_request_t, v: *mut ngx_variable_value_t, data: usize) { + $handler( + unsafe { &mut $crate::http::Request::from_ngx_http_request(r) }, + v, + data, + ); + } + }; +} + +/// Define a static variable evaluator. +/// +/// The get handler is responsible for evaluating a variable in the context of a specific request. +/// Variable evaluators accept a [`Request`] input argument and two output +/// arguments: [`ngx_http_variable_valut_t`] and [`usize`]. +/// Variables: https://nginx.org/en/docs/dev/development_guide.html#http_variables +#[macro_export] +macro_rules! http_variable_get { + ( $name: ident, $handler: expr ) => { + #[no_mangle] + unsafe extern "C" fn $name(r: *mut ngx_http_request_t, v: *mut ngx_variable_value_t, data: usize) -> ngx_int_t { + let status: Status = $handler( + unsafe { &mut $crate::http::Request::from_ngx_http_request(r) }, + v, + data, + ); + status.0 + } + }; +} + +#[repr(transparent)] +pub struct Request(ngx_http_request_t); + +impl Request { + /// Create a [`Request`] from an [`ngx_http_request_t`]. + /// + /// [`ngx_http_request_t`]: https://nginx.org/en/docs/dev/development_guide.html#http_request + /// + /// # Safety + /// + /// The caller has provided a valid non-null pointer to a valid `ngx_http_request_t` + /// which shares the same representation as `Request`. + pub unsafe fn from_ngx_http_request<'a>(r: *mut ngx_http_request_t) -> &'a mut Request { + &mut *r.cast::() + } + + /// Is this the main request (as opposed to a subrequest)? + pub fn is_main(&self) -> bool { + let main = self.0.main.cast(); + std::ptr::eq(self, main) + } + + /// Request pool. + pub fn pool(&self) -> Pool { + // SAFETY: This request is allocated from `pool`, thus must be a valid pool. + unsafe { Pool::from_ngx_pool(self.0.pool) } + } + + /// Pointer to a [`ngx_connection_t`] client connection object. + /// + /// [`ngx_connection_t`]: https://nginx.org/en/docs/dev/development_guide.html#connection + pub fn connection(&self) -> *mut ngx_connection_t { + self.0.connection + } + + pub fn log(&self) -> *mut ngx_log_t { + unsafe { (*self.connection()).log } + } + + /// Module location configuration. + fn get_module_loc_conf_ptr(&self, module: &ngx_module_t) -> *mut c_void { + unsafe { *self.0.loc_conf.add(module.ctx_index) } + } + + /// Module location configuration. + pub fn get_module_loc_conf(&self, module: &ngx_module_t) -> Option<&T> { + let lc_prt = self.get_module_loc_conf_ptr(module) as *mut T; + if lc_prt.is_null() { + return None; + } + let lc = unsafe { &*lc_prt }; + Some(lc) + } + + /// Get Module context pointer + fn get_module_ctx_ptr(&self, module: &ngx_module_t) -> *mut c_void { + unsafe { *self.0.ctx.add(module.ctx_index) } + } + + /// Get Module context + pub fn get_module_ctx(&self, module: &ngx_module_t) -> Option<&T> { + let cf = self.get_module_ctx_ptr(module) as *mut T; + + if cf.is_null() { + return None; + } + let co = unsafe { &*cf }; + Some(co) + } + + pub fn set_module_ctx(&self, value: *mut c_void, module: &ngx_module_t) { + unsafe { + *self.0.ctx.add(module.ctx_index) = value; + }; + } + + /// Get the value of a [complex value]. + /// + /// [complex value]: https://nginx.org/en/docs/dev/development_guide.html#http_complex_values + pub fn get_complex_value(&self, cv: &ngx_http_complex_value_t) -> Option<&NgxStr> { + let r = (self as *const Request as *mut Request).cast(); + let val = cv as *const ngx_http_complex_value_t as *mut ngx_http_complex_value_t; + // SAFETY: `ngx_http_complex_value` does not mutate `r` or `val` and guarentees that + // a valid Nginx string is stored in `value` if it successfully returns. + unsafe { + let mut value = ngx_null_string!(); + if ngx_http_complex_value(r, val, &mut value) != NGX_OK as ngx_int_t { + return None; + } + Some(NgxStr::from_ngx_str(value)) + } + } + + /// Discard (read and ignore) the [request body]. + /// + /// [request body]: https://nginx.org/en/docs/dev/development_guide.html#http_request_body + pub fn discard_request_body(&mut self) -> Status { + unsafe { Status(ngx_http_discard_request_body(&mut self.0)) } + } + + /// Client HTTP [User-Agent]. + /// + /// [User-Agent]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent + pub fn user_agent(&self) -> &NgxStr { + unsafe { NgxStr::from_ngx_str((*self.0.headers_in.user_agent).value) } + } + + /// Set HTTP status of response. + pub fn set_status(&mut self, status: HTTPStatus) { + self.0.headers_out.status = status.into(); + } + + pub fn add_header_in(&mut self, key: &str, value: &str) -> Option<()> { + let table: *mut ngx_table_elt_t = unsafe { ngx_list_push(&mut self.0.headers_in.headers) as _ }; + add_to_ngx_table(table, self.0.pool, key, value) + } + + pub fn add_header_out(&mut self, key: &str, value: &str) -> Option<()> { + let table: *mut ngx_table_elt_t = unsafe { ngx_list_push(&mut self.0.headers_out.headers) as _ }; + add_to_ngx_table(table, self.0.pool, key, value) + } + + /// Set response body [Content-Length]. + /// + /// [Content-Length]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length + pub fn set_content_length_n(&mut self, n: usize) { + self.0.headers_out.content_length_n = n as off_t; + } + + /// Send the output header. + /// + /// Do not call this function until all output headers are set. + pub fn send_header(&mut self) -> Status { + unsafe { Status(ngx_http_send_header(&mut self.0)) } + } + + /// Flag indicating that the output does not require a body. + /// + /// For example, this flag is used by `HTTP HEAD` requests. + pub fn header_only(&self) -> bool { + self.0.header_only() != 0 + } + + /// request method + pub fn method(&self) -> Method { + Method::from_ngx(self.0.method) + } + + /// path part of request only + pub fn path(&self) -> &NgxStr { + unsafe { NgxStr::from_ngx_str(self.0.uri) } + } + + /// full uri - containing path and args + pub fn unparsed_uri(&self) -> &NgxStr { + unsafe { NgxStr::from_ngx_str(self.0.unparsed_uri) } + } + + /// Send the [response body]. + /// + /// This function can be called multiple times. + /// Set the `last_buf` flag in the last body buffer. + /// + /// [response body]: https://nginx.org/en/docs/dev/development_guide.html#http_request_body + pub fn output_filter(&mut self, body: &mut ngx_chain_t) -> Status { + unsafe { Status(ngx_http_output_filter(&mut self.0, body)) } + } + + /// Perform internal redirect to a location + pub fn internal_redirect(&self, location: &str) -> Status { + assert!(!location.is_empty(), "uri location is empty"); + let uri_ptr = &mut ngx_str_t::from_str(self.0.pool, location) as *mut _; + + // FIXME: check status of ngx_http_named_location or ngx_http_internal_redirect + if location.starts_with('@') { + unsafe { + ngx_http_named_location((self as *const Request as *mut Request).cast(), uri_ptr); + } + } else { + unsafe { + ngx_http_internal_redirect( + (self as *const Request as *mut Request).cast(), + uri_ptr, + std::ptr::null_mut(), + ); + } + } + Status::NGX_DONE + } + + /// Send a subrequest + pub fn subrequest( + &self, + uri: &str, + module: &ngx_module_t, + post_callback: unsafe extern "C" fn(*mut ngx_http_request_t, *mut c_void, ngx_int_t) -> ngx_int_t, + ) -> Status { + let uri_ptr = &mut ngx_str_t::from_str(self.0.pool, uri) as *mut _; + // ------------- + // allocate memory and set values for ngx_http_post_subrequest_t + let sub_ptr = self.pool().alloc(std::mem::size_of::()); + + // assert!(sub_ptr.is_null()); + let post_subreq = sub_ptr as *const ngx_http_post_subrequest_t as *mut ngx_http_post_subrequest_t; + unsafe { + (*post_subreq).handler = Some(post_callback); + (*post_subreq).data = self.get_module_ctx_ptr(module); // WARN: safety! ensure that ctx is already set + } + // ------------- + + let mut psr: *mut ngx_http_request_t = std::ptr::null_mut(); + let r = unsafe { + ngx_http_subrequest( + (self as *const Request as *mut Request).cast(), + uri_ptr, + std::ptr::null_mut(), + &mut psr as *mut _, + sub_ptr as *mut _, + NGX_HTTP_SUBREQUEST_WAITED as _, + ) + }; + + // previously call of ngx_http_subrequest() would ensure that the pointer is not null anymore + let mut sr = unsafe { &mut *psr }; + + /* + * allocate fake request body to avoid attempts to read it and to make + * sure real body file (if already read) won't be closed by upstream + */ + sr.request_body = self.pool().alloc(std::mem::size_of::()) as *mut _; + + if sr.request_body.is_null() { + return Status::NGX_ERROR; + } + sr.set_header_only(1 as _); + Status(r) + } + + /// Iterate over headers_in + /// each header item is (String, String) (copied) + pub fn headers_in_iterator(&self) -> NgxListIterator { + unsafe { list_iterator(&self.0.headers_in.headers) } + } + + /// Iterate over headers_out + /// each header item is (String, String) (copied) + pub fn headers_out_iterator(&self) -> NgxListIterator { + unsafe { list_iterator(&self.0.headers_out.headers) } + } +} + +// trait OnSubRequestDone { + +// } + +impl fmt::Debug for Request { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Request").field("request_", &self.0).finish() + } +} + +pub struct NgxListIterator { + done: bool, + part: *const ngx_list_part_t, + h: *const ngx_table_elt_t, + i: ngx_uint_t, +} + +// create new http request iterator +/// # Safety +/// +/// The caller has provided a valid `ngx_str_t` which can be dereferenced validly. +pub unsafe fn list_iterator(list: *const ngx_list_t) -> NgxListIterator { + let part: *const ngx_list_part_t = &(*list).part; + + NgxListIterator { + done: false, + part, + h: (*part).elts as *const ngx_table_elt_t, + i: 0, + } +} + +// iterator for ngx_list_t +impl Iterator for NgxListIterator { + // type Item = (&str,&str); + // TODO: try to use str instead of string + // something like pub struct Header(ngx_table_elt_t); + // then header would have key and value + + type Item = (String, String); + + fn next(&mut self) -> Option { + unsafe { + if self.done { + None + } else { + if self.i >= (*self.part).nelts { + if (*self.part).next.is_null() { + self.done = true; + return None; + } + + // loop back + self.part = (*self.part).next; + self.h = (*self.part).elts as *mut ngx_table_elt_t; + self.i = 0; + } + + let header: *const ngx_table_elt_t = self.h.add(self.i); + let header_name: ngx_str_t = (*header).key; + let header_value: ngx_str_t = (*header).value; + self.i += 1; + Some((header_name.to_string(), header_value.to_string())) + } + } + } +} + +/// A possible error value when converting `Method` +pub struct InvalidMethod { + _priv: (), +} + +/// Request method verb +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct Method(MethodInner); + +impl Method { + /// UNKNOWN + pub const UNKNOWN: Method = Method(MethodInner::Unknown); + + /// GET + pub const GET: Method = Method(MethodInner::Get); + + /// HEAD + pub const HEAD: Method = Method(MethodInner::Head); + + /// POST + pub const POST: Method = Method(MethodInner::Post); + + /// PUT + pub const PUT: Method = Method(MethodInner::Put); + + /// DELETE + pub const DELETE: Method = Method(MethodInner::Delete); + + /// MKCOL + pub const MKCOL: Method = Method(MethodInner::Mkcol); + + /// COPY + pub const COPY: Method = Method(MethodInner::Copy); + + /// MOVE + pub const MOVE: Method = Method(MethodInner::Move); + + /// OPTIONS + pub const OPTIONS: Method = Method(MethodInner::Options); + + /// PROPFIND + pub const PROPFIND: Method = Method(MethodInner::Propfind); + + /// PROPPATCH + pub const PROPPATCH: Method = Method(MethodInner::Proppatch); + + /// LOCK + pub const LOCK: Method = Method(MethodInner::Lock); + + /// UNLOCK + pub const UNLOCK: Method = Method(MethodInner::Unlock); + + /// PATCH + pub const PATCH: Method = Method(MethodInner::Patch); + + /// TRACE + pub const TRACE: Method = Method(MethodInner::Trace); + + /// CONNECT + pub const CONNECT: Method = Method(MethodInner::Connect); + + #[inline] + pub fn as_str(&self) -> &str { + match self.0 { + MethodInner::Unknown => "UNKNOWN", + MethodInner::Get => "GET", + MethodInner::Head => "HEAD", + MethodInner::Post => "POST", + MethodInner::Put => "PUT", + MethodInner::Delete => "DELETE", + MethodInner::Mkcol => "MKCOL", + MethodInner::Copy => "COPY", + MethodInner::Move => "MOVE", + MethodInner::Options => "OPTIONS", + MethodInner::Propfind => "PROPFIND", + MethodInner::Proppatch => "PROPPATCH", + MethodInner::Lock => "LOCK", + MethodInner::Unlock => "UNLOCK", + MethodInner::Patch => "PATCH", + MethodInner::Trace => "TRACE", + MethodInner::Connect => "CONNECT", + } + } + + fn from_bytes(_t: &[u8]) -> Result { + todo!() + } + + fn from_ngx(t: ngx_uint_t) -> Method { + let t = t as _; + match t { + NGX_HTTP_GET => Method(MethodInner::Get), + NGX_HTTP_HEAD => Method(MethodInner::Head), + NGX_HTTP_POST => Method(MethodInner::Post), + NGX_HTTP_PUT => Method(MethodInner::Put), + NGX_HTTP_DELETE => Method(MethodInner::Delete), + NGX_HTTP_MKCOL => Method(MethodInner::Mkcol), + NGX_HTTP_COPY => Method(MethodInner::Copy), + NGX_HTTP_MOVE => Method(MethodInner::Move), + NGX_HTTP_OPTIONS => Method(MethodInner::Options), + NGX_HTTP_PROPFIND => Method(MethodInner::Propfind), + NGX_HTTP_PROPPATCH => Method(MethodInner::Proppatch), + NGX_HTTP_LOCK => Method(MethodInner::Lock), + NGX_HTTP_UNLOCK => Method(MethodInner::Unlock), + NGX_HTTP_PATCH => Method(MethodInner::Patch), + NGX_HTTP_TRACE => Method(MethodInner::Trace), + NGX_HTTP_CONNECT => Method(MethodInner::Connect), + _ => Method(MethodInner::Unknown), + } + } +} + +impl AsRef for Method { + #[inline] + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl<'a> PartialEq<&'a Method> for Method { + #[inline] + fn eq(&self, other: &&'a Method) -> bool { + self == *other + } +} + +impl<'a> PartialEq for &'a Method { + #[inline] + fn eq(&self, other: &Method) -> bool { + *self == other + } +} + +impl PartialEq for Method { + #[inline] + fn eq(&self, other: &str) -> bool { + self.as_ref() == other + } +} + +impl PartialEq for str { + #[inline] + fn eq(&self, other: &Method) -> bool { + self == other.as_ref() + } +} + +impl<'a> PartialEq<&'a str> for Method { + #[inline] + fn eq(&self, other: &&'a str) -> bool { + self.as_ref() == *other + } +} + +impl<'a> PartialEq for &'a str { + #[inline] + fn eq(&self, other: &Method) -> bool { + *self == other.as_ref() + } +} + +impl fmt::Debug for Method { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_ref()) + } +} + +impl fmt::Display for Method { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.write_str(self.as_ref()) + } +} + +impl<'a> From<&'a Method> for Method { + #[inline] + fn from(t: &'a Method) -> Self { + t.clone() + } +} + +impl<'a> TryFrom<&'a [u8]> for Method { + type Error = InvalidMethod; + + #[inline] + fn try_from(t: &'a [u8]) -> Result { + Method::from_bytes(t) + } +} + +impl<'a> TryFrom<&'a str> for Method { + type Error = InvalidMethod; + + #[inline] + fn try_from(t: &'a str) -> Result { + TryFrom::try_from(t.as_bytes()) + } +} + +impl FromStr for Method { + type Err = InvalidMethod; + + #[inline] + fn from_str(t: &str) -> Result { + TryFrom::try_from(t) + } +} + +impl InvalidMethod { + #[allow(dead_code)] + fn new() -> InvalidMethod { + InvalidMethod { _priv: () } + } +} + +impl fmt::Debug for InvalidMethod { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("InvalidMethod") + // skip _priv noise + .finish() + } +} + +impl fmt::Display for InvalidMethod { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("invalid HTTP method") + } +} + +impl Error for InvalidMethod {} + +#[derive(Clone, PartialEq, Eq, Hash)] +enum MethodInner { + Unknown, + Get, + Head, + Post, + Put, + Delete, + Mkcol, + Copy, + Move, + Options, + Propfind, + Proppatch, + Lock, + Unlock, + Patch, + Trace, + Connect, +} diff --git a/src/http/status.rs b/src/http/status.rs new file mode 100644 index 0000000..5aa3c11 --- /dev/null +++ b/src/http/status.rs @@ -0,0 +1,200 @@ +use crate::core::Status; +use crate::ffi::*; +use std::error::Error; +use std::fmt; + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct HTTPStatus(pub ngx_uint_t); + +/// A possible error value when converting a `HTTPStatus` from a `u16` or `&str` +/// +/// This error indicates that the supplied input was not a valid number, was less +/// than 100, or was greater than 599. +#[derive(Debug)] +pub struct InvalidHTTPStatusCode { + _priv: (), +} + +impl InvalidHTTPStatusCode { + fn new() -> InvalidHTTPStatusCode { + InvalidHTTPStatusCode { _priv: () } + } +} + +impl fmt::Display for InvalidHTTPStatusCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("invalid status code".to_string().as_str()) + } +} + +impl Error for InvalidHTTPStatusCode {} + +impl From for Status { + fn from(val: HTTPStatus) -> Self { + Status(val.0 as ngx_int_t) + } +} + +impl From for ngx_uint_t { + fn from(val: HTTPStatus) -> Self { + val.0 + } +} + +impl fmt::Debug for HTTPStatus { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } +} + +impl HTTPStatus { + #[inline] + pub fn from_u16(src: u16) -> Result { + if !(100..600).contains(&src) { + return Err(InvalidHTTPStatusCode::new()); + } + + Ok(HTTPStatus(src.into())) + } + + /// Converts a &[u8] to a status code + pub fn from_bytes(src: &[u8]) -> Result { + if src.len() != 3 { + return Err(InvalidHTTPStatusCode::new()); + } + + let a = src[0].wrapping_sub(b'0') as u16; + let b = src[1].wrapping_sub(b'0') as u16; + let c = src[2].wrapping_sub(b'0') as u16; + + if a == 0 || a > 5 || b > 9 || c > 9 { + return Err(InvalidHTTPStatusCode::new()); + } + + let status = (a * 100) + (b * 10) + c; + Ok(HTTPStatus(status.into())) + } +} + +macro_rules! http_status_codes { + ( + $( + $(#[$docs:meta])* + ($num:expr, $konst:ident, $phrase:expr); + )+ + ) => { + impl HTTPStatus { + $( + $(#[$docs])* + pub const $konst: HTTPStatus = HTTPStatus($num); + )+ + + } + } +} + +http_status_codes! { + /// 100 CONTINUE + (100, CONTINUE, "Continue"); + /// 101 SWITCHING_PROTOCOLS + (101, SWITCHING_PROTOCOLS, "Switching Protocols"); + /// 102 PROCESSING + (102, PROCESSING, "Processing"); + /// 200 OK + (200, OK, "OK"); + /// 201 Created + (201, CREATED, "Created"); + /// 202 Accepted + (202, ACCEPTED, "Accepted"); + /// 204 No Content + (204, NO_CONTENT, "No Content"); + /// 206 Partial Content + (206, PARTIAL_CONTENT, "Partial Content"); + + /// 300 SPECIAL_RESPONSE + (300, SPECIAL_RESPONSE, "SPECIAL_RESPONSE"); + /// 301 Moved Permanently + (301, MOVED_PERMANENTLY, "Moved Permanently"); + /// 302 Moved Temporarily + (302, MOVED_TEMPORARILY, "Moved Temporarily"); + /// 303 See Other + (303, SEE_OTHER, "See Other"); + /// 304 Not Modified + (304, NOT_MODIFIED, "Not Modified"); + /// 307 Temporary Redirect + (307, TEMPORARY_REDIRECT, "Temporary Redirect"); + /// 308 Permanent Redirect + (308, PERMANENT_REDIRECT, "Permanent Redirect"); + + /// 400 Bad Request + (400, BAD_REQUEST, "Bad Request"); + /// 401 Unauthorized + (401, UNAUTHORIZED, "Unauthorized"); + /// 403 Forbidden + (403, FORBIDDEN, "Forbidden"); + /// 404 Not Found + (404, NOT_FOUND, "Not Found"); + /// 405 Method Not Allowed + (405, NOT_ALLOWED, "Method Not Allowed"); + /// 408 Request Time Out + (408, REQUEST_TIME_OUT, "Request Time Out"); + /// 409 Conflict + (409, CONFLICT, "Conflict"); + /// 411 Length Required + (411, LENGTH_REQUIRED, "Length Required"); + /// 412 Precondition Failed + (412, PRECONDITION_FAILED, "Precondition Failed"); + /// 413 Payload Too Large + (413, REQUEST_ENTITY_TOO_LARGE, "Payload Too Large"); + /// 414 Request Uri Too Large + (414, REQUEST_URI_TOO_LARGE, "Request Uri Too Large"); + /// 415 Unsupported Media Type + (415, UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type"); + /// 416 Range Not Satisfiable + (416, RANGE_NOT_SATISFIABLE, "Range Not Satisfiable"); + /// 421 Misdirected Request + (421, MISDIRECTED_REQUEST, "Misdirected Request"); + /// 429 Too Many Requests + (429, TOO_MANY_REQUESTS, "Too Many Requests"); + + // /* Our own HTTP codes */ + // /* The special code to close connection without any response */ + /// 444 CLOSE + (444, CLOSE, "CLOSE"); + + /// 494 NGINX_CODES + (494, NGINX_CODES, "NGINX_CODES"); + + /// 494 REQUEST_HEADER_TOO_LARGE + (494, REQUEST_HEADER_TOO_LARGE, "REQUEST_HEADER_TOO_LARGE"); + + /// 495 NGX_HTTPS_CERT_ERROR + (495, HTTPS_CERT_ERROR, "NGX_HTTPS_CERT_ERROR"); + /// 496 NGX_HTTPS_NO_CERT + (496, HTTPS_NO_CERT, "NGX_HTTPS_NO_CERT"); + + // /* + // * We use the special code for the plain HTTP requests that are sent to + // * HTTPS port to distinguish it from 4XX in an error page redirection + // */ + /// 497 TO_HTTPS + (497, TO_HTTPS, "TO_HTTPS"); + + /// 499 CLIENT_CLOSED_REQUEST + (499, CLIENT_CLOSED_REQUEST, "CLIENT_CLOSED_REQUEST"); + + /// 500 INTERNAL_SERVER_ERROR + (500, INTERNAL_SERVER_ERROR, "INTERNAL_SERVER_ERROR"); + /// 501 NOT_IMPLEMENTED + (501, NOT_IMPLEMENTED, "NOT_IMPLEMENTED"); + /// 502 BAD_GATEWAY + (502, BAD_GATEWAY, "BAD_GATEWAY"); + /// 503 SERVICE_UNAVAILABLE + (503, SERVICE_UNAVAILABLE, "SERVICE_UNAVAILABLE"); + /// 504 GATEWAY_TIME_OUT + (504, GATEWAY_TIME_OUT, "GATEWAY_TIME_OUT"); + /// 505 VERSION_NOT_SUPPORTED + (505, VERSION_NOT_SUPPORTED, "VERSION_NOT_SUPPORTED"); + /// 507 INSUFFICIENT_STORAGE + (507, INSUFFICIENT_STORAGE, "INSUFFICIENT_STORAGE"); +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..821c19d --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,37 @@ +pub mod core; +pub mod ffi; +pub mod http; +pub mod log; + +/// Define modules exported by this library. +/// +/// These are normally generated by the Nginx module system, but need to be +/// defined when building modules outside of it. +#[macro_export] +macro_rules! ngx_modules { + ($( $mod:ident ),+) => { + #[no_mangle] + pub static mut ngx_modules: [*const ngx_module_t; $crate::count!($( $mod, )+) + 1] = [ + $( unsafe { &$mod } as *const ngx_module_t, )+ + std::ptr::null() + ]; + + #[no_mangle] + pub static mut ngx_module_names: [*const c_char; $crate::count!($( $mod, )+) + 1] = [ + $( concat!(stringify!($mod), "\0").as_ptr() as *const i8, )+ + std::ptr::null() + ]; + + #[no_mangle] + pub static mut ngx_module_order: [*const c_char; 1] = [ + std::ptr::null() + ]; + }; +} + +/// Count number of arguments +#[macro_export] +macro_rules! count { + () => { 0usize }; + ($x:tt, $( $xs:tt ),*) => { 1usize + $crate::count!($( $xs, )*) }; +} diff --git a/src/log.rs b/src/log.rs new file mode 100644 index 0000000..37d4ac4 --- /dev/null +++ b/src/log.rs @@ -0,0 +1,29 @@ +/// Write to logger at a specified level. +/// +/// See [Logging](https://nginx.org/en/docs/dev/development_guide.html#logging) +/// for available log levels. +#[macro_export] +macro_rules! ngx_log_debug { + ( $log:expr, $($arg:tt)* ) => { + let log_level = unsafe { (*$log).log_level }; + if log_level != 0 { + let level = $crate::ffi::NGX_LOG_DEBUG as $crate::ffi::ngx_uint_t; + let fmt = ::std::ffi::CString::new("%s").unwrap(); + let c_message = ::std::ffi::CString::new(format!($($arg)*)).unwrap(); + unsafe { + $crate::ffi::ngx_log_error_core(level, $log, 0, fmt.as_ptr(), c_message.as_ptr()); + } + } + } +} + +/// Log to request connection log at level [`NGX_LOG_DEBUG_HTTP`]. +/// +/// [`NGX_LOG_DEBUG_HTTP`]: https://nginx.org/en/docs/dev/development_guide.html#logging +#[macro_export] +macro_rules! ngx_log_debug_http { + ( $request:expr, $($arg:tt)* ) => { + let log = unsafe { (*$request.connection()).log }; + $crate::ngx_log_debug!(log, $($arg)*); + } +} diff --git a/tests/log_test.rs b/tests/log_test.rs index 78785a3..b5a1858 100644 --- a/tests/log_test.rs +++ b/tests/log_test.rs @@ -1,49 +1,101 @@ -extern crate ngx_rust; -extern crate futures; -extern crate hyper; -extern crate tokio_core; +use std::env; +use std::fs; +use std::io::Result; +use std::process::Command; +use std::process::Output; + +const NGX_DEFAULT_VERSION: &str = "1.23.3"; +const NGINX_BIN: &str = "sbin/nginx"; +const NGINX_CONFIG: &str = "conf/nginx.conf"; + +/// harness to test nginx +pub struct Nginx { + pub install_path: String, +} + +impl Default for Nginx { + /// create nginx with default + fn default() -> Nginx { + let path = env::current_dir().unwrap(); + let version = env::var("NGX_VERSION").unwrap_or_else(|_| NGX_DEFAULT_VERSION.to_string()); + let platform = format!("{}-{}", env::consts::OS, env::consts::ARCH); + let ngx_path = format!(".cache/nginx/{}/{}", version, platform); + let install_path = format!("{}/{}", path.display(), ngx_path); + Nginx { install_path } + } +} + +impl Nginx { + pub fn new(path: String) -> Nginx { + Nginx { install_path: path } + } + /// get bin path to nginx instance + pub fn bin_path(&mut self) -> String { + format!("{}/{}", self.install_path, NGINX_BIN) + } + + /// start nginx process with arguments + pub fn cmd(&mut self, args: &[&str]) -> Result { + let bin_path = self.bin_path(); + let result = Command::new(bin_path).args(args).output(); + + match result { + Err(e) => Err(e), + + Ok(output) => { + println!("status: {}", output.status); + println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + Ok(output) + } + } + } + + /// complete stop the nginx binary + pub fn stop(&mut self) -> Result { + self.cmd(&["-s", "stop"]) + } + + /// start the nginx binary + pub fn start(&mut self) -> Result { + self.cmd(&[]) + } + + // make sure we stop existing nginx and start new master process + // intentinally ignore failure in stop + pub fn restart(&mut self) -> Result { + self.stop(); + self.start() + } + + // replace config with another config + pub fn replace_config(&mut self, from: &str) -> Result { + let config_path = format!("{}/{}", self.install_path, NGINX_CONFIG); + println!("copying config from: {} to: {}", from, config_path); // replace with logging + fs::copy(from, config_path) + } +} #[cfg(test)] mod tests { + use super::*; use std::env; - use ngx_rust::nginx::Nginx; - use futures::Future; - use hyper::Client; - use hyper::StatusCode; - use tokio_core::reactor::Core; const TEST_NGINX_CONFIG: &str = "tests/nginx.conf"; - #[test] fn test() { - let mut nginx = Nginx::default(); let path = env::current_dir().unwrap(); - let test_config_path = format!("{}/{}",path.display(),TEST_NGINX_CONFIG); + let test_config_path = format!("{}/{}", path.display(), TEST_NGINX_CONFIG); (nginx.replace_config(&test_config_path)).expect("copy done"); - let output = nginx.restart().expect("fail to start"); + let output = nginx.restart().expect("fail to start"); assert!(output.status.success()); - // make request to 30000 - - let mut core = Core::new().unwrap(); - - let client = Client::new(&core.handle()); - - let uri = "http://localhost:30000".parse().unwrap(); - let work = client.get(uri).map(|res| { - let status = res.status(); - println!("Response: {}", status); - assert_eq!(status,StatusCode::Ok); - - }); - - core.run(work).unwrap(); + let output = nginx.stop().expect("fail to stop"); + assert!(output.status.success()); } - - -} \ No newline at end of file +} diff --git a/tools/README.md b/tools/README.md deleted file mode 100644 index 09c18ce..0000000 --- a/tools/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Tools to compile and run rust based modules - - diff --git a/tools/rust/Dockerfile b/tools/rust/Dockerfile deleted file mode 100644 index 31d365d..0000000 --- a/tools/rust/Dockerfile +++ /dev/null @@ -1,50 +0,0 @@ -FROM ubuntu:16.04 -ARG RUST_VERSION=1.26.0 - -MAINTAINER Sehyo Chang "sehyo@nginx.com" - -# install nginx required libraries - -RUN apt-get update - -# install dev en -RUN apt-get install vim autoconf automake libtool curl make wget unzip gnupg binutils pkg-config -y - -# essential c compiler toolchain includes automake -#n RUN apt-get install build-essential -y -# install clang -RUN wget -O - http://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - -RUN echo 'deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial main' >> /etc/apt/sources.list -RUN wget -O - http://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - -RUN apt-get update -RUN apt-get install llvm-3.9-dev libclang-3.9-dev clang-3.9 -y - -# This is special hack to comment out IPPORT_RESERVED because it conflicts with in.h -# which prevents from compilation of rust binding.rs -RUN sed -i 's:# define IPPORT_RESERVED:// #define IPPORT_RESERVED:' /usr/include/netdb.h - -# install PCRE library -RUN apt-get install libpcre3 libpcre3-dev zlib1g-dev libssl-dev -y - - -# install rust -RUN curl -sO https://static.rust-lang.org/rustup/dist/x86_64-unknown-linux-gnu/rustup-init && \ - chmod +x rustup-init && \ - ./rustup-init -y --default-toolchain $RUST_VERSION --no-modify-path && \ - rm -rf \ - rustup-init \ - /var/lib/apt/lists/* \ - /tmp/* \ - /var/tmp/* - - -ENV PATH $PATH:/root/.cargo/bin - - - -# install protobuf -RUN curl -OL https://github.com/google/protobuf/releases/download/v3.3.0/protoc-3.3.0-linux-x86_64.zip -RUN unzip protoc-3.3.0-linux-x86_64.zip -d protoc3 -RUN mv protoc3/bin/* /usr/local/bin/ -RUN rm protoc-3.3.0-linux-x86_64.zip - diff --git a/tools/rust/Makefile b/tools/rust/Makefile deleted file mode 100644 index 44a49ed..0000000 --- a/tools/rust/Makefile +++ /dev/null @@ -1,13 +0,0 @@ - -TAG = 1.26.0 -NAME = nginxinc/ngx-rust-tool - - -all: build push - -build: - docker build -t $(NAME):$(TAG) --build-arg RUST_VERSION=$(TAG) . - -push: - docker push $(NAME):$(TAG) - diff --git a/tools/rust/README.md b/tools/rust/README.md deleted file mode 100644 index 76d049f..0000000 --- a/tools/rust/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Purpose - -Base image used for building rust based NGINX module. - -It contains rust tools chain and protobuf compiler - -'make build;push'