http-parser 1.0.5 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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