rune_modules/http.rs
1//! The native `http` module for the [Rune Language].
2//!
3//! [Rune Language]: https://rune-rs.github.io
4//!
5//! ## Usage
6//!
7//! Add the following to your `Cargo.toml`:
8//!
9//! ```toml
10//! rune-modules = { version = "0.14.1", features = ["http", "json"] }
11//! ```
12//!
13//! Install it into your context:
14//!
15//! ```rust
16//! let mut context = rune::Context::with_default_modules()?;
17//! context.install(rune_modules::http::module(true)?)?;
18//! context.install(rune_modules::json::module(true)?)?;
19//! # Ok::<_, rune::support::Error>(())
20//! ```
21//!
22//! Use it in Rune:
23//!
24//! ```rust,ignore
25//! use http;
26//! use json;
27//!
28//! fn main() {
29//! let client = http::Client::new();
30//! let response = client.get("http://worldtimeapi.org/api/ip");
31//! let text = response.text();
32//! let json = json::from_string(text);
33//!
34//! let timezone = json["timezone"];
35//!
36//! if timezone is String {
37//! dbg(timezone);
38//! }
39//!
40//! let body = json::to_bytes(#{"hello": "world"});
41//!
42//! let response = client.post("https://postman-echo.com/post")
43//! .body_bytes(body)
44//! .send();
45//!
46//! let response = json::from_string(response.text());
47//! dbg(response);
48//! }
49//! ```
50
51use core::cmp::Ordering;
52use core::hash::Hash;
53
54use rune::alloc::fmt::TryWrite;
55use rune::alloc::prelude::*;
56use rune::runtime::{Bytes, Formatter, Hasher, Ref, VmResult};
57use rune::{docstring, item, Any, ContextError, Module, ToConstValue, Value};
58
59/// A simple HTTP module for Rune.
60///
61/// # Examples
62///
63/// ```rune,no_run
64/// let res = http::get("https://httpstat.us/200?sleep=100").await;
65///
66/// dbg!(res.text().await?);
67/// ```
68#[rune::module(::http)]
69pub fn module(_stdio: bool) -> Result<Module, ContextError> {
70 let mut module = Module::from_meta(self::module_meta)?;
71
72 module.function_meta(get)?;
73
74 module.ty::<Client>()?;
75 module.function_meta(Client::new__meta)?;
76 module.function_meta(Client::get__meta)?;
77 module.function_meta(Client::post__meta)?;
78 module.function_meta(Client::put__meta)?;
79 module.function_meta(Client::delete__meta)?;
80 module.function_meta(Client::head__meta)?;
81
82 module.ty::<Response>()?;
83 module.function_meta(Response::text__meta)?;
84 module.function_meta(Response::json__meta)?;
85 module.function_meta(Response::bytes__meta)?;
86 module.function_meta(Response::status__meta)?;
87 module.function_meta(Response::version__meta)?;
88 module.function_meta(Response::content_length__meta)?;
89
90 module.ty::<RequestBuilder>()?;
91 module.function_meta(RequestBuilder::send__meta)?;
92 module.function_meta(RequestBuilder::header__meta)?;
93 module.function_meta(RequestBuilder::basic_auth__meta)?;
94 module.function_meta(RequestBuilder::bearer_auth__meta)?;
95 module.function_meta(RequestBuilder::fetch_mode_no_cors__meta)?;
96 module.function_meta(RequestBuilder::body_bytes__meta)?;
97
98 module.ty::<StatusCode>()?;
99 module.function_meta(StatusCode::as_u16__meta)?;
100 module.function_meta(StatusCode::as_str__meta)?;
101 module.function_meta(StatusCode::canonical_reason__meta)?;
102 module.function_meta(StatusCode::is_informational__meta)?;
103 module.function_meta(StatusCode::is_success__meta)?;
104 module.function_meta(StatusCode::is_redirection__meta)?;
105 module.function_meta(StatusCode::is_client_error__meta)?;
106 module.function_meta(StatusCode::is_server_error__meta)?;
107 module.function_meta(StatusCode::partial_eq__meta)?;
108 module.implement_trait::<StatusCode>(item!(::std::cmp::PartialEq))?;
109 module.function_meta(StatusCode::eq__meta)?;
110 module.implement_trait::<StatusCode>(item!(::std::cmp::Eq))?;
111 module.function_meta(StatusCode::partial_cmp__meta)?;
112 module.implement_trait::<StatusCode>(item!(::std::cmp::PartialOrd))?;
113 module.function_meta(StatusCode::cmp__meta)?;
114 module.implement_trait::<StatusCode>(item!(::std::cmp::Ord))?;
115 module.function_meta(StatusCode::hash__meta)?;
116 module.function_meta(StatusCode::debug_fmt__meta)?;
117 module.function_meta(StatusCode::display_fmt__meta)?;
118
119 module
120 .constant(
121 "CONTINUE",
122 StatusCode {
123 inner: reqwest::StatusCode::CONTINUE,
124 },
125 )
126 .build_associated::<StatusCode>()?
127 .docs(docstring! {
128 /// Status Code: Continue
129 ///
130 /// # Examples
131 ///
132 /// ```rune
133 /// use http::StatusCode;
134 ///
135 /// let status_code = StatusCode::CONTINUE;
136 /// ```
137 })?;
138
139 module
140 .constant(
141 "SWITCHING_PROTOCOLS",
142 StatusCode {
143 inner: reqwest::StatusCode::SWITCHING_PROTOCOLS,
144 },
145 )
146 .build_associated::<StatusCode>()?
147 .docs(docstring! {
148 /// Status Code: Switching Protocols
149 ///
150 /// # Examples
151 ///
152 /// ```rune
153 /// use http::StatusCode;
154 ///
155 /// let status_code = StatusCode::SWITCHING_PROTOCOLS;
156 /// ```
157 })?;
158
159 module
160 .constant(
161 "PROCESSING",
162 StatusCode {
163 inner: reqwest::StatusCode::PROCESSING,
164 },
165 )
166 .build_associated::<StatusCode>()?
167 .docs(docstring! {
168 /// Status Code: Processing
169 ///
170 /// # Examples
171 ///
172 /// ```rune
173 /// use http::StatusCode;
174 ///
175 /// let status_code = StatusCode::PROCESSING;
176 /// ```
177 })?;
178
179 module
180 .constant(
181 "OK",
182 StatusCode {
183 inner: reqwest::StatusCode::OK,
184 },
185 )
186 .build_associated::<StatusCode>()?
187 .docs(docstring! {
188 /// Status Code: OK
189 ///
190 /// # Examples
191 ///
192 /// ```rune
193 /// use http::StatusCode;
194 ///
195 /// let status_code = StatusCode::OK;
196 /// ```
197 })?;
198
199 module
200 .constant(
201 "CREATED",
202 StatusCode {
203 inner: reqwest::StatusCode::CREATED,
204 },
205 )
206 .build_associated::<StatusCode>()?
207 .docs(docstring! {
208 /// Status Code: Created
209 ///
210 /// # Examples
211 ///
212 /// ```rune
213 /// use http::StatusCode;
214 ///
215 /// let status_code = StatusCode::CREATED;
216 /// ```
217 })?;
218
219 module
220 .constant(
221 "ACCEPTED",
222 StatusCode {
223 inner: reqwest::StatusCode::ACCEPTED,
224 },
225 )
226 .build_associated::<StatusCode>()?
227 .docs(docstring! {
228 /// Status Code: Accepted
229 ///
230 /// # Examples
231 ///
232 /// ```rune
233 /// use http::StatusCode;
234 ///
235 /// let status_code = StatusCode::ACCEPTED;
236 /// ```
237 })?;
238
239 module
240 .constant(
241 "NON_AUTHORITATIVE_INFORMATION",
242 StatusCode {
243 inner: reqwest::StatusCode::NON_AUTHORITATIVE_INFORMATION,
244 },
245 )
246 .build_associated::<StatusCode>()?
247 .docs(docstring! {
248 /// Status Code: Non Authoritative Information
249 ///
250 /// # Examples
251 ///
252 /// ```rune
253 /// use http::StatusCode;
254 ///
255 /// let status_code = StatusCode::NON_AUTHORITATIVE_INFORMATION;
256 /// ```
257 })?;
258
259 module
260 .constant(
261 "NO_CONTENT",
262 StatusCode {
263 inner: reqwest::StatusCode::NO_CONTENT,
264 },
265 )
266 .build_associated::<StatusCode>()?
267 .docs(docstring! {
268 /// Status Code: No Content
269 ///
270 /// # Examples
271 ///
272 /// ```rune
273 /// use http::StatusCode;
274 ///
275 /// let status_code = StatusCode::NO_CONTENT;
276 /// ```
277 })?;
278
279 module
280 .constant(
281 "RESET_CONTENT",
282 StatusCode {
283 inner: reqwest::StatusCode::RESET_CONTENT,
284 },
285 )
286 .build_associated::<StatusCode>()?
287 .docs(docstring! {
288 /// Status Code: Reset Content
289 ///
290 /// # Examples
291 ///
292 /// ```rune
293 /// use http::StatusCode;
294 ///
295 /// let status_code = StatusCode::RESET_CONTENT;
296 /// ```
297 })?;
298
299 module
300 .constant(
301 "PARTIAL_CONTENT",
302 StatusCode {
303 inner: reqwest::StatusCode::PARTIAL_CONTENT,
304 },
305 )
306 .build_associated::<StatusCode>()?
307 .docs(docstring! {
308 /// Status Code: Partial Content
309 ///
310 /// # Examples
311 ///
312 /// ```rune
313 /// use http::StatusCode;
314 ///
315 /// let status_code = StatusCode::PARTIAL_CONTENT;
316 /// ```
317 })?;
318
319 module
320 .constant(
321 "MULTI_STATUS",
322 StatusCode {
323 inner: reqwest::StatusCode::MULTI_STATUS,
324 },
325 )
326 .build_associated::<StatusCode>()?
327 .docs(docstring! {
328 /// Status Code: Multi-Status
329 ///
330 /// # Examples
331 ///
332 /// ```rune
333 /// use http::StatusCode;
334 ///
335 /// let status_code = StatusCode::MULTI_STATUS;
336 /// ```
337 })?;
338
339 module
340 .constant(
341 "ALREADY_REPORTED",
342 StatusCode {
343 inner: reqwest::StatusCode::ALREADY_REPORTED,
344 },
345 )
346 .build_associated::<StatusCode>()?
347 .docs(docstring! {
348 /// Status Code: Already Reported
349 ///
350 /// # Examples
351 ///
352 /// ```rune
353 /// use http::StatusCode;
354 ///
355 /// let status_code = StatusCode::ALREADY_REPORTED;
356 /// ```
357 })?;
358
359 module
360 .constant(
361 "IM_USED",
362 StatusCode {
363 inner: reqwest::StatusCode::IM_USED,
364 },
365 )
366 .build_associated::<StatusCode>()?
367 .docs(docstring! {
368 /// Status Code: IM Used
369 ///
370 /// # Examples
371 ///
372 /// ```rune
373 /// use http::StatusCode;
374 ///
375 /// let status_code = StatusCode::IM_USED;
376 /// ```
377 })?;
378
379 module
380 .constant(
381 "MULTIPLE_CHOICES",
382 StatusCode {
383 inner: reqwest::StatusCode::MULTIPLE_CHOICES,
384 },
385 )
386 .build_associated::<StatusCode>()?
387 .docs(docstring! {
388 /// Status Code: Multiple Choices
389 ///
390 /// # Examples
391 ///
392 /// ```rune
393 /// use http::StatusCode;
394 ///
395 /// let status_code = StatusCode::MULTIPLE_CHOICES;
396 /// ```
397 })?;
398
399 module
400 .constant(
401 "MOVED_PERMANENTLY",
402 StatusCode {
403 inner: reqwest::StatusCode::MOVED_PERMANENTLY,
404 },
405 )
406 .build_associated::<StatusCode>()?
407 .docs(docstring! {
408 /// Status Code: Moved Permanently
409 ///
410 /// # Examples
411 ///
412 /// ```rune
413 /// use http::StatusCode;
414 ///
415 /// let status_code = StatusCode::MOVED_PERMANENTLY;
416 /// ```
417 })?;
418
419 module
420 .constant(
421 "FOUND",
422 StatusCode {
423 inner: reqwest::StatusCode::FOUND,
424 },
425 )
426 .build_associated::<StatusCode>()?
427 .docs(docstring! {
428 /// Status Code: Found
429 ///
430 /// # Examples
431 ///
432 /// ```rune
433 /// use http::StatusCode;
434 ///
435 /// let status_code = StatusCode::FOUND;
436 /// ```
437 })?;
438
439 module
440 .constant(
441 "SEE_OTHER",
442 StatusCode {
443 inner: reqwest::StatusCode::SEE_OTHER,
444 },
445 )
446 .build_associated::<StatusCode>()?
447 .docs(docstring! {
448 /// Status Code: See Other
449 ///
450 /// # Examples
451 ///
452 /// ```rune
453 /// use http::StatusCode;
454 ///
455 /// let status_code = StatusCode::SEE_OTHER;
456 /// ```
457 })?;
458
459 module
460 .constant(
461 "NOT_MODIFIED",
462 StatusCode {
463 inner: reqwest::StatusCode::NOT_MODIFIED,
464 },
465 )
466 .build_associated::<StatusCode>()?
467 .docs(docstring! {
468 /// Status Code: Not Modified
469 ///
470 /// # Examples
471 ///
472 /// ```rune
473 /// use http::StatusCode;
474 ///
475 /// let status_code = StatusCode::NOT_MODIFIED;
476 /// ```
477 })?;
478
479 module
480 .constant(
481 "USE_PROXY",
482 StatusCode {
483 inner: reqwest::StatusCode::USE_PROXY,
484 },
485 )
486 .build_associated::<StatusCode>()?
487 .docs(docstring! {
488 /// Status Code: Use Proxy
489 ///
490 /// # Examples
491 ///
492 /// ```rune
493 /// use http::StatusCode;
494 ///
495 /// let status_code = StatusCode::USE_PROXY;
496 /// ```
497 })?;
498
499 module
500 .constant(
501 "TEMPORARY_REDIRECT",
502 StatusCode {
503 inner: reqwest::StatusCode::TEMPORARY_REDIRECT,
504 },
505 )
506 .build_associated::<StatusCode>()?
507 .docs(docstring! {
508 /// Status Code: Temporary Redirect
509 ///
510 /// # Examples
511 ///
512 /// ```rune
513 /// use http::StatusCode;
514 ///
515 /// let status_code = StatusCode::TEMPORARY_REDIRECT;
516 /// ```
517 })?;
518
519 module
520 .constant(
521 "PERMANENT_REDIRECT",
522 StatusCode {
523 inner: reqwest::StatusCode::PERMANENT_REDIRECT,
524 },
525 )
526 .build_associated::<StatusCode>()?
527 .docs(docstring! {
528 /// Status Code: Permanent Redirect
529 ///
530 /// # Examples
531 ///
532 /// ```rune
533 /// use http::StatusCode;
534 ///
535 /// let status_code = StatusCode::PERMANENT_REDIRECT;
536 /// ```
537 })?;
538
539 module
540 .constant(
541 "BAD_REQUEST",
542 StatusCode {
543 inner: reqwest::StatusCode::BAD_REQUEST,
544 },
545 )
546 .build_associated::<StatusCode>()?
547 .docs(docstring! {
548 /// Status Code: Bad Request
549 ///
550 /// # Examples
551 ///
552 /// ```rune
553 /// use http::StatusCode;
554 ///
555 /// let status_code = StatusCode::BAD_REQUEST;
556 /// ```
557 })?;
558
559 module
560 .constant(
561 "UNAUTHORIZED",
562 StatusCode {
563 inner: reqwest::StatusCode::UNAUTHORIZED,
564 },
565 )
566 .build_associated::<StatusCode>()?
567 .docs(docstring! {
568 /// Status Code: Unauthorized
569 ///
570 /// # Examples
571 ///
572 /// ```rune
573 /// use http::StatusCode;
574 ///
575 /// let status_code = StatusCode::UNAUTHORIZED;
576 /// ```
577 })?;
578
579 module
580 .constant(
581 "PAYMENT_REQUIRED",
582 StatusCode {
583 inner: reqwest::StatusCode::PAYMENT_REQUIRED,
584 },
585 )
586 .build_associated::<StatusCode>()?
587 .docs(docstring! {
588 /// Status Code: Payment Required
589 ///
590 /// # Examples
591 ///
592 /// ```rune
593 /// use http::StatusCode;
594 ///
595 /// let status_code = StatusCode::PAYMENT_REQUIRED;
596 /// ```
597 })?;
598
599 module
600 .constant(
601 "FORBIDDEN",
602 StatusCode {
603 inner: reqwest::StatusCode::FORBIDDEN,
604 },
605 )
606 .build_associated::<StatusCode>()?
607 .docs(docstring! {
608 /// Status Code: Forbidden
609 ///
610 /// # Examples
611 ///
612 /// ```rune
613 /// use http::StatusCode;
614 ///
615 /// let status_code = StatusCode::FORBIDDEN;
616 /// ```
617 })?;
618
619 module
620 .constant(
621 "NOT_FOUND",
622 StatusCode {
623 inner: reqwest::StatusCode::NOT_FOUND,
624 },
625 )
626 .build_associated::<StatusCode>()?
627 .docs(docstring! {
628 /// Status Code: Not Found
629 ///
630 /// # Examples
631 ///
632 /// ```rune
633 /// use http::StatusCode;
634 ///
635 /// let status_code = StatusCode::NOT_FOUND;
636 /// ```
637 })?;
638
639 module
640 .constant(
641 "METHOD_NOT_ALLOWED",
642 StatusCode {
643 inner: reqwest::StatusCode::METHOD_NOT_ALLOWED,
644 },
645 )
646 .build_associated::<StatusCode>()?
647 .docs(docstring! {
648 /// Status Code: Method Not Allowed
649 ///
650 /// # Examples
651 ///
652 /// ```rune
653 /// use http::StatusCode;
654 ///
655 /// let status_code = StatusCode::METHOD_NOT_ALLOWED;
656 /// ```
657 })?;
658
659 module
660 .constant(
661 "NOT_ACCEPTABLE",
662 StatusCode {
663 inner: reqwest::StatusCode::NOT_ACCEPTABLE,
664 },
665 )
666 .build_associated::<StatusCode>()?
667 .docs(docstring! {
668 /// Status Code: Not Acceptable
669 ///
670 /// # Examples
671 ///
672 /// ```rune
673 /// use http::StatusCode;
674 ///
675 /// let status_code = StatusCode::NOT_ACCEPTABLE;
676 /// ```
677 })?;
678
679 module
680 .constant(
681 "PROXY_AUTHENTICATION_REQUIRED",
682 StatusCode {
683 inner: reqwest::StatusCode::PROXY_AUTHENTICATION_REQUIRED,
684 },
685 )
686 .build_associated::<StatusCode>()?
687 .docs(docstring! {
688 /// Status Code: Proxy Authentication Required
689 ///
690 /// # Examples
691 ///
692 /// ```rune
693 /// use http::StatusCode;
694 ///
695 /// let status_code = StatusCode::PROXY_AUTHENTICATION_REQUIRED;
696 /// ```
697 })?;
698
699 module
700 .constant(
701 "REQUEST_TIMEOUT",
702 StatusCode {
703 inner: reqwest::StatusCode::REQUEST_TIMEOUT,
704 },
705 )
706 .build_associated::<StatusCode>()?
707 .docs(docstring! {
708 /// Status Code: Request Timeout
709 ///
710 /// # Examples
711 ///
712 /// ```rune
713 /// use http::StatusCode;
714 ///
715 /// let status_code = StatusCode::REQUEST_TIMEOUT;
716 /// ```
717 })?;
718
719 module
720 .constant(
721 "CONFLICT",
722 StatusCode {
723 inner: reqwest::StatusCode::CONFLICT,
724 },
725 )
726 .build_associated::<StatusCode>()?
727 .docs(docstring! {
728 /// Status Code: Conflict
729 ///
730 /// # Examples
731 ///
732 /// ```rune
733 /// use http::StatusCode;
734 ///
735 /// let status_code = StatusCode::CONFLICT;
736 /// ```
737 })?;
738
739 module
740 .constant(
741 "GONE",
742 StatusCode {
743 inner: reqwest::StatusCode::GONE,
744 },
745 )
746 .build_associated::<StatusCode>()?
747 .docs(docstring! {
748 /// Status Code: Gone
749 ///
750 /// # Examples
751 ///
752 /// ```rune
753 /// use http::StatusCode;
754 ///
755 /// let status_code = StatusCode::GONE;
756 /// ```
757 })?;
758
759 module
760 .constant(
761 "LENGTH_REQUIRED",
762 StatusCode {
763 inner: reqwest::StatusCode::LENGTH_REQUIRED,
764 },
765 )
766 .build_associated::<StatusCode>()?
767 .docs(docstring! {
768 /// Status Code: Length Required
769 ///
770 /// # Examples
771 ///
772 /// ```rune
773 /// use http::StatusCode;
774 ///
775 /// let status_code = StatusCode::LENGTH_REQUIRED;
776 /// ```
777 })?;
778
779 module
780 .constant(
781 "PRECONDITION_FAILED",
782 StatusCode {
783 inner: reqwest::StatusCode::PRECONDITION_FAILED,
784 },
785 )
786 .build_associated::<StatusCode>()?
787 .docs(docstring! {
788 /// Status Code: Precondition Failed
789 ///
790 /// # Examples
791 ///
792 /// ```rune
793 /// use http::StatusCode;
794 ///
795 /// let status_code = StatusCode::PRECONDITION_FAILED;
796 /// ```
797 })?;
798
799 module
800 .constant(
801 "PAYLOAD_TOO_LARGE",
802 StatusCode {
803 inner: reqwest::StatusCode::PAYLOAD_TOO_LARGE,
804 },
805 )
806 .build_associated::<StatusCode>()?
807 .docs(docstring! {
808 /// Status Code: Payload Too Large
809 ///
810 /// # Examples
811 ///
812 /// ```rune
813 /// use http::StatusCode;
814 ///
815 /// let status_code = StatusCode::PAYLOAD_TOO_LARGE;
816 /// ```
817 })?;
818
819 module
820 .constant(
821 "URI_TOO_LONG",
822 StatusCode {
823 inner: reqwest::StatusCode::URI_TOO_LONG,
824 },
825 )
826 .build_associated::<StatusCode>()?
827 .docs(docstring! {
828 /// Status Code: URI Too Long
829 ///
830 /// # Examples
831 ///
832 /// ```rune
833 /// use http::StatusCode;
834 ///
835 /// let status_code = StatusCode::URI_TOO_LONG;
836 /// ```
837 })?;
838
839 module
840 .constant(
841 "UNSUPPORTED_MEDIA_TYPE",
842 StatusCode {
843 inner: reqwest::StatusCode::UNSUPPORTED_MEDIA_TYPE,
844 },
845 )
846 .build_associated::<StatusCode>()?
847 .docs(docstring! {
848 /// Status Code: Unsupported Media Type
849 ///
850 /// # Examples
851 ///
852 /// ```rune
853 /// use http::StatusCode;
854 ///
855 /// let status_code = StatusCode::UNSUPPORTED_MEDIA_TYPE;
856 /// ```
857 })?;
858
859 module
860 .constant(
861 "RANGE_NOT_SATISFIABLE",
862 StatusCode {
863 inner: reqwest::StatusCode::RANGE_NOT_SATISFIABLE,
864 },
865 )
866 .build_associated::<StatusCode>()?
867 .docs(docstring! {
868 /// Status Code: Range Not Satisfiable
869 ///
870 /// # Examples
871 ///
872 /// ```rune
873 /// use http::StatusCode;
874 ///
875 /// let status_code = StatusCode::RANGE_NOT_SATISFIABLE;
876 /// ```
877 })?;
878
879 module
880 .constant(
881 "EXPECTATION_FAILED",
882 StatusCode {
883 inner: reqwest::StatusCode::EXPECTATION_FAILED,
884 },
885 )
886 .build_associated::<StatusCode>()?
887 .docs(docstring! {
888 /// Status Code: Expectation Failed
889 ///
890 /// # Examples
891 ///
892 /// ```rune
893 /// use http::StatusCode;
894 ///
895 /// let status_code = StatusCode::EXPECTATION_FAILED;
896 /// ```
897 })?;
898
899 module
900 .constant(
901 "IM_A_TEAPOT",
902 StatusCode {
903 inner: reqwest::StatusCode::IM_A_TEAPOT,
904 },
905 )
906 .build_associated::<StatusCode>()?
907 .docs(docstring! {
908 /// Status Code: I'm a teapot
909 ///
910 /// # Examples
911 ///
912 /// ```rune
913 /// use http::StatusCode;
914 ///
915 /// let status_code = StatusCode::IM_A_TEAPOT;
916 /// ```
917 })?;
918
919 module
920 .constant(
921 "MISDIRECTED_REQUEST",
922 StatusCode {
923 inner: reqwest::StatusCode::MISDIRECTED_REQUEST,
924 },
925 )
926 .build_associated::<StatusCode>()?
927 .docs(docstring! {
928 /// Status Code: Misdirected Request
929 ///
930 /// # Examples
931 ///
932 /// ```rune
933 /// use http::StatusCode;
934 ///
935 /// let status_code = StatusCode::MISDIRECTED_REQUEST;
936 /// ```
937 })?;
938
939 module
940 .constant(
941 "UNPROCESSABLE_ENTITY",
942 StatusCode {
943 inner: reqwest::StatusCode::UNPROCESSABLE_ENTITY,
944 },
945 )
946 .build_associated::<StatusCode>()?
947 .docs(docstring! {
948 /// Status Code: Unprocessable Entity
949 ///
950 /// # Examples
951 ///
952 /// ```rune
953 /// use http::StatusCode;
954 ///
955 /// let status_code = StatusCode::UNPROCESSABLE_ENTITY;
956 /// ```
957 })?;
958
959 module
960 .constant(
961 "LOCKED",
962 StatusCode {
963 inner: reqwest::StatusCode::LOCKED,
964 },
965 )
966 .build_associated::<StatusCode>()?
967 .docs(docstring! {
968 /// Status Code: Locked
969 ///
970 /// # Examples
971 ///
972 /// ```rune
973 /// use http::StatusCode;
974 ///
975 /// let status_code = StatusCode::LOCKED;
976 /// ```
977 })?;
978
979 module
980 .constant(
981 "FAILED_DEPENDENCY",
982 StatusCode {
983 inner: reqwest::StatusCode::FAILED_DEPENDENCY,
984 },
985 )
986 .build_associated::<StatusCode>()?
987 .docs(docstring! {
988 /// Status Code: Failed Dependency
989 ///
990 /// # Examples
991 ///
992 /// ```rune
993 /// use http::StatusCode;
994 ///
995 /// let status_code = StatusCode::FAILED_DEPENDENCY;
996 /// ```
997 })?;
998
999 module
1000 .constant(
1001 "UPGRADE_REQUIRED",
1002 StatusCode {
1003 inner: reqwest::StatusCode::UPGRADE_REQUIRED,
1004 },
1005 )
1006 .build_associated::<StatusCode>()?
1007 .docs(docstring! {
1008 /// Status Code: Upgrade Required
1009 ///
1010 /// # Examples
1011 ///
1012 /// ```rune
1013 /// use http::StatusCode;
1014 ///
1015 /// let status_code = StatusCode::UPGRADE_REQUIRED;
1016 /// ```
1017 })?;
1018
1019 module
1020 .constant(
1021 "PRECONDITION_REQUIRED",
1022 StatusCode {
1023 inner: reqwest::StatusCode::PRECONDITION_REQUIRED,
1024 },
1025 )
1026 .build_associated::<StatusCode>()?
1027 .docs(docstring! {
1028 /// Status Code: Precondition Required
1029 ///
1030 /// # Examples
1031 ///
1032 /// ```rune
1033 /// use http::StatusCode;
1034 ///
1035 /// let status_code = StatusCode::PRECONDITION_REQUIRED;
1036 /// ```
1037 })?;
1038
1039 module
1040 .constant(
1041 "TOO_MANY_REQUESTS",
1042 StatusCode {
1043 inner: reqwest::StatusCode::TOO_MANY_REQUESTS,
1044 },
1045 )
1046 .build_associated::<StatusCode>()?
1047 .docs(docstring! {
1048 /// Status Code: Too Many Requests
1049 ///
1050 /// # Examples
1051 ///
1052 /// ```rune
1053 /// use http::StatusCode;
1054 ///
1055 /// let status_code = StatusCode::TOO_MANY_REQUESTS;
1056 /// ```
1057 })?;
1058
1059 module
1060 .constant(
1061 "REQUEST_HEADER_FIELDS_TOO_LARGE",
1062 StatusCode {
1063 inner: reqwest::StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE,
1064 },
1065 )
1066 .build_associated::<StatusCode>()?
1067 .docs(docstring! {
1068 /// Status Code: Request Header Fields Too Large
1069 ///
1070 /// # Examples
1071 ///
1072 /// ```rune
1073 /// use http::StatusCode;
1074 ///
1075 /// let status_code = StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE;
1076 /// ```
1077 })?;
1078
1079 module
1080 .constant(
1081 "UNAVAILABLE_FOR_LEGAL_REASONS",
1082 StatusCode {
1083 inner: reqwest::StatusCode::UNAVAILABLE_FOR_LEGAL_REASONS,
1084 },
1085 )
1086 .build_associated::<StatusCode>()?
1087 .docs(docstring! {
1088 /// Status Code: Unavailable For Legal Reasons
1089 ///
1090 /// # Examples
1091 ///
1092 /// ```rune
1093 /// use http::StatusCode;
1094 ///
1095 /// let status_code = StatusCode::UNAVAILABLE_FOR_LEGAL_REASONS;
1096 /// ```
1097 })?;
1098
1099 module
1100 .constant(
1101 "INTERNAL_SERVER_ERROR",
1102 StatusCode {
1103 inner: reqwest::StatusCode::INTERNAL_SERVER_ERROR,
1104 },
1105 )
1106 .build_associated::<StatusCode>()?
1107 .docs(docstring! {
1108 /// Status Code: Internal Server Error
1109 ///
1110 /// # Examples
1111 ///
1112 /// ```rune
1113 /// use http::StatusCode;
1114 ///
1115 /// let status_code = StatusCode::INTERNAL_SERVER_ERROR;
1116 /// ```
1117 })?;
1118
1119 module
1120 .constant(
1121 "NOT_IMPLEMENTED",
1122 StatusCode {
1123 inner: reqwest::StatusCode::NOT_IMPLEMENTED,
1124 },
1125 )
1126 .build_associated::<StatusCode>()?
1127 .docs(docstring! {
1128 /// Status Code: Not Implemented
1129 ///
1130 /// # Examples
1131 ///
1132 /// ```rune
1133 /// use http::StatusCode;
1134 ///
1135 /// let status_code = StatusCode::NOT_IMPLEMENTED;
1136 /// ```
1137 })?;
1138
1139 module
1140 .constant(
1141 "BAD_GATEWAY",
1142 StatusCode {
1143 inner: reqwest::StatusCode::BAD_GATEWAY,
1144 },
1145 )
1146 .build_associated::<StatusCode>()?
1147 .docs(docstring! {
1148 /// Status Code: Bad Gateway
1149 ///
1150 /// # Examples
1151 ///
1152 /// ```rune
1153 /// use http::StatusCode;
1154 ///
1155 /// let status_code = StatusCode::BAD_GATEWAY;
1156 /// ```
1157 })?;
1158
1159 module
1160 .constant(
1161 "SERVICE_UNAVAILABLE",
1162 StatusCode {
1163 inner: reqwest::StatusCode::SERVICE_UNAVAILABLE,
1164 },
1165 )
1166 .build_associated::<StatusCode>()?
1167 .docs(docstring! {
1168 /// Status Code: Service Unavailable
1169 ///
1170 /// # Examples
1171 ///
1172 /// ```rune
1173 /// use http::StatusCode;
1174 ///
1175 /// let status_code = StatusCode::SERVICE_UNAVAILABLE;
1176 /// ```
1177 })?;
1178
1179 module
1180 .constant(
1181 "GATEWAY_TIMEOUT",
1182 StatusCode {
1183 inner: reqwest::StatusCode::GATEWAY_TIMEOUT,
1184 },
1185 )
1186 .build_associated::<StatusCode>()?
1187 .docs(docstring! {
1188 /// Status Code: Gateway Timeout
1189 ///
1190 /// # Examples
1191 ///
1192 /// ```rune
1193 /// use http::StatusCode;
1194 ///
1195 /// let status_code = StatusCode::GATEWAY_TIMEOUT;
1196 /// ```
1197 })?;
1198
1199 module
1200 .constant(
1201 "HTTP_VERSION_NOT_SUPPORTED",
1202 StatusCode {
1203 inner: reqwest::StatusCode::HTTP_VERSION_NOT_SUPPORTED,
1204 },
1205 )
1206 .build_associated::<StatusCode>()?
1207 .docs(docstring! {
1208 /// Status Code: HTTP Version Not Supported
1209 ///
1210 /// # Examples
1211 ///
1212 /// ```rune
1213 /// use http::StatusCode;
1214 ///
1215 /// let status_code = StatusCode::HTTP_VERSION_NOT_SUPPORTED;
1216 /// ```
1217 })?;
1218
1219 module
1220 .constant(
1221 "VARIANT_ALSO_NEGOTIATES",
1222 StatusCode {
1223 inner: reqwest::StatusCode::VARIANT_ALSO_NEGOTIATES,
1224 },
1225 )
1226 .build_associated::<StatusCode>()?
1227 .docs(docstring! {
1228 /// Status Code: Variant Also Negotiates
1229 ///
1230 /// # Examples
1231 ///
1232 /// ```rune
1233 /// use http::StatusCode;
1234 ///
1235 /// let status_code = StatusCode::VARIANT_ALSO_NEGOTIATES;
1236 /// ```
1237 })?;
1238
1239 module
1240 .constant(
1241 "INSUFFICIENT_STORAGE",
1242 StatusCode {
1243 inner: reqwest::StatusCode::INSUFFICIENT_STORAGE,
1244 },
1245 )
1246 .build_associated::<StatusCode>()?
1247 .docs(docstring! {
1248 /// Status Code: Insufficient Storage
1249 ///
1250 /// # Examples
1251 ///
1252 /// ```rune
1253 /// use http::StatusCode;
1254 ///
1255 /// let status_code = StatusCode::INSUFFICIENT_STORAGE;
1256 /// ```
1257 })?;
1258
1259 module
1260 .constant(
1261 "LOOP_DETECTED",
1262 StatusCode {
1263 inner: reqwest::StatusCode::LOOP_DETECTED,
1264 },
1265 )
1266 .build_associated::<StatusCode>()?
1267 .docs(docstring! {
1268 /// Status Code: Loop Detected
1269 ///
1270 /// # Examples
1271 ///
1272 /// ```rune
1273 /// use http::StatusCode;
1274 ///
1275 /// let status_code = StatusCode::LOOP_DETECTED;
1276 /// ```
1277 })?;
1278
1279 module
1280 .constant(
1281 "NOT_EXTENDED",
1282 StatusCode {
1283 inner: reqwest::StatusCode::NOT_EXTENDED,
1284 },
1285 )
1286 .build_associated::<StatusCode>()?
1287 .docs(docstring! {
1288 /// Status Code: Not Extended
1289 ///
1290 /// # Examples
1291 ///
1292 /// ```rune
1293 /// use http::StatusCode;
1294 ///
1295 /// let status_code = StatusCode::NOT_EXTENDED;
1296 /// ```
1297 })?;
1298
1299 module
1300 .constant(
1301 "NETWORK_AUTHENTICATION_REQUIRED",
1302 StatusCode {
1303 inner: reqwest::StatusCode::NETWORK_AUTHENTICATION_REQUIRED,
1304 },
1305 )
1306 .build_associated::<StatusCode>()?
1307 .docs(docstring! {
1308 /// Status Code: Network Authentication Required
1309 ///
1310 /// # Examples
1311 ///
1312 /// ```rune
1313 /// use http::StatusCode;
1314 ///
1315 /// let status_code = StatusCode::NETWORK_AUTHENTICATION_REQUIRED;
1316 /// ```
1317 })?;
1318
1319 module.ty::<Version>()?;
1320 module.function_meta(Version::partial_eq__meta)?;
1321 module.implement_trait::<Version>(item!(::std::cmp::PartialEq))?;
1322 module.function_meta(Version::eq__meta)?;
1323 module.implement_trait::<Version>(item!(::std::cmp::Eq))?;
1324 module.function_meta(Version::partial_cmp__meta)?;
1325 module.implement_trait::<Version>(item!(::std::cmp::PartialOrd))?;
1326 module.function_meta(Version::cmp__meta)?;
1327 module.implement_trait::<Version>(item!(::std::cmp::Ord))?;
1328 module.function_meta(Version::hash__meta)?;
1329 module.function_meta(Version::debug_fmt__meta)?;
1330
1331 module
1332 .constant(
1333 "HTTP_09",
1334 Version {
1335 inner: reqwest::Version::HTTP_09,
1336 },
1337 )
1338 .build_associated::<Version>()?
1339 .docs(docstring! {
1340 /// The `HTTP/0.9` version.
1341 ///
1342 /// # Examples
1343 ///
1344 /// ```rune,no_run
1345 /// use http::Version;
1346 ///
1347 /// let version = Version::HTTP_09;
1348 /// ```
1349 })?;
1350
1351 module
1352 .constant(
1353 "HTTP_10",
1354 Version {
1355 inner: reqwest::Version::HTTP_10,
1356 },
1357 )
1358 .build_associated::<Version>()?
1359 .docs(docstring! {
1360 /// The `HTTP/1.0` version.
1361 ///
1362 /// # Examples
1363 ///
1364 /// ```rune,no_run
1365 /// use http::Version;
1366 ///
1367 /// let version = Version::HTTP_10;
1368 /// ```
1369 })?;
1370
1371 module
1372 .constant(
1373 "HTTP_11",
1374 Version {
1375 inner: reqwest::Version::HTTP_11,
1376 },
1377 )
1378 .build_associated::<Version>()?
1379 .docs(docstring! {
1380 /// The `HTTP/1.1` version.
1381 ///
1382 /// # Examples
1383 ///
1384 /// ```rune,no_run
1385 /// use http::Version;
1386 ///
1387 /// let version = Version::HTTP_11;
1388 /// ```
1389 })?;
1390
1391 module
1392 .constant(
1393 "HTTP_2",
1394 Version {
1395 inner: reqwest::Version::HTTP_2,
1396 },
1397 )
1398 .build_associated::<Version>()?
1399 .docs(docstring! {
1400 /// The `HTTP/2.0` version.
1401 ///
1402 /// # Examples
1403 ///
1404 /// ```rune,no_run
1405 /// use http::Version;
1406 ///
1407 /// let version = Version::HTTP_2;
1408 /// ```
1409 })?;
1410
1411 module
1412 .constant(
1413 "HTTP_3",
1414 Version {
1415 inner: reqwest::Version::HTTP_3,
1416 },
1417 )
1418 .build_associated::<Version>()?
1419 .docs(docstring! {
1420 /// The `HTTP/3.0` version.
1421 ///
1422 /// # Examples
1423 ///
1424 /// ```rune,no_run
1425 /// use http::Version;
1426 ///
1427 /// let version = Version::HTTP_3;
1428 /// ```
1429 })?;
1430
1431 module.ty::<Error>()?;
1432 module.function_meta(Error::display_fmt__meta)?;
1433 Ok(module)
1434}
1435
1436/// An error returned by methods in the `http` module.
1437#[derive(Debug, Any)]
1438#[rune(item = ::http)]
1439pub struct Error {
1440 inner: reqwest::Error,
1441}
1442
1443impl From<reqwest::Error> for Error {
1444 fn from(inner: reqwest::Error) -> Self {
1445 Self { inner }
1446 }
1447}
1448
1449impl Error {
1450 /// Write a display representation the error.
1451 #[rune::function(keep, instance, protocol = DISPLAY_FMT)]
1452 fn display_fmt(&self, f: &mut Formatter) -> VmResult<()> {
1453 rune::vm_write!(f, "{}", self.inner)
1454 }
1455}
1456
1457/// An asynchronous Client to make Requests with.
1458#[derive(Debug, Any)]
1459#[rune(item = ::http)]
1460struct Client {
1461 client: reqwest::Client,
1462}
1463
1464/// A Response to a submitted [`Request`].
1465#[derive(Debug, Any)]
1466#[rune(item = ::http)]
1467pub struct Response {
1468 response: reqwest::Response,
1469}
1470
1471impl Response {
1472 /// Get the response as text.
1473 ///
1474 /// ```rune,no_run
1475 /// let client = http::Client::new();
1476 ///
1477 /// let response = client.get("http://example.com")
1478 /// .body_bytes(b"Hello World")
1479 /// .send()
1480 /// .await?;
1481 ///
1482 /// let response = response.text().await?;
1483 /// ```
1484 #[rune::function(keep, vm_result)]
1485 async fn text(self) -> Result<String, Error> {
1486 let text = self.response.text().await?;
1487 // NB: We simply take ownership of the string here, raising an error in
1488 // case we reach a memory limit.
1489 Ok(String::try_from(text).vm?)
1490 }
1491
1492 /// Get the response as a Rune value decoded from JSON.
1493 ///
1494 /// ```rune,no_run
1495 /// let client = http::Client::new();
1496 ///
1497 /// let response = client.get("http://example.com")
1498 /// .send()
1499 /// .await?;
1500 ///
1501 /// let response = response.json().await?;
1502 /// ```
1503 #[rune::function(keep)]
1504 async fn json(self) -> Result<Value, Error> {
1505 let text = self.response.json().await?;
1506 Ok(text)
1507 }
1508
1509 /// Get the response as bytes.
1510 ///
1511 /// ```rune,no_run
1512 /// let client = http::Client::new();
1513 ///
1514 /// let response = client.get("http://example.com")
1515 /// .send()
1516 /// .await?;
1517 ///
1518 /// let response = response.bytes().await?;
1519 /// ```
1520 #[rune::function(keep, vm_result)]
1521 async fn bytes(mut self) -> Result<Bytes, Error> {
1522 let len = self.response.content_length().unwrap_or(0) as usize;
1523 let mut bytes = Vec::try_with_capacity(len).vm?;
1524
1525 while let Some(chunk) = self.response.chunk().await? {
1526 bytes.try_extend_from_slice(chunk.as_ref()).vm?;
1527 }
1528
1529 Ok(Bytes::from_vec(bytes))
1530 }
1531
1532 /// Get the status code of the response.
1533 #[rune::function(keep, instance)]
1534 fn status(&self) -> StatusCode {
1535 StatusCode {
1536 inner: self.response.status(),
1537 }
1538 }
1539
1540 /// Get the version of the response.
1541 #[rune::function(keep, instance)]
1542 fn version(&self) -> Version {
1543 Version {
1544 inner: self.response.version(),
1545 }
1546 }
1547
1548 /// Get the content-length of this response, if known.
1549 ///
1550 /// Reasons it may not be known:
1551 ///
1552 /// - The server didn't send a `content-length` header.
1553 /// - The response is compressed and automatically decoded (thus changing
1554 /// the actual decoded length).
1555 #[rune::function(keep, instance)]
1556 fn content_length(&self) -> Option<u64> {
1557 self.response.content_length()
1558 }
1559}
1560
1561/// An HTTP status code.
1562#[derive(Debug, Any, PartialEq, Eq, PartialOrd, Ord, ToConstValue)]
1563#[rune(item = ::http)]
1564pub struct StatusCode {
1565 #[const_value(with = self::const_status_code)]
1566 inner: reqwest::StatusCode,
1567}
1568
1569impl StatusCode {
1570 /// Returns the `u16` corresponding to this `StatusCode`.
1571 ///
1572 /// # Note
1573 ///
1574 /// This is the same as the `From<StatusCode>` implementation, but included
1575 /// as an inherent method because that implementation doesn't appear in
1576 /// rustdocs, as well as a way to force the type instead of relying on
1577 /// inference.
1578 ///
1579 /// # Example
1580 ///
1581 /// ```rune
1582 /// use http::StatusCode;
1583 ///
1584 /// let status = StatusCode::OK;
1585 /// assert_eq!(status.as_u16(), 200);
1586 /// ```
1587 #[rune::function(keep, instance)]
1588 #[inline]
1589 fn as_u16(&self) -> u16 {
1590 self.inner.as_u16()
1591 }
1592
1593 /// Returns a &str representation of the `StatusCode`
1594 ///
1595 /// The return value only includes a numerical representation of the status
1596 /// code. The canonical reason is not included.
1597 ///
1598 /// # Example
1599 ///
1600 /// ```rune
1601 /// use http::StatusCode;
1602 ///
1603 /// let status = StatusCode::OK;
1604 /// assert_eq!(status.as_str(), "200");
1605 /// ```
1606 #[rune::function(keep, instance, vm_result)]
1607 #[inline]
1608 fn as_str(&self) -> String {
1609 self.inner.as_str().try_to_owned().vm?
1610 }
1611
1612 /// Get the standardised `reason-phrase` for this status code.
1613 ///
1614 /// This is mostly here for servers writing responses, but could potentially
1615 /// have application at other times.
1616 ///
1617 /// The reason phrase is defined as being exclusively for human readers. You
1618 /// should avoid deriving any meaning from it at all costs.
1619 ///
1620 /// Bear in mind also that in HTTP/2.0 and HTTP/3.0 the reason phrase is
1621 /// abolished from transmission, and so this canonical reason phrase really
1622 /// is the only reason phrase you’ll find.
1623 ///
1624 /// # Example
1625 ///
1626 /// ```rune
1627 /// use http::StatusCode;
1628 ///
1629 /// let status = StatusCode::OK;
1630 /// assert_eq!(status.canonical_reason(), Some("OK"));
1631 /// ```
1632 #[inline]
1633 #[rune::function(keep, instance)]
1634 fn canonical_reason(&self) -> Option<&'static str> {
1635 self.inner.canonical_reason()
1636 }
1637
1638 /// Check if status is within 100-199.
1639 #[inline]
1640 #[rune::function(keep, instance)]
1641 fn is_informational(&self) -> bool {
1642 self.inner.is_informational()
1643 }
1644
1645 /// Check if status is within 200-299.
1646 #[inline]
1647 #[rune::function(keep, instance)]
1648 fn is_success(&self) -> bool {
1649 self.inner.is_success()
1650 }
1651
1652 /// Check if status is within 300-399.
1653 #[inline]
1654 #[rune::function(keep, instance)]
1655 fn is_redirection(&self) -> bool {
1656 self.inner.is_redirection()
1657 }
1658
1659 /// Check if status is within 400-499.
1660 #[inline]
1661 #[rune::function(keep, instance)]
1662 fn is_client_error(&self) -> bool {
1663 self.inner.is_client_error()
1664 }
1665
1666 /// Check if status is within 500-599.
1667 #[inline]
1668 #[rune::function(keep, instance)]
1669 fn is_server_error(&self) -> bool {
1670 self.inner.is_server_error()
1671 }
1672
1673 /// Test two status codes for partial equality.
1674 ///
1675 /// # Examples
1676 ///
1677 /// ```rune
1678 /// use std::ops::partial_eq;
1679 /// use http::StatusCode;
1680 ///
1681 /// let ok = StatusCode::OK;
1682 /// let not_found = StatusCode::NOT_FOUND;
1683 ///
1684 /// assert_eq!(partial_eq(ok, ok), true);
1685 /// assert_eq!(partial_eq(ok, not_found), false);
1686 /// assert_eq!(partial_eq(not_found, ok), false);
1687 /// ```
1688 #[rune::function(keep, instance, protocol = PARTIAL_EQ)]
1689 #[inline]
1690 fn partial_eq(&self, rhs: &Self) -> bool {
1691 PartialEq::eq(&self.inner, &rhs.inner)
1692 }
1693
1694 /// Test two status codes for total equality.
1695 ///
1696 /// # Examples
1697 ///
1698 /// ```rune
1699 /// use std::ops::eq;
1700 /// use http::StatusCode;
1701 ///
1702 /// let ok = StatusCode::OK;
1703 /// let not_found = StatusCode::NOT_FOUND;
1704 ///
1705 /// assert_eq!(eq(ok, ok), true);
1706 /// assert_eq!(eq(ok, not_found), false);
1707 /// assert_eq!(eq(not_found, ok), false);
1708 /// ```
1709 #[rune::function(keep, instance, protocol = EQ)]
1710 #[inline]
1711 fn eq(&self, rhs: &Self) -> bool {
1712 PartialEq::eq(&self.inner, &rhs.inner)
1713 }
1714
1715 /// Perform a partial ordered comparison between two status codes.
1716 ///
1717 /// # Examples
1718 ///
1719 /// ```rune
1720 /// use http::StatusCode;
1721 ///
1722 /// let ok = StatusCode::OK;
1723 /// let not_found = StatusCode::NOT_FOUND;
1724 ///
1725 /// assert!(ok < not_found);
1726 /// assert!(not_found > ok);
1727 /// assert!(ok == ok);
1728 /// ```
1729 ///
1730 /// Using explicit functions:
1731 ///
1732 /// ```rune
1733 /// use std::cmp::Ordering;
1734 /// use std::ops::partial_cmp;
1735 ///
1736 /// use http::StatusCode;
1737 ///
1738 /// let ok = StatusCode::OK;
1739 /// let not_found = StatusCode::NOT_FOUND;
1740 ///
1741 /// assert_eq!(partial_cmp(ok, not_found), Some(Ordering::Less));
1742 /// assert_eq!(partial_cmp(not_found, ok), Some(Ordering::Greater));
1743 /// assert_eq!(partial_cmp(ok, ok), Some(Ordering::Equal));
1744 /// ```
1745 #[rune::function(keep, instance, protocol = PARTIAL_CMP)]
1746 #[inline]
1747 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
1748 PartialOrd::partial_cmp(&self.inner, &rhs.inner)
1749 }
1750
1751 /// Perform a totally ordered comparison between two status codes.
1752 ///
1753 /// # Examples
1754 ///
1755 /// ```rune
1756 /// use std::cmp::Ordering;
1757 /// use std::ops::cmp;
1758 ///
1759 /// use http::StatusCode;
1760 ///
1761 /// let ok = StatusCode::OK;
1762 /// let not_found = StatusCode::NOT_FOUND;
1763 ///
1764 /// assert_eq!(cmp(ok, not_found), Ordering::Less);
1765 /// assert_eq!(cmp(not_found, ok), Ordering::Greater);
1766 /// assert_eq!(cmp(ok, ok), Ordering::Equal);
1767 /// ```
1768 #[rune::function(keep, instance, protocol = CMP)]
1769 #[inline]
1770 fn cmp(&self, rhs: &Self) -> Ordering {
1771 Ord::cmp(&self.inner, &rhs.inner)
1772 }
1773
1774 /// Hash the status code.
1775 ///
1776 /// # Examples
1777 ///
1778 /// ```rune
1779 /// use std::ops::hash;
1780 ///
1781 /// use http::StatusCode;
1782 ///
1783 /// let not_found = StatusCode::NOT_FOUND;
1784 ///
1785 /// assert_eq!(hash(not_found), hash(not_found));
1786 /// ```
1787 #[rune::function(keep, instance, protocol = HASH)]
1788 fn hash(&self, hasher: &mut Hasher) {
1789 self.inner.hash(hasher);
1790 }
1791
1792 /// Write a debug representation of the status code.
1793 ///
1794 /// # Examples
1795 ///
1796 /// ```rune
1797 /// use http::StatusCode;
1798 ///
1799 /// let not_found = StatusCode::NOT_FOUND;
1800 ///
1801 /// println!("{not_found:?}");
1802 /// ```
1803 #[rune::function(keep, instance, protocol = DEBUG_FMT)]
1804 fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> {
1805 rune::vm_write!(f, "{:?}", self.inner)
1806 }
1807
1808 /// Write a display representation of the status code.
1809 ///
1810 /// # Examples
1811 ///
1812 /// ```rune
1813 /// use http::StatusCode;
1814 ///
1815 /// let not_found = StatusCode::NOT_FOUND;
1816 ///
1817 /// println!("{not_found}");
1818 /// ```
1819 #[rune::function(keep, instance, protocol = DISPLAY_FMT)]
1820 fn display_fmt(&self, f: &mut Formatter) -> VmResult<()> {
1821 rune::vm_write!(f, "{}", self.inner)
1822 }
1823}
1824
1825/// HTTP version
1826///
1827/// This module contains a definition of the `Version` type. The `Version`
1828/// type is intended to be accessed through the root of the crate
1829/// (`http::Version`) rather than this module.
1830///
1831/// The `Version` type contains constants that represent the various versions
1832/// of the HTTP protocol.
1833///
1834/// # Examples
1835///
1836/// ```rune
1837/// use http::Version;
1838///
1839/// let http11 = Version::HTTP_11;
1840/// let http2 = Version::HTTP_2;
1841/// assert!(http11 != http2);
1842///
1843/// println!("{:?}", http2);
1844/// ```
1845#[derive(Debug, Any, PartialEq, Eq, PartialOrd, Ord, ToConstValue)]
1846#[rune(item = ::http)]
1847pub struct Version {
1848 #[const_value(with = self::const_version)]
1849 inner: reqwest::Version,
1850}
1851
1852impl Version {
1853 /// Test two versions for partial equality.
1854 ///
1855 /// # Examples
1856 ///
1857 /// ```rune
1858 /// use std::ops::partial_eq;
1859 ///
1860 /// use http::Version;
1861 ///
1862 /// let http11 = Version::HTTP_11;
1863 /// let http2 = Version::HTTP_2;
1864 ///
1865 /// assert_eq!(partial_eq(http11, http11), true);
1866 /// assert_eq!(partial_eq(http11, http2), false);
1867 /// assert_eq!(partial_eq(http2, http11), false);
1868 /// ```
1869 #[rune::function(keep, instance, protocol = PARTIAL_EQ)]
1870 #[inline]
1871 fn partial_eq(&self, rhs: &Self) -> bool {
1872 PartialEq::eq(&self.inner, &rhs.inner)
1873 }
1874
1875 /// Test two versions for total equality.
1876 ///
1877 /// # Examples
1878 ///
1879 /// ```rune
1880 /// use std::ops::eq;
1881 ///
1882 /// use http::Version;
1883 ///
1884 /// let http11 = Version::HTTP_11;
1885 /// let http2 = Version::HTTP_2;
1886 ///
1887 /// assert_eq!(eq(http11, http11), true);
1888 /// assert_eq!(eq(http11, http2), false);
1889 /// assert_eq!(eq(http2, http11), false);
1890 /// ```
1891 #[rune::function(keep, instance, protocol = EQ)]
1892 #[inline]
1893 fn eq(&self, rhs: &Self) -> bool {
1894 PartialEq::eq(&self.inner, &rhs.inner)
1895 }
1896
1897 /// Perform a partial ordered comparison between two versions.
1898 ///
1899 /// # Examples
1900 ///
1901 /// ```rune
1902 /// use http::Version;
1903 ///
1904 /// let http11 = Version::HTTP_11;
1905 /// let http2 = Version::HTTP_2;
1906 ///
1907 /// assert!(http11 < http2);
1908 /// assert!(http2 > http11);
1909 /// assert!(http11 == http11);
1910 /// ```
1911 ///
1912 /// Using explicit functions:
1913 ///
1914 /// ```rune
1915 /// use std::cmp::Ordering;
1916 /// use std::ops::partial_cmp;
1917 ///
1918 /// use http::Version;
1919 ///
1920 /// let http11 = Version::HTTP_11;
1921 /// let http2 = Version::HTTP_2;
1922 ///
1923 /// assert_eq!(partial_cmp(http11, http2), Some(Ordering::Less));
1924 /// assert_eq!(partial_cmp(http2, http11), Some(Ordering::Greater));
1925 /// assert_eq!(partial_cmp(http11, http11), Some(Ordering::Equal));
1926 /// ```
1927 #[rune::function(keep, instance, protocol = PARTIAL_CMP)]
1928 #[inline]
1929 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
1930 PartialOrd::partial_cmp(&self.inner, &rhs.inner)
1931 }
1932
1933 /// Perform a totally ordered comparison between two versions.
1934 ///
1935 /// # Examples
1936 ///
1937 /// ```rune
1938 /// use std::cmp::Ordering;
1939 /// use std::ops::cmp;
1940 ///
1941 /// use http::Version;
1942 ///
1943 /// let http11 = Version::HTTP_11;
1944 /// let http2 = Version::HTTP_2;
1945 ///
1946 /// assert_eq!(cmp(http11, http2), Ordering::Less);
1947 /// assert_eq!(cmp(http2, http11), Ordering::Greater);
1948 /// assert_eq!(cmp(http11, http11), Ordering::Equal);
1949 /// ```
1950 #[rune::function(keep, instance, protocol = CMP)]
1951 #[inline]
1952 fn cmp(&self, rhs: &Self) -> Ordering {
1953 Ord::cmp(&self.inner, &rhs.inner)
1954 }
1955
1956 /// Hash the version.
1957 ///
1958 /// # Examples
1959 ///
1960 /// ```rune
1961 /// use std::ops::hash;
1962 ///
1963 /// use http::Version;
1964 ///
1965 /// let http2 = Version::HTTP_2;
1966 ///
1967 /// assert_eq!(hash(http2), hash(http2));
1968 /// ```
1969 #[rune::function(keep, instance, protocol = HASH)]
1970 fn hash(&self, hasher: &mut Hasher) {
1971 self.inner.hash(hasher);
1972 }
1973
1974 /// Debug print the Version.
1975 ///
1976 /// # Examples
1977 ///
1978 /// ```rune
1979 /// use http::Version;
1980 ///
1981 /// let http11 = Version::HTTP_11;
1982 /// let http2 = Version::HTTP_2;
1983 ///
1984 /// println!("{:?}", http2);
1985 /// ```
1986 #[rune::function(keep, instance, protocol = DEBUG_FMT)]
1987 fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> {
1988 rune::vm_write!(f, "{:?}", self.inner)
1989 }
1990}
1991
1992/// A builder to construct the properties of a Request.
1993///
1994/// To construct a RequestBuilder, refer to the [`Client`] documentation.
1995#[derive(Debug, Any)]
1996#[rune(item = ::http)]
1997pub struct RequestBuilder {
1998 request: reqwest::RequestBuilder,
1999}
2000
2001impl RequestBuilder {
2002 /// Send the request and receive an answer from the server.
2003 ///
2004 /// ```rune,no_run
2005 /// let client = http::Client::new();
2006 ///
2007 /// let response = client.get("http://example.com")
2008 /// .header("Accept", "text/html")
2009 /// .send()
2010 /// .await?;
2011 ///
2012 /// let response = response.text().await?;
2013 /// ```
2014 #[rune::function(keep)]
2015 async fn send(self) -> Result<Response, Error> {
2016 let response = self.request.send().await?;
2017 Ok(Response { response })
2018 }
2019
2020 /// Modify a header in the request.
2021 ///
2022 /// ```rune,no_run
2023 /// let client = http::Client::new();
2024 ///
2025 /// let response = client.get("http://example.com")
2026 /// .header("Accept", "text/html")
2027 /// .send()
2028 /// .await?;
2029 ///
2030 /// let response = response.text().await?;
2031 /// ```
2032 #[rune::function(keep)]
2033 fn header(self, key: &str, value: &str) -> Self {
2034 Self {
2035 request: self.request.header(key, value),
2036 }
2037 }
2038
2039 /// Enable basic authentication in the request.
2040 ///
2041 /// ```rune,no_run
2042 /// let client = http::Client::new();
2043 ///
2044 /// let response = client.get("http://example.com")
2045 /// .basic_auth("admin", Some("good password"))
2046 /// .send()
2047 /// .await?;
2048 ///
2049 /// let response = response.text().await?;
2050 /// ```
2051 #[rune::function(keep)]
2052 fn basic_auth(self, username: &str, password: Option<Ref<str>>) -> Self {
2053 Self {
2054 request: self.request.basic_auth(username, password.as_deref()),
2055 }
2056 }
2057
2058 /// Enable bearer authentication in the request.
2059 ///
2060 /// ```rune,no_run
2061 /// let client = http::Client::new();
2062 ///
2063 /// let response = client.get("http://example.com")
2064 /// .bearer_auth("A1B2C3D4E5")
2065 /// .send()
2066 /// .await?;
2067 ///
2068 /// let response = response.text().await?;
2069 /// ```
2070 #[rune::function(keep)]
2071 fn bearer_auth(self, token: &str) -> Self {
2072 Self {
2073 request: self.request.bearer_auth(token),
2074 }
2075 }
2076
2077 /// Set version in the request.
2078 ///
2079 /// ```rune,no_run
2080 /// let client = http::Client::new();
2081 ///
2082 /// let response = client.get("http://example.com")
2083 /// .version(Version::HTTP_2)
2084 /// .send()
2085 /// .await?;
2086 ///
2087 /// let response = response.text().await?;
2088 /// ```
2089 #[rune::function]
2090 fn version(self, version: Version) -> Self {
2091 Self {
2092 request: self.request.version(version.inner),
2093 }
2094 }
2095
2096 /// Disable CORS on fetching the request.
2097 ///
2098 /// This option is only effective with WebAssembly target.
2099 /// The [request mode][mdn] will be set to 'no-cors'.
2100 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/Request/mode
2101 ///
2102 /// ```rune,no_run
2103 /// let client = http::Client::new();
2104 ///
2105 /// let response = client.get("http://example.com")
2106 /// .fetch_mode_no_cors()
2107 /// .send()
2108 /// .await?;
2109 ///
2110 /// let response = response.text().await?;
2111 /// ```
2112 #[rune::function(keep)]
2113 fn fetch_mode_no_cors(self) -> Self {
2114 Self {
2115 request: self.request.fetch_mode_no_cors(),
2116 }
2117 }
2118
2119 /// Set the request body from bytes.
2120 ///
2121 /// ```rune,no_run
2122 /// let client = http::Client::new();
2123 ///
2124 /// let response = client.get("http://example.com")
2125 /// .body_bytes(b"Hello World")
2126 /// .send()
2127 /// .await?;
2128 ///
2129 /// let response = response.text().await?;
2130 /// ```
2131 #[rune::function(keep)]
2132 fn body_bytes(self, bytes: Bytes) -> Self {
2133 let bytes = bytes.into_vec();
2134
2135 Self {
2136 request: self.request.body(bytes.into_std()),
2137 }
2138 }
2139}
2140
2141impl Client {
2142 /// Construct a new http client.
2143 ///
2144 /// # Examples
2145 ///
2146 /// ```rune
2147 /// let client = http::Client::new();
2148 /// ```
2149 #[rune::function(keep, path = Self::new)]
2150 fn new() -> Self {
2151 Self {
2152 client: reqwest::Client::new(),
2153 }
2154 }
2155
2156 /// Construct a builder to GET the given `url`.
2157 ///
2158 /// # Examples
2159 ///
2160 /// ```rune,no_run
2161 /// let client = http::Client::new();
2162 ///
2163 /// let response = client.get("http://example.com")
2164 /// .send()
2165 /// .await?;
2166 ///
2167 /// let response = response.text().await?;
2168 /// ```
2169 #[rune::function(keep, instance)]
2170 fn get(&self, url: &str) -> RequestBuilder {
2171 RequestBuilder {
2172 request: self.client.get(url),
2173 }
2174 }
2175
2176 /// Construct a builder to POST to the given `url`.
2177 ///
2178 /// # Examples
2179 ///
2180 /// ```rune,no_run
2181 /// let client = http::Client::new();
2182 ///
2183 /// let response = client.post("https://postman-echo.com/post")
2184 /// .body_bytes(b"My post data...")
2185 /// .send()
2186 /// .await?;
2187 ///
2188 /// let response = response.json().await?;
2189 /// ```
2190 #[rune::function(keep, instance)]
2191 fn post(&self, url: &str) -> RequestBuilder {
2192 let request = self.client.post(url);
2193 RequestBuilder { request }
2194 }
2195
2196 /// Construct a builder to PUT to the given `url`.
2197 ///
2198 /// # Examples
2199 ///
2200 /// ```rune,no_run
2201 /// let client = http::Client::new();
2202 ///
2203 /// let response = client.put("https://postman-echo.com/put")
2204 /// .body_bytes(b"My put data...")
2205 /// .send()
2206 /// .await?;
2207 ///
2208 /// let response = response.json().await?;
2209 /// ```
2210 #[rune::function(keep, instance)]
2211 fn put(&self, url: &str) -> RequestBuilder {
2212 let request = self.client.put(url);
2213 RequestBuilder { request }
2214 }
2215
2216 /// Construct a builder to PATCH to the given `url`.
2217 ///
2218 /// # Examples
2219 ///
2220 /// ```rune,no_run
2221 /// let client = http::Client::new();
2222 ///
2223 /// let response = client.patch("https://postman-echo.com/patch")
2224 /// .body_bytes(b"My patch data...")
2225 /// .send()
2226 /// .await?;
2227 ///
2228 /// let response = response.json().await?;
2229 /// ```
2230 #[rune::function(instance)]
2231 fn patch(&self, url: &str) -> RequestBuilder {
2232 let request = self.client.patch(url);
2233 RequestBuilder { request }
2234 }
2235
2236 /// Construct a builder to DELETE to the given `url`.
2237 ///
2238 /// # Examples
2239 ///
2240 /// ```rune,no_run
2241 /// let client = http::Client::new();
2242 ///
2243 /// let response = client.delete("https://postman-echo.com/delete")
2244 /// .body_bytes(b"My delete data...")
2245 /// .send()
2246 /// .await?;
2247 ///
2248 /// let response = response.json().await?;
2249 /// ```
2250 #[rune::function(keep, instance)]
2251 fn delete(&self, url: &str) -> RequestBuilder {
2252 let request = self.client.delete(url);
2253 RequestBuilder { request }
2254 }
2255
2256 /// Construct a builder to HEAD to the given `url`.
2257 ///
2258 /// # Examples
2259 ///
2260 /// ```rune,no_run
2261 /// let client = http::Client::new();
2262 ///
2263 /// let response = client.head("https://postman-echo.com/head")
2264 /// .body_bytes(b"My head data...")
2265 /// .send()
2266 /// .await?;
2267 ///
2268 /// let response = response.json().await?;
2269 /// ```
2270 #[rune::function(keep, instance)]
2271 fn head(&self, url: &str) -> RequestBuilder {
2272 let request = self.client.head(url);
2273 RequestBuilder { request }
2274 }
2275}
2276
2277/// Shorthand for generating a get request.
2278///
2279/// # Examples
2280///
2281/// ```rune,no_run
2282/// let response = http::get("http://worldtimeapi.org/api/ip").await?;
2283/// let json = response.json().await?;
2284///
2285/// let timezone = json["timezone"];
2286/// ```
2287#[rune::function]
2288async fn get(url: Ref<str>) -> Result<Response, Error> {
2289 Ok(Response {
2290 response: reqwest::get(url.as_ref()).await?,
2291 })
2292}
2293
2294mod const_version {
2295 use rune::runtime::{ConstValue, RuntimeError, Value};
2296
2297 #[inline]
2298 pub(super) fn to_const_value(version: reqwest::Version) -> Result<ConstValue, RuntimeError> {
2299 match version {
2300 reqwest::Version::HTTP_09 => Ok(ConstValue::from(1i64)),
2301 reqwest::Version::HTTP_10 => Ok(ConstValue::from(2i64)),
2302 reqwest::Version::HTTP_11 => Ok(ConstValue::from(3i64)),
2303 reqwest::Version::HTTP_2 => Ok(ConstValue::from(4i64)),
2304 reqwest::Version::HTTP_3 => Ok(ConstValue::from(5i64)),
2305 version => Err(RuntimeError::panic(format!(
2306 "Unsupported reqwest version {version:?}"
2307 ))),
2308 }
2309 }
2310
2311 #[inline]
2312 pub(super) fn from_const_value(version: &ConstValue) -> Result<reqwest::Version, RuntimeError> {
2313 from_i64(rune::from_const_value(version)?)
2314 }
2315
2316 #[inline]
2317 pub(super) fn from_value(version: Value) -> Result<reqwest::Version, RuntimeError> {
2318 from_i64(rune::from_value(version)?)
2319 }
2320
2321 #[inline]
2322 fn from_i64(value: i64) -> Result<reqwest::Version, RuntimeError> {
2323 match value {
2324 1i64 => Ok(reqwest::Version::HTTP_09),
2325 2i64 => Ok(reqwest::Version::HTTP_10),
2326 3i64 => Ok(reqwest::Version::HTTP_11),
2327 4i64 => Ok(reqwest::Version::HTTP_2),
2328 5i64 => Ok(reqwest::Version::HTTP_3),
2329 value => Err(RuntimeError::panic(format!(
2330 "unsupported reqwest version {value}"
2331 ))),
2332 }
2333 }
2334}
2335
2336mod const_status_code {
2337 use rune::runtime::{ConstValue, RuntimeError, Value};
2338
2339 #[inline]
2340 pub(super) fn to_const_value(status: reqwest::StatusCode) -> Result<ConstValue, RuntimeError> {
2341 Ok(ConstValue::from(status.as_u16()))
2342 }
2343
2344 #[inline]
2345 pub(super) fn from_const_value(
2346 status: &ConstValue,
2347 ) -> Result<reqwest::StatusCode, RuntimeError> {
2348 match reqwest::StatusCode::from_u16(rune::from_const_value(status)?) {
2349 Ok(status) => Ok(status),
2350 Err(error) => Err(RuntimeError::panic(error)),
2351 }
2352 }
2353
2354 #[inline]
2355 pub(super) fn from_value(value: Value) -> Result<reqwest::StatusCode, RuntimeError> {
2356 match reqwest::StatusCode::from_u16(rune::from_value(value)?) {
2357 Ok(status) => Ok(status),
2358 Err(error) => Err(RuntimeError::panic(error)),
2359 }
2360 }
2361}