1use crate::serve::HttpResponder;
8use fuchsia_repo::body::Body;
9use fuchsia_sync::Mutex;
10use futures::channel::{mpsc, oneshot};
11use futures::future::{BoxFuture, Shared, pending, ready};
12use futures::prelude::*;
13use http_body_util::BodyExt;
14use hyper::{Request, Response, StatusCode};
15use std::collections::HashSet;
16use std::path::{Path, PathBuf};
17use std::sync::Arc;
18use std::sync::atomic::{AtomicBool, AtomicU16, AtomicU32, Ordering};
19
20pub trait RequestExt {
22 fn path(&self) -> &Path;
24}
25
26impl RequestExt for Request<Body> {
27 fn path(&self) -> &Path {
29 Path::new(self.uri().path())
30 }
31}
32
33pub struct StaticResponseCode(StatusCode);
35
36impl HttpResponder for StaticResponseCode {
37 fn respond(&self, _: &Request<Body>, _: Response<Body>) -> BoxFuture<'_, Response<Body>> {
38 ready(Response::builder().status(self.0).body(Body::empty()).unwrap()).boxed()
39 }
40}
41
42impl StaticResponseCode {
43 pub fn new(status: StatusCode) -> Self {
45 Self(status)
46 }
47
48 pub fn ok() -> Self {
50 Self(StatusCode::OK)
51 }
52
53 pub fn not_found() -> Self {
55 Self(StatusCode::NOT_FOUND)
56 }
57
58 pub fn server_error() -> Self {
60 Self(StatusCode::INTERNAL_SERVER_ERROR)
61 }
62
63 pub fn too_many_requests() -> Self {
65 Self(StatusCode::TOO_MANY_REQUESTS)
66 }
67}
68
69#[derive(Debug, Default)]
71pub struct DynamicResponseSetter(Arc<AtomicU16>);
72
73impl DynamicResponseSetter {
74 pub fn set(&self, code: u16) {
76 self.0.store(code, Ordering::SeqCst);
77 }
78}
79
80pub struct DynamicResponseCode {
82 code: Arc<AtomicU16>,
83}
84
85impl HttpResponder for DynamicResponseCode {
86 fn respond<'a>(
87 &'a self,
88 _: &'a Request<Body>,
89 _: Response<Body>,
90 ) -> BoxFuture<'_, Response<Body>> {
91 ready(
92 Response::builder()
93 .status(self.code.load(Ordering::SeqCst))
94 .body(Body::empty())
95 .unwrap(),
96 )
97 .boxed()
98 }
99}
100
101impl DynamicResponseCode {
102 pub fn new(initial: u16) -> (Self, DynamicResponseSetter) {
104 let setter = DynamicResponseSetter(Arc::new(initial.into()));
105 (Self { code: Arc::clone(&setter.0) }, setter)
106 }
107}
108
109#[derive(Debug, Default)]
111pub struct AtomicToggle(Arc<AtomicBool>);
112
113impl AtomicToggle {
114 pub fn new(initial: bool) -> Self {
116 Self(Arc::new(initial.into()))
117 }
118
119 pub fn set(&self) {
121 self.0.store(true, Ordering::SeqCst);
122 }
123
124 pub fn unset(&self) {
126 self.0.store(false, Ordering::SeqCst);
127 }
128}
129
130pub struct Toggleable<H: HttpResponder> {
132 enabled: Arc<AtomicBool>,
133 responder: H,
134}
135
136impl<H: HttpResponder> HttpResponder for Toggleable<H> {
137 fn respond<'a>(
138 &'a self,
139 request: &'a Request<Body>,
140 response: Response<Body>,
141 ) -> BoxFuture<'_, Response<Body>> {
142 if self.enabled.load(Ordering::SeqCst) {
143 self.responder.respond(request, response)
144 } else {
145 ready(response).boxed()
146 }
147 }
148}
149
150impl<H: HttpResponder> Toggleable<H> {
151 pub fn new(should_override: &AtomicToggle, responder: H) -> Self {
153 Self { enabled: Arc::clone(&should_override.0), responder }
154 }
155}
156
157pub struct ForRequestCount<H: HttpResponder> {
159 remaining: Mutex<u32>,
160 responder: H,
161}
162
163impl<H: HttpResponder> HttpResponder for ForRequestCount<H> {
164 fn respond<'a>(
165 &'a self,
166 request: &'a Request<Body>,
167 response: Response<Body>,
168 ) -> BoxFuture<'_, Response<Body>> {
169 let mut remaining = self.remaining.lock();
170 if *remaining > 0 {
171 *remaining -= 1;
172 drop(remaining);
173 self.responder.respond(request, response)
174 } else {
175 ready(response).boxed()
176 }
177 }
178}
179
180impl<H: HttpResponder> ForRequestCount<H> {
181 pub fn new(count: u32, responder: H) -> Self {
183 Self { remaining: Mutex::new(count), responder }
184 }
185}
186
187pub struct ForPath<H: HttpResponder> {
189 path: PathBuf,
190 responder: H,
191}
192
193impl<H: HttpResponder> HttpResponder for ForPath<H> {
194 fn respond<'a>(
195 &'a self,
196 request: &'a Request<Body>,
197 response: Response<Body>,
198 ) -> BoxFuture<'_, Response<Body>> {
199 if self.path == request.path() {
200 self.responder.respond(request, response)
201 } else {
202 ready(response).boxed()
203 }
204 }
205}
206
207impl<H: HttpResponder> ForPath<H> {
208 pub fn new(path: impl Into<PathBuf>, responder: H) -> Self {
210 Self { path: path.into(), responder }
211 }
212}
213
214pub struct ForPaths<H: HttpResponder> {
216 paths: HashSet<PathBuf>,
217 responder: H,
218}
219
220impl<H: HttpResponder> HttpResponder for ForPaths<H> {
221 fn respond<'a>(
222 &'a self,
223 request: &'a Request<Body>,
224 response: Response<Body>,
225 ) -> BoxFuture<'_, Response<Body>> {
226 if self.paths.contains(request.path()) {
227 self.responder.respond(request, response)
228 } else {
229 ready(response).boxed()
230 }
231 }
232}
233
234impl<H: HttpResponder> ForPaths<H> {
235 pub fn new(paths: HashSet<PathBuf>, responder: H) -> Self {
237 Self { paths, responder }
238 }
239}
240
241pub struct ForPathPrefix<H: HttpResponder> {
244 prefix: PathBuf,
245 responder: H,
246}
247
248impl<H: HttpResponder> HttpResponder for ForPathPrefix<H> {
249 fn respond<'a>(
250 &'a self,
251 request: &'a Request<Body>,
252 response: Response<Body>,
253 ) -> BoxFuture<'_, Response<Body>> {
254 if request.path().starts_with(&self.prefix) {
255 self.responder.respond(request, response)
256 } else {
257 ready(response).boxed()
258 }
259 }
260}
261
262impl<H: HttpResponder> ForPathPrefix<H> {
263 pub fn new(prefix: impl Into<PathBuf>, responder: H) -> Self {
266 Self { prefix: prefix.into(), responder }
267 }
268}
269
270pub struct ForPathSuffix<H: HttpResponder> {
275 suffix: PathBuf,
276 responder: H,
277}
278
279impl<H: HttpResponder> HttpResponder for ForPathSuffix<H> {
280 fn respond<'a>(
281 &'a self,
282 request: &'a Request<Body>,
283 response: Response<Body>,
284 ) -> BoxFuture<'_, Response<Body>> {
285 if request.path().ends_with(&self.suffix) {
286 self.responder.respond(request, response)
287 } else {
288 ready(response).boxed()
289 }
290 }
291}
292
293impl<H: HttpResponder> ForPathSuffix<H> {
294 pub fn new(suffix: impl Into<PathBuf>, responder: H) -> Self {
297 Self { suffix: suffix.into(), responder }
298 }
299}
300pub struct OncePerPath<H: HttpResponder> {
302 responder: H,
303 failed_paths: Mutex<HashSet<PathBuf>>,
304}
305
306impl<H: HttpResponder> HttpResponder for OncePerPath<H> {
307 fn respond<'a>(
308 &'a self,
309 request: &'a Request<Body>,
310 response: Response<Body>,
311 ) -> BoxFuture<'_, Response<Body>> {
312 if self.failed_paths.lock().insert(request.path().to_owned()) {
313 self.responder.respond(request, response)
314 } else {
315 ready(response).boxed()
316 }
317 }
318}
319
320impl<H: HttpResponder> OncePerPath<H> {
321 pub fn new(responder: H) -> Self {
323 Self { responder, failed_paths: Mutex::new(HashSet::new()) }
324 }
325}
326
327pub trait JsonTransformer: Send + Sync + Clone + 'static {
330 fn transform(&self, v: serde_json::Value) -> serde_json::Value;
332}
333
334impl<F> JsonTransformer for F
335where
336 F: Fn(serde_json::Value) -> serde_json::Value + Send + Sync + Clone + 'static,
337{
338 fn transform(&self, v: serde_json::Value) -> serde_json::Value {
339 (self)(v)
340 }
341}
342
343impl<T: JsonTransformer> HttpResponder for T {
345 fn respond(
346 &self,
347 _: &Request<Body>,
348 response: Response<Body>,
349 ) -> BoxFuture<'_, Response<Body>> {
350 async move {
351 let (mut parts, body) = response.into_parts();
352 parts.headers.remove(http::header::CONTENT_LENGTH);
353 let bytes = body_to_bytes(body).await;
354 let value = self.transform(serde_json::from_reader(bytes.as_slice()).unwrap());
355 let bytes = serde_json::to_vec(&value).unwrap();
356 Response::from_parts(parts, Body::from(bytes))
357 }
358 .boxed()
359 }
360}
361
362pub struct NotifyWhenRequested {
364 notify: mpsc::UnboundedSender<()>,
365}
366
367impl NotifyWhenRequested {
368 pub fn new() -> (Self, mpsc::UnboundedReceiver<()>) {
370 let (tx, rx) = mpsc::unbounded();
371 (Self { notify: tx }, rx)
372 }
373}
374
375impl HttpResponder for NotifyWhenRequested {
376 fn respond(
377 &self,
378 _: &Request<Body>,
379 response: Response<Body>,
380 ) -> BoxFuture<'_, Response<Body>> {
381 self.notify.unbounded_send(()).unwrap();
382 ready(response).boxed()
383 }
384}
385
386pub struct BlockedResponse {
388 path: PathBuf,
389 unblocker: oneshot::Sender<()>,
390}
391
392impl BlockedResponse {
393 pub fn path(&self) -> &Path {
395 &self.path
396 }
397
398 pub fn unblock(self) {
400 self.unblocker.send(()).expect("request to still be pending")
401 }
402}
403
404pub struct BlockResponseHeaders {
406 blocked_responses: mpsc::UnboundedSender<BlockedResponse>,
407}
408
409impl BlockResponseHeaders {
410 pub fn new() -> (Self, mpsc::UnboundedReceiver<BlockedResponse>) {
412 let (sender, receiver) = mpsc::unbounded();
413
414 (Self { blocked_responses: sender }, receiver)
415 }
416}
417
418impl HttpResponder for BlockResponseHeaders {
419 fn respond(
420 &self,
421 request: &Request<Body>,
422 response: Response<Body>,
423 ) -> BoxFuture<'_, Response<Body>> {
424 let path = request.path().to_owned();
427 let mut blocked_responses = self.blocked_responses.clone();
428 async move {
429 let (unblocker, waiter) = oneshot::channel();
430 blocked_responses
431 .send(BlockedResponse { path, unblocker })
432 .await
433 .expect("receiver to still exist");
434 waiter.await.expect("request to be unblocked");
435 response
436 }
437 .boxed()
438 }
439}
440
441pub struct BlockedBody {
443 path: PathBuf,
444 unblocker: Box<dyn FnOnce() + Send>,
445}
446
447impl BlockedBody {
448 pub fn path(&self) -> &Path {
450 &self.path
451 }
452
453 pub fn unblock(self) {
455 (self.unblocker)()
456 }
457}
458
459pub struct BlockResponseBodies {
461 blocked_responses: mpsc::UnboundedSender<BlockedBody>,
462}
463
464impl BlockResponseBodies {
465 pub fn new() -> (Self, mpsc::UnboundedReceiver<BlockedBody>) {
467 let (sender, receiver) = mpsc::unbounded();
468 (Self { blocked_responses: sender }, receiver)
469 }
470}
471
472impl HttpResponder for BlockResponseBodies {
473 fn respond(
474 &self,
475 request: &Request<Body>,
476 mut response: Response<Body>,
477 ) -> BoxFuture<'_, Response<Body>> {
478 let path = request.path().to_owned();
479 let mut blocked_responses = self.blocked_responses.clone();
480 async move {
481 let (mut sender, new_body) = Body::channel();
484 let old_body = std::mem::replace(response.body_mut(), new_body);
485 let contents = body_to_bytes(old_body).await;
486
487 let unblocker =
489 Box::new(move || sender.try_send_data(contents.into()).expect("sending body"));
490 let () = blocked_responses
491 .send(BlockedBody { path, unblocker })
492 .await
493 .expect("receiver to still exist");
494
495 response
498 }
499 .boxed()
500 }
501}
502
503pub struct BlockResponseBodyOnce {
506 #[allow(clippy::type_complexity)]
507 notify: Mutex<Option<oneshot::Sender<Box<dyn FnOnce() + Send>>>>,
508}
509
510impl BlockResponseBodyOnce {
511 pub fn new() -> (Self, oneshot::Receiver<Box<dyn FnOnce() + Send>>) {
513 let (sender, receiver) = oneshot::channel();
514
515 (Self { notify: Mutex::new(Some(sender)) }, receiver)
516 }
517}
518
519impl HttpResponder for BlockResponseBodyOnce {
520 fn respond(
521 &self,
522 _: &Request<Body>,
523 mut response: Response<Body>,
524 ) -> BoxFuture<'_, Response<Body>> {
525 let notify = self.notify.lock().take().expect("a single request for this path");
526
527 async move {
528 let (mut sender, new_body) = Body::channel();
531 let old_body = std::mem::replace(response.body_mut(), new_body);
532 let contents = body_to_bytes(old_body).await;
533
534 notify
536 .send(Box::new(move || {
537 sender.try_send_data(contents.into()).expect("sending body")
538 }))
539 .map_err(|_| ())
540 .expect("receiver to still exist");
541
542 response
545 }
546 .boxed()
547 }
548}
549
550async fn body_to_bytes(body: Body) -> Vec<u8> {
551 body.collect().await.expect("body to bytes").to_bytes().to_vec()
552}
553
554pub struct OneByteShortThenError;
557
558impl HttpResponder for OneByteShortThenError {
559 fn respond(
560 &self,
561 _: &Request<Body>,
562 response: Response<Body>,
563 ) -> BoxFuture<'_, Response<Body>> {
564 async {
565 let (parts, body) = response.into_parts();
566 let mut bytes = body_to_bytes(body).await;
567 if bytes.pop().is_none() {
568 panic!("can't short 0 bytes");
569 }
570 Response::from_parts(
571 parts,
572 Body::wrap_stream(futures::stream::iter(vec![
573 Ok(bytes),
574 Err("all_but_one_byte_then_eror has sent all but one bytes".to_string()),
575 ])),
576 )
577 }
578 .boxed()
579 }
580}
581
582pub struct NBytesThenError {
585 n: usize,
586}
587
588impl NBytesThenError {
589 pub fn new(n: usize) -> Self {
591 Self { n }
592 }
593}
594impl HttpResponder for NBytesThenError {
595 fn respond(
596 &self,
597 _: &Request<Body>,
598 response: Response<Body>,
599 ) -> BoxFuture<'_, Response<Body>> {
600 let n = self.n;
601 async move {
602 let (parts, body) = response.into_parts();
603 let mut bytes = body_to_bytes(body).await;
604 let initial_len = bytes.len();
605 if initial_len <= n {
606 panic!("not enough bytes to shorten, {initial_len} {n}");
607 }
608 bytes.truncate(n);
609 Response::from_parts(
610 parts,
611 Body::wrap_stream(futures::stream::iter(vec![
612 Ok(bytes),
613 Err("all_but_one_byte_then_eror has sent all but one bytes".to_string()),
614 ])),
615 )
616 }
617 .boxed()
618 }
619}
620
621pub struct OneByteShortThenDisconnect;
624
625impl HttpResponder for OneByteShortThenDisconnect {
626 fn respond(
627 &self,
628 _: &Request<Body>,
629 response: Response<Body>,
630 ) -> BoxFuture<'_, Response<Body>> {
631 async {
632 let (parts, body) = response.into_parts();
633 let mut bytes = body_to_bytes(body).await;
634 if bytes.pop().is_none() {
635 panic!("can't short 0 bytes");
636 }
637 Response::from_parts(
638 parts,
639 Body::wrap_stream(futures::stream::iter(vec![Result::<Vec<u8>, String>::Ok(
640 bytes,
641 )])),
642 )
643 }
644 .boxed()
645 }
646}
647
648pub struct OneByteFlipped;
651
652impl HttpResponder for OneByteFlipped {
653 fn respond(
654 &self,
655 _: &Request<Body>,
656 response: Response<Body>,
657 ) -> BoxFuture<'_, Response<Body>> {
658 async {
659 let (parts, body) = response.into_parts();
660 let mut bytes = body_to_bytes(body).await;
661 if bytes.is_empty() {
662 panic!("can't flip 0 bytes");
663 }
664 bytes[0] = !bytes[0];
665 Response::from_parts(parts, Body::from(bytes))
666 }
667 .boxed()
668 }
669}
670
671pub struct Hang;
673
674impl HttpResponder for Hang {
675 fn respond(&self, _: &Request<Body>, _: Response<Body>) -> BoxFuture<'_, Response<Body>> {
676 pending().boxed()
677 }
678}
679
680pub struct HangBody;
682
683impl HttpResponder for HangBody {
684 fn respond(
685 &self,
686 _: &Request<Body>,
687 response: Response<Body>,
688 ) -> BoxFuture<'_, Response<Body>> {
689 async {
690 let (parts, _) = response.into_parts();
691 Response::from_parts(
692 parts,
693 Body::wrap_stream(futures::stream::pending::<Result<Vec<u8>, String>>()),
694 )
695 }
696 .boxed()
697 }
698}
699
700pub struct Once<H: HttpResponder> {
702 already_forwarded: AtomicBool,
703 responder: H,
704}
705
706impl<H: HttpResponder> HttpResponder for Once<H> {
707 fn respond<'a>(
708 &'a self,
709 request: &'a Request<Body>,
710 response: Response<Body>,
711 ) -> BoxFuture<'_, Response<Body>> {
712 if self.already_forwarded.fetch_or(true, Ordering::SeqCst) {
713 ready(response).boxed()
714 } else {
715 self.responder.respond(request, response)
716 }
717 }
718}
719
720impl<H: HttpResponder> Once<H> {
721 pub fn new(responder: H) -> Self {
723 Self { already_forwarded: AtomicBool::new(false), responder }
724 }
725}
726
727pub struct OverrideNth<H: HttpResponder> {
729 n: u32,
730 call_count: AtomicU32,
731 responder: H,
732}
733
734impl<H: HttpResponder> HttpResponder for OverrideNth<H> {
735 fn respond<'a>(
736 &'a self,
737 request: &'a Request<Body>,
738 response: Response<Body>,
739 ) -> BoxFuture<'_, Response<Body>> {
740 if self.call_count.fetch_add(1, Ordering::SeqCst) + 1 == self.n {
741 self.responder.respond(request, response)
742 } else {
743 ready(response).boxed()
744 }
745 }
746}
747
748impl<H: HttpResponder> OverrideNth<H> {
749 pub fn new(n: u32, responder: H) -> Self {
751 Self { n, call_count: AtomicU32::new(0), responder }
752 }
753}
754
755#[derive(Debug)]
757pub struct HistoryEntry {
758 uri_path: PathBuf,
759 headers: hyper::HeaderMap<hyper::header::HeaderValue>,
760}
761
762impl HistoryEntry {
763 pub fn uri_path(&self) -> &Path {
765 &self.uri_path
766 }
767
768 pub fn headers(&self) -> &http::HeaderMap<hyper::header::HeaderValue> {
770 &self.headers
771 }
772}
773
774pub struct History(Arc<Mutex<Vec<HistoryEntry>>>);
776
777impl History {
778 pub fn take(&self) -> Vec<HistoryEntry> {
780 std::mem::take(&mut self.0.lock())
781 }
782}
783
784pub struct Record {
786 history: History,
787}
788
789impl Record {
790 pub fn new() -> (Self, History) {
792 let history = Arc::new(Mutex::new(vec![]));
793 (Self { history: History(Arc::clone(&history)) }, History(history))
794 }
795}
796
797impl HttpResponder for Record {
798 fn respond<'a>(
799 &'a self,
800 request: &'a Request<Body>,
801 response: Response<Body>,
802 ) -> BoxFuture<'_, Response<Body>> {
803 self.history.0.lock().push(HistoryEntry {
804 uri_path: request.path().to_owned(),
805 headers: request.headers().clone(),
806 });
807 ready(response).boxed()
808 }
809}
810
811pub struct Filter<F: FilterFn, T: HttpResponder> {
813 filter: F,
814 handler: T,
815}
816
817pub trait FilterFn: Send + Sync + 'static {
819 fn filter(&self, request: &Request<Body>) -> bool;
821}
822
823impl<F> FilterFn for F
824where
825 F: Fn(&Request<Body>) -> bool + Send + Sync + 'static,
826{
827 fn filter(&self, request: &Request<Body>) -> bool {
828 (self)(request)
829 }
830}
831
832pub fn is_range_request(request: &Request<Body>) -> bool {
834 request.headers().get(http::header::RANGE).is_some()
835}
836
837impl<F: FilterFn, T: HttpResponder> Filter<F, T> {
838 pub fn new(filter: F, handler: T) -> Self {
840 Self { filter, handler }
841 }
842}
843
844impl<F: FilterFn, T: HttpResponder> HttpResponder for Filter<F, T> {
845 fn respond<'a>(
846 &'a self,
847 request: &'a Request<Body>,
848 response: Response<Body>,
849 ) -> BoxFuture<'_, Response<Body>> {
850 if self.filter.filter(request) {
851 self.handler.respond(request, response)
852 } else {
853 ready(response).boxed()
854 }
855 }
856}
857
858pub struct OverwriteStatusCode {
860 code: http::StatusCode,
861}
862
863impl OverwriteStatusCode {
864 pub fn new(code: http::StatusCode) -> Self {
866 Self { code }
867 }
868}
869
870impl HttpResponder for OverwriteStatusCode {
871 fn respond(
872 &self,
873 _: &Request<Body>,
874 mut response: Response<Body>,
875 ) -> BoxFuture<'_, Response<Body>> {
876 *response.status_mut() = self.code;
877 futures::future::ready(response).boxed()
878 }
879}
880
881pub struct Chain {
883 responders: Vec<Box<dyn HttpResponder>>,
884}
885
886impl Chain {
887 pub fn new(responders: Vec<Box<dyn HttpResponder>>) -> Self {
889 Self { responders }
890 }
891}
892
893impl HttpResponder for Chain {
894 fn respond<'a>(
895 &'a self,
896 request: &'a Request<Body>,
897 mut response: Response<Body>,
898 ) -> BoxFuture<'a, Response<Body>> {
899 async move {
900 for responder in self.responders.iter() {
901 response = responder.respond(request, response).await;
902 }
903 response
904 }
905 .boxed()
906 }
907}
908
909pub struct FailOneThenTemporarilyBlock {
915 path_to_fail: Arc<Mutex<Option<PathBuf>>>,
916 block_until: Shared<oneshot::Receiver<()>>,
917}
918
919impl FailOneThenTemporarilyBlock {
920 pub fn new() -> (Self, oneshot::Sender<()>) {
922 let (send, recv) = oneshot::channel();
923 (Self { path_to_fail: Arc::new(Mutex::new(None)), block_until: recv.shared() }, send)
924 }
925}
926
927impl HttpResponder for FailOneThenTemporarilyBlock {
928 fn respond(&self, request: &Request<Body>, _: Response<Body>) -> BoxFuture<'_, Response<Body>> {
929 let response =
930 Response::builder().status(StatusCode::NOT_FOUND).body(Body::empty()).unwrap();
931 match &mut *self.path_to_fail.lock() {
932 o @ None => {
933 *o = Some(request.path().to_owned());
934 ready(response).boxed()
935 }
936 Some(path_to_fail) if path_to_fail == request.path() => ready(response).boxed(),
937 _ => {
938 let block_until = self.block_until.clone();
939 async move {
940 block_until.await.unwrap();
941 response
942 }
943 }
944 .boxed(),
945 }
946 }
947}