Skip to content

Commit 11c4b66

Browse files
authored
Add streaming upload example. (#206)
1 parent 9170a2a commit 11c4b66

File tree

5 files changed

+219
-0
lines changed

5 files changed

+219
-0
lines changed

examples/streaming_upload/Gemfile

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
source 'https://rubygems.org'
2+
3+
gem "falcon"
+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
GEM
2+
remote: https://rubygems.org/
3+
specs:
4+
async (2.5.0)
5+
console (~> 1.10)
6+
io-event (~> 1.1)
7+
timers (~> 4.1)
8+
async-container (0.16.12)
9+
async
10+
async-io
11+
async-http (0.60.1)
12+
async (>= 1.25)
13+
async-io (>= 1.28)
14+
async-pool (>= 0.2)
15+
protocol-http (~> 0.24.0)
16+
protocol-http1 (~> 0.15.0)
17+
protocol-http2 (~> 0.15.0)
18+
traces (>= 0.8.0)
19+
async-http-cache (0.4.3)
20+
async-http (~> 0.56)
21+
async-io (1.34.3)
22+
async
23+
async-pool (0.4.0)
24+
async (>= 1.25)
25+
build-environment (1.13.0)
26+
console (1.16.2)
27+
fiber-local
28+
falcon (0.42.3)
29+
async
30+
async-container (~> 0.16.0)
31+
async-http (~> 0.57)
32+
async-http-cache (~> 0.4.0)
33+
async-io (~> 1.22)
34+
build-environment (~> 1.13)
35+
bundler
36+
localhost (~> 1.1)
37+
openssl (~> 3.0)
38+
process-metrics (~> 0.2.0)
39+
protocol-rack (~> 0.1)
40+
samovar (~> 2.1)
41+
fiber-local (1.0.0)
42+
io-event (1.1.7)
43+
localhost (1.1.10)
44+
mapping (1.1.1)
45+
openssl (3.1.0)
46+
process-metrics (0.2.1)
47+
console (~> 1.8)
48+
samovar (~> 2.1)
49+
protocol-hpack (1.4.2)
50+
protocol-http (0.24.1)
51+
protocol-http1 (0.15.0)
52+
protocol-http (~> 0.22)
53+
protocol-http2 (0.15.1)
54+
protocol-hpack (~> 1.4)
55+
protocol-http (~> 0.18)
56+
protocol-rack (0.2.4)
57+
protocol-http (~> 0.23)
58+
rack (>= 1.0)
59+
rack (3.0.7)
60+
samovar (2.1.4)
61+
console (~> 1.0)
62+
mapping (~> 1.0)
63+
timers (4.3.5)
64+
traces (0.9.1)
65+
66+
PLATFORMS
67+
x86_64-linux
68+
69+
DEPENDENCIES
70+
falcon
71+
72+
BUNDLED WITH
73+
2.4.6

examples/streaming_upload/README.txt

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Streaming Upload
2+
3+
# ab Results
4+
5+
The filesize was 82078050 bytes.
6+
7+
8+
9+
10+
## concurrent requests
11+
12+
```
13+
bundle exec falcon host ./falcon.rb
14+
```
15+
16+
17+
```
18+
This is ApacheBench, Version 2.3 <$Revision: 1879490 $>
19+
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
20+
Licensed to The Apache Software Foundation, http://www.apache.org/
21+
22+
Benchmarking localhost (be patient).....done
23+
24+
25+
Server Software:
26+
Server Hostname: localhost
27+
Server Port: 9292
28+
29+
Document Path: /
30+
Document Length: 100 bytes
31+
32+
Concurrency Level: 20
33+
Time taken for tests: 7.873 seconds
34+
Complete requests: 100
35+
Failed requests: 9
36+
(Connect: 0, Receive: 0, Length: 9, Exceptions: 0)
37+
Total transferred: 16280 bytes
38+
Total body sent: 8628660682
39+
HTML transferred: 9989 bytes
40+
Requests per second: 12.70 [#/sec] (mean)
41+
Time per request: 1574.576 [ms] (mean)
42+
Time per request: 78.729 [ms] (mean, across all concurrent requests)
43+
Transfer rate: 2.02 [Kbytes/sec] received
44+
1070310.40 kb/s sent
45+
1070312.42 kb/s total
46+
47+
Connection Times (ms)
48+
min mean[+/-sd] median max
49+
Connect: 0 56 44.6 52 141
50+
Processing: 296 1384 725.4 1159 4456
51+
Waiting: 33 126 89.2 121 886
52+
Total: 297 1440 720.8 1236 4464
53+
54+
Percentage of the requests served within a certain time (ms)
55+
50% 1236
56+
66% 1458
57+
75% 1627
58+
80% 1711
59+
90% 2020
60+
95% 3883
61+
98% 4463
62+
99% 4464
63+
100% 4464 (longest request)
64+
```
65+
66+
EOFError errors cause the failed uploads....have to figure out why.

examples/streaming_upload/config.ru

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# frozen_string_literal: true
2+
3+
# run with: falcon serve -n 1 -b http://localhost:9292
4+
5+
require 'digest'
6+
require 'securerandom'
7+
8+
module Protocol
9+
module HTTP1
10+
class Connection
11+
def write_continue
12+
@stream.write("HTTP/1.1 100 Continue\r\n\r\n")
13+
@stream.flush
14+
end
15+
end
16+
end
17+
end
18+
19+
class BodyHandler
20+
attr_reader :time, :md5, :size, :uuid
21+
22+
def initialize(input, length)
23+
@uuid = SecureRandom.uuid
24+
@input = input
25+
@length = length
26+
end
27+
28+
def receive
29+
start = Time.now
30+
@md5 = Digest::MD5.new
31+
@size = 0
32+
@done = false
33+
34+
until @done
35+
begin
36+
chunk = @input.read(10_240) # read will raise EOF so we have to check
37+
rescue EOFError
38+
puts "Seems we're done"
39+
chunk = nil
40+
end
41+
if chunk.nil?
42+
@done = true
43+
else
44+
@md5.update(chunk)
45+
@size += chunk.bytesize
46+
@done = true if @length == @size
47+
end
48+
end
49+
50+
@time = Time.now - start
51+
end
52+
end
53+
54+
run lambda { |env|
55+
request = env['protocol.http.request']
56+
handler = BodyHandler.new(env['rack.input'], env['CONTENT_LENGTH'])
57+
puts "#{env['REQUEST_METHOD']} #{handler.uuid}: #{request.path} #{env['CONTENT_LENGTH']}"
58+
59+
if env['REQUEST_METHOD'] == 'POST'
60+
request.connection.write_continue if request.headers['expect'] == ['100-continue']
61+
handler.receive
62+
msg = "Uploaded #{handler.uuid}: #{handler.md5} #{handler.time} #{handler.size}"
63+
puts msg
64+
[200, {}, [msg]]
65+
else
66+
sleep 1
67+
[200, {}, ["#{env['REQUEST_METHOD']}: #{request.path}\n"]]
68+
end
69+
}

examples/streaming_upload/falcon.rb

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
load :rack, :supervisor
2+
3+
hostname = File.basename(__dir__)
4+
rack hostname do
5+
endpoint Async::HTTP::Endpoint.parse('http://localhost:9292').with(protocol: Async::HTTP::Protocol::HTTP1)
6+
end
7+
8+
supervisor

0 commit comments

Comments
 (0)