12
12
//
13
13
//===----------------------------------------------------------------------===//
14
14
15
+ /// Error thrown from parsing URLEncoded forms
16
+ public struct URLEncodedFormError : Error , CustomStringConvertible {
17
+ public struct Code : Sendable , Equatable {
18
+ fileprivate enum Internal : Equatable {
19
+ case duplicateKeys
20
+ case addingToInvalidType
21
+ case failedToPercentDecode
22
+ case corruptKeyValue
23
+ case notSupported
24
+ case invalidArrayIndex
25
+ case unexpectedError
26
+ }
27
+ fileprivate let value : Internal
28
+
29
+ /// encoded form has duplicate keys in it
30
+ public static var duplicateKeys : Self { . init( value: . duplicateKeys) }
31
+ /// trying to add an array or dictionary value to something isnt an array of dictionary
32
+ public static var addingToInvalidType : Self { . init( value: . addingToInvalidType) }
33
+ /// failed to percent decode key or value
34
+ public static var failedToPercentDecode : Self { . init( value: . failedToPercentDecode) }
35
+ /// corrupt dictionary key in form data
36
+ public static var corruptKeyValue : Self { . init( value: . corruptKeyValue) }
37
+ /// Form structure not supported eg arrays of arrays
38
+ public static var notSupported : Self { . init( value: . notSupported) }
39
+ /// Array includes an invalid array index
40
+ public static var invalidArrayIndex : Self { . init( value: . invalidArrayIndex) }
41
+ /// Unexpected errpr
42
+ public static var unexpectedError : Self { . init( value: . unexpectedError) }
43
+ }
44
+
45
+ public let code : Code
46
+ public let value : String
47
+
48
+ init ( code: Code , value: String ) {
49
+ self . code = code
50
+ self . value = value
51
+ }
52
+
53
+ init ( code: Code , value: Substring ) {
54
+ self . code = code
55
+ self . value = . init( value)
56
+ }
57
+ }
58
+
59
+ extension URLEncodedFormError {
60
+ public var description : String {
61
+ switch self . code. value {
62
+ case . duplicateKeys: " Found duplicate keys with name ' \( self . value) ' "
63
+ case . addingToInvalidType: " Adding array or dictionary value to non array or dictionary value ' \( self . value) ' "
64
+ case . failedToPercentDecode: " Failed to percent decode ' \( self . value) ' "
65
+ case . corruptKeyValue: " Parsing dictionary key value failed ' \( self . value) ' "
66
+ case . notSupported: " URLEncoded form structure not supported ' \( self . value) ' "
67
+ case . invalidArrayIndex: " Invalid array index ' \( self . value) ' "
68
+ case . unexpectedError:
69
+ " Unexpected error with ' \( self . value) ' please add an issue at https://github.com/hummingbird-project/hummingbird/issues "
70
+ }
71
+ }
72
+ }
15
73
/// Internal representation of URL encoded form data used by both encode and decode
16
74
enum URLEncodedFormNode : CustomStringConvertible , Equatable {
17
75
/// holds a value
@@ -20,12 +78,8 @@ enum URLEncodedFormNode: CustomStringConvertible, Equatable {
20
78
case map( Map )
21
79
/// holds an array of nodes
22
80
case array( Array )
23
-
24
- enum Error : Swift . Error , Equatable {
25
- case failedToDecode( String ? = nil )
26
- case notSupported
27
- case invalidArrayIndex( Int )
28
- }
81
+ // empty node
82
+ case empty
29
83
30
84
/// Initialize node from URL encoded form data
31
85
/// - Parameter string: URL encoded form data
@@ -47,12 +101,14 @@ enum URLEncodedFormNode: CustomStringConvertible, Equatable {
47
101
let before = element [ ..< equals] . removingURLPercentEncoding ( )
48
102
let afterEquals = element. index ( after: equals)
49
103
let after = element [ afterEquals... ] . replacingOccurrences ( of: " + " , with: " " )
50
- guard let key = before else { throw Error . failedToDecode ( " Failed to percent decode \( element) " ) }
104
+ guard let key = before else { throw URLEncodedFormError ( code : . failedToPercentDecode , value : element [ ..< equals ] ) }
51
105
52
- guard let keys = KeyParser . parse ( key) else { throw Error . failedToDecode ( " Unexpected key value " ) }
53
- guard let value = NodeValue ( percentEncoded: after) else { throw Error . failedToDecode ( " Failed to percent decode \( after) " ) }
106
+ guard let keys = KeyParser . parse ( key) else { throw URLEncodedFormError ( code: . corruptKeyValue, value: key) }
107
+ guard let value = NodeValue ( percentEncoded: after) else {
108
+ throw URLEncodedFormError ( code: . failedToPercentDecode, value: after)
109
+ }
54
110
55
- try node. addValue ( keys: keys [ ... ] , value: value)
111
+ try node. addValue ( keys: keys [ ... ] , value: value, key : key )
56
112
}
57
113
}
58
114
return node
@@ -62,7 +118,7 @@ enum URLEncodedFormNode: CustomStringConvertible, Equatable {
62
118
/// - Parameters:
63
119
/// - keys: Array of key parser types (array or map)
64
120
/// - value: value to add to leaf node
65
- private func addValue( keys: ArraySlice < KeyParser . KeyType > , value: NodeValue ) throws {
121
+ private func addValue( keys: ArraySlice < KeyParser . KeyType > , value: NodeValue , key : String ) throws {
66
122
/// function for create `URLEncodedFormNode` from `KeyParser.Key.Type`
67
123
func createNode( from key: KeyParser . KeyType ) -> URLEncodedFormNode {
68
124
switch key {
@@ -81,31 +137,35 @@ enum URLEncodedFormNode: CustomStringConvertible, Equatable {
81
137
case ( . map( let map) , . map( let key) ) :
82
138
let key = String ( key)
83
139
if keys. count == 0 {
84
- guard map. values [ key] == nil else { throw Error . failedToDecode ( ) }
140
+ guard map. values [ key] == nil else { throw URLEncodedFormError ( code : . duplicateKeys , value : key ) }
85
141
map. values [ key] = . leaf( value)
86
142
} else {
87
143
if let node = map. values [ key] {
88
- try node. addValue ( keys: keys, value: value)
144
+ try node. addValue ( keys: keys, value: value, key : key )
89
145
} else {
90
146
let node = createNode ( from: keys. first!)
91
147
map. values [ key] = node
92
- try node. addValue ( keys: keys, value: value)
148
+ try node. addValue ( keys: keys, value: value, key : key )
93
149
}
94
150
}
95
151
case ( . array( let array) , . array) :
96
152
if keys. count == 0 {
97
153
array. values. append ( . leaf( value) )
98
154
} else {
99
155
// currently don't support arrays and maps inside arrays
100
- throw Error . notSupported
156
+ throw URLEncodedFormError ( code : . notSupported, value : key )
101
157
}
102
158
case ( . array( let array) , . arrayWithIndices( let index) ) :
103
159
guard keys. count == 0 , array. values. count == index else {
104
- throw Error . invalidArrayIndex ( index)
160
+ throw URLEncodedFormError ( code : . invalidArrayIndex, value : " \( key ) [ \( index) ] " )
105
161
}
106
162
array. values. append ( . leaf( value) )
163
+ case ( _, . arrayWithIndices) , ( _, . array) :
164
+ throw URLEncodedFormError ( code: . addingToInvalidType, value: key)
165
+ case ( _, . map) :
166
+ throw URLEncodedFormError ( code: . addingToInvalidType, value: key)
107
167
default :
108
- throw Error . failedToDecode ( )
168
+ throw URLEncodedFormError ( code : . unexpectedError , value : key )
109
169
}
110
170
}
111
171
@@ -130,6 +190,8 @@ enum URLEncodedFormNode: CustomStringConvertible, Equatable {
130
190
$0. value. encode ( " \( prefix) [ \( $0. key) ] " )
131
191
} . joined ( separator: " & " )
132
192
}
193
+ case . empty:
194
+ return " "
133
195
}
134
196
}
135
197
0 commit comments