Add support for compressed request bodies
This commit is contained in:
parent
9abcdb6886
commit
4e9144fba2
2 changed files with 223 additions and 0 deletions
42
config/initializers/compressed_requests.rb
Normal file
42
config/initializers/compressed_requests.rb
Normal file
|
@ -0,0 +1,42 @@
|
|||
module OpenStreetMap
|
||||
class CompressedRequests
|
||||
def initialize(app)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def method_handled?(env)
|
||||
%w[POST PUT].include? env["REQUEST_METHOD"]
|
||||
end
|
||||
|
||||
def encoding_handled?(env)
|
||||
%w[gzip deflate].include? env["HTTP_CONTENT_ENCODING"]
|
||||
end
|
||||
|
||||
def call(env)
|
||||
if method_handled?(env) && encoding_handled?(env)
|
||||
extracted = decode(env["rack.input"], env["HTTP_CONTENT_ENCODING"])
|
||||
|
||||
env.delete("HTTP_CONTENT_ENCODING")
|
||||
env["CONTENT_LENGTH"] = extracted.bytesize
|
||||
env["rack.input"] = StringIO.new(extracted)
|
||||
end
|
||||
|
||||
if env["HTTP_CONTENT_ENCODING"]
|
||||
[415, {}, []]
|
||||
else
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
|
||||
def decode(input, content_encoding)
|
||||
input.rewind
|
||||
|
||||
case content_encoding
|
||||
when "gzip" then Zlib::GzipReader.new(input).read
|
||||
when "deflate" then Zlib::Inflate.inflate(input.read)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Rails.configuration.middleware.use OpenStreetMap::CompressedRequests
|
181
test/integration/compressed_requests_test.rb
Normal file
181
test/integration/compressed_requests_test.rb
Normal file
|
@ -0,0 +1,181 @@
|
|||
require "test_helper"
|
||||
|
||||
class CompressedRequestsTest < ActionDispatch::IntegrationTest
|
||||
def test_no_compression
|
||||
user = create(:user)
|
||||
changeset = create(:changeset, :user => user)
|
||||
|
||||
node = create(:node)
|
||||
way = create(:way)
|
||||
relation = create(:relation)
|
||||
other_relation = create(:relation)
|
||||
# Create some tags, since we test that they are removed later
|
||||
create(:node_tag, :node => node)
|
||||
create(:way_tag, :way => way)
|
||||
create(:relation_tag, :relation => relation)
|
||||
|
||||
# simple diff to change a node, way and relation by removing
|
||||
# their tags
|
||||
diff = <<CHANGESET.strip_heredoc
|
||||
<osmChange>
|
||||
<modify>
|
||||
<node id='#{node.id}' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
|
||||
<way id='#{way.id}' changeset='#{changeset.id}' version='1'>
|
||||
<nd ref='#{node.id}'/>
|
||||
</way>
|
||||
</modify>
|
||||
<modify>
|
||||
<relation id='#{relation.id}' changeset='#{changeset.id}' version='1'>
|
||||
<member type='way' role='some' ref='#{way.id}'/>
|
||||
<member type='node' role='some' ref='#{node.id}'/>
|
||||
<member type='relation' role='some' ref='#{other_relation.id}'/>
|
||||
</relation>
|
||||
</modify>
|
||||
</osmChange>
|
||||
CHANGESET
|
||||
|
||||
# upload it
|
||||
post "/api/0.6/changeset/#{changeset.id}/upload",
|
||||
:params => diff,
|
||||
:headers => {
|
||||
"HTTP_AUTHORIZATION" => format("Basic %s", Base64.encode64("#{user.display_name}:test")),
|
||||
"HTTP_CONTENT_TYPE" => "application/xml"
|
||||
}
|
||||
assert_response :success,
|
||||
"can't upload an uncompressed diff to changeset: #{@response.body}"
|
||||
|
||||
# check that the changes made it into the database
|
||||
assert_equal 0, Node.find(node.id).tags.size, "node #{node.id} should now have no tags"
|
||||
assert_equal 0, Way.find(way.id).tags.size, "way #{way.id} should now have no tags"
|
||||
assert_equal 0, Relation.find(relation.id).tags.size, "relation #{relation.id} should now have no tags"
|
||||
end
|
||||
|
||||
def test_gzip_compression
|
||||
user = create(:user)
|
||||
changeset = create(:changeset, :user => user)
|
||||
|
||||
node = create(:node)
|
||||
way = create(:way)
|
||||
relation = create(:relation)
|
||||
other_relation = create(:relation)
|
||||
# Create some tags, since we test that they are removed later
|
||||
create(:node_tag, :node => node)
|
||||
create(:way_tag, :way => way)
|
||||
create(:relation_tag, :relation => relation)
|
||||
|
||||
# simple diff to change a node, way and relation by removing
|
||||
# their tags
|
||||
diff = <<CHANGESET.strip_heredoc
|
||||
<osmChange>
|
||||
<modify>
|
||||
<node id='#{node.id}' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
|
||||
<way id='#{way.id}' changeset='#{changeset.id}' version='1'>
|
||||
<nd ref='#{node.id}'/>
|
||||
</way>
|
||||
</modify>
|
||||
<modify>
|
||||
<relation id='#{relation.id}' changeset='#{changeset.id}' version='1'>
|
||||
<member type='way' role='some' ref='#{way.id}'/>
|
||||
<member type='node' role='some' ref='#{node.id}'/>
|
||||
<member type='relation' role='some' ref='#{other_relation.id}'/>
|
||||
</relation>
|
||||
</modify>
|
||||
</osmChange>
|
||||
CHANGESET
|
||||
|
||||
# upload it
|
||||
post "/api/0.6/changeset/#{changeset.id}/upload",
|
||||
:params => gzip_content(diff),
|
||||
:headers => {
|
||||
"HTTP_AUTHORIZATION" => format("Basic %s", Base64.encode64("#{user.display_name}:test")),
|
||||
"HTTP_CONTENT_ENCODING" => "gzip",
|
||||
"HTTP_CONTENT_TYPE" => "application/xml"
|
||||
}
|
||||
assert_response :success,
|
||||
"can't upload a gzip compressed diff to changeset: #{@response.body}"
|
||||
|
||||
# check that the changes made it into the database
|
||||
assert_equal 0, Node.find(node.id).tags.size, "node #{node.id} should now have no tags"
|
||||
assert_equal 0, Way.find(way.id).tags.size, "way #{way.id} should now have no tags"
|
||||
assert_equal 0, Relation.find(relation.id).tags.size, "relation #{relation.id} should now have no tags"
|
||||
end
|
||||
|
||||
def test_deflate_compression
|
||||
user = create(:user)
|
||||
changeset = create(:changeset, :user => user)
|
||||
|
||||
node = create(:node)
|
||||
way = create(:way)
|
||||
relation = create(:relation)
|
||||
other_relation = create(:relation)
|
||||
# Create some tags, since we test that they are removed later
|
||||
create(:node_tag, :node => node)
|
||||
create(:way_tag, :way => way)
|
||||
create(:relation_tag, :relation => relation)
|
||||
|
||||
# simple diff to change a node, way and relation by removing
|
||||
# their tags
|
||||
diff = <<CHANGESET.strip_heredoc
|
||||
<osmChange>
|
||||
<modify>
|
||||
<node id='#{node.id}' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
|
||||
<way id='#{way.id}' changeset='#{changeset.id}' version='1'>
|
||||
<nd ref='#{node.id}'/>
|
||||
</way>
|
||||
</modify>
|
||||
<modify>
|
||||
<relation id='#{relation.id}' changeset='#{changeset.id}' version='1'>
|
||||
<member type='way' role='some' ref='#{way.id}'/>
|
||||
<member type='node' role='some' ref='#{node.id}'/>
|
||||
<member type='relation' role='some' ref='#{other_relation.id}'/>
|
||||
</relation>
|
||||
</modify>
|
||||
</osmChange>
|
||||
CHANGESET
|
||||
|
||||
# upload it
|
||||
post "/api/0.6/changeset/#{changeset.id}/upload",
|
||||
:params => deflate_content(diff),
|
||||
:headers => {
|
||||
"HTTP_AUTHORIZATION" => format("Basic %s", Base64.encode64("#{user.display_name}:test")),
|
||||
"HTTP_CONTENT_ENCODING" => "deflate",
|
||||
"HTTP_CONTENT_TYPE" => "application/xml"
|
||||
}
|
||||
assert_response :success,
|
||||
"can't upload a deflate compressed diff to changeset: #{@response.body}"
|
||||
|
||||
# check that the changes made it into the database
|
||||
assert_equal 0, Node.find(node.id).tags.size, "node #{node.id} should now have no tags"
|
||||
assert_equal 0, Way.find(way.id).tags.size, "way #{way.id} should now have no tags"
|
||||
assert_equal 0, Relation.find(relation.id).tags.size, "relation #{relation.id} should now have no tags"
|
||||
end
|
||||
|
||||
def test_invalid_compression
|
||||
user = create(:user)
|
||||
changeset = create(:changeset, :user => user)
|
||||
|
||||
# upload it
|
||||
post "/api/0.6/changeset/#{changeset.id}/upload",
|
||||
:params => "",
|
||||
:headers => {
|
||||
"HTTP_AUTHORIZATION" => format("Basic %s", Base64.encode64("#{user.display_name}:test")),
|
||||
"HTTP_CONTENT_ENCODING" => "unknown",
|
||||
"HTTP_CONTENT_TYPE" => "application/xml"
|
||||
}
|
||||
assert_response :unsupported_media_type
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def gzip_content(uncompressed)
|
||||
compressed = StringIO.new
|
||||
gz = Zlib::GzipWriter.new(compressed)
|
||||
gz.write(uncompressed)
|
||||
gz.close
|
||||
compressed.string
|
||||
end
|
||||
|
||||
def deflate_content(uncompressed)
|
||||
Zlib::Deflate.deflate(uncompressed)
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue