http-parser 1.0.5 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,311 +1,335 @@
1
-
2
- module HttpParser
3
- HTTP_MAX_HEADER_SIZE = (80 * 1024)
4
-
5
- #
6
- # These share a byte of data as a bitmap
7
- #
8
- TYPES = enum :http_parser_type, [
9
- :request, 0,
10
- :response,
11
- :both
12
- ]
13
- FLAG = {
14
- :CHUNKED => 1 << 2,
15
- :CONNECTION_KEEP_ALIVE => 1 << 3,
16
- :CONNECTION_CLOSE => 1 << 4,
17
- :TRAILING => 1 << 5,
18
- :UPGRADE => 1 << 6,
19
- :SKIPBODY => 1 << 7
20
- }
21
-
22
- #
23
- # Request Methods
24
- #
25
- METHODS = enum :http_method, [
26
- :DELETE, 0,
27
- :GET,
28
- :HEAD,
29
- :POST,
30
- :PUT,
31
- # pathological
32
- :CONNECT,
33
- :OPTIONS,
34
- :TRACE,
35
- # webdav
36
- :COPY,
37
- :LOCK,
38
- :MKCOL,
39
- :MOVE,
40
- :PROPFIND,
41
- :PROPPATCH,
42
- :SEARCH,
43
- :UNLOCK,
44
- # subversion
45
- :REPORT,
46
- :MKACTIVITY,
47
- :CHECKOUT,
48
- :MERGE,
49
- # upnp
50
- :MSEARCH,
51
- :NOTIFY,
52
- :SUBSCRIBE,
53
- :UNSUBSCRIBE,
54
- # RFC-5789
55
- :PATCH,
56
- :PURGE
57
- ]
58
-
59
-
60
- UrlFields = enum :http_parser_url_fields, [
61
- :SCHEMA, 0,
62
- :HOST,
63
- :PORT,
64
- :PATH,
65
- :QUERY,
66
- :FRAGMENT,
67
- :USERINFO,
68
- :MAX
69
- ]
70
-
71
-
72
- #
73
- # Effectively this represents a request instance
74
- #
75
- class Instance < FFI::Struct
76
- layout :type_flags, :uchar,
77
- :state, :uchar,
78
- :header_state, :uchar,
79
- :index, :uchar,
80
-
81
- :nread, :uint32,
82
- :content_length, :int64,
83
-
84
- # READ-ONLY
85
- :http_major, :ushort,
86
- :http_minor, :ushort,
87
- :status_code, :ushort, # responses only
88
- :method, :uchar, # requests only
89
- :error_upgrade, :uchar, # errno = first 7bits, upgrade = last bit
90
-
91
- # PUBLIC
92
- :data, :pointer
93
-
94
-
95
- def initialize(ptr = nil)
96
- if ptr then super(ptr)
97
- else
98
- super()
99
- self.type = :both
100
- end
101
-
102
- yield self if block_given?
103
-
104
- ::HttpParser.http_parser_init(self, self.type) unless ptr
105
- end
106
-
107
- #
108
- # Resets the parser.
109
- #
110
- # @param [:request, :response, :both] new_type
111
- # The new type for the parser.
112
- #
113
- def reset!(new_type = type)
114
- ::HttpParser.http_parser_init(self, new_type)
115
- end
116
-
117
- #
118
- # The type of the parser.
119
- #
120
- # @return [:request, :response, :both]
121
- # The parser type.
122
- #
123
- def type
124
- TYPES[self[:type_flags] & 0x3]
125
- end
126
-
127
- #
128
- # Sets the type of the parser.
129
- #
130
- # @param [:request, :response, :both] new_type
131
- # The new parser type.
132
- #
133
- def type=(new_type)
134
- self[:type_flags] = (flags | TYPES[new_type])
135
- end
136
-
137
- #
138
- # Flags for the parser.
139
- #
140
- # @return [Integer]
141
- # Parser flags.
142
- #
143
- def flags
144
- (self[:type_flags] & 0xfc)
145
- end
146
-
147
- #
148
- # The parsed HTTP major version number.
149
- #
150
- # @return [Integer]
151
- # The HTTP major version number.
152
- #
153
- def http_major
154
- self[:http_major]
155
- end
156
-
157
- #
158
- # The parsed HTTP minor version number.
159
- #
160
- # @return [Integer]
161
- # The HTTP minor version number.
162
- #
163
- def http_minor
164
- self[:http_minor]
165
- end
166
-
167
- #
168
- # The parsed HTTP version.
169
- #
170
- # @return [String]
171
- # The HTTP version.
172
- #
173
- def http_version
174
- "%d.%d" % [self[:http_major], self[:http_minor]]
175
- end
176
-
177
- #
178
- # The parsed HTTP response Status Code.
179
- #
180
- # @return [Integer]
181
- # The HTTP Status Code.
182
- #
183
- # @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1.1
184
- #
185
- def http_status
186
- self[:status_code]
187
- end
188
-
189
- #
190
- # The parsed HTTP Method.
191
- #
192
- # @return [Symbol]
193
- # The HTTP Method name.
194
- #
195
- # @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.1
196
- #
197
- def http_method
198
- METHODS[self[:method]]
199
- end
200
-
201
- #
202
- # Determines whether the `Upgrade` header has been parsed.
203
- #
204
- # @return [Boolean]
205
- # Specifies whether the `Upgrade` header has been seen.
206
- #
207
- # @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.42
208
- #
209
- def upgrade?
210
- (self[:error_upgrade] & 0b10000000) > 0
211
- end
212
-
213
- #
214
- # Determines whether an error occurred during processing.
215
- #
216
- # @return [Boolean]
217
- # Did a parsing error occur with the request?
218
- #
219
- def error?
220
- error = (self[:error_upgrade] & 0b1111111)
221
- return error != 0
222
- end
223
-
224
- #
225
- # Returns the error that occurred during processing.
226
- #
227
- # @return [StandarError]
228
- # Returns the error that occurred.
229
- #
230
- def error
231
- error = (self[:error_upgrade] & 0b1111111)
232
- return nil if error == 0
233
-
234
- err = ::HttpParser.err_name(error)[4..-1] # HPE_ is at the start of all these errors
235
- klass = ERRORS[err.to_sym]
236
- err = "#{::HttpParser.err_desc(error)} (#{err})"
237
- return klass.nil? ? Error::UNKNOWN.new(err) : klass.new(err)
238
- end
239
-
240
- #
241
- # Additional data attached to the parser.
242
- #
243
- # @return [FFI::Pointer]
244
- # Pointer to the additional data.
245
- #
246
- def data
247
- self[:data]
248
- end
249
-
250
- #
251
- # Determines whether the `Connection: keep-alive` header has been
252
- # parsed.
253
- #
254
- # @return [Boolean]
255
- # Specifies whether the Connection should be kept alive.
256
- #
257
- # @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.10
258
- #
259
- def keep_alive?
260
- ::HttpParser.http_should_keep_alive(self) > 0
261
- end
262
-
263
- #
264
- # Halts the parser if called in a callback
265
- #
266
- def stop!
267
- throw :return, 1
268
- end
269
-
270
- #
271
- # Indicates an error has occurred when called in a callback
272
- #
273
- def error!
274
- throw :return, -1
275
- end
276
- end
277
-
278
- class FieldData < FFI::Struct
279
- layout :off, :uint16,
280
- :len, :uint16
281
- end
282
-
283
- class HttpParserUrl < FFI::Struct
284
- layout :field_set, :uint16,
285
- :port, :uint16,
286
- :field_data, [FieldData, UrlFields[:MAX]]
287
- end
288
-
289
-
290
- callback :http_data_cb, [Instance.ptr, :pointer, :size_t], :int
291
- callback :http_cb, [Instance.ptr], :int
292
-
293
-
294
- class Settings < FFI::Struct
295
- layout :on_message_begin, :http_cb,
296
- :on_url, :http_data_cb,
297
- :on_status, :http_data_cb,
298
- :on_header_field, :http_data_cb,
299
- :on_header_value, :http_data_cb,
300
- :on_headers_complete, :http_cb,
301
- :on_body, :http_data_cb,
302
- :on_message_complete, :http_cb
303
- end
304
-
305
-
306
- attach_function :http_parser_init, [Instance.by_ref, :http_parser_type], :void, :blocking => true
307
- attach_function :http_parser_execute, [Instance.by_ref, Settings.by_ref, :pointer, :size_t], :size_t, :blocking => true
308
-
309
- attach_function :http_should_keep_alive, [Instance.by_ref], :int, :blocking => true
310
- attach_function :http_method_str, [:http_method], :string, :blocking => true
311
- end
1
+ # frozen_string_literal: true
2
+
3
+ module HttpParser
4
+ HTTP_MAX_HEADER_SIZE = (80 * 1024)
5
+
6
+ #
7
+ # These share a byte of data as a bitmap
8
+ #
9
+ TYPES = enum :http_parser_type, [
10
+ :request, 0,
11
+ :response,
12
+ :both
13
+ ]
14
+ FLAG = {
15
+ :CHUNKED => 1 << 2,
16
+ :CONNECTION_KEEP_ALIVE => 1 << 3,
17
+ :CONNECTION_CLOSE => 1 << 4,
18
+ :CONNECTION_UPGRADE => 1 << 5,
19
+ :TRAILING => 1 << 6,
20
+ :UPGRADE => 1 << 7,
21
+ :SKIPBODY => 1 << 8
22
+ }
23
+
24
+ #
25
+ # Request Methods
26
+ #
27
+ METHODS = enum :http_method, [
28
+ :DELETE, 0,
29
+ :GET,
30
+ :HEAD,
31
+ :POST,
32
+ :PUT,
33
+ # pathological
34
+ :CONNECT,
35
+ :OPTIONS,
36
+ :TRACE,
37
+ # webdav
38
+ :COPY,
39
+ :LOCK,
40
+ :MKCOL,
41
+ :MOVE,
42
+ :PROPFIND,
43
+ :PROPPATCH,
44
+ :SEARCH,
45
+ :UNLOCK,
46
+ :BIND,
47
+ :REBIND,
48
+ :UNBIND,
49
+ :ACL,
50
+ # subversion
51
+ :REPORT,
52
+ :MKACTIVITY,
53
+ :CHECKOUT,
54
+ :MERGE,
55
+ # upnp
56
+ :MSEARCH,
57
+ :NOTIFY,
58
+ :SUBSCRIBE,
59
+ :UNSUBSCRIBE,
60
+ # RFC-5789
61
+ :PATCH,
62
+ :PURGE,
63
+ # CalDAV
64
+ :MKCALENDAR,
65
+ # RFC-2068, section 19.6.1.2
66
+ :LINK,
67
+ :UNLINK
68
+ ]
69
+
70
+
71
+ UrlFields = enum :http_parser_url_fields, [
72
+ :SCHEMA, 0,
73
+ :HOST,
74
+ :PORT,
75
+ :PATH,
76
+ :QUERY,
77
+ :FRAGMENT,
78
+ :USERINFO,
79
+ :MAX
80
+ ]
81
+
82
+
83
+ #
84
+ # Effectively this represents a request instance
85
+ #
86
+ class Instance < FFI::Struct
87
+ layout :type_flags, :uchar,
88
+ :state, :uchar,
89
+ :header_state, :uchar,
90
+ :index, :uchar,
91
+
92
+ :nread, :uint32,
93
+ :content_length, :uint64,
94
+
95
+ # READ-ONLY
96
+ :http_major, :ushort,
97
+ :http_minor, :ushort,
98
+ :status_code, :ushort, # responses only
99
+ :method, :uchar, # requests only
100
+ :error_upgrade, :uchar, # errno = first 7bits, upgrade = last bit
101
+
102
+ # PUBLIC
103
+ :data, :pointer
104
+
105
+
106
+ def initialize(ptr = nil)
107
+ if ptr then super(ptr)
108
+ else
109
+ super()
110
+ self.type = :both
111
+ end
112
+
113
+ yield self if block_given?
114
+
115
+ ::HttpParser.http_parser_init(self, self.type) unless ptr
116
+ end
117
+
118
+ #
119
+ # Resets the parser.
120
+ #
121
+ # @param [:request, :response, :both] new_type
122
+ # The new type for the parser.
123
+ #
124
+ def reset!(new_type = type)
125
+ ::HttpParser.http_parser_init(self, new_type)
126
+ end
127
+
128
+ #
129
+ # The type of the parser.
130
+ #
131
+ # @return [:request, :response, :both]
132
+ # The parser type.
133
+ #
134
+ def type
135
+ TYPES[self[:type_flags] & 0x3]
136
+ end
137
+
138
+ #
139
+ # Sets the type of the parser.
140
+ #
141
+ # @param [:request, :response, :both] new_type
142
+ # The new parser type.
143
+ #
144
+ def type=(new_type)
145
+ self[:type_flags] = (flags | TYPES[new_type])
146
+ end
147
+
148
+ #
149
+ # Flags for the parser.
150
+ #
151
+ # @return [Integer]
152
+ # Parser flags.
153
+ #
154
+ def flags
155
+ (self[:type_flags] & 0xfc)
156
+ end
157
+
158
+ #
159
+ # The parsed HTTP major version number.
160
+ #
161
+ # @return [Integer]
162
+ # The HTTP major version number.
163
+ #
164
+ def http_major
165
+ self[:http_major]
166
+ end
167
+
168
+ #
169
+ # The parsed HTTP minor version number.
170
+ #
171
+ # @return [Integer]
172
+ # The HTTP minor version number.
173
+ #
174
+ def http_minor
175
+ self[:http_minor]
176
+ end
177
+
178
+ #
179
+ # The parsed HTTP version.
180
+ #
181
+ # @return [String]
182
+ # The HTTP version.
183
+ #
184
+ def http_version
185
+ "%d.%d" % [self[:http_major], self[:http_minor]]
186
+ end
187
+
188
+ #
189
+ # The parsed HTTP response Status Code.
190
+ #
191
+ # @return [Integer]
192
+ # The HTTP Status Code.
193
+ #
194
+ # @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1.1
195
+ #
196
+ def http_status
197
+ self[:status_code]
198
+ end
199
+
200
+ #
201
+ # The parsed HTTP Method.
202
+ #
203
+ # @return [Symbol]
204
+ # The HTTP Method name.
205
+ #
206
+ # @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.1
207
+ #
208
+ def http_method
209
+ METHODS[self[:method]]
210
+ end
211
+
212
+ #
213
+ # Determines whether the `Upgrade` header has been parsed.
214
+ #
215
+ # @return [Boolean]
216
+ # Specifies whether the `Upgrade` header has been seen.
217
+ #
218
+ # @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.42
219
+ #
220
+ def upgrade?
221
+ (self[:error_upgrade] & 0b10000000) > 0
222
+ end
223
+
224
+ #
225
+ # Determines whether an error occurred during processing.
226
+ #
227
+ # @return [Boolean]
228
+ # Did a parsing error occur with the request?
229
+ #
230
+ def error?
231
+ error = (self[:error_upgrade] & 0b1111111)
232
+ return error != 0
233
+ end
234
+
235
+ #
236
+ # Returns the error that occurred during processing.
237
+ #
238
+ # @return [StandarError]
239
+ # Returns the error that occurred.
240
+ #
241
+ def error
242
+ error = (self[:error_upgrade] & 0b1111111)
243
+ return nil if error == 0
244
+
245
+ err = ::HttpParser.err_name(error)[4..-1] # HPE_ is at the start of all these errors
246
+ klass = ERRORS[err.to_sym]
247
+ err = "#{::HttpParser.err_desc(error)} (#{err})"
248
+ return klass.nil? ? Error::UNKNOWN.new(err) : klass.new(err)
249
+ end
250
+
251
+ #
252
+ # Additional data attached to the parser.
253
+ #
254
+ # @return [FFI::Pointer]
255
+ # Pointer to the additional data.
256
+ #
257
+ def data
258
+ self[:data]
259
+ end
260
+
261
+ #
262
+ # Determines whether the `Connection: keep-alive` header has been
263
+ # parsed.
264
+ #
265
+ # @return [Boolean]
266
+ # Specifies whether the Connection should be kept alive.
267
+ #
268
+ # @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.10
269
+ #
270
+ def keep_alive?
271
+ ::HttpParser.http_should_keep_alive(self) > 0
272
+ end
273
+
274
+ #
275
+ # Determines if a chunked response has completed
276
+ #
277
+ # @return [Boolean]
278
+ # Specifies whether the chunked response has completed
279
+ #
280
+ def final_chunk?
281
+ ::HttpParser.http_body_is_final(self) > 0
282
+ end
283
+
284
+ #
285
+ # Halts the parser if called in a callback
286
+ #
287
+ def stop!
288
+ throw :return, 1
289
+ end
290
+
291
+ #
292
+ # Indicates an error has occurred when called in a callback
293
+ #
294
+ def error!
295
+ throw :return, -1
296
+ end
297
+ end
298
+
299
+ class FieldData < FFI::Struct
300
+ layout :off, :uint16,
301
+ :len, :uint16
302
+ end
303
+
304
+ class HttpParserUrl < FFI::Struct
305
+ layout :field_set, :uint16,
306
+ :port, :uint16,
307
+ :field_data, [FieldData, UrlFields[:MAX]]
308
+ end
309
+
310
+
311
+ callback :http_data_cb, [Instance.ptr, :pointer, :size_t], :int
312
+ callback :http_cb, [Instance.ptr], :int
313
+
314
+
315
+ class Settings < FFI::Struct
316
+ layout :on_message_begin, :http_cb,
317
+ :on_url, :http_data_cb,
318
+ :on_status, :http_data_cb,
319
+ :on_header_field, :http_data_cb,
320
+ :on_header_value, :http_data_cb,
321
+ :on_headers_complete, :http_cb,
322
+ :on_body, :http_data_cb,
323
+ :on_message_complete, :http_cb,
324
+ :on_chunk_header, :http_cb,
325
+ :on_chunk_complete, :http_cb
326
+ end
327
+
328
+
329
+ attach_function :http_parser_init, [Instance.by_ref, :http_parser_type], :void
330
+ attach_function :http_parser_execute, [Instance.by_ref, Settings.by_ref, :pointer, :size_t], :size_t
331
+ attach_function :http_should_keep_alive, [Instance.by_ref], :int
332
+
333
+ # Checks if this is the final chunk of the body
334
+ attach_function :http_body_is_final, [Instance.by_ref], :int
335
+ end