Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/lutris/mime/MimeHeader.java


1   /*
2    * Enhydra Java Application Server Project
3    * 
4    * The contents of this file are subject to the Enhydra Public License
5    * Version 1.1 (the "License"); you may not use this file except in
6    * compliance with the License. You may obtain a copy of the License on
7    * the Enhydra web site ( http://www.enhydra.org/ ).
8    * 
9    * Software distributed under the License is distributed on an "AS IS"
10   * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 
11   * the License for the specific terms governing rights and limitations
12   * under the License.
13   * 
14   * The Initial Developer of the Enhydra Application Server is Lutris
15   * Technologies, Inc. The Enhydra Application Server and portions created
16   * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
17   * All Rights Reserved.
18   * 
19   * Contributor(s):
20   * 
21   * $Id: MimeHeader.java,v 1.8.12.1 2000/10/19 17:58:53 jasona Exp $
22   */
23  
24  
25  
26  
27  package com.lutris.mime;
28  import java.util.*;
29  import java.io.*;
30  
31  /**
32   * Represents a generic parsed Mime header.  Specific header types, such
33   * as <code>Content-Type</code> are represented by classes derived from
34   * this header.  The constructor for this class parses only parameters
35   * according to the rules specified in RFC2045 Section 5.1 Page 11.
36   * It is left to derived classes to parse type-specifiec information
37   * such as the Mime type (<code>Content-Type</code>) or content disposition
38   * (<code>Content-Disposition</code>).
39   */
40  public class MimeHeader {
41      /**
42       * Contains the parsed parameters for this hash table.
43       */
44      private Hashtable  myParams;
45      
46      /**
47       * Contains the type-independent value (if any) for the header.
48       */
49      private String  myValue;
50      
51      /**
52       * Contains the Mime header type value, defined as the characters
53       * before the first colon (':') character.
54       */
55      private String  myHeaderType;
56      
57      /**
58       * The raw, unparsed header line passed to the constructor.
59       */
60      private String  rawHeaderLine;
61      
62      /**
63       * Constructs a generic <code>MimeHeader</code> object and initializes
64       * its internal parameter list.
65       */
66      public
67      MimeHeader(String headerLine)
68      {
69    myParams = new Hashtable();
70    rawHeaderLine = headerLine;
71    int pos = headerLine.indexOf(':');
72    if (pos < 0) {
73        myHeaderType = null;
74    } else {
75        myHeaderType = headerLine.substring(0, pos).trim().toLowerCase();
76        headerLine = headerLine.substring(pos+1);
77    }
78    pos = headerLine.indexOf(';');
79    if (pos < 0) {
80        // Handle potential comment.
81        pos = headerLine.indexOf('(');
82        if (pos < 0) {
83      myValue = headerLine.trim();
84        } else { 
85      myValue = headerLine.substring(0, pos).trim();
86        }
87    } else { 
88        myValue = headerLine.substring(0, pos).trim();
89    }
90      }
91      
92      /** 
93       * Used by derived classes to put a parameter into the internal
94       * parameter value holder.
95       * 
96       * @param name  The name of the parameter value to add.
97       * @param value  The value to add.
98       */
99      protected
100     void putParameter(String name, String value)
101     {
102   name = name.toLowerCase();
103   String[] oldvals = (String[]) myParams.get(name);
104   int num = oldvals == null ? 0 : oldvals.length;
105   String[] newvals = new String[num+1];
106   for (int i=0; i < num; i++) {
107       newvals[i] = oldvals[i];
108       oldvals[i] = null;
109   }
110   newvals[num] = value;
111   oldvals = null;
112   myParams.put(name, newvals);
113     }
114     
115     /**
116      * Returns the "value" of this header.  This is defined to be the
117      * trimmed substring between the first colon (':') character and
118      * the first semicolon (';') character. For example, observe the
119      * following header line:
120      * <PRE>
121      *   Content-Type: multipart/form-data; boundary="000572A9AD4"
122      * </PRE>
123      * The <b>value</b> of this header is <i>multipart/form-data</i>,
124      * the <b>header type</b> is <i>Content-Type</i>, and the first
125      * <b>parameter</b> is named <i>boundary</i> and has the value
126      * <i>00572A9AD4</i>.
127      * 
128      * @return  The <b>value</b> of this Mime header.
129      */
130     public
131     String getValue()
132     {
133   return myValue;
134     }
135     
136     /**
137      * Returns the <b>header type</b> of this header.  This is defined to
138      * be the substring from the first character up to first colon (':')
139      * character.  For example, observe the following header line:
140      * <PRE>
141      *   Content-Type: multipart/form-data; boundary="000572A9AD4"
142      * </PRE>
143      * The <b>value</b> of this header is <i>multipart/form-data</i>,
144      * the <b>header type</b> is <i>Content-Type</i>, and the first
145      * <b>parameter</b> is named <i>boundary</i> and has the value
146      * <i>00572A9AD4</i>.
147      * 
148      * @return  The <b>header type</b> of this Mime header.
149      */
150     public
151     String getHeaderType()
152     {
153   return myHeaderType;
154     }
155     
156     /**
157      * Returns the string passed to the constructor without any parsing.
158      * 
159      * @returns  The unparsed Mime header line in its entirety.
160      */
161     public
162     String getRawHeaderLine()
163     {
164   return rawHeaderLine;
165     }
166 
167     /**
168      * Returns a single <code>String</code> value representing the
169      * last occurence of the <b>parameter</b> named by <code>name</code>.
170      * For example, observe the following header line:
171      * <PRE>
172      *   Content-Type: multipart/form-data; boundary="000572A9AD4"
173      * </PRE>
174      * The <b>value</b> of this header is <i>multipart/form-data</i>,
175      * the <b>header type</b> is <i>Content-Type</i>, and the first
176      * <b>parameter</b> is named <i>boundary</i> and has the value
177      * <i>00572A9AD4</i>.
178      * 
179      * @param  name  The name of the <b>parameter</b> to return.
180      * @return  The value of the last occurence of the named
181      *     <b>parameter</b> or <code>null</code> if not found.
182      */
183     public
184     String getParameter(String name)
185     {
186   name = name.toLowerCase();
187   String[] vals = (String[]) myParams.get(name);
188   if (vals == null) return null;
189   if (vals.length < 1) return null;
190   return vals[vals.length - 1];
191     }
192     
193     /**
194      * Returns an array of <code>String</code> containing all occurences
195      * of values named by <code>name</code>.
196      * For example, observe the following header line:
197      * <PRE>
198      *   Content-Type: multipart/form-data; boundary="000572A9AD4"
199      * </PRE>
200      * The <b>value</b> of this header is <i>multipart/form-data</i>,
201      * the <b>header type</b> is <i>Content-Type</i>, and the first
202      * <b>parameter</b> is named <i>boundary</i> and has the value
203      * <i>00572A9AD4</i>.
204      * 
205      * @param  name  The name of the <b>parameter</b> to return.
206      * @return  Array containing all values for the named 
207      *     <b>parameter</b> or <code>null</code> if not found.
208      */
209     public String[] getParameters(String name)
210     {
211   name = name.toLowerCase();
212   String[] vals = (String[]) myParams.get(name);
213   if (vals == null) return null;
214   if (vals.length < 1) return null;
215   return vals;
216     }
217     
218     /**
219      * Returns an enumeration of all of the parameter names parsed from
220      * the current Mime header.
221      * 
222      * @return An enumeration of the names of all parameters parsed from
223      *     the Mime header.
224      */
225     public Enumeration getParameterNames()
226     {
227   return myParams.keys();
228     }
229     
230     private static
231     void skipComment(PushbackReader input)
232     throws IOException
233     {
234   int ch;
235   while ((ch = input.read()) >= 0) if (ch == ')') return;
236     }
237     
238     private final
239     String parseToken(PushbackReader input, boolean trim)
240     throws IOException
241     {
242   StringBuffer buf = new StringBuffer();
243   int ch;
244   if (trim) {
245       while ((ch = input.read()) >= 0) if ((ch > ' ') && (ch < 0xff)) {
246     input.unread(ch);
247     if (ch == '(') {
248         skipComment(input);
249     }
250     else 
251         break;
252       }
253   }
254         while ((ch = input.read()) >= 0) {
255       switch (ch) {
256     case '=': case ';':
257         input.unread(ch);
258         return buf.toString();
259     case '(':
260         skipComment(input);
261         break;
262     default:
263         if ((ch > ' ') && (ch < 0xff))
264       buf.append((char)ch);
265         else {
266       input.unread(ch);
267       return buf.toString();
268         }
269         break;
270       }
271   }
272   return buf.toString();
273     }
274     
275     private final
276     String parseQuotedString(PushbackReader input)
277     throws IOException
278     {
279   StringBuffer buf = new StringBuffer();
280   int ch;
281         while ((ch = input.read()) >= 0) {
282       switch (ch) {
283     case '"':
284         return buf.toString();
285             
286     case '\\':
287         if ((ch = input.read()) >= 0) {
288                 if ((ch!='\\')&&(ch!='"')) {
289               buf.append('\\');                                    
290                 }
291           buf.append((char)ch);
292         } else {
293           buf.append('\\');
294       return buf.toString();
295         }
296         break;
297             
298     default:
299         buf.append((char)ch);
300         break;
301       }
302   }
303   return buf.toString();
304     }
305     
306     /**
307      * Parses the a given string into <i>key=parameter</i> pairs in 
308      * accordance with RFC2045 Section 5.1 Page 11.  Quoted strings
309      * are parsed in accordance with the RFC822 definition of the
310      * "<code>quoted-string</code>" grammatic construct.  According
311      * to RFC822, quoted strings are strings, enclosed in double-quote
312      * marks, which contain any character except LF or double-quote.
313      * The backslash character is used to literally quote the following
314      * character.  Octal or hex code backquoting is not supported.
315      */
316     protected
317     void parseParameters(String headerLine)
318     {
319   try {
320       StringReader reader = new StringReader(headerLine);
321       PushbackReader input = new PushbackReader(reader);
322       int ch;
323       String key, value;
324       while (true) {
325           key = parseToken(input, true);
326     ch = input.read();
327     if (ch < 0) break;
328     switch (ch) {
329         case '=':
330       switch (ch = input.read()) {
331           case '"':
332         value = parseQuotedString(input);
333         if (key.length() > 0) {
334             putParameter(key, value);
335         }
336         break;
337           default:
338         input.unread(ch);
339         value = parseToken(input, false);
340         if (key.length() > 0) {
341             putParameter(key, value);
342         }
343         break;
344       }
345       while (((ch = input.read()) >= 0) && (ch != ';')) {
346           if (ch == '(') {
347         skipComment(input);
348           }
349       }
350       break;
351         case ';':
352       // Not a key=value pair.
353       break;
354         default:
355       // Garbled input.
356       return;
357     } // outer switch
358       } // outer while
359       return;
360   }
361   catch (IOException e) {
362       return;
363   }
364     }
365 }
366