quicsilver 0.1.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 +7 -0
- data/.gitignore +12 -0
- data/.gitmodules +3 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +22 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +28 -0
- data/README.md +105 -0
- data/Rakefile +31 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/README.md +105 -0
- data/examples/minimal_http3_client.rb +89 -0
- data/examples/minimal_http3_server.rb +32 -0
- data/examples/rack_http3_server.rb +60 -0
- data/examples/setup_certs.sh +57 -0
- data/ext/quicsilver/extconf.rb +25 -0
- data/ext/quicsilver/quicsilver.c +807 -0
- data/lib/quicsilver/client.rb +191 -0
- data/lib/quicsilver/http3/request_encoder.rb +112 -0
- data/lib/quicsilver/http3/request_parser.rb +158 -0
- data/lib/quicsilver/http3/response_encoder.rb +73 -0
- data/lib/quicsilver/http3.rb +68 -0
- data/lib/quicsilver/listener_data.rb +29 -0
- data/lib/quicsilver/server.rb +258 -0
- data/lib/quicsilver/server_configuration.rb +49 -0
- data/lib/quicsilver/version.rb +3 -0
- data/lib/quicsilver.rb +22 -0
- data/quicsilver.gemspec +44 -0
- metadata +143 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 5e879e4531621883da97721256a2b0db478ba995d8bf54c93ddf959fca9cd36d
|
|
4
|
+
data.tar.gz: 579023d40239d8c7a77671be44fb37265d735f864a13072887598406908c0aae
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 25c070017404e15d673cfcb267ef90722dd255af0c68dd3488f1065ebe8fcc84614054b7ae3b5b0e2cd1bc74ca725a7ddd4e0500b80f849580ebef3306705443
|
|
7
|
+
data.tar.gz: 61f273afb32f2a45d07bc2f634a8f6d52973654b4e874ed01dd87a674126046f2e332741ca464b6f41a025e206064172a9614c602bb7285dab0b68b6efa7d09a
|
data/.gitignore
ADDED
data/.gitmodules
ADDED
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.4.2
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2025-10-28
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Initial HTTP/3 server implementation using Microsoft MSQUIC
|
|
12
|
+
- HTTP/3 client for testing and development
|
|
13
|
+
- Rack support
|
|
14
|
+
- HTTP/3 frame encoding/decoding (DATA, HEADERS, SETTINGS)
|
|
15
|
+
- QPACK header compression (static table support)
|
|
16
|
+
- Bidirectional request/response streams
|
|
17
|
+
- Request body buffering for large payloads
|
|
18
|
+
|
|
19
|
+
### Limitations
|
|
20
|
+
This is still in prototype, it has the following known limitations:
|
|
21
|
+
- No server push, GOAWAY, or trailer support
|
|
22
|
+
- Limited error handling
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
quicsilver (0.1.0)
|
|
5
|
+
|
|
6
|
+
GEM
|
|
7
|
+
remote: https://rubygems.org/
|
|
8
|
+
specs:
|
|
9
|
+
minitest (5.25.5)
|
|
10
|
+
rake (10.5.0)
|
|
11
|
+
rake-compiler (1.3.0)
|
|
12
|
+
rake
|
|
13
|
+
rake-compiler-dock (1.9.1)
|
|
14
|
+
|
|
15
|
+
PLATFORMS
|
|
16
|
+
arm64-darwin-23
|
|
17
|
+
ruby
|
|
18
|
+
|
|
19
|
+
DEPENDENCIES
|
|
20
|
+
bundler (~> 2.0)
|
|
21
|
+
minitest (~> 5.0)
|
|
22
|
+
quicsilver!
|
|
23
|
+
rake (~> 10.0)
|
|
24
|
+
rake-compiler (~> 1.2)
|
|
25
|
+
rake-compiler-dock (~> 1.3)
|
|
26
|
+
|
|
27
|
+
BUNDLED WITH
|
|
28
|
+
2.6.5
|
data/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Quicsilver
|
|
2
|
+
|
|
3
|
+
HTTP/3 server for Ruby with Rack support.
|
|
4
|
+
|
|
5
|
+
Disclaimer: currenly in early prototype.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
git clone <repository>
|
|
11
|
+
cd quicsilver
|
|
12
|
+
bundle install
|
|
13
|
+
rake compile
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
### 1. Set up certificates
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
bash examples/setup_certs.sh
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### 2. Run a Rack app over HTTP/3
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
require "quicsilver"
|
|
28
|
+
|
|
29
|
+
# Define your Rack app
|
|
30
|
+
app = ->(env) {
|
|
31
|
+
path = env['PATH_INFO']
|
|
32
|
+
|
|
33
|
+
case path
|
|
34
|
+
when '/'
|
|
35
|
+
[200, {'Content-Type' => 'text/plain'}, ["Hello HTTP/3!"]]
|
|
36
|
+
when '/api/users'
|
|
37
|
+
[200, {'Content-Type' => 'application/json'}, ['{"users": ["alice", "bob"]}']]
|
|
38
|
+
else
|
|
39
|
+
[404, {'Content-Type' => 'text/plain'}, ["Not Found"]]
|
|
40
|
+
end
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
# Start HTTP/3 server with Rack app
|
|
44
|
+
server = Quicsilver::Server.new(4433, app: app)
|
|
45
|
+
server.start
|
|
46
|
+
server.wait_for_connections
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 3. Test with the client
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
ruby examples/minimal_http3_client.rb
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Usage
|
|
56
|
+
|
|
57
|
+
### Rack HTTP/3 Server
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
require "quicsilver"
|
|
61
|
+
|
|
62
|
+
app = ->(env) {
|
|
63
|
+
[200, {'Content-Type' => 'text/html'}, ["<h1>Hello from HTTP/3!</h1>"]]
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
server = Quicsilver::Server.new(4433, app: app)
|
|
67
|
+
server.start
|
|
68
|
+
server.wait_for_connections
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### HTTP/3 Client
|
|
72
|
+
|
|
73
|
+
```ruby
|
|
74
|
+
require "quicsilver"
|
|
75
|
+
|
|
76
|
+
client = Quicsilver::Client.new("127.0.0.1", 4433, unsecure: true)
|
|
77
|
+
client.connect
|
|
78
|
+
|
|
79
|
+
# Send HTTP/3 request
|
|
80
|
+
request = Quicsilver::HTTP3::RequestEncoder.new(
|
|
81
|
+
method: 'GET',
|
|
82
|
+
path: '/api/users',
|
|
83
|
+
authority: 'example.com'
|
|
84
|
+
)
|
|
85
|
+
client.send_data(request.encode)
|
|
86
|
+
|
|
87
|
+
client.disconnect
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Development
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Run tests
|
|
94
|
+
rake test
|
|
95
|
+
|
|
96
|
+
# Build extension
|
|
97
|
+
rake compile
|
|
98
|
+
|
|
99
|
+
# Clean build artifacts
|
|
100
|
+
rake clean
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## License
|
|
104
|
+
|
|
105
|
+
MIT License
|
data/Rakefile
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require "bundler/gem_tasks"
|
|
2
|
+
require "rake/testtask"
|
|
3
|
+
require "rake/extensiontask"
|
|
4
|
+
|
|
5
|
+
Rake::ExtensionTask.new('quicsilver') do |ext|
|
|
6
|
+
ext.lib_dir = 'lib/quicsilver'
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
task :setup do
|
|
10
|
+
# Initialize git submodule if it doesn't exist
|
|
11
|
+
unless File.exist?('vendor/msquic')
|
|
12
|
+
sh 'git submodule add https://github.com/microsoft/msquic.git vendor/msquic'
|
|
13
|
+
sh 'cd vendor/msquic && git submodule update --init --recursive'
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
task :build_msquic => :setup do
|
|
18
|
+
# Build MSQUIC using CMake with proper macOS framework linking
|
|
19
|
+
sh 'cd vendor/msquic && cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXE_LINKER_FLAGS="-framework CoreServices" -DCMAKE_SHARED_LINKER_FLAGS="-framework CoreServices"'
|
|
20
|
+
sh 'cd vendor/msquic && cmake --build build --config Release'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
task :build => [:build_msquic, :compile]
|
|
24
|
+
|
|
25
|
+
Rake::TestTask.new(:test) do |t|
|
|
26
|
+
t.libs << "test"
|
|
27
|
+
t.libs << "lib"
|
|
28
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
task :default => :test
|
data/bin/console
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "quicsilver"
|
|
5
|
+
|
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
8
|
+
|
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
10
|
+
# require "pry"
|
|
11
|
+
# Pry.start
|
|
12
|
+
|
|
13
|
+
require "irb"
|
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/examples/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Quicsilver Examples
|
|
2
|
+
|
|
3
|
+
This directory contains examples for testing your Ruby QUIC implementation.
|
|
4
|
+
|
|
5
|
+
## š Quick Start
|
|
6
|
+
|
|
7
|
+
### 1. Generate Certificates
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
cd examples
|
|
11
|
+
./setup_certs.sh
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
This creates the necessary certificate files in the `certs/` directory.
|
|
15
|
+
|
|
16
|
+
### 2. Run the Server
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Terminal 1
|
|
20
|
+
ruby examples/test_server.rb
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### 3. Test the Connection
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Terminal 2
|
|
27
|
+
ruby examples/test_connection.rb
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## š Files
|
|
31
|
+
|
|
32
|
+
| File | Purpose |
|
|
33
|
+
|------|---------|
|
|
34
|
+
| `setup_certs.sh` | Generate certificates for testing |
|
|
35
|
+
| `test_server.rb` | Ruby QUIC server |
|
|
36
|
+
| `test_connection.rb` | QUIC client test |
|
|
37
|
+
|
|
38
|
+
## ā
Expected Output
|
|
39
|
+
|
|
40
|
+
**Server:**
|
|
41
|
+
```
|
|
42
|
+
š„ Quicsilver QUIC Server Test
|
|
43
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
44
|
+
š Server Info:
|
|
45
|
+
server_id: a47271c7ae4276d5
|
|
46
|
+
address: 127.0.0.1
|
|
47
|
+
port: 4433
|
|
48
|
+
running: false
|
|
49
|
+
cert_file: /path/to/certs/server.crt
|
|
50
|
+
key_file: /path/to/certs/server.key
|
|
51
|
+
max_connections: 100
|
|
52
|
+
|
|
53
|
+
š Starting QUIC server on 127.0.0.1:4433
|
|
54
|
+
ā
QUIC server started successfully!
|
|
55
|
+
š Listening for connections...
|
|
56
|
+
šÆ Server is running! Press Ctrl+C to stop
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Client:**
|
|
60
|
+
```
|
|
61
|
+
š Testing QUIC Connection to 127.0.0.1:4433...
|
|
62
|
+
|
|
63
|
+
Connected to 127.0.0.1:4433
|
|
64
|
+
ā
SUCCESS! Connected to QUIC server
|
|
65
|
+
š Connection time: 13.5ms
|
|
66
|
+
š Connected status: true
|
|
67
|
+
š Connection info: {"connected" => true, "failed" => false, ...}
|
|
68
|
+
|
|
69
|
+
š§Ŗ Testing connection stability...
|
|
70
|
+
ā±ļø Tick 1: Connected = true
|
|
71
|
+
ā±ļø Tick 2: Connected = true
|
|
72
|
+
ā±ļø Tick 3: Connected = true
|
|
73
|
+
ā
Connection test completed!
|
|
74
|
+
š Connection closed cleanly
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## š§ Manual Certificate Setup
|
|
78
|
+
|
|
79
|
+
If you prefer to create certificates manually:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
mkdir -p certs
|
|
83
|
+
cd certs
|
|
84
|
+
|
|
85
|
+
# Generate private key
|
|
86
|
+
openssl genrsa -out server.key 2048
|
|
87
|
+
|
|
88
|
+
# Generate certificate with proper QUIC extensions
|
|
89
|
+
openssl req -new -x509 -key server.key -out server.crt -days 365 \
|
|
90
|
+
-subj "/CN=localhost/O=QuicsilverTest/C=US" \
|
|
91
|
+
-addext "subjectAltName=DNS:localhost,IP:127.0.0.1" \
|
|
92
|
+
-addext "extendedKeyUsage=serverAuth"
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## š Troubleshooting
|
|
96
|
+
|
|
97
|
+
**Port in use error:** The server automatically cleans up port 4433 before starting.
|
|
98
|
+
|
|
99
|
+
**Connection refused:** Make sure the server is running before testing the client.
|
|
100
|
+
|
|
101
|
+
**Certificate errors:** Run `./setup_certs.sh` to regenerate certificates with proper QUIC extensions.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
That's it! No Docker, no external servers, just pure Ruby QUIC. šÆ
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "quicsilver"
|
|
5
|
+
|
|
6
|
+
puts "š Minimal HTTP/3 Client Example"
|
|
7
|
+
puts "=" * 40
|
|
8
|
+
|
|
9
|
+
# Create client
|
|
10
|
+
client = Quicsilver::Client.new("127.0.0.1", 4433, unsecure: true)
|
|
11
|
+
|
|
12
|
+
puts "š§ Connecting to server..."
|
|
13
|
+
begin
|
|
14
|
+
client.connect
|
|
15
|
+
puts "ā
Connected successfully!"
|
|
16
|
+
puts "š Connection info: #{client.connection_info}"
|
|
17
|
+
|
|
18
|
+
# HTTP/3 requests using RequestEncoder
|
|
19
|
+
require_relative '../lib/quicsilver/http3/request_encoder'
|
|
20
|
+
|
|
21
|
+
request1 = Quicsilver::HTTP3::RequestEncoder.new(
|
|
22
|
+
method: 'GET',
|
|
23
|
+
path: '/api/users',
|
|
24
|
+
authority: 'example.com'
|
|
25
|
+
)
|
|
26
|
+
client.send_data(request1.encode)
|
|
27
|
+
|
|
28
|
+
request2 = Quicsilver::HTTP3::RequestEncoder.new(
|
|
29
|
+
method: 'GET',
|
|
30
|
+
path: '/api/posts/123',
|
|
31
|
+
authority: 'example.com'
|
|
32
|
+
)
|
|
33
|
+
client.send_data(request2.encode)
|
|
34
|
+
|
|
35
|
+
request3 = Quicsilver::HTTP3::RequestEncoder.new(
|
|
36
|
+
method: 'POST',
|
|
37
|
+
path: '/api/messages',
|
|
38
|
+
authority: 'example.com',
|
|
39
|
+
body: '{"text":"Hello world"}'
|
|
40
|
+
)
|
|
41
|
+
client.send_data(request3.encode)
|
|
42
|
+
|
|
43
|
+
# JSON payloads (API requests) - now as proper HTTP/3 POST requests
|
|
44
|
+
request4 = Quicsilver::HTTP3::RequestEncoder.new(
|
|
45
|
+
method: 'POST',
|
|
46
|
+
path: '/api/subscribe',
|
|
47
|
+
authority: 'example.com',
|
|
48
|
+
headers: { 'content-type' => 'application/json' },
|
|
49
|
+
body: '{"action":"subscribe","channel":"orders"}'
|
|
50
|
+
)
|
|
51
|
+
client.send_data(request4.encode)
|
|
52
|
+
|
|
53
|
+
request5 = Quicsilver::HTTP3::RequestEncoder.new(
|
|
54
|
+
method: 'POST',
|
|
55
|
+
path: '/api/update',
|
|
56
|
+
authority: 'example.com',
|
|
57
|
+
headers: { 'content-type' => 'application/json' },
|
|
58
|
+
body: '{"action":"update","user_id":42,"status":"online"}'
|
|
59
|
+
)
|
|
60
|
+
client.send_data(request5.encode)
|
|
61
|
+
|
|
62
|
+
# These old manually-crafted requests use incorrect QPACK indices - removed
|
|
63
|
+
|
|
64
|
+
# Metrics/telemetry
|
|
65
|
+
# client.send_data("METRIC:cpu=45.2,mem=1024,ts=#{Time.now.to_i}")
|
|
66
|
+
# client.send_data("EVENT:login,user=alice,ip=192.168.1.100")
|
|
67
|
+
|
|
68
|
+
# Large message test - now as HTTP/3 request
|
|
69
|
+
request8 = Quicsilver::HTTP3::RequestEncoder.new(
|
|
70
|
+
method: 'POST',
|
|
71
|
+
path: '/upload',
|
|
72
|
+
authority: 'example.com',
|
|
73
|
+
body: "X" * 50000 # 50KB
|
|
74
|
+
)
|
|
75
|
+
client.send_data(request8.encode)
|
|
76
|
+
|
|
77
|
+
# Keep connection alive for a bit
|
|
78
|
+
puts "ā³ Connection established. Press Enter to disconnect..."
|
|
79
|
+
gets
|
|
80
|
+
|
|
81
|
+
rescue Quicsilver::ConnectionError => e
|
|
82
|
+
puts "ā Connection failed: #{e.message}"
|
|
83
|
+
rescue Quicsilver::TimeoutError => e
|
|
84
|
+
puts "ā° Connection timed out: #{e.message}"
|
|
85
|
+
ensure
|
|
86
|
+
puts "š Disconnecting..."
|
|
87
|
+
client.disconnect
|
|
88
|
+
puts "š Disconnected"
|
|
89
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "quicsilver"
|
|
5
|
+
|
|
6
|
+
puts "š Minimal HTTP/3 Server Example"
|
|
7
|
+
puts "=" * 40
|
|
8
|
+
|
|
9
|
+
# First, set up certificates if they don't exist
|
|
10
|
+
unless File.exist?("certs/server.crt") && File.exist?("certs/server.key")
|
|
11
|
+
puts "š Setting up certificates..."
|
|
12
|
+
system("bash examples/setup_certs.sh")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Create and start the server
|
|
16
|
+
server = Quicsilver::Server.new(4433)
|
|
17
|
+
|
|
18
|
+
puts "š§ Starting server..."
|
|
19
|
+
server.start
|
|
20
|
+
|
|
21
|
+
puts "ā
Server is running on port 4433"
|
|
22
|
+
puts "š Server info: #{server.server_info}"
|
|
23
|
+
|
|
24
|
+
# Keep the server running
|
|
25
|
+
puts "ā³ Server is running. Press Ctrl+C to stop..."
|
|
26
|
+
begin
|
|
27
|
+
server.wait_for_connections
|
|
28
|
+
rescue Interrupt
|
|
29
|
+
puts "\nš Stopping server..."
|
|
30
|
+
server.stop
|
|
31
|
+
puts "š Server stopped"
|
|
32
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "quicsilver"
|
|
5
|
+
|
|
6
|
+
puts "š Rack HTTP/3 Server Example"
|
|
7
|
+
puts "=" * 40
|
|
8
|
+
|
|
9
|
+
# First, set up certificates if they don't exist
|
|
10
|
+
unless File.exist?("certs/server.crt") && File.exist?("certs/server.key")
|
|
11
|
+
puts "š Setting up certificates..."
|
|
12
|
+
system("bash examples/setup_certs.sh")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Define a simple Rack app
|
|
16
|
+
app = ->(env) {
|
|
17
|
+
path = env['PATH_INFO']
|
|
18
|
+
method = env['REQUEST_METHOD']
|
|
19
|
+
|
|
20
|
+
case path
|
|
21
|
+
when '/'
|
|
22
|
+
[200,
|
|
23
|
+
{'Content-Type' => 'text/plain'},
|
|
24
|
+
["Welcome to Quicsilver HTTP/3!\n"]]
|
|
25
|
+
when '/api/users'
|
|
26
|
+
[200,
|
|
27
|
+
{'Content-Type' => 'application/json'},
|
|
28
|
+
['{"users": ["alice", "bob", "charlie"]}']]
|
|
29
|
+
when '/api/status'
|
|
30
|
+
[200,
|
|
31
|
+
{'Content-Type' => 'application/json'},
|
|
32
|
+
["{\"status\": \"ok\", \"method\": \"#{method}\", \"path\": \"#{path}\"}"]]
|
|
33
|
+
else
|
|
34
|
+
[404,
|
|
35
|
+
{'Content-Type' => 'text/plain'},
|
|
36
|
+
["Not Found: #{path}\n"]]
|
|
37
|
+
end
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# Create and start the server with the Rack app
|
|
41
|
+
server = Quicsilver::Server.new(4433, app: app)
|
|
42
|
+
|
|
43
|
+
puts "š§ Starting server..."
|
|
44
|
+
server.start
|
|
45
|
+
|
|
46
|
+
puts "ā
Server is running on port 4433"
|
|
47
|
+
puts "š Try these requests:"
|
|
48
|
+
puts " curl --http3 -k https://127.0.0.1:4433/"
|
|
49
|
+
puts " curl --http3 -k https://127.0.0.1:4433/api/users"
|
|
50
|
+
puts " curl --http3 -k https://127.0.0.1:4433/api/status"
|
|
51
|
+
|
|
52
|
+
# Keep the server running
|
|
53
|
+
puts "ā³ Server is running. Press Ctrl+C to stop..."
|
|
54
|
+
begin
|
|
55
|
+
server.wait_for_connections
|
|
56
|
+
rescue Interrupt
|
|
57
|
+
puts "\nš Stopping server..."
|
|
58
|
+
server.stop
|
|
59
|
+
puts "š Server stopped"
|
|
60
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Quicsilver Certificate Setup
|
|
4
|
+
# This script generates self-signed certificates for QUIC testing
|
|
5
|
+
|
|
6
|
+
echo "š Generating certificates for Quicsilver QUIC testing..."
|
|
7
|
+
|
|
8
|
+
# Create certs directory if it doesn't exist
|
|
9
|
+
mkdir -p ../certs
|
|
10
|
+
cd ../certs
|
|
11
|
+
|
|
12
|
+
# Create OpenSSL config with proper TLS server extensions
|
|
13
|
+
cat > openssl.conf << 'EOF'
|
|
14
|
+
[req]
|
|
15
|
+
distinguished_name = req_distinguished_name
|
|
16
|
+
req_extensions = v3_req
|
|
17
|
+
prompt = no
|
|
18
|
+
|
|
19
|
+
[req_distinguished_name]
|
|
20
|
+
CN = localhost
|
|
21
|
+
O = QuicsilverTest
|
|
22
|
+
C = US
|
|
23
|
+
|
|
24
|
+
[v3_req]
|
|
25
|
+
keyUsage = keyEncipherment, dataEncipherment
|
|
26
|
+
extendedKeyUsage = serverAuth
|
|
27
|
+
subjectAltName = @alt_names
|
|
28
|
+
|
|
29
|
+
[alt_names]
|
|
30
|
+
DNS.1 = localhost
|
|
31
|
+
IP.1 = 127.0.0.1
|
|
32
|
+
EOF
|
|
33
|
+
|
|
34
|
+
# Generate private key and certificate
|
|
35
|
+
echo "š Generating private key..."
|
|
36
|
+
openssl genrsa -out server.key 2048
|
|
37
|
+
|
|
38
|
+
echo "š Generating certificate..."
|
|
39
|
+
openssl req -new -x509 -key server.key -out server.crt -days 365 \
|
|
40
|
+
-config openssl.conf -extensions v3_req
|
|
41
|
+
|
|
42
|
+
# Create PKCS#12 format (optional, for other tools)
|
|
43
|
+
echo "š¦ Creating PKCS#12 bundle..."
|
|
44
|
+
openssl pkcs12 -export -out server.p12 -inkey server.key -in server.crt \
|
|
45
|
+
-passout pass:password -name "localhost"
|
|
46
|
+
|
|
47
|
+
# Clean up
|
|
48
|
+
rm openssl.conf
|
|
49
|
+
|
|
50
|
+
echo "ā
Certificate files created:"
|
|
51
|
+
echo " š server.crt - Certificate file"
|
|
52
|
+
echo " š server.key - Private key file"
|
|
53
|
+
echo " š¦ server.p12 - PKCS#12 bundle (password: 'password')"
|
|
54
|
+
echo ""
|
|
55
|
+
echo "š You can now run:"
|
|
56
|
+
echo " Terminal 1: ruby examples/test_server.rb"
|
|
57
|
+
echo " Terminal 2: ruby examples/test_connection.rb"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'mkmf'
|
|
2
|
+
|
|
3
|
+
# Find MSQUIC in the submodule
|
|
4
|
+
msquic_dir = File.expand_path('../../../vendor/msquic', __FILE__)
|
|
5
|
+
|
|
6
|
+
# Add MSQUIC include directory
|
|
7
|
+
$CFLAGS << " -I#{msquic_dir}/src/inc"
|
|
8
|
+
$CFLAGS << " -I#{msquic_dir}/src/inc/public"
|
|
9
|
+
|
|
10
|
+
# Add our fixes header
|
|
11
|
+
$CFLAGS << " -I#{File.expand_path('.', __FILE__)}"
|
|
12
|
+
|
|
13
|
+
# Add MSQUIC library directory
|
|
14
|
+
lib_dir = "#{msquic_dir}/build/bin/Release"
|
|
15
|
+
$LDFLAGS << " -L#{lib_dir}"
|
|
16
|
+
|
|
17
|
+
# Set rpath so the extension can find the library at runtime
|
|
18
|
+
$LDFLAGS << " -Wl,-rpath,#{lib_dir}"
|
|
19
|
+
|
|
20
|
+
# Find the MSQUIC library
|
|
21
|
+
unless find_library('msquic', nil, lib_dir)
|
|
22
|
+
raise "MSQUIC library not found. Please run 'rake build_msquic' first."
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
create_makefile('quicsilver/quicsilver')
|