Skip to content

Commit 333b862

Browse files
authored
Merge pull request #69 from arangodb/response-header
Adding Response.Header(string) & tests
2 parents 61eebff + c740258 commit 333b862

File tree

8 files changed

+140
-2
lines changed

8 files changed

+140
-2
lines changed

connection.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ type Response interface {
9191
// If so, nil is returned.
9292
// If not, an attempt is made to parse an error response in the body and an error is returned.
9393
CheckStatus(validStatusCodes ...int) error
94+
// Header returns the value of a response header with given key.
95+
// If no such header is found, an empty string is returned.
96+
// On nested Response's, this function will always return an empty string.
97+
Header(key string) string
9498
// ParseBody performs protocol specific unmarshalling of the response data into the given result.
9599
// If the given field is non-empty, the contents of that field will be parsed into the given result.
96100
// This can only be used for requests that return a single object.

http/response_json.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ func (r *httpJSONResponse) CheckStatus(validStatusCodes ...int) error {
7777
}
7878
}
7979

80+
// Header returns the value of a response header with given key.
81+
// If no such header is found, an empty string is returned.
82+
func (r *httpJSONResponse) Header(key string) string {
83+
return r.resp.Header.Get(key)
84+
}
85+
8086
// ParseBody performs protocol specific unmarshalling of the response data into the given result.
8187
// If the given field is non-empty, the contents of that field will be parsed into the given result.
8288
func (r *httpJSONResponse) ParseBody(field string, result interface{}) error {

http/response_json_element.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ func (r *httpJSONResponseElement) CheckStatus(validStatusCodes ...int) error {
8989
}
9090
}
9191

92+
// Header returns the value of a response header with given key.
93+
// If no such header is found, an empty string is returned.
94+
func (r *httpJSONResponseElement) Header(key string) string {
95+
return ""
96+
}
97+
9298
// ParseBody performs protocol specific unmarshalling of the response data into the given result.
9399
// If the given field is non-empty, the contents of that field will be parsed into the given result.
94100
func (r *httpJSONResponseElement) ParseBody(field string, result interface{}) error {

http/response_vpack.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ func (r *httpVPackResponse) CheckStatus(validStatusCodes ...int) error {
7575
}
7676
}
7777

78+
// Header returns the value of a response header with given key.
79+
// If no such header is found, an empty string is returned.
80+
func (r *httpVPackResponse) Header(key string) string {
81+
return r.resp.Header.Get(key)
82+
}
83+
7884
// ParseBody performs protocol specific unmarshalling of the response data into the given result.
7985
// If the given field is non-empty, the contents of that field will be parsed into the given result.
8086
func (r *httpVPackResponse) ParseBody(field string, result interface{}) error {

http/response_vpack_element.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ func (r *httpVPackResponseElement) CheckStatus(validStatusCodes ...int) error {
8787
}
8888
}
8989

