nu_command/network/http/
http_.rs

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            // common to get more than help. Get by default
19            .optional(
20                "URL",
21                SyntaxShape::String,
22                "The URL to fetch the contents from.",
23            )
24            // post
25            .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            // common
37            .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}