github.com/vmware/govmomi@v0.43.0/simulator/http_nfc_lease.go (about) 1 /* 2 Copyright (c) 2019-2023 VMware, Inc. All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package simulator 18 19 import ( 20 "crypto/sha1" 21 "encoding/hex" 22 "fmt" 23 "hash" 24 "io" 25 "log" 26 "net/http" 27 "os" 28 "strings" 29 "sync" 30 31 "github.com/vmware/govmomi/vim25/methods" 32 "github.com/vmware/govmomi/vim25/mo" 33 "github.com/vmware/govmomi/vim25/soap" 34 "github.com/vmware/govmomi/vim25/types" 35 ) 36 37 type metadata struct { 38 sha1 []byte 39 size int64 40 } 41 42 type HttpNfcLease struct { 43 mo.HttpNfcLease 44 files map[string]string 45 metadata map[string]metadata 46 } 47 48 var ( 49 nfcLease sync.Map // HTTP access to NFC leases are token based and do not require Session auth 50 nfcPrefix = "/nfc/" 51 ) 52 53 // ServeNFC handles NFC file upload/download 54 func ServeNFC(w http.ResponseWriter, r *http.Request) { 55 p := strings.Split(r.URL.Path, "/") 56 id, name := p[len(p)-2], p[len(p)-1] 57 ref := types.ManagedObjectReference{Type: "HttpNfcLease", Value: id} 58 l, ok := nfcLease.Load(ref) 59 if !ok { 60 log.Printf("invalid NFC lease: %s", id) 61 http.NotFound(w, r) 62 return 63 } 64 lease := l.(*HttpNfcLease) 65 file, ok := lease.files[name] 66 if !ok { 67 log.Printf("invalid NFC device id: %s", name) 68 http.NotFound(w, r) 69 return 70 } 71 72 status := http.StatusOK 73 var dst hash.Hash 74 var src io.ReadCloser 75 76 switch r.Method { 77 case http.MethodPut, http.MethodPost: 78 dst = sha1.New() 79 src = r.Body 80 case http.MethodGet: 81 f, err := os.Open(file) 82 if err != nil { 83 http.NotFound(w, r) 84 return 85 } 86 src = f 87 default: 88 status = http.StatusMethodNotAllowed 89 } 90 91 n, err := io.Copy(dst, src) 92 _ = src.Close() 93 if dst != nil { 94 lease.metadata[name] = metadata{ 95 sha1: dst.Sum(nil), 96 size: n, 97 } 98 } 99 100 msg := fmt.Sprintf("transferred %d bytes", n) 101 if err != nil { 102 status = http.StatusInternalServerError 103 msg = err.Error() 104 } 105 tracef("nfc %s %s: %s", r.Method, file, msg) 106 w.WriteHeader(status) 107 } 108 109 func (l *HttpNfcLease) error(ctx *Context, err *types.LocalizedMethodFault) { 110 ctx.WithLock(l, func() { 111 ctx.Map.Update(l, []types.PropertyChange{ 112 {Name: "state", Val: types.HttpNfcLeaseStateError}, 113 {Name: "error", Val: err}, 114 }) 115 }) 116 } 117 118 func (l *HttpNfcLease) ready(ctx *Context, entity types.ManagedObjectReference, urls []types.HttpNfcLeaseDeviceUrl) { 119 info := &types.HttpNfcLeaseInfo{ 120 Lease: l.Self, 121 Entity: entity, 122 DeviceUrl: urls, 123 LeaseTimeout: 300, 124 } 125 126 ctx.WithLock(l, func() { 127 ctx.Map.Update(l, []types.PropertyChange{ 128 {Name: "state", Val: types.HttpNfcLeaseStateReady}, 129 {Name: "info", Val: info}, 130 }) 131 }) 132 } 133 134 func newHttpNfcLease(ctx *Context) *HttpNfcLease { 135 lease := &HttpNfcLease{ 136 HttpNfcLease: mo.HttpNfcLease{ 137 State: types.HttpNfcLeaseStateInitializing, 138 }, 139 files: make(map[string]string), 140 metadata: make(map[string]metadata), 141 } 142 143 ctx.Session.Put(lease) 144 nfcLease.Store(lease.Reference(), lease) 145 146 return lease 147 } 148 149 func (l *HttpNfcLease) HttpNfcLeaseComplete(ctx *Context, req *types.HttpNfcLeaseComplete) soap.HasFault { 150 ctx.Session.Remove(ctx, req.This) 151 nfcLease.Delete(req.This) 152 153 return &methods.HttpNfcLeaseCompleteBody{ 154 Res: new(types.HttpNfcLeaseCompleteResponse), 155 } 156 } 157 158 func (l *HttpNfcLease) HttpNfcLeaseAbort(ctx *Context, req *types.HttpNfcLeaseAbort) soap.HasFault { 159 ctx.Session.Remove(ctx, req.This) 160 nfcLease.Delete(req.This) 161 162 return &methods.HttpNfcLeaseAbortBody{ 163 Res: new(types.HttpNfcLeaseAbortResponse), 164 } 165 } 166 167 func (l *HttpNfcLease) HttpNfcLeaseProgress(ctx *Context, req *types.HttpNfcLeaseProgress) soap.HasFault { 168 l.TransferProgress = req.Percent 169 170 return &methods.HttpNfcLeaseProgressBody{ 171 Res: new(types.HttpNfcLeaseProgressResponse), 172 } 173 } 174 175 func (l *HttpNfcLease) getDeviceKey(name string) string { 176 for _, devUrl := range l.Info.DeviceUrl { 177 if name == devUrl.TargetId { 178 return devUrl.Key 179 } 180 } 181 return "unknown" 182 } 183 184 func (l *HttpNfcLease) HttpNfcLeaseGetManifest(ctx *Context, req *types.HttpNfcLeaseGetManifest) soap.HasFault { 185 entries := []types.HttpNfcLeaseManifestEntry{} 186 for name, md := range l.metadata { 187 entries = append(entries, types.HttpNfcLeaseManifestEntry{ 188 Key: l.getDeviceKey(name), 189 Sha1: hex.EncodeToString(md.sha1), 190 Size: md.size, 191 }) 192 } 193 return &methods.HttpNfcLeaseGetManifestBody{ 194 Res: &types.HttpNfcLeaseGetManifestResponse{ 195 Returnval: entries, 196 }, 197 } 198 }