Skip to content

Commit 62a31ea

Browse files
authored
Merge pull request #3 from vapor/form-data-bug
Repro: parsing multiple fields give corrupted results
2 parents 8f413a0 + 96d5cb2 commit 62a31ea

File tree

11 files changed

+132
-128
lines changed

11 files changed

+132
-128
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ Packages
22
.build
33
.DS_Store
44
*.xcodeproj
5+
Package.pins
56

Sources/FormData/ContentDispositionParser.swift

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import Core
22

3-
/**
4-
Parses `Content-Disposition` header values for
5-
form-data encoded messages.
6-
*/
3+
/// Parses `Content-Disposition` header values for
4+
/// form-data encoded messages.
75
final class ContentDispositionParser {
86
/// Key types expected in the content disposition.
97
enum Key {
@@ -29,15 +27,13 @@ final class ContentDispositionParser {
2927
self.state = .none
3028
}
3129

32-
/**
33-
Parse a stream of bytes by iterating over each byte
34-
and calling `parse()`.
35-
36-
After each byte, check the `state` of the header parser.
37-
- finished: a full key/value pair has been found.
38-
- parsingPrefix/Key/Value: the parser is currently parsing values.
39-
- none: parser has not yet received bytes.
40-
*/
30+
/// Parse a stream of bytes by iterating over each byte
31+
/// and calling `parse()`.
32+
///
33+
/// After each byte, check the `state` of the header parser.
34+
/// - finished: a full key/value pair has been found.
35+
/// - parsingPrefix/Key/Value: the parser is currently parsing values.
36+
/// - none: parser has not yet received bytes.
4137
func parse(_ byte: Byte) {
4238
main: switch state {
4339
case .none:

Sources/FormData/Field.swift

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
import Multipart
22

3-
/**
4-
A single form-data field with the field name,
5-
optional filename, and underlying Multipart.Part.
6-
7-
Headers and body reside in the Part.
8-
*/
3+
/// A single form-data field with the field name,
4+
/// optional filename, and underlying Multipart.Part.
5+
///
6+
/// Headers and body reside in the Part.
97
public struct Field {
108
public var name: String
119
public var filename: String?

Sources/FormData/Parser.swift

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@ import Core
22
import Multipart
33
import HTTP
44

5-
/**
6-
Parses form-data specific elements from
7-
multipart data parsed by an underlying multipart
8-
parser.
9-
*/
5+
/// Parses form-data specific elements from
6+
/// multipart data parsed by an underlying multipart
7+
/// parser.
108
public final class Parser {
119
/// The underlying multipart parser.
1210
/// Subscribe to preamble and epilogue events.

Sources/FormData/Serializer.swift

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import Core
22
import Multipart
33

4-
/**
5-
Creates a multipart/form-data formatted array of bytes from Fields
6-
suitable for an HTTP response or request body.
7-
*/
4+
/// Creates a multipart/form-data formatted array of bytes from Fields
5+
/// suitable for an HTTP response or request body.
86
public final class Serializer {
97

108
/// The underlying multipart serializer.
@@ -15,18 +13,16 @@ public final class Serializer {
1513
self.multipart = multipart
1614
}
1715

18-
/**
19-
This method serializes an entire Field.
20-
21-
This may be called as many times as needed.
22-
23-
After all Field have been serialized,
24-
`finish()` must be called on the multipart serializer
25-
to add the closing boundary.
26-
27-
Fields can obviously not be serialized after the
28-
epilogue has been serialized.
29-
*/
16+
/// This method serializes an entire Field.
17+
///
18+
/// This may be called as many times as needed.
19+
///
20+
/// After all Field have been serialized,
21+
/// `finish()` must be called on the multipart serializer
22+
/// to add the closing boundary.
23+
///
24+
/// Fields can obviously not be serialized after the
25+
/// epilogue has been serialized.
3026
public func serialize(_ field: Field) throws {
3127
var part = field.part
3228

Sources/Multipart/BoundaryParser.swift

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import Core
22

3-
/**
4-
Attempts to parse a supplied boundary out of a stream of bytes.
5-
6-
Pass a stream of bytes into to the parser by continually calling `parse()`.
7-
*/
3+
/// Attempts to parse a supplied boundary out of a stream of bytes.
4+
///
5+
/// Pass a stream of bytes into to the parser by continually calling `parse()`.
86
final class BoundaryParser {
97
// An enum representing all possible states the parser can be in.
108
enum State {
@@ -26,16 +24,14 @@ final class BoundaryParser {
2624
self.state = .none
2725
}
2826

29-
/**
30-
Parse a stream of bytes by iterating over each byte
31-
and calling `parse()`.
32-
33-
After each byte, check the `state` of the boundary parser.
34-
- finished: a boundary was found!
35-
- parsing: the parser may have found a boundary, do not buffer bytes.
36-
- invalid: what looked like a boundary is not. reclaim the skipped bytes.
37-
- none: no boundary detected, continue buffering the bytes.
38-
*/
27+
/// Parse a stream of bytes by iterating over each byte
28+
/// and calling `parse()`.
29+
///
30+
/// After each byte, check the `state` of the boundary parser.
31+
/// - finished: a boundary was found!
32+
/// - parsing: the parser may have found a boundary, do not buffer bytes.
33+
/// - invalid: what looked like a boundary is not. reclaim the skipped bytes.
34+
/// - none: no boundary detected, continue buffering the bytes.
3935
func parse(_ byte: Byte) throws {
4036
main: switch state {
4137
case .none:

Sources/Multipart/HeaderParser.swift

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import Core
22

3-
/**
4-
Parses headers from the top of an HTTP-style message.
5-
6-
Pass a stream of bytes into the parser by continually calling `parse()`.
7-
*/
3+
/// Parses headers from the top of an HTTP-style message.
4+
///
5+
/// Pass a stream of bytes into the parser by continually calling `parse()`.
86
final class HeaderParser {
97
// An enum representing all possible states the parser can be in.
108
enum State {
@@ -22,15 +20,13 @@ final class HeaderParser {
2220
self.state = .none
2321
}
2422

25-
/**
26-
Parse a stream of bytes by iterating over each byte
27-
and calling `parse()`.
28-
29-
After each byte, check the `state` of the header parser.
30-
- finished: a full header has been found, hold onto the key and value.
31-
- parsingKey/Value: the parser is currently gathering the header.
32-
- none: parser has not yet received bytes.
33-
*/
23+
/// Parse a stream of bytes by iterating over each byte
24+
/// and calling `parse()`.
25+
///
26+
/// After each byte, check the `state` of the header parser.
27+
/// - finished: a full header has been found, hold onto the key and value.
28+
/// - parsingKey/Value: the parser is currently gathering the header.
29+
/// - none: parser has not yet received bytes.
3430
func parse(_ byte: Byte) throws {
3531
main: switch state {
3632
case .none:

Sources/Multipart/Parser.swift

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ import Core
22
import HTTP
33
import Foundation
44

5-
/**
6-
Parses preamble, Parts, and epilogue from a Multipart
7-
formatted sequence of bytes likely from an HTTP request or response.
8-
*/
5+
/// Parses preamble, Parts, and epilogue from a Multipart
6+
/// formatted sequence of bytes likely from an HTTP request or response.
97
public final class Parser {
108
/// The multipart boundary being used.
119
public let boundary: Bytes
@@ -95,16 +93,14 @@ public final class Parser {
9593
// need to be passed around.
9694
private var buffer: Bytes
9795

98-
/**
99-
The main method for passing bytes into the parser.
100-
101-
A copy is performed to move the bytes passed into
102-
the parser's internal memory. The bytes are then
103-
iterated over one by one.
104-
105-
Callbacks will be made as the preamble, Parts, and
106-
epilogue are discovered.
107-
*/
96+
/// The main method for passing bytes into the parser.
97+
///
98+
/// A copy is performed to move the bytes passed into
99+
/// the parser's internal memory. The bytes are then
100+
/// iterated over one by one.
101+
///
102+
/// Callbacks will be made as the preamble, Parts, and
103+
/// epilogue are discovered.
108104
public func parse(_ bytes: Bytes) throws {
109105
buffer += bytes
110106

@@ -114,13 +110,11 @@ public final class Parser {
114110
}
115111
}
116112

117-
/**
118-
Call this method when there are no bytes
119-
left to parse.
120-
121-
This will trigger any parsed epilogue bytes
122-
to be returned.
123-
*/
113+
/// Call this method when there are no bytes
114+
/// left to parse.
115+
///
116+
/// This will trigger any parsed epilogue bytes
117+
/// to be returned.
124118
public func finish() throws {
125119
guard !hasFinished else {
126120
throw Error.hasAlreadyFinished
@@ -231,8 +225,9 @@ public final class Parser {
231225

232226
let raw = Array(buffer[0..<bodyEndIndex])
233227
let body = Array(raw.trimmed([.newLine, .carriageReturn]))
234-
235-
let pos = bodyEndIndex + boundarySize
228+
229+
// newline
230+
let pos = bodyEndIndex + boundarySize + 1
236231
if pos > buffer.count {
237232
buffer = []
238233
} else {

Sources/Multipart/Part.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import Core
22
import HTTP
33

4-
/**
5-
A single Multipart part with 0 or more
6-
headers and a body.
7-
*/
4+
/// A single Multipart part with 0 or more
5+
/// headers and a body.
86
public struct Part {
97
public var headers: [HeaderKey: String]
108
public var body: Bytes

Sources/Multipart/Serializer.swift

Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ import Core
22

33
private let crlf: Bytes = [.carriageReturn, .newLine]
44

5-
/**
6-
Creates a multipart formatted array of bytes from Parts
7-
suitable for an HTTP response or request body.
8-
*/
5+
/// Creates a multipart formatted array of bytes from Parts
6+
/// suitable for an HTTP response or request body.
97
public final class Serializer {
108
/// The multipart boundary being used.
119
public let boundary: Bytes
@@ -28,15 +26,13 @@ public final class Serializer {
2826
case epilogueAlreadySerialized
2927
}
3028

31-
/**
32-
Call this method to add bytes to the preamble.
33-
34-
This is equivalent to simply prepending bytes
35-
to the beginning of the serialized data.
36-
37-
Preamble can obviously not be serialized after
38-
parts or the epilogue have been serialized.
39-
*/
29+
/// Call this method to add bytes to the preamble.
30+
///
31+
/// This is equivalent to simply prepending bytes
32+
/// to the beginning of the serialized data.
33+
///
34+
/// Preamble can obviously not be serialized after
35+
/// parts or the epilogue have been serialized.
4036
public func serialize(preamble: Bytes) throws {
4137
guard !partsSerialized else {
4238
throw Error.partsAlreadySerialized
@@ -45,17 +41,15 @@ public final class Serializer {
4541
serialize(preamble)
4642
}
4743

48-
/**
49-
This method serializes an entire Part.
50-
51-
This may be called as many times as needed.
52-
53-
After all Parts have been serialized,
54-
`finish()` must be called to add the closing boundary.
55-
56-
Parts can obviously not be serialized after the
57-
epilogue has been serialized.
58-
*/
44+
/// This method serializes an entire Part.
45+
///
46+
/// This may be called as many times as needed.
47+
///
48+
/// After all Parts have been serialized,
49+
/// `finish()` must be called to add the closing boundary.
50+
///
51+
/// Parts can obviously not be serialized after the
52+
/// epilogue has been serialized.
5953
public func serialize(_ part: Part) throws {
6054
guard !epilogueSerialized else {
6155
throw Error.epilogueAlreadySerialized
@@ -79,14 +73,12 @@ public final class Serializer {
7973
partsSerialized = true
8074
}
8175

82-
/**
83-
This method serializes the closing boundary.
84-
85-
No parts or preamble can be serialized after this
86-
method is called.
87-
88-
This method must be called to complete the serialized data.
89-
*/
76+
/// This method serializes the closing boundary.
77+
///
78+
/// No parts or preamble can be serialized after this
79+
/// method is called.
80+
///
81+
/// This method must be called to complete the serialized data.
9082
public func finish(epilogue: Bytes = []) throws {
9183
guard !epilogueSerialized else {
9284
throw Error.epilogueAlreadySerialized

0 commit comments

Comments
 (0)