Package org.w3c.www.http

Source Code of org.w3c.www.http.HttpMessage

// HttpMessage.java
// $Id: HttpMessage.java,v 1.45 2007/02/09 22:05:52 ylafon Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html

package org.w3c.www.http;

import java.io.IOException;
import java.io.OutputStream;

import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;

import org.w3c.util.ArrayDictionary;
import org.w3c.util.EmptyEnumeration;

import org.w3c.www.mime.MimeHeaderHolder;
import org.w3c.www.mime.MimeParser;

/**
* The basic class for all HTTP messages, as define in the HTTP spec.
* This class is the base class for a number of other classes, including
* both the ingoing/outgoing requests and replies.
*/

public class HttpMessage implements MimeHeaderHolder, Cloneable, HTTP {

    // FIXME doc
    public final static int EMIT_HEADERS = (1<<0);
    public final static int EMIT_BODY    = (1<<2);
    public final static int EMIT_FOOTERS = (1<<3);
    public final static int EMIT_ALL     = ((1<<0)|(1<<1)|(1<<2));

    // HTTP message well-known headers
    public static int H_CACHE_CONTROL     = 0;
    public static int H_CONNECTION        = 1;
    public static int H_PROXY_CONNECTION  = 2;
    public static int H_DATE              = 3;
    public static int H_PRAGMA            = 4;
    public static int H_TRANSFER_ENCODING = 5;
    public static int H_UPGRADE           = 6;
    public static int H_VIA               = 7;

    public static int H_PROTOCOL          = 8;
    public static int H_PROTOCOL_REQUEST  = 9;
    public static int H_PROTOCOL_INFO     = 10;
    public static int H_PROTOCOL_QUERY    = 11;

    public static int H_SET_COOKIE        = 12;
    public static int H_COOKIE            = 13;

    public static int H_TRAILER           = 14;

    public static int H_MAN_EXT           = 15;
    public static int H_OPT_EXT           = 16;
    public static int H_CMAN_EXT          = 17;
    public static int H_COPT_EXT          = 18;

    public static int MAX_HEADERS = 61;

    /**
     * The header value factory.
     */
    protected static Hashtable factory = new Hashtable(23) ;

    /**
     * The header value repository.
     * At this time, I am using this quite inefficient scheme, but the API
     * have been carefully designed to enable a more efficient implementation.
     */
    protected Dictionary headers = null ;
    /**
     * The major version of this message, according to HTTP specs.
     */
    protected short major = 1;
    /**
     * The minoir version of this message, according to HTTP specs.
     */
    protected short minor = 1;
    /**
     * The date at which this message was last emitted.
     */
    protected long emitdate = -1;
    /**
     * The state dictionary.
     */
    protected ArrayDictionary state = null;
    /**
     * The extension namespace counter.
     */
    private int extCurrentNamespace = 10;

    // FIXME
    protected
    HeaderValue values[] = null;

    protected static
    HeaderDescription descriptors[] = new HeaderDescription[MAX_HEADERS];

    // Initialize the global header factory

    protected final static void registerHeader(String name, String cls) {
  HeaderDescription d = new HeaderDescription(name, cls);
  factory.put(d.getName(), d);
    }

    protected final static void registerHeader(String name
                 , String c
                 , int i) {
  HeaderDescription d = new HeaderDescription(name, c, i);
  descriptors[i] = d;
  factory.put(d.getName(), d);
    }

    static {
  registerHeader("Cache-Control"
           , "org.w3c.www.http.HttpCacheControl"
           , H_CACHE_CONTROL);
  registerHeader("Connection"
           , "org.w3c.www.http.HttpTokenList"
           , H_CONNECTION);
  registerHeader("Proxy-Connection"
           , "org.w3c.www.http.HttpTokenList"
           , H_PROXY_CONNECTION);
  registerHeader("Date"
           , "org.w3c.www.http.HttpDate"
           , H_DATE);
  registerHeader("Pragma"
           , "org.w3c.www.http.HttpTokenList"
           , H_PRAGMA);
  registerHeader("Transfer-Encoding"
           ,"org.w3c.www.http.HttpTokenList"
           , H_TRANSFER_ENCODING);
  registerHeader("Upgrade"
           , "org.w3c.www.http.HttpTokenList"
           , H_UPGRADE);
  registerHeader("Via"
           , "org.w3c.www.http.HttpCaseTokenList"
           , H_VIA);
  registerHeader("Trailer"
           , "org.w3c.www.http.HttpTokenList"
           , H_TRAILER);
  registerHeader("Protocol"
           , "org.w3c.www.http.HttpBag"
           , H_PROTOCOL);
  registerHeader("Protocol-Request"
           , "org.w3c.www.http.HttpBag"
           , H_PROTOCOL_REQUEST);
  registerHeader("Protocol-Query"
           , "org.w3c.www.http.HttpBag"
           , H_PROTOCOL_QUERY);
  registerHeader("Protocol-Info"
           , "org.w3c.www.http.HttpBag"
           , H_PROTOCOL_INFO);
  registerHeader("Set-Cookie"
           , "org.w3c.www.http.HttpSetCookieList"
           , H_SET_COOKIE);
  registerHeader("Cookie"
           , "org.w3c.www.http.HttpCookieList"
           , H_COOKIE);
  registerHeader("Man",
           "org.w3c.www.http.HttpExtList",
           H_MAN_EXT);
  registerHeader("Opt",
           "org.w3c.www.http.HttpExtList",
           H_OPT_EXT);
  registerHeader("C-Man",
           "org.w3c.www.http.HttpExtList",
           H_CMAN_EXT);
  registerHeader("C-Opt",
           "org.w3c.www.http.HttpExtList",
           H_COPT_EXT);
    }

    /**
     * Get a header value, given its name.
     * @param name The name of the field whose value is to be fetched.
     * @param def The default value if the field is undefined.
     */

    public HeaderValue getHeaderValue(String name, HeaderValue def) {
  // Check the description, for fast access:
  HeaderValue       v = null;
  HeaderDescription d = (HeaderDescription) factory.get(name);
  if ( d != null  && d.offset >= 0) {
      v = values[d.offset];
  } else if ( headers != null ) {
      v = (HeaderValue) headers.get(name);
  }
  return v == null ? def : v ;
    }

    /**
     * Get a header value by name.
     * @param name The header's name.
     * @return The value of the header, as a String, or
     * <strong>null</strong>
     * if undefined.
     */

    public final HeaderValue getHeaderValue(String name) {
  return getHeaderValue(name.toLowerCase(), null);
    }

    /**
     * Fast access to header value.
     * <p>This method provides a very fast access to pre-defined header
     * values. You can use it on all headers that have an access token.
     * @param idx The token of the header to access.
     * @return An instance of <code>HeaderValue</code> or <strong>null
     * </strong> if undefined.
     */

