proxy.go (1960B)
1 // Copyright 2017 The Gorilla WebSocket Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package websocket 6 7 import ( 8 "bufio" 9 "encoding/base64" 10 "errors" 11 "net" 12 "net/http" 13 "net/url" 14 "strings" 15 ) 16 17 type netDialerFunc func(network, addr string) (net.Conn, error) 18 19 func (fn netDialerFunc) Dial(network, addr string) (net.Conn, error) { 20 return fn(network, addr) 21 } 22 23 func init() { 24 proxy_RegisterDialerType("http", func(proxyURL *url.URL, forwardDialer proxy_Dialer) (proxy_Dialer, error) { 25 return &httpProxyDialer{proxyURL: proxyURL, forwardDial: forwardDialer.Dial}, nil 26 }) 27 } 28 29 type httpProxyDialer struct { 30 proxyURL *url.URL 31 forwardDial func(network, addr string) (net.Conn, error) 32 } 33 34 func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) { 35 hostPort, _ := hostPortNoPort(hpd.proxyURL) 36 conn, err := hpd.forwardDial(network, hostPort) 37 if err != nil { 38 return nil, err 39 } 40 41 connectHeader := make(http.Header) 42 if user := hpd.proxyURL.User; user != nil { 43 proxyUser := user.Username() 44 if proxyPassword, passwordSet := user.Password(); passwordSet { 45 credential := base64.StdEncoding.EncodeToString([]byte(proxyUser + ":" + proxyPassword)) 46 connectHeader.Set("Proxy-Authorization", "Basic "+credential) 47 } 48 } 49 50 connectReq := &http.Request{ 51 Method: http.MethodConnect, 52 URL: &url.URL{Opaque: addr}, 53 Host: addr, 54 Header: connectHeader, 55 } 56 57 if err := connectReq.Write(conn); err != nil { 58 conn.Close() 59 return nil, err 60 } 61 62 // Read response. It's OK to use and discard buffered reader here becaue 63 // the remote server does not speak until spoken to. 64 br := bufio.NewReader(conn) 65 resp, err := http.ReadResponse(br, connectReq) 66 if err != nil { 67 conn.Close() 68 return nil, err 69 } 70 71 if resp.StatusCode != 200 { 72 conn.Close() 73 f := strings.SplitN(resp.Status, " ", 2) 74 return nil, errors.New(f[1]) 75 } 76 return conn, nil 77 }