Class: ICAPrb::Server::Services::ServiceBase
- Inherits:
-
Object
- Object
- ICAPrb::Server::Services::ServiceBase
- Includes:
- Parser::ChunkedEncodingHelper
- Defined in:
- lib/icaprb/server/services.rb
Overview
Base class for ICAP services
Direct Known Subclasses
Instance Attribute Summary collapse
-
#counter ⇒ Object
readonly
the counter is used to determine if too many connections are opened by the proxy.
-
#is_tag ⇒ Object
The IS-Tag is a required header.
-
#max_connections ⇒ Object
Maximum amount of concurrent connections per IP.
-
#options_ttl ⇒ Object
send the ttl via options header - the options are valid for the given time.
-
#preview_size ⇒ Object
The preview size has to be set if the server supports previews.
-
#service_id ⇒ Object
If you want to send a service id header to the
ICAPclient, you can set it here. -
#service_name ⇒ Object
the name of the service which is used in the response header (Service-Name).
-
#supported_methods ⇒ Object
the supported methods for this service.
-
#timeout ⇒ Object
timeout for the service.
-
#transfer_complete ⇒ Object
Arrayof file extensions which should be always sent to theICAPserver (no preview). -
#transfer_ignore ⇒ Object
Arrayof file extensions which should not be sent to theICAPserver (not even a preview). -
#transfer_preview ⇒ Object
Arrayof file extensions which need a preview sent to theICAPserver (do not send the full file in advance).
Instance Method Summary collapse
-
#do_process(server, ip, io, data) ⇒ Object
this method is called by the server when it receives a new ICAP request it will increase the counter by one, call process_request and decreases the counter by one.
-
#enter(ip) ⇒ Object
when the connection enters this method will increase the counter.
-
#generate_options_response(io) ⇒ Object
This method is called by the server when the client sends an options request which is not a mandatory upgrade.
-
#get_the_rest_of_the_data(io) ⇒ Object
When we get a preview, we can answer it or request the rest of the data.
-
#got_all_data?(data) ⇒ Boolean
returns true if we already got all data or if we are in a preview.
-
#initialize(service_name, supported_methods = [], preview_size = nil, options_ttl = 60, transfer_preview = nil, transfer_ignore = nil, transfer_complete = nil, max_connections = 100000) ⇒ ServiceBase
constructor
initialize a new service.
-
#leave(ip) ⇒ Object
when the request is answered we can allow the next one by decrementing the counter.
-
#process_request(_, _, _, _) ⇒ Object
- parameters: server
- reference to the icap server ip
- ip address of the peer socket
- socket to communicate data
-
the parsed request.
-
#set_generic_icap_headers(icap_header) ⇒ Object
set headers independently from the response type.
-
#supports_preview? ⇒ Boolean
returns if this service supports previews which means it can request the rest of the data if they are required.
Constructor Details
#initialize(service_name, supported_methods = [], preview_size = nil, options_ttl = 60, transfer_preview = nil, transfer_ignore = nil, transfer_complete = nil, max_connections = 100000) ⇒ ServiceBase
initialize a new service
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/icaprb/server/services.rb', line 46 def initialize(service_name,supported_methods = [], preview_size = nil, = 60, transfer_preview = nil, transfer_ignore = nil, transfer_complete = nil, max_connections = 100000) #TODO Work in progress; sort @service_name = service_name = @supported_methods = supported_methods @preview_size = preview_size @transfer_preview = transfer_preview @transfer_ignore = transfer_ignore @transfer_complete = transfer_complete @max_connections = max_connections @is_tag = nil @service_id = nil @timeout = nil @counter = {} end |
Instance Attribute Details
#counter ⇒ Object (readonly)
the counter is used to determine if too many connections are opened by the proxy. If this is the case, the the server answers with an error
41 42 43 |
# File 'lib/icaprb/server/services.rb', line 41 def counter @counter end |
#is_tag ⇒ Object
The IS-Tag is a required header. If you change it, the cache of the proxy will be flushed. You usually do not need to change this header. You may want to add your service name here.
35 36 37 |
# File 'lib/icaprb/server/services.rb', line 35 def is_tag @is_tag end |
#max_connections ⇒ Object
Maximum amount of concurrent connections per IP. The server will not accept more connections and answers with an error
32 33 34 |
# File 'lib/icaprb/server/services.rb', line 32 def max_connections @max_connections end |
#options_ttl ⇒ Object
send the ttl via options header - the options are valid for the given time
11 12 13 |
# File 'lib/icaprb/server/services.rb', line 11 def end |
#preview_size ⇒ Object
The preview size has to be set if the server supports previews. Otherwise use nil here. If your service supports previews
22 23 24 |
# File 'lib/icaprb/server/services.rb', line 22 def preview_size @preview_size end |
#service_id ⇒ Object
If you want to send a service id header to the ICAP client, you can set it here. Use nil to disable this header.
38 39 40 |
# File 'lib/icaprb/server/services.rb', line 38 def service_id @service_id end |
#service_name ⇒ Object
the name of the service which is used in the response header (Service-Name)
9 10 11 |
# File 'lib/icaprb/server/services.rb', line 9 def service_name @service_name end |
#supported_methods ⇒ Object
the supported methods for this service. This must be an Array which contains symbols. The values are:
- :request_mod
-
request mod is supported
- :response_mod
-
response mod is supported
Do not add :options - this would be wrong here!
19 20 21 |
# File 'lib/icaprb/server/services.rb', line 19 def supported_methods @supported_methods end |
#timeout ⇒ Object
timeout for the service
43 44 45 |
# File 'lib/icaprb/server/services.rb', line 43 def timeout @timeout end |
#transfer_complete ⇒ Object
Array of file extensions which should be always sent to the ICAP server (no preview)
24 25 26 |
# File 'lib/icaprb/server/services.rb', line 24 def transfer_complete @transfer_complete end |
#transfer_ignore ⇒ Object
Array of file extensions which should not be sent to the ICAP server (not even a preview)
26 27 28 |
# File 'lib/icaprb/server/services.rb', line 26 def transfer_ignore @transfer_ignore end |
#transfer_preview ⇒ Object
Array of file extensions which need a preview sent to the ICAP server (do not send the full file in advance)
29 30 31 |
# File 'lib/icaprb/server/services.rb', line 29 def transfer_preview @transfer_preview end |
Instance Method Details
#do_process(server, ip, io, data) ⇒ Object
this method is called by the server when it receives a new ICAP request it will increase the counter by one, call process_request and decreases the counter by one.
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/icaprb/server/services.rb', line 113 def do_process(server,ip,io,data) begin enter(ip) rescue Response.display_error_page(io,503,{'title' => 'ICAP Error', 'content' => 'Sorry, too much work for me', :http_version => '1.1', :http_status => 500}) return end begin unless @supported_methods.include? data[:icap_data][:request_line][:icap_method] Response.display_error_page(io,501,{'title' => 'Method not implemented', 'content' => 'I do not know what to do with that...', :http_version => '1.1', :http_status => 500}) return end if @timeout begin Timeout::timeout(@timeout) do process_request(server,ip,io,data) end rescue Timeout::Error => e # do not do a graceful shutdown of the connection as the client may fail server.logger.error e io.close end else process_request(server,ip,io,data) end rescue leave(ip) raise end leave(ip) end |
#enter(ip) ⇒ Object
when the connection enters this method will increase the counter. If the counter exceeds the limit, the request will be rejected
154 155 156 157 158 159 160 161 |
# File 'lib/icaprb/server/services.rb', line 154 def enter(ip) if @counter[ip] raise :connection_limit_exceeded unless (@counter[ip] < @max_connections) || @max_connections.nil? @counter[ip] += 1 else @counter[ip] = 1 end end |
#generate_options_response(io) ⇒ Object
This method is called by the server when the client sends an options request which is not a mandatory upgrade.
The data used here is set by the constructor and it should be configured when the Service is initialized.
Parameters: io the socket used to answer the request
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/icaprb/server/services.rb', line 176 def (io) response = ::ICAPrb::Server::Response.new response.components << ::ICAPrb::Server::NullBody.new methods = [] methods << 'REQMOD' if @supported_methods.include? :request_mod methods << 'RESPMOD' if @supported_methods.include? :response_mod response.icap_header['Methods'] = methods.join(', ') set_generic_icap_headers(response.icap_header) response.icap_header['Max-Connections'] = @max_connections if @max_connections response.icap_header['Options-TTL'] = if response.icap_header['Preview'] = @preview_size if @preview_size response.icap_header['Transfer-Ignore'] = @transfer_ignore.join(', ') if @transfer_ignore response.icap_header['Transfer-Complete'] = @transfer_complete.join(', ') if @transfer_complete response.icap_header['Transfer-Preview'] = @transfer_preview.join(', ') if @transfer_preview response.icap_header['Allow'] = '204' response.write_headers_to_socket io end |
#get_the_rest_of_the_data(io) ⇒ Object
When we get a preview, we can answer it or request the rest of the data. This method will send the status “100 Continue” to request the rest of the data and it will then request all the data which is left and returns this data as a single string.
You may want to concatenate it with the data you already got in the preview using the << operator.
WARNING: DO NOT CALL THIS METHOD IF YOU ARE NOT IN A PREVIEW!
102 103 104 105 106 107 108 109 |
# File 'lib/icaprb/server/services.rb', line 102 def get_the_rest_of_the_data(io) data = '' Response.continue(io) until (line,_ = read_chunk(io); line) && line == :eof data += line end return data end |
#got_all_data?(data) ⇒ Boolean
returns true if we already got all data or if we are in a preview. if we are not in a preview, the preview header is not present => outside of a preview and if the ieof is set, there is no data left - we have all data everything else means there is data left to request. NOTE: this will only work once! Do not request data after calling this method and call it again - you will get a false negative.
89 90 91 92 93 |
# File 'lib/icaprb/server/services.rb', line 89 def got_all_data?(data) return true unless data[:icap_data][:header]['Preview'] return true if data[:http_response_body].ieof return false end |
#leave(ip) ⇒ Object
when the request is answered we can allow the next one by decrementing the counter
164 165 166 |
# File 'lib/icaprb/server/services.rb', line 164 def leave(ip) @counter[ip] -= 1 end |
#process_request(_, _, _, _) ⇒ Object
parameters:
- server
-
reference to the icap server
- ip
-
ip address of the peer
- socket
-
socket to communicate
- data
-
the parsed request
69 70 71 |
# File 'lib/icaprb/server/services.rb', line 69 def process_request(_,_,_,_) raise :not_implemented end |
#set_generic_icap_headers(icap_header) ⇒ Object
set headers independently from the response type
parameters:
icap_header-
The hash which holds the ICAP headers.
198 199 200 201 202 |
# File 'lib/icaprb/server/services.rb', line 198 def set_generic_icap_headers(icap_header) icap_header['Service-Name'] = @service_name icap_header['ISTag'] = @is_tag if @is_tag icap_header['Service-ID'] = @service_id if @service_id end |
#supports_preview? ⇒ Boolean
returns if this service supports previews which means it can request the rest of the data if they are required. If you do not override this method, this will return false so you will get the complete request.
75 76 77 78 |
# File 'lib/icaprb/server/services.rb', line 75 def supports_preview? return false if @preview_size.nil? return preview_size >= 0 end |