chore(deps): bump github.com/Azure/azure-sdk-for-go/sdk/storage/azblob (#3114)

Bumps [github.com/Azure/azure-sdk-for-go/sdk/storage/azblob](https://github.com/Azure/azure-sdk-for-go) from 1.3.1 to 1.3.2.
- [Release notes](https://github.com/Azure/azure-sdk-for-go/releases)
- [Changelog](https://github.com/Azure/azure-sdk-for-go/blob/main/documentation/release.md)
- [Commits](https://github.com/Azure/azure-sdk-for-go/compare/sdk/azcore/v1.3.1...sdk/storage/azblob/v1.3.2)

---
updated-dependencies:
- dependency-name: github.com/Azure/azure-sdk-for-go/sdk/storage/azblob
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
dependabot[bot] 2024-04-19 10:33:38 -07:00 committed by GitHub
parent 8ee87b542d
commit 4a516dbae3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
38 changed files with 366 additions and 101 deletions

4
go.mod
View File

@ -4,7 +4,7 @@ go 1.22
require ( require (
cloud.google.com/go/storage v1.40.0 cloud.google.com/go/storage v1.40.0
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.1 github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.2
github.com/aws/aws-sdk-go-v2 v1.26.1 github.com/aws/aws-sdk-go-v2 v1.26.1
github.com/aws/aws-sdk-go-v2/config v1.27.11 github.com/aws/aws-sdk-go-v2/config v1.27.11
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.15 github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.15
@ -151,7 +151,7 @@ require (
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 // indirect github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 // indirect
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect
github.com/Microsoft/hcsshim v0.11.4 // indirect github.com/Microsoft/hcsshim v0.11.4 // indirect
github.com/aws/aws-sdk-go-v2/service/ecr v1.24.5 // indirect github.com/aws/aws-sdk-go-v2/service/ecr v1.24.5 // indirect

8
go.sum
View File

@ -17,16 +17,16 @@ github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 h1:59M
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0/go.mod h1:OahwfttHWG6eJ0clwcfBAHoDI6X/LV/15hx/wlMZSrU= github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0/go.mod h1:OahwfttHWG6eJ0clwcfBAHoDI6X/LV/15hx/wlMZSrU=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2 h1:c4k2FIYIh4xtwqrQwV0Ct1v5+ehlNXj5NI/MWVsiTkQ= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2/go.mod h1:5FDJtLEO/GxwNgUxbwrY3LP0pEoThTQJtk2oysdXHxM= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ= github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc= github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0 h1:AifHbc4mg0x9zW52WOpKbsHaDKuRhlI7TVl47thgQ70= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0 h1:AifHbc4mg0x9zW52WOpKbsHaDKuRhlI7TVl47thgQ70=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0/go.mod h1:T5RfihdXtBDxt1Ch2wobif3TvzTdumDy29kahv6AV9A= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0/go.mod h1:T5RfihdXtBDxt1Ch2wobif3TvzTdumDy29kahv6AV9A=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.1 h1:fXPMAmuh0gDuRDey0atC8cXBuKIlqCzCkL8sm1n9Ov0= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.2 h1:YUUxeiOWgdAQE3pXt2H7QXzZs0q8UBjgRbl56qo8GYM=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.1/go.mod h1:SUZc9YRRHfx2+FAQKNDGrssXehqLpxmwRv2mC/5ntj4= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.2/go.mod h1:dmXQgZuiSubAecswZE+Sm8jkvEa7kQgTPVRvwL/nd0E=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=

View File

@ -1,5 +1,46 @@
# Release History # Release History
## 1.11.1 (2024-04-02)
### Bugs Fixed
* Pollers that use the `Location` header won't consider `http.StatusRequestTimeout` a terminal failure.
* `runtime.Poller[T].Result` won't consider non-terminal error responses as terminal.
## 1.11.0 (2024-04-01)
### Features Added
* Added `StatusCodes` to `arm/policy.RegistrationOptions` to allow supporting non-standard HTTP status codes during registration.
* Added field `InsecureAllowCredentialWithHTTP` to `azcore.ClientOptions` and dependent authentication pipeline policies.
* Added type `MultipartContent` to the `streaming` package to support multipart/form payloads with custom Content-Type and file name.
### Bugs Fixed
* `runtime.SetMultipartFormData` won't try to stringify `[]byte` values.
* Pollers that use the `Location` header won't consider `http.StatusTooManyRequests` a terminal failure.
### Other Changes
* Update dependencies.
## 1.10.0 (2024-02-29)
### Features Added
* Added logging event `log.EventResponseError` that will contain the contents of `ResponseError.Error()` whenever an `azcore.ResponseError` is created.
* Added `runtime.NewResponseErrorWithErrorCode` for creating an `azcore.ResponseError` with a caller-supplied error code.
* Added type `MatchConditions` for use in conditional requests.
### Bugs Fixed
* Fixed a potential race condition between `NullValue` and `IsNullValue`.
* `runtime.EncodeQueryParams` will escape semicolons before calling `url.ParseQuery`.
### Other Changes
* Update dependencies.
## 1.9.2 (2024-02-06) ## 1.9.2 (2024-02-06)
### Bugs Fixed ### Bugs Fixed

View File

@ -23,7 +23,7 @@ pr:
- sdk/azcore/ - sdk/azcore/
- eng/ - eng/
stages: extends:
- template: /eng/pipelines/templates/jobs/archetype-sdk-client.yml template: /eng/pipelines/templates/jobs/archetype-sdk-client.yml
parameters: parameters:
ServiceDirectory: azcore ServiceDirectory: azcore

View File

@ -8,6 +8,7 @@ package azcore
import ( import (
"reflect" "reflect"
"sync"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported" "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared" "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
@ -41,13 +42,28 @@ func NewSASCredential(sas string) *SASCredential {
} }
// holds sentinel values used to send nulls // holds sentinel values used to send nulls
var nullables map[reflect.Type]interface{} = map[reflect.Type]interface{}{} var nullables map[reflect.Type]any = map[reflect.Type]any{}
var nullablesMu sync.RWMutex
// NullValue is used to send an explicit 'null' within a request. // NullValue is used to send an explicit 'null' within a request.
// This is typically used in JSON-MERGE-PATCH operations to delete a value. // This is typically used in JSON-MERGE-PATCH operations to delete a value.
func NullValue[T any]() T { func NullValue[T any]() T {
t := shared.TypeOfT[T]() t := shared.TypeOfT[T]()
nullablesMu.RLock()
v, found := nullables[t] v, found := nullables[t]
nullablesMu.RUnlock()
if found {
// return the sentinel object
return v.(T)
}
// promote to exclusive lock and check again (double-checked locking pattern)
nullablesMu.Lock()
defer nullablesMu.Unlock()
v, found = nullables[t]
if !found { if !found {
var o reflect.Value var o reflect.Value
if k := t.Kind(); k == reflect.Map { if k := t.Kind(); k == reflect.Map {
@ -72,6 +88,9 @@ func NullValue[T any]() T {
func IsNullValue[T any](v T) bool { func IsNullValue[T any](v T) bool {
// see if our map has a sentinel object for this *T // see if our map has a sentinel object for this *T
t := reflect.TypeOf(v) t := reflect.TypeOf(v)
nullablesMu.RLock()
defer nullablesMu.RUnlock()
if o, found := nullables[t]; found { if o, found := nullables[t]; found {
o1 := reflect.ValueOf(o) o1 := reflect.ValueOf(o)
v1 := reflect.ValueOf(v) v1 := reflect.ValueOf(v)

View File

@ -46,3 +46,12 @@ func (e ETag) WeakEquals(other ETag) bool {
func (e ETag) IsWeak() bool { func (e ETag) IsWeak() bool {
return len(e) >= 4 && strings.HasPrefix(string(e), "W/\"") && strings.HasSuffix(string(e), "\"") return len(e) >= 4 && strings.HasPrefix(string(e), "W/\"") && strings.HasSuffix(string(e), "\"")
} }
// MatchConditions specifies HTTP options for conditional requests.
type MatchConditions struct {
// Optionally limit requests to resources that have a matching ETag.
IfMatch *ETag
// Optionally limit requests to resources that do not match the ETag.
IfNoneMatch *ETag
}

View File

@ -51,15 +51,15 @@ type Request struct {
values opValues values opValues
} }
type opValues map[reflect.Type]interface{} type opValues map[reflect.Type]any
// Set adds/changes a value // Set adds/changes a value
func (ov opValues) set(value interface{}) { func (ov opValues) set(value any) {
ov[reflect.TypeOf(value)] = value ov[reflect.TypeOf(value)] = value
} }
// Get looks for a value set by SetValue first // Get looks for a value set by SetValue first
func (ov opValues) get(value interface{}) bool { func (ov opValues) get(value any) bool {
v, ok := ov[reflect.ValueOf(value).Elem().Type()] v, ok := ov[reflect.ValueOf(value).Elem().Type()]
if ok { if ok {
reflect.ValueOf(value).Elem().Set(reflect.ValueOf(v)) reflect.ValueOf(value).Elem().Set(reflect.ValueOf(v))
@ -108,7 +108,7 @@ func (req *Request) Next() (*http.Response, error) {
} }
// SetOperationValue adds/changes a mutable key/value associated with a single operation. // SetOperationValue adds/changes a mutable key/value associated with a single operation.
func (req *Request) SetOperationValue(value interface{}) { func (req *Request) SetOperationValue(value any) {
if req.values == nil { if req.values == nil {
req.values = opValues{} req.values = opValues{}
} }
@ -116,7 +116,7 @@ func (req *Request) SetOperationValue(value interface{}) {
} }
// OperationValue looks for a value set by SetOperationValue(). // OperationValue looks for a value set by SetOperationValue().
func (req *Request) OperationValue(value interface{}) bool { func (req *Request) OperationValue(value any) bool {
if req.values == nil { if req.values == nil {
return false return false
} }

View File

@ -13,6 +13,7 @@ import (
"net/http" "net/http"
"regexp" "regexp"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/log"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared" "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
"github.com/Azure/azure-sdk-for-go/sdk/internal/exported" "github.com/Azure/azure-sdk-for-go/sdk/internal/exported"
) )
@ -20,36 +21,45 @@ import (
// NewResponseError creates a new *ResponseError from the provided HTTP response. // NewResponseError creates a new *ResponseError from the provided HTTP response.
// Exported as runtime.NewResponseError(). // Exported as runtime.NewResponseError().
func NewResponseError(resp *http.Response) error { func NewResponseError(resp *http.Response) error {
respErr := &ResponseError{
StatusCode: resp.StatusCode,
RawResponse: resp,
}
// prefer the error code in the response header // prefer the error code in the response header
if ec := resp.Header.Get(shared.HeaderXMSErrorCode); ec != "" { if ec := resp.Header.Get(shared.HeaderXMSErrorCode); ec != "" {
respErr.ErrorCode = ec return NewResponseErrorWithErrorCode(resp, ec)
return respErr
} }
// if we didn't get x-ms-error-code, check in the response body // if we didn't get x-ms-error-code, check in the response body
body, err := exported.Payload(resp, nil) body, err := exported.Payload(resp, nil)
if err != nil { if err != nil {
// since we're not returning the ResponseError in this
// case we also don't want to write it to the log.
return err return err
} }
var errorCode string
if len(body) > 0 { if len(body) > 0 {
if code := extractErrorCodeJSON(body); code != "" { if fromJSON := extractErrorCodeJSON(body); fromJSON != "" {
respErr.ErrorCode = code errorCode = fromJSON
} else if code := extractErrorCodeXML(body); code != "" { } else if fromXML := extractErrorCodeXML(body); fromXML != "" {
respErr.ErrorCode = code errorCode = fromXML
} }
} }
return NewResponseErrorWithErrorCode(resp, errorCode)
}
// NewResponseErrorWithErrorCode creates an *azcore.ResponseError from the provided HTTP response and errorCode.
// Exported as runtime.NewResponseErrorWithErrorCode().
func NewResponseErrorWithErrorCode(resp *http.Response, errorCode string) error {
respErr := &ResponseError{
ErrorCode: errorCode,
StatusCode: resp.StatusCode,
RawResponse: resp,
}
log.Write(log.EventResponseError, respErr.Error())
return respErr return respErr
} }
func extractErrorCodeJSON(body []byte) string { func extractErrorCodeJSON(body []byte) string {
var rawObj map[string]interface{} var rawObj map[string]any
if err := json.Unmarshal(body, &rawObj); err != nil { if err := json.Unmarshal(body, &rawObj); err != nil {
// not a JSON object // not a JSON object
return "" return ""
@ -58,7 +68,7 @@ func extractErrorCodeJSON(body []byte) string {
// check if this is a wrapped error, i.e. { "error": { ... } } // check if this is a wrapped error, i.e. { "error": { ... } }
// if so then unwrap it // if so then unwrap it
if wrapped, ok := rawObj["error"]; ok { if wrapped, ok := rawObj["error"]; ok {
unwrapped, ok := wrapped.(map[string]interface{}) unwrapped, ok := wrapped.(map[string]any)
if !ok { if !ok {
return "" return ""
} }

View File

@ -15,24 +15,36 @@ import (
type Event = log.Event type Event = log.Event
const ( const (
EventRequest = azlog.EventRequest EventRequest = azlog.EventRequest
EventResponse = azlog.EventResponse EventResponse = azlog.EventResponse
EventRetryPolicy = azlog.EventRetryPolicy EventResponseError = azlog.EventResponseError
EventLRO = azlog.EventLRO EventRetryPolicy = azlog.EventRetryPolicy
EventLRO = azlog.EventLRO
) )
// Write invokes the underlying listener with the specified event and message.
// If the event shouldn't be logged or there is no listener then Write does nothing.
func Write(cls log.Event, msg string) { func Write(cls log.Event, msg string) {
log.Write(cls, msg) log.Write(cls, msg)
} }
func Writef(cls log.Event, format string, a ...interface{}) { // Writef invokes the underlying listener with the specified event and formatted message.
// If the event shouldn't be logged or there is no listener then Writef does nothing.
func Writef(cls log.Event, format string, a ...any) {
log.Writef(cls, format, a...) log.Writef(cls, format, a...)
} }
// SetListener will set the Logger to write to the specified listener.
func SetListener(lst func(Event, string)) { func SetListener(lst func(Event, string)) {
log.SetListener(lst) log.SetListener(lst)
} }
// Should returns true if the specified log event should be written to the log.
// By default all log events will be logged. Call SetEvents() to limit
// the log events for logging.
// If no listener has been set this will return false.
// Calling this method is useful when the message to log is computationally expensive
// and you want to avoid the overhead if its log event is not enabled.
func Should(cls log.Event) bool { func Should(cls log.Event) bool {
return log.Should(cls) return log.Should(cls)
} }

View File

@ -27,7 +27,7 @@ func Applicable(resp *http.Response) bool {
} }
// CanResume returns true if the token can rehydrate this poller type. // CanResume returns true if the token can rehydrate this poller type.
func CanResume(token map[string]interface{}) bool { func CanResume(token map[string]any) bool {
_, ok := token["asyncURL"] _, ok := token["asyncURL"]
return ok return ok
} }

View File

@ -29,7 +29,7 @@ func Applicable(resp *http.Response) bool {
} }
// CanResume returns true if the token can rehydrate this poller type. // CanResume returns true if the token can rehydrate this poller type.
func CanResume(token map[string]interface{}) bool { func CanResume(token map[string]any) bool {
t, ok := token["type"] t, ok := token["type"]
if !ok { if !ok {
return false return false

View File

@ -26,7 +26,7 @@ func Applicable(resp *http.Response) bool {
} }
// CanResume returns true if the token can rehydrate this poller type. // CanResume returns true if the token can rehydrate this poller type.
func CanResume(token map[string]interface{}) bool { func CanResume(token map[string]any) bool {
_, ok := token["fakeURL"] _, ok := token["fakeURL"]
return ok return ok
} }

View File

@ -28,7 +28,7 @@ func Applicable(resp *http.Response) bool {
} }
// CanResume returns true if the token can rehydrate this poller type. // CanResume returns true if the token can rehydrate this poller type.
func CanResume(token map[string]interface{}) bool { func CanResume(token map[string]any) bool {
t, ok := token["type"] t, ok := token["type"]
if !ok { if !ok {
return false return false
@ -103,6 +103,10 @@ func (p *Poller[T]) Poll(ctx context.Context) (*http.Response, error) {
} else if resp.StatusCode > 199 && resp.StatusCode < 300 { } else if resp.StatusCode > 199 && resp.StatusCode < 300 {
// any 2xx other than a 202 indicates success // any 2xx other than a 202 indicates success
p.CurState = poller.StatusSucceeded p.CurState = poller.StatusSucceeded
} else if pollers.IsNonTerminalHTTPStatusCode(resp) {
// the request timed out or is being throttled.
// DO NOT include this as a terminal failure. preserve
// the existing state and return the response.
} else { } else {
p.CurState = poller.StatusFailed p.CurState = poller.StatusFailed
} }

View File

@ -25,7 +25,7 @@ func Applicable(resp *http.Response) bool {
} }
// CanResume returns true if the token can rehydrate this poller type. // CanResume returns true if the token can rehydrate this poller type.
func CanResume(token map[string]interface{}) bool { func CanResume(token map[string]any) bool {
_, ok := token["oplocURL"] _, ok := token["oplocURL"]
return ok return ok
} }

View File

@ -74,7 +74,7 @@ func ExtractToken(token string) ([]byte, error) {
// IsTokenValid returns an error if the specified token isn't applicable for generic type T. // IsTokenValid returns an error if the specified token isn't applicable for generic type T.
func IsTokenValid[T any](token string) error { func IsTokenValid[T any](token string) error {
raw := map[string]interface{}{} raw := map[string]any{}
if err := json.Unmarshal([]byte(token), &raw); err != nil { if err := json.Unmarshal([]byte(token), &raw); err != nil {
return err return err
} }
@ -185,3 +185,16 @@ func ResultHelper[T any](resp *http.Response, failed bool, out *T) error {
} }
return nil return nil
} }
// IsNonTerminalHTTPStatusCode returns true if the HTTP status code should be
// considered non-terminal thus eligible for retry.
func IsNonTerminalHTTPStatusCode(resp *http.Response) bool {
return exported.HasStatusCode(resp,
http.StatusRequestTimeout, // 408
http.StatusTooManyRequests, // 429
http.StatusInternalServerError, // 500
http.StatusBadGateway, // 502
http.StatusServiceUnavailable, // 503
http.StatusGatewayTimeout, // 504
)
}

View File

@ -40,5 +40,5 @@ const (
Module = "azcore" Module = "azcore"
// Version is the semantic version (see http://semver.org) of this module. // Version is the semantic version (see http://semver.org) of this module.
Version = "v1.9.2" Version = "v1.11.1"
) )

View File

@ -23,6 +23,11 @@ const (
// This includes information like the HTTP status code, headers, and request URL. // This includes information like the HTTP status code, headers, and request URL.
EventResponse Event = "Response" EventResponse Event = "Response"
// EventResponseError entries contain information about HTTP responses that returned
// an *azcore.ResponseError (i.e. responses with a non 2xx HTTP status code).
// This includes the contents of ResponseError.Error().
EventResponseError Event = "ResponseError"
// EventRetryPolicy entries contain information specific to the retry policy in use. // EventRetryPolicy entries contain information specific to the retry policy in use.
EventRetryPolicy Event = "Retry" EventRetryPolicy Event = "Retry"

View File

@ -39,6 +39,11 @@ type ClientOptions struct {
// Cloud specifies a cloud for the client. The default is Azure Public Cloud. // Cloud specifies a cloud for the client. The default is Azure Public Cloud.
Cloud cloud.Configuration Cloud cloud.Configuration
// InsecureAllowCredentialWithHTTP enables authenticated requests over HTTP.
// By default, authenticated requests to an HTTP endpoint are rejected by the client.
// WARNING: setting this to true will allow sending the credential in clear text. Use with caution.
InsecureAllowCredentialWithHTTP bool
// Logging configures the built-in logging policy. // Logging configures the built-in logging policy.
Logging LogOptions Logging LogOptions
@ -147,6 +152,11 @@ type BearerTokenOptions struct {
// When this field isn't set, the policy follows its default behavior of authorizing every request with a bearer token from // When this field isn't set, the policy follows its default behavior of authorizing every request with a bearer token from
// its given credential. // its given credential.
AuthorizationHandler AuthorizationHandler AuthorizationHandler AuthorizationHandler
// InsecureAllowCredentialWithHTTP enables authenticated requests over HTTP.
// By default, authenticated requests to an HTTP endpoint are rejected by the client.
// WARNING: setting this to true will allow sending the bearer token in clear text. Use with caution.
InsecureAllowCredentialWithHTTP bool
} }
// AuthorizationHandler allows SDK developers to insert custom logic that runs when BearerTokenPolicy must authorize a request. // AuthorizationHandler allows SDK developers to insert custom logic that runs when BearerTokenPolicy must authorize a request.

View File

@ -14,6 +14,14 @@ import (
// NewResponseError creates an *azcore.ResponseError from the provided HTTP response. // NewResponseError creates an *azcore.ResponseError from the provided HTTP response.
// Call this when a service request returns a non-successful status code. // Call this when a service request returns a non-successful status code.
// The error code will be extracted from the *http.Response, either from the x-ms-error-code
// header (preferred) or attempted to be parsed from the response body.
func NewResponseError(resp *http.Response) error { func NewResponseError(resp *http.Response) error {
return exported.NewResponseError(resp) return exported.NewResponseError(resp)
} }
// NewResponseErrorWithErrorCode creates an *azcore.ResponseError from the provided HTTP response and errorCode.
// Use this variant when the error code is in a non-standard location.
func NewResponseErrorWithErrorCode(resp *http.Response, errorCode string) error {
return exported.NewResponseErrorWithErrorCode(resp, errorCode)
}

View File

@ -24,6 +24,7 @@ type BearerTokenPolicy struct {
authzHandler policy.AuthorizationHandler authzHandler policy.AuthorizationHandler
cred exported.TokenCredential cred exported.TokenCredential
scopes []string scopes []string
allowHTTP bool
} }
type acquiringResourceState struct { type acquiringResourceState struct {
@ -55,6 +56,7 @@ func NewBearerTokenPolicy(cred exported.TokenCredential, scopes []string, opts *
cred: cred, cred: cred,
scopes: scopes, scopes: scopes,
mainResource: temporal.NewResource(acquire), mainResource: temporal.NewResource(acquire),
allowHTTP: opts.InsecureAllowCredentialWithHTTP,
} }
} }
@ -80,7 +82,7 @@ func (b *BearerTokenPolicy) Do(req *policy.Request) (*http.Response, error) {
return req.Next() return req.Next()
} }
if err := checkHTTPSForAuth(req); err != nil { if err := checkHTTPSForAuth(req, b.allowHTTP); err != nil {
return nil, err return nil, err
} }
@ -113,8 +115,8 @@ func (b *BearerTokenPolicy) Do(req *policy.Request) (*http.Response, error) {
return res, err return res, err
} }
func checkHTTPSForAuth(req *policy.Request) error { func checkHTTPSForAuth(req *policy.Request, allowHTTP bool) error {
if strings.ToLower(req.Raw().URL.Scheme) != "https" { if strings.ToLower(req.Raw().URL.Scheme) != "https" && !allowHTTP {
return errorinfo.NonRetriableError(errors.New("authenticated requests are not permitted for non TLS protected (https) endpoints")) return errorinfo.NonRetriableError(errors.New("authenticated requests are not permitted for non TLS protected (https) endpoints"))
} }
return nil return nil

View File

@ -12,13 +12,19 @@ import (
// KeyCredentialPolicy authorizes requests with a [azcore.KeyCredential]. // KeyCredentialPolicy authorizes requests with a [azcore.KeyCredential].
type KeyCredentialPolicy struct { type KeyCredentialPolicy struct {
cred *exported.KeyCredential cred *exported.KeyCredential
header string header string
prefix string prefix string
allowHTTP bool
} }
// KeyCredentialPolicyOptions contains the optional values configuring [KeyCredentialPolicy]. // KeyCredentialPolicyOptions contains the optional values configuring [KeyCredentialPolicy].
type KeyCredentialPolicyOptions struct { type KeyCredentialPolicyOptions struct {
// InsecureAllowCredentialWithHTTP enables authenticated requests over HTTP.
// By default, authenticated requests to an HTTP endpoint are rejected by the client.
// WARNING: setting this to true will allow sending the authentication key in clear text. Use with caution.
InsecureAllowCredentialWithHTTP bool
// Prefix is used if the key requires a prefix before it's inserted into the HTTP request. // Prefix is used if the key requires a prefix before it's inserted into the HTTP request.
Prefix string Prefix string
} }
@ -32,9 +38,10 @@ func NewKeyCredentialPolicy(cred *exported.KeyCredential, header string, options
options = &KeyCredentialPolicyOptions{} options = &KeyCredentialPolicyOptions{}
} }
return &KeyCredentialPolicy{ return &KeyCredentialPolicy{
cred: cred, cred: cred,
header: header, header: header,
prefix: options.Prefix, prefix: options.Prefix,
allowHTTP: options.InsecureAllowCredentialWithHTTP,
} }
} }
@ -44,7 +51,7 @@ func (k *KeyCredentialPolicy) Do(req *policy.Request) (*http.Response, error) {
// this prevents a panic that might be hard to diagnose and allows testing // this prevents a panic that might be hard to diagnose and allows testing
// against http endpoints that don't require authentication. // against http endpoints that don't require authentication.
if k.cred != nil { if k.cred != nil {
if err := checkHTTPSForAuth(req); err != nil { if err := checkHTTPSForAuth(req, k.allowHTTP); err != nil {
return nil, err return nil, err
} }
val := exported.KeyCredentialGet(k.cred) val := exported.KeyCredentialGet(k.cred)

View File

@ -12,13 +12,17 @@ import (
// SASCredentialPolicy authorizes requests with a [azcore.SASCredential]. // SASCredentialPolicy authorizes requests with a [azcore.SASCredential].
type SASCredentialPolicy struct { type SASCredentialPolicy struct {
cred *exported.SASCredential cred *exported.SASCredential
header string header string
allowHTTP bool
} }
// SASCredentialPolicyOptions contains the optional values configuring [SASCredentialPolicy]. // SASCredentialPolicyOptions contains the optional values configuring [SASCredentialPolicy].
type SASCredentialPolicyOptions struct { type SASCredentialPolicyOptions struct {
// placeholder for future optional values // InsecureAllowCredentialWithHTTP enables authenticated requests over HTTP.
// By default, authenticated requests to an HTTP endpoint are rejected by the client.
// WARNING: setting this to true will allow sending the authentication key in clear text. Use with caution.
InsecureAllowCredentialWithHTTP bool
} }
// NewSASCredentialPolicy creates a new instance of [SASCredentialPolicy]. // NewSASCredentialPolicy creates a new instance of [SASCredentialPolicy].
@ -26,9 +30,13 @@ type SASCredentialPolicyOptions struct {
// - header is the name of the HTTP request header in which the shared access signature is placed // - header is the name of the HTTP request header in which the shared access signature is placed
// - options contains optional configuration, pass nil to accept the default values // - options contains optional configuration, pass nil to accept the default values
func NewSASCredentialPolicy(cred *exported.SASCredential, header string, options *SASCredentialPolicyOptions) *SASCredentialPolicy { func NewSASCredentialPolicy(cred *exported.SASCredential, header string, options *SASCredentialPolicyOptions) *SASCredentialPolicy {
if options == nil {
options = &SASCredentialPolicyOptions{}
}
return &SASCredentialPolicy{ return &SASCredentialPolicy{
cred: cred, cred: cred,
header: header, header: header,
allowHTTP: options.InsecureAllowCredentialWithHTTP,
} }
} }
@ -38,7 +46,7 @@ func (k *SASCredentialPolicy) Do(req *policy.Request) (*http.Response, error) {
// this prevents a panic that might be hard to diagnose and allows testing // this prevents a panic that might be hard to diagnose and allows testing
// against http endpoints that don't require authentication. // against http endpoints that don't require authentication.
if k.cred != nil { if k.cred != nil {
if err := checkHTTPSForAuth(req); err != nil { if err := checkHTTPSForAuth(req, k.allowHTTP); err != nil {
return nil, err return nil, err
} }
req.Raw().Header.Add(k.header, exported.SASCredentialGet(k.cred)) req.Raw().Header.Add(k.header, exported.SASCredentialGet(k.cred))

View File

@ -154,7 +154,7 @@ func NewPollerFromResumeToken[T any](token string, pl exported.Pipeline, options
if err != nil { if err != nil {
return nil, err return nil, err
} }
var asJSON map[string]interface{} var asJSON map[string]any
if err := json.Unmarshal(raw, &asJSON); err != nil { if err := json.Unmarshal(raw, &asJSON); err != nil {
return nil, err return nil, err
} }
@ -240,7 +240,7 @@ func (p *Poller[T]) PollUntilDone(ctx context.Context, options *PollUntilDoneOpt
} }
start := time.Now() start := time.Now()
logPollUntilDoneExit := func(v interface{}) { logPollUntilDoneExit := func(v any) {
log.Writef(log.EventLRO, "END PollUntilDone() for %T: %v, total time: %s", p.op, v, time.Since(start)) log.Writef(log.EventLRO, "END PollUntilDone() for %T: %v, total time: %s", p.op, v, time.Since(start))
} }
log.Writef(log.EventLRO, "BEGIN PollUntilDone() for %T", p.op) log.Writef(log.EventLRO, "BEGIN PollUntilDone() for %T", p.op)
@ -334,6 +334,11 @@ func (p *Poller[T]) Result(ctx context.Context) (res T, err error) {
err = p.op.Result(ctx, p.result) err = p.op.Result(ctx, p.result)
var respErr *exported.ResponseError var respErr *exported.ResponseError
if errors.As(err, &respErr) { if errors.As(err, &respErr) {
if pollers.IsNonTerminalHTTPStatusCode(respErr.RawResponse) {
// the request failed in a non-terminal way.
// don't cache the error or mark the Poller as done
return
}
// the LRO failed. record the error // the LRO failed. record the error
p.err = err p.err = err
} else if err != nil { } else if err != nil {

View File

@ -11,9 +11,11 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"encoding/xml" "encoding/xml"
"errors"
"fmt" "fmt"
"io" "io"
"mime/multipart" "mime/multipart"
"net/textproto"
"net/url" "net/url"
"path" "path"
"strings" "strings"
@ -21,6 +23,7 @@ import (
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported" "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared" "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming"
) )
// Base64Encoding is usesd to specify which base-64 encoder/decoder to use when // Base64Encoding is usesd to specify which base-64 encoder/decoder to use when
@ -42,12 +45,19 @@ func NewRequest(ctx context.Context, httpMethod string, endpoint string) (*polic
} }
// EncodeQueryParams will parse and encode any query parameters in the specified URL. // EncodeQueryParams will parse and encode any query parameters in the specified URL.
// Any semicolons will automatically be escaped.
func EncodeQueryParams(u string) (string, error) { func EncodeQueryParams(u string) (string, error) {
before, after, found := strings.Cut(u, "?") before, after, found := strings.Cut(u, "?")
if !found { if !found {
return u, nil return u, nil
} }
qp, err := url.ParseQuery(after) // starting in Go 1.17, url.ParseQuery will reject semicolons in query params.
// so, we must escape them first. note that this assumes that semicolons aren't
// being used as query param separators which is per the current RFC.
// for more info:
// https://github.com/golang/go/issues/25192
// https://github.com/golang/go/issues/50034
qp, err := url.ParseQuery(strings.ReplaceAll(after, ";", "%3B"))
if err != nil { if err != nil {
return "", err return "", err
} }
@ -102,7 +112,7 @@ func MarshalAsByteArray(req *policy.Request, v []byte, format Base64Encoding) er
} }
// MarshalAsJSON calls json.Marshal() to get the JSON encoding of v then calls SetBody. // MarshalAsJSON calls json.Marshal() to get the JSON encoding of v then calls SetBody.
func MarshalAsJSON(req *policy.Request, v interface{}) error { func MarshalAsJSON(req *policy.Request, v any) error {
b, err := json.Marshal(v) b, err := json.Marshal(v)
if err != nil { if err != nil {
return fmt.Errorf("error marshalling type %T: %s", v, err) return fmt.Errorf("error marshalling type %T: %s", v, err)
@ -112,7 +122,7 @@ func MarshalAsJSON(req *policy.Request, v interface{}) error {
} }
// MarshalAsXML calls xml.Marshal() to get the XML encoding of v then calls SetBody. // MarshalAsXML calls xml.Marshal() to get the XML encoding of v then calls SetBody.
func MarshalAsXML(req *policy.Request, v interface{}) error { func MarshalAsXML(req *policy.Request, v any) error {
b, err := xml.Marshal(v) b, err := xml.Marshal(v)
if err != nil { if err != nil {
return fmt.Errorf("error marshalling type %T: %s", v, err) return fmt.Errorf("error marshalling type %T: %s", v, err)
@ -122,10 +132,10 @@ func MarshalAsXML(req *policy.Request, v interface{}) error {
return req.SetBody(exported.NopCloser(bytes.NewReader(b)), shared.ContentTypeAppXML) return req.SetBody(exported.NopCloser(bytes.NewReader(b)), shared.ContentTypeAppXML)
} }
// SetMultipartFormData writes the specified keys/values as multi-part form // SetMultipartFormData writes the specified keys/values as multi-part form fields with the specified value.
// fields with the specified value. File content must be specified as a ReadSeekCloser. // File content must be specified as an [io.ReadSeekCloser] or [streaming.MultipartContent].
// All other values are treated as string values. // Byte slices will be treated as JSON. All other values are treated as string values.
func SetMultipartFormData(req *policy.Request, formData map[string]interface{}) error { func SetMultipartFormData(req *policy.Request, formData map[string]any) error {
body := bytes.Buffer{} body := bytes.Buffer{}
writer := multipart.NewWriter(&body) writer := multipart.NewWriter(&body)
@ -141,6 +151,60 @@ func SetMultipartFormData(req *policy.Request, formData map[string]interface{})
return nil return nil
} }
quoteEscaper := strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
writeMultipartContent := func(fieldname string, mpc streaming.MultipartContent) error {
if mpc.Body == nil {
return errors.New("streaming.MultipartContent.Body cannot be nil")
}
// use fieldname for the file name when unspecified
filename := fieldname
if mpc.ContentType == "" && mpc.Filename == "" {
return writeContent(fieldname, filename, mpc.Body)
}
if mpc.Filename != "" {
filename = mpc.Filename
}
// this is pretty much copied from multipart.Writer.CreateFormFile
// but lets us set the caller provided Content-Type and filename
h := make(textproto.MIMEHeader)
h.Set("Content-Disposition",
fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
quoteEscaper.Replace(fieldname), quoteEscaper.Replace(filename)))
contentType := "application/octet-stream"
if mpc.ContentType != "" {
contentType = mpc.ContentType
}
h.Set("Content-Type", contentType)
fd, err := writer.CreatePart(h)
if err != nil {
return err
}
// copy the data to the form file
if _, err = io.Copy(fd, mpc.Body); err != nil {
return err
}
return nil
}
// the same as multipart.Writer.WriteField but lets us specify the Content-Type
writeField := func(fieldname, contentType string, value string) error {
h := make(textproto.MIMEHeader)
h.Set("Content-Disposition",
fmt.Sprintf(`form-data; name="%s"`, quoteEscaper.Replace(fieldname)))
h.Set("Content-Type", contentType)
fd, err := writer.CreatePart(h)
if err != nil {
return err
}
if _, err = fd.Write([]byte(value)); err != nil {
return err
}
return nil
}
for k, v := range formData { for k, v := range formData {
if rsc, ok := v.(io.ReadSeekCloser); ok { if rsc, ok := v.(io.ReadSeekCloser); ok {
if err := writeContent(k, k, rsc); err != nil { if err := writeContent(k, k, rsc); err != nil {
@ -154,13 +218,35 @@ func SetMultipartFormData(req *policy.Request, formData map[string]interface{})
} }
} }
continue continue
} else if mpc, ok := v.(streaming.MultipartContent); ok {
if err := writeMultipartContent(k, mpc); err != nil {
return err
}
continue
} else if mpcs, ok := v.([]streaming.MultipartContent); ok {
for _, mpc := range mpcs {
if err := writeMultipartContent(k, mpc); err != nil {
return err
}
}
continue
} }
// ensure the value is in string format
s, ok := v.(string) var content string
if !ok { contentType := shared.ContentTypeTextPlain
s = fmt.Sprintf("%v", v) switch tt := v.(type) {
case []byte:
// JSON, don't quote it
content = string(tt)
contentType = shared.ContentTypeAppJSON
case string:
content = tt
default:
// ensure the value is in string format
content = fmt.Sprintf("%v", v)
} }
if err := writer.WriteField(k, s); err != nil {
if err := writeField(k, contentType, content); err != nil {
return err return err
} }
} }

View File

@ -40,7 +40,7 @@ func UnmarshalAsByteArray(resp *http.Response, v *[]byte, format Base64Encoding)
} }
// UnmarshalAsJSON calls json.Unmarshal() to unmarshal the received payload into the value pointed to by v. // UnmarshalAsJSON calls json.Unmarshal() to unmarshal the received payload into the value pointed to by v.
func UnmarshalAsJSON(resp *http.Response, v interface{}) error { func UnmarshalAsJSON(resp *http.Response, v any) error {
payload, err := Payload(resp) payload, err := Payload(resp)
if err != nil { if err != nil {
return err return err
@ -61,7 +61,7 @@ func UnmarshalAsJSON(resp *http.Response, v interface{}) error {
} }
// UnmarshalAsXML calls xml.Unmarshal() to unmarshal the received payload into the value pointed to by v. // UnmarshalAsXML calls xml.Unmarshal() to unmarshal the received payload into the value pointed to by v.
func UnmarshalAsXML(resp *http.Response, v interface{}) error { func UnmarshalAsXML(resp *http.Response, v any) error {
payload, err := Payload(resp) payload, err := Payload(resp)
if err != nil { if err != nil {
return err return err

View File

@ -73,3 +73,17 @@ func (p *progress) Seek(offset int64, whence int) (int64, error) {
func (p *progress) Close() error { func (p *progress) Close() error {
return p.rc.Close() return p.rc.Close()
} }
// MultipartContent contains streaming content used in multipart/form payloads.
type MultipartContent struct {
// Body contains the required content body.
Body io.ReadSeekCloser
// ContentType optionally specifies the HTTP Content-Type for this Body.
// The default value is application/octet-stream.
ContentType string
// Filename optionally specifies the filename for this Body.
// The default value is the field name for the multipart/form section.
Filename string
}

View File

@ -1,5 +1,14 @@
# Release History # Release History
## 1.3.2 (2024-04-09)
### Bugs Fixed
* Fixed an issue where GetSASURL() was providing HTTPS SAS, instead of the default http+https SAS. Fixes [#22448](https://github.com/Azure/azure-sdk-for-go/issues/22448)
### Other Changes
* Integrate `InsecureAllowCredentialWithHTTP` client options.
* Update dependencies.
## 1.3.1 (2024-02-28) ## 1.3.1 (2024-02-28)
### Bugs Fixed ### Bugs Fixed

View File

@ -9,19 +9,19 @@ package appendblob
import ( import (
"context" "context"
"errors" "errors"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/sas"
"io" "io"
"os" "os"
"time" "time"
"github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/base" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/base"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/shared" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/shared"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/sas"
) )
// ClientOptions contains the optional parameters when creating a Client. // ClientOptions contains the optional parameters when creating a Client.
@ -36,8 +36,8 @@ type Client base.CompositeClient[generated.BlobClient, generated.AppendBlobClien
// - options - client options; pass nil to accept the default values // - options - client options; pass nil to accept the default values
func NewClient(blobURL string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) { func NewClient(blobURL string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) {
audience := base.GetAudience((*base.ClientOptions)(options)) audience := base.GetAudience((*base.ClientOptions)(options))
authPolicy := shared.NewStorageChallengePolicy(cred, audience)
conOptions := shared.GetClientOptions(options) conOptions := shared.GetClientOptions(options)
authPolicy := shared.NewStorageChallengePolicy(cred, audience, conOptions.InsecureAllowCredentialWithHTTP)
plOpts := runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy}} plOpts := runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy}}
azClient, err := azcore.NewClient(exported.ModuleName, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) azClient, err := azcore.NewClient(exported.ModuleName, exported.ModuleVersion, plOpts, &conOptions.ClientOptions)

View File

@ -37,8 +37,8 @@ type Client base.Client[generated.BlobClient]
// - options - client options; pass nil to accept the default values // - options - client options; pass nil to accept the default values
func NewClient(blobURL string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) { func NewClient(blobURL string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) {
audience := base.GetAudience((*base.ClientOptions)(options)) audience := base.GetAudience((*base.ClientOptions)(options))
authPolicy := shared.NewStorageChallengePolicy(cred, audience)
conOptions := shared.GetClientOptions(options) conOptions := shared.GetClientOptions(options)
authPolicy := shared.NewStorageChallengePolicy(cred, audience, conOptions.InsecureAllowCredentialWithHTTP)
plOpts := runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy}} plOpts := runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy}}
azClient, err := azcore.NewClient(exported.ModuleName, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) azClient, err := azcore.NewClient(exported.ModuleName, exported.ModuleVersion, plOpts, &conOptions.ClientOptions)

View File

@ -11,9 +11,6 @@ import (
"context" "context"
"encoding/base64" "encoding/base64"
"errors" "errors"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/sas"
"io" "io"
"math" "math"
"os" "os"
@ -22,16 +19,19 @@ import (
"time" "time"
"github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming" "github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to" "github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
"github.com/Azure/azure-sdk-for-go/sdk/internal/log" "github.com/Azure/azure-sdk-for-go/sdk/internal/log"
"github.com/Azure/azure-sdk-for-go/sdk/internal/uuid" "github.com/Azure/azure-sdk-for-go/sdk/internal/uuid"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/base" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/base"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/shared" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/shared"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/sas"
) )
// ClientOptions contains the optional parameters when creating a Client. // ClientOptions contains the optional parameters when creating a Client.
@ -46,8 +46,8 @@ type Client base.CompositeClient[generated.BlobClient, generated.BlockBlobClient
// - options - client options; pass nil to accept the default values // - options - client options; pass nil to accept the default values
func NewClient(blobURL string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) { func NewClient(blobURL string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) {
audience := base.GetAudience((*base.ClientOptions)(options)) audience := base.GetAudience((*base.ClientOptions)(options))
authPolicy := shared.NewStorageChallengePolicy(cred, audience)
conOptions := shared.GetClientOptions(options) conOptions := shared.GetClientOptions(options)
authPolicy := shared.NewStorageChallengePolicy(cred, audience, conOptions.InsecureAllowCredentialWithHTTP)
plOpts := runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy}} plOpts := runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy}}
azClient, err := azcore.NewClient(exported.ModuleName, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) azClient, err := azcore.NewClient(exported.ModuleName, exported.ModuleVersion, plOpts, &conOptions.ClientOptions)

View File

@ -21,8 +21,8 @@ pr:
- sdk/storage/azblob - sdk/storage/azblob
stages: extends:
- template: /eng/pipelines/templates/jobs/archetype-sdk-client.yml template: /eng/pipelines/templates/jobs/archetype-sdk-client.yml
parameters: parameters:
ServiceDirectory: 'storage/azblob' ServiceDirectory: 'storage/azblob'
RunLiveTests: true RunLiveTests: true

View File

@ -11,8 +11,6 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror"
"net/http" "net/http"
"net/url" "net/url"
"time" "time"
@ -20,8 +18,10 @@ import (
"github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/appendblob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/appendblob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/base" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/base"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported"
@ -43,8 +43,8 @@ type Client base.Client[generated.ContainerClient]
// - options - client options; pass nil to accept the default values // - options - client options; pass nil to accept the default values
func NewClient(containerURL string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) { func NewClient(containerURL string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) {
audience := base.GetAudience((*base.ClientOptions)(options)) audience := base.GetAudience((*base.ClientOptions)(options))
authPolicy := shared.NewStorageChallengePolicy(cred, audience)
conOptions := shared.GetClientOptions(options) conOptions := shared.GetClientOptions(options)
authPolicy := shared.NewStorageChallengePolicy(cred, audience, conOptions.InsecureAllowCredentialWithHTTP)
plOpts := runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy}} plOpts := runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy}}
azClient, err := azcore.NewClient(exported.ModuleName, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) azClient, err := azcore.NewClient(exported.ModuleName, exported.ModuleVersion, plOpts, &conOptions.ClientOptions)
@ -348,7 +348,6 @@ func (c *Client) GetSASURL(permissions sas.ContainerPermissions, expiry time.Tim
// Containers do not have snapshots, nor versions. // Containers do not have snapshots, nor versions.
qps, err := sas.BlobSignatureValues{ qps, err := sas.BlobSignatureValues{
Version: sas.Version, Version: sas.Version,
Protocol: sas.ProtocolHTTPS,
ContainerName: urlParts.ContainerName, ContainerName: urlParts.ContainerName,
Permissions: permissions.String(), Permissions: permissions.String(),
StartTime: st, StartTime: st,
@ -371,7 +370,8 @@ func (c *Client) NewBatchBuilder() (*BatchBuilder, error) {
switch cred := c.credential().(type) { switch cred := c.credential().(type) {
case *azcore.TokenCredential: case *azcore.TokenCredential:
authPolicy = shared.NewStorageChallengePolicy(*cred, base.GetAudience(c.getClientOptions())) conOptions := c.getClientOptions()
authPolicy = shared.NewStorageChallengePolicy(*cred, base.GetAudience(conOptions), conOptions.InsecureAllowCredentialWithHTTP)
case *SharedKeyCredential: case *SharedKeyCredential:
authPolicy = exported.NewSharedKeyCredPolicy(cred) authPolicy = exported.NewSharedKeyCredPolicy(cred)
case nil: case nil:

View File

@ -8,5 +8,5 @@ package exported
const ( const (
ModuleName = "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" ModuleName = "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
ModuleVersion = "v1.3.1" ModuleVersion = "v1.3.2"
) )

View File

@ -8,11 +8,12 @@ package shared
import ( import (
"errors" "errors"
"net/http"
"strings"
"github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
"net/http"
"strings"
) )
type storageAuthorizer struct { type storageAuthorizer struct {
@ -20,13 +21,14 @@ type storageAuthorizer struct {
tenantID string tenantID string
} }
func NewStorageChallengePolicy(cred azcore.TokenCredential, audience string) policy.Policy { func NewStorageChallengePolicy(cred azcore.TokenCredential, audience string, allowHTTP bool) policy.Policy {
s := storageAuthorizer{scopes: []string{audience}} s := storageAuthorizer{scopes: []string{audience}}
return runtime.NewBearerTokenPolicy(cred, []string{audience}, &policy.BearerTokenOptions{ return runtime.NewBearerTokenPolicy(cred, []string{audience}, &policy.BearerTokenOptions{
AuthorizationHandler: policy.AuthorizationHandler{ AuthorizationHandler: policy.AuthorizationHandler{
OnRequest: s.onRequest, OnRequest: s.onRequest,
OnChallenge: s.onChallenge, OnChallenge: s.onChallenge,
}, },
InsecureAllowCredentialWithHTTP: allowHTTP,
}) })
} }

View File

@ -8,7 +8,6 @@ package pageblob
import ( import (
"context" "context"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/sas"
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
@ -23,6 +22,7 @@ import (
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/shared" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/shared"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/sas"
) )
// ClientOptions contains the optional parameters when creating a Client. // ClientOptions contains the optional parameters when creating a Client.
@ -37,8 +37,8 @@ type Client base.CompositeClient[generated.BlobClient, generated.PageBlobClient]
// - options - client options; pass nil to accept the default values // - options - client options; pass nil to accept the default values
func NewClient(blobURL string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) { func NewClient(blobURL string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) {
audience := base.GetAudience((*base.ClientOptions)(options)) audience := base.GetAudience((*base.ClientOptions)(options))
authPolicy := shared.NewStorageChallengePolicy(cred, audience)
conOptions := shared.GetClientOptions(options) conOptions := shared.GetClientOptions(options)
authPolicy := shared.NewStorageChallengePolicy(cred, audience, conOptions.InsecureAllowCredentialWithHTTP)
plOpts := runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy}} plOpts := runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy}}
azClient, err := azcore.NewClient(exported.ModuleName, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) azClient, err := azcore.NewClient(exported.ModuleName, exported.ModuleVersion, plOpts, &conOptions.ClientOptions)

View File

@ -8,6 +8,7 @@ package sas
import ( import (
"errors" "errors"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated"
"net" "net"
"net/url" "net/url"
"strings" "strings"
@ -23,7 +24,7 @@ const (
var ( var (
// Version is the default version encoded in the SAS token. // Version is the default version encoded in the SAS token.
Version = "2021-12-02" Version = generated.ServiceVersion
) )
// TimeFormats ISO 8601 format. // TimeFormats ISO 8601 format.

View File

@ -11,9 +11,6 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/base"
"net/http" "net/http"
"strings" "strings"
"time" "time"
@ -21,8 +18,11 @@ import (
"github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/base"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/shared" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/shared"
@ -41,8 +41,8 @@ type Client base.Client[generated.ServiceClient]
// - options - client options; pass nil to accept the default values // - options - client options; pass nil to accept the default values
func NewClient(serviceURL string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) { func NewClient(serviceURL string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) {
audience := base.GetAudience((*base.ClientOptions)(options)) audience := base.GetAudience((*base.ClientOptions)(options))
authPolicy := shared.NewStorageChallengePolicy(cred, audience)
conOptions := shared.GetClientOptions(options) conOptions := shared.GetClientOptions(options)
authPolicy := shared.NewStorageChallengePolicy(cred, audience, conOptions.InsecureAllowCredentialWithHTTP)
plOpts := runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy}} plOpts := runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy}}
azClient, err := azcore.NewClient(exported.ModuleName, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) azClient, err := azcore.NewClient(exported.ModuleName, exported.ModuleVersion, plOpts, &conOptions.ClientOptions)
@ -280,7 +280,6 @@ func (s *Client) GetSASURL(resources sas.AccountResourceTypes, permissions sas.A
st := o.format() st := o.format()
qps, err := sas.AccountSignatureValues{ qps, err := sas.AccountSignatureValues{
Version: sas.Version, Version: sas.Version,
Protocol: sas.ProtocolHTTPS,
Permissions: permissions.String(), Permissions: permissions.String(),
ResourceTypes: resources.String(), ResourceTypes: resources.String(),
StartTime: st, StartTime: st,
@ -320,7 +319,8 @@ func (s *Client) NewBatchBuilder() (*BatchBuilder, error) {
switch cred := s.credential().(type) { switch cred := s.credential().(type) {
case *azcore.TokenCredential: case *azcore.TokenCredential:
authPolicy = shared.NewStorageChallengePolicy(*cred, base.GetAudience(s.getClientOptions())) conOptions := s.getClientOptions()
authPolicy = shared.NewStorageChallengePolicy(*cred, base.GetAudience(conOptions), conOptions.InsecureAllowCredentialWithHTTP)
case *SharedKeyCredential: case *SharedKeyCredential:
authPolicy = exported.NewSharedKeyCredPolicy(cred) authPolicy = exported.NewSharedKeyCredPolicy(cred)
case nil: case nil:

4
vendor/modules.txt vendored
View File

@ -33,7 +33,7 @@ github.com/AdamKorcz/go-118-fuzz-build/testing
## explicit ## explicit
github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/runtime/2019-08-15-preview/containerregistry github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/runtime/2019-08-15-preview/containerregistry
github.com/Azure/azure-sdk-for-go/version github.com/Azure/azure-sdk-for-go/version
# github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2 # github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1
## explicit; go 1.18 ## explicit; go 1.18
github.com/Azure/azure-sdk-for-go/sdk/azcore github.com/Azure/azure-sdk-for-go/sdk/azcore
github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud
@ -61,7 +61,7 @@ github.com/Azure/azure-sdk-for-go/sdk/internal/log
github.com/Azure/azure-sdk-for-go/sdk/internal/poller github.com/Azure/azure-sdk-for-go/sdk/internal/poller
github.com/Azure/azure-sdk-for-go/sdk/internal/temporal github.com/Azure/azure-sdk-for-go/sdk/internal/temporal
github.com/Azure/azure-sdk-for-go/sdk/internal/uuid github.com/Azure/azure-sdk-for-go/sdk/internal/uuid
# github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.1 # github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.2
## explicit; go 1.18 ## explicit; go 1.18
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob github.com/Azure/azure-sdk-for-go/sdk/storage/azblob
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/appendblob github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/appendblob