    public final HeaderValue getHeaderValue(int idx) {
  return values[idx];
    }

    /**
     * Set a header value.
     * @param name The name of the header to define.
     * @param value It's HeaderValue.
     */

    public void setHeaderValue(String name, HeaderValue value) {
  String lname = name.toLowerCase();
  HeaderDescription d = (HeaderDescription) factory.get(lname);
  if(d != null && d.offset >= 0) {
      values[d.offset] = value ;
  } else {
      if ( headers == null )
    headers = new ArrayDictionary(5, 5);
      headers.put(lname, value);
  }
    }

    /**
     * Get a header value, keyed by it's header description.
     * This is usefull when enumerating headers, by the mean of
     * <code>enumerateHeaderDescriptions</code>.
     * @param d The header description.
     * @return A HeaderValue instance, if the header is defined,
     * <strong>null</strong> otherwise.
     */

    public HeaderValue getHeaderValue(HeaderDescription d) {
  // Try to be as fast as possible:
  if ( d.offset >= 0 ) {
      return values[d.offset];
  } else {
      return ((headers != null)
        ? (HeaderValue) headers.get(d.getName())
        : null);
  }
    }

    /**
     * Set a header value, keyed by it's header description.
     * @param d The header description.
     * @param v The HeaderValue instance, or <strong>null</strong> to
     * reset the header value.
     */

    public void setHeaderValue(HeaderDescription d, HeaderValue v) {
  if ( d.offset >= 0 ) {
      values[d.offset] = v;
  } else {
      if ( headers == null )
    headers = new ArrayDictionary(5, 5);
      headers.put(d.getName(), v);
  }
    }

    /**
     * Fast write accessor to headers.
     * <p> This method provides a very fast write access to header
     * values. It can be used with any of the headers that have
     * a pre-defined access token.
     * @param idx The access token of the header's to write to.
     * @param value The new header value.
     */

    public final void setHeaderValue(int idx, HeaderValue value) {
  values[idx] = value;
    }

    /**
     * Remove a header, by name.
     * @param name The name of the header to remove.
     */

    public void removeHeader(String name) {
  String lname = name.toLowerCase();
  HeaderDescription d = (HeaderDescription) factory.get(lname);
  if ( d != null ) {
      if ( d.offset >= 0 ) {
    values[d.offset] = null;
      } else if ( headers != null ) {
    headers.remove(lname);
      }
  }
    }

    /**
     * Remove a header, by address.
     * A fast version of the above.
     * @param idx The index of the header to remove.
     */

    public final void removeHeader(int idx) {
  if ((idx >= 0) && (idx < MAX_HEADERS))
      values[idx] = null;
    }

    /**
     * Enumerate all the available headers for that message.
     * This method returns an enumeration of HeaderDescription instances,
     * which you can then use to access most efficiently header values.
     * @param all If <strong>true</strong> the enumeration will cover
     * all headers (even the ones that are not defined for that message)
     * otherwise, it will cover only defined headers.
     * @return An enumeration.
     */

    public Enumeration enumerateHeaderDescriptions(boolean all) {
  return new headerEnumerator(this, all);
    }

    /**
     * Enumerate all the headers defined for that message.
     * This method returns an enumeration of HeaderDescription instances,
     * which you can then use to access most efficiently header values.
     * @return An enumeration.
     */

    public Enumeration enumerateHeaderDescriptions() {
  return new headerEnumerator(this, false);
    }

    /**
     * State management - Add a piece of state to this request.
     * If the piece of state already exists, it is overriden by the new
     * value.
     * @param name The name of the piece of state to define.
     * @param value It's corresponding value, or <strong>null</strong> to
     * reset the value.
     */

    public void setState(String name, Object value) {
  if ( value != null ) {
      if ( state == null )
    state = new ArrayDictionary(4, 4);
      state.put(name, value);
  } else if ( state != null ) {
      state.remove(name);
  }
    }

    /**
     * State management - Lookup the value of a state on this request.
     * @param name The name of the piece of state to look for.
     * @return An object, if the piece of state is defined, <strong>null
     * </strong> otherwise.
     */

    public Object getState(String name) {
  return (state == null) ? null : state.get(name);
    }

    /**
     * State management - Remove a piece of state from this request.
     * @param name The name of the piece of state to remove.
     */

    public void delState(String name) {
  if ( state != null )
      state.remove(name);
    }

    /**
     * State management - Is the given state defined for the message ?
     * @return A boolean <strong>true</strong> if the state is defined,
     * <strong>false</strong> otherwise.
     */

    public boolean hasState(String name) {
  return (state != null) && (state.get(name) != null);
    }

    /**
     * Get an enumeration of the states names.
     * @return an Enumeration
     */
    public Enumeration getStateNames() {
  return ((state != null) ? state.keys() : new EmptyEnumeration());
    }

    /**
     * Get a clone of this HTTP message.
     * @return An HttpMessage, of the class of the message receiver.
     */

    public HttpMessage getClone() {
  try {
      // Start by a std clone:
      HttpMessage cl =  (HttpMessage) clone();
      // Then all tables:
      cl.values  = new HeaderValue[MAX_HEADERS];
      System.arraycopy(values, 0, cl.values, 0, MAX_HEADERS);
      if ( cl.headers != null )
    cl.headers = ((ArrayDictionary)
            ((ArrayDictionary) headers).clone());
      if ( cl.state != null )
    cl.state = (ArrayDictionary) state.clone();
      return cl;
  } catch (Exception ex) {
      throw new RuntimeException ("Clone not supported !");
  }
    }

    /**
     * Get a clone of this HTTP message.
     * It is a semi-deep clone, not a complete one.
     * @return An HttpMessage, of the class of the message receiver.
     */

    public HttpMessage getDeeperClone() {
  try {
      // Start by a std clone:
      HttpMessage cl =  (HttpMessage) clone();
      // Then all tables:
      cl.values  = new HeaderValue[MAX_HEADERS];
      for (int i=0; i< MAX_HEADERS; i++) {
    if (values[i] != null) {
        cl.values[i] = (HeaderValue)
                            ((BasicValue) values[i]).clone();
    }
      }
      // that _should_ be ok.
      if ( cl.headers != null )
    cl.headers = ((ArrayDictionary)
            ((ArrayDictionary) headers).clone());
      // FIXME need to do a better cloning of that.
      if ( cl.state != null )
    cl.state = (ArrayDictionary) state.clone();
      return cl;
  } catch (Exception ex) {
      throw new RuntimeException ("Clone not supported !");
  }
    }

    /**
     * Get a header field value as a String.
     * @param name The name of the header.
     * @return A String giving the header value, or <strong>null</strong>
     *    if undefined.
     */