90+
// Header returns the value of a response header with given key.
91+
// If no such header is found, an empty string is returned.
92+
func (r *httpVPackResponseElement) Header(key string) string {
93+
return ""
94+
}
95+
9096
// ParseBody performs protocol specific unmarshalling of the response data into the given result.
9197
// If the given field is non-empty, the contents of that field will be parsed into the given result.
9298
func (r *httpVPackResponseElement) ParseBody(field string, result interface{}) error {

test/client_test.go

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"crypto/tls"
2828
httplib "net/http"
2929
"os"
30+
"strconv"
3031
"strings"
3132
"sync"
3233
"testing"
@@ -163,7 +164,7 @@ func createClientFromEnv(t testEnv, waitUntilReady bool, connection ...*driver.C
163164
t.Fatalf("Failed to create new client: %s", describe(err))
164165
}
165166
if waitUntilReady {
166-
timeout := 3*time.Minute
167+
timeout := 3 * time.Minute
167168
ctx, cancel := context.WithTimeout(context.Background(), timeout)
168169
defer cancel()
169170
if up := waitUntilServerAvailable(ctx, c, t); !up {
@@ -244,7 +245,7 @@ func TestCreateClientHttpConnectionCustomTransport(t *testing.T) {
244245
if err != nil {
245246
t.Fatalf("Failed to create new client: %s", describe(err))
246247
}
247-
timeout := 3*time.Minute
248+
timeout := 3 * time.Minute
248249
ctx, cancel := context.WithTimeout(context.Background(), timeout)
249250
defer cancel()
250251
if up := waitUntilServerAvailable(ctx, c, t); !up {
@@ -256,3 +257,45 @@ func TestCreateClientHttpConnectionCustomTransport(t *testing.T) {
256257
t.Logf("Got server version %s", info)
257258
}
258259
}
260+
261+
// TestResponseHeader checks the Response.Header function.
262+
func TestResponseHeader(t *testing.T) {
263+
c := createClientFromEnv(t, true)
264+
ctx := context.Background()
265+
266+
version, err := c.Version(nil)
267+
if err != nil {
268+
t.Fatalf("Version failed: %s", describe(err))
269+
}
270+
isv33p := version.Version.CompareTo("3.3") >= 0
271+
if !isv33p {
272+
t.Skip("This test requires version 3.3")
273+
} else {
274+
var resp driver.Response
275+
db := ensureDatabase(ctx, c, "_system", nil, t)
276+
col := ensureCollection(ctx, db, "response_header_test", nil, t)
277+
278+
// `ETag` header must contain the `_rev` of the new document in quotes.
279+
doc := map[string]string{
280+
"Test": "TestResponseHeader",
281+
"Intent": "Check Response.Header",
282+
}
283+
meta, err := col.CreateDocument(driver.WithResponse(ctx, &resp), doc)
284+
if err != nil {
285+
t.Fatalf("CreateDocument failed: %s", describe(err))
286+
}
287+
expectedETag := strconv.Quote(meta.Rev)
288+
if x := resp.Header("ETag"); x != expectedETag {
289+
t.Errorf("Unexpected result from Header('ETag'), got '%s', expected '%s'", x, expectedETag)
290+
}
291+
if x := resp.Header("Etag"); x != expectedETag {
292+
t.Errorf("Unexpected result from Header('Etag'), got '%s', expected '%s'", x, expectedETag)
293+
}
294+
if x := resp.Header("etag"); x != expectedETag {
295+
t.Errorf("Unexpected result from Header('etag'), got '%s', expected '%s'", x, expectedETag)
296+
}
297+
if x := resp.Header("ETAG"); x != expectedETag {
298+
t.Errorf("Unexpected result from Header('ETAG'), got '%s', expected '%s'", x, expectedETag)
299+
}
300+
}
301+
}

vst/response.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ package vst
2424

2525
import (
2626
"fmt"
27+
"strings"
28+
"sync"
2729

2830
driver "github.com/arangodb/go-driver"
2931
"github.com/arangodb/go-driver/vst/protocol"
@@ -36,6 +38,9 @@ type vstResponse struct {
3638
Version int
3739
Type int
3840
ResponseCode int
41+
meta velocypack.Slice
42+
metaMutex sync.Mutex
43+
metaMap map[string]string
3944
slice velocypack.Slice
4045
bodyArray []driver.Response
4146
}
@@ -48,10 +53,13 @@ func newResponse(msg protocol.Message, endpoint string, rawResponse *[]byte) (*v
4853
return nil, driver.WithStack(err)
4954
}
5055
//panic("hdr: " + hex.EncodeToString(hdr))
56+
var hdrLen velocypack.ValueLength
5157
if l, err := hdr.Length(); err != nil {
5258
return nil, driver.WithStack(err)
5359
} else if l < 3 {
5460
return nil, driver.WithStack(fmt.Errorf("Expected a header of 3 elements, got %d", l))
61+
} else {
62+
hdrLen = l
5563
}
5664

5765
resp := &vstResponse{
@@ -81,6 +89,16 @@ func newResponse(msg protocol.Message, endpoint string, rawResponse *[]byte) (*v
8189
} else {
8290
resp.ResponseCode = int(code)
8391
}
92+
// Decode meta
93+
if hdrLen >= 4 {
94+
if elem, err := hdr.At(3); err != nil {
95+
return nil, driver.WithStack(err)
96+
} else if !elem.IsObject() {
97+
return nil, driver.WithStack(fmt.Errorf("Expected meta field to be of type Object, got %s", elem.Type()))
98+
} else {
99+
resp.meta = elem
100+
}
101+
}
84102

85103
// Fetch body directly after hdr
86104
if body, err := hdr.Next(); err != nil {
@@ -130,6 +148,49 @@ func (r *vstResponse) CheckStatus(validStatusCodes ...int) error {
130148
}
131149
}
132150

151+
// Header returns the value of a response header with given key.
152+
// If no such header is found, an empty string is returned.
153+
func (r *vstResponse) Header(key string) string {
154+
r.metaMutex.Lock()
155+
defer r.metaMutex.Unlock()
156+
157+
if r.meta != nil {
158+
if r.metaMap == nil {
159+
// Read all headers
160+
metaMap := make(map[string]string)
161+
keyCount, err := r.meta.Length()
162+
if err != nil {
163+
return ""
164+
}
165+
for k := velocypack.ValueLength(0); k < keyCount; k++ {
166+
key, err := r.meta.KeyAt(k)
167+
if err != nil {
168+
continue
169+
}
170+
value, err := r.meta.ValueAt(k)
171+
if err != nil {
172+
continue
173+
}
174+
keyStr, err := key.GetString()
175+
if err != nil {
176+
continue
177+
}
178+
valueStr, err := value.GetString()
179+
if err != nil {
180+
continue
181+
}
182+
metaMap[strings.ToLower(keyStr)] = valueStr
183+
}
184+
r.metaMap = metaMap
185+
}
186+
key = strings.ToLower(key)
187+
if value, found := r.metaMap[key]; found {
188+
return value
189+
}
190+
}
191+
return ""
192+
}
193+
133194
// ParseBody performs protocol specific unmarshalling of the response data into the given result.
134195
// If the given field is non-empty, the contents of that field will be parsed into the given result.
135196
func (r *vstResponse) ParseBody(field string, result interface{}) error {

vst/response_element.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ func (r *vstResponseElement) CheckStatus(validStatusCodes ...int) error {
8787
}
8888
}
8989

90+
// Header returns the value of a response header with given key.
91+
// If no such header is found, an empty string is returned.
92+
func (r *vstResponseElement) Header(key string) string {
93+
return ""
94+
}
95+
9096
// ParseBody performs protocol specific unmarshalling of the response data into the given result.
9197
// If the given field is non-empty, the contents of that field will be parsed into the given result.
9298
func (r *vstResponseElement) ParseBody(field string, result interface{}) error {

0 commit comments

Comments
 (0)