landline 0.12.1 → 0.13.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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/STRUCTURE.md +129 -0
- data/lib/landline/dsl/methods_common.rb +10 -7
- data/lib/landline/extensions/session.rb +1 -1
- data/lib/landline/extensions/websocket.rb +80 -82
- data/lib/landline/path.rb +24 -5
- data/lib/landline/pattern_matching.rb +10 -2
- data/lib/landline/server.rb +2 -2
- data/lib/landline/util/cookie.rb +2 -0
- data/lib/landline/util/lookup.rb +1 -1
- data/lib/landline/util/multipart.rb +1 -1
- data/lib/landline/util/parseutils.rb +8 -4
- data/lib/landline.rb +2 -2
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 290ba72a21e71891ae33e361aea7afcff00d98429f96b303e061158c3bd34520
|
4
|
+
data.tar.gz: 545debbdab28e39eaa6f94e588bfcf371259cbcd6e33399517d7c3d3bd4393da
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e0b7da7816dcfba10f2e3db537344b6057ca7377da5a6a9e3b8aa4892883d417339cce001935705ebf60816eb9a2965501de5adae111235e79c551b0ede6f5a
|
7
|
+
data.tar.gz: 2177431dd21d534a1936541f287647bb23ced5968bada8b7a642b44f5d21c16f4cc4690654a11ee6194d62dc7027511a819c69ab123ce81d562ee166cf20157f
|
data/README.md
CHANGED
@@ -194,7 +194,7 @@ For things to render correctly, please install the `redcarpet` gem.
|
|
194
194
|
|
195
195
|
```plain
|
196
196
|
Landline - an HTTP request pattern matching system
|
197
|
-
Copyright (C)
|
197
|
+
Copyright (C) 2023-2024 yessiest (yessiest@text.512mb.org)
|
198
198
|
|
199
199
|
This program is free software: you can redistribute it and/or modify
|
200
200
|
it under the terms of the GNU General Public License as published by
|
data/STRUCTURE.md
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
# Landline library and application structure
|
2
|
+
|
3
|
+
## File layout
|
4
|
+
|
5
|
+
- `/landline/lib/*.rb` - core of the library
|
6
|
+
- `/landline/lib/dsl/` - module namespaces for use by executable contexts
|
7
|
+
- `/landline/lib/path/` - nodes that extend the Path class (traversable
|
8
|
+
node/setup execution context)
|
9
|
+
- `/landline/lib/probe/` - nodes that extend the Probe class (executable
|
10
|
+
nodes/per-request execution context)
|
11
|
+
- `/landline/lib/template/` - template engine adapters
|
12
|
+
- `/landline/lib/util/` - utility classes and modules
|
13
|
+
- `/landline/lib/pattern_matching/` - classes that implement path pattern
|
14
|
+
matching (i.e. globs, regex and static traversal paths)
|
15
|
+
|
16
|
+
## Architecture overview
|
17
|
+
|
18
|
+
The following chapter defines information that pertains to the overall
|
19
|
+
structure and interaction of landline's core abstractions - Nodes, Paths
|
20
|
+
and Probes.
|
21
|
+
|
22
|
+
For context: Node is an element of the path tree, and is another name for a
|
23
|
+
Probe (which is a leaf of the tree) or a path (which is an internal vertex
|
24
|
+
of the tree)
|
25
|
+
|
26
|
+
```plaintext
|
27
|
+
Path +-> Path +-> Probe
|
28
|
+
| |
|
29
|
+
| +-> Probe
|
30
|
+
+-> Probe
|
31
|
+
|
|
32
|
+
|-> Path -> Probe
|
33
|
+
```
|
34
|
+
|
35
|
+
### Execution contexts
|
36
|
+
|
37
|
+
In Sinatra, which this library takes most of its influence from, every
|
38
|
+
request creates its own instance of the Sinatra application. This seemed
|
39
|
+
like an excessive measure to solve a trivial problem of race conditions on a
|
40
|
+
shared execution context, so to solve that, Landline introduces per-request
|
41
|
+
execution contexts, which have a life time that spans the duration of
|
42
|
+
request processing.
|
43
|
+
|
44
|
+
In short, there are two distinct execution contexts:
|
45
|
+
|
46
|
+
- Per-request execution context, which is used by blocks that process the
|
47
|
+
request and which is bound to that given request
|
48
|
+
- Setup execution context, in which the Landline node tree is constructed
|
49
|
+
|
50
|
+
For every Path-like node, the supplied block is executed in the setup
|
51
|
+
context bound to that path.
|
52
|
+
|
53
|
+
For every Probe-like node, the supplied block is executed in the per-request
|
54
|
+
context of the request that is passed to the probe.
|
55
|
+
|
56
|
+
These execution contexts also affect the receivers of the instance variable
|
57
|
+
write and read operations. Additionally, the two types have different
|
58
|
+
sets of available methods, and every DSL method has a description attached
|
59
|
+
which describes in which context that method can be used (this is due to the
|
60
|
+
limitations of the YARD parser and due to the need of showing method
|
61
|
+
descriptions in the IDE)
|
62
|
+
|
63
|
+
### Request traversal
|
64
|
+
|
65
|
+
Requests in Landline traverse through a series of paths that determine
|
66
|
+
which route the request would take. All nodes are organized in a tree
|
67
|
+
structure, where the root of the tree is a Server object that handles
|
68
|
+
things likes localized jumps, request/response conversion and response
|
69
|
+
finalization, and root-level error/`die()` handling.
|
70
|
+
|
71
|
+
Every path-like node can be supplied with callbacks that perform
|
72
|
+
the following functions:
|
73
|
+
|
74
|
+
- filters - callbacks that filter incoming request objects
|
75
|
+
- preprocessors - callbacks that don't usually affect the routing decision
|
76
|
+
but can modify requests before they come through
|
77
|
+
- postprocessors - callbacks that execute either when a request exits a
|
78
|
+
given path after not finding any suitable probe-like node or when a
|
79
|
+
response to a request is being finalized
|
80
|
+
- pipeline - single callback that is injected in the execution stack that
|
81
|
+
can be used to catch throws and exceptions
|
82
|
+
|
83
|
+
(see `/examples/logging.ru`, `/examples/norxondor_gorgonax/config.ru`)
|
84
|
+
|
85
|
+
The execution contexts for every callback (except pipeline) are shared with
|
86
|
+
those of the probe-like execution contexts, meaning that an instance
|
87
|
+
variable written to in a filter or a preprocessor can be accessed from the
|
88
|
+
probe node or a postprocessor callback.
|
89
|
+
|
90
|
+
Once all preprocessors and filters are finished successfully, the request
|
91
|
+
is passed to all subsequent graph elements (either other Paths or Probes)
|
92
|
+
to check whether a given Node accepts that element.
|
93
|
+
|
94
|
+
If the subtree of the path contains at least one probe that accepts the
|
95
|
+
request, that probe finishes processing the request and either exits
|
96
|
+
the tree immediately by throwing the `:finish` signal with a response
|
97
|
+
or by returning a valid (not nil) response from the `process` method,
|
98
|
+
in which case the response ascends from the probe back to the root.
|
99
|
+
|
100
|
+
If none of the subsequent elements of a path accepted the request, the
|
101
|
+
path executes `die(404)` if `bounce` is not enabled, and if `bounce` is
|
102
|
+
enabled, the request exits from the path and proceeds to sibling
|
103
|
+
(adjacent) paths. (see `/examples/dirbounce.ru`)
|
104
|
+
|
105
|
+
A probe can finish the request by either throwing a response, by executing a
|
106
|
+
jump to another path, by explicitly dying with a status code or by throwing
|
107
|
+
an exception (which effectively causes `die(500)`)
|
108
|
+
(see `/examples/errorpages.ru`, `/examples/jumps.ru`)
|
109
|
+
|
110
|
+
If a jump is executed, the path of the request is rewritten locally, and the
|
111
|
+
request is fed through the server again for processing. This is effectively
|
112
|
+
a localized redirect which retains accumulated request processing
|
113
|
+
information (i.e. instance variables)
|
114
|
+
(see `/examples/jumps.ru`)
|
115
|
+
|
116
|
+
The tree can be changed at runtime, but it's generally not advisable to
|
117
|
+
depend on that fact. If, eventually, some solution will be found to
|
118
|
+
optimizing trees into linear routing paths, and if that solution is proven
|
119
|
+
to improve performance, this statement might become false.
|
120
|
+
|
121
|
+
```plaintext
|
122
|
+
+--------------------------------------+
|
123
|
+
v |
|
124
|
+
run (obj) -> App#call -> Server#call +-> Path#go -> ... -> Probe#go +
|
125
|
+
| | (if app acts as a wrapper for another
|
126
|
+
<-----------------------+ | Rack server and if response is 404
|
127
|
+
(returns back to Rack server | with x-cascade header set)
|
128
|
+
if no jumps occured) +-> passthrough#call
|
129
|
+
```
|
@@ -9,14 +9,17 @@ module Landline
|
|
9
9
|
# @param errorcode [Integer]
|
10
10
|
# @param backtrace [Array(String), nil]
|
11
11
|
# @raise [UncaughtThrowError] throws :finish to return back to Server
|
12
|
-
def die(errorcode, backtrace: nil)
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
12
|
+
def die(errorcode, backtrace: nil, error: nil)
|
13
|
+
response = Landline::Response.convert(
|
14
|
+
(@origin.properties["handle.#{errorcode}"] or
|
15
|
+
@origin.properties["handle.default"]).call(
|
16
|
+
errorcode,
|
17
|
+
backtrace: backtrace,
|
18
|
+
error: error
|
19
|
+
)
|
19
20
|
)
|
21
|
+
response.status = errorcode if response.status == 200
|
22
|
+
throw :finish, response
|
20
23
|
end
|
21
24
|
|
22
25
|
# (in Landline::Probe context)
|
@@ -24,28 +24,6 @@ module Landline
|
|
24
24
|
@__listeners[event]&.delete(listener)
|
25
25
|
end
|
26
26
|
|
27
|
-
# Await for an event
|
28
|
-
# @param event [Symbol, Array<Symbol>] event or array of events to wait for
|
29
|
-
# @return [Array]
|
30
|
-
# @sg-ignore
|
31
|
-
def await(event)
|
32
|
-
blocking = true
|
33
|
-
output = nil
|
34
|
-
listener = proc do |*data|
|
35
|
-
output = data
|
36
|
-
blocking = false
|
37
|
-
end
|
38
|
-
if event.is_a? Array
|
39
|
-
event.each { |x| on(x, &listener) }
|
40
|
-
else
|
41
|
-
on(event, &listener)
|
42
|
-
end
|
43
|
-
while blocking; end
|
44
|
-
return output[0] if output.is_a? Array and output.length == 1
|
45
|
-
|
46
|
-
output
|
47
|
-
end
|
48
|
-
|
49
27
|
private
|
50
28
|
|
51
29
|
# Trigger the queue clearing process
|
@@ -95,19 +73,6 @@ module Landline
|
|
95
73
|
)
|
96
74
|
@readable = true
|
97
75
|
@writable = true
|
98
|
-
@data = Queue.new
|
99
|
-
on :message do |msg|
|
100
|
-
@data.enq(msg)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
# Start the main loop for the eventifier
|
105
|
-
# @return [void]
|
106
|
-
def ready
|
107
|
-
return if @ready
|
108
|
-
|
109
|
-
_loop
|
110
|
-
@ready = true
|
111
76
|
end
|
112
77
|
|
113
78
|
# Send data through websocket
|
@@ -125,31 +90,33 @@ module Landline
|
|
125
90
|
type: type
|
126
91
|
)
|
127
92
|
@io.write(frame.to_s)
|
93
|
+
rescue Errno::EPIPE => e
|
94
|
+
@writable = false
|
95
|
+
_emit :error, e
|
96
|
+
close if @readable
|
97
|
+
nil
|
128
98
|
end
|
129
99
|
|
130
100
|
# Read data from socket synchronously
|
131
|
-
# @return [
|
101
|
+
# @return [WebSocket::Frame::Base, nil] nil if socket received a close event
|
132
102
|
def read
|
133
103
|
unless @readable
|
134
104
|
raise self.class::WebSocketError,
|
135
105
|
"socket closed for reading"
|
136
106
|
end
|
137
107
|
|
138
|
-
|
108
|
+
_process_events(proc { _read })
|
139
109
|
end
|
140
110
|
|
141
|
-
#
|
142
|
-
# @return [
|
143
|
-
def
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
111
|
+
# Read data from socket without blocking
|
112
|
+
# @return [WebSocket::Frame::Base, nil] nil if socket received a close event
|
113
|
+
def read_nonblock
|
114
|
+
unless @readable
|
115
|
+
raise self.class::WebSocketError,
|
116
|
+
"socket closed for reading"
|
117
|
+
end
|
148
118
|
|
149
|
-
|
150
|
-
def close_write
|
151
|
-
@writable = false
|
152
|
-
@io.close_write
|
119
|
+
_process_events(proc { _read_nonblock })
|
153
120
|
end
|
154
121
|
|
155
122
|
# Establish a connection through handshake
|
@@ -179,58 +146,88 @@ module Landline
|
|
179
146
|
handshake
|
180
147
|
end
|
181
148
|
|
182
|
-
# Close
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
149
|
+
# Close socket for reading
|
150
|
+
def close_read
|
151
|
+
raise WebSocketError, 'socket closed for reading' unless @readable
|
152
|
+
|
153
|
+
_emit :close
|
187
154
|
@readable = false
|
155
|
+
@io.close_read
|
156
|
+
end
|
157
|
+
|
158
|
+
# Close socket for reading
|
159
|
+
def close_write
|
160
|
+
raise WebSocketError, 'socket closed for writing' unless @writable
|
161
|
+
|
162
|
+
write(nil, type: :close)
|
163
|
+
@writable = false
|
164
|
+
@io.close_write
|
165
|
+
end
|
166
|
+
|
167
|
+
# Close the socket entirely
|
168
|
+
def close
|
169
|
+
raise WebSocketError, 'socket closed' unless @writable or @readable
|
170
|
+
|
171
|
+
close_read if @readable
|
172
|
+
close_write if @writable
|
188
173
|
end
|
189
174
|
|
175
|
+
# Obtain internal IO object
|
176
|
+
# @return [IO]
|
177
|
+
def to_io
|
178
|
+
io
|
179
|
+
end
|
180
|
+
|
181
|
+
attr_reader :io, :readable, :writable
|
182
|
+
|
190
183
|
private
|
191
184
|
|
192
|
-
#
|
193
|
-
# @
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
185
|
+
# Process incoming websocket events
|
186
|
+
# @param next_frame [#call] callback to get the next frame
|
187
|
+
# @return [WebSocket::Frame::Base, nil]
|
188
|
+
def _process_events(next_frame)
|
189
|
+
loop do
|
190
|
+
frame = next_frame.call
|
191
|
+
return nil unless frame
|
192
|
+
|
193
|
+
case frame.type
|
194
|
+
when :binary, :text, :pong then return frame
|
195
|
+
when :ping
|
196
|
+
write frame.to_s, type: :pong
|
197
|
+
when :close
|
198
|
+
close_read
|
199
|
+
return nil
|
200
|
+
else raise WebSocketError, "unknown frame type #{frame.type}"
|
204
201
|
end
|
205
|
-
rescue IOError => e
|
206
|
-
@writable = false
|
207
|
-
_emit :error, e
|
208
|
-
close
|
209
|
-
ensure
|
210
|
-
close_read
|
211
202
|
end
|
212
203
|
end
|
213
204
|
|
214
205
|
# Receive data through websocket
|
215
206
|
# @return [String] output from frame
|
216
207
|
def _read
|
217
|
-
while (char = @io.
|
208
|
+
while (char = @io.read(1))
|
218
209
|
@frame_parser << char
|
219
210
|
frame = @frame_parser.next
|
220
211
|
return frame if frame
|
221
212
|
end
|
213
|
+
rescue Errno::ECONNRESET => e
|
214
|
+
_emit :error, e
|
215
|
+
close if @readable or @writable
|
216
|
+
nil
|
222
217
|
end
|
223
218
|
|
224
|
-
#
|
225
|
-
# @return [
|
226
|
-
def
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
219
|
+
# Receive data through websocket asynchronously
|
220
|
+
# @return [String] output from frame
|
221
|
+
def _read_nonblock
|
222
|
+
while (char = @io.read_nonblock(1))
|
223
|
+
@frame_parser << char
|
224
|
+
frame = @frame_parser.next
|
225
|
+
return frame if frame
|
226
|
+
end
|
227
|
+
rescue Errno::ECONNRESET => e
|
228
|
+
_emit :error, e
|
229
|
+
close if @readable or @writable
|
230
|
+
nil
|
234
231
|
end
|
235
232
|
end
|
236
233
|
end
|
@@ -267,6 +264,7 @@ module Landline
|
|
267
264
|
**@params
|
268
265
|
)
|
269
266
|
)
|
267
|
+
""
|
270
268
|
end
|
271
269
|
end
|
272
270
|
end
|
data/lib/landline/path.rb
CHANGED
@@ -37,6 +37,24 @@ module Landline
|
|
37
37
|
context.instance_exec(&setup)
|
38
38
|
end
|
39
39
|
|
40
|
+
# (see ::Landline::Node#go)
|
41
|
+
def go(request)
|
42
|
+
# This is done to allow pipeline to interject handlers
|
43
|
+
# I'm more than willing to admit that this is stupid,
|
44
|
+
# but it is well worth the logical flexibility.
|
45
|
+
if ['handle.default', 'handle.505'].any? do |x|
|
46
|
+
@properties.storage.include? x
|
47
|
+
end
|
48
|
+
begin
|
49
|
+
super(request)
|
50
|
+
rescue StandardError => e
|
51
|
+
_die(request, 500, backtrace: [e.to_s] + e.backtrace, error: e)
|
52
|
+
end
|
53
|
+
else
|
54
|
+
super(request)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
40
58
|
# Method callback on successful request navigation.
|
41
59
|
# Finds the next appropriate path to go to.
|
42
60
|
# @return [Boolean] true if further navigation will be done
|
@@ -138,8 +156,6 @@ module Landline
|
|
138
156
|
return exit_stack(request, value) if value
|
139
157
|
|
140
158
|
notfound(request)
|
141
|
-
rescue StandardError => e
|
142
|
-
_die(request, 500, backtrace: [e.to_s] + e.backtrace)
|
143
159
|
end
|
144
160
|
|
145
161
|
# Run enqueued postprocessors on navigation failure
|
@@ -175,16 +191,19 @@ module Landline
|
|
175
191
|
# @param errorcode [Integer]
|
176
192
|
# @param backtrace [Array(String), nil]
|
177
193
|
# @raise [UncaughtThrowError] throws :finish to stop processing
|
178
|
-
def _die(request, errorcode, backtrace: nil)
|
194
|
+
def _die(request, errorcode, backtrace: nil, error: nil)
|
179
195
|
proccontext = get_context(request)
|
180
|
-
|
181
|
-
|
196
|
+
response = Landline::Response.convert(
|
197
|
+
proccontext.instance_exec(
|
182
198
|
errorcode,
|
183
199
|
backtrace: backtrace,
|
200
|
+
error: error,
|
184
201
|
&(@properties["handle.#{errorcode}"] or
|
185
202
|
@properties["handle.default"])
|
186
203
|
)
|
187
204
|
)
|
205
|
+
response.status = errorcode if response.status == 200
|
206
|
+
throw :finish, response
|
188
207
|
end
|
189
208
|
end
|
190
209
|
end
|
@@ -35,7 +35,7 @@ module Landline
|
|
35
35
|
def match(input)
|
36
36
|
if @pattern.is_a? String
|
37
37
|
input = Landline::PatternMatching.canonicalize(input)
|
38
|
-
if
|
38
|
+
if _match?(input)
|
39
39
|
[input.delete_prefix(@pattern), [], {}]
|
40
40
|
else
|
41
41
|
false
|
@@ -51,7 +51,8 @@ module Landline
|
|
51
51
|
# @return [Boolean]
|
52
52
|
def match?(input)
|
53
53
|
if @pattern.is_a? String
|
54
|
-
Landline::PatternMatching.canonicalize(input)
|
54
|
+
input = Landline::PatternMatching.canonicalize(input)
|
55
|
+
_match?(input)
|
55
56
|
else
|
56
57
|
@pattern.match?(input)
|
57
58
|
end
|
@@ -59,6 +60,13 @@ module Landline
|
|
59
60
|
|
60
61
|
private
|
61
62
|
|
63
|
+
def _match?(input)
|
64
|
+
parts = input.split("/")
|
65
|
+
@pattern.split("/").map.with_index do |part, index|
|
66
|
+
parts[index] == part
|
67
|
+
end.all?(true)
|
68
|
+
end
|
69
|
+
|
62
70
|
def patternify(pattern)
|
63
71
|
classdomain = Landline::PatternMatching
|
64
72
|
classdomain.constants
|
data/lib/landline/server.rb
CHANGED
@@ -58,14 +58,14 @@ module Landline
|
|
58
58
|
def setup_properties(*_args, **_opts)
|
59
59
|
{
|
60
60
|
"index" => [],
|
61
|
-
"handle.default" => proc do |code, backtrace: nil|
|
61
|
+
"handle.default" => proc do |code, backtrace: nil, **_extra|
|
62
62
|
page = Landline::Util.default_error_page(code, backtrace)
|
63
63
|
headers = {
|
64
64
|
"content-length": page.bytesize,
|
65
65
|
"content-type": "text/html",
|
66
66
|
"x-cascade": true
|
67
67
|
}
|
68
|
-
[headers, page]
|
68
|
+
[code, headers, page]
|
69
69
|
end,
|
70
70
|
"path" => "/"
|
71
71
|
}.each { |k, v| @properties[k] = v unless @properties[k] }
|
data/lib/landline/util/cookie.rb
CHANGED
@@ -115,6 +115,8 @@ module Landline
|
|
115
115
|
|
116
116
|
data.split(";").map do |cookiestr|
|
117
117
|
key, value = cookiestr.match(/([^=]+)=?(.*)/).to_a[1..].map(&:strip)
|
118
|
+
next unless key and value
|
119
|
+
|
118
120
|
cookie = Cookie.new(key, value)
|
119
121
|
if hash[cookie.key]
|
120
122
|
hash[cookie.key].append(cookie)
|
data/lib/landline/util/lookup.rb
CHANGED
@@ -28,7 +28,7 @@ module Landline
|
|
28
28
|
# Decode charset parameter
|
29
29
|
def decode(data)
|
30
30
|
data = Landline::Util.unescape_html(data)
|
31
|
-
return data unless self.headers['charset']
|
31
|
+
return data.force_encoding("UTF-8") unless self.headers['charset']
|
32
32
|
|
33
33
|
data.force_encoding(self.headers['charset']).encode("UTF-8")
|
34
34
|
end
|
@@ -15,12 +15,16 @@ module Landline
|
|
15
15
|
PRINTCHAR = /[\x2-\x7E]/
|
16
16
|
# Matches 1 or more CHARs excluding CTLs
|
17
17
|
PRINTABLE = /#{PRINTCHAR}+/o
|
18
|
+
# !! RFC 6265 IS PROPOSED AND NOT AN IMPLEMENTED STANDARD YET !!
|
18
19
|
# Matches the RFC6265 definition of a cookie-octet
|
19
|
-
|
20
|
-
|
21
|
-
COOKIE_NAME = TOKEN
|
20
|
+
# COOKIE_VALUE = /(?:#{QUOTED}|#{COOKIE_OCTET})/o
|
21
|
+
# COOKIE_NAME = TOKEN
|
22
22
|
# Matches the RFC6265 definition of cookie-pair.
|
23
23
|
# Captures name (1) and value (2).
|
24
|
+
# !! RFC 6265 IS PROPOSED AND NOT AN IMPLEMENTED STANDARD YET !!
|
25
|
+
COOKIE_OCTET = /[\x21-\x7E&&[^",;\\]]*/
|
26
|
+
COOKIE_NAME = /[^;,=\s]*/
|
27
|
+
COOKIE_VALUE = /[^;,\s]*/
|
24
28
|
COOKIE_PAIR = /\A(#{COOKIE_NAME})=(#{COOKIE_VALUE})\z/o
|
25
29
|
# Matches a very abstract definition of a quoted header paramter.
|
26
30
|
# Captures name (1) and value (2).
|
@@ -83,7 +87,7 @@ module Landline
|
|
83
87
|
unless input.match? HeaderRegexp::PRINTABLE
|
84
88
|
raise Landline::ParsingError, "input is not ascii printable"
|
85
89
|
end
|
86
|
-
|
90
|
+
|
87
91
|
opts.each do |key, value|
|
88
92
|
check_param(key, value)
|
89
93
|
newparam = if [String, Integer].include? value.class
|
data/lib/landline.rb
CHANGED
@@ -12,11 +12,11 @@ require_relative 'landline/app'
|
|
12
12
|
# Landline is a backend framework born as a by-product of experimentation
|
13
13
|
module Landline
|
14
14
|
# Landline version
|
15
|
-
VERSION = '0.
|
15
|
+
VERSION = '0.13.0 "Realign" (pre-alpha)'
|
16
16
|
|
17
17
|
# Landline branding and version
|
18
18
|
VLINE = "Landline/#{Landline::VERSION} (Ruby/#{RUBY_VERSION}/#{RUBY_RELEASE_DATE})\n".freeze
|
19
19
|
|
20
20
|
# Landline copyright
|
21
|
-
COPYRIGHT = "Copyright 2023 Yessiest"
|
21
|
+
COPYRIGHT = "Copyright 2023-2024 Yessiest"
|
22
22
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: landline
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yessiest
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-12-10 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |
|
14
14
|
Landline is a no-hard-dependencies HTTP routing DSL that was made entirely for fun.
|
@@ -21,10 +21,12 @@ extra_rdoc_files:
|
|
21
21
|
- HACKING.md
|
22
22
|
- LICENSE.md
|
23
23
|
- README.md
|
24
|
+
- STRUCTURE.md
|
24
25
|
files:
|
25
26
|
- HACKING.md
|
26
27
|
- LICENSE.md
|
27
28
|
- README.md
|
29
|
+
- STRUCTURE.md
|
28
30
|
- lib/landline.rb
|
29
31
|
- lib/landline/app.rb
|
30
32
|
- lib/landline/dsl/constructors_path.rb
|
@@ -82,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
82
84
|
- !ruby/object:Gem::Version
|
83
85
|
version: '0'
|
84
86
|
requirements: []
|
85
|
-
rubygems_version: 3.5.
|
87
|
+
rubygems_version: 3.5.16
|
86
88
|
signing_key:
|
87
89
|
specification_version: 4
|
88
90
|
summary: Elegant HTTP DSL
|