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}