Skip to content
This repository has been archived by the owner on Oct 8, 2024. It is now read-only.

Commit

Permalink
Merge pull request #99 from PThorpe92/p_headers
Browse files Browse the repository at this point in the history
feat: add headers page with 2 default header options. TODO: Add more options
  • Loading branch information
PThorpe92 authored Nov 17, 2023
2 parents fb1cdd1 + 2cc38c8 commit 776619f
Show file tree
Hide file tree
Showing 11 changed files with 156 additions and 26 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ authors = ["PThorpe92 <[email protected]>"]
description = "A (ratatui) TUI for HTTP requests with libcurl, recursive downloads with wget, command storage and API key management"
license = "GPL-3.0"
edition = "2021"
repository = "https://github.com/PThorpe92/CuTE"

[[bin]]
name = "cute"
Expand Down
5 changes: 4 additions & 1 deletion src/app.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::database::db::{SavedCommand, SavedKey, DB};
use crate::display::menuopts::OPTION_PADDING_MID;
use crate::display::AppOptions;
use crate::display::{AppOptions, HeaderKind};
use crate::request::command::{CmdOpts, CMD};
use crate::request::curl::{AuthKind, Curl};
use crate::screens::screen::Screen;
Expand Down Expand Up @@ -320,6 +320,7 @@ impl<'a> App<'a> {
AppOptions::Headers(_) => self.command.as_mut().unwrap().remove_headers(opt.get_value()),
AppOptions::Auth(_) => self.command.as_mut().unwrap().set_auth(crate::request::curl::AuthKind::None),
AppOptions::EnableHeaders => self.command.as_mut().unwrap().enable_response_headers(false),
AppOptions::ContentHeaders(_)=> self.command.as_mut().unwrap().set_content_header(HeaderKind::None),
}
self.opts
.retain(|x| mem::discriminant(x) != mem::discriminant(opt));
Expand Down Expand Up @@ -367,6 +368,7 @@ impl<'a> App<'a> {
| AppOptions::ProgressBar
| AppOptions::SaveCommand
| AppOptions::SaveToken
| AppOptions::ContentHeaders(_) // Headers can be pushed but these are pre-defined
| AppOptions::EnableHeaders => true,
_ => false,
}
Expand All @@ -392,6 +394,7 @@ impl<'a> App<'a> {
AppOptions::UnrestrictedAuth => self.command.as_mut().unwrap().set_unrestricted_auth(true),
AppOptions::TcpKeepAlive => self.command.as_mut().unwrap().set_tcp_keepalive(true),
AppOptions::SaveToken => self.command.as_mut().unwrap().save_token(true),
AppOptions::ContentHeaders(k)=> self.command.as_mut().unwrap().set_content_header(k),
AppOptions::Auth(ref kind) => self.command.as_mut().unwrap().set_auth(kind.clone()),
// Auth will be toggled for all types except for Basic, Bearer and digest
_ => {}
Expand Down
15 changes: 11 additions & 4 deletions src/display/menuopts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ pub const DISPLAY_OPT_COOKIE: &str = " Add Cookie: ";
pub const DISPLAY_OPT_USERAGENT: &str = " Specify User-Agent: ";
pub const DISPLAY_OPT_PROXY_TUNNEL: &str = " Enable HTTP Proxy-Tunnel 󱠾 ";
pub const DISPLAY_OPT_URL: &str = " Request URL: ";
pub const DISPLAY_OPT_CONTENT_HEADERS: &str = " Headers: ";
pub const UPLOAD_FILEPATH_ERROR: &str =
"Error: Invalid file path. Please enter an absolute path or a valid relative path.";
pub const SOCKET_ERROR: &str =
Expand Down Expand Up @@ -131,14 +132,13 @@ lazy_static! {
"View my stored API keys 󱂛  ",
"View or execute my saved commands  ",
];
pub static ref REQUEST_MENU_OPTIONS: [&'static str; 13] = [
pub static ref REQUEST_MENU_OPTIONS: [&'static str; 12] = [
"Add a URL 󰖟 ",
"Add a file for uploads  ",
"Add Unix Socket address 󰟩 ",
"Add Authentication 󰯄 ",
"Add Headers  ",
"Authentication 󰯄 ",
"Header Options  ",
"Enable verbose output [-v]",
"Enable response Headers 󰃁 ",
"Add Request Body 󰘦 ",
"Save this Command  ",
"Save your API token or login information  ",
Expand All @@ -161,6 +161,13 @@ lazy_static! {
"PATCH",
"HEAD",
];
pub static ref HEADER_MENU_OPTIONS: [&'static str; 5] = [
"Add Custom Header 󰖟 ",
"Add Content-Type: Application/Json  ",
"Add Accept: Application/Json  ",
"Enable Response Headers 󰰀 ",
"Return to request menu  ",
];
pub static ref AUTHENTICATION_MENU_OPTIONS: [&'static str; 6] = [
"Basic",
"Bearer",
Expand Down
37 changes: 31 additions & 6 deletions src/display/mod.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,36 @@
use std::fmt::{Display, Formatter};

use crate::{
display::menuopts::{DISPLAY_OPT_MAX_REC, DISPLAY_OPT_MAX_REDIRECTS, DISPLAY_OPT_REFERRER},
request::curl::AuthKind,
};

use self::menuopts::{
DISPLAY_OPT_AUTH, DISPLAY_OPT_BODY, DISPLAY_OPT_CA_PATH, DISPLAY_OPT_CERT_INFO,
DISPLAY_OPT_COMMAND_SAVED, DISPLAY_OPT_COOKIE, DISPLAY_OPT_FAIL_ON_ERROR,
DISPLAY_OPT_FOLLOW_REDIRECTS, DISPLAY_OPT_HEADERS, DISPLAY_OPT_MATCH_WILDCARD,
DISPLAY_OPT_OUTFILE, DISPLAY_OPT_PROGRESS_BAR, DISPLAY_OPT_PROXY_TUNNEL,
DISPLAY_OPT_TCP_KEEPALIVE, DISPLAY_OPT_TOKEN_SAVED, DISPLAY_OPT_UNIX_SOCKET,
DISPLAY_OPT_UNRESTRICTED_AUTH, DISPLAY_OPT_UPLOAD, DISPLAY_OPT_URL, DISPLAY_OPT_USERAGENT,
DISPLAY_OPT_VERBOSE,
DISPLAY_OPT_COMMAND_SAVED, DISPLAY_OPT_CONTENT_HEADERS, DISPLAY_OPT_COOKIE,
DISPLAY_OPT_FAIL_ON_ERROR, DISPLAY_OPT_FOLLOW_REDIRECTS, DISPLAY_OPT_HEADERS,
DISPLAY_OPT_MATCH_WILDCARD, DISPLAY_OPT_OUTFILE, DISPLAY_OPT_PROGRESS_BAR,
DISPLAY_OPT_PROXY_TUNNEL, DISPLAY_OPT_TCP_KEEPALIVE, DISPLAY_OPT_TOKEN_SAVED,
DISPLAY_OPT_UNIX_SOCKET, DISPLAY_OPT_UNRESTRICTED_AUTH, DISPLAY_OPT_UPLOAD, DISPLAY_OPT_URL,
DISPLAY_OPT_USERAGENT, DISPLAY_OPT_VERBOSE,
};

// TODO: clean all this up
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum HeaderKind {
Accept,
ContentType,
None,
}
impl Display for HeaderKind {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
HeaderKind::Accept => write!(f, "Accept: Application/json"),
HeaderKind::ContentType => write!(f, "Content-Type: Application/json"),
HeaderKind::None => write!(f, ""),
}
}
}
/*
* Display - This is For Structures That Represent Display Items
* Or Are Related To Display Items In Some Way
Expand Down Expand Up @@ -41,6 +59,7 @@ pub enum AppOptions {
FollowRedirects,
Cookie(String),
EnableHeaders,
ContentHeaders(HeaderKind),
ProgressBar,
FailOnError,
ProxyTunnel,
Expand All @@ -59,6 +78,11 @@ pub enum AppOptions {
impl AppOptions {
pub fn replace_value(&mut self, val: String) {
match self {
AppOptions::ContentHeaders(ref mut kind) => match val.as_str() {
"Accept" => *kind = HeaderKind::Accept,
"Content-Type" => *kind = HeaderKind::ContentType,
_ => *kind = HeaderKind::None,
},
AppOptions::Headers(ref mut key) => {
*key = val;
}
Expand Down Expand Up @@ -138,6 +162,7 @@ impl AppOptions {
AppOptions::UnrestrictedAuth => format!("{}{}", DISPLAY_OPT_UNRESTRICTED_AUTH, "󰄨"),
AppOptions::UploadFile(file) => format!("{}{}", DISPLAY_OPT_UPLOAD, file.clone()),
AppOptions::RequestBody(body) => format!("{}{}", DISPLAY_OPT_BODY, body.clone()),
AppOptions::ContentHeaders(kind) => format!("{}{}", DISPLAY_OPT_CONTENT_HEADERS, kind),
}
}
}
8 changes: 7 additions & 1 deletion src/request/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::{
curl::{AuthKind, Curl},
wget::Wget,
};
use crate::database::db::DB;
use crate::{database::db::DB, display::HeaderKind};
use std::fmt::{Display, Error, Formatter};

pub enum Cmd<'a> {
Expand Down Expand Up @@ -106,6 +106,11 @@ impl<'a> CurlOpts for Cmd<'a> {
false
}
}
fn set_content_header(&mut self, kind: HeaderKind) {
if let Cmd::Curl(curl) = self {
curl.set_content_header(kind);
}
}
fn set_upload_file(&mut self, file: &str) {
if let Cmd::Curl(curl) = self {
curl.set_upload_file(file);
Expand Down Expand Up @@ -256,6 +261,7 @@ pub trait CmdOpts {
fn has_auth(&self) -> bool;
}
pub trait CurlOpts {
fn set_content_header(&mut self, kind: HeaderKind);
fn set_request_body(&mut self, body: &str);
fn set_upload_file(&mut self, file: &str);
fn add_cookie(&mut self, cookie: String);
Expand Down
42 changes: 41 additions & 1 deletion src/request/curl.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::database::db::DB;
use crate::display::HeaderKind;
use serde::de::{MapAccess, Visitor};
use serde::ser::SerializeStruct;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
Expand Down Expand Up @@ -494,6 +495,26 @@ impl<'a> CurlOpts for Curl<'a> {
self.curl.progress(on).unwrap();
}

fn set_content_header(&mut self, kind: HeaderKind) {
if kind == HeaderKind::None && self.headers.is_some() {
self.headers
.as_mut()
.unwrap()
.retain(|x| !x.contains("application/json"));
}
let header_value = match kind {
HeaderKind::Accept => "Accept: application/json",
HeaderKind::ContentType => "Content-Type: application/json",
HeaderKind::None => "",
};

if let Some(ref mut headers) = self.headers {
headers.push(String::from(header_value));
} else {
self.headers = Some(vec![String::from(header_value)]);
}
}

fn save_command(&mut self, opt: bool) {
self.save.0 = opt;
}
Expand Down Expand Up @@ -1008,7 +1029,6 @@ mod tests {
use super::*;
use mockito::ServerGuard;
use serde_json::json;

fn setup(method: &str) -> ServerGuard {
let mut server = mockito::Server::new();
// Start a mock server
Expand All @@ -1027,6 +1047,26 @@ mod tests {
assert_eq!(curl.opts.len(), 0);
assert_eq!(curl.resp, None);
}
#[test]
fn test_set_content_headers() {
let mut curl = Curl::new();
curl.set_content_header(HeaderKind::ContentType);
assert_eq!(curl.headers.as_ref().unwrap().len(), 1);
assert_eq!(
curl.headers.as_ref().unwrap()[0],
"Content-Type: application/json"
);
}

#[test]
fn test_remove_content_headers() {
let mut curl = Curl::new();
curl.add_headers("Authorization: Bearer 12345678910".to_string());
curl.set_content_header(HeaderKind::ContentType);
curl.remove_headers("Content-Type: application/json".to_string());
assert_eq!(curl.headers.as_ref().unwrap().len(), 1);
assert!(curl.headers.is_some());
}

#[test]
fn test_build_command_str() {
Expand Down
36 changes: 36 additions & 0 deletions src/screens/headers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use tui::prelude::Backend;
use tui::Frame;

use super::render::handle_screen_defaults;
use super::Screen;
use crate::app::App;
use crate::display::inputopt::InputOpt;
use crate::display::{AppOptions, HeaderKind};

pub fn handle_headers_screen<B: Backend>(app: &mut App, frame: &mut Frame<'_, B>) {
handle_screen_defaults(app, frame);

match app.selected {
// add custom headers
Some(0) => app.goto_screen(Screen::InputMenu(InputOpt::Headers)),
//
// add content-type application/json
Some(1) => {
app.add_app_option(AppOptions::ContentHeaders(HeaderKind::ContentType));
}
//
// add accept application/json
Some(2) => {
app.add_app_option(AppOptions::ContentHeaders(HeaderKind::Accept));
}
//
// accept headers in response
Some(3) => {
app.add_app_option(AppOptions::EnableHeaders);
}
//
// return to request menu
Some(4) => app.goto_screen(Screen::RequestMenu(String::new())),
_ => {}
}
}
2 changes: 1 addition & 1 deletion src/screens/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ use ::tui::prelude::{Color, Text};
use ::tui::style::Style;
use ::tui::widgets::{Block, Borders, Paragraph, Wrap};
pub use screen::Screen;

pub mod error;
pub mod headers;
pub mod saved_commands;

pub fn small_alert_box(r: Rect) -> Rect {
Expand Down
4 changes: 4 additions & 0 deletions src/screens/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::screens::input::input::handle_default_input_screen;

use super::auth::handle_authentication_screen;
use super::downloads::handle_downloads_screen;
use super::headers::handle_headers_screen;
use super::home::handle_home_screen;
use super::input::request_body_input::handle_req_body_input_screen;
use super::method::handle_method_select_screen;
Expand Down Expand Up @@ -188,6 +189,9 @@ pub fn handle_screen<B: Backend>(app: &mut App, frame: &mut Frame<'_, B>, screen
Screen::SavedCommands => {
handle_saved_commands_screen(app, frame);
}
Screen::Headers => {
handle_headers_screen(app, frame);
}
Screen::Error(e) => {
handle_error_screen(app, frame, e);
}
Expand Down
16 changes: 7 additions & 9 deletions src/screens/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,23 @@ pub fn handle_request_menu_screen<B: Backend>(
// Auth
Some(3) => app.goto_screen(Screen::Authentication),
// Headers
Some(4) => app.goto_screen(Screen::InputMenu(InputOpt::Headers)),
Some(4) => app.goto_screen(Screen::Headers),
// Verbose
Some(5) => app.add_app_option(AppOptions::Verbose),
// Enable headers in response
Some(6) => app.add_app_option(AppOptions::EnableHeaders),
// Request Body
Some(7) => app.goto_screen(Screen::RequestBodyInput),
Some(6) => app.goto_screen(Screen::RequestBodyInput),
// Save this command
Some(8) => app.add_app_option(AppOptions::SaveCommand),
Some(7) => app.add_app_option(AppOptions::SaveCommand),
// Save your token or login
Some(9) => {
Some(8) => {
if !app.has_auth() {
app.goto_screen(Screen::RequestMenu(String::from(SAVE_AUTH_ERROR)));
return;
}
app.add_app_option(AppOptions::SaveToken);
}
// Execute command
Some(10) => {
Some(9) => {
if !app.has_url() && !app.has_unix_socket() {
app.goto_screen(Screen::RequestMenu(String::from(VALID_COMMAND_ERROR)));
return;
Expand All @@ -63,9 +61,9 @@ pub fn handle_request_menu_screen<B: Backend>(
}
}
// more options
Some(11) => app.goto_screen(Screen::MoreFlags),
Some(10) => app.goto_screen(Screen::MoreFlags),
// clear options
Some(12) => {
Some(11) => {
app.remove_all_app_options();
app.goto_screen(Screen::Method);
}
Expand Down
16 changes: 13 additions & 3 deletions src/screens/screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ use std::fmt::{Display, Formatter};

use crate::display::inputopt::InputOpt;
use crate::display::menuopts::{
AUTHENTICATION_MENU_OPTIONS, CMD_MENU_OPTIONS, DOWNLOAD_MENU_OPTIONS, KEY_MENU_OPTIONS,
MAIN_MENU_OPTIONS, METHOD_MENU_OPTIONS, MORE_FLAGS_MENU, NEWLINE, OPTION_PADDING_MAX,
OPTION_PADDING_MID, OPTION_PADDING_MIN, REQUEST_MENU_OPTIONS, RESPONSE_MENU_OPTIONS,
AUTHENTICATION_MENU_OPTIONS, CMD_MENU_OPTIONS, DOWNLOAD_MENU_OPTIONS, HEADER_MENU_OPTIONS,
KEY_MENU_OPTIONS, MAIN_MENU_OPTIONS, METHOD_MENU_OPTIONS, MORE_FLAGS_MENU, NEWLINE,
OPTION_PADDING_MAX, OPTION_PADDING_MID, OPTION_PADDING_MIN, REQUEST_MENU_OPTIONS,
RESPONSE_MENU_OPTIONS,
};
use tui::style::{Color, Modifier, Style};
use tui::widgets::{Block, Borders, List, ListItem};
Expand All @@ -30,6 +31,7 @@ pub enum Screen {
Error(String),
ViewBody,
MoreFlags,
Headers,
CmdMenu(usize),
KeysMenu(usize),
RequestBodyInput,
Expand All @@ -52,6 +54,7 @@ impl Display for Screen {
Screen::Error(_) => "Error",
Screen::ViewBody => "ViewBody",
Screen::MoreFlags => "MoreFlags",
Screen::Headers => "Headers",
Screen::CmdMenu(_) => "CmdMenu",
Screen::KeysMenu(_) => "KeysMenu",
Screen::RequestBodyInput => "RequestBodyInput",
Expand Down Expand Up @@ -120,6 +123,13 @@ impl<'a> Screen {
Screen::InputMenu(_) => {
vec![ListItem::new("Input Menu").style(Style::default().fg(Color::Green))]
}
Screen::Headers => {
return HEADER_MENU_OPTIONS
.iter()
.map(|x| format!("{}{}", x, OPTION_PADDING_MID))
.map(|i| ListItem::new(i.clone()))
.collect();
}
Screen::Authentication => {
let len = AUTHENTICATION_MENU_OPTIONS.len();
return AUTHENTICATION_MENU_OPTIONS
Expand Down

0 comments on commit 776619f

Please sign in to comment.