使用Golang转发HTTP流数据

2019-08-13  本文已影响0人  土豆吞噬者
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)
    }
}
上一篇下一篇

猜你喜欢

热点阅读