mirror of
https://github.com/Microsoft/vscode
synced 2024-10-01 08:50:48 +00:00
forwarding: make https work for port forwarding (#213943)
Closes https://github.com/microsoft/vscode/issues/201465
This commit is contained in:
parent
b82c3b9087
commit
54dd0ecc65
|
@ -2,7 +2,7 @@
|
|||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
use super::protocol::{self, PortPrivacy};
|
||||
use super::protocol::{self, PortPrivacy, PortProtocol};
|
||||
use crate::auth;
|
||||
use crate::constants::{IS_INTERACTIVE_CLI, PROTOCOL_VERSION_TAG, TUNNEL_SERVICE_USER_AGENT};
|
||||
use crate::state::{LauncherPaths, PersistedState};
|
||||
|
@ -221,8 +221,11 @@ impl ActiveTunnel {
|
|||
&self,
|
||||
port_number: u16,
|
||||
privacy: PortPrivacy,
|
||||
protocol: PortProtocol,
|
||||
) -> Result<(), AnyError> {
|
||||
self.manager.add_port_tcp(port_number, privacy).await?;
|
||||
self.manager
|
||||
.add_port_tcp(port_number, privacy, protocol)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -972,13 +975,14 @@ impl ActiveTunnelManager {
|
|||
&self,
|
||||
port_number: u16,
|
||||
privacy: PortPrivacy,
|
||||
protocol: PortProtocol,
|
||||
) -> Result<(), WrappedError> {
|
||||
self.relay
|
||||
.lock()
|
||||
.await
|
||||
.add_port(&TunnelPort {
|
||||
port_number,
|
||||
protocol: Some(TUNNEL_PROTOCOL_AUTO.to_owned()),
|
||||
protocol: Some(protocol.to_contract_str().to_string()),
|
||||
access_control: Some(privacy_to_tunnel_acl(privacy)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
|
@ -27,7 +27,7 @@ use super::{
|
|||
protocol::{
|
||||
self,
|
||||
forward_singleton::{PortList, SetPortsResponse},
|
||||
PortPrivacy,
|
||||
PortPrivacy, PortProtocol,
|
||||
},
|
||||
shutdown_signal::ShutdownSignal,
|
||||
};
|
||||
|
@ -71,8 +71,13 @@ impl PortCount {
|
|||
}
|
||||
}
|
||||
}
|
||||
#[derive(Clone)]
|
||||
struct PortMapRec {
|
||||
count: PortCount,
|
||||
protocol: PortProtocol,
|
||||
}
|
||||
|
||||
type PortMap = HashMap<u16, PortCount>;
|
||||
type PortMap = HashMap<u16, PortMapRec>;
|
||||
|
||||
/// The PortForwardingHandle is given out to multiple consumers to allow
|
||||
/// them to set_ports that they want to be forwarded.
|
||||
|
@ -99,8 +104,8 @@ impl PortForwardingSender {
|
|||
for p in current.iter() {
|
||||
if !ports.contains(p) {
|
||||
let n = v.get_mut(&p.number).expect("expected port in map");
|
||||
n[p.privacy] -= 1;
|
||||
if n.is_empty() {
|
||||
n.count[p.privacy] -= 1;
|
||||
if n.count.is_empty() {
|
||||
v.remove(&p.number);
|
||||
}
|
||||
}
|
||||
|
@ -110,12 +115,19 @@ impl PortForwardingSender {
|
|||
if !current.contains(p) {
|
||||
match v.get_mut(&p.number) {
|
||||
Some(n) => {
|
||||
n[p.privacy] += 1;
|
||||
n.count[p.privacy] += 1;
|
||||
n.protocol = p.protocol;
|
||||
}
|
||||
None => {
|
||||
let mut pc = PortCount::default();
|
||||
pc[p.privacy] += 1;
|
||||
v.insert(p.number, pc);
|
||||
let mut count = PortCount::default();
|
||||
count[p.privacy] += 1;
|
||||
v.insert(
|
||||
p.number,
|
||||
PortMapRec {
|
||||
count,
|
||||
protocol: p.protocol,
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -164,22 +176,34 @@ impl PortForwardingReceiver {
|
|||
while self.receiver.changed().await.is_ok() {
|
||||
let next = self.receiver.borrow().clone();
|
||||
|
||||
for (port, count) in current.iter() {
|
||||
let privacy = count.primary_privacy();
|
||||
if !matches!(next.get(port), Some(n) if n.primary_privacy() == privacy) {
|
||||
for (port, rec) in current.iter() {
|
||||
let privacy = rec.count.primary_privacy();
|
||||
if !matches!(next.get(port), Some(n) if n.count.primary_privacy() == privacy) {
|
||||
match tunnel.remove_port(*port).await {
|
||||
Ok(_) => info!(log, "stopped forwarding port {} at {:?}", *port, privacy),
|
||||
Err(e) => error!(log, "failed to stop forwarding port {}: {}", port, e),
|
||||
Ok(_) => info!(
|
||||
log,
|
||||
"stopped forwarding {} port {} at {:?}", rec.protocol, *port, privacy
|
||||
),
|
||||
Err(e) => error!(
|
||||
log,
|
||||
"failed to stop forwarding {} port {}: {}", rec.protocol, port, e
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (port, count) in next.iter() {
|
||||
let privacy = count.primary_privacy();
|
||||
if !matches!(current.get(port), Some(n) if n.primary_privacy() == privacy) {
|
||||
match tunnel.add_port_tcp(*port, privacy).await {
|
||||
Ok(_) => info!(log, "forwarding port {} at {:?}", port, privacy),
|
||||
Err(e) => error!(log, "failed to forward port {}: {}", port, e),
|
||||
for (port, rec) in next.iter() {
|
||||
let privacy = rec.count.primary_privacy();
|
||||
if !matches!(current.get(port), Some(n) if n.count.primary_privacy() == privacy) {
|
||||
match tunnel.add_port_tcp(*port, privacy, rec.protocol).await {
|
||||
Ok(_) => info!(
|
||||
log,
|
||||
"forwarding {} port {} at {:?}", rec.protocol, port, privacy
|
||||
),
|
||||
Err(e) => error!(
|
||||
log,
|
||||
"failed to forward {} port {}: {}", rec.protocol, port, e
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,10 @@ use crate::{
|
|||
util::errors::{AnyError, CannotForwardControlPort, ServerHasClosed},
|
||||
};
|
||||
|
||||
use super::{dev_tunnels::ActiveTunnel, protocol::PortPrivacy};
|
||||
use super::{
|
||||
dev_tunnels::ActiveTunnel,
|
||||
protocol::{PortPrivacy, PortProtocol},
|
||||
};
|
||||
|
||||
pub enum PortForwardingRec {
|
||||
Forward(u16, PortPrivacy, oneshot::Sender<Result<String, AnyError>>),
|
||||
|
@ -89,7 +92,9 @@ impl PortForwardingProcessor {
|
|||
}
|
||||
|
||||
if !self.forwarded.contains(&port) {
|
||||
tunnel.add_port_tcp(port, privacy).await?;
|
||||
tunnel
|
||||
.add_port_tcp(port, privacy, PortProtocol::Auto)
|
||||
.await?;
|
||||
self.forwarded.insert(port);
|
||||
}
|
||||
|
||||
|
|
|
@ -299,10 +299,40 @@ pub enum PortPrivacy {
|
|||
Private,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Copy, Eq, Clone, Debug)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum PortProtocol {
|
||||
Auto,
|
||||
Http,
|
||||
Https,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for PortProtocol {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.to_contract_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for PortProtocol {
|
||||
fn default() -> Self {
|
||||
Self::Auto
|
||||
}
|
||||
}
|
||||
|
||||
impl PortProtocol {
|
||||
pub fn to_contract_str(&self) -> &'static str {
|
||||
match *self {
|
||||
Self::Auto => tunnels::contracts::TUNNEL_PROTOCOL_AUTO,
|
||||
Self::Http => tunnels::contracts::TUNNEL_PROTOCOL_HTTP,
|
||||
Self::Https => tunnels::contracts::TUNNEL_PROTOCOL_HTTPS,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod forward_singleton {
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::PortPrivacy;
|
||||
use super::{PortPrivacy, PortProtocol};
|
||||
|
||||
pub const METHOD_SET_PORTS: &str = "set_ports";
|
||||
|
||||
|
@ -310,6 +340,7 @@ pub mod forward_singleton {
|
|||
pub struct PortRec {
|
||||
pub number: u16,
|
||||
pub privacy: PortPrivacy,
|
||||
pub protocol: PortProtocol,
|
||||
}
|
||||
|
||||
pub type PortList = Vec<PortRec>;
|
||||
|
|
|
@ -37,6 +37,7 @@ class Tunnel implements vscode.Tunnel {
|
|||
constructor(
|
||||
public readonly remoteAddress: { port: number; host: string },
|
||||
public readonly privacy: TunnelPrivacyId,
|
||||
public readonly protocol: 'http' | 'https',
|
||||
) { }
|
||||
|
||||
public setPortFormat(formatString: string) {
|
||||
|
@ -82,7 +83,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
|||
{
|
||||
tunnelFeatures: {
|
||||
elevation: false,
|
||||
protocol: false,
|
||||
protocol: true,
|
||||
privacyOptions: [
|
||||
{ themeIcon: 'globe', id: TunnelPrivacyId.Public, label: vscode.l10n.t('Public') },
|
||||
{ themeIcon: 'lock', id: TunnelPrivacyId.Private, label: vscode.l10n.t('Private') },
|
||||
|
@ -152,6 +153,7 @@ class TunnelProvider implements vscode.TunnelProvider {
|
|||
const tunnel = new Tunnel(
|
||||
tunnelOptions.remoteAddress,
|
||||
(tunnelOptions.privacy as TunnelPrivacyId) || TunnelPrivacyId.Private,
|
||||
tunnelOptions.protocol === 'https' ? 'https' : 'http',
|
||||
);
|
||||
|
||||
this.tunnels.add(tunnel);
|
||||
|
@ -238,7 +240,7 @@ class TunnelProvider implements vscode.TunnelProvider {
|
|||
return;
|
||||
}
|
||||
|
||||
const ports = [...this.tunnels].map(t => ({ number: t.remoteAddress.port, privacy: t.privacy }));
|
||||
const ports = [...this.tunnels].map(t => ({ number: t.remoteAddress.port, privacy: t.privacy, protocol: t.protocol }));
|
||||
this.state.process.stdin.write(`${JSON.stringify(ports)}\n`);
|
||||
|
||||
if (ports.length === 0 && !this.state.cleanupTimeout) {
|
||||
|
|
Loading…
Reference in a new issue