mirror of
https://github.com/ivabus/urouter
synced 2024-11-22 00:15:11 +03:00
0.5.3: create "external" alias type
Signed-off-by: Ivan Bushchik <ivabus@ivabus.dev>
This commit is contained in:
parent
886c4cf2fa
commit
82ddc180cb
5 changed files with 76 additions and 43 deletions
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "urouter"
|
name = "urouter"
|
||||||
version = "0.5.2"
|
version = "0.5.3"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://github.com/ivabus/urouter"
|
repository = "https://github.com/ivabus/urouter"
|
||||||
|
@ -15,3 +15,4 @@ url-escape = "0.1.1"
|
||||||
smurf = "0.3.0"
|
smurf = "0.3.0"
|
||||||
clap = { version = "4.4.11", features = ["derive"] }
|
clap = { version = "4.4.11", features = ["derive"] }
|
||||||
regex = "1.10.2"
|
regex = "1.10.2"
|
||||||
|
ureq = { version = "2.9.1", features = ["brotli", "native-certs"] }
|
||||||
|
|
28
README.md
28
README.md
|
@ -16,18 +16,19 @@ JSON file with array of sets (or set with one field of arrays of sets with `--al
|
||||||
|
|
||||||
Each set contains 2 necessary elements and 1 optional.
|
Each set contains 2 necessary elements and 1 optional.
|
||||||
|
|
||||||
- Necessary
|
- `uri` (string) - of URL after host (e.g., `/`, `some/cool/path`, should not start with `/` (only for root))
|
||||||
- `uri` (string) - of url after host (e.g., `/`, `some/cool/path`, should not start with `/` (only for root))
|
- `alias` (set) - set of one field
|
||||||
- `alias` (set) - set of one field
|
- `url` (string) - redirect to URL with HTTP 303 See Other
|
||||||
- `url` (string) - redirect to url with HTTP 303 See Other
|
|
||||||
- `file` (string) - read file from path `--dir/file` where `--dir` is option (default: `.`, see `--help`) and respond with HTTP 200 OK with `content-type: text/plain`
|
- `file` (string) - read file from path `--dir/file` where `--dir` is option (default: `.`, see `--help`) and respond with HTTP 200 OK with `content-type: text/plain`
|
||||||
- `text` (string) - plain text HTTP 200 OK with `content-type: text/plain`
|
- `text` (string) - plain text with HTTP 200 OK with `content-type: text/plain`
|
||||||
- Optional
|
- `external` (set) - download (every time) file using `ureq` HTTP library and response with contents of downloaded resource with HTTP 200 OK and extracted `content-type` from response
|
||||||
- `agent` (set) - set of one necessary field and one optional
|
- `url` (string) - URL to download
|
||||||
|
- `headers` (set, optional) - headers to include with request
|
||||||
|
- `agent` (set, optional) - set of one necessary field and one optional
|
||||||
- `regex` (string) - regular expression to match user-agent HTTP header
|
- `regex` (string) - regular expression to match user-agent HTTP header
|
||||||
- `only_matching` (bool, optional, false by default) - if false whole alias will be visible for any user agent, if true only for regex matched
|
- `only_matching` (bool, optional, false by default) - if false whole alias will be visible for any user agent, if true only for regex matched
|
||||||
|
|
||||||
#### Set of array of sets
|
#### Set of array of sets (use only for very specific workarounds)
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
@ -67,6 +68,17 @@ Each set contains 2 necessary elements and 1 optional.
|
||||||
"alias": {
|
"alias": {
|
||||||
"text": "sometext"
|
"text": "sometext"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uri": "external",
|
||||||
|
"alias": {
|
||||||
|
"external": {
|
||||||
|
"url": "https://somecool.external.link",
|
||||||
|
"headers": {
|
||||||
|
"user-agent": "curl/8.6.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
11
alias.json
11
alias.json
|
@ -23,5 +23,16 @@
|
||||||
"regex": "^curl/[0-9].[0-9].[0-9]$",
|
"regex": "^curl/[0-9].[0-9].[0-9]$",
|
||||||
"only_matching": true
|
"only_matching": true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uri": "external",
|
||||||
|
"alias": {
|
||||||
|
"external": {
|
||||||
|
"url": "https://iva.bz",
|
||||||
|
"headers": {
|
||||||
|
"user-agent": "curl/8.6.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
52
src/main.rs
52
src/main.rs
|
@ -1,26 +1,10 @@
|
||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MIT License
|
Global comments:
|
||||||
*
|
- I'm ok with unwrapping because if unwrap fails Rocket will automatically return
|
||||||
* Copyright (c) 2023 Ivan Bushchik
|
500 Internal Server Error
|
||||||
*
|
*/
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
* copy of this software and associated documentation files (the "Software"),
|
|
||||||
* to deal in the Software without restriction, including without limitation
|
|
||||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
* and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
* Software is furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
* DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
mod structs;
|
mod structs;
|
||||||
|
|
||||||
|
@ -28,8 +12,8 @@ use structs::*;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rocket;
|
extern crate rocket;
|
||||||
|
|
||||||
use rocket::http::Status;
|
use rocket::http::{ContentType, Status};
|
||||||
use std::cell::{OnceCell, RefCell};
|
use std::cell::OnceCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::hint::unreachable_unchecked;
|
use std::hint::unreachable_unchecked;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -43,7 +27,7 @@ use regex::Regex;
|
||||||
use rocket::figment::Figment;
|
use rocket::figment::Figment;
|
||||||
|
|
||||||
static mut ALIAS: OnceCell<Vec<Alias>> = OnceCell::new();
|
static mut ALIAS: OnceCell<Vec<Alias>> = OnceCell::new();
|
||||||
static mut COMPILED_REGEXES: RefCell<Option<HashMap<String, Regex>>> = RefCell::new(None);
|
static mut COMPILED_REGEXES: OnceCell<HashMap<String, Regex>> = OnceCell::new();
|
||||||
|
|
||||||
fn get_return(alias: &Alias) -> Response {
|
fn get_return(alias: &Alias) -> Response {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
@ -52,9 +36,21 @@ fn get_return(alias: &Alias) -> Response {
|
||||||
AliasType::Url(url) => Response::Redirect(Box::from(Redirect::to(url.clone()))),
|
AliasType::Url(url) => Response::Redirect(Box::from(Redirect::to(url.clone()))),
|
||||||
AliasType::File(path) => {
|
AliasType::File(path) => {
|
||||||
dir.push(&PathBuf::from(&path));
|
dir.push(&PathBuf::from(&path));
|
||||||
Response::Text(RawText(smurf::io::read_file_str(&dir).unwrap()))
|
Response::Text(Box::new(RawText(smurf::io::read_file_str(&dir).unwrap())))
|
||||||
|
}
|
||||||
|
AliasType::Text(text) => Response::Text(Box::new(RawText(text.clone()))),
|
||||||
|
AliasType::External(source) => {
|
||||||
|
let mut request = ureq::get(&source.url);
|
||||||
|
for (header, value) in &source.headers {
|
||||||
|
request = request.set(header, value);
|
||||||
|
}
|
||||||
|
let result = request.call().unwrap();
|
||||||
|
let ct = result.content_type();
|
||||||
|
Response::Custom(Box::new((
|
||||||
|
ContentType::parse_flexible(ct).unwrap(),
|
||||||
|
RawText(result.into_string().unwrap()),
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
AliasType::Text(text) => Response::Text(RawText(text.clone())),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +125,7 @@ async fn main() -> Result<(), rocket::Error> {
|
||||||
(Instant::now() - compilation_start).as_secs_f64() * 1000.0
|
(Instant::now() - compilation_start).as_secs_f64() * 1000.0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
*COMPILED_REGEXES.get_mut() = Some(compiled_regexes);
|
COMPILED_REGEXES.set(compiled_regexes).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let figment = Figment::from(rocket::Config::default())
|
let figment = Figment::from(rocket::Config::default())
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use rocket::http::Status;
|
use rocket::http::{ContentType, Status};
|
||||||
use rocket::request::{FromRequest, Outcome};
|
use rocket::request::{FromRequest, Outcome};
|
||||||
use rocket::response::content::RawText;
|
use rocket::response::content::RawText;
|
||||||
use rocket::response::Redirect;
|
use rocket::response::{Redirect, Responder};
|
||||||
use rocket::Request;
|
use rocket::Request;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
@ -50,6 +53,8 @@ pub enum AliasType {
|
||||||
File(String),
|
File(String),
|
||||||
#[serde(alias = "text")]
|
#[serde(alias = "text")]
|
||||||
Text(String),
|
Text(String),
|
||||||
|
#[serde(alias = "external")]
|
||||||
|
External(External),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
|
@ -58,11 +63,19 @@ pub struct Agent {
|
||||||
pub only_matching: Option<bool>,
|
pub only_matching: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
|
pub struct External {
|
||||||
|
pub url: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub headers: HashMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Responder)]
|
#[derive(Responder)]
|
||||||
pub enum Response {
|
pub enum Response {
|
||||||
Text(RawText<String>),
|
Text(Box<RawText<String>>),
|
||||||
Redirect(Box<Redirect>),
|
Redirect(Box<Redirect>),
|
||||||
Status(Status),
|
Status(Status),
|
||||||
|
Custom(Box<(ContentType, RawText<String>)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UserAgent(pub String);
|
pub struct UserAgent(pub String);
|
||||||
|
|
Loading…
Reference in a new issue