httpray 1.0.2

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 40bd4048bb72f0169b178246b13b20f86504eba4
4
+ data.tar.gz: 28642af4d6aeb959c948d24e6fb122e17cccb197
5
+ SHA512:
6
+ metadata.gz: 5ea297d70ed2aaf3acf4dda9ad65248a0158a49340d509394c3ce7631497486ad930a035ad43a9b0686e26a6edae6886a20b36fa0828cbfdf7c37682bbb3bc3f
7
+ data.tar.gz: bb5d0f9279feeb73b69d2a13eb54ad0516ef7ff8bef36437a701761176cd66dec66c286daac11184e795bb747a0534e001a13335446f7dab6a1495cfd2b2d522
data/.gitignore ADDED
@@ -0,0 +1,54 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # Used by dotenv library to load environment variables.
14
+ # .env
15
+
16
+ ## Specific to RubyMotion:
17
+ .dat*
18
+ .repl_history
19
+ build/
20
+ *.bridgesupport
21
+ build-iPhoneOS/
22
+ build-iPhoneSimulator/
23
+
24
+ ## Specific to RubyMotion (use of CocoaPods):
25
+ #
26
+ # We recommend against adding the Pods directory to your .gitignore. However
27
+ # you should judge for yourself, the pros and cons are mentioned at:
28
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
29
+ #
30
+ # vendor/Pods/
31
+
32
+ ## Documentation cache and generated files:
33
+ /.yardoc/
34
+ /_yardoc/
35
+ /doc/
36
+ /rdoc/
37
+
38
+ ## Environment normalization:
39
+ /.bundle/
40
+ /vendor/bundle
41
+ /lib/bundler/man/
42
+
43
+ # for a library or gem, you might want to ignore these files since the code is
44
+ # intended to run in multiple environments; otherwise, check them in:
45
+ # Gemfile.lock
46
+ # .ruby-version
47
+ # .ruby-gemset
48
+
49
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
50
+ .rvmrc
51
+
52
+ # vim temp files
53
+ *.swp
54
+ *.un~
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 2.1.5
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,18 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ HTTPray (1.0.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+
10
+ PLATFORMS
11
+ ruby
12
+
13
+ DEPENDENCIES
14
+ HTTPray!
15
+ bundler (>= 1.2)
16
+
17
+ BUNDLED WITH
18
+ 1.13.6
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 G Gordon Worley III
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # httpray
2
+ Non-blocking HTTP library for Ruby
3
+
4
+ [![Gem Version](https://badge.fury.io/rb/HTTPray.svg)](https://badge.fury.io/rb/HTTPray)
5
+
6
+ Started out the same as the [fire-and-forget](https://github.com/mattetti/fire-and-forget) gem but with a more exposed interface, TLS support, and a better name. Added ideas from [tcp_timeout](https://github.com/lann/tcp-timeout-ruby) and accidentally ended up creating a light-weight, non-blocking HTTP client.
7
+
8
+ It differs from other Ruby HTTP libraries that support async because it doesn't use Threads, making HTTPray much less resource intensive to use since it instead directly implements HTTP/HTTPS 1.0 using `Socket` and `IO#select` for timeouts. You can optionally ask to be handed back the socket before it is closed in case you want to listen for a response, but that's not really what you're here for, and it creates a Fiber.
9
+
10
+ Great for use with sending data to HTTP endpoints for which you are willing to accept a UDP-style best-effort approach, but with the added guarantee of TCP that the packets made it to the server. Only the server will know what it did with the data, though!
11
+
12
+ ## Install
13
+
14
+ ```ruby
15
+ gem "httpray"
16
+ ```
17
+
18
+ ## Use
19
+
20
+ ```ruby
21
+ require 'httpray'
22
+
23
+ # def HTTParty.request!(method, uri, headers = {}, body = "", timeout = 1, ssl_context = nil)
24
+
25
+ # send an HTTP request and don't listen for the response
26
+ HTTPray.request(
27
+ "POST",
28
+ "https://your.diety/prayers",
29
+ {"Content-Type" => "application/prayer"},
30
+ "It's me, Margret",
31
+ 1) # timeout in seconds
32
+
33
+ # party with a response
34
+ HTTPray.request("GET", "https://your.diety/answered_prayers") do |socket|
35
+ socket.gets
36
+ end
37
+
38
+ # party dangerously (you have to close your own socket!)
39
+ socket = HTTPray.request!("GET", "https://your.diety/answered_prayers")
40
+ puts socket.gets
41
+ socket.close
42
+ ```
43
+
44
+ ## Help
45
+
46
+ HTTPray has minimal convenience and sanitization features because I didn't need them. All that it does is fill in the Host, User-Agent, Accept, and Content-Length headers for you. The body must be a string, so convert it yourself first. The URI can be a `URI` or a `String` that will go through `URI.parse`. You're welcome. You can also pass an `OpenSSL::SSL::SSLContext` if you want more control over how TLS is used, but if you don't provide one it will be created for you if needed.
47
+
48
+ Timeout support does not extend to the response since you just get back a `Socket`. You're own your own for how you want to handle that.
49
+
50
+ If you want it to be easier to use, feel free to submit pull requests. As long as you don't break existing functionality I will probably accept them.
51
+
52
+ ## Tests
53
+
54
+ There are some tests that exercise the code paths. You can run them with:
55
+
56
+ ```bash
57
+ ruby -I . test/httparty_test.rb
58
+ ```
59
+
60
+ Unfortunately they have to hit real network endpoints, so they won't work without a network.
data/httpray.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'httpray/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "httpray"
7
+ spec.version = HTTPray::VERSION
8
+ spec.authors = ["G Gordon Worley III"]
9
+ spec.email = ["gworley3@gmail.com"]
10
+ spec.description = %q{Fire-and-forget HTTP requests for Ruby}
11
+ spec.summary = %q{Like UDP but for HTTP over TCP}
12
+ spec.homepage = "https://github.com/gworley3/httpray"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.post_install_message = "HTT🙏 for mercy"
21
+ end
@@ -0,0 +1,3 @@
1
+ module HTTPray
2
+ VERSION = "1.0.2".freeze
3
+ end
data/lib/httpray.rb ADDED
@@ -0,0 +1,76 @@
1
+ require 'uri'
2
+ require 'openssl'
3
+ require 'socket'
4
+
5
+ require_relative 'httpray/version'
6
+
7
+ module HTTPray
8
+ class Timeout < StandardError; end
9
+
10
+ DEFAULT_HEADERS = {
11
+ "User-Agent" => "HTTPray #{VERSION}",
12
+ "Accept" => "*/*"
13
+ }.freeze
14
+
15
+ def self.request2!(method, uri, headers = {}, body = "", timeout = 1, ssl_context = nil)
16
+ uri = URI.parse(uri) unless URI === uri
17
+ address = Socket.getaddrinfo(uri.host, nil, Socket::AF_INET).first[3]
18
+ socket_address = Socket.pack_sockaddr_in(uri.port, address)
19
+
20
+ socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
21
+ socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
22
+
23
+ begin
24
+ socket.connect_nonblock(socket_address)
25
+ rescue Errno::EINPROGRESS
26
+ if IO.select(nil, [socket], [socket], timeout)
27
+ begin
28
+ socket.connect_nonblock(socket_address)
29
+ rescue Errno::EISCONN
30
+ # connected
31
+ end
32
+ else
33
+ raise Timeout
34
+ end
35
+ end
36
+
37
+ original_socket = socket
38
+ if uri.scheme == "https"
39
+ ssl_context ||= OpenSSL::SSL::SSLContext.new
40
+ socket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
41
+ socket.hostname = uri.host
42
+ socket.sync_close = true
43
+ socket.connect
44
+ end
45
+
46
+ headers = DEFAULT_HEADERS.merge(headers).merge(
47
+ "Host" => uri.host,
48
+ "Content-Length" => body.bytesize)
49
+
50
+ if IO.select(nil, [socket], [socket], 1)
51
+ socket.puts "#{method} #{uri.request_uri} HTTP/1.0\r\n"
52
+ headers.each do |header, value|
53
+ socket.puts "#{header}: #{value}\r\n"
54
+ end
55
+ socket.puts "\r\n"
56
+ socket.puts body
57
+
58
+ yield(socket) if block_given?
59
+ else
60
+ raise Timeout
61
+ end
62
+ return socket, original_socket
63
+ end
64
+
65
+ def self.request!(*args)
66
+ socket, _ = request2!(*args)
67
+ socket
68
+ end
69
+
70
+ def self.request(*args)
71
+ socket = request!(*args)
72
+ yield(socket) if block_given?
73
+ ensure
74
+ socket.close if socket && !socket.closed?
75
+ end
76
+ end
@@ -0,0 +1,56 @@
1
+ require 'minitest/autorun'
2
+ require 'lib/httpray'
3
+
4
+ class HTTPrayTest < MiniTest::Unit::TestCase
5
+ def test_request_timesout_with_bad_address
6
+ assert_raises HTTPray::Timeout do
7
+ HTTPray.request("GET", "httppppp://httpbin.org/status/200")
8
+ end
9
+ end
10
+ def test_request_sends
11
+ HTTPray.request("GET", "http://httpbin.org/get")
12
+ assert true
13
+ end
14
+ def test_request_receives_response
15
+ HTTPray.request("GET", "http://httpbin.org/status/200") do |socket|
16
+ assert_equal "HTTP/1.1 200 OK\r\n", socket.gets
17
+ end
18
+ end
19
+ def test_secure_request_sends
20
+ HTTPray.request("GET", "https://httpbin.org/get")
21
+ assert true
22
+ end
23
+ def test_all_options_accepted
24
+ HTTPray.request(
25
+ "POST",
26
+ "https://httpbin.org/post",
27
+ {"Content-Type" => "application/x-www-form-urlencoded"},
28
+ "q=httpray",
29
+ 5,
30
+ OpenSSL::SSL::SSLContext.new) do |socket|
31
+ assert_equal "HTTP/1.1 200 OK\r\n", socket.gets
32
+ end
33
+ end
34
+ def test_original_socket_closed_with_ssl
35
+ socket, original_socket = HTTPray.request2!(
36
+ "GET",
37
+ "https://httpbin.org/delay/10")
38
+ refute_same socket, original_socket
39
+ refute socket.closed?
40
+ refute original_socket.closed?
41
+ socket.close
42
+ assert socket.closed?
43
+ assert original_socket.closed?
44
+ end
45
+ def test_original_socket_closed_without_ssl
46
+ socket, original_socket = HTTPray.request2!(
47
+ "GET",
48
+ "http://httpbin.org/delay/10")
49
+ assert_same socket, original_socket
50
+ refute socket.closed?
51
+ refute original_socket.closed?
52
+ socket.close
53
+ assert socket.closed?
54
+ assert original_socket.closed?
55
+ end
56
+ end
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: httpray
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.2
5
+ platform: ruby
6
+ authors:
7
+ - G Gordon Worley III
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-07-14 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Fire-and-forget HTTP requests for Ruby
14
+ email:
15
+ - gworley3@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".gitignore"
21
+ - ".tool-versions"
22
+ - Gemfile
23
+ - Gemfile.lock
24
+ - LICENSE
25
+ - README.md
26
+ - httpray.gemspec
27
+ - lib/httpray.rb
28
+ - lib/httpray/version.rb
29
+ - test/httpray_test.rb
30
+ homepage: https://github.com/gworley3/httpray
31
+ licenses:
32
+ - MIT
33
+ metadata: {}
34
+ post_install_message: "HTT\U0001F64F for mercy"
35
+ rdoc_options: []
36
+ require_paths:
37
+ - lib
38
+ required_ruby_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ requirements: []
49
+ rubyforge_project:
50
+ rubygems_version: 2.2.2
51
+ signing_key:
52
+ specification_version: 4
53
+ summary: Like UDP but for HTTP over TCP
54
+ test_files:
55
+ - test/httpray_test.rb