1use nu_engine::{command_prelude::*, get_full_help};
2
3use super::client::RedirectMode;
4use super::get::run_get;
5use super::post::run_post;
6
7#[derive(Clone)]
8pub struct Http;
9
10impl Command for Http {
11 fn name(&self) -> &str {
12 "http"
13 }
14
15 fn signature(&self) -> Signature {
16 Signature::build("http")
17 .input_output_types(vec![(Type::Nothing, Type::Any)])
18 .optional(
20 "URL",
21 SyntaxShape::String,
22 "The URL to fetch the contents from.",
23 )
24 .optional(
26 "data",
27 SyntaxShape::Any,
28 "The contents of the post body. Required unless part of a pipeline.",
29 )
30 .named(
31 "content-type",
32 SyntaxShape::Any,
33 "the MIME type of content to post",
34 Some('t'),
35 )
36 .named(
38 "user",
39 SyntaxShape::Any,
40 "the username when authenticating",
41 Some('u'),
42 )
43 .named(
44 "password",
45 SyntaxShape::Any,
46 "the password when authenticating",
47 Some('p'),
48 )
49 .named(
50 "max-time",
51 SyntaxShape::Duration,
52 "max duration before timeout occurs",
53 Some('m'),
54 )
55 .named(
56 "headers",
57 SyntaxShape::Any,
58 "custom headers you want to add ",
59 Some('H'),
60 )
61 .switch(
62 "raw",
63 "fetch contents as text rather than a table",
64 Some('r'),
65 )
66 .switch(
67 "insecure",
68 "allow insecure server connections when using SSL",
69 Some('k'),
70 )
71 .switch(
72 "full",
73 "Returns the record, containing metainformation about the exchange in addition to \
74 the response.
75 Returning record fields:
76 - urls: list of url redirects this command had to make to get to the destination
77 - headers.request: list of headers passed when doing the request
78 - headers.response: list of received headers
79 - body: the http body of the response
80 - status: the http status of the response\n",
81 Some('f'),
82 )
83 .switch(
84 "allow-errors",
85 "do not fail if the server returns an error code",
86 Some('e'),
87 )
88 .param(
89 Flag::new("redirect-mode")
90 .short('R')
91 .arg(SyntaxShape::String)
92 .desc(
93 "What to do when encountering redirects. Default: 'follow'. Valid \
94 options: 'follow' ('f'), 'manual' ('m'), 'error' ('e').",
95 )
96 .completion(Completion::new_list(RedirectMode::MODES)),
97 )
98 .category(Category::Network)
99 }
100
101 fn description(&self) -> &str {
102 "Various commands for working with http methods."
103 }
104
105 fn extra_description(&self) -> &str {
106 "Without a subcommand but with a URL provided, it performs a GET request by default or a POST request if data is provided. You can use one of the following subcommands. Using this command as-is will only display this help message."
107 }
108
109 fn search_terms(&self) -> Vec<&str> {
110 vec![
111 "network", "fetch", "pull", "request", "download", "curl", "wget",
112 ]
113 }
114
115 fn run(
116 &self,
117 engine_state: &EngineState,
118 stack: &mut Stack,
119 call: &Call,
120 input: PipelineData,
121 ) -> Result<PipelineData, ShellError> {
122 let url = call.opt::<Value>(engine_state, stack, 0)?;
123 let data = call.opt::<Value>(engine_state, stack, 1)?;
124 match (url.is_some(), data.is_some()) {
125 (true, true) => run_post(engine_state, stack, call, input),
126 (true, false) => run_get(engine_state, stack, call, input),
127 (false, true) => Err(ShellError::NushellFailed {
128 msg: (String::from("Default verb is get with a payload. Impossible state")),
129 }),
130 (false, false) => Ok(Value::string(
131 get_full_help(self, engine_state, stack),
132 call.head,
133 )
134 .into_pipeline_data()),
135 }
136 }
137
138 fn examples(&self) -> Vec<Example<'_>> {
139 vec![
140 Example {
141 description: "Get content from example.com with default verb",
142 example: "http https://www.example.com",
143 result: None,
144 },
145 Example {
146 description: "Post content to example.com with default verb",
147 example: "http https://www.example.com 'body'",
148 result: None,
149 },
150 Example {
151 description: "Get content from example.com with explicit verb",
152 example: "http get https://www.example.com",
153 result: None,
154 },
155 ]
156 }
157}