Path: blob/main/components/gitpod-cli/cmd/ports-expose.go
2498 views
// Copyright (c) 2020 Gitpod GmbH. All rights reserved.1// Licensed under the GNU Affero General Public License (AGPL).2// See License.AGPL.txt in the project root for license information.34package cmd56import (7"fmt"8"net/http"9"net/http/httputil"10"net/url"11"strconv"1213"github.com/google/tcpproxy"14"github.com/gorilla/handlers"15"github.com/spf13/cobra"16"golang.org/x/xerrors"17)1819var rewriteHostHeader bool2021var portExposeCmd = &cobra.Command{22Use: "expose <local-port> [target-port]",23Short: "Makes a port available on 0.0.0.0 so that it can be exposed to the internet",24Long: ``,25Args: cobra.RangeArgs(1, 2),26RunE: func(cmd *cobra.Command, args []string) error {27srcp, err := strconv.ParseUint(args[0], 10, 16)28if err != nil {29return xerrors.Errorf("local-port cannot be parsed as int: %w", err)30}3132trgp := srcp + 133if len(args) > 1 {34var err error35trgp, err = strconv.ParseUint(args[1], 10, 16)36if err != nil {37return xerrors.Errorf("target-port cannot be parsed as int: %w", err)38}39}4041if rewriteHostHeader {42remote, _ := url.Parse(fmt.Sprintf("http://localhost:%d", srcp))43host := fmt.Sprintf("localhost:%d", srcp) // Spec: https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2344proxy := httputil.NewSingleHostReverseProxy(remote)45originalDirector := proxy.Director46proxy.Director = func(r *http.Request) {47originalDirector(r)48r.Host = host49}50// we want both X-Forwarded-Proto AND X-Forwarded-Host to reach the backend5152server := http.Server{53Addr: fmt.Sprintf(":%d", trgp),54Handler: handlers.ProxyHeaders(http.HandlerFunc(proxy.ServeHTTP)),55}56fmt.Printf("Proxying HTTP traffic: 0.0.0.0:%d -> 127.0.0.1:%d (with host rewriting)\n", trgp, srcp)57errchan := make(chan error)58go func() {59err := server.ListenAndServe()60errchan <- err61}()6263select {64case <-cmd.Context().Done():65server.Close()66case err := <-errchan:67return xerrors.Errorf("reverse proxy failed: %w", err)68}69return nil70}7172var p tcpproxy.Proxy73p.AddRoute(fmt.Sprintf(":%d", trgp), tcpproxy.To(fmt.Sprintf("127.0.0.1:%d", srcp)))74fmt.Printf("Forwarding traffic: 0.0.0.0:%d -> 127.0.0.1:%d\n", trgp, srcp)75errchan := make(chan error)76go func() {77err := p.Run()78errchan <- err79}()80select {81case <-cmd.Context().Done():82p.Close()83case err := <-errchan:84return xerrors.Errorf("reverse proxy failed: %w", err)85}86return nil87},88}8990var portExposeCmdAlias = &cobra.Command{91Hidden: true,92Deprecated: "please use `ports expose` instead.",93Use: "forward-port <local-port> [target-port]",94Short: portExposeCmd.Short,95Long: portExposeCmd.Long,96Args: portExposeCmd.Args,97RunE: portExposeCmd.RunE,98}99100func init() {101portsCmd.AddCommand(portExposeCmd)102portExposeCmd.Flags().BoolVarP(&rewriteHostHeader, "rewrite-host-header", "r", false, "rewrites the host header of passing HTTP requests to localhost")103104rootCmd.AddCommand(portExposeCmdAlias)105portExposeCmdAlias.Flags().BoolVarP(&rewriteHostHeader, "rewrite-host-header", "r", false, "rewrites the host header of passing HTTP requests to localhost")106}107108109