rack-json_response_wrapper 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1b045582186350a205ba09cd1b9ef961283d4bda
4
+ data.tar.gz: 1bab96a3396b352f8c8149180a1b00da138aa996
5
+ SHA512:
6
+ metadata.gz: 8ec0543023c93957f5f78e54a78d674dda6cc98fe432f6fa69f0d15d7c1f6eaaab937be283a6fe5f44e13ba9790c61caa6679ba637d932e669f2e2daab7e4040
7
+ data.tar.gz: e21ce554077dc7f3e4c94c27e93f92bdaf9a765743c2b77ee013d3709009fce5a6d04034956f4d0fbfb92c6d9a736c3d5f3852f2a4faf6f6ce4fff250147b630
data/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <http://unlicense.org/>
@@ -0,0 +1,17 @@
1
+ rack-json_response_wrapper
2
+ ==========================
3
+
4
+ Rack Middleware for JSON APIs accessed cross-domain from legacy browsers
5
+
6
+ Firefox version 4 does not support response headers for cross-domain requests. This middleware intercepts all requests and if the X-WRAP-RESPONSE is set, the response will be wrappped in JSON as follows:
7
+
8
+ Suppose the following is the original response body:
9
+
10
+ {"key": "value"}
11
+
12
+ With X-WRAP-RESPONSE set to true, the new response will be:
13
+
14
+ {
15
+ "header": { ... bunch of headers ... },
16
+ "body": {"key": "value"}
17
+ }
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "bundler/setup"
3
+
4
+ task default: [:spec]
5
+
6
+ desc 'run rspec specs'
7
+ task :spec do
8
+ ENV['RACK_ENV'] ||= 'test'
9
+ sh 'rspec'
10
+ end
@@ -0,0 +1,62 @@
1
+ module Rack
2
+ class JsonResponseWrapper
3
+ def initialize(app)
4
+ @app = app
5
+ end
6
+
7
+ def call(env)
8
+ response = @app.call(env)
9
+
10
+ if should_wrap? env, response
11
+ wrap_response(response)
12
+ else
13
+ response
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def should_wrap?(env, response)
20
+ response_header = response[1]
21
+
22
+ is_json = response_header['Content-Type'].match(/application\/json/)
23
+ wants_wrap = env.include? 'X-WRAP-RESPONSE'
24
+
25
+ is_json && wants_wrap
26
+ end
27
+
28
+ def wrap_response(response)
29
+ response_body = response[2].reduce(&:concat)
30
+ response_header = response[1]
31
+
32
+ response_obj = JSON.parse(response_body)
33
+
34
+ wrapped_obj = {
35
+ header: response_header,
36
+ body: response_obj
37
+ }
38
+
39
+ # dump JSON to get new content length
40
+ wrapped_body = JSON.dump(wrapped_obj)
41
+
42
+ # when we change the content-length, the length will change.
43
+ # therefore, calculate the offset by comparing the length of the old vs. new
44
+ original_content_length = response_header['Content-Length']
45
+ new_content_length = wrapped_body.length
46
+ adjusted_content_length =
47
+ new_content_length.to_s.to_json.length - original_content_length.to_s.to_json.length
48
+
49
+ # adjust the new content-length by this offset
50
+ new_content_length += adjusted_content_length
51
+
52
+ # set the content length part of the header and redump the JSON
53
+ wrapped_obj[:header]['Content-Length'] = new_content_length.to_s
54
+ wrapped_body = JSON.dump(wrapped_obj)
55
+
56
+ wrapped = response.dup
57
+ wrapped[2] = [wrapped_body]
58
+
59
+ wrapped
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,64 @@
1
+ require 'json'
2
+ require_relative '../spec_helper'
3
+
4
+ describe Rack::JsonResponseWrapper do
5
+ include Rack::Test::Methods
6
+
7
+ class MockedApp < Sinatra::Base
8
+ post '/' do
9
+ content_type 'application/json'
10
+ JSON.dump(JSON.parse(request.body.read))
11
+ end
12
+
13
+ post '/html' do
14
+ content_type 'text/html'
15
+ JSON.dump(JSON.parse(request.body.read))
16
+ end
17
+ end
18
+
19
+ def app
20
+ @app ||= Rack::JsonResponseWrapper.new(MockedApp)
21
+ end
22
+
23
+ describe 'call' do
24
+ before do
25
+ @obj = { foo: true, bar: 1, baz: 'hoagie' }
26
+ @json = JSON.dump(@obj)
27
+ end
28
+
29
+ it 'does nothing to the response if X-WRAP-RESPONSE is not defined' do
30
+ post '/', @json
31
+
32
+ expect(last_response.body).to eq @json
33
+ end
34
+
35
+ it 'does nothing to the response if Content-Type is not json, even with X-WRAP-RESPONSE' do
36
+ post '/html', @json, 'X-WRAP-RESPONSE' => true
37
+
38
+ expect(last_response.body).to eq @json
39
+ end
40
+
41
+ it 'wraps the response if X-WRAP-RESPONSE is set' do
42
+ post '/', @json, 'X-WRAP-RESPONSE' => true
43
+
44
+ @response_obj = JSON.parse(last_response.body)
45
+
46
+ expect(@response_obj).to include 'header'
47
+ expect(@response_obj).to include 'body'
48
+
49
+
50
+ expect(JSON.dump(@response_obj['body'])).to eq @json
51
+ end
52
+
53
+ it 'when wrapping, includes response header in body' do
54
+ post '/', @json, 'X-WRAP-RESPONSE' => true
55
+
56
+ @response_obj = JSON.parse(last_response.body)
57
+ @response_header = last_response.header
58
+
59
+ @response_wrapped_header = @response_obj['header']
60
+
61
+ expect(JSON.dump(@response_wrapped_header)).to eq JSON.dump(@response_header)
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,9 @@
1
+ require 'rspec'
2
+ require 'rack/test'
3
+ require 'sinatra/base'
4
+
5
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'rack', 'json_response_wrapper.rb')
6
+
7
+ RSpec.configure do |config|
8
+ ENV['RACK_ENV'] ||= 'test'
9
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-json_response_wrapper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - g. nicholas d'andrea
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-08-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 3.0.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 3.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rack-test
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 0.6.2
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 0.6.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: sinatra
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 1.4.5
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 1.4.5
55
+ description: "Rack Middleware for JSON APIs accessed cross-domain from legacy browsers\n\nFirefox
56
+ version 4 does not support response headers for cross-domain requests.\nThis middleware
57
+ intercepts all requests and if the X-WRAP-RESPONSE is set, \nthe response will be
58
+ wrappped in JSON like {header: ..., body: ...}\n"
59
+ email: nick@gnidan.org
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - LICENSE
65
+ - README.md
66
+ - Rakefile
67
+ - lib/rack/json_response_wrapper.rb
68
+ - spec/rack/json_response_wrapper_spec.rb
69
+ - spec/spec_helper.rb
70
+ homepage: http://github.com/gnidan/rack-json_response_wrapper
71
+ licenses:
72
+ - Unlicense / Public Domain
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 2.2.2
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: Rack Middleware for JSON APIs accessed cross-domain from legacy browsers
94
+ test_files: []