mirror of
https://github.com/kerberos-io/onvif.git
synced 2025-09-26 20:01:17 +08:00
92 lines
2.3 KiB
Go
92 lines
2.3 KiB
Go
package networking
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
|
|
"github.com/beevik/etree"
|
|
"github.com/icholy/digest"
|
|
"github.com/juju/errors"
|
|
)
|
|
|
|
// SendSoap send soap message
|
|
func SendSoap(httpClient *http.Client, endpoint, message string) (*http.Response, error) {
|
|
resp, err := httpClient.Post(endpoint, "application/soap+xml; charset=utf-8", bytes.NewBufferString(message))
|
|
if err != nil {
|
|
return resp, errors.Annotate(err, "Post")
|
|
}
|
|
|
|
// if resp.StatusCode is 4xx,5xx, return error
|
|
if resp.StatusCode >= 400 && resp.StatusCode < 600 {
|
|
return resp, errors.Errorf("Server error: %d: %s", resp.StatusCode, resp.Status)
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
func SendSoapWithDigest(httpClient *http.Client, endpoint, message, username, password string) (*http.Response, error) {
|
|
doc := etree.NewDocument()
|
|
if err := doc.ReadFromString(message); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
e := doc.FindElement("./Envelope/Header/Security")
|
|
if e != nil {
|
|
bodyTag := doc.Root().SelectElement("Header")
|
|
bodyTag.RemoveChild(e)
|
|
data, err := doc.WriteToString()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
message = data
|
|
}
|
|
|
|
req, err := http.NewRequest("POST", endpoint, bytes.NewBufferString(message))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
req.Header.Set("Content-Type", "application/soap+xml; charset=utf-8")
|
|
resp, err := httpClient.Do(req)
|
|
if err != nil {
|
|
return resp, errors.Annotate(err, "Post with digest")
|
|
}
|
|
|
|
if resp.StatusCode != http.StatusUnauthorized {
|
|
return resp, err
|
|
}
|
|
|
|
wwwAuth := resp.Header.Get("WWW-Authenticate")
|
|
chal, err := digest.ParseChallenge(wwwAuth)
|
|
if err != nil {
|
|
return resp, fmt.Errorf("fail to parse challenge: %w", err)
|
|
}
|
|
|
|
cred, err := digest.Digest(chal, digest.Options{
|
|
Method: "POST",
|
|
URI: req.URL.RequestURI(),
|
|
Username: username,
|
|
Password: password,
|
|
})
|
|
|
|
if err != nil {
|
|
return resp, fmt.Errorf("fail to build digest: %w", err)
|
|
}
|
|
|
|
// Readout body to close the connection
|
|
resp.Body.Close()
|
|
|
|
req.Header.Add("Authorization", cred.String())
|
|
req.Body = io.NopCloser((bytes.NewBufferString(message)))
|
|
resp, err = httpClient.Do(req)
|
|
if err != nil {
|
|
return nil, errors.Annotate(err, "Post with digest")
|
|
}
|
|
if resp.StatusCode >= 400 && resp.StatusCode < 600 {
|
|
return resp, errors.Errorf("Post with digest error: %d: %s", resp.StatusCode, resp.Status)
|
|
}
|
|
|
|
return resp, nil
|
|
}
|