github.com/Ingenico-ePayments/connect-sdk-go@v0.0.0-20240318153750-1f8cd329b9c9/communicator/MetaDataProvider.go (about) 1 package communicator 2 3 import ( 4 "encoding/base64" 5 "errors" 6 "runtime" 7 8 "github.com/Ingenico-ePayments/connect-sdk-go/communicator/communication" 9 "github.com/Ingenico-ePayments/connect-sdk-go/defaultimpl" 10 "github.com/Ingenico-ePayments/connect-sdk-go/domain/metadata" 11 ) 12 13 var ( 14 // ErrProhibitedHeader occurs when the header name is prohibited 15 ErrProhibitedHeader = errors.New("header is prohibited") 16 ) 17 18 type serverMetaInfo struct { 19 PlatformIdentifier string `json:"platformIdentifier,omitempty"` 20 SDKIdentifier string `json:"sdkIdentifier,omitempty"` 21 SDKCreator string `json:"sdkCreator,omitempty"` 22 Integrator string `json:"integrator,omitempty"` 23 ShoppingCartExtension *metadata.ShoppingCartExtension `json:"shoppingCartExtension,omitempty"` 24 } 25 26 // MetaDataProvider provides meta info about the server. Thread-safe. 27 type MetaDataProvider struct { 28 serverMetaInfo serverMetaInfo 29 metaDataHeaders []communication.Header 30 } 31 32 // ProhibitedHeaders are the headers that can't be included in the server requests 33 var ProhibitedHeaders = []string{serverMetaInfoHeader, "X-GCS-Idempotence-Key", 34 "Date", "Content-Type", "Authorization"} 35 36 func getPlatformIdentifier() string { 37 //I believe there is no standard function thus we need to do something like 38 //https://github.com/matishsiao/goInfo 39 return runtime.GOOS + " " + runtime.Version() + "(" + runtime.GOARCH + ")" 40 } 41 42 const sdkIdentifier = "GoServerSDK/v" + sdkVersion 43 const sdkVersion = "2.47.0" 44 const serverMetaInfoHeader = "X-GCS-ServerMetaInfo" 45 46 // NewMetaDataProviderWithBuilder creates a MetaDataProvider with the given MetaDataProviderBuilder 47 func NewMetaDataProviderWithBuilder(builder MetaDataProviderBuilder) (*MetaDataProvider, error) { 48 return newMetaDataProvider(builder.integrator, builder.ShoppingCartExtension, builder.AdditionalRequestHeaders) 49 } 50 51 // NewMetaDataProviderWithIntegrator creates a MetaDataProvider with the given integrator 52 func NewMetaDataProviderWithIntegrator(integrator string) (*MetaDataProvider, error) { 53 return newMetaDataProvider(integrator, nil, nil) 54 } 55 56 func newMetaDataProvider(integrator string, shoppingCartExtension *metadata.ShoppingCartExtension, additionalRequestHeaders []communication.Header) (*MetaDataProvider, error) { 57 err := validateAdditionalRequestHeaders(additionalRequestHeaders) 58 if err != nil { 59 return nil, err 60 } 61 sMetaInfo := serverMetaInfo{ 62 getPlatformIdentifier(), 63 sdkIdentifier, 64 "Ingenico", 65 integrator, 66 shoppingCartExtension, 67 } 68 marshaller, err := defaultimpl.NewDefaultMarshaller() 69 if err != nil { 70 return nil, err 71 } 72 73 serverMetaInfoString, err := marshaller.Marshal(&sMetaInfo) 74 if err != nil { 75 return nil, err 76 } 77 78 serverMetaInfoBase64 := base64.StdEncoding.EncodeToString([]byte(serverMetaInfoString)) 79 header, err := communication.NewHeader(serverMetaInfoHeader, serverMetaInfoBase64) 80 if err != nil { 81 return nil, err 82 } 83 head := []communication.Header{*header} 84 head = append(head, additionalRequestHeaders...) 85 return &MetaDataProvider{sMetaInfo, head}, nil 86 } 87 88 func validateAdditionalRequestHeader(additionalRequestHeader communication.Header) error { 89 for _, a := range ProhibitedHeaders { 90 if a == additionalRequestHeader.Name() { 91 return ErrProhibitedHeader 92 } 93 } 94 return nil 95 } 96 97 func validateAdditionalRequestHeaders(additionalRequestHeaders []communication.Header) error { 98 for _, additionalRequestHeader := range additionalRequestHeaders { 99 err := validateAdditionalRequestHeader(additionalRequestHeader) 100 if err != nil { 101 return err 102 } 103 } 104 return nil 105 } 106 107 // MetaDataHeaders returns the server related headers containing the metadata to be associated with the request (if any). 108 // This will always contain at least an automatically generated header X-GCS-ServerMetaInfo. 109 func (m *MetaDataProvider) MetaDataHeaders() []communication.Header { 110 // Return a clone instead of the original slice - immutability insurance 111 return append([]communication.Header{}, m.metaDataHeaders...) 112 }