Source for gnu.inet.http.Headers

   1: /*
   2:  * Headers.java
   3:  * Copyright (C) 2004 The Free Software Foundation
   4:  * 
   5:  * This file is part of GNU inetlib, a library.
   6:  * 
   7:  * GNU inetlib is free software; you can redistribute it and/or modify
   8:  * it under the terms of the GNU General Public License as published by
   9:  * the Free Software Foundation; either version 2 of the License, or
  10:  * (at your option) any later version.
  11:  * 
  12:  * GNU inetlib is distributed in the hope that it will be useful,
  13:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15:  * GNU General Public License for more details.
  16:  * 
  17:  * You should have received a copy of the GNU General Public License
  18:  * along with this library; if not, write to the Free Software
  19:  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20:  * 
  21:  * Linking this library statically or dynamically with other modules is
  22:  * making a combined work based on this library.  Thus, the terms and
  23:  * conditions of the GNU General Public License cover the whole
  24:  * combination.
  25:  *
  26:  * As a special exception, the copyright holders of this library give you
  27:  * permission to link this library with independent modules to produce an
  28:  * executable, regardless of the license terms of these independent
  29:  * modules, and to copy and distribute the resulting executable under
  30:  * terms of your choice, provided that you also meet, for each linked
  31:  * independent module, the terms and conditions of the license of that
  32:  * module.  An independent module is a module which is not derived from
  33:  * or based on this library.  If you modify this library, you may extend
  34:  * this exception to your version of the library, but you are not
  35:  * obliged to do so.  If you do not wish to do so, delete this
  36:  * exception statement from your version.
  37:  */
  38: 
  39: package gnu.inet.http;
  40: 
  41: import java.io.InputStream;
  42: import java.io.IOException;
  43: import java.text.DateFormat;
  44: import java.text.ParseException;
  45: import java.util.Collection;
  46: import java.util.Date;
  47: import java.util.Iterator;
  48: import java.util.LinkedHashMap;
  49: import java.util.LinkedHashSet;
  50: import java.util.Map;
  51: import java.util.Set;
  52: 
  53: import gnu.inet.util.LineInputStream;
  54: 
  55: /**
  56:  * A collection of HTTP header names and associated values.
  57:  * Retrieval of values is case insensitive. An iteration over the keys
  58:  * returns the header names in the order they were received.
  59:  *
  60:  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
  61:  */
  62: public class Headers
  63:   implements Map
  64: {
  65: 
  66:   static final DateFormat dateFormat = new HTTPDateFormat();
  67: 
  68:   static class Header
  69:   {
  70: 
  71:     final String name;
  72: 
  73:     Header(String name)
  74:     {
  75:       if (name == null || name.length() == 0)
  76:         {
  77:           throw new IllegalArgumentException(name);
  78:         }
  79:       this.name = name;
  80:     }
  81: 
  82:     public int hashCode()
  83:     {
  84:       return name.toLowerCase().hashCode();
  85:     }
  86: 
  87:     public boolean equals(Object other)
  88:     {
  89:       if (other instanceof Header)
  90:         {
  91:           return ((Header) other).name.equalsIgnoreCase(name);
  92:         }
  93:       return false;
  94:     }
  95: 
  96:     public String toString()
  97:     {
  98:       return name;
  99:     }
 100:     
 101:   }
 102: 
 103:   static class HeaderEntry
 104:     implements Map.Entry
 105:   {
 106: 
 107:     final Map.Entry entry;
 108: 
 109:     HeaderEntry(Map.Entry entry)
 110:     {
 111:       this.entry = entry;
 112:     }
 113: 
 114:     public Object getKey()
 115:     {
 116:       return ((Header) entry.getKey()).name;
 117:     }
 118: 
 119:     public Object getValue()
 120:     {
 121:       return entry.getValue();
 122:     }
 123: 
 124:     public Object setValue(Object value)
 125:     {
 126:       return entry.setValue(value);
 127:     }
 128: 
 129:     public int hashCode()
 130:     {
 131:       return entry.hashCode();
 132:     }
 133: 
 134:     public boolean equals(Object other)
 135:     {
 136:       return entry.equals(other);
 137:     }
 138: 
 139:     public String toString()
 140:     {
 141:       return getKey().toString() + "=" + getValue();
 142:     }
 143:     
 144:   }
 145: 
 146:   private LinkedHashMap headers;
 147: 
 148:   public Headers()
 149:   {
 150:     headers = new LinkedHashMap();
 151:   }
 152: 
 153:   public int size()
 154:   {
 155:     return headers.size();
 156:   }
 157: 
 158:   public boolean isEmpty()
 159:   {
 160:     return headers.isEmpty();
 161:   }
 162: 
 163:   public boolean containsKey(Object key)
 164:   {
 165:     return headers.containsKey(new Header((String) key));
 166:   }
 167: 
 168:   public boolean containsValue(Object value)
 169:   {
 170:     return headers.containsValue(value);
 171:   }
 172: 
 173:   public Object get(Object key)
 174:   {
 175:     return headers.get(new Header((String) key));
 176:   }
 177: 
 178:   /**
 179:    * Returns the value of the specified header as a string.
 180:    */
 181:   public String getValue(String header)
 182:   {
 183:     return (String) headers.get(new Header(header));
 184:   }
 185: 
 186:   /**
 187:    * Returns the value of the specified header as an integer,
 188:    * or -1 if the header is not present or not an integer.
 189:    */
 190:   public int getIntValue(String header)
 191:   {
 192:     String val = getValue(header);
 193:     if (val == null)
 194:       {
 195:         return -1;
 196:       }
 197:     try
 198:       {
 199:         return Integer.parseInt(val);
 200:       }
 201:     catch (NumberFormatException e)
 202:       {
 203:       }
 204:     return -1;
 205:   }
 206: 
 207:   /**
 208:    * Returns the value of the specified header as a date,
 209:    * or <code>null</code> if the header is not present or not a date.
 210:    */
 211:   public Date getDateValue(String header)
 212:   {
 213:     String val = getValue(header);
 214:     if (val == null)
 215:       {
 216:         return null;
 217:       }
 218:     try
 219:       {
 220:         return dateFormat.parse(val);
 221:       }
 222:     catch (ParseException e)
 223:       {
 224:         return null;
 225:       }
 226:   }
 227: 
 228:   public Object put(Object key, Object value)
 229:   {
 230:     return headers.put(new Header((String) key), value);
 231:   }
 232: 
 233:   public Object remove(Object key)
 234:   {
 235:     return headers.remove(new Header((String) key));
 236:   }
 237: 
 238:   public void putAll(Map t)
 239:   {
 240:     for (Iterator i = t.keySet().iterator(); i.hasNext(); )
 241:       {
 242:         String key = (String) i.next();
 243:         String value = (String) t.get(key);
 244:         headers.put(new Header(key), value);
 245:       }
 246:   }
 247:   
 248:   public void clear()
 249:   {
 250:     headers.clear();
 251:   }
 252: 
 253:   public Set keySet()
 254:   {
 255:     Set keys = headers.keySet();
 256:     Set ret = new LinkedHashSet();
 257:     for (Iterator i = keys.iterator(); i.hasNext(); )
 258:       {
 259:         ret.add(((Header) i.next()).name);
 260:       }
 261:     return ret;
 262:   }
 263: 
 264:   public Collection values()
 265:   {
 266:     return headers.values();
 267:   }
 268: 
 269:   public Set entrySet()
 270:   {
 271:     Set entries = headers.entrySet();
 272:     Set ret = new LinkedHashSet();
 273:     for (Iterator i = entries.iterator(); i.hasNext(); )
 274:       {
 275:         Map.Entry entry = (Map.Entry) i.next();
 276:         ret.add(new HeaderEntry(entry));
 277:       }
 278:     return ret;
 279:   }
 280: 
 281:   public boolean equals(Object other)
 282:   {
 283:     return headers.equals(other);
 284:   }
 285: 
 286:   public int hashCode()
 287:   {
 288:     return headers.hashCode();
 289:   }
 290: 
 291:   /**
 292:    * Parse the specified input stream, adding headers to this collection.
 293:    */
 294:   public void parse(InputStream in)
 295:     throws IOException
 296:   {
 297:     LineInputStream lin = (in instanceof LineInputStream) ?
 298:       (LineInputStream) in : new LineInputStream(in);
 299:     
 300:     String name = null;
 301:     StringBuffer value = new StringBuffer();
 302:     while (true)
 303:       {
 304:         String line = lin.readLine();
 305:         if (line == null)
 306:           {
 307:             if (name != null)
 308:               {
 309:                 addValue(name, value.toString());
 310:               }
 311:             break;
 312:           }
 313:         int len = line.length();
 314:         if (len < 2)
 315:           {
 316:             if (name != null)
 317:               {
 318:                 addValue(name, value.toString());
 319:               }
 320:             break;
 321:           }
 322:         char c1 = line.charAt(0);
 323:         if (c1 == ' ' || c1 == '\t')
 324:           {
 325:             // Continuation
 326:             value.append(line.substring(0, len - 1));
 327:           }
 328:         else
 329:           {
 330:             if (name != null)
 331:               {
 332:                 addValue(name, value.toString());
 333:               }
 334:             
 335:             int di = line.indexOf(':');
 336:             name = line.substring(0, di);
 337:             value.setLength(0);
 338:             do
 339:               {
 340:                 di++;
 341:               }
 342:             while (di < len && line.charAt(di) == ' ');
 343:             value.append(line.substring(di, len - 1));
 344:           }
 345:       }
 346:   }
 347:   
 348:   private void addValue(String name, String value)
 349:   {
 350:     Header key = new Header(name);
 351:     String old = (String) headers.get(key);
 352:     if (old == null)
 353:       {
 354:         headers.put(key, value);
 355:       }
 356:     else
 357:       {
 358:         headers.put(key, old + ", " + value);
 359:       }
 360:   }
 361:   
 362: }