diff options
| -rw-r--r-- | errors.go | 12 | ||||
| -rw-r--r-- | field_metadata.go (renamed from headers/metadata.go) | 40 | ||||
| -rw-r--r-- | field_string.go (renamed from headers/string.go) | 44 | ||||
| -rw-r--r-- | field_time.go (renamed from headers/time.go) | 47 | ||||
| -rw-r--r-- | field_uint64.go (renamed from headers/uint64.go) | 71 | ||||
| -rw-r--r-- | generated.go | 298 | ||||
| -rw-r--r-- | generated.go.in | 80 | ||||
| -rw-r--r-- | headers.go | 7 | ||||
| -rw-r--r-- | headers/base.go | 33 | ||||
| -rw-r--r-- | headers/errors.go | 31 | ||||
| -rw-r--r-- | headers/headers.go | 91 | ||||
| -rw-r--r-- | headers/headers_test.go | 97 |
12 files changed, 273 insertions, 578 deletions
@@ -76,3 +76,15 @@ func Is(err error, code int) bool { } return false } + +//MalformedHeaderError is generated when a response from Swift contains a +//malformed header. +type MalformedHeaderError struct { + Key string + ParseError error +} + +//Error implements the builtin/error interface. +func (e MalformedHeaderError) Error() string { + return "Bad header " + e.Key + ": " + e.ParseError.Error() +} diff --git a/headers/metadata.go b/field_metadata.go index 8f07e89..cebd2af 100644 --- a/headers/metadata.go +++ b/field_metadata.go @@ -16,37 +16,41 @@ * ******************************************************************************/ -package headers +package schwift -//Metadata is a helper type that provides safe access to the metadata headers -//in a schwift.Headers instance. It cannot be directly constructed, but each -//subtype of schwift.Headers has a field "Metadata" of this type. For example: +//FieldMetadata is a helper type that provides safe access to the metadata headers +//in a SomethingHeaders instance. It cannot be directly constructed, but each +//SomethingHeaders type has a method "Metadata" returning this type. For example: // -// var hdr ObjectHeaders +// hdr := make(ObjectHeaders) // //the following two statements are equivalent -// hdr.Set("X-Object-Meta-Access", "strictly confidential") -// hdr.Metadata.Set("Access", "strictly confidential") -// //because hdr.Metadata is a headers.Metadata instance -type Metadata struct { - Base +// hdr["X-Object-Meta-Access"] = "strictly confidential" +// hdr.Metadata().Set("Access", "strictly confidential") +type FieldMetadata struct { + h headerInterface + k string } //Clear works like Headers.Clear(), but prepends the metadata prefix to the key. -func (m Metadata) Clear(key string) { - m.H.Clear(m.K + key) +func (m FieldMetadata) Clear(key string) { + m.h.Clear(m.k + key) } //Del works like Headers.Del(), but prepends the metadata prefix to the key. -func (m Metadata) Del(key string) { - m.H.Del(m.K + key) +func (m FieldMetadata) Del(key string) { + m.h.Del(m.k + key) } //Get works like Headers.Get(), but prepends the metadata prefix to the key. -func (m Metadata) Get(key string) string { - return m.H.Get(m.K + key) +func (m FieldMetadata) Get(key string) string { + return m.h.Get(m.k + key) } //Set works like Headers.Set(), but prepends the metadata prefix to the key. -func (m Metadata) Set(key, value string) { - m.H.Set(m.K+key, value) +func (m FieldMetadata) Set(key, value string) { + m.h.Set(m.k+key, value) +} + +func (m FieldMetadata) validate() error { + return nil } diff --git a/headers/string.go b/field_string.go index 9979aef..d44d517 100644 --- a/headers/string.go +++ b/field_string.go @@ -16,45 +16,49 @@ * ******************************************************************************/ -package headers +package schwift -//String is a helper type that provides type-safe access to a Swift header key -//whose value is a string. It cannot be directly constructed, but some subtypes -//of schwift.Headers have fields of this type. For example: +//FieldString is a helper type that provides type-safe access to a Swift header key +//whose value is a string. It cannot be directly constructed, but methods on +//the Headers types return this type. For example: // -// var hdr AccountHeaders +// hdr := make(AccountHeaders) // //the following two statements are equivalent: -// hdr.Set("X-Container-Read", ".r:*,.rlistings") -// hdr.ReadACL.Set(".r:*,.rlistings") -// //because hdr.ReadACL is a headers.String instance -type String struct { - Base +// hdr["X-Container-Read"] = ".r:*,.rlistings" +// hdr.ReadACL().Set(".r:*,.rlistings") +type FieldString struct { + h headerInterface + k string } //Exists checks whether there is a value for this header. -func (f String) Exists() bool { - return f.H.Get(f.K) != "" +func (f FieldString) Exists() bool { + return f.h.Get(f.k) != "" } //Get returns the value for this header, or the empty string if there is no value. -func (f String) Get() string { - return f.H.Get(f.K) +func (f FieldString) Get() string { + return f.h.Get(f.k) } //Set writes a new value for this header into the corresponding schwift.Headers //instance. -func (f String) Set(value string) { - f.H.Set(f.K, value) +func (f FieldString) Set(value string) { + f.h.Set(f.k, value) } //Del removes this key from the original schwift.Headers instance, so that the //key will remain unchanged on the server during Update(). -func (f String) Del() { - f.H.Del(f.K) +func (f FieldString) Del() { + f.h.Del(f.k) } //Clear sets this key to an empty string in the original schwift.Headers //instance, so that the key will be removed on the server during Update(). -func (f String) Clear() { - f.H.Clear(f.K) +func (f FieldString) Clear() { + f.h.Clear(f.k) +} + +func (f FieldString) validate() error { + return nil } diff --git a/headers/time.go b/field_time.go index 5f9209f..d8a1776 100644 --- a/headers/time.go +++ b/field_time.go @@ -16,7 +16,7 @@ * ******************************************************************************/ -package headers +package schwift import ( "math" @@ -24,28 +24,37 @@ import ( "time" ) -//UnixTimeReadonly is a helper type that provides type-safe access to a Swift -//header whose value is a UNIX timestamp. It cannot be directly constructed, -//but some subtypes of schwift.Headers have fields of this type. For example: +//FieldUnixTimeReadonly is a helper type that provides type-safe access to a +//Swift header whose value is a UNIX timestamp. It cannot be directly +//constructed, but methods on the Headers types return this type. For example: // -// var hdr AccountHeaders -// //hdr.Timestamp is a headers.UnixTimeReadonly instance -// hdr.Timestamp.Get() //returns a time.Time -// hdr.Get("X-Timestamp") //returns a string containing a UNIX timestamp -// //refering to the same point in time -type UnixTimeReadonly struct { - Base +// //suppose you have: +// hdr, err := obj.Headers() +// +// //you could do all this: +// sec, err := strconv.ParseFloat(hdr.Get("X-Timestamp"), 64) +// time := time.Unix(int64(sec), int64(1e9 * (sec - math.Floor(sec)))) +// +// //or you can just: +// time := hdr.Timestamp().Get() +// +//Don't worry about the missing `err` in the last line. When the X-Timestamp +//header fails to parse, Object.Headers() already returns the corresponding +//MalformedHeaderError. +type FieldUnixTimeReadonly struct { + h headerInterface + k string } //Exists checks whether there is a value for this header. -func (f UnixTimeReadonly) Exists() bool { - return f.H.Get(f.K) != "" +func (f FieldUnixTimeReadonly) Exists() bool { + return f.h.Get(f.k) != "" } //Get returns the value for this header, or the zero value if there is no value //(or if it is not a valid timestamp). -func (f UnixTimeReadonly) Get() time.Time { - v, err := strconv.ParseFloat(f.H.Get(f.K), 64) +func (f FieldUnixTimeReadonly) Get() time.Time { + v, err := strconv.ParseFloat(f.h.Get(f.k), 64) if err != nil { return time.Time{} } @@ -56,10 +65,8 @@ func (f UnixTimeReadonly) Get() time.Time { ) } -//Validate is only used internally, but needs to be exported to cross package -//boundaries. -func (f UnixTimeReadonly) Validate() error { - val := f.H.Get(f.K) +func (f FieldUnixTimeReadonly) validate() error { + val := f.h.Get(f.k) if val == "" { return nil } @@ -67,5 +74,5 @@ func (f UnixTimeReadonly) Validate() error { if err == nil { return nil } - return MalformedHeaderError{f.K, err} + return MalformedHeaderError{f.k, err} } diff --git a/headers/uint64.go b/field_uint64.go index 6e8668b..4655478 100644 --- a/headers/uint64.go +++ b/field_uint64.go @@ -16,34 +16,34 @@ * ******************************************************************************/ -package headers +package schwift import ( "strconv" ) -//Uint64 is a helper type that provides type-safe access to a Swift header +//FieldUint64 is a helper type that provides type-safe access to a Swift header //whose value is an unsigned integer. It cannot be directly constructed, but -//some subtypes of schwift.Headers have fields of this type. For example: +//methods on the Headers types return this type. For example: // -// var hdr AccountHeaders +// hdr := make(AccountHeaders) // //the following two statements are equivalent: -// hdr.Set("X-Account-Meta-Quota-Bytes", "1048576") -// hdr.QuotaBytes.Set(1 << 20) -// //because hdr.QuotaBytes is a headers.Uint64 instance -type Uint64 struct { - Base +// hdr["X-Account-Meta-Quota-Bytes"] = "1048576" +// hdr.QuotaBytes().Set(1 << 20) +type FieldUint64 struct { + h headerInterface + k string } //Exists checks whether there is a value for this header. -func (f Uint64) Exists() bool { - return f.H.Get(f.K) != "" +func (f FieldUint64) Exists() bool { + return f.h.Get(f.k) != "" } //Get returns the value for this header, or 0 if there is no value (or if it is //not a valid uint64). -func (f Uint64) Get() uint64 { - v, err := strconv.ParseUint(f.H.Get(f.K), 10, 64) +func (f FieldUint64) Get() uint64 { + v, err := strconv.ParseUint(f.h.Get(f.k), 10, 64) if err != nil { return 0 } @@ -52,26 +52,26 @@ func (f Uint64) Get() uint64 { //Set writes a new value for this header into the corresponding schwift.Headers //instance. -func (f Uint64) Set(value uint64) { - f.H.Set(f.K, strconv.FormatUint(value, 10)) +func (f FieldUint64) Set(value uint64) { + f.h.Set(f.k, strconv.FormatUint(value, 10)) } //Del removes this key from the original schwift.Headers instance, so that the //key will remain unchanged on the server during Update(). -func (f Uint64) Del() { - f.H.Del(f.K) +func (f FieldUint64) Del() { + f.h.Del(f.k) } //Clear sets this key to an empty string in the original schwift.Headers //instance, so that the key will be removed on the server during Update(). -func (f Uint64) Clear() { - f.H.Clear(f.K) +func (f FieldUint64) Clear() { + f.h.Clear(f.k) } -//Validate is only used internally, but needs to be exported to cross package +//validate is only used internally, but needs to be exported to cross package //boundaries. -func (f Uint64) Validate() error { - val := f.H.Get(f.K) +func (f FieldUint64) validate() error { + val := f.h.Get(f.k) if val == "" { return nil } @@ -79,36 +79,35 @@ func (f Uint64) Validate() error { if err == nil { return nil } - return MalformedHeaderError{f.K, err} + return MalformedHeaderError{f.k, err} } //////////////////////////////////////////////////////////////////////////////// -//Uint64Readonly is a readonly variant of Uint64. It is used for fields that -//cannot be set by the client. -type Uint64Readonly struct { - Base +//FieldUint64Readonly is a readonly variant of FieldUint64. It is used for +//fields that cannot be set by the client. +type FieldUint64Readonly struct { + h headerInterface + k string } //Exists checks whether there is a value for this header. -func (f Uint64Readonly) Exists() bool { - return f.H.Get(f.K) != "" +func (f FieldUint64Readonly) Exists() bool { + return f.h.Get(f.k) != "" } //Get returns the value for this header, or 0 if there is no value (or if it is //not a valid uint64). -func (f Uint64Readonly) Get() uint64 { - v, err := strconv.ParseUint(f.H.Get(f.K), 10, 64) +func (f FieldUint64Readonly) Get() uint64 { + v, err := strconv.ParseUint(f.h.Get(f.k), 10, 64) if err != nil { return 0 } return v } -//Validate is only used internally, but needs to be exported to cross package -//boundaries. -func (f Uint64Readonly) Validate() error { - val := f.H.Get(f.K) +func (f FieldUint64Readonly) validate() error { + val := f.h.Get(f.k) if val == "" { return nil } @@ -116,5 +115,5 @@ func (f Uint64Readonly) Validate() error { if err == nil { return nil } - return MalformedHeaderError{f.K, err} + return MalformedHeaderError{f.k, err} } diff --git a/generated.go b/generated.go index a3dca80..60b5a46 100644 --- a/generated.go +++ b/generated.go @@ -8,16 +8,13 @@ package schwift -import ( - "net/textproto" - - "github.com/majewsky/schwift/headers" -) +import "net/textproto" //AccountHeaders contains the headers for a schwift.Account instance. // //To read and write well-known headers, use the methods on this type. -//To read and write arbitary headers, use the methods on type Headers. +//To read and write arbitary headers, use the http.Header-like methods Get(), +//Set(), Clear(), Del(). type AccountHeaders map[string]string //Clear sets the value for the specified header to the empty string. When the @@ -49,114 +46,84 @@ func (h AccountHeaders) Set(key, value string) { h[textproto.CanonicalMIMEHeaderKey(key)] = value } -//Validate returns headers.MalformedHeaderError if the value of any well-known -//header does not conform to its data type. This is called automatically by -//Schwift when preparing an AccountHeaders instance from a GET/HEAD response, -//so you usually do not need to do it yourself. You will get the validation error -//from the Account method doing the request, e.g. Headers(). +//Validate returns MalformedHeaderError if the value of any well-known header +//does not conform to its data type. This is called automatically by Schwift +//when preparing an AccountHeaders instance from a GET/HEAD response, so you +//usually do not need to do it yourself. You will get the validation error from +//the Account method doing the request, e.g. Headers(). func (h AccountHeaders) Validate() error { - if err := h.BytesUsed().Validate(); err != nil { + if err := h.BytesUsed().validate(); err != nil { + return err + } + if err := h.ContainerCount().validate(); err != nil { + return err + } + if err := h.Metadata().validate(); err != nil { + return err + } + if err := h.QuotaBytes().validate(); err != nil { return err } - if err := h.ContainerCount().Validate(); err != nil { + if err := h.TempURLKey2().validate(); err != nil { return err } - if err := h.QuotaBytes().Validate(); err != nil { + if err := h.TempURLKey().validate(); err != nil { return err } - if err := h.ObjectCount().Validate(); err != nil { + if err := h.ObjectCount().validate(); err != nil { return err } - if err := h.Timestamp().Validate(); err != nil { + if err := h.Timestamp().validate(); err != nil { return err } return evadeGolintComplaint1() } //BytesUsed provides type-safe access to X-Account-Bytes-Used headers. -func (h AccountHeaders) BytesUsed() headers.Uint64Readonly { - return headers.Uint64Readonly{ - Base: headers.Base{ - H: h, - K: "X-Account-Bytes-Used", - }, - } +func (h AccountHeaders) BytesUsed() FieldUint64Readonly { + return FieldUint64Readonly{h, "X-Account-Bytes-Used"} } //ContainerCount provides type-safe access to X-Account-Container-Count headers. -func (h AccountHeaders) ContainerCount() headers.Uint64Readonly { - return headers.Uint64Readonly{ - Base: headers.Base{ - H: h, - K: "X-Account-Container-Count", - }, - } +func (h AccountHeaders) ContainerCount() FieldUint64Readonly { + return FieldUint64Readonly{h, "X-Account-Container-Count"} } //Metadata provides type-safe access to X-Account-Meta- headers. -func (h AccountHeaders) Metadata() headers.Metadata { - return headers.Metadata{ - Base: headers.Base{ - H: h, - K: "X-Account-Meta-", - }, - } +func (h AccountHeaders) Metadata() FieldMetadata { + return FieldMetadata{h, "X-Account-Meta-"} } //QuotaBytes provides type-safe access to X-Account-Meta-Quota-Bytes headers. -func (h AccountHeaders) QuotaBytes() headers.Uint64 { - return headers.Uint64{ - Base: headers.Base{ - H: h, - K: "X-Account-Meta-Quota-Bytes", - }, - } +func (h AccountHeaders) QuotaBytes() FieldUint64 { + return FieldUint64{h, "X-Account-Meta-Quota-Bytes"} } //TempURLKey2 provides type-safe access to X-Account-Meta-Temp-URL-Key-2 headers. -func (h AccountHeaders) TempURLKey2() headers.String { - return headers.String{ - Base: headers.Base{ - H: h, - K: "X-Account-Meta-Temp-URL-Key-2", - }, - } +func (h AccountHeaders) TempURLKey2() FieldString { + return FieldString{h, "X-Account-Meta-Temp-URL-Key-2"} } //TempURLKey provides type-safe access to X-Account-Meta-Temp-URL-Key headers. -func (h AccountHeaders) TempURLKey() headers.String { - return headers.String{ - Base: headers.Base{ - H: h, - K: "X-Account-Meta-Temp-URL-Key", - }, - } +func (h AccountHeaders) TempURLKey() FieldString { + return FieldString{h, "X-Account-Meta-Temp-URL-Key"} } //ObjectCount provides type-safe access to X-Account-Object-Count headers. -func (h AccountHeaders) ObjectCount() headers.Uint64Readonly { - return headers.Uint64Readonly{ - Base: headers.Base{ - H: h, - K: "X-Account-Object-Count", - }, - } +func (h AccountHeaders) ObjectCount() FieldUint64Readonly { + return FieldUint64Readonly{h, "X-Account-Object-Count"} } //Timestamp provides type-safe access to X-Timestamp headers. -func (h AccountHeaders) Timestamp() headers.UnixTimeReadonly { - return headers.UnixTimeReadonly{ - Base: headers.Base{ - H: h, - K: "X-Timestamp", - }, - } +func (h AccountHeaders) Timestamp() FieldUnixTimeReadonly { + return FieldUnixTimeReadonly{h, "X-Timestamp"} } //ContainerHeaders contains the headers for a schwift.Container instance. // //To read and write well-known headers, use the methods on this type. -//To read and write arbitary headers, use the methods on type Headers. +//To read and write arbitary headers, use the http.Header-like methods Get(), +//Set(), Clear(), Del(). type ContainerHeaders map[string]string //Clear sets the value for the specified header to the empty string. When the @@ -188,178 +155,133 @@ func (h ContainerHeaders) Set(key, value string) { h[textproto.CanonicalMIMEHeaderKey(key)] = value } -//Validate returns headers.MalformedHeaderError if the value of any well-known -//header does not conform to its data type. This is called automatically by -//Schwift when preparing an ContainerHeaders instance from a GET/HEAD response, -//so you usually do not need to do it yourself. You will get the validation error -//from the Container method doing the request, e.g. Headers(). +//Validate returns MalformedHeaderError if the value of any well-known header +//does not conform to its data type. This is called automatically by Schwift +//when preparing an ContainerHeaders instance from a GET/HEAD response, so you +//usually do not need to do it yourself. You will get the validation error from +//the Container method doing the request, e.g. Headers(). func (h ContainerHeaders) Validate() error { - if err := h.BytesUsed().Validate(); err != nil { + if err := h.BytesUsed().validate(); err != nil { + return err + } + if err := h.Metadata().validate(); err != nil { + return err + } + if err := h.BytesUsedQuota().validate(); err != nil { + return err + } + if err := h.ObjectCountQuota().validate(); err != nil { + return err + } + if err := h.TempURLKey2().validate(); err != nil { + return err + } + if err := h.TempURLKey().validate(); err != nil { return err } - if err := h.BytesUsedQuota().Validate(); err != nil { + if err := h.ObjectCount().validate(); err != nil { return err } - if err := h.ObjectCountQuota().Validate(); err != nil { + if err := h.ReadACL().validate(); err != nil { return err } - if err := h.ObjectCount().Validate(); err != nil { + if err := h.SyncKey().validate(); err != nil { return err } - if err := h.Timestamp().Validate(); err != nil { + if err := h.SyncTo().validate(); err != nil { + return err + } + if err := h.WriteACL().validate(); err != nil { + return err + } + if err := h.HistoryLocation().validate(); err != nil { + return err + } + if err := h.StoragePolicy().validate(); err != nil { + return err + } + if err := h.Timestamp().validate(); err != nil { + return err + } + if err := h.VersionsLocation().validate(); err != nil { return err } return evadeGolintComplaint1() } //BytesUsed provides type-safe access to X-Container-Bytes-Used headers. -func (h ContainerHeaders) BytesUsed() headers.Uint64Readonly { - return headers.Uint64Readonly{ - Base: headers.Base{ - H: h, - K: "X-Container-Bytes-Used", - }, - } +func (h ContainerHeaders) BytesUsed() FieldUint64Readonly { + return FieldUint64Readonly{h, "X-Container-Bytes-Used"} } //Metadata provides type-safe access to X-Container-Meta- headers. -func (h ContainerHeaders) Metadata() headers.Metadata { - return headers.Metadata{ - Base: headers.Base{ - H: h, - K: "X-Container-Meta-", - }, - } +func (h ContainerHeaders) Metadata() FieldMetadata { + return FieldMetadata{h, "X-Container-Meta-"} } //BytesUsedQuota provides type-safe access to X-Container-Meta-Quota-Bytes headers. -func (h ContainerHeaders) BytesUsedQuota() headers.Uint64 { - return headers.Uint64{ - Base: headers.Base{ - H: h, - K: "X-Container-Meta-Quota-Bytes", - }, - } +func (h ContainerHeaders) BytesUsedQuota() FieldUint64 { + return FieldUint64{h, "X-Container-Meta-Quota-Bytes"} } //ObjectCountQuota provides type-safe access to X-Container-Meta-Quota-Count headers. -func (h ContainerHeaders) ObjectCountQuota() headers.Uint64 { - return headers.Uint64{ - Base: headers.Base{ - H: h, - K: "X-Container-Meta-Quota-Count", - }, - } +func (h ContainerHeaders) ObjectCountQuota() FieldUint64 { + return FieldUint64{h, "X-Container-Meta-Quota-Count"} } //TempURLKey2 provides type-safe access to X-Container-Meta-Temp-URL-Key-2 headers. -func (h ContainerHeaders) TempURLKey2() headers.String { - return headers.String{ - Base: headers.Base{ - H: h, - K: "X-Container-Meta-Temp-URL-Key-2", - }, - } +func (h ContainerHeaders) TempURLKey2() FieldString { + return FieldString{h, "X-Container-Meta-Temp-URL-Key-2"} } //TempURLKey provides type-safe access to X-Container-Meta-Temp-URL-Key headers. -func (h ContainerHeaders) TempURLKey() headers.String { - return headers.String{ - Base: headers.Base{ - H: h, - K: "X-Container-Meta-Temp-URL-Key", - }, - } +func (h ContainerHeaders) TempURLKey() FieldString { + return FieldString{h, "X-Container-Meta-Temp-URL-Key"} } //ObjectCount provides type-safe access to X-Container-Object-Count headers. -func (h ContainerHeaders) ObjectCount() headers.Uint64Readonly { - return headers.Uint64Readonly{ - Base: headers.Base{ - H: h, - K: "X-Container-Object-Count", - }, - } +func (h ContainerHeaders) ObjectCount() FieldUint64Readonly { + return FieldUint64Readonly{h, "X-Container-Object-Count"} } //ReadACL provides type-safe access to X-Container-Read headers. -func (h ContainerHeaders) ReadACL() headers.String { - return headers.String{ - Base: headers.Base{ - H: h, - K: "X-Container-Read", - }, - } +func (h ContainerHeaders) ReadACL() FieldString { + return FieldString{h, "X-Container-Read"} } //SyncKey provides type-safe access to X-Container-Sync-Key headers. -func (h ContainerHeaders) SyncKey() headers.String { - return headers.String{ - Base: headers.Base{ - H: h, - K: "X-Container-Sync-Key", - }, - } +func (h ContainerHeaders) SyncKey() FieldString { + return FieldString{h, "X-Container-Sync-Key"} } //SyncTo provides type-safe access to X-Container-Sync-To headers. -func (h ContainerHeaders) SyncTo() headers.String { - return headers.String{ - Base: headers.Base{ - H: h, - K: "X-Container-Sync-To", - }, - } +func (h ContainerHeaders) SyncTo() FieldString { + return FieldString{h, "X-Container-Sync-To"} } //WriteACL provides type-safe access to X-Container-Write headers. -func (h ContainerHeaders) WriteACL() headers.String { - return headers.String{ - Base: headers.Base{ - H: h, - K: "X-Container-Write", - }, - } +func (h ContainerHeaders) WriteACL() FieldString { + return FieldString{h, "X-Container-Write"} } //HistoryLocation provides type-safe access to X-History-Location headers. -func (h ContainerHeaders) HistoryLocation() headers.String { - return headers.String{ - Base: headers.Base{ - H: h, - K: "X-History-Location", - }, - } +func (h ContainerHeaders) HistoryLocation() FieldString { + return FieldString{h, "X-History-Location"} } //StoragePolicy provides type-safe access to X-Storage-Policy headers. -func (h ContainerHeaders) StoragePolicy() headers.String { - return headers.String{ - Base: headers.Base{ - H: h, - K: "X-Storage-Policy", - }, - } +func (h ContainerHeaders) StoragePolicy() FieldString { + return FieldString{h, "X-Storage-Policy"} } //Timestamp provides type-safe access to X-Timestamp headers. -func (h ContainerHeaders) Timestamp() headers.UnixTimeReadonly { - return headers.UnixTimeReadonly{ - Base: headers.Base{ - H: h, - K: "X-Timestamp", - }, - } +func (h ContainerHeaders) Timestamp() FieldUnixTimeReadonly { + return FieldUnixTimeReadonly{h, "X-Timestamp"} } //VersionsLocation provides type-safe access to X-Versions-Location headers. -func (h ContainerHeaders) VersionsLocation() headers.String { - return headers.String{ - Base: headers.Base{ - H: h, - K: "X-Versions-Location", - }, - } +func (h ContainerHeaders) VersionsLocation() FieldString { + return FieldString{h, "X-Versions-Location"} } func evadeGolintComplaint1() error { diff --git a/generated.go.in b/generated.go.in index 034a8e4..808c950 100644 --- a/generated.go.in +++ b/generated.go.in @@ -1,33 +1,33 @@ { "Account": { "Fields": [ - { "Header": "X-Account-Bytes-Used", "Attribute": "BytesUsed", "Type": "headers.Uint64Readonly" }, - { "Header": "X-Account-Container-Count", "Attribute": "ContainerCount", "Type": "headers.Uint64Readonly" }, - { "Header": "X-Account-Meta-", "Attribute": "Metadata", "Type": "headers.Metadata" }, - { "Header": "X-Account-Meta-Quota-Bytes", "Attribute": "QuotaBytes", "Type": "headers.Uint64" }, - { "Header": "X-Account-Meta-Temp-URL-Key-2", "Attribute": "TempURLKey2", "Type": "headers.String" }, - { "Header": "X-Account-Meta-Temp-URL-Key", "Attribute": "TempURLKey", "Type": "headers.String" }, - { "Header": "X-Account-Object-Count", "Attribute": "ObjectCount", "Type": "headers.Uint64Readonly" }, - { "Header": "X-Timestamp", "Attribute": "Timestamp", "Type": "headers.UnixTimeReadonly" } + { "Header": "X-Account-Bytes-Used", "Attribute": "BytesUsed", "Type": "Uint64Readonly" }, + { "Header": "X-Account-Container-Count", "Attribute": "ContainerCount", "Type": "Uint64Readonly" }, + { "Header": "X-Account-Meta-", "Attribute": "Metadata", "Type": "Metadata" }, + { "Header": "X-Account-Meta-Quota-Bytes", "Attribute": "QuotaBytes", "Type": "Uint64" }, + { "Header": "X-Account-Meta-Temp-URL-Key-2", "Attribute": "TempURLKey2", "Type": "String" }, + { "Header": "X-Account-Meta-Temp-URL-Key", "Attribute": "TempURLKey", "Type": "String" }, + { "Header": "X-Account-Object-Count", "Attribute": "ObjectCount", "Type": "Uint64Readonly" }, + { "Header": "X-Timestamp", "Attribute": "Timestamp", "Type": "UnixTimeReadonly" } ] }, "Container": { "Fields": [ - { "Header": "X-Container-Bytes-Used", "Attribute": "BytesUsed", "Type": "headers.Uint64Readonly" }, - { "Header": "X-Container-Meta-", "Attribute": "Metadata", "Type": "headers.Metadata" }, - { "Header": "X-Container-Meta-Quota-Bytes", "Attribute": "BytesUsedQuota", "Type": "headers.Uint64" }, - { "Header": "X-Container-Meta-Quota-Count", "Attribute": "ObjectCountQuota", "Type": "headers.Uint64" }, - { "Header": "X-Container-Meta-Temp-URL-Key-2", "Attribute": "TempURLKey2", "Type": "headers.String" }, - { "Header": "X-Container-Meta-Temp-URL-Key", "Attribute": "TempURLKey", "Type": "headers.String" }, - { "Header": "X-Container-Object-Count", "Attribute": "ObjectCount", "Type": "headers.Uint64Readonly" }, - { "Header": "X-Container-Read", "Attribute": "ReadACL", "Type": "headers.String" }, - { "Header": "X-Container-Sync-Key", "Attribute": "SyncKey", "Type": "headers.String" }, - { "Header": "X-Container-Sync-To", "Attribute": "SyncTo", "Type": "headers.String" }, - { "Header": "X-Container-Write", "Attribute": "WriteACL", "Type": "headers.String" }, - { "Header": "X-History-Location", "Attribute": "HistoryLocation", "Type": "headers.String" }, - { "Header": "X-Storage-Policy", "Attribute": "StoragePolicy", "Type": "headers.String" }, - { "Header": "X-Timestamp", "Attribute": "Timestamp", "Type": "headers.UnixTimeReadonly" }, - { "Header": "X-Versions-Location", "Attribute": "VersionsLocation", "Type": "headers.String" } + { "Header": "X-Container-Bytes-Used", "Attribute": "BytesUsed", "Type": "Uint64Readonly" }, + { "Header": "X-Container-Meta-", "Attribute": "Metadata", "Type": "Metadata" }, + { "Header": "X-Container-Meta-Quota-Bytes", "Attribute": "BytesUsedQuota", "Type": "Uint64" }, + { "Header": "X-Container-Meta-Quota-Count", "Attribute": "ObjectCountQuota", "Type": "Uint64" }, + { "Header": "X-Container-Meta-Temp-URL-Key-2", "Attribute": "TempURLKey2", "Type": "String" }, + { "Header": "X-Container-Meta-Temp-URL-Key", "Attribute": "TempURLKey", "Type": "String" }, + { "Header": "X-Container-Object-Count", "Attribute": "ObjectCount", "Type": "Uint64Readonly" }, + { "Header": "X-Container-Read", "Attribute": "ReadACL", "Type": "String" }, + { "Header": "X-Container-Sync-Key", "Attribute": "SyncKey", "Type": "String" }, + { "Header": "X-Container-Sync-To", "Attribute": "SyncTo", "Type": "String" }, + { "Header": "X-Container-Write", "Attribute": "WriteACL", "Type": "String" }, + { "Header": "X-History-Location", "Attribute": "HistoryLocation", "Type": "String" }, + { "Header": "X-Storage-Policy", "Attribute": "StoragePolicy", "Type": "String" }, + { "Header": "X-Timestamp", "Attribute": "Timestamp", "Type": "UnixTimeReadonly" }, + { "Header": "X-Versions-Location", "Attribute": "VersionsLocation", "Type": "String" } ] } } @@ -42,18 +42,15 @@ package schwift -import ( - "net/textproto" - - "github.com/majewsky/schwift/headers" -) +import "net/textproto" {{- range $htype, $hmeta := . }} //{{$htype}}Headers contains the headers for a schwift.{{$htype}} instance. // //To read and write well-known headers, use the methods on this type. -//To read and write arbitary headers, use the methods on type Headers. +//To read and write arbitary headers, use the http.Header-like methods Get(), +//Set(), Clear(), Del(). type {{$htype}}Headers map[string]string //Clear sets the value for the specified header to the empty string. When the @@ -91,30 +88,25 @@ func (h {{$htype}}Headers) Set(key, value string) { h[textproto.CanonicalMIMEHeaderKey(key)] = value } -//Validate returns headers.MalformedHeaderError if the value of any well-known -//header does not conform to its data type. This is called automatically by -//Schwift when preparing an {{$htype}}Headers instance from a GET/HEAD response, -//so you usually do not need to do it yourself. You will get the validation error -//from the {{$htype}} method doing the request, e.g. Headers(). +//Validate returns MalformedHeaderError if the value of any well-known header +//does not conform to its data type. This is called automatically by Schwift +//when preparing an {{$htype}}Headers instance from a GET/HEAD response, so you +//usually do not need to do it yourself. You will get the validation error from +//the {{$htype}} method doing the request, e.g. Headers(). func (h {{$htype}}Headers) Validate() error { -{{- range $field := $hmeta.Fields }}{{if not (eq $field.Type "headers.String" "headers.Metadata")}} - if err := h.{{$field.Attribute}}().Validate(); err != nil { +{{- range $field := $hmeta.Fields }} + if err := h.{{$field.Attribute}}().validate(); err != nil { return err } -{{- end }}{{ end }} +{{- end }} return evadeGolintComplaint1() } {{- range $field := $hmeta.Fields }} //{{$field.Attribute}} provides type-safe access to {{$field.Header}} headers. -func (h {{$htype}}Headers) {{$field.Attribute}}() {{$field.Type}} { - return {{$field.Type}}{ - Base: headers.Base{ - H: h, - K: "{{$field.Header}}", - }, - } +func (h {{$htype}}Headers) {{$field.Attribute}}() Field{{$field.Type}} { + return Field{{$field.Type}}{h, "{{$field.Header}}"} } {{- end }} {{- end }} @@ -46,3 +46,10 @@ func headersFromHTTP(src http.Header) map[string]string { } return h } + +type headerInterface interface { + Clear(string) + Del(string) + Get(string) string + Set(string, string) +} diff --git a/headers/base.go b/headers/base.go deleted file mode 100644 index 3b5b3ec..0000000 --- a/headers/base.go +++ /dev/null @@ -1,33 +0,0 @@ -/****************************************************************************** -* -* Copyright 2018 Stefan Majewsky <majewsky@gmx.net> -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -******************************************************************************/ - -package headers - -//Base is an implementation detail. -type Base struct { - H Interface - K string -} - -//Interface is an implementation detail. -type Interface interface { - Clear(string) - Del(string) - Get(string) string - Set(string, string) -} diff --git a/headers/errors.go b/headers/errors.go deleted file mode 100644 index 6c1f5ab..0000000 --- a/headers/errors.go +++ /dev/null @@ -1,31 +0,0 @@ -/****************************************************************************** -* -* Copyright 2018 Stefan Majewsky <majewsky@gmx.net> -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -******************************************************************************/ - -package headers - -//MalformedHeaderError is generated when a response from Swift contains a -//malformed header. -type MalformedHeaderError struct { - Key string - ParseError error -} - -//Error implements the builtin/error interface. -func (e MalformedHeaderError) Error() string { - return "Bad header " + e.Key + ": " + e.ParseError.Error() -} diff --git a/headers/headers.go b/headers/headers.go deleted file mode 100644 index 33127a8..0000000 --- a/headers/headers.go +++ /dev/null @@ -1,91 +0,0 @@ -/****************************************************************************** -* -* Copyright 2018 Stefan Majewsky <majewsky@gmx.net> -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -******************************************************************************/ - -//Package headers contains helper types for the type-safe representation of -//headers on Swift accounts/containers/objects. -package headers - -import ( - "net/http" - "net/textproto" -) - -//Headers works like http.Header, but does not allow multiple values per key. -// -//If you write the map directly, without using the provided methods, you must -//normalize all keys with textproto.CanonicalMIMEHeaderKey(). Otherwise, the -//results are undefined. -type Headers map[string]string - -//Clear sets the value for the specified header to the empty string. When the -//Headers instance is then sent to the server with Update(), the server will -//delete the value for that header; cf. Del(). -func (h Headers) Clear(key string) { - h.Set(key, "") -} - -//Del deletes a key from the Headers instance. When the Headers instance -//is then sent to the server with Update(), Del() has different effects -//depending on context because of Swift's inconsistent API: -// -//For most writable attributes, a key which has been deleted with Del() will -//remain unchanged on the server. To remove the key on the server, use Clear() -//instead. -// -//For object metadata (but not other object attributes), deleting a key will -//cause that key to be deleted on the server. Del() is identical to Clear() in -//this case. -func (h Headers) Del(key string) { - k := textproto.CanonicalMIMEHeaderKey(key) - delete(h, k) -} - -//Get returns the value for the specified header. -func (h Headers) Get(key string) string { - if h == nil { - return "" - } - k := textproto.CanonicalMIMEHeaderKey(key) - return h[k] -} - -//Set sets a new value for the specified header, possibly overwriting a -//previous value. -func (h Headers) Set(key, value string) { - k := textproto.CanonicalMIMEHeaderKey(key) - h[k] = value -} - -//ToHTTP converts this map into a http.Header. -func (h Headers) ToHTTP() http.Header { - dest := make(http.Header, len(h)) - for k, v := range h { - dest.Set(k, v) - } - return dest -} - -//FromHTTP populates this map with the headers in the given http.Header. When a -//header has multiple values, every value but the first one will be discarded. -func (h Headers) FromHTTP(src http.Header) { - for k, v := range src { - if len(v) > 0 { - h.Set(k, v[0]) - } - } -} diff --git a/headers/headers_test.go b/headers/headers_test.go deleted file mode 100644 index 9724435..0000000 --- a/headers/headers_test.go +++ /dev/null @@ -1,97 +0,0 @@ -/****************************************************************************** -* -* Copyright 2018 Stefan Majewsky <majewsky@gmx.net> -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -******************************************************************************/ - -package headers - -import "testing" - -func TestHeaders(t *testing.T) { - h := make(Headers) - h.Set("first", "value1") - h.Set("second-thing", "value2") - - expectHeaders(t, h, map[string]string{ - "First": "value1", - "Second-Thing": "value2", - }) - - expectString(t, h.Get("first"), "value1") - expectString(t, h.Get("First"), "value1") - expectString(t, h.Get("FIRST"), "value1") - - h.Set("first", "changed") - h.Set("third", "") - - expectHeaders(t, h, map[string]string{ - "First": "changed", - "Second-Thing": "value2", - "Third": "", - }) - - h.Clear("second-thing") - h.Clear("fourth-thing") - - expectHeaders(t, h, map[string]string{ - "First": "changed", - "Second-Thing": "", - "Third": "", - "Fourth-Thing": "", - }) - - h.Del("FIRST") - h.Del("second-Thing") - - expectHeaders(t, h, map[string]string{ - "Third": "", - "Fourth-Thing": "", - }) - -} - -func expectString(t *testing.T, actual string, expected string) { - t.Helper() - if actual != expected { - t.Errorf("expected value %q, got %q instead\n", expected, actual) - } -} - -func expectHeaders(t *testing.T, actual Headers, expected map[string]string) { - t.Helper() - reported := make(map[string]bool) - - for k, av := range actual { - ev, exists := expected[k] - if !exists { - ev = "<not set>" - } - if av != ev { - t.Errorf(`expected "%s: %s", got "%s: %s" instead`, k, ev, k, av) - reported[k] = true - } - } - - for k, ev := range expected { - av, exists := actual[k] - if !exists { - av = "<not set>" - } - if av != ev && !reported[k] { - t.Errorf(`expected "%s: %s", got "%s: %s" instead`, k, ev, k, av) - } - } -} |
