/* ** (c) COPYRIGHT MIT 1995. ** Please first read the full copyright statement in the file COPYRIGH. */
The Host class manages what we know about a remote host. This can for example be what type of host it is, and what version it is using. Notice that a host object can be used to describe both a server or a client - all information in the Host object can be shared regardless of whether it is to be used in a server application or a client application.
This module is implemented by HTHost.c, and it is a part of the W3C Reference Library.
#ifndef HTHOST_H #define HTHOST_H typedef struct _HTHost HTHost; #include "HTChannl.h" #include "HTReq.h" #include "HTEvent.h"
The Host class contains information about the remote host, for example the type (HTTP/1.0, HTTP/1.1, FTP etc.) along with information on how the connections can be used (if it supports persistent connections, interleaved access etc.)
We keep a cache of information that we know about a remote host. This allows us to be much more detailed in generating requests. Search the host info cache for a host object or create a new one and add it. Examples of host names are
extern HTHost * HTHost_new (char * host);
The Host Class contains an automatic garbage collection of Host objects so that we don't keep information around that is stale.
Searches the cache of known hosts to see if we already have information about this host. If not then we return NULL.
extern HTHost * HTHost_find (char * host);
This is what we know about the remote host
Get the name of the remote host. This is set automatically when a new Host object and can be asked for at any point in time. You can not change the host name but must create a new Host object instead.
extern char * HTHost_name (HTHost * host);
Define the host class of the host at the other end. A class is a generic description of the protocol which is exactly like the access method in a URL, for example "http" etc. The host version is a finer distinction (sub-class) between various versions of the host class, for example HTTP/0.9, HTTP/1.1 etc. The host version is a bit flag that the protocol module can define on its own. That way we don't have to change this module when registering a new protocol module. The host type is a description of whether we can keep the connection persistent or not.
extern char * HTHost_class (HTHost * host); extern void HTHost_setClass (HTHost * host, char * s_class); extern int HTHost_version (HTHost * host); extern void HTHost_setVersion (HTHost * host, int version);
We keep track of the capabilities of the remote host. In many cases the information that we get is specific to servers but this doesn't have to be the case.
A server can inform a client about the supported methods using the
Public
header.
extern HTMethod HTHost_publicMethods (HTHost * me); extern void HTHost_setPublicMethods (HTHost * me, HTMethod methodset); extern void HTHost_appendPublicMethods (HTHost * me, HTMethod methodset);
A server can send its server application name and version in a HTTP response. We pick up this information and add it to the Host object
extern char * HTHost_server (HTHost * host); extern BOOL HTHost_setServer (HTHost * host, const char * server);
A client can send the name of the client application in a HTTP request. We pick up this information and add it to the Host Object
extern char * HTHost_userAgent (HTHost * host); extern BOOL HTHost_setUserAgent (HTHost * host, const char * userAgent);
Since all HTTP entities are represented in HTTP messages as sequences of bytes, the concept of a byte range is meaningful for any HTTP entity. (However, not all clients and servers need to support byte-range operations.) Byte range specifications in HTTP apply to the sequence of bytes in the entity-body (not necessarily the same as the message-body). A byte range operation may specify a single range of bytes, or a set of ranges within a single entity.
You can also check whether a specific range unit is OK. We always say
YES
except if we have a specific statement from the server that
it doesn't understand byte ranges - that is - it has sent "none" in a
"Accept-Range" response header
extern char * HTHost_rangeUnits (HTHost * host); extern BOOL HTHost_setRangeUnits (HTHost * host, const char * units); extern BOOL HTHost_isRangeUnitAcceptable (HTHost * host, const char * unit);
We don't want more than MaxSockets-2 connections to be persistent in order to avoid deadlock.
extern BOOL HTHost_setChannel (HTHost * host, HTChannel * channel, HTTransportMode mode); extern BOOL HTHost_clearChannel (HTHost * host, int status); extern HTChannel * HTHost_channel (HTHost * host);
Check whether we have a persistent channel or not
extern BOOL HTHost_isPersistent (HTHost * host);
Before we can start a new connection to the host we must be sure that the host is idle. That is, if it can accept a new connection. We have several modes describing how and when a host is idle. This is a function of the Transport Object
extern BOOL HTHost_isIdle (HTHost * host);
Handle the connection mode. The mode may change mode in the middle of a connection If the new mode is lower than the old mode then adjust the pipeline accordingly. That is, if we are going into single mode then move all entries in the pipeline and move the rest to the pending queue. They will get launched at a later point in time.
extern HTTransportMode HTHost_mode (HTHost * host, BOOL * active); extern BOOL HTHost_setMode (HTHost * host, HTTransportMode mode);
Normally we wait for the peer process to close persistent connections but in order not to use up our own resources, we have a timeout on our own. The default value is 1 hour, but you can modify the value using the following methods:
extern time_t HTHost_persistTimeout (time_t timeout); extern void HTHost_setPersistTimeout (time_t timeout);
Each persistent connection has an absolute value of when this connection most likely will expire. If the peer process does not inform us, we use our own timeout.
extern void HTHost_setPersistExpires (HTHost * host, time_t expires); extern time_t HTHost_persistExpires (HTHost * host);
Requests are queued in the Host object until we have resources to start them. The request is in the form of a Net object as we may have multiple socket requests per Request object. This is for example the case with FTP which uses two connections.
extern int HTHost_addNet (HTHost * host, HTNet * net); extern BOOL HTHost_deleteNet (HTHost * host, HTNet * net); extern HTList * HTHost_net (HTHost * host);
Before we can start a new connection to the host we must be sure that the host is idle. That is, if it can accept a new connection. We have several modes describing how and when a host is idle. This is a function of the Transport Object
extern BOOL HTHost_isIdle (HTHost * host);
There are two ways we can end up with pending reqyests:
This set of functions handles pending host objects and can start new requests as resources get available. The first function checks the host object for any pending Net objects and return the first of these Net objects.
extern HTNet * HTHost_nextPendingNet (HTHost * host);
The second checks the list of pending host objects waiting for a socket and returns the first of these Host objects.
extern HTHost * HTHost_nextPendingHost (void);
Start the next pending request if any. First we look for pending requests for the same host and then we check for any other pending hosts. If nothing pending then register a catch close event handler to have something catching the socket if the remote server closes the connection, for example due to timeout.
extern BOOL HTHost_launchPending (HTHost * host);
#endif /* HTHOST_H */