    public String getValue(String name) {
  HeaderValue value = getHeaderValue(name);
  return (value != null) ? value.toExternalForm() : null;
    }

    /**
     * Get a header field value as a String.
     * @param d The header description.
     * @return The String value for the given header, or <strong>null</strong>
     * if undefined.
     */

    public String getValue(HeaderDescription d) {
  HeaderValue v = getHeaderValue(d);
  return (v == null) ? null : v.toString();
    }

    /**
     * Define a new header field.
     * @param name The name of the header to be defined or reset.
     * @param value It's String value, or <strong>null</strong> to reset
     * the value.
     */

    public void setValue(String name, String strval) {
  String            lname = name.toLowerCase();
  HeaderDescription d     = null;
  // If reset ing value:
  if ( strval == null ) {
      d = (HeaderDescription) factory.get(lname);
      if ( d != null ) {
    if ( d.offset >= 0 ) {
        values[d.offset] = null;
    } else if ( headers != null ) {
        headers.remove(lname);
    }
      }
      return;
  }
  // Get or create the appropriate value holder:
  HeaderValue value = getHeaderValue(lname);
  if ( value == null ) {
      if ( d == null )
    d = (HeaderDescription) factory.get(lname);
      if ( d == null ) {
    registerHeader(name, "org.w3c.www.http.HttpString");
    value = new HttpString();
      } else {
    value = d.getHolder();
      }
  }
  // Set (or reset) the byte value:
  byte bval[] = new byte[strval.length()];
  strval.getBytes(0, bval.length, bval, 0);
  value.setBytes(bval, 0, bval.length);
  // Register this new header:
  setHeaderValue(lname, value);
    }

    /**
     * Probe this message for a defined header.
     * @param name The name of the header to check.
     * @return <strong>true</strong> if the header is defined, <strong>
     *    false</strong> otherwise.
     */

    public boolean hasHeader(String name) {
  return getHeaderValue(name) != null;
    }

    /**
     * Probe this message for a defined header, fast access !
     * @param idx The index of the well-known header to check.
     * @return <strong>true</strong> if the header is defined, <strong>
     *    false</strong> otherwise.
     */

    public boolean hasHeader(int idx) {
  return values[idx] != null;
    }

    /**
     * MimeHeaderHolder implementation - The MIME parser callback.
     * This method is called if the HttpMessage is created by parsing
     * an input stream. Each time the MIME parser detects a new header
     * field, it calls back this method.
     * @param name The name of the header that has been encountered.
     * @param buf The buffer containing the header value.
     * @param off The offset of the header value in the above buffer.
     * @param len The length of the header value in the above buffer.
     */

    public void notifyHeader(String name, byte buf[], int off, int len) {
  // Get the header value repository, or create a new one:
  String      lname = name.toLowerCase();
  HeaderValue value = getHeaderValue(lname);
  if ( value == null ) {
      HeaderDescription d = (HeaderDescription) factory.get(lname);
      if ( d == null ) {
    // Slow header access anyway:
    value = new HttpString();
    if ( headers == null )
        headers = new ArrayDictionary(5, 5);
    registerHeader(name, "org.w3c.www.http.HttpString");
    headers.put(lname, value);
      } else {
    value = d.getHolder();
    if (d.offset >= 0) {
        values[d.offset] = value;
    } else {
        if ( headers == null )
      headers = new ArrayDictionary(5, 5);
        headers.put(lname, value);
    }
      }
  }
  // Notify the header value of the newly received bunch of bytes:
  value.addBytes(buf, off, len);
    }

    /**
     * MimeHeaderHolder implementation - HTTP message about to be parsed.
     * No further action is required at this point (we do not distinguish
     * between request or reply here). The MIME parsing is to continue normally
     * so we return <strong>false</strong>.
     * @return Always <strong>false</strong> to conotinue the MIME parsing.
     * @exception HttpParserException if parsing failed.
     * @exception IOException if an IO error occurs.
     */

    public boolean notifyBeginParsing(MimeParser parser)
   throws HttpParserException, IOException
    {
  return false;
    }

    /**
     * MimeHeaderHolder implementation - HTTP message parsing done.
     * Nothing special to be done here, return straight.
     * @exception HttpParserException if parsing failed.
     * @exception IOException if an IO error occurs.
     */

    public void notifyEndParsing(MimeParser parser)
   throws HttpParserException, IOException
    {
  return;
    }

    /**
     * This message is about to be emited.
     * Take any appropriate actions.
     * @exception IOException if an IO error occurs.
     */

    protected void startEmit(OutputStream out, int what)
  throws IOException
    {
  return ;
    }

    /**
     * This message has been emited.
     * Take any appropriate action.
     * @exception IOException if an IO error occurs.
     */

    protected void endEmit(OutputStream out, int what)
  throws IOException
    {
  return ;
    }

