aboutsummaryrefslogtreecommitdiff
path: root/errors.go
blob: 5784126fca62dcaa4c700a2021879b8b10d4c04e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/******************************************************************************
*
*  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 schwift

import (
	"errors"
	"fmt"
	"net/http"
	"strconv"
	"strings"
)

var (
	//ErrChecksumMismatch is returned by Object.Upload() when the Etag in the
	//server response does not match the uploaded data.
	ErrChecksumMismatch = errors.New("Etag on uploaded object does not match MD5 checksum of uploaded data")
	//ErrNoContainerName is returned by Request.Do() if ObjectName is given, but
	//ContainerName is empty.
	ErrNoContainerName = errors.New("missing container name")
	//ErrMalformedContainerName is returned by Request.Do() if ContainerName
	//contains slashes.
	ErrMalformedContainerName = errors.New("container name may not contain slashes")
	//ErrNotSupported is returned by bulk operations, large object operations,
	//etc. if the server does not support the requested operation.
	ErrNotSupported = errors.New("operation not supported by this Swift server")
	//ErrAccountMismatch is returned by operations on an account that accept
	//objects as arguments, if (some of) the provided objects are located in a
	//different account.
	ErrAccountMismatch = errors.New("some of the given objects are not in this account")
)

//UnexpectedStatusCodeError is generated when a request to Swift does not yield
//a response with the expected successful status code.
type UnexpectedStatusCodeError struct {
	ExpectedStatusCodes []int
	ActualResponse      *http.Response
	ResponseBody        []byte
}

//Error implements the builtin/error interface.
func (e UnexpectedStatusCodeError) Error() string {
	codeStrs := make([]string, len(e.ExpectedStatusCodes))
	for idx, code := range e.ExpectedStatusCodes {
		codeStrs[idx] = strconv.Itoa(code)
	}
	msg := fmt.Sprintf("expected %s response, got %d instead",
		strings.Join(codeStrs, "/"),
		e.ActualResponse.StatusCode,
	)
	if len(e.ResponseBody) > 0 {
		msg += ": " + string(e.ResponseBody)
	}
	return msg
}

//BulkObjectError is the error message for a single object in a bulk operation.
//It is not generated individually, only as part of BulkError.
type BulkObjectError struct {
	ContainerName string
	ObjectName    string
	StatusCode    int
}

//Error implements the builtin/error interface.
func (e BulkObjectError) Error() string {
	return fmt.Sprintf("%s/%s: %d %s",
		e.ContainerName, e.ObjectName,
		e.StatusCode, http.StatusText(e.StatusCode),
	)
}

//BulkError is returned by Account.BulkUpload() when the archive was
//uploaded and unpacked successfully, but some (or all) objects could not be
//saved in Swift; and by Account.BulkDelete() when not all requested objects
//could be deleted.
type BulkError struct {
	//StatusCode contains the overall HTTP status code of the operation.
	StatusCode int
	//OverallError contains the fatal error that aborted the bulk operation, or a
	//summary of which recoverable errors were encountered. It may be empty.
	OverallError string
	//ObjectErrors contains errors that occurred while working on individual
	//objects. It may be empty if no such errors occurred.
	ObjectErrors []BulkObjectError
}

//Error implements the builtin/error interface. To fit into one line, it
//condenses the ObjectErrors into a count.
func (e BulkError) Error() string {
	result := fmt.Sprintf("%d %s", e.StatusCode, http.StatusText(e.StatusCode))
	if e.OverallError != "" {
		result += ": " + e.OverallError
	}
	if len(e.ObjectErrors) > 0 {
		result += fmt.Sprintf(" (+%d object errors)", len(e.ObjectErrors))
	}
	return result
}

//Is checks if the given error is an UnexpectedStatusCodeError for that status
//code. For example:
//
//	err := container.Delete(nil)
//	if err != nil {
//	    if schwift.Is(err, http.StatusNotFound) {
//	        //container does not exist -> just what we wanted
//	        return nil
//	    } else {
//	        //report unexpected error
//	        return err
//	    }
//	}
func Is(err error, code int) bool {
	if e, ok := err.(UnexpectedStatusCodeError); ok {
		return e.ActualResponse.StatusCode == code
	}
	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()
}