|
12 | 12 | #include "base64.hpp"
|
13 | 13 | #include "connect.hpp"
|
14 | 14 | #include "cookie.hpp"
|
| 15 | +#include "file.hpp" |
| 16 | +#include "message.hpp" |
15 | 17 | #include "mime_type.hpp"
|
16 | 18 | #include "multipart_form.hpp"
|
17 | 19 | #include "urlencoded_form.hpp"
|
@@ -96,124 +98,6 @@ can_reuse_connection(
|
96 | 98 | return true;
|
97 | 99 | }
|
98 | 100 |
|
99 |
| -class json_body |
100 |
| -{ |
101 |
| - std::string body_; |
102 |
| - |
103 |
| -public: |
104 |
| - void |
105 |
| - append(core::string_view value) noexcept |
106 |
| - { |
107 |
| - body_.append(value); |
108 |
| - } |
109 |
| - |
110 |
| - void |
111 |
| - append(std::istream& is) |
112 |
| - { |
113 |
| - body_.append(std::istreambuf_iterator<char>{ is }, {}); |
114 |
| - } |
115 |
| - |
116 |
| - core::string_view |
117 |
| - content_type() const noexcept |
118 |
| - { |
119 |
| - return "application/json"; |
120 |
| - } |
121 |
| - |
122 |
| - std::size_t |
123 |
| - content_length() const noexcept |
124 |
| - { |
125 |
| - return body_.size(); |
126 |
| - } |
127 |
| - |
128 |
| - buffers::const_buffer |
129 |
| - body() const noexcept |
130 |
| - { |
131 |
| - return { body_.data(), body_.size() }; |
132 |
| - } |
133 |
| -}; |
134 |
| - |
135 |
| -class message |
136 |
| -{ |
137 |
| - std::variant< |
138 |
| - std::monostate, |
139 |
| - json_body, |
140 |
| - urlencoded_form, |
141 |
| - multipart_form> body_; |
142 |
| -public: |
143 |
| - message() = default; |
144 |
| - |
145 |
| - message(json_body&& json_body) |
146 |
| - : body_{ std::move(json_body) } |
147 |
| - { |
148 |
| - } |
149 |
| - |
150 |
| - message(urlencoded_form&& form) |
151 |
| - : body_{ std::move(form) } |
152 |
| - { |
153 |
| - } |
154 |
| - |
155 |
| - message(multipart_form&& form) |
156 |
| - : body_{ std::move(form) } |
157 |
| - { |
158 |
| - } |
159 |
| - |
160 |
| - void |
161 |
| - set_headers(http_proto::request& req) const |
162 |
| - { |
163 |
| - std::visit( |
164 |
| - [&](auto& f) |
165 |
| - { |
166 |
| - if constexpr(!std::is_same_v< |
167 |
| - decltype(f), const std::monostate&>) |
168 |
| - { |
169 |
| - req.set_method(http_proto::method::post); |
170 |
| - |
171 |
| - auto content_length = f.content_length(); |
172 |
| - req.set_content_length(content_length); |
173 |
| - if(content_length >= 1024 * 1024) |
174 |
| - { |
175 |
| - req.set( |
176 |
| - http_proto::field::expect, |
177 |
| - "100-continue"); |
178 |
| - } |
179 |
| - |
180 |
| - req.set( |
181 |
| - http_proto::field::content_type, |
182 |
| - f.content_type()); |
183 |
| - } |
184 |
| - }, |
185 |
| - body_); |
186 |
| - } |
187 |
| - |
188 |
| - void |
189 |
| - start_serializer( |
190 |
| - http_proto::serializer& ser, |
191 |
| - http_proto::request& req) const |
192 |
| - { |
193 |
| - std::visit( |
194 |
| - [&](auto& f) |
195 |
| - { |
196 |
| - if constexpr(std::is_same_v< |
197 |
| - decltype(f), const multipart_form&>) |
198 |
| - { |
199 |
| - ser.start< |
200 |
| - multipart_form::source>(req, &f); |
201 |
| - } |
202 |
| - else if constexpr( |
203 |
| - std::is_same_v<decltype(f), const json_body&> || |
204 |
| - std::is_same_v<decltype(f), const urlencoded_form&>) |
205 |
| - { |
206 |
| - ser.start(req, f.body()); |
207 |
| - } |
208 |
| - else |
209 |
| - { |
210 |
| - ser.start(req); |
211 |
| - } |
212 |
| - }, |
213 |
| - body_); |
214 |
| - } |
215 |
| -}; |
216 |
| - |
217 | 101 | http_proto::request
|
218 | 102 | create_request(
|
219 | 103 | const po::variables_map& vm,
|
@@ -629,6 +513,9 @@ main(int argc, char* argv[])
|
629 | 513 | ("unix-socket",
|
630 | 514 | po::value<std::string>()->value_name("<path>"),
|
631 | 515 | "Connect through this Unix domain socket")
|
| 516 | + ("upload-file,T", |
| 517 | + po::value<std::string>()->value_name("<file>"), |
| 518 | + "Transfer local FILE to destination") |
632 | 519 | ("url",
|
633 | 520 | po::value<std::string>()->value_name("<url>"),
|
634 | 521 | "URL to work with")
|
@@ -774,9 +661,14 @@ main(int argc, char* argv[])
|
774 | 661 |
|
775 | 662 | auto msg = message{};
|
776 | 663 |
|
777 |
| - if((!!vm.count("form") + !!vm.count("data") + !!vm.count("json")) == 2) |
| 664 | + if((!!vm.count("form") + |
| 665 | + !!vm.count("data") + |
| 666 | + !!vm.count("json") + |
| 667 | + !!vm.count("upload-file")) == 2) |
| 668 | + { |
778 | 669 | throw std::runtime_error{
|
779 | 670 | "You can only select one HTTP request method"};
|
| 671 | + } |
780 | 672 |
|
781 | 673 | if(vm.count("form"))
|
782 | 674 | {
|
@@ -872,6 +764,30 @@ main(int argc, char* argv[])
|
872 | 764 | msg = std::move(body);
|
873 | 765 | }
|
874 | 766 |
|
| 767 | + if(vm.count("upload-file")) |
| 768 | + { |
| 769 | + msg = [&]()-> message |
| 770 | + { |
| 771 | + auto path = vm.at("upload-file").as<std::string>(); |
| 772 | + if(path == "-") |
| 773 | + return stdin_body{}; |
| 774 | + |
| 775 | + // Append the filename to the URL if it |
| 776 | + // doesn't already end with one |
| 777 | + auto segs = url.encoded_segments(); |
| 778 | + if(segs.empty()) |
| 779 | + { |
| 780 | + segs.push_back(::filename(path)); |
| 781 | + } |
| 782 | + else if(auto back = --segs.end(); back->empty()) |
| 783 | + { |
| 784 | + segs.replace(back, ::filename(path)); |
| 785 | + } |
| 786 | + |
| 787 | + return file_body{ std::move(path) }; |
| 788 | + }(); |
| 789 | + } |
| 790 | + |
875 | 791 | auto cookie_jar = std::optional<::cookie_jar>{};
|
876 | 792 | auto explicit_cookies = std::string{};
|
877 | 793 |
|
|
0 commit comments