Class: Net::AJP13::Client

Inherits:
Object
  • Object
show all
Includes:
Constants
Defined in:
lib/net/ajp13/client.rb

Overview

AJP1.3 client

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(address, port = DEFAULT_PORT) ⇒ Client

Creates a new Net::AJP13::Client object for the specified address.

address

The FQDN of the servlet container to connect toe.

port

The port number to connect to.

This method does not open the TCP connection.



82
83
84
85
86
87
88
89
90
# File 'lib/net/ajp13/client.rb', line 82

def initialize(address, port = DEFAULT_PORT)
  @address = address
  @port = port || DEFAULT_PORT
  @state = nil

  @open_timeout = 30
  @read_timeout = 60
  @write_timeout = 60
end

Instance Attribute Details

#addressObject (readonly)

The host name to connect to.



97
98
99
# File 'lib/net/ajp13/client.rb', line 97

def address
  @address
end

#open_timeoutObject

Seconds to wait until connection is opened. If the Client object cannot open a connection in this many seconds, it raises a TimeoutError exception.



127
128
129
# File 'lib/net/ajp13/client.rb', line 127

def open_timeout
  @open_timeout
end

#portObject (readonly)

The port number to connect to.



99
100
101
# File 'lib/net/ajp13/client.rb', line 99

def port
  @port
end

#read_timeoutObject

Seconds to wait until reading one block (by one read(2) call). It raises a TimeoutError exception when timeout



131
132
133
# File 'lib/net/ajp13/client.rb', line 131

def read_timeout
  @read_timeout
end

#stateObject (readonly)

State of the TCP/AJP connection. The value is

nil

If neither TCP connection nor AJP session is opened.

:idle

If a TCP connection is opened but no request is being handled over the connection.

:assigned

If the TCP connection is opened and handling a specific request.



109
110
111
# File 'lib/net/ajp13/client.rb', line 109

def state
  @state
end

#write_timeoutObject

Seconds to wait until writing one block (by one write(2) call). It raises a TimeoutError exception when timeout



135
136
137
# File 'lib/net/ajp13/client.rb', line 135

def write_timeout
  @write_timeout
end

Class Method Details

.start(address, port = DEFAULT_PORT, &block) ⇒ Object

Creates a new Net::AJP13::Client object for the specified address, and opens its TCP connection and AJP session.

If the optional block is given, the newly created Net::AJP13::Client object is passed to it and closed when the block finishes.

When called with a block, returns the return value of the block; otherwise, returns the newly created Net::AJP13::Client object.

address

The FQDN of the servlet container to connect toe.

port

The port number to connect to.



173
174
175
# File 'lib/net/ajp13/client.rb', line 173

def self.start(address, port = DEFAULT_PORT, &block) # :yield: +ajp13+
  self.new(address, port).start(&block)
end

Instance Method Details

#ask_to_shutdownObject

Asks the application server to shut itself down.



195
196
197
198
199
200
201
202
203
# File 'lib/net/ajp13/client.rb', line 195

def ask_to_shutdown
  ensure_idling

  packet = Net::AJP13::Packet.new
  packet.direction = :to_app
  packet.append_byte SHUTDOWN

  packet.send_to(@socket)
end

#assigned?Boolean

returns true if the TCP connection is handling a specific request.

Returns:

  • (Boolean)


117
# File 'lib/net/ajp13/client.rb', line 117

def assigned?; @state == :assigned end

#body_chunk_packet(io, max_len) ⇒ Object

read a bytes from io, and returns BODY_CHUNK packet to send the bytes.



234
235
236
237
238
239
240
241
# File 'lib/net/ajp13/client.rb', line 234

def body_chunk_packet(io, max_len)
  chunk = io.eof? ? '' : io.readpartial(max_len)
  packet = Net::AJP13::Packet.new
  packet.direction = :to_app
  packet.append_integer chunk.length
  packet.append_bytes chunk
  packet
end

#finishObject

Closes TCP connection. Raises AJPStateError if not started.

Raises:

  • (Net::AJP13::AJPStateError)


179
180
181
182
183
# File 'lib/net/ajp13/client.rb', line 179

def finish
  raise Net::AJP13::AJPStateError, 'AJP session not yet started' unless @state
  @socket.close unless @socket.closed?
  @state = @socket = nil
end

#get(path, header = nil, &block) ⇒ Object

Equals #request(GetRequest.new(path, header)) in this version.



356
357
358
# File 'lib/net/ajp13/client.rb', line 356

def get(path, header = nil, &block)
  request(Net::AJP13::GetRequest.new(path, header), &block)
end

#idle?Boolean

returns true if the TCP connection is opened, but no request is being handled over the connection.

Returns:

  • (Boolean)


121
# File 'lib/net/ajp13/client.rb', line 121

def idle?; @state == :idle end

#inspectObject

:nodoc:



92
93
94
# File 'lib/net/ajp13/client.rb', line 92

def inspect #:nodoc:
  "#<#{self.class} #{@address}:#{@port} state=#{@state}>"
end

#pingObject

Sends ping message to the application server. Raises

IOError

if the TCP socket raises it.

TimeOutError


