使用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)
}
}