    /**
     * Emit the headers.
     * @exception IOException if an IO error occurs.
     */
    protected void emitHeaders(OutputStream out, int what)
  throws IOException
    {
  if ((what & EMIT_HEADERS) != EMIT_HEADERS) {
      return;
 
  // If no date is set, then it's time to set it ourself:
  emitdate = System.currentTimeMillis();
  if ( ! hasHeader(H_DATE) ) {
      setHeaderValue(H_DATE, new HttpDate(true, emitdate));
  }
  //Update the Connection Header for hop by hop extensions
  String oldconn[] = getConnection();
  HttpTokenList connection   = null;
  if (oldconn != null) {
      connection = new HttpTokenList(oldconn);
  } else {
      connection = new HttpTokenList(new String[0]);
  }
  HttpExtList extl = getHttpCManExtDecl();
  if (extl != null) {
      connection.addToken("C-Man", false);
      HttpExt exts[] = extl.getHttpExts();
      for (int i=0 ; i < exts.length ; i++) {
    HttpExt     ext     = exts[i];
    Dictionary  headers = getExtensionHeaders(ext);
    Enumeration henum   = headers.keys();
    while (henum.hasMoreElements()) {
        String header =
      ext.getRealHeader((String) henum.nextElement());
        connection.addToken(header, false);
    }
      }
  }
  extl = getHttpCOptExtDecl();
  if (extl != null) {
      connection.addToken("C-Opt", false);
      HttpExt exts[] = extl.getHttpExts();
      for (int i=0 ; i < exts.length ; i++) {
    HttpExt     ext     = exts[i];
    Dictionary  headers = getExtensionHeaders(ext);
    Enumeration henum   = headers.keys();
    while (henum.hasMoreElements()) {
        String header =
      ext.getRealHeader((String) henum.nextElement());
        connection.addToken(header, false);
    }
      }
  }

  if (hasHeader("C-Ext"))
      connection.addToken("C-Ext", false);

  String tokens[] = (String[])connection.getValue();
  if ((tokens != null) && (tokens.length > 0))
      setHeaderValue(H_CONNECTION, connection);
 
  //update cache control for Ext header
  if (hasHeader("Ext"))
      addNoCache("Ext");

  // Emit well-known headers first:
  for (int i = 0 ; i < MAX_HEADERS ; i++) {
      HeaderDescription d = descriptors[i];
      HeaderValue       v = values[i];
      if (v instanceof HttpSetCookieList) {
    // ugly hack :(
    HttpSetCookieList hscl = (HttpSetCookieList) v;
    if (hscl.isOriginal()) {
        int nbc = hscl.length();
        if (nbc == 0) { //the ugliest hack I have ever wrote ;-)
      out.write(d.getTitle());
      out.write(':'); out.write(' ');
      v.emit(out);
      out.write('\r'); out.write('\n');
        } else {
      for (int j = 0 ; j < nbc ; j++) {
          out.write(d.getTitle());
          out.write(':'); out.write(' ');
          hscl.emitCookie(out, j);
          out.write('\r'); out.write('\n');
      }
        }
    } else {
        int rcs = hscl.copyLength();
        for (int j = 0 ; j < rcs ; j++) {
      out.write(d.getTitle());
      out.write(':'); out.write(' ');
      hscl.emitCopyCookie(out, j);
      out.write('\r'); out.write('\n');
        }
    }
      } else if ( v != null ) {
    out.write(d.getTitle());
    out.write(':'); out.write(' ');
    v.emit(out);
    out.write('\r'); out.write('\n');
      }
  }
  // Emit extension headers:
  if ( headers != null ) {
      Enumeration e = headers.keys();
      while ( e.hasMoreElements() ) {
    String            n = (String) e.nextElement();
    HeaderDescription d = (HeaderDescription) factory.get(n);
    HeaderValue       v = (HeaderValue) headers.get(n);
    if ( v != null ) {
        out.write(d.getTitle());
        out.write(':'); out.write(' ');
        v.emit(out);
        out.write('\r'); out.write('\n');
    }
      }
  }
  out.write('\r'); out.write('\n');
    }

    public void dump(OutputStream out) {
  try {
      emitHeaders(out, EMIT_HEADERS);
  } catch (Exception ex) {
  }
    }

    /**
     * Emit this message to the given output stream.
     * This methods emits the given message to the stream, after invoking
     * the <code>startEmit</code> method. Once the whole message has been
     * emited, the <code>endEmit</code> method is called back.
     * @param out The output stream to emit the message to.
     * @exception IOException If the message couldn't be emited to the
     * given stream, due to IO errors.
     */

    public void emit(OutputStream out)
  throws IOException
    {
  startEmit(out, EMIT_ALL) ;
  if ( major > 0 )
      emitHeaders(out, EMIT_ALL);
  endEmit(out, EMIT_ALL) ;
    }
    /**
     * @param out The output stream to emit the message to.
     * @param what (fixme doc)
     * @exception IOException If the message couldn't be emited to the
     * given stream, due to IO errors.
     */
    public void emit(OutputStream out, int what)
  throws IOException
    {
  startEmit(out, what);
  emitHeaders(out, what);
  endEmit(out, what);
    }

    /**
     * Header accessor - set the cache control associated with the message.
     * This method should not be used in general, it's much more preferable
     * to use the various cache control accessors available.
     * @param control The cache control policy, or <strong>null</strong>
     * to reset the value.
     */

    public void setCacheControl(HttpCacheControl control) {
  setHeaderValue(H_CACHE_CONTROL, control);
    }

    /**
     * Header accessor - get the cache control policy.
     * @return The current cache control policy, or <strong>null</strong>
     *     if undefined.
     */

    public HttpCacheControl getCacheControl() {
  HeaderValue value = getHeaderValue(H_CACHE_CONTROL);
  return (value != null) ? (HttpCacheControl) value.getValue() : null;
    }

    /**
     * Set the <code>max-age</code> value of the associated cache control.
     * This method hides as much as possible, the difference between
     * HTTP/1.1 max-age, and HTTP/1.0 expires headers. It will set only
     * the appropriate one.
     * @param maxage The max-age value, or <strong>-1</strong> to reset the
     * value.
     */

    public void setMaxAge(int maxage) {
  HttpCacheControl cc = getCacheControl();
  if ( cc == null ) {
      if ( maxage == -1 )
    return ;
      setCacheControl(cc = new HttpCacheControl(true));
  }
  cc.setMaxAge(maxage);
    }

    /**
     * Get the <code>max-age</code> value for the current cache control.
     * @return The max age value, as an integer, or <strong>-1</strong> if
     * undefined.
     */

    public int getMaxAge() {
  HttpCacheControl cc = getCacheControl();
  return (cc == null) ? -1 : cc.getMaxAge();
    }

    /**
     * Set the <code>s-maxage</code> value of the associated cache control.
     * Set the s-maxage value on an HTTP/1.1 reply
     * @param maxage The max-age value in seconds, or <strong>-1</strong>
     * to reset the value.
     */

    public void setSMaxAge(int smaxage) {
  HttpCacheControl cc = getCacheControl();
  if ( cc == null ) {
      setCacheControl(cc = new HttpCacheControl(true));
  }
  cc.setSMaxAge(smaxage);
    }

    /**
     * Get the <code>s-maxage</code> value for the current cache control.
     * @return The s-maxage value, as an integer (seconds), or
     * <strong>-1</strong> if undefined.
     */
    public int getSMaxAge() {
  HttpCacheControl cc = getCacheControl();
  return (cc == null) ? -1 : cc.getSMaxAge();
    }

    /**
     * Get the <code>no-cache</code> directive of the cache control header.
     * @return A list of token (potentially empty) encoded as an array of
     * String (with 0 length if empty), or <strong>null</strong> if
     * undefined.
     */

    public String[] getNoCache() {
  HttpCacheControl cc = getCacheControl();
  return (cc == null) ? null : cc.getNoCache();
    }

    /**
     * Set the <code>no-cache</code> directive of the cache control header.
     * @param nocache A list of headers name encoded as an array of String
     * (of length possibly <strong>0</strong>), or <strong>null</strong>
     * to reset the value.
     */

    public void setNoCache(String nocache[]) {
  HttpCacheControl cc = getCacheControl();
  if ( cc == null ) {
      if ( nocache == null )
    return;
      setCacheControl(cc = new HttpCacheControl(true));
  }
  cc.setNoCache(nocache);
    }

    /**
     * Set the <code>no-cache</code> directive globally.
     */

    public void setNoCache() {
  HttpCacheControl cc = getCacheControl();
  if ( cc == null )
      setCacheControl(cc = new HttpCacheControl(true));
  cc.setNoCache();
    }

    /**
     * Add the given header name to the <code>no-cache</code> directive.
     * @param name The header name to add there.
     */

    public void addNoCache(String name) {
  HttpCacheControl cc = getCacheControl();
  if ( cc == null )
      setCacheControl(cc = new HttpCacheControl(true));
  cc.addNoCache(name);
    }

    /**
     * Check the <code>no-store</code> directive of the cache control header.
     * @return A boolean <strong>true</strong> if set, <strong>false</strong>
     * otherwise.
     */

    public boolean checkNoStore() {
  HttpCacheControl cc = getCacheControl();
  return (cc == null) ? false : cc.checkNoStore();
    }

    /**
     * Set the <code>no-store</code> directive.
     * @param onoff Turn it on or off.
     */

    public void setNoStore(boolean onoff) {
  HttpCacheControl cc = getCacheControl();
  if ( cc == null ) {
      if ( ! onoff )
    return;
      setCacheControl(cc = new HttpCacheControl(true));
  }
  cc.setNoStore(onoff);
    }

    /**
     * Check the <code>only-if-cached</code> directive.
     * @return A boolean, <strong>true</strong> if the directive is set,
     * <strong>false</strong> otherwise.
     */

    public boolean checkOnlyIfCached() {
  HttpCacheControl cc = getCacheControl();
  return (cc == null) ? false : cc.checkOnlyIfCached();
    }

    /**
     * Set the <code>only-if-cached</code> directive.
     * @param onoff Turn it on or off.
     */

    public void setOnlyIfCached(boolean onoff) {
  HttpCacheControl cc = getCacheControl();
  if (cc == null) {
      if ( ! onoff )
    return;
      setCacheControl(cc = new HttpCacheControl(true));
  }
  cc.setOnlyIfCached(onoff);
    }

    // FIXME add all the other cache control directive

    /**
     * Header accessor - set the connection header value.
     * @param tokens The connection tokens as a String array, or <strong>null
     * </strong> to reset the value.
     */

    public void setConnection(String tokens[]) {
  setHeaderValue(H_CONNECTION
           , ((tokens == null)
        ? null
        : new HttpTokenList(tokens)));
    }

    /**
     * Header accessor - get the connection header value.
     * @return The tokens of the connection header, as a String array, or
     * <strong>null</strong> if undefined.
     */

    public String[] getConnection() {
  HeaderValue value = getHeaderValue(H_CONNECTION);
  return (value != null) ? (String[]) value.getValue() : null;
    }

    /**
     * Add the given header name to the <code>Connection</code> header.
     * @param name The name of the header to add to the <code>Connection</code>
     * header.
     */

    public void addConnection(String name) {
  HttpTokenList list = (HttpTokenList) getHeaderValue(H_CONNECTION);
  if ( list == null ) {
      String sList[] = new String[1];
      sList[0]       = name.toLowerCase();
      setHeaderValue(H_CONNECTION, new HttpTokenList(sList));
  } else {
      list.addToken(name, false);
  }
    }

    /**
     * Does the connection header include the given token ?
     * @return A boolean.
     */

    public boolean hasConnection(String tok) {
  HttpTokenList list = (HttpTokenList) getHeaderValue(H_CONNECTION);
  return (list == null) ? false : list.hasToken(tok, false);
    }

    /**
     * Header accessor - set the proxy connection header value.
     * @param tokens The connection tokens as a String array, or
     * <strong>null</strong> to reset the value.
     */

    public void setProxyConnection(String tokens[]) {
  setHeaderValue(H_PROXY_CONNECTION
           , ((tokens == null)
        ? null
        : new HttpTokenList(tokens)));
    }

    /**
     * Add the given header name to the <code>Proxy-Connection</code> header.
     * @param name The name of the header to add to the
     * <code>Proxy-Connection</code> header.
     */

    public void addProxyConnection(String name) {
  HttpTokenList list = (HttpTokenList)getHeaderValue(H_PROXY_CONNECTION);
  if ( list == null ) {
      String sList[] = new String[1];
      sList[0]       = name.toLowerCase();
      setHeaderValue(H_PROXY_CONNECTION, new HttpTokenList(sList));
  } else {
      list.addToken(name, false);
  }
    }

    /**
     * Header accessor - get the proxy connection header value.
     * @return The tokens of the connection header, as a String array,
     * or <strong>null</strong> if undefined.
     */

    public String[] getProxyConnection() {
  HeaderValue value = getHeaderValue(H_PROXY_CONNECTION);
  return (value != null) ? (String[]) value.getValue() : null;
    }

    /**
     * Does the proxy connection header defines the given token.
     * @param tok The token to check for.
     * @return A boolean.
     */

    public boolean hasProxyConnection(String tok) {
  HttpTokenList l = (HttpTokenList) getHeaderValue(H_PROXY_CONNECTION);
  return (l == null) ? false : l.hasToken(tok, false);
    }

    /**
     * Header accessor - set the date of this message.
     * @param date The date of the message, following Java runtime conventions
     * (number of milliseconds since epoch), or <strong>-1</strong> to
     * reset the value.
     */

    public void setDate(long date) {
  setHeaderValue(H_DATE
           , ((date == -1) ? null : new HttpDate(true, date)));
    }

    /**
     * Header accessor - get the date of this message.
     * @return A long giving the date of this message, following the Java
     *    runtime convention (milliseconds since epoch), or <strong>-1</strong>
     *    if undefined.
     */

    public long getDate() {
  HeaderValue date = getHeaderValue(H_DATE);
  return (date != null) ? ((Long) date.getValue()).longValue() : -1;
    }

    /**
     * Header accessor - set the pragmas applicable to this message.
     * @param tokens The pragma tokens as a String array, or <strong>null
     * </strong> to reset the value.
     */

    public void setPragma(String tokens[]) {
  setHeaderValue(H_PRAGMA
           , ((tokens == null)
        ? null
        : new HttpTokenList(tokens)));
    }

    /**
     * Header accessor - get the pragmas applicable to this message.
     * @return The pragma tokens applicable to this message, encoded
     *    as a String array, or <strong>null</strong> if undefined.
     */

    public String[] getPragma() {
  HeaderValue value = getHeaderValue(H_PRAGMA);
  return (value != null) ? (String[]) value.getValue() : null;
    }

    /**
     * Header accessor - Check for a given pragma.
     * @param pragma The pragma to check for.
     * @return A boolean <strong>true</strong> if this pragma is set,
     * <strong>false</strong> otherwise.
     */

    public boolean hasPragma(String pragma) {
  HttpTokenList list = (HttpTokenList) getHeaderValue(H_PRAGMA);
  return (list != null) ? list.hasToken(pragma, false) : false;
    }

    /**
     * Add the given directive to the <code>Pragma</code> header.
     * @param name The name of the directive to add to the <code>Pragma</code>
     * header.
     */

    public void addPragma(String name) {
  HttpTokenList list = (HttpTokenList) getHeaderValue(H_PRAGMA);
  if ( list == null ) {
      String sList[] = new String[1];
      sList[0]       = name.toLowerCase();
      setHeaderValue(H_PRAGMA, new HttpTokenList(sList));
  } else {
      list.addToken(name, false);
  }
    }

    /**
     * Header accessor - set the transfer encoding for this message.
     * This just sets the transfer encoding, it is up to the rest of the
     * application to make sure that the encoding is actually applied
     * at emiting time.
     * @param tokens The transfer encoding tokens as a String array, or
     * <strong>null</strong> to reset the value.
     */

    public void setTransferEncoding(String tokens[]) {
  setHeaderValue(H_TRANSFER_ENCODING
           , ((tokens == null)
        ? null
        : new HttpTokenList(tokens)));
    }

    /**
     * Add an encoding token to the given reply stream (ie the body).
     * @param name The name of the encoding to add.
     */

    public void addTransferEncoding(String name) {
  HttpTokenList l = (HttpTokenList) getHeaderValue(H_TRANSFER_ENCODING);
  if ( l == null ) {
      String sList[] = new String[1];
      sList[0]       = name.toLowerCase();
      setHeaderValue(H_TRANSFER_ENCODING, new HttpTokenList(sList));
  } else {
      l.addToken(name, false);
  }
    }

    /**
     * Header accessor - get the transfer encoding applying to this message.
     * @return The list of encoding tokens, as a String array, or <strong>
     *    null</strong> if undefined.
     */

    public String[] getTransferEncoding() {
  HeaderValue value = getHeaderValue(H_TRANSFER_ENCODING);
  return (value != null) ? (String[]) value.getValue() : null;
    }

    /**
     * Header accessor - Check for a given transfer encoding.
     * @param encoding The pragma to check for.
     * @return A boolean <strong>true</strong> if this encoding is set,
     * <strong>false</strong> otherwise.
     */

    public boolean hasTransferEncoding(String encoding) {
  HttpTokenList l = (HttpTokenList) getHeaderValue(H_TRANSFER_ENCODING);
  return (l != null) ? l.hasToken(encoding, false) : false;
    }

    /**
     * Header accessor - set the upgrade header of this message.
     * @param products An array of products you want this message to carry
     * or <strong>null</strong> to reset the value.
     */

    public void setUpgrade(String products[]) {
  setHeaderValue(H_UPGRADE
           , ((products == null)
        ? null
        : new HttpTokenList(products)));
    }

    /**
     * Header accessor - get the upgrade header of this message.
     * @return A list of products, encoded as an array of String
     *    or <strong>null</strong> if undefined.
     */

    public String[] getUpgrade() {
  HeaderValue value = getHeaderValue(H_UPGRADE);
  return (value != null) ? (String[]) value.getValue() : null;
    }

    /**
     * Header accessor - set the Via header of this message.
     * @param vias The hops to be placed in the <code>Via</code> header, or
     * <strong>null</strong> to reset the value.
     */

    public void setVia(String vias[]) {
  setHeaderValue(H_VIA
           , ((vias == null) ? null : new HttpTokenList(vias)));
    }

    /**
     * Header accessor - get the via header of this message.
     * @return A Via array describing each hop of the message, or <strong>
     *    null</strong> if undefined.
     */

    public String[] getVia() {
  HeaderValue value = getHeaderValue(H_VIA);
  return (value != null) ? (String[]) value.getValue() : null;
    }

    /**
     * Add a via clause to the via header.
     * @param via The new via clause.
     */

    public void addVia(String via) {
  HttpTokenList list = (HttpTokenList) getHeaderValue(H_VIA);
  if ( list == null ) {
      String sList[] = new String[1];
      sList[0]       = via;
      setVia(sList);
  } else {
      list.addToken(via, true);
  }
    }

    /**
     * Get the set of protocol extensions that have been applied to that
     * that message.
     * @return A bag containing the description of the protocol extensions
     * applied to that message, or <strong>null</strong>.
     */

    public HttpBag getProtocol() {
  HeaderValue value = getHeaderValue(H_PROTOCOL);
  return (value != null) ? (HttpBag) value.getValue() : null;
    }

    /**
     * Set the protocol extensions applied to that message.
     * @param protocols A bag instance, describing the protocol extensions
     * applied to the message, or <strong>null</strong> to reset previous
     * value.
     */

    public void setProtocol(HttpBag bag) {
  setHeaderValue(H_PROTOCOL, bag);
    }

    /**
     * Get the set of protocol extensions requested by this message.
     * @return A bag containing the description of the protocol extensions
     * requested by this message, or <strong>null</strong>.
     */

    public HttpBag getProtocolRequest() {
  HeaderValue value = getHeaderValue(H_PROTOCOL_REQUEST);
  return (value != null) ? (HttpBag) value.getValue() : null;
    }

    /**
     * Set the protocol extensions required by this message.
     * @param protocols A bag instance, describing the protocol extensions
     * required by the message, or <strong>null</strong> to reset previous
     * value.
     */

    public void setProtocolRequest(HttpBag bag) {
  setHeaderValue(H_PROTOCOL_REQUEST, bag);
    }

    /**
     * Get the protocol extensions informations carried by this message.
     * @return A bag containing the description of the protocol extensions
     * informations carried by that message, or <strong>null</strong>.
     */

    public HttpBag getProtocolInfo() {
  HeaderValue value = getHeaderValue(H_PROTOCOL_INFO);
  return (value != null) ? (HttpBag) value.getValue() : null;
    }

    /**
     * Attach protocol extensions informations to that message.
     * @param protocols A bag instance, describing the protocol extensions
     * informations to attach to the message, or <strong>null</strong> to
     * reset previous value.
     */

    public void setProtocolInfo(HttpBag bag) {
  setHeaderValue(H_PROTOCOL_INFO, bag);
    }

    /**
     * Get the set of protocol extensions that are queried through this
     * message.
     * @return A bag containing the description of the protocol extensions
     * queried by that message, or <strong>null</strong>.
     */

    public HttpBag getProtocolQuery() {
  HeaderValue value = getHeaderValue(H_PROTOCOL_QUERY);
  return (value != null) ? (HttpBag) value.getValue() : null;
    }

    /**
     * Set the protocol extensions queried by that message.
     * @param protocols A bag instance, describing the protocol extensions
     * queried by the message, or <strong>null</strong> to reset previous
     * value.
     */

    public void setProtocolQuery(HttpBag bag) {
  setHeaderValue(H_PROTOCOL_QUERY, bag);
    }

    /**
     * Get this message trailer
     * @return A list of encoding tokens, encoded as a String array, or
     *    <strong>null</strong> if undefined.
     */

    public String[] getTrailer() {
  HeaderValue value = getHeaderValue(H_TRAILER);
  return (value != null) ? (String[]) value.getValue() : null;
    }

    /**
     * Set this message trailer
     * @param encodings A list of encoding tokens, encoded as a String array
     * or <strong>null</strong> to reset the value.
     */

    public void setTrailer(String trailers[]) {
  setHeaderValue(H_TRAILER
           , ((trailers == null)
        ? null
        : new HttpTokenList(trailers)));
    }

    /**
     * Get the value of the SetCookie header.
     * @return AN HttpSetCookie instance, or <strong>null</strong> if
     * undefined.
     */

    public HttpSetCookieList getSetCookie() {
  HeaderValue value = getHeaderValue(H_SET_COOKIE);
  return (value != null) ? (HttpSetCookieList) value.getValue() : null;
    }

    /**
     * Set the value of the Set-Cookie header.
     * @param setcookies The HttpSetCookie value.
     */

    public void setSetCookie(HttpSetCookieList setcookie) {
  setHeaderValue(H_SET_COOKIE, setcookie);
    }

    /**
     * Get the cookies attached to that message.
     * @return An instance of HttpCookie holding the list of available
     * cookies, or <strong>null</strong> if undefined.
     */

    public HttpCookieList getCookie() {
  HeaderValue value = getHeaderValue(H_COOKIE);
  return (value != null) ? (HttpCookieList) value.getValue() : null;
    }

    /**
     * Set the cookies attached to this message.
     * @param cookies The HttpCookie instance describing the cookies, or
     * <strong>null</strong> to reset value.
     */

    public void setCookie(HttpCookieList cookie) {
  setHeaderValue(H_COOKIE, cookie);
    }

    /**
     * Get the String identifying the HTTP version used for this message.
     * @return A String identifying the protocol version.
     */

    public String getVersion() {
  switch(major) {
    case 0:
      switch(minor) {
        case 9:
    return "HTTP/0.9";
      }
      break;
    case 1:
      switch(minor) {
        case 0:
    return "HTTP/1.0";
        case 1:
    return "HTTP/1.1";
      }
  }
  return "HTTP/"+major+"."+minor;
    }

    /**
     * Get the major version number of this message.
     * This method returns the major version that the caller should use to
     * <em>drive</em> message processing. It <em>may not</em> match the
     * version number actually emitted on the wire, which is computed
     * by the API itself.
     * @return A ninteger giving the major version number.
     */

    public short getMajorVersion() {
  return major;
    }

    /**
     * Get the minor version number of this message.
     * This method returns the minor version that the caller should use
     * to drive message processing. It <em>may not</em> match the
     * minor version number emitted on the wire, which is computed by the
     * API itself.
     * @return An integer giving the minor version number.
     */

    public short getMinorVersion() {
  return minor;
    }

    /**
     * Get the date at which this message was last emitted, if ever it was.
     * @return The date, in milliseconds since Java epoch at which this message
     * was emitted, or <strong>-1</strong> if the message was never emitted.
     */

    public long getEmitDate() {
  return emitdate;
    }

    /**
     * Get an Http Extension Listfrom the following list:
     * <ul>
     * <li>Mandatory (End-to-End) Extensions
     * <li>Mandatory (Hop-by-Hop) Extensions
     * <li>Optionnal (End-to-End) Extensions
     * <li>Optionnal (hop-by-Hop) Extensions
     * </ul>
     * @param ext the Extension id
     * @return a HttpExtList containing the extension declaration (or null)
     */
    public HttpExtList getExtList(String id) {
  HttpExtList extlist = getHttpManExtDecl();
  HttpExt ext = (extlist != null ? extlist.getHttpExt(id) : null);
  if (ext == null) {
      extlist = getHttpCManExtDecl();
      ext = (extlist != null ? extlist.getHttpExt(id) : null);
      if (ext == null) {
    extlist = getHttpOptExtDecl();
    ext = (extlist != null ? extlist.getHttpExt(id) : null);
    if (ext == null) {
        extlist = getHttpCOptExtDecl();
        ext = (extlist != null ? extlist.getHttpExt(id) : null);
        if (ext == null) {
      extlist = null;
        }
    }
      }
  }
  return extlist;
    }

    /**
     * get the String value of the given header relative to the given
     * Extension. This method search the header in the following declarations:
     * <ul>
     * <li>Mandatory (End-to-End) Extensions
     * <li>Mandatory (Hop-by-Hop) Extensions
     * <li>Optionnal (End-to-End) Extensions
     * <li>Optionnal (hop-by-Hop) Extensions
     * </ul>
     * @param ext the extension
     * @param header the extension header
     * @return a String (or null)
     */
    public String getExtHeader(String ext, String header) {
  String value = getManExtHeader(ext, header);
  if (value == null) {
      value = getCManExtHeader(ext, header);
      if (value == null) {
    value = getOptExtHeader(ext, header);
    if (value == null) {
        value = getCOptExtHeader(ext, header);
    }
      }
  }
  return value;
    }

    /**
     * get the String value of the given header relative to the given
     * Extension. This method search the header in the following declarations:
     * <ul>
     * <li>Mandatory (End-to-End) Extensions
     * </ul>
     * @param ext the extension
     * @param header the extension header
     * @return a String (or null)
     */
    public String getManExtHeader(String ext, String header) {
  return getExtHeader(getHttpManExtDecl(), ext, header);
    }

    /**
     * get the String value of the given header relative to the given
     * Extension. This method search the header in the following declarations:
     * <ul>
     * <li>Optionnal (End-to-End) Extensions
     * </ul>
     * @param ext the extension
     * @param header the extension header
     * @return a String (or null)
     */
    public String getOptExtHeader(String ext, String header) {
  return getExtHeader(getHttpOptExtDecl(), ext, header);
    }

    /**
     * get the String value of the given header relative to the given
     * Extension. This method search the header in the following declarations:
     * <ul>
     * <li>Mandatory (Hop-by-Hop) Extensions
     * </ul>
     * @param ext the extension
     * @param header the extension header
     * @return a String (or null)
     */
    public String getCManExtHeader(String ext, String header) {
  return getExtHeader(getHttpCManExtDecl(), ext, header);
    }

    /**
     * get the String value of the given header relative to the given
     * Extension. This method search the header in the following declarations:
     * <ul>
     * <li>Optionnal (hop-by-Hop) Extensions
     * </ul>
     * @param ext the extension
     * @param header the extension header
     * @return a String (or null)
     */
    public String getCOptExtHeader(String ext, String header) {
  return getExtHeader(getHttpCOptExtDecl(), ext, header);
    }

    private String getExtHeader(HttpExtList list, String ext, String header)
    {
  if (list == null) {
      return null;
  }
  HttpExt extheader = list.getHttpExt(ext);
  if (extheader != null) {
      String realheader = extheader.getNamespace()+"-"+header;
      return getValue(realheader);
  }
  return null;
    }

    /**
     * Get The Mandatory (End-to-End) Extension declaration list.
     * @return a HttpExtList instance or null;
     */
    public HttpExtList getHttpManExtDecl() {
  HeaderValue value = getHeaderValue(H_MAN_EXT);
  HttpExtList list  = null;
  if (value != null) {
      list = (HttpExtList) value.getValue();
      if (list != null) {
    list.setManOptFlag(HttpExtList.MAN);
      }
  }
  return list;
    }

    /**
     * Set The Mandatory (End-to-End) Extension declaration list.
     * @param exts the extension declaration list.
     */
    public void setHttpManExtDecl(HttpExtList exts) {
  exts.setManOptFlag(HttpExtList.MAN);
  setNamespaces(exts);
  setHeaderValue(H_MAN_EXT, exts);
    }

    /**
     * Get The Mandatory (Hop-by-Hop) Extension declaration list.
     * @return a HttpExtList instance or null;    
     */
    public HttpExtList getHttpCManExtDecl() {
  HeaderValue value = getHeaderValue(H_CMAN_EXT);
  HttpExtList list  = null;
  if (value != null) {
      list  = (HttpExtList) value.getValue();
      if (list != null) {
    list.setManOptFlag(HttpExtList.CMAN);
      }
  }
  return list;
    }

    /**
     * Set the Extension declaration.
     * WARNING: The ManOpt flag of exts must have been set.
     * @param exts the extension declaration list.
     */
    public void setHttpExtDecl(HttpExtList exts) {
  setNamespaces(exts);
  switch (exts.getManOptFlag())
      {
      case HttpExtList.MAN:
    setHeaderValue(H_MAN_EXT, exts);
    break;
      case HttpExtList.CMAN:
    setHeaderValue(H_CMAN_EXT, exts);
    break;
      case HttpExtList.OPT:
    setHeaderValue(H_OPT_EXT, exts);
    break;
      case HttpExtList.COPT:
    setHeaderValue(H_COPT_EXT, exts);
    break;
      default:
    setHeaderValue(H_MAN_EXT, exts);
      }
    }

    /**
     * Set The Mandatory (Hop-by-Hop) Extension declaration list.
     * @param exts the extension declaration list.
     */
    public void setHttpCManExtDecl(HttpExtList exts) {
  exts.setManOptFlag(HttpExtList.CMAN);
  setNamespaces(exts);
  setHeaderValue(H_CMAN_EXT, exts);
    }

    /**
     * Get The Optionnal (End-to-End) Extension declaration list.
     * @return a HttpExtList instance or null;
     */
    public HttpExtList getHttpOptExtDecl() {
  HeaderValue value = getHeaderValue(H_OPT_EXT);
  HttpExtList list  = null;
  if (value != null) {
      list = (HttpExtList) value.getValue();
      if (list != null) {
    list.setManOptFlag(HttpExtList.OPT);
      }
  }
  return list;
    }

    /**
     * Set The Optional (End-to-End) Extension declaration list.
     * @param exts the extension declaration list.
     */
    public void setHttpOptExtDecl(HttpExtList exts) {
  exts.setManOptFlag(HttpExtList.OPT);
  setNamespaces(exts);
  setHeaderValue(H_OPT_EXT, exts);
    }

    /**
     * Get The Optionnal (Hop-by-Hop) Extension declaration list.
     * @return a HttpExtList instance or null;    
     */
    public HttpExtList getHttpCOptExtDecl() {
  HeaderValue value = getHeaderValue(H_COPT_EXT);
  HttpExtList list  = null;
  if (value != null) {
      list = (HttpExtList) value.getValue();
      if (list != null) {
    list.setManOptFlag(HttpExtList.COPT);
      }
  }
  return list;
    }

    /**
     * Set The Optional (Hop-by-Hop) Extension declaration list.
     * @param exts the extension declaration list.
     */
    public void setHttpCOptExtDecl(HttpExtList exts) {
  exts.setManOptFlag(HttpExtList.COPT);
  setNamespaces(exts);
  setHeaderValue(H_COPT_EXT, exts);
    }

    protected void setNamespaces(HttpExtList extl) {
  HttpExt exts[] = extl.getHttpExts();
  for (int i = 0 ; i < exts.length ; i++) {
      if (exts[i].isGenerated())
    throw new HttpExtException("This extension Object is already "+
             "associated to an HttpMessage: "+
             exts[i].getName());
      if (exts[i].needsHeaders())
    exts[i].setNamespace(generateExtNamespace());
  }
    }

    /**
     * Get the headers relative to the given Http Extension declaration.
     * @param ext the HttpExt
     * @return a Dictionnary of <String, HeaderValue>
     */
    public Dictionary getExtensionHeaders(HttpExt ext) {
  ArrayDictionary extheaders = new ArrayDictionary(5, 5);
  if (headers != null) {
      Enumeration     henum      = headers.keys();
      String          namespace  = ext.getNamespace();

      if (namespace == null) {
    return extheaders;
      }

      namespace += "-";
     
      while (henum.hasMoreElements()) {
    String name = (String) henum.nextElement();
    if (name.startsWith(namespace)) {
        //remove namespace
        String realname = name.substring(3);
        extheaders.put(realname, headers.get(name));
    }
      }
  }
  return extheaders;
    }

    /**
     * Set an extension header relative to the given extension declaration.
     * @param ext The extension declaration
     * @param name the header name
     * @param value the header value
     */
    public synchronized void setExtensionHeader(HttpExt ext,
            String name,
            String value)
    {
  if (ext.isGenerated())
      throw new HttpExtException("This extension Object is already "+
               "associated to an HttpMessage: "+
               ext.getName());
  String namespace = ext.getNamespace();
  if (namespace == null) {
      namespace = generateExtNamespace();
      ext.setNamespace(namespace);
  }
  setValue(namespace+"-"+name, value);
    }

    /**
     * get a new namespace.
     * @return an int.
     */
    protected synchronized String generateExtNamespace() {
  return String.valueOf(extCurrentNamespace++);
    }

    public void setEnd2EndExtensionAcknowledgmentHeader() {
  setValue("Ext","");
    }

    public void setHopByHopExtensionAcknowledgmentHeader() {
  setValue("C-Ext","");
    }

    public final static void registerExtHeader(String name, String cls) {
  registerHeader(name, cls);
    }

    public HttpMessage(MimeParser parser) {
  // FIXME
  this.values  = new HeaderValue[MAX_HEADERS];
    }

    public HttpMessage() {
  // FIXME
  this.values  = new HeaderValue[MAX_HEADERS];
    }

 
}
TOP

Related Classes of org.w3c.www.http.HttpMessage

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.