diff --git a/.drone.yml b/.drone.yml index c398f79..88ec18d 100644 --- a/.drone.yml +++ b/.drone.yml @@ -36,13 +36,16 @@ steps: registry: code.birch-tree.net repo: code.birch-tree.net/dorian/mirror-server tags: - - 0.3.0 + - 0.3.1 - latest cache_from: - code.birch-tree.net/dorian/mirror-server:latest - code.birch-tree.net/dorian/mirror-server:build depends_on: - test + when: + ref: + - refs/tags/* - name: create-debian-package image: code.birch-tree.net/dorian/mirror-server:build @@ -54,6 +57,9 @@ steps: from_secret: gitea-release-password depends_on: - test + when: + ref: + - refs/tags/* image_pull_secrets: - docker-config diff --git a/Cargo.toml b/Cargo.toml index b41e7eb..57f1ffa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mirror-server" -version = "0.3.0" +version = "0.3.1" edition = "2021" authors = ["Dorian Pula "] description = "A simple server for mirror HTTP requests for testing." diff --git a/Dockerfile b/Dockerfile index 097a0da..de0d199 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.76 AS BUILD +FROM rust:1.76-buster AS BUILD ENV APP_NAME=mirror-server ENV APP_HOME=/srv/${APP_NAME} @@ -19,7 +19,8 @@ RUN cargo build \ && rm src/*.rs # Bring in the source -COPY ["src", "./src/"] +COPY ["./src/*", "./src/"] +COPY ["README.md", "LICENSE", "./"] # Build the example API. RUN cargo build --release @@ -31,8 +32,5 @@ ENV APP_NAME=mirror-server ENV APP_HOME=/srv/${APP_NAME} RUN apt update -RUN mkdir -p ${APP_HOME} -WORKDIR ${APP_HOME} - COPY --from=BUILD ${APP_HOME}/target/release/${APP_NAME} /usr/local/bin/ CMD ${APP_NAME} \ No newline at end of file diff --git a/README.md b/README.md index c165ec7..655f307 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # mirror-server -A simple server for mirroring HTTP requests for testing. +A simple server for mirroring HTTP requests for testing. It is optimized for +working with REST API JSON calls, and catching headers. [![Build Status](https://ci.birch-tree.net/api/badges/dorian/mirror-server/status.svg)](https://ci.birch-tree.net/dorian/mirror-server) @@ -13,25 +14,78 @@ A simple server for mirroring HTTP requests for testing. * Create a DEB package: * Install cargo-deb: `cargo install cargo-deb` * Create the DEB package: `cargo deb` -* Faster builds using [cargo-watch](https://watchexec.github.io/#cargo-watch): `cargo watch -x run` +* Faster builds using [`cargo-watch`](https://watchexec.github.io/#cargo-watch): `cargo watch -x run` +* Installing the binary locally from source: `cargo install --path .` ## Install +`mirror-server` is installable either by a local Cargo install or a Debian +package. Additionally `mirror-server` can be run as a Docker container using +the latest (or tagged) release. + +### Docker Image + +Run via Docker using: + +```console +$ docker run -p 8080:8080 code.birch-tree.net/dorian/mirror-server:latest +``` + +### Debian Package + Download the DEB file, and install it: ```bash -VERSION=0.3.0 +VERSION=0.3.1 REPO_URL=https://code.birch-tree.net/api/packages/dorian/generic/mirror-server/ curl "${REPO_URL}/${VERSION}/mirror-server_${VERSION}_amd64.deb" sudo dpkg -i "mirror-server-${VERSION}_amd64.deb" ``` -## TODO +Afterward you can run using `mirror-server` -* [x] Migrate actix to axum for easier maintainability. -* [x] Add mirroring of JSON request. -* [x] Add logging to server. -* [x] Create Docker image for mirror-server for easier distribution. -* [x] Add publishing of DEB and Docker image to DroneCI. -* [ ] Add documentation to the API. -* [ ] Publish crate on . +## Usage + +You can get all the options that `mirror-server` supports by running it with +the help option `--help` or `-h`: + +```console +$ mirror-server --help +A simple server for mirror HTTP requests for testing. + +Usage: mirror-server [OPTIONS] + +Options: + -p, --port Port to run on [default: 8080] + -i, --ips Listen to IP mask [default: 0.0.0.0] + -h, --help Print help + -V, --version Print version +``` + +After starting the server, you can send requests to it. Using `curl` you +can send `mirror-server` JSON requests: + +```console +$ curl -s -X PUT -D '{"hello": "world"}' -H 'Content-Type: application/json' \ + http://localhost:8080/api/testing | jq . +``` + +And `mirror-server` responds to requests with JSON responses: + +```json +{ + "method": "PUT", + "path": "/api/testing", + "host": "localhost:8180", + "headers": { + "accept": "*/*", + "content-length": "18", + "content-type": "application/json", + "host": "localhost:8080", + "user-agent": "curl/7.68.0" + }, + "body": { + "hello": "world" + } +} +``` diff --git a/src/main.rs b/src/main.rs index 95c8ff1..13a8c5e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +#![doc = include_str!("../README.md")] + use axum::{ extract::{Host, Json, OriginalUri}, http::{header::HeaderMap, Method}, @@ -10,6 +12,11 @@ use std::collections::BTreeMap; use tower_http::trace; use tracing::{info, warn, Level}; + +/// CLI arguments used by the [`Parser`]. +/// +/// Creates the usage and version information that is standard in a CLI +/// utility. #[derive(Parser)] #[command(author, version, about, long_about = None)] struct CliArgs { @@ -22,16 +29,34 @@ struct CliArgs { ips: String, } +/// The response consisting of the echoed request to the mirror-server. #[derive(Serialize, Deserialize, Debug, PartialEq)] struct EchoResponse { + /// The [`Method`] used in the request. method: String, + /// The path used in the request. path: String, + /// The original schema, hostname and port of the request. host: String, + /// The headers in the request. headers: BTreeMap, + /// (Optional) The JSON body in the request. #[serde(skip_serializing_if = "Option::is_none")] body: Option, } +/// [`Handler`](axum::handler) for responding with a break-down of the captured request. +/// +/// Captures the request and responds with a JSON response of the elements of the request. +/// +/// ## Arguments +/// * `method` - The HTTP [`Method`] used for the request. i.e. `GET`, `POST`, `PATCH`, etc. +/// * `original_uri` - The URI used for the request. +/// * `host` - The hostname of the request. +/// * `header_map` - A map with the headers used during the request. +/// * `body` - An optional JSON body, if it is past in to the request. +/// Requires a header of `Content-Type: application/json` and a body passed in the request. +/// async fn echo_request( method: Method, original_uri: OriginalUri, @@ -67,6 +92,10 @@ async fn echo_request( Json(response) } +/// Create a [`Router`] to handling capture all HTTP requests to the server. +/// +/// Wires up a default catch-all route for the application. Also adds the tracing infrastructure +/// to capture requests. fn app() -> Router { Router::new().fallback(echo_request).layer( trace::TraceLayer::new_for_http() @@ -75,6 +104,7 @@ fn app() -> Router { ) } +/// The main application starts the mirror-server application. #[tokio::main] async fn main() { let cli_args = CliArgs::parse();