210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/net/ajp13/client.rb', line 210

def ping
  ensure_idling

  packet = Net::AJP13::Packet.new
  packet.direction = :to_app
  packet.append_byte CPING

  packet.send_to(@socket)

  packet = Net::AJP13::Packet.from_io(@socket)
  case packet.message_type
  when CPONG_REPLY
    return true
  when SEND_BODY_CHUNK, SEND_HEADERS, END_RESPONSE, GET_BODY_CHUNK
    raise Net::AJP13::AJPStateError, 
      "Unexpected packet type #{packet.message_type}"
  else
    raise Net::AJP13::AJPPacketError, 
      "Unrecognized packet type #{packet.message_type}"
  end
end

#post(path, body, header = nil, &block) ⇒ Object



360
361
362
363
364
365
366
367
# File 'lib/net/ajp13/client.rb', line 360

def post(path, body, header = nil, &block)
  post = Net::AJP13::PostRequest.new(path, header)
  if body.respond_to?(:read)
    post.body_stream = body
  else
    post.body = body
  end
end

#request(req) ⇒ Object

Sends req to the connected application server.

Returns a Net::AJP13::Reponse object, which represents the received response. Raises AJPStateError unless the session state is :idle.

If called with a block, yields each fragment of the entity body in turn as a string as it is read from the socket. Note that in this case, the returned response object may not contain a (meaningful) body.

If the application server says that the connection is not ‘reusable’, this method calls #finish after receiving the response.



257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
# File 'lib/net/ajp13/client.rb', line 257

def request(req) #:yields: +response_body_fragment+
  ensure_idling
  @state = :assigned

  begin
    req.protocol ||= 'HTTP/1.0'
    req['host'] ||= address
    req.server_port ||= 80

    if req.body
      req['content-length'] ||= req.body.length.to_s
	req['content-type'] ||= 'application/x-www-from-urlencoded'
	body_stream = StringIO.new(req.body)
    elsif req.body_stream
      if req['content-length']
 body_stream = req.body_stream
	else
 if req.body_stream.respond_to?(:length)
   req['content-length'] = req.body_stream.length.to_s
   body_stream = req.body_stream
 else
   body_stream = StringIO.new(req.body_stream.read)
   req['content-length'] = body_stream.length.to_s
 end
	end
	req['content-type'] ||= 'application/x-www-from-urlencoded'
    end
    
    req.send_to @socket
    packet = nil
    if body_stream
      # Mainly, for StringIO
      unless body_stream.respond_to?(:readpartial)
 class << body_stream
   alias_method :readpartial, :read
 end
	end

      chunk = 
 body_chunk_packet(body_stream, MAX_BODY_CHUNK_SIZE)
	chunk.send_to @socket

      loop do
        packet = Net::AJP13::Packet.from_io(@socket)
        case packet.message_type
        when GET_BODY_CHUNK
          required = packet.read_integer
   chunk = body_chunk_packet(body_stream, 
                             [required, MAX_BODY_CHUNK_SIZE].min)
   chunk.send_to @socket
          next
        when SEND_HEADERS
          break
        when SEND_BODY_CHUNK, END_RESPONSE
          raise Net::AJP13::AJPStateError, 'Unexpected state'
        else
          raise Net::AJP13::AJPPacketError, 
     "Unrecognized packet type : #{packet.message_type}"
        end
      end
    else
      packet = Net::AJP13::Packet.from_io(@socket) 
    end

    res = Net::AJP13::Response.from_packet(packet)
    loop do
      packet = Net::AJP13::Packet.from_io(@socket)
      case packet_type = packet.read_byte
      when GET_BODY_CHUNK, SEND_HEADERS
        raise AJPError, 'Unexpected state'
      when SEND_BODY_CHUNK
        len = packet.read_integer
        body = packet.read_bytes(len)
 terminator = packet.read_byte # TODO: This terminator is undocumented.
        # raise AJPError, 'Block packet' unless packet.eof?
        if block_given?
          yield body
        else
          res.body ||= ''
          res.body << body
        end
        next
      when END_RESPONSE
        is_reusable = packet.read_boolean
        finish unless is_reusable
        break
      else
        raise Net::AJP13::AJPPacketError, 
   "Unrecoginized packet type #{packet_type}"
      end
    end
  ensure
    @state = :idle
  end

  return res
end

#startObject

Opens TCP connection and AJP session. Raises IOError if already started.

When this method is called with block, gives a HTTP object to the block and closes the TCP connection after the block executed.

When called with a block, returns the return value of the block; otherwise, returns self.

Raises:

  • (IOError)


145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/net/ajp13/client.rb', line 145

def start #:yields: self if block given
  raise IOError, 'AJP session already opended' if @state
  Timeout.timeout(@open_timeout) {
    @socket = TCPSocket.new(address, port)
  }
  @state = :idle
  if block_given?
    begin
      return yield(self)
    ensure
      finish if started?
    end
  else
    return self
  end
end

#started?Boolean Also known as: active?

returns true if the TCP connection is opened.

Returns:

  • (Boolean)


112
# File 'lib/net/ajp13/client.rb', line 112

def started?; !!@state end