Q:

How to read body from response with status 101 Switching Protocols

I am connected to a server, in Kubernetes cluster, with POST request and headers to upgrade the request.  I am using the following function:  
func PostRequest(client *http. Client, url string, bodyData []byte) (*http. Response, error){
    req, _ := http. NewRequest("POST", url, bytes. NewBuffer(bodyData))
    //req. Header. Set("Authorization", "Bearer " + BEARER_TOKEN)
    req. Header. Set("X-Stream-Protocol-Version", "v2.channel.k8s.io")
    req. Header. Set("X-Stream-Protocol-Version", "channel.k8s.io")
    req. Header. Set("Upgrade", "SPDY/3.1")
    req. Header. Set("Connection","upgrade")
    req. Header. Set("Content-Type", "application/x-www-form-urlencoded")

    resp, err := (*client).Do(req)

    return resp, err
}

After I received the response, I tried to read it but it stuck when I read the body:  
url2 := "https://<serveri_ip>:10250/exec/default/mypod/mycontainer?command=ls&command=/&input=1&output=1&tty=1"

resp, err := PostRequest(api. GlobalClient, url2, []byte(""))
fmt. Println(r. Status)
fmt. Println(r. Header)
bodyBytes, err := ioutil. ReadAll(r. Body) // -> it stuck here
fmt. Println(string(bodyBytes))  

I suppose it tried to open websocket, so I tried to use gorilla websocket library like that:  
u := url. URL{Scheme: "ws", Host: "<node_ip>:10250", Path: "/exec/default/mypod/mycontainer?command=ls&command=/&input=1&output=1&tty=1"}

interrupt := make(chan os. Signal, 1)
signal. Notify(interrupt, os. Interrupt)

c, _, err := websocket. DefaultDialer. Dial(u. String(), nil)
if err ! = nil {
  log. Fatal("dial:", err)
}
defer c.Close()

But it printed an error:  

2020/04/04 20:51:25 dial:websocket: bad handshake

What I am doing wrong? 
How can I read response body from status "Switching Protocols"

A:

I managed to do it with Kubernetes go-client library:  
package main

import (
    "crypto/tls"
    "fmt"
    "net/http"
    "net/url"
    "os"
    "time"

    restclient "k8s.io/client-go/rest"
    "k8s.io/client-go/tools/remotecommand"
)

func main(){

    /*req. Header. Add("X-Stream-Protocol-Version", "v4.channel.k8s.io")
    req. Header. Add("X-Stream-Protocol-Version", "v3.channel.k8s.io")
    req. Header. Add("X-Stream-Protocol-Version", "v2.channel.k8s.io")
    req. Header. Add("X-Stream-Protocol-Version", "channel.k8s.io")
    req. Header. Add("Connection", "upgrade")
    req. Header. Add("Upgrade", "SPDY/3.1")*/
    //url2 := "https://123.123.123.123:10250/exec/default/my-pod/nginx?command=ls&command=/&input=1&output=1&tty=1"
    tr := &http. Transport{
        MaxIdleConns:       10,
        IdleConnTimeout:    30 * time. Second,
        DisableCompression: true,
        TLSClientConfig: &tls. Config{InsecureSkipVerify: true},
    }

    config := &restclient. Config{
        Host:                "https://123.123.123.123:10250",
        APIPath:             "/exec/default/my-pod/nginx",
        TLSClientConfig:     restclient. TLSClientConfig{
            Insecure: true,
        },
        Transport:           tr,
    }

    url3 := &url. URL{
        Scheme:     "https",
        Opaque:     "",
        User:       nil,
        Host:       "123.123.123.123:10250",
        Path:       "/exec/default/my-pod/nginx",
        RawPath:    "",
        RawQuery:   "command=ls&command=/&input=1&output=1&tty=1",
    }
    exec, err := remotecommand. NewSPDYExecutor(config, "POST", url3)
    if err ! = nil {
        fmt. Println(err)
    }

    // Thanks for this blog post https://www.henryxieblogs.com/2019/05/
    err = exec. Stream(remotecommand. StreamOptions{
        Stdin:  os. Stdin,
        Stdout: os. Stdout,
        Stderr: os. Stderr,
        Tty:true,
    })

    fmt. Println(err)
}

