http1/protocol/
upgrade.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use std::{
    fmt::{Debug, Display},
    io::{Read, Write},
    sync::{Arc, Condvar, Mutex},
};

use super::connection::Connection;

#[derive(Debug)]
pub enum PendingUpgradeError {
    Failed,
    NoConnection,
}

impl std::error::Error for PendingUpgradeError {}

impl Display for PendingUpgradeError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            PendingUpgradeError::Failed => write!(f, "failed to upgrade connection"),
            PendingUpgradeError::NoConnection => write!(f, "no pending connection upgrade"),
        }
    }
}

#[derive(Default)]
enum UpgradeState {
    #[default]
    Waiting,
    Pending(Upgrade),
    Completed,
}

/// A pending connection upgrade.
#[derive(Clone)]
pub struct PendingUpgrade(Arc<(Mutex<UpgradeState>, Condvar)>);

/// A notifier that sends the upgraded connection when ready.
pub struct NotifyUpgradeReady(Arc<(Mutex<UpgradeState>, Condvar)>);

impl NotifyUpgradeReady {
    pub fn notify(self, upgrade: Upgrade) -> bool {
        let (mutex, cond_var) = &*self.0;
        match mutex.lock() {
            Ok(mut x) => {
                *x = UpgradeState::Pending(upgrade);
                cond_var.notify_one();
                true
            }
            Err(_) => false,
        }
    }
}

impl PendingUpgrade {
    pub(crate) fn new() -> (NotifyUpgradeReady, PendingUpgrade) {
        let pair = Arc::new((Mutex::new(UpgradeState::Waiting), Condvar::new()));
        (NotifyUpgradeReady(pair.clone()), PendingUpgrade(pair))
    }

    /// Wait for the connection upgrade to be available.
    pub fn wait(self) -> Result<Upgrade, PendingUpgradeError> {
        let (mutex, cond_var) = &*self.0;
        let mut lock = mutex.lock().map_err(|_| PendingUpgradeError::Failed)?;

        while matches!(*lock, UpgradeState::Waiting) {
            lock = cond_var
                .wait(lock)
                .map_err(|_| PendingUpgradeError::Failed)?;
        }

        match std::mem::take(&mut *lock) {
            UpgradeState::Pending(upgrade) => {
                let _ = std::mem::replace(&mut *lock, UpgradeState::Completed);
                Ok(upgrade)
            }
            UpgradeState::Completed => panic!("websocket upgrade was already completed"),
            UpgradeState::Waiting => unreachable!(),
        }
    }
}

impl Debug for PendingUpgrade {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_tuple("PendingUpgrade").finish()
    }
}

/// Provides the connection stream to write and read after a connection upgrade.
pub struct Upgrade(Connection);

impl Upgrade {
    pub(crate) fn new(conn: Connection) -> Self {
        Upgrade(conn)
    }

    pub fn try_clone(&self) -> Option<Self> {
        self.0.try_clone().map(Upgrade)
    }
}

impl Debug for Upgrade {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_tuple("Upgrade").finish()
    }
}

impl Read for Upgrade {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        Read::read(&mut self.0, buf)
    }
}

impl Write for Upgrade {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        Write::write(&mut self.0, buf)
    }

    fn flush(&mut self) -> std::io::Result<()> {
        Write::flush(&mut self.0)
    }
}