1// +build go1.13 2 3// Copyright (c) Microsoft Corporation. All rights reserved. 4// Licensed under the MIT License. 5 6package body 7 8import ( 9 "errors" 10 "net/http" 11 12 "github.com/Azure/azure-sdk-for-go/sdk/armcore/internal/pollers" 13 "github.com/Azure/azure-sdk-for-go/sdk/azcore" 14) 15 16// Applicable returns true if the LRO is using no headers, just provisioning state. 17// This is only applicable to PATCH and PUT methods and assumes no polling headers. 18func Applicable(resp *azcore.Response) bool { 19 // we can't check for absense of headers due to some misbehaving services 20 // like redis that return a Location header but don't actually use that protocol 21 return resp.Request.Method == http.MethodPatch || resp.Request.Method == http.MethodPut 22} 23 24// Poller is an LRO poller that uses the Body pattern. 25type Poller struct { 26 // The poller's type, used for resume token processing. 27 Type string `json:"type"` 28 29 // The URL for polling. 30 PollURL string `json:"pollURL"` 31 32 // The LRO's current state. 33 CurState string `json:"state"` 34} 35 36// New creates a new Poller from the provided initial response. 37func New(resp *azcore.Response, pollerID string) (*Poller, error) { 38 azcore.Log().Write(azcore.LogLongRunningOperation, "Using Body poller.") 39 p := &Poller{ 40 Type: pollers.MakeID(pollerID, "body"), 41 PollURL: resp.Request.URL.String(), 42 } 43 // default initial state to InProgress. depending on the HTTP 44 // status code and provisioning state, we might change the value. 45 curState := pollers.StatusInProgress 46 provState, err := pollers.GetProvisioningState(resp) 47 if err != nil && !errors.Is(err, pollers.ErrNoBody) { 48 return nil, err 49 } 50 if resp.StatusCode == http.StatusCreated && provState != "" { 51 // absense of provisioning state is ok for a 201, means the operation is in progress 52 curState = provState 53 } else if resp.StatusCode == http.StatusOK { 54 if provState != "" { 55 curState = provState 56 } else if provState == "" { 57 // for a 200, absense of provisioning state indicates success 58 curState = pollers.StatusSucceeded 59 } 60 } else if resp.StatusCode == http.StatusNoContent { 61 curState = pollers.StatusSucceeded 62 } 63 p.CurState = curState 64 return p, nil 65} 66 67// URL returns the polling URL. 68func (p *Poller) URL() string { 69 return p.PollURL 70} 71 72// Done returns true if the LRO has reached a terminal state. 73func (p *Poller) Done() bool { 74 return pollers.IsTerminalState(p.Status()) 75} 76 77// Update updates the Poller from the polling response. 78func (p *Poller) Update(resp *azcore.Response) error { 79 if resp.StatusCode == http.StatusNoContent { 80 p.CurState = pollers.StatusSucceeded 81 return nil 82 } 83 state, err := pollers.GetProvisioningState(resp) 84 if errors.Is(err, pollers.ErrNoBody) { 85 // a missing response body in non-204 case is an error 86 return err 87 } else if state == "" { 88 // a response body without provisioning state is considered terminal success 89 state = pollers.StatusSucceeded 90 } else if err != nil { 91 return err 92 } 93 p.CurState = state 94 return nil 95} 96 97// FinalGetURL returns the empty string as no final GET is required for this poller type. 98func (*Poller) FinalGetURL() string { 99 return "" 100} 101 102// Status returns the status of the LRO. 103func (p *Poller) Status() string { 104 return p.CurState 105} 106