|
Packit |
63bb0d |
/*
|
|
Packit |
63bb0d |
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
Licensed under the Apache License, Version 2.0 (the "License");
|
|
Packit |
63bb0d |
you may not use this file except in compliance with the License.
|
|
Packit |
63bb0d |
You may obtain a copy of the License at
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
Unless required by applicable law or agreed to in writing, software
|
|
Packit |
63bb0d |
distributed under the License is distributed on an "AS IS" BASIS,
|
|
Packit |
63bb0d |
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
Packit |
63bb0d |
See the License for the specific language governing permissions and
|
|
Packit |
63bb0d |
limitations under the License.
|
|
Packit |
63bb0d |
*/
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
package soap
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
import (
|
|
Packit |
63bb0d |
"fmt"
|
|
Packit |
63bb0d |
"io"
|
|
Packit |
63bb0d |
"net/http"
|
|
Packit |
63bb0d |
"net/http/httputil"
|
|
Packit |
63bb0d |
"sync/atomic"
|
|
Packit |
63bb0d |
"time"
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
"github.com/vmware/govmomi/vim25/debug"
|
|
Packit |
63bb0d |
)
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// teeReader wraps io.TeeReader and patches through the Close() function.
|
|
Packit |
63bb0d |
type teeReader struct {
|
|
Packit |
63bb0d |
io.Reader
|
|
Packit |
63bb0d |
io.Closer
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
func newTeeReader(rc io.ReadCloser, w io.Writer) io.ReadCloser {
|
|
Packit |
63bb0d |
return teeReader{
|
|
Packit |
63bb0d |
Reader: io.TeeReader(rc, w),
|
|
Packit |
63bb0d |
Closer: rc,
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// debugRoundTrip contains state and logic needed to debug a single round trip.
|
|
Packit |
63bb0d |
type debugRoundTrip struct {
|
|
Packit |
63bb0d |
cn uint64 // Client number
|
|
Packit |
63bb0d |
rn uint64 // Request number
|
|
Packit |
63bb0d |
log io.WriteCloser // Request log
|
|
Packit |
63bb0d |
cs []io.Closer // Files that need closing when done
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
func (d *debugRoundTrip) logf(format string, a ...interface{}) {
|
|
Packit |
63bb0d |
now := time.Now().Format("2006-01-02T15-04-05.000000000")
|
|
Packit |
63bb0d |
fmt.Fprintf(d.log, "%s - %04d: ", now, d.rn)
|
|
Packit |
63bb0d |
fmt.Fprintf(d.log, format, a...)
|
|
Packit |
63bb0d |
fmt.Fprintf(d.log, "\n")
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
func (d *debugRoundTrip) enabled() bool {
|
|
Packit |
63bb0d |
return d != nil
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
func (d *debugRoundTrip) done() {
|
|
Packit |
63bb0d |
for _, c := range d.cs {
|
|
Packit |
63bb0d |
c.Close()
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
func (d *debugRoundTrip) newFile(suffix string) io.WriteCloser {
|
|
Packit |
63bb0d |
return debug.NewFile(fmt.Sprintf("%d-%04d.%s", d.cn, d.rn, suffix))
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
func (d *debugRoundTrip) ext(h http.Header) string {
|
|
Packit |
63bb0d |
const json = "application/json"
|
|
Packit |
63bb0d |
ext := "xml"
|
|
Packit |
63bb0d |
if h.Get("Accept") == json || h.Get("Content-Type") == json {
|
|
Packit |
63bb0d |
ext = "json"
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
return ext
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
func (d *debugRoundTrip) debugRequest(req *http.Request) string {
|
|
Packit |
63bb0d |
if d == nil {
|
|
Packit |
63bb0d |
return ""
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Capture headers
|
|
Packit |
63bb0d |
var wc io.WriteCloser = d.newFile("req.headers")
|
|
Packit |
63bb0d |
b, _ := httputil.DumpRequest(req, false)
|
|
Packit |
63bb0d |
wc.Write(b)
|
|
Packit |
63bb0d |
wc.Close()
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
ext := d.ext(req.Header)
|
|
Packit |
63bb0d |
// Capture body
|
|
Packit |
63bb0d |
wc = d.newFile("req." + ext)
|
|
Packit |
63bb0d |
req.Body = newTeeReader(req.Body, wc)
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Delay closing until marked done
|
|
Packit |
63bb0d |
d.cs = append(d.cs, wc)
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
return ext
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
func (d *debugRoundTrip) debugResponse(res *http.Response, ext string) {
|
|
Packit |
63bb0d |
if d == nil {
|
|
Packit |
63bb0d |
return
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Capture headers
|
|
Packit |
63bb0d |
var wc io.WriteCloser = d.newFile("res.headers")
|
|
Packit |
63bb0d |
b, _ := httputil.DumpResponse(res, false)
|
|
Packit |
63bb0d |
wc.Write(b)
|
|
Packit |
63bb0d |
wc.Close()
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Capture body
|
|
Packit |
63bb0d |
wc = d.newFile("res." + ext)
|
|
Packit |
63bb0d |
res.Body = newTeeReader(res.Body, wc)
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Delay closing until marked done
|
|
Packit |
63bb0d |
d.cs = append(d.cs, wc)
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
var cn uint64 // Client counter
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// debugContainer wraps the debugging state for a single client.
|
|
Packit |
63bb0d |
type debugContainer struct {
|
|
Packit |
63bb0d |
cn uint64 // Client number
|
|
Packit |
63bb0d |
rn uint64 // Request counter
|
|
Packit |
63bb0d |
log io.WriteCloser // Request log
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
func newDebug() *debugContainer {
|
|
Packit |
63bb0d |
d := debugContainer{
|
|
Packit |
63bb0d |
cn: atomic.AddUint64(&cn, 1),
|
|
Packit |
63bb0d |
rn: 0,
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
if !debug.Enabled() {
|
|
Packit |
63bb0d |
return nil
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
d.log = debug.NewFile(fmt.Sprintf("%d-client.log", d.cn))
|
|
Packit |
63bb0d |
return &d
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
func (d *debugContainer) newRoundTrip() *debugRoundTrip {
|
|
Packit |
63bb0d |
if d == nil {
|
|
Packit |
63bb0d |
return nil
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
drt := debugRoundTrip{
|
|
Packit |
63bb0d |
cn: d.cn,
|
|
Packit |
63bb0d |
rn: atomic.AddUint64(&d.rn, 1),
|
|
Packit |
63bb0d |
log: d.log,
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
return &drt
|
|
Packit |
63bb0d |
}
|