This repository has been archived by the owner on Jan 15, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
response.go
134 lines (119 loc) · 3.48 KB
/
response.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright 2014 Mikio Hara. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ssdp
import (
"bufio"
"bytes"
"fmt"
"io"
"net"
"net/http"
)
func parseResponse(b []byte) (*http.Response, error) {
br := bufio.NewReader(bytes.NewBuffer(b))
resp, err := http.ReadResponse(br, nil)
if err != nil {
return nil, err
}
return resp, nil
}
type response struct {
conn // network connection endpoint
mifs []net.Interface
path *path // reverse path
}
type responseWriter struct {
response
hdr http.Header // response header
wrthdr bool // whether the header has been written
buf bytes.Buffer
req *http.Request
}
// Header implements the Header method of http.ResponseWriter
// interface.
func (resp *responseWriter) Header() http.Header {
return resp.hdr
}
// Write implements the Write method of http.ResponseWriter interface.
func (resp *responseWriter) Write(b []byte) (int, error) {
if !resp.wrthdr {
resp.WriteHeader(http.StatusOK)
}
return resp.writeTo(b, resp.path.src)
}
// WriteHeader implements the WriteHeader method of
// http.ResponseWriter interface.
func (resp *responseWriter) WriteHeader(code int) {
resp.wrthdr = true
fmt.Fprintf(&resp.buf, "%s %d %s\r\n", resp.req.Proto, code, http.StatusText(code))
resp.hdr.Write(&resp.buf)
resp.buf.WriteString("\r\n")
resp.writeTo(resp.buf.Bytes(), resp.path.src)
}
func newResponseWriter(conn conn, mifs []net.Interface, grp *net.UDPAddr, path *path, req *http.Request) *responseWriter {
resp := &responseWriter{
response: response{
conn: conn,
mifs: mifs,
path: path,
},
hdr: make(http.Header),
req: req,
}
resp.path.dst.Port = grp.Port
if ipv6LinkLocal(path.src.IP) {
path.src.Zone = interfaceByIndex(resp.mifs, resp.path.ifIndex).Name
}
return resp
}
// A ResponseRedirector represents a SSDP response message redirector.
type ResponseRedirector struct {
response
resp *http.Response
buf bytes.Buffer
}
// Header returns the HTTP header map that will be sent by WriteTo
// method.
func (rdr *ResponseRedirector) Header() http.Header {
return rdr.resp.Header
}
// WriteTo writes the SSDP response message. The outbound network
// interface ifi is used for sending multicast messages. It uses the
// system assigned multicast network interface when ifi is nil.
func (rdr *ResponseRedirector) WriteTo(dst *net.UDPAddr, ifi *net.Interface) (int, error) {
if ifi != nil {
rdr.SetMulticastInterface(ifi)
}
fmt.Fprintf(&rdr.buf, "%s %s\r\n", rdr.resp.Proto, rdr.resp.Status)
rdr.resp.Header.Write(&rdr.buf)
rdr.buf.WriteString("\r\n")
io.Copy(&rdr.buf, rdr.resp.Body)
rdr.resp.Body.Close()
return rdr.writeTo(rdr.buf.Bytes(), dst)
}
// ForwardPath returns the destination address of the SSDP response
// message.
func (rdr *ResponseRedirector) ForwardPath() *net.UDPAddr {
return rdr.path.dst
}
// ReversePath returns the source address and inbound interface of the
// SSDP response message.
func (rdr *ResponseRedirector) ReversePath() (*net.UDPAddr, *net.Interface) {
return rdr.path.src, interfaceByIndex(rdr.mifs, rdr.path.ifIndex)
}
func newResponseRedirector(conn conn, mifs []net.Interface, grp *net.UDPAddr, path *path, resp *http.Response) *ResponseRedirector {
rdr := &ResponseRedirector{
response: response{
conn: conn,
mifs: mifs,
path: path,
},
resp: resp,
}
rdr.path.dst.Port = grp.Port
if ipv6LinkLocal(path.src.IP) {
path.src.Zone = interfaceByIndex(mifs, path.ifIndex).Name
}
return rdr
}