<ppdoc>
<copyright>
    Copyright (c) 2001 by Addison Wesley Longman.  This
    material may be distributed only subject to the terms and
    conditions set forth in the Open Publication License, v1.0 or
    later (the latest version is presently available at
    http://www.opencontent.org/openpub/).
</copyright>
<chapter  ref="xref-000020" name="Network and Web Libraries">
<p/>
Ruby provides two levels of access to network services. At a low
level, you can access the basic socket support in the underlying
operating system, which allows you to implement clients and servers for
both connection-oriented and connectionless protocols. These are
documented in the next section.
<p/>
Ruby also has libraries that provide higher-level access to
specific application-level network protocols, such as FTP,
HTTP, and so on. These are documented starting
on page 482.
<p/>
Finally, the <classname>CGI</classname> libraries, documented beginning on page 497,
provide server-side developers with a
convenient interface for developing Web applications.
<section>Socket-Level Access</section>
<p/>
Sockets are the endpoints of a bidirectional communications
channel. Sockets may communicate within a process, between processes
on the same machine, or between processes on different
continents. Sockets may be implemented over a number of different
channel types: Unix domain sockets, TCP, UDP, and so on. The socket
library provides specific classes for handling the common transports
as well as a generic interface for handling the rest. All
functionality in the socket library is accessible through a single
extension library. Access it using
<p/>
<codefragment>
<alltt><fullcode><![CDATA[  require 'socket'
]]></fullcode>
require<nbsp/>'socket'
</alltt>
</codefragment>
<p/>
Sockets have their own vocabulary:
<p/>
<dl>
<dt>domain</dt><dd>  
  The family of protocols that will be used as the transport
  mechanism. These values are constants such as <tt>PF_INET</tt>, <tt>PF_UNIX</tt>,
  <tt>PF_X25</tt>, and so on.
</dd><dt>type</dt><dd>  
  The type of communications between the two endpoints, typically
  <tt>SOCK_STREAM</tt> for connection-oriented protocols and
  <tt>SOCK_DGRAM</tt> for connectionless protocols.
</dd><dt>protocol</dt><dd>  
  Typically zero, this may be used to identify a variant of a protocol 
  within a domain and type.
</dd><dt>hostName</dt><dd>  
  The identifier of a network interface:
  <ul>
  <li> a string, which can be a host name, a dotted-quad address, or
    an IPV6 address in colon (and possibly dot) notation,
  </li><li> the string ``&lt;broadcast&gt;'', which specifies an
    <tt>INADDR_BROADCAST</tt> address,
  </li><li> a zero-length string, which specifies <tt>INADDR_ANY</tt>, or
  </li><li> an <classname>Integer</classname>, interpreted as a binary address in host byte
    order.
  </li></ul>
</dd><dt>port</dt><dd>  
  (sometimes called <b>service</b>)
  Each server listens for clients calling on one or more ports.
  A port may be a <classname>Fixnum</classname> port number, a string containing a port number, or the
  name of a service.
</dd></dl>
<p/>
Sockets are children of class <classname>IO</classname>. Once a socket has been
successfully opened, the conventional I/O methods may be used. However, 
greater efficiency is sometimes obtained by using socket-specific
methods. As with other I/O classes, socket I/O blocks by default.
The hierarchy of the socket classes is shown in Figure
26.1 on page 471.
<p/>
For more information on the use of sockets, see your operating system
documentation. You'll also find a comprehensive treatment in
W. Richard Stevens,
<em>Unix Network Programming, Volumes 1 and
  2</em><nbsp/>.
<p/>
<class name="BasicSocket" super="IO" type="class" ref="xref-000001">  
  <classname>BasicSocket</classname> is an abstract base class for all other socket
  classes.
<p/>
  This class and its subclasses often manipulate addresses using
  something called a <tt>struct sockaddr</tt>,   which is effectively
  an opaque binary string.<footnote>In reality, it maps onto the
    underlying C-language <tt>struct sockaddr</tt> set of structures,
    documented in the man pages and in the books by Stevens.</footnote>
<p/>
  <methods type="class">
        <method name="do_not_reverse_lookup" ref="do_not_reverse_lookup">
      <callseq>
                BasicSocket.do_not_reverse_lookup <returns><const>true</const> or <const>false</const></returns>
      </callseq>
      <desc>
<p/>
      Returns the value of the global reverse lookup flag. If set to 
      <const>true</const>, queries on remote addresses will return the
      numeric address but not the host name.
<p/>
      </desc>
    </method>
<p/>
        <method name="do_not_reverse_lookup=" ref="do_not_reverse_lookup_eq">
      <callseq>
                BasicSocket.do_not_reverse_lookup = <const>true</const> or <const>false</const></callseq>
      <desc>
<p/>
      Sets the global reverse lookup flag.
<p/>
      </desc>
    </method>
<p/>
        <method name="lookup_order" ref="lookup_order">
      <callseq>
        BasicSocket.lookup_order
        <returns><obj>aFixnum</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the global address lookup order, one of:
<p/>
      <table>
<th>
  <td><b>Order</b></td>
  <td><b>Families Searched</b></td>
</th>
<tr>
  <td><tt>LOOKUP_UNSP</tt></td>
  <td><tt>AF_UNSPEC</tt></td>
</tr>
<tr>
  <td><tt>LOOKUP_INET</tt></td>
  <td><tt>AF_INET</tt>, <tt>AF_INET6</tt>, <tt>AF_UNSPEC</tt></td>
</tr>
<tr>
  <td><tt>LOOKUP_INET6</tt></td>
  <td><tt>AF_INET6</tt>, <tt>AF_INET</tt>, <tt>AF_UNSPEC</tt></td>
</tr>
<bottomrule/></table>
<p/>
      </desc>
    </method>
<p/>
        <method name="lookup_order=" ref="lookup_order_eq">
      <callseq>
        BasicSocket.lookup_order = <obj>aFixnum</obj>
      </callseq>
      <desc>
<p/>
      Sets the global address lookup order.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
  <methods type="instance">
        <method name="close_read" ref="close_read">
      <callseq>
        <obj>aSession</obj>.close_read <returns><tt>nil</tt></returns>
      </callseq>
      <desc>
<p/>
      Closes the readable connection on this socket.
<p/>
      </desc>
    </method>
<p/>
        <method name="close_write" ref="close_write">
      <callseq>
        <obj>aSession</obj>.close_write <returns><tt>nil</tt></returns>
      </callseq>
      <desc>
<p/>
      Closes the writable connection on this socket.
<p/>
      </desc>
    </method>
<p/>
        <method name="getpeername" ref="getpeername">
      <callseq>
        <obj>aSession</obj>.getpeername
        <returns><obj>aString</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the <tt>struct sockaddr</tt> structure associated with the
      other end of this socket connection.
<p/>
      </desc>
    </method>
<p/>
        <method name="getsockname" ref="getsockname">
      <callseq>
        <obj>aSession</obj>.getsockname
        <returns><obj>aString</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the <tt>struct sockaddr</tt> structure associated with <obj>aSession</obj>.
<p/>
      </desc>
    </method>
<p/>
        <method name="getsockopt" ref="getsockopt">
      <callseq>
        <obj>aSession</obj>.getsockopt( <obj>level</obj>,
        <obj>optname</obj> ) <returns><obj>aString</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the value of the specified option.
<p/>
      </desc>
    </method>
<p/>
        <method name="recv" ref="recv">
      <callseq>
        <obj>aSession</obj>.recv( <obj>len</obj>, <opt>, <obj>flags</obj></opt> )
        <returns><obj>aString</obj></returns>
      </callseq>
      <desc>
<p/>
      Receives up to <obj>len</obj> bytes from <obj>aSession</obj>.
<p/>
      </desc>
    </method>
<p/>
        <method name="send" ref="send">
      <callseq>
        <obj>aSession</obj>.send( <obj>aString</obj>, <obj>flags</obj>,
        <opt>, <obj>to</obj></opt> ) <returns><obj>aFixnum</obj></returns>
      </callseq>
      <desc>
<p/>
      Sends <obj>aString</obj> over <obj>aSession</obj>. If specified, <obj>to</obj> is a
      <tt>struct sockaddr</tt> specifying the recipient
      address. <obj>flags</obj> are the sum or one or more of the
      <tt>MSG_</tt> options (listed on page 478). Returns the
      number of characters sent.
<p/>
      </desc>
    </method>
<p/>
        <method name="setsockopt" ref="setsockopt">
      <callseq>
        <obj>aSession</obj>.setsockopt(
        <obj>level</obj>, <obj>optname</obj>, <obj>optval</obj> ) <returns>0</returns>
      </callseq>
      <desc>
<p/>
      Sets a socket option. <obj>level</obj> is one of the socket-level
      options (listed on page 478). <obj>optname</obj> and
      <obj>optval</obj> are protocol specific---see your system
      documentation for details.
<p/>
      </desc>
    </method>
<p/>
        <method name="shutdown" ref="shutdown">
      <callseq>
        <obj>aSession</obj>.shutdown( <obj>how</obj>=2 )
        <returns>0</returns>
      </callseq>
      <desc>
<p/>
      Shuts down the receive (<obj>how</obj> == 0), or send (<obj>how</obj> == 1),
      or both (<obj>how</obj> == 2), parts of this socket.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
</class>
<p/>
<class name="IPSocket" super="BasicSocket" type="class" ref="xref-000002">  
  Class <classname>IPSocket</classname> is a base class for sockets using IP as 
  their transport. <classname>TCPSocket</classname> and <classname>UDPSocket</classname> are based on this
  class.
<p/>
  <methods type="class">
        <method name="getaddress" ref="getaddress">
      <callseq>
        IPSocket.getaddress( <obj>hostName</obj> )
        <returns><obj>aString</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the dotted-quad IP address of <obj>hostName</obj>.
<p/>
<codefragment>
<fullcode><![CDATA[!- require 'socket'
        a = IPSocket.getaddress('www.ruby-lang.org')
        a
]]></fullcode><rubycode>
<tr>
<td colspan="3"><tt>a<nbsp/>=<nbsp/>IPSocket.getaddress('www.ruby-lang.org')</tt></td>
</tr>
<tr>
  <td><tt>a</tt></td>
  <td>&#187;</td>
  <td><tt>"210.251.121.214"</tt></td>
</tr>
</rubycode>
<p/>
</codefragment>
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
  <methods type="instance">
        <method name="addr" ref="addr">
      <callseq>
        <obj>aSession</obj>.addr <returns><obj>anArray</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the domain, port, name, and IP address of <obj>aSession</obj> as a
      four-element array. The name will be returned as an address if
      the <tt>do_not_reverse_lookup</tt> flag is <const>true</const>.
<p/>
<codefragment>
<fullcode><![CDATA[!-      require 'socket'
        u = UDPSocket.new
!-        u.bind('localhost', 8765)
#        u.bind('localhost', 8765)
        u.addr
        BasicSocket.do_not_reverse_lookup = true
        u.addr
]]></fullcode><rubycode>
<tr>
<td colspan="3"><tt>u<nbsp/>=<nbsp/>UDPSocket.new</tt></td>
</tr>
<tr>
<td colspan="3"><tt>u.bind('localhost',<nbsp/>8765)</tt></td>
</tr>
<tr>
  <td><tt>u.addr</tt></td>
  <td>&#187;</td>
  <td><tt>["AF_INET",<nbsp/>8765,<nbsp/>"localhost",<nbsp/>"127.0.0.1"]</tt></td>
</tr>
<tr>
<td colspan="3"><tt>BasicSocket.do_not_reverse_lookup<nbsp/>=<nbsp/>true</tt></td>
</tr>
<tr>
  <td><tt>u.addr</tt></td>
  <td>&#187;</td>
  <td><tt>["AF_INET",<nbsp/>8765,<nbsp/>"127.0.0.1",<nbsp/>"127.0.0.1"]</tt></td>
</tr>
</rubycode>
<p/>
</codefragment>
<p/>
      </desc>
    </method>
<p/>
        <method name="peeraddr" ref="peeraddr">
      <callseq>
        <obj>aSession</obj>.peeraddr <returns><obj>anArray</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the domain, port, name, and IP address of the peer.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
</class>
<p/>
<class name="TCPSocket" super="IPSocket" type="class" ref="xref-000003">  
<p/>
<codefragment>
<fullcode><![CDATA[!-    require 'socket'
    t = TCPSocket.new('localhost', 'ftp')
    t.gets
    t.close
]]></fullcode><rubycode>
<tr>
<td colspan="3"><tt>t<nbsp/>=<nbsp/>TCPSocket.new('localhost',<nbsp/>'ftp')</tt></td>
</tr>
<tr>
  <td><tt>t.gets</tt></td>
  <td>&#187;</td>
  <td><tt>"220<nbsp/>zip.local.thomases.com<nbsp/>FTP<nbsp/>server<nbsp/>(Version<nbsp/>6.5/OpenBSD,<nbsp/>linux<nbsp/>port<nbsp/>0.3.2)<nbsp/>ready.\r\n"</tt></td>
</tr>
<tr>
  <td><tt>t.close</tt></td>
  <td>&#187;</td>
  <td><tt>nil</tt></td>
</tr>
</rubycode>
<p/>
</codefragment>
<p/>
  <methods type="class">
        <method name="gethostbyname" ref="gethostbyname">
      <callseq>
        TCPSocket.gethostbyname(
        <obj>hostName</obj> ) <returns><obj>anArray</obj></returns>
      </callseq>
      <desc>
<p/>
      Looks up <obj>hostName</obj> and returns its canonical name, an array
      containing any aliases, the address
      type (<tt>AF_INET</tt>), and the dotted-quad IP address.
<p/>
<codefragment>
<fullcode><![CDATA[!- require 'socket'
        a = TCPSocket.gethostbyname('ns.pragprog.com')
        a
]]></fullcode><rubycode>
<tr>
<td colspan="3"><tt>a<nbsp/>=<nbsp/>TCPSocket.gethostbyname('ns.pragprog.com')</tt></td>
</tr>
<tr>
  <td><tt>a</tt></td>
  <td>&#187;</td>
  <td><tt>["pragprog.com",<nbsp/>[],<nbsp/>2,<nbsp/>"216.87.136.211"]</tt></td>
</tr>
</rubycode>
<p/>
</codefragment>
<p/>
      </desc>
    </method>
<p/>
        <method name="new" ref="new">
      <callseq>
        TCPSocket.new( <obj>hostName</obj>, <obj>port</obj> )
        <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
      Opens a TCP connection to <obj>hostName</obj> on the <obj>port</obj>.
<p/>
      </desc>
    </method>
<p/>
        <method name="open" ref="open">
      <callseq>
        TCPSocket.open( <obj>hostName</obj>, <obj>port</obj> )
        <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
      Synonym for <ccm><front>TCPSocket</front><back>new</back></ccm>.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
  <methods type="instance">
        <method name="recvfrom" ref="recvfrom">
      <callseq>
        <obj>aSession</obj>.recvfrom(
        <obj>len</obj> <opt>, <obj>flags</obj></opt> ) <returns><obj>anArray</obj></returns>
      </callseq>
      <desc>
<p/>
      Receives up to <obj>len</obj> bytes on the connection. <obj>flags</obj> is
      zero or more of the <tt>MSG_</tt> options (listed
      on page 478).
      Returns a two-element
      array. The first element is the received data, the second is an
      array containing information about the peer.
<p/>
<codefragment>
<alltt><fullcode><![CDATA[!-    require 'socket'
        t = TCPSocket.new('localhost', 'ftp')
        data = t.recvfrom(30)
        data
!-        t.close
]]></fullcode>
t<nbsp/>=<nbsp/>TCPSocket.new('localhost',<nbsp/>'ftp')
data<nbsp/>=<nbsp/>t.recvfrom(30)
data
</alltt>
</codefragment>
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
</class>
<p/>
<class name="SOCKSSocket" super="TCPSocket" type="class" ref="xref-000004">    
<p/>
  Class <classname>SOCKSSocket</classname> supports connections based on the SOCKS protocol.
  <methods type="class">
        <method name="new" ref="new">
      <callseq>
        SOCKSSocket.new( <obj>hostName</obj>, <obj>port</obj> )
        <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
      Opens a SOCKS connection to <obj>port</obj> on <obj>hostName</obj>.
<p/>
      </desc>
    </method>
<p/>
        <method name="open" ref="open">
      <callseq>
        SOCKSSocket.open( <obj>hostName</obj>, <obj>port</obj> )
        <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
      Synonym for <ccm><front>SOCKSSocket</front><back>new</back></ccm>.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
  <methods type="instance">
        <method name="close" ref="close">
      <callseq>
        <obj>aSession</obj>.close <returns><tt>nil</tt></returns>
      </callseq>
      <desc>
<p/>
      Closes this SOCKS connection.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
</class>
<p/>
<class name="TCPServer" super="TCPSocket" type="class" ref="xref-000005">    
  A <classname>TCPServer</classname> accepts incoming TCP connections. Here is a Web
  server that listens on a given port and returns the time.
<p/>
<codefragment>
<alltt><fullcode><![CDATA[    require 'socket'
    port = (ARGV[0] || 80).to_i
    server = TCPServer.new('localhost', port)
    while (session = server.accept)
      puts "Request: #{session.gets}"
      session.print "HTTP/1.1 200/OK\r\nContent-type: text/html\r\n\r\n"
      session.print "<html><body><h1>#{Time.now}</h1></body></html>\r\n"
      session.close
    end
]]></fullcode>
require<nbsp/>'socket'
port<nbsp/>=<nbsp/>(ARGV[0]<nbsp/>||<nbsp/>80).to_i
server<nbsp/>=<nbsp/>TCPServer.new('localhost',<nbsp/>port)
while<nbsp/>(session<nbsp/>=<nbsp/>server.accept)
<nbsp/><nbsp/>puts<nbsp/>"Request:<nbsp/>#{session.gets}"
<nbsp/><nbsp/>session.print<nbsp/>"HTTP/1.1<nbsp/>200/OK\r\nContent-type:<nbsp/>text/html\r\n\r\n"
<nbsp/><nbsp/>session.print<nbsp/>"&lt;html&gt;&lt;body&gt;&lt;h1&gt;#{Time.now}&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;\r\n"
<nbsp/><nbsp/>session.close
end
</alltt>
</codefragment>
<p/>
  <methods type="class">
        <method name="new" ref="new">
      <callseq>
        TCPServer.new( <opt><obj>hostName</obj>,</opt> <obj>port</obj> )
        <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
         Creates a new socket on the given
      interface (identified by <obj>hostName</obj> and port). If
      <obj>hostName</obj> is omitted, the server will listen on all
      interfaces on the current host (equivalent to an address of
      0.0.0.0).
<p/>
      </desc>
    </method>
<p/>
        <method name="open" ref="open">
      <callseq>
        TCPServer.open( <opt><obj>hostName</obj>,</opt> <obj>port</obj> )
        <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
      Synonym for <ccm><front>TCPServer</front><back>new</back></ccm>.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
  <methods type="instance">
        <method name="accept" ref="accept">
      <callseq>
        <obj>aSession</obj>.accept <returns><obj>aTCPSocket</obj></returns>
      </callseq>
      <desc>
<p/>
      Waits for a connection on <obj>aSession</obj>, and returns a new <classname>TCPSocket</classname> 
      connected to the caller. See the example 
      on page 474.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
</class>
<p/>
<class name="UDPSocket" super="IPSocket" type="class" ref="xref-000006">  
<p/>
  UDP sockets send and receive datagrams. In order to receive data, a
  socket must be bound to a particular port. You have two choices when 
  sending data: you can connect to a remote UDP socket and thereafter 
  send datagrams to that port, or you can specify a host and port for
  use with every packet you send. This example is a UDP server that
  prints the message it receives. It is called by both connectionless and
  connection-based clients.
<p/>
<codefragment>
<alltt><fullcode><![CDATA[    require 'socket'

    $port = 4321

    sThread = Thread.start do     # run server in a thread
      server = UDPSocket.open
      server.bind(nil, $port)
      2.times { p server.recvfrom(64) }
    end
    
    # Ad-hoc client
    UDPSocket.open.send("ad hoc", 0, 'localhost', $port)
    
    # Connection based client
    sock = UDPSocket.open
    sock.connect('localhost', $port)
    sock.send("connection-based", 0)
    sThread.join
]]></fullcode>
require<nbsp/>'socket'
<p/>
$port<nbsp/>=<nbsp/>4321
<p/>
sThread<nbsp/>=<nbsp/>Thread.start<nbsp/>do<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>#<nbsp/>run<nbsp/>server<nbsp/>in<nbsp/>a<nbsp/>thread
<nbsp/><nbsp/>server<nbsp/>=<nbsp/>UDPSocket.open
<nbsp/><nbsp/>server.bind(nil,<nbsp/>$port)
<nbsp/><nbsp/>2.times<nbsp/>{<nbsp/>p<nbsp/>server.recvfrom(64)<nbsp/>}
end
<p/>
#<nbsp/>Ad-hoc<nbsp/>client
UDPSocket.open.send("ad<nbsp/>hoc",<nbsp/>0,<nbsp/>'localhost',<nbsp/>$port)
<p/>
#<nbsp/>Connection<nbsp/>based<nbsp/>client
sock<nbsp/>=<nbsp/>UDPSocket.open
sock.connect('localhost',<nbsp/>$port)
sock.send("connection-based",<nbsp/>0)
sThread.join
</alltt>
</codefragment>
<em>produces:</em>
<codefragment><alltt>
["ad<nbsp/>hoc",<nbsp/>["AF_INET",<nbsp/>32893,<nbsp/>"localhost",<nbsp/>"127.0.0.1"]]
["connection-based",<nbsp/>["AF_INET",<nbsp/>32894,<nbsp/>"localhost",<nbsp/>"127.0.0.1"]]
</alltt>
</codefragment>
<p/>
  <methods type="class">
        <method name="new" ref="new">
      <callseq>
        UDPSocket.new( <obj>family</obj> = <tt>AF_INET</tt> )
        <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
      Creates an endpoint for UDP communications, optionally specifying 
      the address family.
<p/>
      </desc>
    </method>
<p/>
        <method name="open" ref="open">
      <callseq>
        UDPSocket.open( <obj>family</obj> = <tt>AF_INET</tt>
        )
        <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
      Synonym for <ccm><front>UDPSocket</front><back>new</back></ccm>.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
  <methods type="instance">
<p/>
        <method name="bind" ref="bind">
      <callseq>
        <obj>aSession</obj>.bind( <obj>hostName</obj>, <obj>port</obj> )
        <returns>0</returns>
      </callseq>
      <desc>
<p/>
      Associates the local end of the UDP connection with a given
      <obj>hostName</obj> and <obj>port</obj>. Must be used by servers to
      establish an accessible endpoint.
<p/>
      </desc>
    </method>
<p/>
        <method name="connect" ref="connect">
      <callseq>
        <obj>aSession</obj>.connect( <obj>hostName</obj>, <obj>port</obj> )
        <returns>0</returns>
      </callseq>
      <desc>
<p/>
      Creates a connection to the given <obj>hostName</obj> and <obj>port</obj>.
      Subsequent
      <cim><front>UDPSocket</front><back>send</back></cim> requests that don't override the recipient 
      will use this connection. Multiple <tt>connect</tt> requests may be
      issued on <obj>aSession</obj>: the most recent will be used by <tt>send</tt>.
<p/>
      </desc>
    </method>
<p/>
        <method name="recvfrom" ref="recvfrom">
      <callseq>
        <obj>aSession</obj>.recvfrom(
        <obj>len</obj> <opt>, <obj>flags</obj></opt> ) <returns><obj>anArray</obj></returns>
      </callseq>
      <desc>
<p/>
      Receives up to <obj>len</obj> bytes from <obj>aSession</obj>. <obj>flags</obj> is zero
      or more of the <tt>MSG_</tt> options (listed
      on page 478).
      The result is a two-element
      array containing the received data and information on the
      sender. See the example on page 475.
<p/>
      </desc>
    </method>
<p/>
        <method name="send" ref="send">
      <callseq>
                  <obj>aSession</obj>.send( <obj>aString</obj>, <obj>flags</obj> )
          <returns><obj>aFixnum</obj></returns><br/><obj>aSession</obj>.send( <obj>aString</obj>, <obj>flags</obj>, <obj>hostName</obj>, <obj>port</obj> )
          <returns><obj>aFixnum</obj></returns>
      </callseq>
      <desc>
<p/>
      The two-parameter form sends <obj>aString</obj> on an existing
      connection. The four-parameter form sends <obj>aString</obj> to
      <obj>port</obj> on <obj>hostName</obj>.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
</class>
<p/>
<class name="UNIXSocket" super="BasicSocket" type="class" ref="xref-000007">    
  Class <classname>UNIXSocket</classname> supports interprocess communications using the Unix 
  domain protocol. Although the underlying protocol supports both
  datagram and stream connections, the Ruby library provides only a
  stream-based connection.
<p/>
<codefragment>
<alltt><fullcode><![CDATA[    require 'socket'

    $path = "/tmp/sample"
!-    begin ; File.unlink($path) ; rescue ; end
    
    sThread = Thread.start do        # run server in a thread
      sock = UNIXServer.open($path)
      s1 = sock.accept
      p s1.recvfrom(124)
    end
    
    client = UNIXSocket.open($path)
    client.send("hello", 0)
    client.close
    
    sThread.join
]]></fullcode>
require<nbsp/>'socket'
<p/>
$path<nbsp/>=<nbsp/>"/tmp/sample"
<p/>
sThread<nbsp/>=<nbsp/>Thread.start<nbsp/>do<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>#<nbsp/>run<nbsp/>server<nbsp/>in<nbsp/>a<nbsp/>thread
<nbsp/><nbsp/>sock<nbsp/>=<nbsp/>UNIXServer.open($path)
<nbsp/><nbsp/>s1<nbsp/>=<nbsp/>sock.accept
<nbsp/><nbsp/>p<nbsp/>s1.recvfrom(124)
end
<p/>
client<nbsp/>=<nbsp/>UNIXSocket.open($path)
client.send("hello",<nbsp/>0)
client.close
<p/>
sThread.join
</alltt>
</codefragment>
<em>produces:</em>
<codefragment><alltt>
["hello",<nbsp/>["AF_UNIX",<nbsp/>""]]
</alltt>
</codefragment>
<p/>
  <methods type="class">
        <method name="new" ref="new">
      <callseq>
        UNIXSocket.new( <obj>path</obj> )
        <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
      Opens a new domain socket on <obj>path</obj>, which must be a pathname.
<p/>
      </desc>
    </method>
<p/>
        <method name="open" ref="open">
      <callseq>
        UNIXSocket.open( <obj>path</obj> )
        <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
      Synonym for <ccm><front>UNIXSocket</front><back>new</back></ccm>.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
  <methods type="instance">
        <method name="addr" ref="addr">
      <callseq>
        <obj>aSession</obj>.addr <returns><obj>anArray</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the address family and path of this socket.
<p/>
      </desc>
    </method>
<p/>
        <method name="path" ref="path">
      <callseq>
        <obj>aSession</obj>.path <returns><obj>aString</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the path of this domain socket.
<p/>
      </desc>
    </method>
<p/>
        <method name="peeraddr" ref="peeraddr">
      <callseq>
        <obj>aSession</obj>.peeraddr <returns><obj>anArray</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the address family and path of the server end of the connection.
<p/>
      </desc>
    </method>
<p/>
        <method name="recvfrom" ref="recvfrom">
      <callseq>
        <obj>aSession</obj>.recvfrom(
        <obj>len</obj> <opt>, <obj>flags</obj></opt> ) <returns><obj>anArray</obj></returns>
      </callseq>
      <desc>
<p/>
      Receives up to <obj>len</obj> bytes from <obj>aSession</obj>. <obj>flags</obj> is
      zero or more of the <tt>MSG_</tt> options (listed
      on page 478).
      The first element of the 
      returned array is the received data, and the second contains
      (minimal) information on the sender.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
</class>
<p/>
<class name="UNIXServer" super="UNIXSocket" type="class" ref="xref-000008">  
<p/>
  Class <classname>UNIXServer</classname> provides a simple Unix domain socket
  server. See <classname>UNIXSocket</classname> for example code.
<p/>
  <methods type="class">
        <method name="new" ref="new">
      <callseq>
        UNIXServer.new( <obj>path</obj> )
        <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
      Creates a server on the given <obj>path</obj>. The corresponding file 
      must not exist at the time of the call.
<p/>
      </desc>
    </method>
<p/>
        <method name="open" ref="open">
      <callseq>
        UNIXServer.open( <obj>path</obj> )
        <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
      Synonym for <ccm><front>UNIXServer</front><back>new</back></ccm>.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
  <methods type="instance">
        <method name="accept" ref="accept">
      <callseq>
        <obj>aSession</obj>.accept
        <returns><obj>aUnixSocket</obj></returns>
      </callseq>
      <desc>
<p/>
      Waits for a connection on the server socket and returns a new
      socket object for that connection. See the example for
      <classname>UNIXSocket</classname> on page 476.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
</class>
<p/>
<class name="Socket" super="BasicSocket" type="class" ref="xref-000009">  
<p/>
  Class <classname>Socket</classname> provides access to the underlying operating system
  socket implementation.  It can be used to provide more
  operating system-specific
  functionality than the protocol-specific socket classes, but at the
  expense of greater complexity. In particular, the class handles
  addresses using <tt>struct sockaddr</tt> structures packed into Ruby
  strings, which can be a joy to manipulate.
<p/>
  <noTableConstants>
  Class <classname>Socket</classname> defines constants for use throughout the socket
  library. Individual constants are available only on architectures
  that support the related facility.
<p/>
  <dl><dt>Types:</dt><dd><br/><tt>SOCK_DGRAM</tt>,
      <tt>SOCK_PACKET</tt>,
      <tt>SOCK_RAW</tt>,
      <tt>SOCK_RDM</tt>,
      <tt>SOCK_SEQPACKET</tt>,
      <tt>SOCK_STREAM</tt>.
<p/>
    </dd><dt>Protocol families:</dt><dd><br/><tt>PF_APPLETALK</tt>,
      <tt>PF_AX25</tt>,
      <tt>PF_INET6</tt>,
      <tt>PF_INET</tt>,
      <tt>PF_IPX</tt>,
      <tt>PF_UNIX</tt>,
      <tt>PF_UNSPEC</tt>.
<p/>
    </dd><dt>Address families:</dt><dd><br/><tt>AF_APPLETALK</tt>,
      <tt>AF_AX25</tt>,
      <tt>AF_INET6</tt>,
      <tt>AF_INET</tt>,
      <tt>AF_IPX</tt>,
      <tt>AF_UNIX</tt>,
      <tt>AF_UNSPEC</tt>.
<p/>
    </dd><dt>Lookup-order options:</dt><dd><br/><tt>LOOKUP_INET6</tt>,
      <tt>LOOKUP_INET</tt>,
      <tt>LOOKUP_UNSPEC</tt>.
<p/>
    </dd><dt>Send/receive options:</dt><dd><br/><tt>MSG_DONTROUTE</tt>,
      <tt>MSG_OOB</tt>,
      <tt>MSG_PEEK</tt>.
<p/>
    </dd><dt>Socket-level options:</dt><dd><br/><tt>SOL_ATALK</tt>,
      <tt>SOL_AX25</tt>,
      <tt>SOL_IPX</tt>,
      <tt>SOL_IP</tt>,
      <tt>SOL_SOCKET</tt>,
      <tt>SOL_TCP</tt>,
      <tt>SOL_UDP</tt>.
<p/>
    </dd><dt>Socket options:</dt><dd><br/><tt>SO_BROADCAST</tt>,
      <tt>SO_DEBUG</tt>,
      <tt>SO_DONTROUTE</tt>,
      <tt>SO_ERROR</tt>,
      <tt>SO_KEEPALIVE</tt>,
      <tt>SO_LINGER</tt>,
      <tt>SO_NO_CHECK</tt>,
      <tt>SO_OOBINLINE</tt>,
      <tt>SO_PRIORITY</tt>,
      <tt>SO_RCVBUF</tt>,
      <tt>SO_REUSEADDR</tt>,
      <tt>SO_SNDBUF</tt>,
      <tt>SO_TYPE</tt>.
<p/>
    </dd><dt>QOS options:</dt><dd><br/><tt>SOPRI_BACKGROUND</tt>,
      <tt>SOPRI_INTERACTIVE</tt>,
      <tt>SOPRI_NORMAL</tt>.
<p/>
    </dd><dt>Multicast options:</dt><dd><br/><tt>IP_ADD_MEMBERSHIP</tt>,
      <tt>IP_DEFAULT_MULTICAST_LOOP</tt>,
      <tt>IP_DEFAULT_MULTICAST_TTL</tt>,
      <tt>IP_MAX_MEMBERSHIPS</tt>,
      <tt>IP_MULTICAST_IF</tt>,
      <tt>IP_MULTICAST_LOOP</tt>,
      <tt>IP_MULTICAST_TTL</tt>.
<p/>
      </dd><dt>TCP options:</dt><dd><br/><tt>TCP_MAXSEG</tt>,
      <tt>TCP_NODELAY</tt>.
<p/>
      </dd><dt><tt>getaddrinfo</tt> error codes:</dt><dd><br/><tt>EAI_ADDRFAMILY</tt>,
      <tt>EAI_AGAIN</tt>,
      <tt>EAI_BADFLAGS</tt>,
      <tt>EAI_BADHINTS</tt>,
      <tt>EAI_FAIL</tt>,
      <tt>EAI_FAMILY</tt>,
      <tt>EAI_MAX</tt>,
      <tt>EAI_MEMORY</tt>,
      <tt>EAI_NODATA</tt>,
      <tt>EAI_NONAME</tt>,
      <tt>EAI_PROTOCOL</tt>,
      <tt>EAI_SERVICE</tt>,
      <tt>EAI_SOCKTYPE</tt>,
      <tt>EAI_SYSTEM</tt>.
<p/>
      </dd><dt><tt>ai_flags</tt> values:</dt><dd><br/><tt>AI_ALL</tt>,
      <tt>AI_CANONNAME</tt>,
      <tt>AI_MASK</tt>,
      <tt>AI_NUMERICHOST</tt>,
      <tt>AI_PASSIVE</tt>,
      <tt>AI_V4MAPPED_CFG</tt>.
    </dd></dl>
  </noTableConstants>
<p/>
  <methods type="class">
        <method name="for_fd" ref="for_fd">
      <callseq>
        Socket.for_fd( <obj>anFD</obj> )
        <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
      Wraps an already open file descriptor into a socket object.
<p/>
      </desc>
    </method>
<p/>
        <method name="getaddrinfo" ref="getaddrinfo">
      <callseq>
        Socket.getaddrinfo(
          <obj>hostName</obj>, <obj>port</obj>,<br/><opt><obj>family</obj>
            <opt><obj>socktype</obj> <opt><obj>protocol</obj> <opt><obj>flags</obj></opt></opt></opt></opt> )
          <returns><obj>anArray</obj></returns>
      </callseq>
      <desc>
<p/>
        Returns an array of arrays describing the given host and
        port (optionally qualified as shown). Each subarray
        contains the address family, port number, host name, host IP
        address, protocol family, socket type, and protocol.
<p/>
<codefragment>
<alltt><fullcode><![CDATA[!-        require 'socket'
#          for line in Socket.getaddrinfo('www.microsoft.com', 'http')
#            puts line.join(", ")
#          end
!-        puts "AF_INET, 80, microsoft.net, 207.46.130.149, 2, 1, 6"
!-        puts "AF_INET, 80, microsoft.net, 207.46.131.137, 2, 1, 6"
!-        puts "AF_INET, 80, microsoft.com, 207.46.230.218, 2, 1, 6"
!-        puts "AF_INET, 80, microsoft.com, 207.46.230.219, 2, 1, 6"
!-        puts "AF_INET, 80, microsoft.net, 207.46.130.14, 2, 1, 6"
]]></fullcode>
for<nbsp/>line<nbsp/>in<nbsp/>Socket.getaddrinfo('www.microsoft.com',<nbsp/>'http')
<nbsp/><nbsp/>puts<nbsp/>line.join(",<nbsp/>")
end
</alltt>
</codefragment>
<em>produces:</em>
<codefragment><alltt>
AF_INET,<nbsp/>80,<nbsp/>microsoft.net,<nbsp/>207.46.130.149,<nbsp/>2,<nbsp/>1,<nbsp/>6
AF_INET,<nbsp/>80,<nbsp/>microsoft.net,<nbsp/>207.46.131.137,<nbsp/>2,<nbsp/>1,<nbsp/>6
AF_INET,<nbsp/>80,<nbsp/>microsoft.com,<nbsp/>207.46.230.218,<nbsp/>2,<nbsp/>1,<nbsp/>6
AF_INET,<nbsp/>80,<nbsp/>microsoft.com,<nbsp/>207.46.230.219,<nbsp/>2,<nbsp/>1,<nbsp/>6
AF_INET,<nbsp/>80,<nbsp/>microsoft.net,<nbsp/>207.46.130.14,<nbsp/>2,<nbsp/>1,<nbsp/>6
</alltt>
</codefragment>
<p/>
      </desc>
    </method>
<p/>
        <method name="gethostbyaddr" ref="gethostbyaddr">
      <callseq>
        Socket.gethostbyaddr(
        <obj>addr</obj>, <obj>type</obj>=<tt>AF_INET</tt> )
        <returns><obj>anArray</obj></returns>
      </callseq>
      <desc>
              Returns the host name, address family, and <tt>sockaddr</tt> component
      for the given address.
<p/>
<codefragment>
<fullcode><![CDATA[!-        require 'socket'
        a = Socket.gethostbyname("216.87.136.211")
        res = Socket.gethostbyaddr(a[3], a[2])
        res.join(', ')
]]></fullcode><rubycode>
<tr>
<td colspan="3"><tt>a<nbsp/>=<nbsp/>Socket.gethostbyname("216.87.136.211")</tt></td>
</tr>
<tr>
<td colspan="3"><tt>res<nbsp/>=<nbsp/>Socket.gethostbyaddr(a[3],<nbsp/>a[2])</tt></td>
</tr>
<tr>
  <td><tt>res.join(',<nbsp/>')</tt></td>
  <td>&#187;</td>
  <td><tt>"pragprog.com,<nbsp/>,<nbsp/>2,<nbsp/>\330W\210\323"</tt></td>
</tr>
</rubycode>
<p/>
</codefragment>
<p/>
      </desc>
    </method>
<p/>
        <method name="gethostbyname" ref="gethostbyname">
      <callseq>
        Socket.gethostbyname( <obj>hostName</obj> )
        <returns><obj>anArray</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns a four-element array containing the canonical host name,
      a subarray of host aliases, the address family, and the address
      portion of the <tt>sockaddr</tt> structure.
<p/>
<codefragment>
<fullcode><![CDATA[!-        require 'socket'
        a = Socket.gethostbyname("216.87.136.211")
        a.join(', ')
]]></fullcode><rubycode>
<tr>
<td colspan="3"><tt>a<nbsp/>=<nbsp/>Socket.gethostbyname("216.87.136.211")</tt></td>
</tr>
<tr>
  <td><tt>a.join(',<nbsp/>')</tt></td>
  <td>&#187;</td>
  <td><tt>"pragprog.com,<nbsp/>,<nbsp/>2,<nbsp/>\330W\210\323"</tt></td>
</tr>
</rubycode>
<p/>
</codefragment>
<p/>
      </desc>
    </method>
<p/>
        <method name="gethostname" ref="gethostname">
      <callseq>
        <obj>aSession</obj>.gethostname
        <returns><obj>aString</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the name of the current host.
<p/>
      </desc>
    </method>
<p/>
        <method name="getnameinfo" ref="getnameinfo">
      <callseq>
        Socket.getnameinfo(
        <obj>addr</obj> <opt>, <obj>flags</obj></opt> )
        <returns><obj>anArray</obj></returns>
      </callseq>
      <desc>
<p/>
      Looks up the given address, which may be either a string
      containing a sockaddr or a three- or four-element array. If
      <obj>sockaddr</obj> is an array, it should contain the string address 
      family, the port (or nil), and the host name or IP address. If a 
      fourth element is present and not <tt>nil</tt>, it will be used as the host name.
      Returns a canonical hostname (or address) and port number as an array.
<p/>
<codefragment>
<fullcode><![CDATA[!-        require 'socket'
        a = Socket.getnameinfo(["AF_INET", '23', 'www.ruby-lang.org'])
        a
]]></fullcode><rubycode>
<tr>
<td colspan="3"><tt>a<nbsp/>=<nbsp/>Socket.getnameinfo(["AF_INET",<nbsp/>'23',<nbsp/>'www.ruby-lang.org'])</tt></td>
</tr>
<tr>
  <td><tt>a</tt></td>
  <td>&#187;</td>
  <td><tt>["helium.ruby-lang.org",<nbsp/>"telnet"]</tt></td>
</tr>
</rubycode>
<p/>
</codefragment>
<p/>
      </desc>
    </method>
<p/>
        <method name="getservbyname" ref="getservbyname">
      <callseq>
        Socket.getservbyname(
        <obj>service</obj>, <obj>proto</obj>=<tt>'tcp'</tt> )
        <returns><obj>aFixnum</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the port corresponding to the given service and
      protocol.
<p/>
<codefragment>
<fullcode><![CDATA[!-        require 'socket'
       Socket.getservbyname("telnet")
]]></fullcode><rubycode>
<tr>
  <td><tt>Socket.getservbyname("telnet")</tt></td>
  <td>&#187;</td>
  <td><tt>23</tt></td>
</tr>
</rubycode>
<p/>
</codefragment>
<p/>
      </desc>
    </method>
<p/>
        <method name="new" ref="new">
      <callseq>
        Socket.new( <obj>domain</obj>, <obj>type</obj>,
        <obj>protocol</obj> ) <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
      Creates a socket using the given parameters.
<p/>
      </desc>
    </method>
<p/>
        <method name="open" ref="open">
      <callseq>
        Socket.open( <obj>domain</obj>, <obj>type</obj>,
        <obj>protocol</obj> ) <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
      Synonym for <ccm><front>Socket</front><back>new</back></ccm>.
<p/>
      </desc>
    </method>
<p/>
        <method name="pair" ref="pair">
      <callseq>
        Socket.pair(  <obj>domain</obj>, <obj>type</obj>,
        <obj>protocol</obj> ) <returns><obj>anArray</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns a pair of connected, anonymous sockets of the given
      domain,  type, and protocol.
<p/>
      </desc>
    </method>
<p/>
        <method name="socketpair" ref="socketpair">
      <callseq>
        Socket.socketpair(  <obj>domain</obj>, <obj>type</obj>,
        <obj>protocol</obj> ) <returns><obj>anArray</obj></returns>
      </callseq>
      <desc>
<p/>
      Synonym for <ccm><front>Socket</front><back>pair</back></ccm>.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
  <methods type="instance">
        <method name="accept" ref="accept">
      <callseq>
        <obj>aSession</obj>.accept <returns><obj>anArray</obj></returns>
      </callseq>
      <desc>
<p/>
      Accepts an incoming connection returning an array containing a
      new <classname>Socket</classname> object and a string holding the <tt>struct
        sockaddr</tt> information about the caller.
<p/>
      </desc>
    </method>
<p/>
        <method name="bind" ref="bind">
      <callseq>
        <obj>aSession</obj>.bind( <obj>sockaddr</obj> )
        <returns>0</returns>
      </callseq>
      <desc>
<p/>
      Binds to the given <tt>struct sockaddr</tt>, contained in a string.
<p/>
      </desc>
    </method>
<p/>
        <method name="connect" ref="connect">
      <callseq>
        <obj>aSession</obj>.connect( <obj>sockaddr</obj> )
        <returns>0</returns>
      </callseq>
      <desc>
<p/>
      Connects to the given <tt>struct sockaddr</tt>, contained in a string.
<p/>
      </desc>
    </method>
<p/>
        <method name="listen" ref="listen">
      <callseq>
        <obj>aSession</obj>.listen( <obj>aFixnum</obj> )
        <returns>0</returns>
      </callseq>
      <desc>
<p/>
      Listens for connections, using the specified <obj>aFixnum</obj> as
      the backlog.
<p/>
      </desc>
    </method>
<p/>
        <method name="recvfrom" ref="recvfrom">
      <callseq>
        <obj>aSession</obj>.recvfrom(
        <obj>len</obj> <opt>, <obj>flags</obj></opt> ) <returns><obj>anArray</obj></returns>
      </callseq>
      <desc>
<p/>
      Receives up to <obj>len</obj> bytes from <obj>aSession</obj>. <obj>flags</obj> is
      zero or more of the <tt>MSG_</tt> options. The first element of the 
      result is the data received. The second element contains
      protocol-specific information on the sender.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
</class>
<p/>
<section>Higher-Level Access</section>
<p/>
Ruby provides a set of classes to facilitate writing clients for:
<ul>
<li> File Transfer Protocol (FTP)
</li><li> HyperText Transfer Protocol (HTTP)
</li><li> Post Office Protocol (POP)
</li><li> Simple Mail Transfer Protocol (SMTP)
</li><li> Telnet
</li></ul>
<p/>
HTTP, POP, and SMTP are layered on top of a helper class,
<tt>lib/net/protocol</tt>.  Although we don't document the <classname>Protocol</classname>
class here, you should probably study it if you are considering
writing your own network client.
<p/>
<class name="Net::FTP" super="Object" type="class" ref="xref-000010">  
<p/>
<codefragment>
<alltt><fullcode><![CDATA[      require 'net/ftp'
      
      ftp = Net::FTP.new('ftp.netlab.co.jp')
      ftp.login
      files = ftp.chdir('pub/lang/ruby/contrib')
      files = ftp.list('n*')
      ftp.getbinaryfile('nif.rb-0.91.gz', 'nif.gz', 1024)
      ftp.close
]]></fullcode>
require<nbsp/>'net/ftp'
<p/>
ftp<nbsp/>=<nbsp/>Net::FTP.new('ftp.netlab.co.jp')
ftp.login
files<nbsp/>=<nbsp/>ftp.chdir('pub/lang/ruby/contrib')
files<nbsp/>=<nbsp/>ftp.list('n*')
ftp.getbinaryfile('nif.rb-0.91.gz',<nbsp/>'nif.gz',<nbsp/>1024)
ftp.close
</alltt>
</codefragment>
<p/>
  The <tt>net/ftp</tt> library implements a File Transfer Protocol (FTP)
  client.
<p/>
  <constants>
<tr>
  <td><constant>
       <constname>FTP_PORT</constname>
       <constval></constval>
       <constdesc>Default port for FTP connections (21).</constdesc>
     </constant>
</td>
</tr>
</constants>
<p/>
  <methods type="class">
        <method name="new" ref="new">
      <callseq>
        FTP.new( <obj>host</obj>=<tt>nil</tt>,
        <obj>user</obj>=<tt>nil</tt>,
        <obj>passwd</obj>=<tt>nil</tt>,
        <obj>acct</obj>=<tt>nil</tt>) <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
      Creates and returns a new <classname>FTP</classname> object. If the host parameter is 
      not <tt>nil</tt>, a connection is made to that
      host. Additionally, if the <obj>user</obj> parameter is not <tt>nil</tt>, the 
      given user name, password, and (optionally) account are
      used to log in. See the description of <cim><front>FTP</front><back>login</back></cim>
      on page 484.
<p/>
      </desc>
    </method>
<p/>
        <method name="open" ref="open">
      <callseq>
        FTP.open( <obj>host</obj>,
        <obj>user</obj>=<tt>nil</tt>,
        <obj>passwd</obj>=<tt>nil</tt>,
        <obj>acct</obj>=<tt>nil</tt>) <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
      A synonym for <ccm><front>FTP</front><back>new</back></ccm>, but with a mandatory <obj>host</obj>
      parameter.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
  <methods type="instance">
<p/>
      <method name="Server commands" ref="Servercommands">
      <callseq>
                <obj>aSession</obj>.acct( <obj>account</obj> )<br/><obj>aSession</obj>.chdir( <obj>dir</obj> )<br/><obj>aSession</obj>.delete( <obj>remoteFile</obj> )<br/><obj>aSession</obj>.mdtm( <obj>remoteFile</obj> ) <returns><obj>aString</obj></returns><br/><obj>aSession</obj>.mkdir( <obj>dir</obj> )<br/><obj>aSession</obj>.nlst( <obj>dir</obj>=<tt>nil</tt> ) <returns><obj>anArray</obj></returns><br/><obj>aSession</obj>.rename( <obj>fromname</obj>, <obj>toname</obj> )<br/><obj>aSession</obj>.rmdir( <obj>dir</obj> )<br/><obj>aSession</obj>.pwd <returns><obj>aString</obj></returns><br/><obj>aSession</obj>.size( <obj>remoteFile</obj> ) <returns><obj>anInteger</obj></returns><br/><obj>aSession</obj>.status <returns><obj>aString</obj></returns><br/><obj>aSession</obj>.system <returns><obj>aString</obj></returns>        
      </callseq>
      <desc>
<p/>
      Issues the corresponding server command and returns the result.
<p/>
      </desc>
    </method>
<p/>
        <method name="close" ref="close">
      <callseq>
        <obj>aSession</obj>.close
      </callseq>
      <desc>
<p/>
      Closes the current connection.
<p/>
      </desc>
    </method>
<p/>
        <method name="closed?" ref="closed_qm">
      <callseq>
        <obj>aSession</obj>.closed? <returns><const>true</const> or <const>false</const></returns>
      </callseq>
      <desc>
<p/>
      Returns <const>true</const> if the current connection is closed.
<p/>
      </desc>
    </method>
<p/>
        <method name="connect" ref="connect">
      <callseq>
        <obj>aSession</obj>.connect( <obj>host</obj>,
        <obj>port</obj>=FTP_PORT )
      </callseq>
      <desc>
<p/>
      Establishes an FTP connection to <obj>host</obj>, optionally overriding
      the default port. If the environment variable
      <tt>SOCKS_SERVER</tt>
      is set, sets up the connection through
      a SOCKS proxy. Raises an exception (typically
      <exception>Errno::ECONNREFUSED</exception>) if the connection
      cannot be established.
<p/>
      </desc>
    </method>
<p/>
        <method name="debug_mode" ref="debug_mode">
      <callseq>
        <obj>aSession</obj>.debug_mode <returns><const>true</const> or <const>false</const></returns>
      </callseq>
      <desc>
<p/>
      Returns the current debug mode.
<p/>
      </desc>
    </method>
<p/>
        <method name="debug_mode=" ref="debug_mode_eq">
      <callseq>
        <obj>aSession</obj>.debug_mode = <const>true</const> or <const>false</const></callseq>
      <desc>
<p/>
      If the debug mode is <const>true</const>, all traffic to and from the
      server is written to <var>$stdout</var>.
<p/>
      </desc>
    </method>
<p/>
        <method name="dir" ref="dir">
      <callseq>
                  <obj>aSession</obj>.dir( <optz>pattern</optz> ) <returns><obj>anArray</obj></returns><br/><obj>aSession</obj>.dir( <optz>pattern</optz> ) <block>{| line | <blockbody>block</blockbody> }</block>
<p/>
      </callseq>
      <desc>
<p/>
      Synonym for <cim><front>FTP</front><back>list</back></cim>.
<p/>
      </desc>
    </method>
<p/>
        <method name="getbinaryfile" ref="getbinaryfile">
      <callseq>
                <obj>aSession</obj>.getbinaryfile(
        <obj>remotefile</obj>, <obj>localfile</obj>, <obj>blocksize</obj>,
        <obj>callback</obj>=<tt>nil</tt>)<br/><obj>aSession</obj>.getbinaryfile(
        <obj>remotefile</obj>, <obj>localfile</obj>, <obj>blocksize</obj> )
        <block>{| data | <blockbody>block</blockbody> }</block>
<p/>
      </callseq>
      <desc>
<p/>
    Retrieves <obj>remotefile</obj> in binary mode, storing the result in
    <obj>localfile</obj>. If <obj>callback</obj> or an associated block is
    supplied, calls it, passing in the retrieved data in
    <obj>blocksize</obj> chunks.
<p/>
      </desc>
    </method>
<p/>
      <method name="gettextfile" ref="gettextfile">
      <callseq>
                <obj>aSession</obj>.gettextfile(
        <obj>remotefile</obj>, <obj>localfile</obj>,
        <obj>callback</obj>=<tt>nil</tt>)<br/><obj>aSession</obj>.gettextfile(
        <obj>remotefile</obj>, <obj>localfile</obj> )
        <block>{| data | <blockbody>block</blockbody> }</block>
<p/>
      </callseq>
      <desc>
<p/>
    Retrieves <obj>remotefile</obj> in ASCII (text) mode, storing the result in
    <obj>localfile</obj>. If <obj>callback</obj> or an associated block is
    supplied, calls it, passing in the retrieved data one line at a time.
<p/>
      </desc>
    </method>
<p/>
        <method name="lastresp" ref="lastresp">
      <callseq>
        <obj>aSession</obj>.lastresp <returns><obj>aString</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the host's last response.
<p/>
      </desc>
    </method>
<p/>
        <method name="list" ref="list">
      <callseq>
                  <obj>aSession</obj>.list( <optz>pattern</optz> ) <returns><obj>anArray</obj></returns><br/><obj>aSession</obj>.list( <optz>pattern</optz> ) <block>{| line | <blockbody>block</blockbody> }</block>
<p/>
      </callseq>
      <desc>
<p/>
      Fetches a directory listing of files matching the given
      pattern(s). If a block is associated with the call, invokes it
      with each line of the result. Otherwise, returns the result as an
      array of strings.
<p/>
      </desc>
    </method>
<p/>
        <method name="login" ref="login">
      <callseq>
        <obj>aSession</obj>.login( <obj>user</obj>="anonymous",
        <obj>passwd</obj>=<tt>nil</tt>, <obj>acct</obj>=<tt>nil</tt> ) <returns>aString</returns>
      </callseq>
      <desc>
<p/>
      Logs into
      the remote host. <obj>aSession</obj> must have been previously
      connected. If <obj>user</obj> is the string ``anonymous'' and the
      password is <tt>nil</tt>, a password of <em>user@host</em> is
      synthesized. If the <obj>acct</obj> parameter is not <tt>nil</tt>, an FTP
      <tt>ACCT</tt> command is sent following the successful
      login. Raises an exception on error (typically
      <exception>Net::FTPPermError</exception>).
<p/>
      </desc>
    </method>
<p/>
          <method name="ls" ref="ls">
      <callseq>
                  <obj>aSession</obj>.ls( <optz>pattern</optz> ) <returns><obj>anArray</obj></returns><br/><obj>aSession</obj>.ls( <optz>pattern</optz> ) <block>{| line | <blockbody>block</blockbody> }</block>
<p/>
      </callseq>
      <desc>
<p/>
      Synonym for <cim><front>FTP</front><back>list</back></cim>.
<p/>
      </desc>
    </method>
<p/>
        <method name="mtime" ref="mtime">
      <callseq>
        <obj>aSession</obj>.mtime( <obj>remoteFile</obj>,
        <obj>local</obj>=<const>false</const> ) <returns><obj>aTime</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the last-modified time of <obj>remoteFile</obj>, interpreting
      the server's response as a GMT time if <obj>local</obj> is
      <const>false</const>, or as a local time otherwise.
<p/>
      </desc>
    </method>
<p/>
        <method name="passive" ref="passive">
      <callseq>
        <obj>aSession</obj>.passive <returns><const>true</const> or <const>false</const></returns>
      </callseq>
      <desc>
<p/>
      Returns the state of the <tt>passive</tt> flag.
<p/>
      </desc>
    </method>
<p/>
        <method name="passive=" ref="passive_eq">
      <callseq>
        <obj>aSession</obj>.passive = <const>true</const> or <const>false</const></callseq>
      <desc>
<p/>
      Puts the connection into passive mode if <const>true</const>.
<p/>
      </desc>
    </method>
<p/>
        <method name="putbinaryfile" ref="putbinaryfile">
      <callseq>
                  <obj>aSession</obj>.putbinaryfile(
          <obj>localfile</obj>, <obj>remotefile</obj>, <obj>blocksize</obj>,
          <obj>callback</obj>=<tt>nil</tt>)<br/><obj>aSession</obj>.putbinaryfile(
          <obj>localfile</obj>, <obj>remotefile</obj>, <obj>blocksize</obj> )
          <block>{| data | <blockbody>block</blockbody> }</block>
<p/>
      </callseq>
      <desc>
<p/>
      Transfers <obj>localfile</obj> to the server in binary mode, storing
      the result in
      <obj>remotefile</obj>. If <obj>callback</obj> or an associated block is
      supplied, calls it, passing in the transmitted data in
      <obj>blocksize</obj> chunks.
<p/>
      </desc>
    </method>
<p/>
        <method name="puttextfile" ref="puttextfile">
      <callseq>
                  <obj>aSession</obj>.puttextfile(
          <obj>localfile</obj>, <obj>remotefile</obj>,
          <obj>callback</obj>=<tt>nil</tt>)<br/><obj>aSession</obj>.puttextfile(
          <obj>localfile</obj>, <obj>remotefile</obj>, <obj>blocksize</obj> )
          <block>{| data | <blockbody>block</blockbody> }</block>
<p/>
      </callseq>
      <desc>
<p/>
      Transfers <obj>localfile</obj> to the server in ASCII (text) mode,
      storing the result in <obj>remotefile</obj>. If <obj>callback</obj> or an
      associated block is supplied, calls it, passing in the
      transmitted data one line at a time.
<p/>
      </desc>
    </method>
<p/>
        <method name="resume" ref="resume">
      <callseq>
        <obj>aSession</obj>.resume <returns><const>true</const> or <const>false</const></returns>
      </callseq>
      <desc>
<p/>
      Returns the status of the <em>resume</em> flag (see
      <cim><front>FTP</front><back>resume=</back></cim>).  Default is <const>false</const>.
<p/>
      </desc>
    </method>
<p/>
        <method name="resume=" ref="resume_eq">
      <callseq>
        <obj>aSession</obj>.resume=<obj>aBoolean</obj>
      </callseq>
      <desc>
<p/>
      Sets the status of the <em>resume</em> flag.  When <em>resume</em> is
      <const>true</const>, partially received files will resume where they
      left off, instead of starting from the beginning again.  This is
      done by sending a <tt>REST</tt> command (<tt>REST</tt>art incomplete
      transfer) to the server.
<p/>
      </desc>
    </method>
<p/>
        <method name="retrbinary" ref="retrbinary">
      <callseq>
        <obj>aSession</obj>.retrbinary(
        <obj>cmd</obj>, <obj>blocksize</obj> ) <block>{| data | <blockbody>block</blockbody> }</block>
<p/>
      </callseq>
      <desc>
<p/>
      Puts the connection into binary (image) mode, issues the given
      command, and fetches the data returned, passing it to the associated 
      block in chunks of <obj>blocksize</obj> characters.  Note that 
      <obj>cmd</obj> is a server command (such as ``RETR myfile'').
<p/>
      </desc>
    </method>
<p/>
        <method name="retrlines" ref="retrlines">
      <callseq>
        <obj>aSession</obj>.retrlines(cmd) <block>{| line | <blockbody>block</blockbody> }</block>
<p/>
      </callseq>
      <desc>
<p/>
      Puts the connection into ASCII (text) mode, issues the given
      command, and passes the resulting data, one line at a time, to the
      associated block. If no block is given, prints the lines. Note that 
      <obj>cmd</obj> is a server command (such as ``RETR myfile'').
<p/>
      </desc>
    </method>
<p/>
        <method name="return_code" ref="return_code">
      <callseq>
        <obj>aSession</obj>.return_code <returns><obj>aFixnum</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the return code from the last operation.
<p/>
      </desc>
    </method>
<p/>
        <method name="storbinary" ref="storbinary">
      <callseq>
                  <obj>aSession</obj>.storbinary( <obj>cmd</obj>, <obj>fileName</obj>, <obj>blocksize</obj>,
          <obj>callback</obj>=<tt>nil</tt>) <br/><obj>aSession</obj>.storbinary( <obj>cmd</obj>, <obj>fileName</obj>, <obj>blocksize</obj> )
          <block>{| data | <blockbody>block</blockbody> }</block>
<p/>
      </callseq>
      <desc>
<p/>
      Puts the connection into binary (image) mode, issues the given
      server-side command (such as ``STOR myfile''), and sends the
      contents of the file named <obj>fileName</obj> to the server. If the optional
      block is given, or if the <obj>callBack</obj> parameter is a <classname>Proc</classname>,
      also passes it the data, in chunks of <obj>blocksize</obj> characters.
<p/>
      </desc>
    </method>
<p/>
      <method name="storlines" ref="storlines">
      <callseq>
                <obj>aSession</obj>.storlines( <obj>cmd</obj>, <obj>fileName</obj>,
        <obj>callback</obj>=<tt>nil</tt>) <br/><obj>aSession</obj>.storlines( <obj>cmd</obj>, <obj>fileName</obj> )
        <block>{| data | <blockbody>block</blockbody> }</block>
<p/>
      </callseq>
      <desc>
<p/>
    Puts the connection into ASCII (text) mode, issues the given
    server-side command (such as ``STOR myfile''), and sends the
    contents of the file named <obj>fileName</obj> to the server, one line at a 
    time. If the optional
    block is given, or if the <obj>callBack</obj> parameter is a <classname>Proc</classname>,
    also passes it the lines.
<p/>
      </desc>
    </method>
<p/>
        <method name="welcome" ref="welcome">
      <callseq>
        <obj>aSession</obj>.welcome <returns><obj>aString</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the host's welcome message.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
</class>
<p/>
<class name="Net::HTTP" super="Net::Protocol" type="class" ref="xref-000011">  
<p/>
<codefragment>
<alltt><fullcode><![CDATA[      require 'net/http'
      
      h = Net::HTTP.new('www.pragmaticprogrammer.com', 80)
      resp, data = h.get('/index.html', nil )
      puts "Code = #{resp.code}"
      puts "Message = #{resp.message}"
      resp.each {|key, val| printf "%-14s = %-40.40s\n", key, val }
      p data[0..55]
]]></fullcode>
require<nbsp/>'net/http'
<p/>
h<nbsp/>=<nbsp/>Net::HTTP.new('www.pragmaticprogrammer.com',<nbsp/>80)
resp,<nbsp/>data<nbsp/>=<nbsp/>h.get('/index.html',<nbsp/>nil<nbsp/>)
puts<nbsp/>"Code<nbsp/>=<nbsp/>#{resp.code}"
puts<nbsp/>"Message<nbsp/>=<nbsp/>#{resp.message}"
resp.each<nbsp/>{|key,<nbsp/>val|<nbsp/>printf<nbsp/>"%-14s<nbsp/>=<nbsp/>%-40.40s\n",<nbsp/>key,<nbsp/>val<nbsp/>}
p<nbsp/>data[0..55]
</alltt>
</codefragment>
<em>produces:</em>
<codefragment><alltt>
Code<nbsp/>=<nbsp/>200
Message<nbsp/>=<nbsp/>OK
content-length<nbsp/>=<nbsp/>8061
date<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>=<nbsp/>Mon,<nbsp/>26<nbsp/>Nov<nbsp/>2001<nbsp/>05:46:25<nbsp/>GMT
connection<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>=<nbsp/>close
content-type<nbsp/><nbsp/><nbsp/>=<nbsp/>text/html
last-modified<nbsp/><nbsp/>=<nbsp/>Tue,<nbsp/>13<nbsp/>Nov<nbsp/>2001<nbsp/>03:12:30<nbsp/>GMT
etag<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>=<nbsp/>"804d98-1f7d-3bf08f9e"
server<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>=<nbsp/>Rapidsite/Apa-1.3.14<nbsp/>(Unix)<nbsp/>FrontPage/4.
accept-ranges<nbsp/><nbsp/>=<nbsp/>bytes
"&lt;!DOCTYPE<nbsp/>HTML<nbsp/>PUBLIC<nbsp/>\"-//W3C//DTD<nbsp/>HTML<nbsp/>4.0<nbsp/>Transitional"
</alltt>
</codefragment>
<p/>
  The <tt>net/http</tt> library provides a simple client to fetch headers
  and Web page contents using the HTTP protocol.
<p/>
  The <meth>get</meth>, <meth>post</meth>, and <meth>head</meth> requests raise
  exceptions on any error, including some HTTP status responses that
  would normally be considered recoverable. There are two ways of
  handling these.
<p/>
  <ol>
  <li> Each method has a corresponding version <meth>get2</meth>,
    <meth>post2</meth>, or <meth>head2</meth> that does not raise an
    exception. These versions are documented in the source.
  </li><li> Recoverable errors raise a
    <exception>Net::ProtoRetriableError</exception> exception. This exception contains a
    <tt>data</tt> attribute containing the response returned by the
    server.
  </li></ol>
<p/>
  The code below illustrates the handling of an HTTP status 301, a redirect.
  It uses Tomoyuki Kosimizu's URI    
  package, available in the RAA.
<p/>
<codefragment>
<alltt><fullcode><![CDATA[    h = Net::HTTP.new(ARGV[0] || 'www.ruby-lang.org', 80)
    url = ARGV[1] || '/'
     
    begin
      resp, data = h.get(url, nil) { |a| }
    rescue Net::ProtoRetriableError => detail
      head = detail.data

      if head.code == "301"
        uri = URI.create(head['location'])

        host = uri['host']
        url  = uri['path']
        port = uri['port']
         
        h.finish
        h = Net::HTTP.new(host, port)

        retry
      end
    end
]]></fullcode>
h<nbsp/>=<nbsp/>Net::HTTP.new(ARGV[0]<nbsp/>||<nbsp/>'www.ruby-lang.org',<nbsp/>80)
url<nbsp/>=<nbsp/>ARGV[1]<nbsp/>||<nbsp/>'/'
<p/>
begin
<nbsp/><nbsp/>resp,<nbsp/>data<nbsp/>=<nbsp/>h.get(url,<nbsp/>nil)<nbsp/>{<nbsp/>|a|<nbsp/>}
rescue<nbsp/>Net::ProtoRetriableError<nbsp/>=&gt;<nbsp/>detail
<nbsp/><nbsp/>head<nbsp/>=<nbsp/>detail.data
<p/>
<nbsp/><nbsp/>if<nbsp/>head.code<nbsp/>==<nbsp/>"301"
<nbsp/><nbsp/><nbsp/><nbsp/>uri<nbsp/>=<nbsp/>URI.create(head['location'])
<p/>
<nbsp/><nbsp/><nbsp/><nbsp/>host<nbsp/>=<nbsp/>uri['host']
<nbsp/><nbsp/><nbsp/><nbsp/>url<nbsp/><nbsp/>=<nbsp/>uri['path']
<nbsp/><nbsp/><nbsp/><nbsp/>port<nbsp/>=<nbsp/>uri['port']
<p/>
<nbsp/><nbsp/><nbsp/><nbsp/>h.finish
<nbsp/><nbsp/><nbsp/><nbsp/>h<nbsp/>=<nbsp/>Net::HTTP.new(host,<nbsp/>port)
<p/>
<nbsp/><nbsp/><nbsp/><nbsp/>retry
<nbsp/><nbsp/>end
end
</alltt>
</codefragment>
<p/>
  <methods type="class">
        <method name="new" ref="new">
      <callseq>
        Net::HTTP.new( <obj>host</obj>='localhost',
        <obj>port</obj>=80,
        <obj>proxy</obj>=<tt>nil</tt>, <obj>proxy_port</obj>=<tt>nil</tt> )
        <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
      Creates and returns a new <classname>HTTP</classname> object. No connection is
      made until <cim><front>HTTP</front><back>start</back></cim> is called.
<p/>
      </desc>
    </method>
<p/>
        <method name="port" ref="port">
      <callseq>
        Net::HTTP.port <returns><obj>aFixnum</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the default HTTP port (80).
<p/>
      </desc>
    </method>
<p/>
        <method name="start" ref="start">
      <callseq>
                  Net::HTTP.start( <obj>host</obj>=<tt>nil</tt>, <obj>port</obj>=80 )<br/>Net::HTTP.start( <obj>host</obj>=<tt>nil</tt>, <obj>port</obj>=80 )
          <block>{| <obj>aSession</obj> | <blockbody>block</blockbody> }</block>
<p/>
      </callseq>
      <desc>
<p/>
      Equivalent to <tt>Net::HTTP.new(<obj>host</obj>, <obj>port</obj>).start</tt>.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
  <methods type="instance">
        <method name="get" ref="get">
      <callseq>
                  <obj>aSession</obj>.get( <obj>path</obj>, <obj>headers</obj>=<tt>nil</tt>, <obj>dest</obj>="" )
          <returns><obj>anArray</obj></returns><br/><obj>aSession</obj>.get( <obj>path</obj>, <obj>headers</obj>=<tt>nil</tt>) <block>{| result | <blockbody>block</blockbody> }</block>
<p/>
          <returns><obj>anArray</obj></returns>
      </callseq>
      <desc>
<p/>
      Retrieves headers and content from the specified <obj>path</obj> on
      the host specified when <obj>aSession</obj> was created. If specified, the
      <obj>headers</obj> parameter is a <classname>Hash</classname> containing additional
      header names and values to be sent with the request. The method
      returns a two-element array. The first element is an
      <tt>HTTPResponse</tt> object (documented in the next section).
      The second element is the page's content.
      The page's content is also passed to the <meth>&lt;&lt;</meth> method of 
      the <obj>dest</obj> parameter, or to the block if specified. This
      result is built network block by network block, not line by line.
      An exception is raised
      if an error is encountered. Multiple <meth>get</meth> calls may be
      made on <obj>aSession</obj>. Unless <cim><front>Protocol</front><back>finish</back></cim> is explicitly
      called, the connection will use the HTTP/1.1 keep-alive
      protocol, and will not close between requests.
<p/>
      </desc>
    </method>
<p/>
        <method name="head" ref="head">
      <callseq>
        <obj>aSession</obj>.head( <obj>path</obj>, <obj>headers</obj>=<tt>nil</tt> )
        <returns><obj>aHash</obj></returns>
      </callseq>
      <desc>
<p/>
      Retrieves headers from the specified <obj>path</obj> on the host
      specified when <obj>aSession</obj> was created. If specified, the
      <obj>headers</obj> parameter is a hash containing additional
      header names and values to be sent with the request. The method
      returns a hash of received headers.  An exception is raised if
      an error is encountered. Multiple <meth>head</meth> calls may be
      made on <obj>aSession</obj>.
<p/>
      </desc>
    </method>
<p/>
        <method name="post" ref="post">
      <callseq>
                  <obj>aSession</obj>.post( <obj>path</obj>, <obj>data</obj>, <obj>headers</obj>=<tt>nil</tt>,
          <obj>dest</obj>="" ) <returns><obj>anArray</obj></returns><br/><obj>aSession</obj>.post( <obj>path</obj>, <obj>data</obj>, <obj>headers</obj>=<tt>nil</tt> )
          <block>{| result | <blockbody>block</blockbody> }</block>
 <returns></returns><obj>anArray</obj>
      </callseq>
      <desc>
<p/>
      Sends <obj>data</obj> to <obj>path</obj> using an HTTP POST
      request. <obj>headers</obj> is a hash containing additional
      headers. Assigns the result to <obj>data</obj> or to the block, as
      for <cim><front>Net_HTTP</front><back>get</back></cim>. Returns a two-element array containing
      an HTTPResponse object and the reply body.
<p/>
      </desc>
    </method>
<p/>
        <method name="start" ref="start">
      <callseq>
                  <obj>aSession</obj>.start<br/><obj>aSession</obj>.start <block>{| <obj>aSession</obj> | <blockbody>block</blockbody> }</block>
<p/>
      </callseq>
      <desc>
<p/>
      Establishes a connection to the host associated with
      <obj>aSession</obj>. (<meth>start</meth> is actually a method in
      <classname>Net::Protocol</classname>, but its use is required in HTTP objects.) In 
      the block form, closes the session at the end of the block.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
</class>
<p/>
<class name="Net::HTTPResponse" super="" type="class" ref="xref-000012">  
  Represents an HTTP response to a GET or POST request.
<p/>
  <methods type="instance">
        <method name="[ ]" ref="_ob_cb">
      <callseq>
        <obj>aSession</obj>[ <obj>aKey</obj> ]
        <returns><obj>aString</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the header corresponding to the case-insensitive
      key. For example, a key of ``Content-type'' might return
      ``text/html''.
<p/>
      </desc>
    </method>
<p/>
        <method name="[ ]=" ref="_ob_cb_eq">
      <callseq>
        <obj>aSession</obj>[ <obj>aKey</obj> ] = <obj>aString</obj>
      </callseq>
      <desc>
<p/>
      Sets the header corresponding to the case-insensitive
      key. 
<p/>
      </desc>
    </method>
<p/>
        <method name="code" ref="code">
      <callseq>
        <obj>aSession</obj>.code <returns><obj>aString</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the result code from the request (for example, ``404'').
<p/>
      </desc>
    </method>
<p/>
        <method name="each" ref="each">
      <callseq>
        <obj>aSession</obj>.each <block>{| key, val | <blockbody>block</blockbody> }</block>
<p/>
      </callseq>
      <desc>
<p/>
      Iterates over all the header key-value pairs.
<p/>
      </desc>
    </method>
<p/>
        <method name="key?" ref="key_qm">
      <callseq>
        <obj>aSession</obj>.key?( <obj>aKey</obj> ) <returns><const>true</const> or <const>false</const></returns>
      </callseq>
      <desc>
<p/>
      Returns <const>true</const> only if a header with the given key exists.
<p/>
      </desc>
    </method>
<p/>
        <method name="message" ref="message">
      <callseq>
        <obj>aSession</obj>.message <returns><obj>aString</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the result message from the request (for example, ``Not found'').
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
</class>
<p/>
<class name="Net::POP" super="Net::Protocol" type="class" ref="xref-000013">      
<p/>
<codefragment>
<alltt><fullcode><![CDATA[      require 'net/pop'
#      pop = Net::POP3.new('server.ruby-stuff.com')
#      pop.start('user', 'secret') do |pop|
!- if `hostname -s`.chomp == 'zip'
!-     pop = Net::POP3.new('fast')
!- else
!-  class Msg
!-    def header
!-      "From: dummy msg for Andy\r\nlooks-better: on dave's box\r\n"
!-    end
!-    def all(s)
!-      s << self.header << "\n" << "That's all folks!\n"
!-    end
!-  end
!-  class Pop
!-    def mails
!-      [ Msg.new ]
!-    end
!-    def start(a,b)
!-      yield self
!-    end
!-  end
!-  pop = Pop.new
!- end
!- pop.start('testmailuser', 'secret134') do |pop|
        msg = pop.mails[0]

        # Print the 'From:' header line
        puts msg.header.split("\r\n").grep(/^From: /)
      
        # Put message to $stdout (by calling <<)
        puts "\nFull message:\n"
        msg.all($stdout)
      end
]]></fullcode>
require<nbsp/>'net/pop'
pop<nbsp/>=<nbsp/>Net::POP3.new('server.ruby-stuff.com')
pop.start('user',<nbsp/>'secret')<nbsp/>do<nbsp/>|pop|
<nbsp/><nbsp/>msg<nbsp/>=<nbsp/>pop.mails[0]
<p/>
<nbsp/><nbsp/>#<nbsp/>Print<nbsp/>the<nbsp/>'From:'<nbsp/>header<nbsp/>line
<nbsp/><nbsp/>puts<nbsp/>msg.header.split("\r\n").grep(/^From:<nbsp/>/)
<p/>
<nbsp/><nbsp/>#<nbsp/>Put<nbsp/>message<nbsp/>to<nbsp/>$stdout<nbsp/>(by<nbsp/>calling<nbsp/>&lt;&lt;)
<nbsp/><nbsp/>puts<nbsp/>"\nFull<nbsp/>message:\n"
<nbsp/><nbsp/>msg.all($stdout)
end
</alltt>
</codefragment>
<em>produces:</em>
<codefragment><alltt>
From:<nbsp/>Dave<nbsp/>Thomas<nbsp/>&lt;dave@pragmaticprogrammer.com&gt;
<p/>
Full<nbsp/>message:
Return-Path:<nbsp/>&lt;dave@pragmaticprogrammer.com&gt;
Received:<nbsp/>(from<nbsp/>dave@pragmaticprogrammer.com)
	by<nbsp/>pragmaticprogrammer.com<nbsp/>(8.8.7/8.8.7)<nbsp/>id<nbsp/>XAA10537;
	Sun,<nbsp/>21<nbsp/>May<nbsp/>2000<nbsp/>23:45:58<nbsp/>-0500
Date:<nbsp/>Sun,<nbsp/>21<nbsp/>May<nbsp/>2000<nbsp/>23:45:58<nbsp/>-0500
From:<nbsp/>Dave<nbsp/>Thomas<nbsp/>&lt;dave@pragmaticprogrammer.com&gt;
Message-Id:<nbsp/>&lt;200005220445.XAA10537@pragmaticprogrammer.com&gt;
To:<nbsp/>user@ruby-stuff.com
Subject:<nbsp/>New<nbsp/>Ruby<nbsp/>Version
Status:<nbsp/>RO
<p/>
Just<nbsp/>to<nbsp/>let<nbsp/>you<nbsp/>know<nbsp/>there's<nbsp/>a<nbsp/>new<nbsp/>Ruby<nbsp/>version<nbsp/>out.
</alltt>
</codefragment>
<p/>
  The <tt>net/pop</tt> library provides a simple client to fetch and
  delete mail on a Post Office Protocol (POP) server.
<p/>
  The class <classname>Net::POP3</classname> is used to access a POP server, returning
  a list of <classname>Net::POPMail</classname> objects, one per message stored on the
  server. These <classname>POPMail</classname> objects are then used to fetch and/or
  delete individual messages.
  The library also provides an alternative to the <classname>POP3</classname> class that
  performs <classname>APOP</classname> authentication.
<p/>
  <methods type="class">
        <method name="new" ref="new">
      <callseq>
        HTTP.new( <obj>host</obj>='localhost', <obj>port</obj>=110 )
        <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
      Creates and returns a new <classname>POP3</classname> object. No connection is
      made until <cim><front>POP3</front><back>start</back></cim> is called.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
  <methods type="instance">
<p/>
        <method name="each" ref="each">
      <callseq>
        <obj>aSession</obj>.each <block>{| popmail | <blockbody>block</blockbody> }</block>
<p/>
      </callseq>
      <desc>
<p/>
      Calls the associated block once for each e-mail stored on the
      server, passing in the corresponding <classname>POPMail</classname> object.
<p/>
      </desc>
    </method>
<p/>
        <method name="finish" ref="finish">
      <callseq>
        <obj>aSession</obj>.finish <returns><const>true</const> or <const>false</const></returns>
      </callseq>
      <desc>
<p/>
      Closes the pop connection. Some servers require that a
      connection is closed before they honor actions such as deleting
      mail. Returns <const>false</const> if the connection was never used.
<p/>
      </desc>
    </method>
<p/>
        <method name="mails" ref="mails">
      <callseq>
        <obj>aSession</obj>.mails <returns><obj>anArray</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns an array of <classname>POPMail</classname> objects, where each object
      corresponds to an e-mail message stored on the server.
<p/>
      </desc>
    </method>
<p/>
        <method name="start" ref="start">
      <callseq>
                  <obj>aSession</obj>.start( <obj>user</obj>, <obj>password</obj> )<br/><obj>aSession</obj>.start( <obj>user</obj>, <obj>password</obj> ) <block>{| pop | <blockbody>block</blockbody> }</block>
<p/>
      </callseq>
      <desc>
<p/>
      Establishes a connection to the pop server, using the supplied
      username and password. Fetches a list of mail held on the server, 
      which may be accessed using the <cim><front>POP3</front><back>mails</back></cim> and
      <cim><front>POP3</front><back>each</back></cim> methods. In block form, passes <obj>aSession</obj> to the
      block, and closes the connection using <meth>finish</meth> when the
      block terminates.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
</class>
<p/>
<class name="Net::APOP" super="Net::POP3" type="class" ref="xref-000014">
  <methods type="instance">
        <method name="start" ref="start">
      <callseq>
        <obj>aSession</obj>.start( <obj>user</obj>, <obj>password</obj>
        )
      </callseq>
      <desc>
<p/>
      Establishes a connection to the APOP server.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
</class>
<p/>
<class name="Net::POPMail" super="Object" type="class" ref="xref-000015">
  <methods type="instance">
        <method name="all" ref="all">
      <callseq>
                  <obj>aSession</obj>.all <returns><obj>aString</obj></returns><br/><obj>aSession</obj>.all( <obj>dest</obj> )<br/><obj>aSession</obj>.all <block>{| aString | <blockbody>block</blockbody> }</block>
<p/>
      </callseq>
      <desc>
<p/>
      Fetches the corresponding e-mail from the server. With no argument 
      or associated block, returns the e-mail as a string. With an
      argument but no block, appends the e-mail to <obj>dest</obj> by
      invoking <obj>dest</obj><tt>&lt;&lt;</tt> for each line in the e-mail. With
      an associated block, invokes the block once for each line in the e-mail.
<p/>
      </desc>
    </method>
<p/>
        <method name="delete" ref="delete">
      <callseq>
        <obj>aSession</obj>.delete
      </callseq>
      <desc>
<p/>
      Deletes the e-mail from the server.
<p/>
      </desc>
    </method>
<p/>
        <method name="delete!" ref="delete_oh">
      <callseq>
        <obj>aSession</obj>.delete!
      </callseq>
      <desc>
<p/>
      Synonym for <cim><front>POPMail</front><back>delete</back></cim>.
<p/>
      </desc>
    </method>
<p/>
        <method name="header" ref="header">
      <callseq>
        <obj>aSession</obj>.header <returns><obj>aString</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the header lines for the corresponding e-mail message.
<p/>
      </desc>
    </method>
<p/>
        <method name="size" ref="size">
      <callseq>
        <obj>aSession</obj>.size <returns><obj>aFixnum</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the size in bytes of the corresponding e-mail.
<p/>
      </desc>
    </method>
<p/>
        <method name="top" ref="top">
      <callseq>
        <obj>aSession</obj>.top( <obj>lines</obj> )  <returns><obj>aString</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the header lines, plus <obj>lines</obj> message lines for the
      corresponding e-mail message.
<p/>
      </desc>
    </method>
<p/>
        <method name="uidl" ref="uidl">
      <callseq>
        <obj>aSession</obj>.uidl <returns><obj>aString</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns the server-specific unique identifier for the
      corresponding e-mail.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
</class>
<p/>
<class name="Net::SMTP" super="Net::Protocol" type="class" ref="xref-000016">    
<p/>
<codefragment>
<alltt><fullcode><![CDATA[      require 'net/smtp'

      # --- Send using class methods
      msg = [ "Subject: Test\n", "\n", "Now is the time\n" ]
      Net::SMTP.start do |smtp|
        smtp.sendmail( msg,  'dave@localhost', ['dave'] )
      end

      # --- Send using SMTP object and an adaptor
      smtp = Net::SMTP.new
      smtp.start('pragprog.com')
      smtp.ready('dave@localhost', 'dave') do |a|
        a.write "Subject: Test1\r\n"
        a.write "\r\n"
        a.write "And so is this"
      end
]]></fullcode>
require<nbsp/>'net/smtp'
<p/>
#<nbsp/>---<nbsp/>Send<nbsp/>using<nbsp/>class<nbsp/>methods
msg<nbsp/>=<nbsp/>[<nbsp/>"Subject:<nbsp/>Test\n",<nbsp/>"\n",<nbsp/>"Now<nbsp/>is<nbsp/>the<nbsp/>time\n"<nbsp/>]
Net::SMTP.start<nbsp/>do<nbsp/>|smtp|
<nbsp/><nbsp/>smtp.sendmail(<nbsp/>msg,<nbsp/><nbsp/>'dave@localhost',<nbsp/>['dave']<nbsp/>)
end
<p/>
#<nbsp/>---<nbsp/>Send<nbsp/>using<nbsp/>SMTP<nbsp/>object<nbsp/>and<nbsp/>an<nbsp/>adaptor
smtp<nbsp/>=<nbsp/>Net::SMTP.new
smtp.start('pragprog.com')
smtp.ready('dave@localhost',<nbsp/>'dave')<nbsp/>do<nbsp/>|a|
<nbsp/><nbsp/>a.write<nbsp/>"Subject:<nbsp/>Test1\r\n"
<nbsp/><nbsp/>a.write<nbsp/>"\r\n"
<nbsp/><nbsp/>a.write<nbsp/>"And<nbsp/>so<nbsp/>is<nbsp/>this"
end
</alltt>
</codefragment>
<p/>
  The <tt>net/smtp</tt> library provides a simple client to send
  electronic mail using the Simple Mail Transfer Protocol (SMTP).
  <methods type="class">
        <method name="new" ref="new">
      <callseq>
        Net::SMTP.new( <obj>server</obj>='localhost',
        <obj>port</obj>=25 ) <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
      Returns a new <classname>SMTP</classname> object connected to the given server and
      port.
<p/>
      </desc>
    </method>
<p/>
        <method name="start" ref="start">
      <callseq>
                  Net::SMTP.start( <obj>server</obj>='localhost', <obj>port</obj>=25,
            <obj>domain</obj>=ENV['HOSTNAME'], <obj>acct</obj>=<tt>nil</tt>,
            <obj>passwd</obj>=<tt>nil</tt>, <obj>authtype</obj>=:cram_md5 ) <returns><obj>aSession</obj></returns><br/>Net::SMTP.start( <obj>server</obj>='localhost', <obj>port</obj>=25,
            <obj>domain</obj>=ENV['HOSTNAME'], <obj>acct</obj>=<tt>nil</tt>,
            <obj>passwd</obj>=<tt>nil</tt>, <obj>authtype</obj>=:cram_md5 )
            <block>{| smtp | <blockbody>block</blockbody> }</block>
<p/>
      </callseq>
      <desc>
<p/>
        Equivalent to <tt>Net::SMTP.new(<obj>server</obj>,
          <obj>port</obj>).start(...)</tt>. For an explanation of the remainder 
        of the parameters, see the instance method <cim><front>Net_SMTP</front><back>start</back></cim>.
        Creates a new <classname>SMTP</classname> object. The <obj>domain</obj> parameter will be 
      used in the initial <tt>HELO</tt> or <tt>EHLO</tt> transaction with the
      SMTP server. In the block form, the <obj>smtp</obj> object is passed
      into the block. When the block terminates, the session is closed.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
  <methods type="instance">
<p/>
        <method name="ready" ref="ready">
      <callseq>
        <obj>aSession</obj>.ready( <obj>from</obj>, <obj>to</obj> )
          <block>{| anAdaptor | <blockbody>block</blockbody> }</block>
<p/>
      </callseq>
      <desc>
<p/>
      Equivalent to <tt>sendmail(from, to) { ...}</tt>. 
      Sends header and body lines to the sendmail server. The
      <obj>from</obj> parameter is used as the sender's name in the
      <tt>MAIL FROM:</tt> command, and the <obj>to</obj> is either a string or
      an array of strings containing the recipients
      for the <tt>RCPT TO:</tt> command. 
      The block is passed an adaptor object. Lines are
      sent to the server by calling the adaptor's <tt>write</tt> method. The
      terminating '.' and <tt>QUIT</tt> are sent automatically.
<p/>
      </desc>
    </method>
<p/>
        <method name="sendmail" ref="sendmail">
      <callseq>
                  <obj>aSession</obj>.sendmail( <obj>src</obj>, <obj>from</obj>, <obj>to</obj> )
      </callseq>
      <desc>
<p/>
      Sends header and body lines to the sendmail server. The
      <obj>from</obj> parameter is used as the sender's name in the
      <tt>MAIL FROM:</tt> command, and <obj>to</obj> is either a string or an
      array of strings containing the
      recipients for the <tt>RCPT TO:</tt> command. 
      Lines to be sent are fetched by invoking <obj>src</obj><tt>.each</tt>.  The
      terminating '.' and <tt>QUIT</tt> are sent automatically.
<p/>
      </desc>
    </method>
<p/>
        <method name="start" ref="start">
      <callseq>
                  <obj>aSession</obj>.start( <obj>domain</obj>=ENV['HOSTNAME'], <obj>acct</obj>=<tt>nil</tt>,
            <obj>passwd</obj>=<tt>nil</tt>, <obj>authtype</obj>=:cram_md5 ) <returns><const>true</const> or <const>false</const></returns><br/><obj>aSession</obj>.start( <obj>domain</obj>=ENV['HOSTNAME'], <obj>acct</obj>=<tt>nil</tt>,
            <obj>passwd</obj>=<tt>nil</tt>, <obj>authtype</obj>=:cram_md5 )
            <block>{| smtp | <blockbody>block</blockbody> }</block>
<returns><const>true</const> or <const>false</const></returns>
      </callseq>
      <desc>
<p/>
        Starts an SMTP session by connecting to the given domain
        (host). If <obj>acct</obj> and <obj>passwd</obj> are given,
        authentication will be attempted using the given
        authentication type (<tt>:plain</tt> or <tt>:cram_md5</tt>). If a
        block is supplied, it will be invoked with <obj>aSession</obj> as a
        parameter. The connection will be closed when the block terminates.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
</class>
<p/>
<class name="Net::Telnet" super="[Socket]" type="class" ref="xref-000017">  
<p/>
    Connect to a <tt>localhost</tt>, run the ``date'' command, and disconnect.
<p/>
<codefragment>
<fullcode><![CDATA[      require 'net/telnet'

      tn = Net::Telnet.new({})
#      tn.login "guest", "secret"
!-    tn.login "tempuser", "wombat"
      tn.cmd "date"
!-    tn.close
]]></fullcode><rubycode>
<tr>
<td colspan="3"><tt>require<nbsp/>'net/telnet'</tt></td>
</tr>
<tr>
<td colspan="3"><tt></tt></td>
</tr>
<tr>
<td colspan="3"><tt>tn<nbsp/>=<nbsp/>Net::Telnet.new({})</tt></td>
</tr>
<tr>
<td colspan="3"><tt>tn.login<nbsp/>"guest",<nbsp/>"secret"</tt></td>
</tr>
<tr>
  <td><tt>tn.cmd<nbsp/>"date"</tt></td>
  <td>&#187;</td>
  <td><tt>"date\r\nSun<nbsp/>Nov<nbsp/>25<nbsp/>23:46:32<nbsp/>CST<nbsp/>2001\n\r&gt;<nbsp/>"</tt></td>
</tr>
</rubycode>
<p/>
</codefragment>
<p/>
    Monitor output as it occurs. We associate a block with each of the 
    library calls; this block is called whenever data becomes
    available from the host.
<p/>
<codefragment>
<alltt><fullcode><![CDATA[      require 'net/telnet'

      tn = Net::Telnet.new({})     { |str| print str }
#      tn.login("guest", "secret")  { |str| print str }
!-    tn.login("tempuser", "wombat")  { |str| print str.sub(/tempuser/, 'guest') }
      tn.cmd("date")  { |str| print str }
!-    tn.close
]]></fullcode>
require<nbsp/>'net/telnet'
<p/>
tn<nbsp/>=<nbsp/>Net::Telnet.new({})<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>{<nbsp/>|str|<nbsp/>print<nbsp/>str<nbsp/>}
tn.login("guest",<nbsp/>"secret")<nbsp/><nbsp/>{<nbsp/>|str|<nbsp/>print<nbsp/>str<nbsp/>}
tn.cmd("date")<nbsp/><nbsp/>{<nbsp/>|str|<nbsp/>print<nbsp/>str<nbsp/>}
</alltt>
</codefragment>
<em>produces:</em>
<codefragment><alltt>
Trying<nbsp/>localhost...
Connected<nbsp/>to<nbsp/>localhost.
Welcome<nbsp/>to<nbsp/>SuSE<nbsp/>Linux<nbsp/>7.1<nbsp/>(i386)<nbsp/>-<nbsp/>Kernel<nbsp/>2.4.0-64GB-SMP<nbsp/>(7).
<p/>
zip<nbsp/>login:<nbsp/>guest
Password:
Last<nbsp/>login:<nbsp/>Sun<nbsp/>Nov<nbsp/>25<nbsp/>23:46:32<nbsp/>from<nbsp/>localhost
/etc/zshrc:<nbsp/>setopt:<nbsp/>no<nbsp/>such<nbsp/>option:<nbsp/>histexpiredupsfirst<nbsp/>[31]

&gt;<nbsp/>date
Sun<nbsp/>Nov<nbsp/>25<nbsp/>23:46:32<nbsp/>CST<nbsp/>2001

&gt;
</alltt>
</codefragment>
<p/>
    Get the time from an NTP server.    
<p/>
<codefragment>
<alltt><fullcode><![CDATA[      require 'net/telnet'
!-      tn = Net::Telnet.new('Host'       => 'ntp0.cornell.edu',
#      tn = Net::Telnet.new('Host'       => 'time.nonexistent.org',
                           'Port'       => 'time',
                           'Timeout'    => 60,
                           'Telnetmode' => false)
      atomicTime = tn.recv(4).unpack('N')[0]
      puts "Atomic time: " + Time.at(atomicTime - 2208988800).to_s
      puts "Local time:  " + Time.now.to_s
!-    tn.close
]]></fullcode>
require<nbsp/>'net/telnet'
tn<nbsp/>=<nbsp/>Net::Telnet.new('Host'<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>=&gt;<nbsp/>'time.nonexistent.org',
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>'Port'<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>=&gt;<nbsp/>'time',
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>'Timeout'<nbsp/><nbsp/><nbsp/><nbsp/>=&gt;<nbsp/>60,
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>'Telnetmode'<nbsp/>=&gt;<nbsp/>false)
atomicTime<nbsp/>=<nbsp/>tn.recv(4).unpack('N')[0]
puts<nbsp/>"Atomic<nbsp/>time:<nbsp/>"<nbsp/>+<nbsp/>Time.at(atomicTime<nbsp/>-<nbsp/>2208988800).to_s
puts<nbsp/>"Local<nbsp/>time:<nbsp/><nbsp/>"<nbsp/>+<nbsp/>Time.now.to_s
</alltt>
</codefragment>
<em>produces:</em>
<codefragment><alltt>
Atomic<nbsp/>time:<nbsp/>Sun<nbsp/>Nov<nbsp/>25<nbsp/>23:46:24<nbsp/>CST<nbsp/>2001
Local<nbsp/>time:<nbsp/><nbsp/>Sun<nbsp/>Nov<nbsp/>25<nbsp/>23:46:32<nbsp/>CST<nbsp/>2001
</alltt>
</codefragment>
<p/>
  The <tt>net/telnet</tt> library provides a complete implementation of a
  telnet client and includes features that make it a convenient
  mechanism for interacting with non-telnet services.
<p/>
  Although the class description that follows indicates that
  <classname>Net::Telnet</classname> is a subclass of class <classname>Socket</classname>, this is a lie.
  In reality, the class delegates to <classname>Socket</classname>. The net effect is the
  same: the methods of <classname>Socket</classname> and its parent, class <classname>IO</classname>, are
  available through <classname>Net::Telnet</classname> objects.
<p/>
  The methods <meth>new</meth>, <meth>cmd</meth>, <meth>login</meth>, and
  <meth>waitfor</meth> take an optional block. If present, the block is
  passed output from the server as it is received by the routine.
  This can be used to provide realtime output, rather than waiting for
  (for example) a login to complete before displaying the server's
  response.
<p/>
  <methods type="class">
        <method name="new" ref="new">
      <callseq>
                  Net::Telnet.new( <obj>options</obj> ) <returns><obj>aSession</obj></returns><br/>Net::Telnet.new( <obj>options</obj> ) <block>{| str | <blockbody>block</blockbody> }</block>
 <returns><obj>aSession</obj></returns>          
      </callseq>
      <desc>
<p/>
      Connects to a server. <obj>options</obj> is a
      <classname>Hash</classname> with zero or more of the following:
<p/>
      <table>
<th>
  <td><b>Option</b></td>
  <td><b>Default</b></td>
  <td><b>Meaning</b></td>
</th>
<tr>
  <td><tt>Binmode</tt></td>
  <td><const>false</const></td>
  <td>If true, no end-of-line
        processing will be performed.</td>
</tr>
<tr>
  <td><tt>Host</tt></td>
  <td>localhost</td>
  <td>Name or address of server's host.</td>
</tr>
<tr>
  <td><tt>Port</tt></td>
  <td>23</td>
  <td>Name or number of service to call.</td>
</tr>
<tr>
  <td><tt>Prompt</tt></td>
  <td><tt>/[$%#&gt;]/</tt></td>
  <td>Pattern that matches the host's
        prompt.</td>
</tr>
<tr>
  <td><tt>Telnetmode</tt></td>
  <td><const>true</const></td>
  <td>If <const>false</const>, ignore the
        majority of telnet embedded escape sequences. Used when
        talking with a non-telnet server.</td>
</tr>
<tr>
  <td><tt>Timeout</tt></td>
  <td>10</td>
  <td>Time in seconds to wait for a server
        response (both during connection and during regular data
        transmission).</td>
</tr>
<tr>
  <td><tt>Waittime</tt></td>
  <td>0</td>
  <td>Time to wait for prompt to appear in
        received data stream.</td>
</tr>
<bottomrule/></table>
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
  <methods type="instance">
        <method name="binmode" ref="binmode">
      <callseq>
        <obj>aSession</obj>.binmode <returns><const>true</const> or <const>false</const></returns>
      </callseq>
      <desc>
<p/>
      Returns the current value of the <tt>Binmode</tt> flag.
<p/>
      </desc>
    </method>
<p/>
        <method name="binmode=" ref="binmode_eq">
      <callseq>
        <obj>aSession</obj>.binmode = <const>true</const> or <const>false</const></callseq>
      <desc>
<p/>
      Sets the <tt>Binmode</tt> flag, returning the new value.
<p/>
      </desc>
    </method>
<p/>
        <method name="cmd" ref="cmd">
      <callseq>
                  <obj>aSession</obj>.cmd( <obj>options</obj> ) <returns><obj>aString</obj></returns><br/><obj>aSession</obj>.cmd( <obj>options</obj> ) <block>{| str | <blockbody>block</blockbody> }</block>
<returns><obj>aString</obj></returns>          
      </callseq>
      <desc>
<p/>
      Sends a string to the server and waits (using a timeout) for a
      string that matches a pattern to be returned by the server. If
      the parameter is not a <classname>Hash</classname>, it is sent as a string to the server, and
      the pattern to match and the timeout are the <tt>Prompt</tt> and
      <tt>Timeout</tt> options given when <obj>aSession</obj> was created. 
      If <obj>options</obj> is a <classname>Hash</classname>, then <obj>options['String']</obj> is
      sent to the server. <obj>options['Match']</obj> may be used to
      override the class <tt>Prompt</tt> parameter, and <obj>options['Timeout']</obj> 
      the timeout. The method returns the complete server response.
<p/>
      </desc>
    </method>
<p/>
        <method name="login" ref="login">
      <callseq>
                    <obj>aSession</obj>.login( <obj>options</obj>,
            <obj>password</obj>=nil ) <returns><obj>aString</obj></returns><br/><obj>aSession</obj>.login( <obj>options</obj>,
            <obj>password</obj>=nil ) <block>{| str | <blockbody>block</blockbody> }</block>
 <returns><obj>aString</obj></returns>          
      </callseq>
      <desc>
<p/>
      If <obj>options</obj> is a <classname>Hash</classname>, a username is taken from
      <obj>options['Name']</obj> and a password from
      <obj>options['Password']</obj>; otherwise, <obj>options</obj> is assumed to
      be the username, and <obj>password</obj> the password. The method
      waits for the server to send the string matching the pattern
      <tt>/login[:<visible_space/>]*\z/</tt> and sends the username. If a
      password is given, it then waits for the server to send
      <tt>/Password[:<visible_space/>]*\z/</tt> and sends the password. The
      method returns the full server response.
<p/>
      </desc>
    </method>
<p/>
        <method name="print" ref="print">
      <callseq>
        <obj>aSession</obj>.print( <obj>aString</obj> )
      </callseq>
      <desc>
<p/>
      Sends <obj>aString</obj> to the server, honoring <tt>Telnetmode</tt>,
      <tt>Binarymode</tt>, and any additional modes negotiated with the
      server. 
<p/>
      </desc>
    </method>
<p/>
        <method name="telnetmode" ref="telnetmode">
      <callseq>
        <obj>aSession</obj>.telnetmode <returns><const>true</const> or <const>false</const></returns>
      </callseq>
      <desc>
<p/>
      Returns the current value of the <tt>Telnetmode</tt> flag.
<p/>
      </desc>
    </method>
<p/>
        <method name="telnetmode=" ref="telnetmode_eq">
      <callseq>
        <obj>aSession</obj>.telnetmode= <const>true</const> or <const>false</const></callseq>
      <desc>
<p/>
      Sets the <tt>Telnetmode</tt>
      flag, returning the new value.
<p/>
      </desc>
    </method>
<p/>
        <method name="waitfor" ref="waitfor">
      <callseq>
                  <obj>aSession</obj>.waitfor( <obj>options</obj> ) <returns><obj>aString</obj></returns><br/><obj>aSession</obj>.waitfor( <obj>options</obj> ) <block>{| str | <blockbody>block</blockbody> }</block>
 <returns><obj>aString</obj></returns>          
      </callseq>
      <desc>
<p/>
      Waits for the server to respond with a string that matches a
      string or pattern. If <obj>options</obj> is not a <classname>Hash</classname>, it
      is compared against the cumulative server output as that output 
      is received using <obj>options.</obj><tt>===</tt>. It is likely that you will
      want to use a regular expression in this case.
<p/>
      If <obj>options</obj> is a <classname>Hash</classname>, then <obj>options['Match']</obj>,
      <obj>options['Prompt']</obj>, or <obj>options['String']</obj> provides the
      match. In the latter case, the string will be converted to a
      regular expression before being used. <obj>options</obj> may also
      include the keys ``Timeout'' and ``Waittime'' to override the
      class options of the same names.
<p/>
      </desc>
    </method>
<p/>
        <method name="write" ref="write">
      <callseq>
        <obj>aSession</obj>.write( <obj>aString</obj> )
      </callseq>
      <desc>
<p/>
      Writes <obj>aString</obj> to the server with no translation.
<p/>
      </desc>
    </method>
<p/>
  </methods>
<p/>
</class>
<p/>
<section>CGI Development</section>
<p/>
<class name="CGI" super="Object" type="class" ref="xref-000018">  
<p/>
<codefragment>
<alltt><fullcode><![CDATA[  require "cgi"
  cgi = CGI.new("html3")  # add HTML generation methods
  cgi.out {
    CGI.pretty (
      cgi.html {
        cgi.head { cgi.title{"TITLE"} } +
        cgi.body {
          cgi.form {
            cgi.textarea("get_text") +
            cgi.br +
            cgi.submit
          } +
          cgi.h1 { "This is big!" } +
          cgi.center { "Jazz Greats of the 20" + 
            cgi.small {"th"} + " century" + cgi.hr
          } + cgi.p + cgi.table ('BORDER' => '5') {
            cgi.tr { cgi.td {"Artist"} + cgi.td {"Album"} } +
            cgi.tr { cgi.td {"Davis, Miles"} + 
            cgi.td {"Kind of Blue"} }
          }
        }
      }
    ) # CGI.pretty is a method call, not a block
  }
]]></fullcode>
require<nbsp/>"cgi"
cgi<nbsp/>=<nbsp/>CGI.new("html3")<nbsp/><nbsp/>#<nbsp/>add<nbsp/>HTML<nbsp/>generation<nbsp/>methods
cgi.out<nbsp/>{
<nbsp/><nbsp/>CGI.pretty<nbsp/>(
<nbsp/><nbsp/><nbsp/><nbsp/>cgi.html<nbsp/>{
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>cgi.head<nbsp/>{<nbsp/>cgi.title{"TITLE"}<nbsp/>}<nbsp/>+
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>cgi.body<nbsp/>{
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>cgi.form<nbsp/>{
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>cgi.textarea("get_text")<nbsp/>+
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>cgi.br<nbsp/>+
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>cgi.submit
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>}<nbsp/>+
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>cgi.h1<nbsp/>{<nbsp/>"This<nbsp/>is<nbsp/>big!"<nbsp/>}<nbsp/>+
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>cgi.center<nbsp/>{<nbsp/>"Jazz<nbsp/>Greats<nbsp/>of<nbsp/>the<nbsp/>20"<nbsp/>+
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>cgi.small<nbsp/>{"th"}<nbsp/>+<nbsp/>"<nbsp/>century"<nbsp/>+<nbsp/>cgi.hr
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>}<nbsp/>+<nbsp/>cgi.p<nbsp/>+<nbsp/>cgi.table<nbsp/>('BORDER'<nbsp/>=&gt;<nbsp/>'5')<nbsp/>{
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>cgi.tr<nbsp/>{<nbsp/>cgi.td<nbsp/>{"Artist"}<nbsp/>+<nbsp/>cgi.td<nbsp/>{"Album"}<nbsp/>}<nbsp/>+
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>cgi.tr<nbsp/>{<nbsp/>cgi.td<nbsp/>{"Davis,<nbsp/>Miles"}<nbsp/>+
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>cgi.td<nbsp/>{"Kind<nbsp/>of<nbsp/>Blue"}<nbsp/>}
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>}
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>}
<nbsp/><nbsp/><nbsp/><nbsp/>}
<nbsp/><nbsp/>)<nbsp/>#<nbsp/>CGI.pretty<nbsp/>is<nbsp/>a<nbsp/>method<nbsp/>call,<nbsp/>not<nbsp/>a<nbsp/>block
}
</alltt>
</codefragment>
<p/>
(The output of this script is shown in Figure 26.2 on page 499.)
<p/>
  The <classname>CGI</classname> class provides support for programs used as a Web server
  CGI (Common Gateway Interface) script.  It contains several
  methods for accessing fields in a CGI form, manipulating ``cookies'' and
  the environment, and outputting formatted HTML.
<p/>
  Since environment variables contain a lot of useful information for
  a CGI script, <classname>CGI</classname> makes accessing them very easy---environment
  variables are accessible as attributes of <classname>CGI</classname> objects.  For
  instance, <tt>cgi.auth_type</tt> returns the value of
  <tt>ENV["AUTH_TYPE"]</tt>.  To create the method name, the environment
  variable name is translated to all lowercase, and the
  ``<tt>HTTP_</tt>'' prefix is stripped off.  Thus,
  <tt>HTTP_USER_AGENT</tt> would be available as the method
  <tt>user_agent</tt>.
<p/>
  Cookies are represented using a separate object of class
  <classname>CGI::Cookie</classname>, containing the following accessors:  
  <table>
<th>
  <td><b>Accessor</b></td>
  <td><b>Description</b></td>
</th>
<tr>
  <td><tt>name</tt></td>
  <td>Name of this cookie</td>
</tr>
<tr>
  <td><tt>value</tt></td>
  <td>Array of values</td>
</tr>
<tr>
  <td><tt>path</tt></td>
  <td>Path (optional)</td>
</tr>
<tr>
  <td><tt>domain</tt></td>
  <td>Domain (optional)</td>
</tr>
<tr>
  <td><tt>expires</tt></td>
  <td>Time of expiry, defaults to <ccm><file>time</file><front>Time</front><back>now</back><mref>now</mref></ccm> (optional)</td>
</tr>
<tr>
  <td><tt>secure</tt></td>
  <td><const>true</const> for a secure cookie</td>
</tr>
<bottomrule/></table>
<p/>
<figure type="figure">Figure not available...</figure>
<p/>
You create a cookie object using <ccm><front>CGI_Cookie</front><back>new</back></ccm>, which takes
  as arguments the accessors listed above, or <ccm><front>CGI_Cookie</front><back>parse</back></ccm>,
  which takes an encoded string and returns a cookie object.
<p/>
    <methods type="class">
<p/>
          <method name="escape" ref="escape">
      <callseq>
        CGI.escape( <obj>aString</obj> )
            <returns><obj>aNewString</obj></returns>
      </callseq>
      <desc>
<p/>
        Returns a URL-encoded string made from the given argument, where unsafe
        characters (not alphanumeric, ``_'', ``-'', or ``.'') are encoded 
        using ``%xx'' escapes.
<p/>
      </desc>
    </method>
<p/>
          <method name="escapeElement" ref="escapeElement">
      <callseq>
        CGI.escapeElement( <obj>aString</obj>  
          <optz>, <obj>elements</obj></optz> )
            <returns><obj>aNewString</obj></returns>
      </callseq>
      <desc>
<p/>
          Returns a string made from the given argument with certain
          HTML-special characters escaped. The HTML elements given in
          <obj>elements</obj> will be escaped; other HTML elements will not
          be affected.
<p/>
<codefragment>
<alltt><fullcode><![CDATA[!- require 'cgi'            
             print CGI::escapeElement('<BR><A HREF="url"></A><P>', "A", "IMG")
]]></fullcode>
print<nbsp/>CGI::escapeElement('&lt;BR&gt;&lt;A<nbsp/>HREF="url"&gt;&lt;/A&gt;&lt;P&gt;',<nbsp/>"A",<nbsp/>"IMG")
</alltt>
</codefragment>
<em>produces:</em>
<codefragment><alltt>
&lt;BR&gt;&amp;lt;A<nbsp/>HREF=&amp;quot;url&amp;quot;&amp;gt;&amp;lt;/A&amp;gt;&lt;P&gt;
</alltt>
</codefragment>
<p/>
      </desc>
    </method>
<p/>
          <method name="escapeHTML" ref="escapeHTML">
      <callseq>
        CGI.escapeHTML( <obj>aString</obj> )
            <returns><obj>aNewString</obj></returns>
      </callseq>
      <desc>
<p/>
          Returns a string made from the given argument with
          HTML-special characters (such as
          ``<tt>&amp;</tt>'',``<tt>"</tt>'',``<tt>&lt;</tt>'',``<tt>&gt;</tt>'') quoted using
          ``<tt>&amp;amp;</tt>'', ``<tt>&amp;quot;</tt>'', ``<tt>&amp;lt;</tt>'',
          ``<tt>&amp;gt;</tt>'', and so on.
<p/>
      </desc>
    </method>
<p/>
          <method name="new" ref="new">
      <callseq>
        CGI.new( <optz><obj>aString</obj></optz> )
            <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
        Returns a new <classname>CGI</classname> object.  If HTML output is required, the
        desired standards level must be given in <obj>aString</obj>
        (otherwise, no output routines will be created). The level may be
        one of:
<p/>
        <table>
<th>
  <td><b>String</b></td>
  <td><b>Standards Level</b></td>
  <td><b>String</b></td>
  <td><b>Standards Level</b></td>
</th>
<tr>
  <td>``html3''</td>
  <td>HTML 3.2</td>
  <td>``html4''</td>
  <td>HTML 4.0 Strict</td>
</tr>
<tr>
  <td>``html4Tr''</td>
  <td>HTML 4.0 Transitional</td>
  <td>``html4Fr''</td>
  <td>HTML 4.0 Frameset</td>
</tr>
<bottomrule/></table>
<p/>
      </desc>
    </method>
<p/>
          <method name="parse" ref="parse">
      <callseq>
        CGI.parse( <obj>aString</obj> )
          <returns><obj>aHash</obj></returns>
      </callseq>
      <desc>
<p/>
        Parses a query string and returns
        a hash of its <em>key-value</em> pairs.
<p/>
      </desc>
    </method>
<p/>
          <method name="pretty" ref="pretty">
      <callseq>
        CGI.pretty( <obj>anHTMLString</obj>,
            <obj>aLeaderString</obj>="  " )
            <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
          Formats the given <obj>anHTMLString</obj> in a nice, readable
          format, optionally prefixing each line with
          <obj>aLeaderString</obj>.
<p/>
      </desc>
    </method>
<p/>
          <method name="rfc1123_date" ref="rfc1123_date">
      <callseq>
        CGI.rfc1123_date( <obj>aTime</obj> )
            <returns><obj>aString</obj></returns>
      </callseq>
      <desc>
<p/>
          Returns a string representing the given time according to
          RFC 1123 (for instance, <tt>Mon, 1 Jan 2001 00:00:00 GMT</tt>).
<p/>
      </desc>
    </method>
<p/>
          <method name="unescape" ref="unescape">
      <callseq>
        CGI.unescape( <obj>aString</obj> )
            <returns><obj>aNewString</obj></returns>
      </callseq>
      <desc>
<p/>
          Returns a string containing ``unsafe'' characters made from
          the given URL-encoded argument, where unsafe characters were
          encoded using ``%'' escapes.
<p/>
      </desc>
    </method>
<p/>
          <method name="unescapeElement" ref="unescapeElement">
      <callseq>
        CGI.unescapeElement( <obj>aString</obj>  
          <optz>, <obj>elements</obj></optz> )
            <returns><obj>aNewString</obj></returns>
      </callseq>
      <desc>
<p/>
          Returns a string with the selected escaped HTML elements
          expanded to the actual characters.
<p/>
      </desc>
    </method>
<p/>
          <method name="unescapeHTML" ref="unescapeHTML">
      <callseq>
        CGI.unescapeHTML( <obj>aString</obj> )
            <returns><obj>aNewString</obj></returns>
      </callseq>
      <desc>
<p/>
          Returns a string made from the given argument with
          HTML-special quoted characters expanded to the actual
          characters.
<p/>
      </desc>
    </method>
<p/>
    </methods>
<p/>
    <methods type="instance">
<p/>
          <method name="[ ]" ref="_ob_cb">
      <callseq>
        <obj>aSession</obj>[ <optn><obj>aString</obj></optn> ]
            <returns><obj>anArray</obj></returns>
      </callseq>
      <desc>
<p/>
        Returns the values of the given field names from the CGI
        form in an <classname>Array</classname>.  See the note on multipart forms on page 503.
<p/>
      </desc>
    </method>
<p/>
          <method name="cookies" ref="cookies">
      <callseq>
        <obj>aSession</obj>.cookies
          <returns><obj>aHash</obj></returns>
      </callseq>
      <desc>
<p/>
        Returns a new <classname>Hash</classname> object containing <em>key-value</em>
        pairs of cookie keys and values.
<p/>
      </desc>
    </method>
<p/>
          <method name="has_key?" ref="has_key_qm">
      <callseq>
        <obj>aSession</obj>.has_key( <obj>aString</obj> )
          <returns><const>true</const> or <const>false</const></returns>
      </callseq>
      <desc>
<p/>
        Returns <const>true</const> if the form contains a field named
        <obj>aString</obj>.
<p/>
      </desc>
    </method>
<p/>
          <method name="header" ref="header">
      <callseq>
                    <obj>aSession</obj>.header( <obj>aContentType</obj>="text/html" )
            <returns><obj>aString</obj></returns> <br/><obj>aSession</obj>.header( <obj>aHash</obj> )
            <returns><obj>aString</obj></returns> <br/>
      </callseq>
      <desc>
<p/>
          Returns a string containing the given headers
          (in the <tt>MOD_RUBY</tt> environment, the resulting header is
          sent immediately instead). If a hash is given as an
          argument, then the <em>key-value</em> pairs will be used to
          generate headers.
<p/>
      </desc>
    </method>
<p/>
          <method name="keys" ref="keys">
      <callseq>
        <obj>aSession</obj>.keys
            <returns><obj>anArray</obj></returns>
      </callseq>
      <desc>
<p/>
        Returns an array of all existing field names for the form.
<p/>
      </desc>
    </method>
<p/>
          <method name="out" ref="out">
      <callseq>
                    <obj>aSession</obj>.out( <obj>aContentType</obj>="text/html" ) <block>{ <blockbody>block</blockbody> }</block>
<returns><tt>nil</tt></returns> <br/><obj>aSession</obj>.out( <obj>aHash</obj> ) <block>{ <blockbody>block</blockbody> }</block>
<returns><tt>nil</tt></returns> <br/>
      </callseq>
      <desc>
<p/>
          Generates HTML output using the results of the block as the
          content.  Headers are generated as with <cim><front>CGI</front><back>header</back></cim>.
          See the example at the start of this section.
<p/>
      </desc>
    </method>
<p/>
          <method name="params" ref="params">
      <callseq>
        <obj>aSession</obj>.params
          <returns><obj>aHash</obj></returns>
      </callseq>
      <desc>
<p/>
        Returns a new <classname>Hash</classname> object containing <em>key-value</em>
        pairs of field names and values from the form.
<p/>
      </desc>
    </method>
<p/>
    </methods>
<p/>
</class>
<p/>
<subsection>HTML Output Methods</subsection>
In addition, <classname>CGI</classname> supports the following HTML output methods.  Each
of these methods is named after the corresponding HTML feature (or
close to it).  Those tags that require content (such as
<tt>blockquote</tt>) take an optional block; the block should return a
<classname>String</classname> that will be used as the content for the feature.  These
methods may take arguments as indicated, or as a hash with the given
names as keys.
<p/>\<hr></hr>
<br/><tt>a</tt>( <em><obj>url</obj></em> )<br/><tt>a</tt>( <em><tt>HREF</tt></em> =&gt; )<p/>
<p/>
<br/><tt>base</tt>( <em><obj>url</obj></em> )<br/><tt>base</tt>( <em><tt>HREF</tt></em> =&gt; )<p/>
<p/>
<br/><tt>blockquote</tt>( <em><obj>cite=""</obj></em> ) { <em>aString</em> }<br/><tt>blockquote</tt>( <em><tt>CITE</tt></em> =&gt; ) { <em>aString</em> }<p/>
<p/>
<br/><tt>caption</tt>( <em><obj>align=nil</obj></em> ) { <em>aString</em> }<br/><tt>caption</tt>( <em><tt>ALIGN</tt></em> =&gt; ) { <em>aString</em> }<p/>
<p/>
<br/><tt>checkbox</tt>( <em><obj>name</obj>=<tt>nil</tt>, <obj>value</obj>=<tt>nil</tt>, <obj>checked</obj>=<tt>nil</tt></em> )<br/><tt>checkbox</tt>( <em><tt>NAME</tt>, <tt>VALUE</tt>, <tt>CHECKED</tt></em> =&gt; )<p/>
<p/>
<br/><tt>checkbox_group</tt>( <em><obj>name</obj>=<tt>nil</tt>, <optn><obj>items</obj></optn></em> )<br/><tt>checkbox_group</tt>( <em>  <tt>NAME</tt>, <tt>VALUES</tt></em> =&gt; )<p/>
<p/>
<blockquote>Items may be individual <classname>String</classname> names, or any of: 
  an array of [<nbsp/><obj>name</obj>,<nbsp/><obj>checked</obj><nbsp/>], 
  an array of [<nbsp/><obj>value</obj>,<nbsp/><obj>name</obj><nbsp/>],
  or an array of [<nbsp/><obj>value</obj>,<nbsp/><obj>name</obj>,<nbsp/><obj>checked</obj><nbsp/>].
  The value for the hash key VALUES should be an array of these items.
  </blockquote>
<p/>
<br/><tt>file_field</tt>( <em><obj>name</obj>="", <obj>size</obj>=20, <obj>maxlength</obj>=<tt>nil</tt></em> )<br/><tt>file_field</tt>( <em>  <tt>NAME</tt>, <tt>SIZE</tt>, <tt>MAXLENGTH</tt></em> =&gt; )<p/>
<p/>
<br/><tt>form</tt>( <em><obj>method</obj>="post", <obj>action</obj>=<tt>nil</tt>,
  <obj>enctype</obj>="application/x-www-form-urlencoded"</em> ) { <em>aStr</em> }<br/><tt>form</tt>( <em>  <tt>METHOD</tt>, <tt>ACTION</tt>, <tt>ENCTYPE</tt></em> =&gt; ) { <em>aStr</em> }<p/>
<p/>
<br/><tt>hidden</tt>( <em><obj>name</obj>="", <obj>value</obj>=<tt>nil</tt></em> )<br/><tt>hidden</tt>( <em><tt>NAME</tt>, <tt>VALUE</tt></em> =&gt; )<p/>
<p/>
<br/><tt>html</tt>( <em></em> ) { <em>aString</em> }<br/><tt>html</tt>( <em><tt>PRETTY</tt>, <tt>DOCTYPE</tt></em> =&gt; ) { <em>aString</em> }<p/>
<p/>
<br/><tt>img_button</tt>( <em><obj>src</obj>="", <obj>name</obj>=<tt>nil</tt>, <obj>alt</obj>=<tt>nil</tt></em> )<br/><tt>img_button</tt>( <em>  <tt>SRC</tt>, <tt>NAME</tt>, <tt>ALT</tt></em> =&gt; )<p/>
<p/>
<br/><tt>img</tt>( <em><obj>src</obj>="", <obj>alt</obj>="", <obj>width</obj>=<tt>nil</tt>, <obj>height</obj>=<tt>nil</tt></em> )<br/><tt>img</tt>( <em>  <tt>SRC</tt>, <tt>ALT</tt>, <tt>WIDTH</tt>, <tt>HEIGHT</tt></em> =&gt; )<p/>
<p/>
<br/><tt>multipart_form</tt>( <em><obj>action</obj>=<tt>nil</tt>, <obj>enctype</obj>="multipart/form-data"</em> ) { <em>aString</em> }<br/><tt>multipart_form</tt>( <em><tt>METHOD</tt>, <tt>ACTION</tt>, <tt>ENCTYPE</tt></em> =&gt; ) { <em>aString</em> }<p/>
<p/>
<br/><tt>password_field</tt>( <em><obj>name</obj>="", <obj>value</obj>=<tt>nil</tt>, <obj>size</obj>=40, 
  <obj>maxlength</obj>=<tt>nil</tt></em> )<br/><tt>password_field</tt>( <em><tt>NAME</tt>, <tt>VALUE</tt>, <tt>SIZE</tt>, <tt>MAXLENGTH</tt></em> =&gt; )<p/>
<p/>
<br/><tt>popup_menu</tt>( <em><obj>name</obj>="", <obj>items</obj></em> )<br/><tt>popup_menu</tt>( <em>  <tt>NAME</tt>, <tt>SIZE</tt>,  <tt>MULTIPLE</tt>, <tt>VALUES</tt> <em>(array of items)</em></em> =&gt; )<p/>
<p/>
<blockquote>Items may be individual <classname>String</classname> names, or any of: 
  an array of [<nbsp/><obj>name</obj>,<nbsp/><obj>selected</obj><nbsp/>], 
  an array of [<nbsp/><obj>value</obj>,<nbsp/><obj>name</obj><nbsp/>],
  or an array of [<nbsp/><obj>value</obj>,<nbsp/><obj>name</obj>,<nbsp/><obj>selected</obj><nbsp/>].
  The value for the hash key VALUES should be an array of these items.
  </blockquote>
<p/>
<br/><tt>radio_button</tt>( <em><obj>name</obj>="", <obj>value</obj>=<tt>nil</tt>, <obj>checked</obj>=<tt>nil</tt></em> )<br/><tt>radio_button</tt>( <em>  <tt>NAME</tt>, <tt>VALUE</tt>, <tt>CHECKED</tt></em> =&gt; )<p/>
<p/>
<br/><tt>radio_group</tt>( <em><obj>name</obj>="", <obj>items</obj></em> )<br/><tt>radio_group</tt>( <em><tt>NAME</tt>, <tt>VALUES</tt>
  <em>(array of items)</em></em> =&gt; )<p/>
<p/>
<blockquote>Items may be individual <classname>String</classname> names, or any of: 
  an array of [<nbsp/><obj>name</obj>,<nbsp/><obj>selected</obj><nbsp/>], 
  an array of [<nbsp/><obj>value</obj>,<nbsp/><obj>name</obj><nbsp/>],
  or an array of [<nbsp/><obj>value</obj>,<nbsp/><obj>name</obj>,<nbsp/><obj>selected</obj><nbsp/>].
  The value for the hash key VALUES should be an array of these items.
  </blockquote>
<p/>
<br/><tt>reset</tt>( <em><obj>value</obj>=<tt>nil</tt>, <obj>name</obj>=<tt>nil</tt></em> )<br/><tt>reset</tt>( <em><tt>VALUE</tt>, <tt>NAME</tt></em> =&gt; )<p/>
<p/>
<br/><tt>scrolling_list</tt>( <em><em>alias for</em> popup_menu</em> )<br/><tt>scrolling_list</tt>( <em></em> =&gt; )<p/>
<p/>
<br/><tt>submit</tt>( <em><obj>value</obj>=<tt>nil</tt>, <obj>name</obj>=<tt>nil</tt></em> )<br/><tt>submit</tt>( <em><tt>VALUE</tt>, <tt>NAME</tt></em> =&gt; )<p/>
<p/>
<br/><tt>text_field</tt>( <em><obj>name</obj>="", <obj>value</obj>=<tt>nil</tt>, <obj>size</obj>=40,
  <obj>maxlength</obj>=<tt>nil</tt></em> )<br/><tt>text_field</tt>( <em><tt>NAME</tt>, <tt>VALUE</tt>, <tt>SIZE</tt>, MAXLENGTH</em> =&gt; )<p/>
<p/>
<br/><tt>textarea</tt>( <em><obj>name</obj>="", <obj>cols</obj>=70, <obj>rows</obj>=10</em> )<br/><tt>textarea</tt>( <em>  <tt>NAME</tt>, <tt>COLS</tt>, <tt>ROWS</tt></em> =&gt; )<p/>
<p/>
\<hr></hr>
<p/>
In addition, all HTML tags are supported as methods, including
<tt>title</tt>, <tt>head</tt>, <tt>body</tt>, <tt>br</tt>, <tt>pre</tt>, and so on.
The block given to the method must return a <classname>String</classname>, which will be
used as the content for that tag type.  Not all tags require content:
<tt>&lt;P&gt;</tt>, for example, does not.
The available tags vary according to the supported HTML level---Table
26.1 on page 503 lists the complete set.  For these methods, you
can pass in a hash with attributes for the given tag.  For instance, you
might pass in <tt>'BORDER'=&gt;'5'</tt> to the <tt>table</tt> method to set the
border width of the table.
<figure type="table">
  <caption>HTML tags available as methods</caption>  
  <table>
<th>
  <td>{<b>HTML 3</b>}</td>
</th>
<tr>
  <td>a address applet area b base basefont big blockquote body br caption
    center cite code dd dfn dir div dl dt em font form h1 h2 h3 h4 h5 h6
    head hr html i img input isindex kbd li link listing map menu meta
    ol option p param plaintext pre samp script select small strike
    strong style sub sup table td textarea th title tr tt u ul var xmp</td>
</tr>
<toprule/><tr>
  <td>{<b>HTML 4</b>}</td>
</tr>
<th>
  <td>a abbr acronym address area b base bdo big blockquote body br
    button caption cite code col colgroup dd del dfn div dl dt em
    fieldset form h1 h2 h3 h4 h5 h6 head hr html i img input ins kbd
    label legend li link map meta noscript object ol optgroup option p
    param pre q samp script select small span strong style sub sup
    table tbody td textarea tfoot th thead title tr tt ul var</td>
</th>
<th>
  <td>{<b>HTML 4 Transitional</b>}</td>
</th>
<tr>
  <td>a abbr acronym address applet area b base basefont bdo big
    blockquote body br button caption center cite code col colgroup dd
    del dfn dir div dl dt em fieldset font form h1 h2 h3 h4 h5 h6 head
    hr html i iframe img input ins isindex kbd label legend li link map
    menu meta noframes noscript object ol optgroup option p param pre q
    s samp script select small span strike strong style sub sup table
    tbody td textarea tfoot th thead title tr tt u ul var</td>
</tr>
<toprule/><tr>
  <td></td>
</tr>
<th>
  <td>frame frameset</td>
</th>
<bottomrule/></table>
<p/>
</figure>
<p/>
<subsection>Multipart Form Values</subsection>
<p/>
When dealing with a multipart form, the array returned by <cim><front>CGI</front><back>[]</back></cim>
is composed of objects of class <classname>Tempfile</classname>, with the following
dynamically added methods:
<table>
<th>
  <td><b>Method</b></td>
  <td><b>Description</b></td>
</th>
<tr>
  <td><tt>read</tt></td>
  <td>Body</td>
</tr>
<tr>
  <td><tt>local_path</tt></td>
  <td>Path to local file containing the content</td>
</tr>
<tr>
  <td><tt>original_filename</tt></td>
  <td>Original filename of the content</td>
</tr>
<tr>
  <td><tt>content_type</tt></td>
  <td>Content type</td>
</tr>
<bottomrule/></table>
<p/>
<class name="CGI::Session" super="Object" type="class" ref="xref-000019">
<p/>
  A <classname>CGI::Session</classname> maintains a persistent state for web users in a
  CGI environment.  Sessions may be memory-resident or may be stored
  on disk.  See the discussion on page 146 for details.
<p/>
    <methods type="class">
          <method name="new" ref="new">
      <callseq>
        CGI::Session.new( <obj>aCgi</obj>, <optz><obj>aHash</obj></optz> )
            <returns><obj>aSession</obj></returns>
      </callseq>
      <desc>
<p/>
          Returns a new session object for the <classname>CGI</classname> query.  Options 
          that may be given in <obj>aHash</obj> include:
<p/>
          <table>
<th>
  <td><b>Option</b></td>
  <td><b>Description</b></td>
</th>
<tr>
  <td><tt>session_key</tt></td>
  <td>Name of CGI key for session
          identification.</td>
</tr>
<tr>
  <td><tt>session_id</tt></td>
  <td>Value of session id.</td>
</tr>
<tr>
  <td><tt>new_session</tt></td>
  <td>If <const>true</const>, create a new session 
                 id for this session. If <const>false</const>, use an
                 existing session identified by <tt>session_id</tt>. If
                 omitted, use an existing session if available,
                 otherwise create a new one.</td>
</tr>
<tr>
  <td><tt>database_manager</tt></td>
  <td>Class to use to save sessions; may be
          <classname>CGI::Session::FileStore</classname> or
          <classname>CGI::Session::MemoryStore</classname>
          (or user defined if you're
          brave). Default is <tt>FileStore</tt>.</td>
</tr>
<th>
  <td><tt>tmpdir</tt></td>
  <td>For <tt>FileStore,</tt> directory for session files.</td>
</th>
<th>
  <td><tt>prefix</tt></td>
  <td>For <tt>FileStore,</tt> prefix of session filenames.</td>
</th>
<bottomrule/></table>
<p/>
      </desc>
    </method>
<p/>
    </methods>
<p/>
    <methods type="instance">
<p/>
          <method name="[ ]" ref="_ob_cb">
      <callseq>
        <obj>aSession</obj>[ <obj>aKey</obj> ]
            <returns><obj>aValue</obj></returns>
      </callseq>
      <desc>
<p/>
          Returns the value for the given key.
<p/>
      </desc>
    </method>
<p/>
          <method name="[ ]=" ref="_ob_cb_eq">
      <callseq>
        <obj>aSession</obj>[ <obj>aKey</obj> ] = <obj>aValue</obj>
            <returns><obj>aValue</obj></returns>
      </callseq>
      <desc>
<p/>
          Sets the value for the given key.
<p/>
      </desc>
    </method>
<p/>
          <method name="delete" ref="delete">
      <callseq>
        <obj>aSession</obj>.delete
<p/>
      </callseq>
      <desc>
<p/>
          Calls the <tt>delete</tt> method of the underlying database
          manager. For <tt>FileStore</tt>, deletes the physical file
          containing the session.
          For <tt>MemoryStore</tt>, removes the session from memory.
<p/>
      </desc>
    </method>
<p/>
          <method name="update" ref="update">
      <callseq>
        <obj>aSession</obj>.update
<p/>
      </callseq>
      <desc>
<p/>
          Calls the <tt>update</tt> method of the underlying database
          manager. For <tt>FileStore</tt>, writes the session data out to
          disk. Has no effect with <tt>MemoryStore</tt>.
<p/>
      </desc>
    </method>
<p/>
    </methods>
<p/>
</class>
<p/>
</chapter>
</ppdoc>
