使用Golang转发HTTP流数据

package main

import (
	"fmt"
	"net/http"
	"strings"
	"flag"
)

var(
	serverAddr string
)



func main() {
	flag.StringVar(&serverAddr,"addr",":80","server listen addr")
	flag.Parse()
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		_, _ = w.Write([]byte("radio relay server"))
	})
	http.HandleFunc("/play", handlePlay)
	_ = http.ListenAndServe(serverAddr, nil)
}

//提取http头中包含icy-的key-value对
func extractIcyHeaders(headers map[string][]string) map[string]string{
	icyHeaders := make(map[string] string)
	for k, v := range headers{
		k=strings.ToLower(k)
		if strings.HasPrefix(k,"icy-"){
			if len(v)==0{
				icyHeaders[k]=""
			}else{
				icyHeaders[k]=v[0]
			}
		}
	}
	return icyHeaders
}

func sendRequest(url string, icyRequestHeaders map[string]string) *http.Response {
	if len(url)<5{
		fmt.Println("url length too short!")
		return nil
	}
	client := &http.Client{}
	request, err:= http.NewRequest("GET", url, nil)
	if err != nil {
		fmt.Println(err.Error())
		return nil
	}
	for k, v := range icyRequestHeaders {
		request.Header[k]=[]string{v}
	}
	response, err := client.Do(request)
	if err != nil {
		fmt.Println(err.Error())
		return nil
	}
	return response
}



func receiveBody(response *http.Response) (exitChan chan struct{},dataChan chan []byte){
    exitChan=make(chan struct{})
	dataChan=make(chan []byte, 10)
	go func() {
		defer close(dataChan)
		defer response.Body.Close()
		for {
			select {
			case <-exitChan:
				fmt.Println("exit receive data!")
				return
			default:{
				buf := make([]byte, 4096)
				n, err:= response.Body.Read(buf)
				if err != nil || n == 0{
					fmt.Println("receive data error!")
					return
				}else{
					dataChan <-buf[:n]
				}
			}
			}
		}
	}()
	return
}


func setResponseHeaders(w http.ResponseWriter,response *http.Response){
	w.Header().Set("Content-Type","audio/mpeg")
	w.Header().Set("transfer-encoding","identity")
	icyResponseHeaders:=extractIcyHeaders(response.Header)
	for k, v := range icyResponseHeaders {
		w.Header()[k]=[]string{v}
	}
}

func sendBody(w http.ResponseWriter, dataChan <-chan []byte) {
	for {
		data,ok := <-dataChan
		if (!ok){
			fmt.Println("receive data error!")
			break
		}
		n, err := w.Write(data)
		if err != nil || n == 0 {
			fmt.Println("send data error!")
			break
		}
	}
}



func handlePlay(w http.ResponseWriter, r *http.Request) {
	_ = r.ParseForm()
	url:=r.Form.Get("url")
	response:=sendRequest(url,extractIcyHeaders(r.Form));
	if (response!=nil){
		setResponseHeaders(w,response)
		exitChan,dataChan:=receiveBody(response);
		sendBody(w, dataChan)
		close(exitChan)
	}else{
		w.WriteHeader(500)
	}
}

你可能感兴趣的:(Golang)