Add SOAP action support.
This commit is contained in:
parent
489c180de9
commit
1b8d66b887
@ -19,7 +19,16 @@ func (i indentLevel) String() string {
|
|||||||
func displayDevice(indent indentLevel, device *goupnp.Device) {
|
func displayDevice(indent indentLevel, device *goupnp.Device) {
|
||||||
fmt.Println(indent.String(), device)
|
fmt.Println(indent.String(), device)
|
||||||
for _, srv := range device.Services {
|
for _, srv := range device.Services {
|
||||||
fmt.Println((indent + 1).String(), srv)
|
fmt.Println((indent + 1).String(), srv, srv.SCPDURL.URL.String(), srv.ControlURL.URL.String())
|
||||||
|
fmt.Println(goupnp.ServiceTypeWANPPPConnection, srv.ServiceType)
|
||||||
|
if srv.ServiceType == goupnp.ServiceTypeWANPPPConnection {
|
||||||
|
results, err := goupnp.PerformSoapAction(goupnp.ServiceTypeWANPPPConnection, "GetExternalIPAddress", &srv.ControlURL.URL, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
} else {
|
||||||
|
fmt.Println(results)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for _, subdev := range device.Devices {
|
for _, subdev := range device.Devices {
|
||||||
displayDevice(indent+1, subdev)
|
displayDevice(indent+1, subdev)
|
||||||
|
@ -11,11 +11,11 @@ import (
|
|||||||
// Non-exhaustive set of UPnP service types.
|
// Non-exhaustive set of UPnP service types.
|
||||||
const (
|
const (
|
||||||
ServiceTypeLayer3Forwarding = "urn:schemas-upnp-org:service:Layer3Forwarding:1"
|
ServiceTypeLayer3Forwarding = "urn:schemas-upnp-org:service:Layer3Forwarding:1"
|
||||||
ServiceTypeWANCommonInterfaceConfig = "urn:schemas-upnp-org:WANCommonInterfaceConfig:1"
|
ServiceTypeWANCommonInterfaceConfig = "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"
|
||||||
// WANPPPConnection is typically useful with regard to the external IP and
|
// WANPPPConnection is typically useful with regard to the external IP and
|
||||||
// port forwarding.
|
// port forwarding.
|
||||||
// http://upnp.org/specs/gw/UPnP-gw-WANPPPConnection-v1-Service.pdf
|
// http://upnp.org/specs/gw/UPnP-gw-WANPPPConnection-v1-Service.pdf
|
||||||
ServiceTypeWANPPPConnection = "urn:schemas-upnp-org:WANPPPConnection:1"
|
ServiceTypeWANPPPConnection = "urn:schemas-upnp-org:service:WANPPPConnection:1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Non-exhaustive set of UPnP device types.
|
// Non-exhaustive set of UPnP device types.
|
||||||
|
107
soap.go
Normal file
107
soap.go
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
// Definition for the SOAP structure required for UPnP's SOAP usage.
|
||||||
|
|
||||||
|
package goupnp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/xml"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SoapEncodingStyle = "http://schemas.xmlsoap.org/soap/encoding/"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NameValue struct {
|
||||||
|
Name string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSoapAction creates a SoapEnvelope with the given action and arguments.
|
||||||
|
func newSoapAction(actionNamespace, actionName string, arguments []NameValue) *SoapEnvelope {
|
||||||
|
env := &SoapEnvelope{
|
||||||
|
EncodingStyle: SoapEncodingStyle,
|
||||||
|
Body: SoapBody{
|
||||||
|
Action: SoapAction{
|
||||||
|
XMLName: xml.Name{actionNamespace, actionName},
|
||||||
|
Arguments: make([]SoapArgument, len(arguments)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range arguments {
|
||||||
|
env.Body.Action.Arguments[i].XMLName.Local = arguments[i].Name
|
||||||
|
env.Body.Action.Arguments[i].Value = arguments[i].Value
|
||||||
|
}
|
||||||
|
|
||||||
|
return env
|
||||||
|
}
|
||||||
|
|
||||||
|
// PerformSoapAction makes a SOAP request, with the given action.
|
||||||
|
func PerformSoapAction(actionNamespace, actionName string, url *url.URL, arguments []NameValue) ([]NameValue, error) {
|
||||||
|
requestEnv := newSoapAction(actionNamespace, actionName, arguments)
|
||||||
|
requestBytes, err := xml.Marshal(requestEnv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
client := http.Client{}
|
||||||
|
response, err := client.Do(&http.Request{
|
||||||
|
Method: "POST",
|
||||||
|
URL: url,
|
||||||
|
Header: http.Header{
|
||||||
|
"SOAPACTION": []string{actionNamespace + "#" + actionName},
|
||||||
|
"CONTENT-TYPE": []string{"text/xml; charset=\"utf-8\""},
|
||||||
|
},
|
||||||
|
Body: ioutil.NopCloser(bytes.NewBuffer(requestBytes)),
|
||||||
|
// Set ContentLength to avoid chunked encoding - some servers might not support it.
|
||||||
|
ContentLength: int64(len(requestBytes)),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
if response.StatusCode != 200 {
|
||||||
|
return nil, fmt.Errorf("goupnp: SOAP request got %s response from %s", response.Status, url.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder := xml.NewDecoder(response.Body)
|
||||||
|
fmt.Println(response.Header)
|
||||||
|
var responseEnv SoapEnvelope
|
||||||
|
if err := decoder.Decode(&responseEnv); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
results := make([]NameValue, len(responseEnv.Body.Action.Arguments))
|
||||||
|
for i, soapArg := range responseEnv.Body.Action.Arguments {
|
||||||
|
results[i] = NameValue{
|
||||||
|
Name: soapArg.XMLName.Local,
|
||||||
|
Value: soapArg.Value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type SoapEnvelope struct {
|
||||||
|
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"`
|
||||||
|
EncodingStyle string `xml:"http://schemas.xmlsoap.org/soap/envelope/ encodingStyle,attr"`
|
||||||
|
Body SoapBody `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SoapBody struct {
|
||||||
|
Action SoapAction `xml:",any"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SoapAction struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
Arguments []SoapArgument `xml:",any"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SoapArgument struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
Value string `xml:",chardata"`
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user