htcp 0.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.
@@ -0,0 +1,5 @@
1
+ .DS_Store
2
+ doc
3
+ pkg
4
+ .yardoc
5
+ .idea
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2008-2010 Alexey Kovyrin
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
13
+ all 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
21
+ THE SOFTWARE.
@@ -0,0 +1,55 @@
1
+ = Ruby Implementation of the HTCP Protocol Client
2
+
3
+ This simple library implements HTCP protocol (http://www.htcp.org/) and could be used in any
4
+ Ruby project to manage any HTCP-compliant caching server (authors use it for Squid 2.7 servers
5
+ management).
6
+
7
+
8
+ == What commands are supported?
9
+
10
+ At this moment the only supported HTCP command is CLR that could be used to remove a cached
11
+ page from any HTCP-compliant server.
12
+
13
+
14
+ == How to install?
15
+
16
+ There are two options when approaching htcp-ruby installation:
17
+
18
+ * using the gem (recommended and could be used in non-Rails projects)
19
+ * install as a Rails plugin
20
+
21
+ To install as a gem in a Rails project, add this to your environment.rb:
22
+
23
+ config.gem 'htcp'
24
+
25
+ And then run the command:
26
+
27
+ sudo rake gems:install
28
+
29
+ To install loops as a Rails plugin you need to do the following:
30
+
31
+ ./script/plugin install git://github.com/kovyrin/htcp-ruby.git
32
+
33
+ This will install the whole package in your vendor/plugins directory.
34
+ For merb applications, just check out the code and place it to the vendor/plugins directory.
35
+
36
+
37
+ == How to use?
38
+
39
+ Here is a simple code that could be used to purge a page from a caching server:
40
+
41
+ # Instantiate HTCP client
42
+ # It is possible to pass an array of servers to the constructor,
43
+ # in that case any request sent to the client will be sent out
44
+ # to all specified servers
45
+ htcp = Htcp::Client.new('cache01.local')
46
+
47
+ # Send CLR request and purge a page from the cache
48
+ htcp.clr("http://www.yoursite.com/some/page/url")
49
+
50
+
51
+ == Who are the authors?
52
+
53
+ This plugin has been created in Scribd.com for our internal use and then the sources were opened for other
54
+ people to use. All the code in this package has been developed by Alexey Kovyrin for Scribd.com and is
55
+ released under the MIT license. For more details, see LICENSE file.
@@ -0,0 +1,16 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gemspec|
4
+ gemspec.name = 'htcp'
5
+ gemspec.summary = 'HTCP Protocol Client implemented in Ruby'
6
+ gemspec.description = 'This simple library implements HTCP protocol (www.htcp.org/) and could be used in any Ruby project to manage any HTCP-compliant caching server (authors use it for Squid 2.7 servers management).'
7
+ gemspec.email = 'alexey@kovyrin.net'
8
+ gemspec.homepage = 'http://github.com/kovyrin/htcp-ruby'
9
+ gemspec.rubyforge_project = 'htcp'
10
+ gemspec.authors = ['Alexey Kovyrin']
11
+ gemspec.files.include ['lib/**/*']
12
+ end
13
+ Jeweler::GemcutterTasks.new
14
+ rescue LoadError
15
+ puts 'Jeweler not available. Install it with: sudo gem install jeweler'
16
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.2
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ puts "TBD"
@@ -0,0 +1,64 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{htcp}
8
+ s.version = "0.0.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Alexey Kovyrin"]
12
+ s.date = %q{2010-05-29}
13
+ s.default_executable = %q{htcp-client}
14
+ s.description = %q{This simple library implements HTCP protocol (www.htcp.org/) and could be used in any Ruby project to manage any HTCP-compliant caching server (authors use it for Squid 2.7 servers management).}
15
+ s.email = %q{alexey@kovyrin.net}
16
+ s.executables = ["htcp-client"]
17
+ s.extra_rdoc_files = [
18
+ "LICENSE",
19
+ "README.rdoc"
20
+ ]
21
+ s.files = [
22
+ ".gitignore",
23
+ "LICENSE",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "bin/htcp-client",
28
+ "htcp.gemspec",
29
+ "init.rb",
30
+ "lib/htcp.rb",
31
+ "lib/htcp/autoload.rb",
32
+ "lib/htcp/client.rb",
33
+ "lib/htcp/message/auth.rb",
34
+ "lib/htcp/message/base.rb",
35
+ "lib/htcp/message/constructor.rb",
36
+ "lib/htcp/message/data.rb",
37
+ "lib/htcp/message/header.rb",
38
+ "lib/htcp/message/op_data/clr.rb",
39
+ "lib/htcp/message/specifier.rb",
40
+ "spec/htcp/client_spec.rb",
41
+ "spec/spec_helper.rb"
42
+ ]
43
+ s.homepage = %q{http://github.com/kovyrin/htcp-ruby}
44
+ s.rdoc_options = ["--charset=UTF-8"]
45
+ s.require_paths = ["lib"]
46
+ s.rubyforge_project = %q{htcp}
47
+ s.rubygems_version = %q{1.3.6}
48
+ s.summary = %q{HTCP Protocol Client implemented in Ruby}
49
+ s.test_files = [
50
+ "spec/htcp/client_spec.rb",
51
+ "spec/spec_helper.rb"
52
+ ]
53
+
54
+ if s.respond_to? :specification_version then
55
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
56
+ s.specification_version = 3
57
+
58
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
59
+ else
60
+ end
61
+ else
62
+ end
63
+ end
64
+
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), 'lib/htcp')
@@ -0,0 +1,7 @@
1
+ module Htcp
2
+ # @return [String]
3
+ # a full path to the loops "lib" directory.
4
+ LIB_ROOT = File.expand_path(File.dirname(__FILE__)) unless const_defined?('LIB_ROOT')
5
+ end
6
+
7
+ require File.join(Htcp::LIB_ROOT, 'htcp/autoload')
@@ -0,0 +1,28 @@
1
+ module Htcp
2
+ module Autoload
3
+ # @private
4
+ def __p(*path) File.join(Htcp::LIB_ROOT, 'htcp', *path) end
5
+ end
6
+ extend Autoload
7
+
8
+ # Define autoloaded modules/classes
9
+ autoload :Client, __p('client')
10
+
11
+ module Message
12
+ extend Autoload
13
+
14
+ autoload :Base, __p('message/base')
15
+ autoload :Constructor, __p('message/constructor')
16
+
17
+ autoload :Auth, __p('message/auth')
18
+ autoload :Data, __p('message/data')
19
+ autoload :Header, __p('message/header')
20
+ autoload :Specifier, __p('message/specifier')
21
+
22
+ module OpData
23
+ extend Autoload
24
+
25
+ autoload :Clr, __p('message/op_data/clr')
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,40 @@
1
+ require 'socket'
2
+
3
+ module Htcp
4
+ class Client
5
+ DEFAULT_PORT = 4827
6
+
7
+ def initialize(*servers_list)
8
+ @servers = servers_list.flatten
9
+ end
10
+
11
+ def clr(url, headers = '')
12
+ message = Htcp::Message::Constructor.new(
13
+ :opcode => Htcp::Message::OpData::Clr::OP_CODE,
14
+ :rd => 0,
15
+ :trans_id => Time.now.to_i,
16
+ :op_data => Htcp::Message::OpData::Clr.new(:uri => url, :headers => headers)
17
+ )
18
+ send_messages(message)
19
+ end
20
+
21
+ private
22
+
23
+ def send_messages(message)
24
+ message = message.to_s
25
+ @servers.each { |s| send_message(s, message) }
26
+ end
27
+
28
+ def send_message(server, message)
29
+ host, port = parse_server(server)
30
+ UDPSocket.new.send(message, 0, host, port)
31
+ end
32
+
33
+ def parse_server(server)
34
+ host, port = server.split(':')
35
+ port = port.to_i
36
+ port = DEFAULT_PORT if port.zero?
37
+ return host, port
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,13 @@
1
+ module Htcp
2
+ module Message
3
+ class Auth < Htcp::Message::Base
4
+ def initialize(params)
5
+ # Not implemented
6
+ end
7
+
8
+ def to_s
9
+ encode_int16(2)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,33 @@
1
+ module Htcp
2
+ module Message
3
+ class Base
4
+ # Put 16-bit int(s) to request.
5
+ def encode_int8(*ints)
6
+ request = ''
7
+ ints.each { |i| request << [i].pack('C') }
8
+ return request
9
+ end
10
+
11
+ # Put 16-bit int(s) to request.
12
+ def encode_int16(*ints)
13
+ request = ''
14
+ ints.each { |i| request << [i].pack('n') }
15
+ return request
16
+ end
17
+
18
+ # Put 32-bit int(s) to request.
19
+ def encode_int32(*ints)
20
+ request = ''
21
+ ints.each { |i| request << [i].pack('N') }
22
+ return request
23
+ end
24
+
25
+ # Put string(s) to request (first length, then the string itself).
26
+ def encode_string(*strings)
27
+ request = ''
28
+ strings.each { |s| request << encode_int16(s.length) + s }
29
+ return request
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,17 @@
1
+ module Htcp
2
+ module Message
3
+ class Constructor
4
+ def initialize(params)
5
+ @header = Htcp::Message::Header.new(params[:head] || {})
6
+ @data = Htcp::Message::Data.new(params[:data] || params)
7
+ @auth = Htcp::Message::Auth.new(params[:auth] || {})
8
+ end
9
+
10
+ def to_s
11
+ payload = @data.to_s + @auth.to_s
12
+ @header.payload_len = payload.length
13
+ @header.to_s + payload
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,27 @@
1
+ module Htcp
2
+ module Message
3
+ class Data < Htcp::Message::Base
4
+ def initialize(params)
5
+ @params = params
6
+ end
7
+
8
+ def to_s
9
+ # Process data fields
10
+ rr = @params[:response] ? 1 : 0
11
+ response_code = @params[:response] || 0
12
+ f1 = (rr.zero?) ? @params[:rd] : @params[:mo]
13
+
14
+ # Compose request
15
+ request = ''
16
+
17
+ request << encode_int8(response_code << 4 | @params[:opcode])
18
+ request << encode_int8((f1 << 1) | rr)
19
+ request << encode_int32(@params[:trans_id])
20
+ request << @params[:op_data].to_s
21
+
22
+ # Encode request with string
23
+ encode_int16(request.length + 2) + request
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,20 @@
1
+ module Htcp
2
+ module Message
3
+ class Header < Htcp::Message::Base
4
+ attr_accessor :payload_len
5
+
6
+ def initialize(params)
7
+ @params = {
8
+ :major => 0,
9
+ :minor => 0
10
+ }.merge(params)
11
+
12
+ @payload_len = 0
13
+ end
14
+
15
+ def to_s
16
+ encode_int16(@payload_len + 4) + encode_int8(@params[:major], @params[:minor])
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ module Htcp
2
+ module Message
3
+ module OpData
4
+ class Clr < Htcp::Message::Base
5
+ OP_CODE = 4
6
+
7
+ def initialize(params)
8
+ @specifier = Htcp::Message::Specifier.new(params)
9
+ end
10
+
11
+ def to_s
12
+ encode_int16(0) + @specifier.to_s
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ module Htcp
2
+ module Message
3
+ class Specifier < Htcp::Message::Base
4
+ def initialize(params)
5
+ @params = params
6
+ end
7
+
8
+ def to_s
9
+ request = ''
10
+
11
+ request << encode_string(@params[:method] || 'GET')
12
+ request << encode_string(@params[:uri])
13
+ request << encode_string(@params[:version] || 'HTTP/1.1')
14
+ request << encode_string(@params[:headers] || '')
15
+
16
+ return request
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe Htcp::Client do
4
+ context "in constructor" do
5
+ it "should accept one server" do
6
+ Htcp::Client.new('foo')
7
+ end
8
+
9
+ it "should accept a list of servers" do
10
+ Htcp::Client.new('foo', 'bar')
11
+ end
12
+
13
+ it "should accept an array of servers" do
14
+ Htcp::Client.new(['foo', 'bar'])
15
+ end
16
+
17
+ it "should accept alist of arrays of servers" do
18
+ Htcp::Client.new(['foo', 'bar'], 'baz', ['blah'])
19
+ end
20
+ end
21
+
22
+ context "in parse_server method" do
23
+ before do
24
+ @htcp = Htcp::Client.new('foo')
25
+ end
26
+
27
+ it "should accept a 'host:port' server format" do
28
+ @htcp.send(:parse_server, 'foo:123').should == [ 'foo', 123 ]
29
+ end
30
+
31
+ it "should accept a 'host' server format" do
32
+ @htcp.send(:parse_server, 'foo').should == [ 'foo', Htcp::Client::DEFAULT_PORT ]
33
+ end
34
+
35
+ it "should accept a 'host:invalid_port' server format" do
36
+ @htcp.send(:parse_server, 'foo:blah').should == [ 'foo', Htcp::Client::DEFAULT_PORT ]
37
+ end
38
+ end
39
+
40
+ context "in clr method" do
41
+ before do
42
+ @htcp = Htcp::Client.new('127.0.0.1')
43
+ end
44
+
45
+ context "when called without additional headers" do
46
+ it "should compose a CLR request and try to send it out" do
47
+ @htcp.should_receive(:send_messages)
48
+ @htcp.clr('http://www.blah.com/foo/bar?baz=blah')
49
+ end
50
+ end
51
+
52
+ context "when called with additional headers" do
53
+ it "should compose a CLR request and try to send it out" do
54
+ @htcp.should_receive(:send_messages)
55
+ @htcp.clr('http://www.blah.com/foo/bar?baz=blah', 'Foo: bar')
56
+ end
57
+ end
58
+ end
59
+
60
+ context "in send_message method" do
61
+ it "should send the message out to one server when only one server specified" do
62
+ htcp = Htcp::Client.new('127.0.0.1')
63
+ htcp.should_receive(:send_message).once
64
+ htcp.clr('http://www.blah.com/foo/bar?baz=blah')
65
+ end
66
+
67
+ it "should send the message out to all servers when many servers specified" do
68
+ htcp = Htcp::Client.new('127.0.0.1', '127.0.0.2')
69
+ htcp.should_receive(:send_message).twice
70
+ htcp.clr('http://www.blah.com/foo/bar?baz=blah')
71
+ end
72
+ end
73
+ end
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(File.dirname(__FILE__)), 'lib', 'htcp')
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: htcp
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 2
9
+ version: 0.0.2
10
+ platform: ruby
11
+ authors:
12
+ - Alexey Kovyrin
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-05-29 00:00:00 -04:00
18
+ default_executable: htcp-client
19
+ dependencies: []
20
+
21
+ description: This simple library implements HTCP protocol (www.htcp.org/) and could be used in any Ruby project to manage any HTCP-compliant caching server (authors use it for Squid 2.7 servers management).
22
+ email: alexey@kovyrin.net
23
+ executables:
24
+ - htcp-client
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - LICENSE
29
+ - README.rdoc
30
+ files:
31
+ - .gitignore
32
+ - LICENSE
33
+ - README.rdoc
34
+ - Rakefile
35
+ - VERSION
36
+ - bin/htcp-client
37
+ - htcp.gemspec
38
+ - init.rb
39
+ - lib/htcp.rb
40
+ - lib/htcp/autoload.rb
41
+ - lib/htcp/client.rb
42
+ - lib/htcp/message/auth.rb
43
+ - lib/htcp/message/base.rb
44
+ - lib/htcp/message/constructor.rb
45
+ - lib/htcp/message/data.rb
46
+ - lib/htcp/message/header.rb
47
+ - lib/htcp/message/op_data/clr.rb
48
+ - lib/htcp/message/specifier.rb
49
+ - spec/htcp/client_spec.rb
50
+ - spec/spec_helper.rb
51
+ has_rdoc: true
52
+ homepage: http://github.com/kovyrin/htcp-ruby
53
+ licenses: []
54
+
55
+ post_install_message:
56
+ rdoc_options:
57
+ - --charset=UTF-8
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ segments:
65
+ - 0
66
+ version: "0"
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ requirements: []
75
+
76
+ rubyforge_project: htcp
77
+ rubygems_version: 1.3.6
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: HTCP Protocol Client implemented in Ruby
81
+ test_files:
82
+ - spec/htcp/client_spec.rb
83
+ - spec/spec_helper.rb