001: /*
002: * @(#)ContentEncodingModule.java 0.3-2 18/06/1999
003: *
004: * This file is part of the HTTPClient package
005: * Copyright (C) 1996-1999 Ronald Tschalär
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free
019: * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
020: * MA 02111-1307, USA
021: *
022: * For questions, suggestions, bug-reports, enhancement-requests etc.
023: * I may be contacted at:
024: *
025: * ronald@innovation.ch
026: *
027: */
028:
029: package HTTPClient;
030:
031: import java.io.IOException;
032: import java.util.Vector;
033: import java.util.zip.InflaterInputStream;
034: import java.util.zip.GZIPInputStream;
035:
036: /**
037: * This module handles the Content-Encoding response header. It currently
038: * handles the "gzip", "deflate", "compress" and "identity" tokens.
039: *
040: * Note: This module requires JDK 1.1 or later.
041: *
042: * @version 0.3-2 18/06/1999
043: * @author Ronald Tschalär
044: */
045:
046: class ContentEncodingModule implements HTTPClientModule,
047: GlobalConstants {
048: static {
049: /* This ensures that the loading of this class is only successful
050: * if we're in JDK 1.1 (or later) and have access to java.util.zip
051: */
052: try {
053: new InflaterInputStream(null);
054: } catch (NullPointerException npe) { /* JDK 1.2 Final started throwing this */
055: }
056: }
057:
058: // Constructors
059:
060: ContentEncodingModule() {
061: }
062:
063: // Methods
064:
065: /**
066: * Invoked by the HTTPClient.
067: */
068: public int requestHandler(Request req, Response[] resp)
069: throws ModuleException {
070: // parse Accept-Encoding header
071:
072: int idx;
073: NVPair[] hdrs = req.getHeaders();
074: for (idx = 0; idx < hdrs.length; idx++)
075: if (hdrs[idx].getName().equalsIgnoreCase("Accept-Encoding"))
076: break;
077:
078: Vector pae;
079: if (idx == hdrs.length) {
080: hdrs = Util.resizeArray(hdrs, idx + 1);
081: req.setHeaders(hdrs);
082: pae = new Vector();
083: } else {
084: try {
085: pae = Util.parseHeader(hdrs[idx].getValue());
086: } catch (ParseException pe) {
087: throw new ModuleException(pe.toString());
088: }
089: }
090:
091: // done if "*;q=1.0" present
092:
093: HttpHeaderElement all = Util.getElement(pae, "*");
094: if (all != null) {
095: NVPair[] params = all.getParams();
096: for (idx = 0; idx < params.length; idx++)
097: if (params[idx].getName().equalsIgnoreCase("q"))
098: break;
099:
100: if (idx == params.length) // no qvalue, i.e. q=1.0
101: return REQ_CONTINUE;
102:
103: if (params[idx].getValue() == null
104: || params[idx].getValue().length() == 0)
105: throw new ModuleException(
106: "Invalid q value for \"*\" in "
107: + "Accept-Encoding header: ");
108:
109: try {
110: if (Float.valueOf(params[idx].getValue()).floatValue() > 0.)
111: return REQ_CONTINUE;
112: } catch (NumberFormatException nfe) {
113: throw new ModuleException(
114: "Invalid q value for \"*\" in "
115: + "Accept-Encoding header: "
116: + nfe.getMessage());
117: }
118: }
119:
120: // Add gzip, deflate and compress tokens to the Accept-Encoding header
121:
122: if (!pae.contains(new HttpHeaderElement("deflate")))
123: pae.addElement(new HttpHeaderElement("deflate"));
124: if (!pae.contains(new HttpHeaderElement("gzip")))
125: pae.addElement(new HttpHeaderElement("gzip"));
126: if (!pae.contains(new HttpHeaderElement("x-gzip")))
127: pae.addElement(new HttpHeaderElement("x-gzip"));
128: if (!pae.contains(new HttpHeaderElement("compress")))
129: pae.addElement(new HttpHeaderElement("compress"));
130: if (!pae.contains(new HttpHeaderElement("x-compress")))
131: pae.addElement(new HttpHeaderElement("x-compress"));
132:
133: hdrs[idx] = new NVPair("Accept-Encoding", Util
134: .assembleHeader(pae));
135:
136: return REQ_CONTINUE;
137: }
138:
139: /**
140: * Invoked by the HTTPClient.
141: */
142: public void responsePhase1Handler(Response resp, RoRequest req) {
143: }
144:
145: /**
146: * Invoked by the HTTPClient.
147: */
148: public int responsePhase2Handler(Response resp, Request req) {
149: return RSP_CONTINUE;
150: }
151:
152: /**
153: * Invoked by the HTTPClient.
154: */
155: public void responsePhase3Handler(Response resp, RoRequest req)
156: throws IOException, ModuleException {
157: String ce = resp.getHeader("Content-Encoding");
158: if (ce == null || req.getMethod().equals("HEAD")
159: || resp.getStatusCode() == 206)
160: return;
161:
162: Vector pce;
163: try {
164: pce = Util.parseHeader(ce);
165: } catch (ParseException pe) {
166: throw new ModuleException(pe.toString());
167: }
168:
169: if (pce.size() == 0)
170: return;
171:
172: String encoding = ((HttpHeaderElement) pce.firstElement())
173: .getName();
174: if (encoding.equalsIgnoreCase("gzip")
175: || encoding.equalsIgnoreCase("x-gzip")) {
176: if (DebugMods)
177: System.err.println("CEM: pushing gzip-input-stream");
178:
179: resp.inp_stream = new GZIPInputStream(resp.inp_stream);
180: pce.removeElementAt(pce.size() - 1);
181: resp.deleteHeader("Content-length");
182: } else if (encoding.equalsIgnoreCase("deflate")) {
183: if (DebugMods)
184: System.err
185: .println("CEM: pushing inflater-input-stream");
186:
187: resp.inp_stream = new InflaterInputStream(resp.inp_stream);
188: pce.removeElementAt(pce.size() - 1);
189: resp.deleteHeader("Content-length");
190: } else if (encoding.equalsIgnoreCase("compress")
191: || encoding.equalsIgnoreCase("x-compress")) {
192: if (DebugMods)
193: System.err
194: .println("CEM: pushing uncompress-input-stream");
195:
196: resp.inp_stream = new UncompressInputStream(resp.inp_stream);
197: pce.removeElementAt(pce.size() - 1);
198: resp.deleteHeader("Content-length");
199: } else if (encoding.equalsIgnoreCase("identity")) {
200: if (DebugMods)
201: System.err.println("CEM: ignoring 'identity' token");
202: pce.removeElementAt(pce.size() - 1);
203: } else {
204: if (DebugMods)
205: System.err.println("CEM: Unknown content encoding '"
206: + encoding + "'");
207: }
208:
209: if (pce.size() > 0)
210: resp
211: .setHeader("Content-Encoding", Util
212: .assembleHeader(pce));
213: else
214: resp.deleteHeader("Content-Encoding");
215: }
216:
217: /**
218: * Invoked by the HTTPClient.
219: */
220: public void trailerHandler(Response resp, RoRequest req) {
221: }
222: }
|