htcp 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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