icaprb-server 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE +11 -0
- data/README.md +50 -0
- data/README.rdoc +34 -0
- data/Rakefile +17 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/bin/start_server.rb +36 -0
- data/icaprb-server.gemspec +23 -0
- data/lib/icaprb/icapuri.rb +24 -0
- data/lib/icaprb/server/constants.rb +83 -0
- data/lib/icaprb/server/data_structures.rb +182 -0
- data/lib/icaprb/server/request_parser.rb +295 -0
- data/lib/icaprb/server/response.rb +168 -0
- data/lib/icaprb/server/services.rb +241 -0
- data/lib/icaprb/server/version.rb +6 -0
- data/lib/icaprb/server.rb +211 -0
- metadata +107 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c29df2175284d6033e5651bfa7cd4c31b4b22a8b
|
4
|
+
data.tar.gz: eb49631c989580e438dbe18a8f8b64e2f2e5121c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c9172a8ea5df5842fab74ed6d2b21ad1b72380882d36b8d1602ca0ec50655c576b89fad64ba6fe061dcfc7554a13c23c43e9d0f5a0fb769f18c63f0d563ce5f1
|
7
|
+
data.tar.gz: 6d8f06a8a04715fe4f3469ae060fe9975694119c5c5914b328b39bb7e3cdc731ab35238c2d0486ef9dee6e83a85ea78e1326aa8417f208c73c913772ce880f93
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
Copyright (c) 2016, Fabian Franz
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
5
|
+
|
6
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
7
|
+
|
8
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
9
|
+
|
10
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
11
|
+
|
data/README.md
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# ICAPrb::Server
|
2
|
+
|
3
|
+
Welcome to my projekt. I tried to implement the server part of the ICAP communication in [Ruby](https://www.ruby-lang.org/de/),
|
4
|
+
so the server configuration can load different things and the code may be changed at runtime (for example if you want a high uptime).
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'icaprb-server'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install icaprb-server
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
Getting your server running is really easy:
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
# require it
|
28
|
+
require "icaprb/server"
|
29
|
+
|
30
|
+
# create an instance of a server
|
31
|
+
s = ICAPrb::Server::ICAPServer.new
|
32
|
+
|
33
|
+
# add your services
|
34
|
+
s.services['echo'] = ICAPrb::Server::Services::EchoService.new
|
35
|
+
|
36
|
+
# and run it
|
37
|
+
s.run
|
38
|
+
|
39
|
+
```
|
40
|
+
|
41
|
+
## Development
|
42
|
+
|
43
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
44
|
+
|
45
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
46
|
+
|
47
|
+
## Contributing
|
48
|
+
|
49
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/fabianfrz/ICAPrb-Server, however I may not have enough time to provide fixes soon.
|
50
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
Welcome to my ICAP server
|
2
|
+
=========================
|
3
|
+
|
4
|
+
This server has been written as a semester project by Fabian Franz.
|
5
|
+
It is fully written in ruby, so it should run on any implementation of ruby in any version >= 2.0.0.
|
6
|
+
|
7
|
+
It is really easy to use it and create your own ICAP service and make it available for your proxy.
|
8
|
+
|
9
|
+
First of all you need an instance of ICAPrb::Server::ICAPServer, which does not need any parameters but can take a
|
10
|
+
hostname and a port, as well as some options which are requred for setting up logging or TLS.
|
11
|
+
The default is localhost on port 1344 which usually results in a binding of [::1]:1344 as IPv6
|
12
|
+
is preferred on modern systems.
|
13
|
+
|
14
|
+
When you created your server, you will have to add some +services+ by writing an instance of them in the services
|
15
|
+
property of the server, with the name as key.
|
16
|
+
|
17
|
+
When all your services are added to the server, you can simply start it by calling the "run" method.
|
18
|
+
Note, that run will +block+ the process and will run until the process is interrupted (for example by pressing ctrl + c).
|
19
|
+
|
20
|
+
---
|
21
|
+
|
22
|
+
You can write your own services by extending the ServiceBase class which is in ICAPrb::Server::Services.
|
23
|
+
Please look at the documentation of this class or just copy the EchoService and use it as a base for your own service.
|
24
|
+
|
25
|
+
---
|
26
|
+
|
27
|
+
Note: ICAP is a mighty tool and it can do good and evil things.
|
28
|
+
It could be illegal to use this kind of software in your country.
|
29
|
+
You are encuraged to check if this software and the services running on it are legal
|
30
|
+
and don't use this software in case it is not.
|
31
|
+
|
32
|
+
---
|
33
|
+
|
34
|
+
If you want to know more about ICAP, you should read the RFC 3507.
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
require 'rdoc/task'
|
4
|
+
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
|
7
|
+
RDoc::Task.new do |rdoc|
|
8
|
+
rdoc.main = 'README.rdoc'
|
9
|
+
rdoc.rdoc_files.include('README.rdoc', 'lib/**/*.rb')
|
10
|
+
end
|
11
|
+
|
12
|
+
desc 'search for undocumented things'
|
13
|
+
task :not_documented do
|
14
|
+
sh 'rdoc --dry-run -V 2> /dev/null | grep "(undocumented)" | sed -E "s/^\\s+//g"'
|
15
|
+
end
|
16
|
+
|
17
|
+
task :default => :spec
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "icaprb/server"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
include ICAPrb::Server
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/bin/start_server.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#
|
2
|
+
require "bundler/setup"
|
3
|
+
require "icaprb/server"
|
4
|
+
require 'logger'
|
5
|
+
include ICAPrb::Server
|
6
|
+
|
7
|
+
trap('SIGINT') { exit! 0 }
|
8
|
+
########################################################################
|
9
|
+
# DIFFERENT WAYS TO RUN THE SERVER #
|
10
|
+
########################################################################
|
11
|
+
|
12
|
+
# normal socket
|
13
|
+
#s = ICAPServer.new
|
14
|
+
# puts 'Server is running on port 1344. Press CTRL+C to exit...'
|
15
|
+
|
16
|
+
# squid v4 variant
|
17
|
+
#options = {secure: true,
|
18
|
+
# certificate: '../cert.pem',
|
19
|
+
# key: '../key.pem',
|
20
|
+
# tls_socket: true}
|
21
|
+
#s = ICAPServer.new('localhost',11344,options)
|
22
|
+
# puts 'Server is running on port 11344. Press CTRL+C to exit...'
|
23
|
+
|
24
|
+
# rfc 3507 variant
|
25
|
+
options = {secure: true,
|
26
|
+
certificate: '../cert.pem',
|
27
|
+
key: '../key.pem',
|
28
|
+
tls_socket: false}
|
29
|
+
s = ICAPServer.new('localhost',1344,options)
|
30
|
+
puts 'Server is running on port 1344. Press CTRL+C to exit...'
|
31
|
+
|
32
|
+
########################################################################
|
33
|
+
s.logger.level = Logger::INFO
|
34
|
+
s.services['echo'] = Services::EchoService.new
|
35
|
+
|
36
|
+
s.run
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'icaprb/server/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "icaprb-server"
|
8
|
+
spec.version = ICAPrb::Server::VERSION
|
9
|
+
spec.authors = ["Fabian Franz"]
|
10
|
+
spec.email = ["fabian.franz@students.fh-hagenberg.at"]
|
11
|
+
|
12
|
+
spec.summary = %q{This project includes an ICAP server fully implemented in Ruby but it does not include services.}
|
13
|
+
spec.homepage = "https://github.com/fabianfrz/ICAPrb-Server"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
16
|
+
spec.bindir = "exe"
|
17
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
21
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
22
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# = icaprb/server/icapuri.rb
|
2
|
+
# Author:: Fabian Franz
|
3
|
+
#
|
4
|
+
# See URI for general documentation
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'uri/generic'
|
8
|
+
|
9
|
+
module URI #:nodoc:
|
10
|
+
|
11
|
+
# Class to represent ICAP URIs
|
12
|
+
class ICAP < Generic
|
13
|
+
# The ICAP default port is 1344
|
14
|
+
DEFAULT_PORT = 1344
|
15
|
+
end
|
16
|
+
# Class to represent ICAP URIs
|
17
|
+
class ICAPS < Generic
|
18
|
+
# The ICAP default port is 11344
|
19
|
+
DEFAULT_PORT = 11344
|
20
|
+
end
|
21
|
+
|
22
|
+
@@schemes['ICAP'] = ICAP
|
23
|
+
@@schemes['ICAPS'] = ICAPS
|
24
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module ICAPrb
|
2
|
+
module Server
|
3
|
+
# Status Codes by IANA / RFC for HTTP
|
4
|
+
HTTP_STATUS_CODES =
|
5
|
+
{100=>'Continue',
|
6
|
+
101=>'Switching Protocols',
|
7
|
+
102=>'Processing',
|
8
|
+
200=>'OK',
|
9
|
+
201=>'Created',
|
10
|
+
202=>'Accepted',
|
11
|
+
203=>'Non-Authoritative Information',
|
12
|
+
204=>'No Content',
|
13
|
+
205=>'Reset Content',
|
14
|
+
206=>'Partial Content',
|
15
|
+
207=>'Multi-Status',
|
16
|
+
208=>'Already Reported',
|
17
|
+
226=>'IM Used',
|
18
|
+
300=>'Multiple Choices',
|
19
|
+
301=>'Moved Permanently',
|
20
|
+
302=>'Found',
|
21
|
+
303=>'See Other',
|
22
|
+
304=>'Not Modified',
|
23
|
+
305=>'Use Proxy',
|
24
|
+
306=>'Unused',
|
25
|
+
307=>'Temporary Redirect',
|
26
|
+
308=>'Permanent Redirect',
|
27
|
+
400=>'Bad Request',
|
28
|
+
401=>'Unauthorized',
|
29
|
+
402=>'Payment Required',
|
30
|
+
403=>'Forbidden',
|
31
|
+
404=>'Not Found',
|
32
|
+
405=>'Method Not Allowed',
|
33
|
+
406=>'Not Acceptable',
|
34
|
+
407=>'Proxy Authentication Required',
|
35
|
+
408=>'Request Timeout',
|
36
|
+
409=>'Conflict',
|
37
|
+
410=>'Gone',
|
38
|
+
411=>'Length Required',
|
39
|
+
412=>'Precondition Failed',
|
40
|
+
413=>'Payload Too Large',
|
41
|
+
414=>'URI Too Long',
|
42
|
+
415=>'Unsupported Media Type',
|
43
|
+
416=>'Range Not Satisfiable',
|
44
|
+
417=>'Expectation Failed',
|
45
|
+
421=>'Misdirected Request',
|
46
|
+
422=>'Unprocessable Entity',
|
47
|
+
423=>'Locked',
|
48
|
+
424=>'Failed Dependency',
|
49
|
+
425=>'Unassigned',
|
50
|
+
426=>'Upgrade Required',
|
51
|
+
427=>'Unassigned',
|
52
|
+
428=>'Precondition Required',
|
53
|
+
429=>'Too Many Requests',
|
54
|
+
430=>'Unassigned',
|
55
|
+
431=>'Request Header Fields Too Large',
|
56
|
+
451=>'Unavailable For Legal Reasons',
|
57
|
+
500=>'Internal Server Error',
|
58
|
+
501=>'Not Implemented',
|
59
|
+
502=>'Bad Gateway',
|
60
|
+
503=>'Service Unavailable',
|
61
|
+
504=>'Gateway Timeout',
|
62
|
+
505=>'HTTP Version Not Supported',
|
63
|
+
506=>'Variant Also Negotiates',
|
64
|
+
507=>'Insufficient Storage',
|
65
|
+
508=>'Loop Detected',
|
66
|
+
509=>'Unassigned',
|
67
|
+
510=>'Not Extended',
|
68
|
+
511=>'Network Authentication Required'}
|
69
|
+
# differences defined in RFC 3507
|
70
|
+
ICAP_STATUS_CODES = HTTP_STATUS_CODES.dup.merge(
|
71
|
+
{
|
72
|
+
100 => 'Continue after ICAP Preview',
|
73
|
+
204 => 'No modifications needed',
|
74
|
+
404 => 'ICAP Service not found',
|
75
|
+
405 => 'Method not allowed for service',
|
76
|
+
408 => 'Request timeout',
|
77
|
+
500 => 'Server error',
|
78
|
+
501 => 'Method not implemented',
|
79
|
+
503 => 'Service overloaded',
|
80
|
+
505 => 'ICAP version not supported by server'
|
81
|
+
})
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
# patch ruby strings
|
2
|
+
class String
|
3
|
+
# converts the string to a chunk (chunked encoding)
|
4
|
+
def to_chunk
|
5
|
+
length.to_s(16) + "\r\n" + self + "\r\n"
|
6
|
+
end
|
7
|
+
# extracts a ruby string from a chunk (chunked encoding)
|
8
|
+
def chunk_to_s
|
9
|
+
len_alpha = scan(/\A([\da-fA-F]+)\r\n/).first.first
|
10
|
+
len = len_alpha.to_i(16)
|
11
|
+
offset_data = len_alpha.length + 2 # 2 = CRLF
|
12
|
+
end_of_message = (offset_data+len)
|
13
|
+
str = self[offset_data...end_of_message]
|
14
|
+
raise 'Too many data in chunk' if end_of_message + 2 != length
|
15
|
+
str
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module ICAPrb
|
20
|
+
module Server
|
21
|
+
|
22
|
+
# This class is the base for the HTTP header classes. It is a subclass of +Hash+.
|
23
|
+
class HTTP_Header < Hash
|
24
|
+
|
25
|
+
# Converts the array to a +String+ and which will be the complete HTTP Header,
|
26
|
+
# witch contains the request or status line.
|
27
|
+
#
|
28
|
+
# It will join the headers with \r\n and ends with \r\n\r\n
|
29
|
+
def to_s
|
30
|
+
data = []
|
31
|
+
each do |key, value|
|
32
|
+
data << "#{key}: #{value}"
|
33
|
+
end
|
34
|
+
request_line + data.join("\r\n") + "\r\n\r\n"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# The +RequestHeader+ represents the header information of an HTTP request. It contains the status line as well as
|
39
|
+
# the other headers. The headers are accessible by the array access operator
|
40
|
+
class RequestHeader < HTTP_Header
|
41
|
+
# the path requested by the user
|
42
|
+
attr_accessor :http_path
|
43
|
+
# The HTTP Method (also known as Verb) as a String. For Example GET, POST, PUT, DELETE or OPTIONS
|
44
|
+
attr_accessor :http_method
|
45
|
+
# The HTTP version which is used by the application
|
46
|
+
attr_accessor :http_version
|
47
|
+
|
48
|
+
# Initializes a new Object of +RequestHeader+
|
49
|
+
# Params:
|
50
|
+
# +http_method+:: The HTTP Method (also known as Verb) as a String. For Example GET, POST, PUT, DELETE or OPTIONS
|
51
|
+
# +http_path+:: The Resource which has been requested by the user
|
52
|
+
# +http_version+:: The HTTP version which is used by the application
|
53
|
+
def initialize(http_method, http_path, http_version = '1.1')
|
54
|
+
@http_method = http_method
|
55
|
+
@http_path = http_path
|
56
|
+
@http_version = http_version
|
57
|
+
end
|
58
|
+
|
59
|
+
# The request header is always the first header and it can be included only once in an ICAP response
|
60
|
+
def <=>(value)
|
61
|
+
return 0 if value.class == RequestHeader
|
62
|
+
-1
|
63
|
+
end
|
64
|
+
|
65
|
+
# creates the request line for the request
|
66
|
+
# it will include the method, the path and the used http version.
|
67
|
+
def request_line
|
68
|
+
"#{@http_method} #{@http_path} HTTP/#{@http_version}\r\n"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# This class represents the +Body+ of an HTTP request. It has to come after the headers in ICAP messages.
|
73
|
+
# It will be used if the request contains data (usually POST)
|
74
|
+
#
|
75
|
+
# Use the << operator to concatenate the strings as + would return a string and your ICAP answer would fail.
|
76
|
+
class RequestBody < String
|
77
|
+
# true if we are in the preview
|
78
|
+
attr_accessor :ieof
|
79
|
+
|
80
|
+
# initializes a new RequestBody which is a String but has an ieof tag additionally.
|
81
|
+
def initialize (string, ieof = false)
|
82
|
+
super string
|
83
|
+
@ieof = ieof
|
84
|
+
end
|
85
|
+
# A body comes after the headers
|
86
|
+
def <=>(other)
|
87
|
+
case other
|
88
|
+
when RequestHeader
|
89
|
+
1
|
90
|
+
when ResponseHeader
|
91
|
+
1
|
92
|
+
when RequestBody
|
93
|
+
0
|
94
|
+
when ResponseBody
|
95
|
+
0
|
96
|
+
when NullBody
|
97
|
+
-1
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
# This class represents the +Header+ of an HTTP response. It includes the headers sent by the web server as well as
|
104
|
+
# the status line
|
105
|
+
class ResponseHeader < HTTP_Header
|
106
|
+
# Params:
|
107
|
+
# +http_version+:: is the version of http to use - usually 1.1
|
108
|
+
# +status_code+:: is the status code of the http protocol. For example 200 for OK
|
109
|
+
def initialize(http_version, status_code)
|
110
|
+
@http_version = http_version
|
111
|
+
@status_code = status_code
|
112
|
+
end
|
113
|
+
|
114
|
+
# creates the response line for the request
|
115
|
+
# it will contain the http version, the status code and the status text from HTTP_STATUS_CODES
|
116
|
+
def request_line
|
117
|
+
"HTTP/#{@http_version} #{@status_code} #{HTTP_STATUS_CODES[@status_code]}\r\n"
|
118
|
+
end
|
119
|
+
|
120
|
+
# The request header has to come first
|
121
|
+
def <=>(other)
|
122
|
+
case other
|
123
|
+
when RequestHeader
|
124
|
+
1
|
125
|
+
when ResponseHeader
|
126
|
+
0
|
127
|
+
else
|
128
|
+
-1
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# This class represents the response body which should be sent to the user.
|
134
|
+
# If it is missing, it could be replaced by a NullBody
|
135
|
+
class ResponseBody < String
|
136
|
+
# if it is in the preview, this will be true, otherwise nil or false
|
137
|
+
attr_accessor :ieof
|
138
|
+
|
139
|
+
# initializes a new RequestBody which is a String but has an ieof tag additionally.
|
140
|
+
def initialize(string, ieof = false)
|
141
|
+
super string
|
142
|
+
@ieof = ieof
|
143
|
+
end
|
144
|
+
|
145
|
+
# compare to sort within an array
|
146
|
+
# Response Bodies are usually at the end
|
147
|
+
def <=>(other)
|
148
|
+
case other
|
149
|
+
when RequestHeader
|
150
|
+
1
|
151
|
+
when ResponseHeader
|
152
|
+
1
|
153
|
+
when RequestBody
|
154
|
+
0
|
155
|
+
when ResponseBody
|
156
|
+
0
|
157
|
+
when NullBody
|
158
|
+
-1
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# The +NullBody+ is a Class to have an Body without content. It exists to let the ICAP client know, that there
|
164
|
+
# will not be any body for this HTTP request. This usually happens when a 204 No Content ist sent.
|
165
|
+
class NullBody
|
166
|
+
# Returns an empty +String+
|
167
|
+
def to_s
|
168
|
+
''
|
169
|
+
end
|
170
|
+
|
171
|
+
# It is always the last entry in ICAP responses.
|
172
|
+
def <=>(_)
|
173
|
+
1
|
174
|
+
end
|
175
|
+
|
176
|
+
# Show an empty string on the IRB instead of the object id, so it looks like a +ResponseBody+
|
177
|
+
def inspect
|
178
|
+
'""'
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|