KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > HTTPClient > ContentMD5Module


1 /*
2  * @(#)ContentMD5Module.java 0.3-2 18/06/1999
3  *
4  * This file is part of the HTTPClient package
5  * Copyright (C) 1996-1999 Ronald Tschalär
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library 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 GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free
19  * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307, USA
21  *
22  * For questions, suggestions, bug-reports, enhancement-requests etc.
23  * I may be contacted at:
24  *
25  * ronald@innovation.ch
26  *
27  */

28
29 package HTTPClient;
30
31 import java.io.IOException JavaDoc;
32 import java.net.ProtocolException JavaDoc;
33
34
35 /**
36  * This module handles the Content-MD5 response header. If this header was
37  * sent with a response and the entity isn't encoded using an unknown
38  * transport encoding then an MD5InputStream is wrapped around the response
39  * input stream. The MD5InputStream keeps a running digest and checks this
40  * against the expected digest from the Content-MD5 header the stream is
41  * closed. An IOException is thrown at that point if the digests don't match.
42  *
43  * @version 0.3-2 18/06/1999
44  * @author Ronald Tschalär
45  */

46
47 class ContentMD5Module implements HTTPClientModule, GlobalConstants
48 {
49     // Constructors
50

51     ContentMD5Module()
52     {
53     }
54
55
56     // Methods
57

58     /**
59      * Invoked by the HTTPClient.
60      */

61     public int requestHandler(Request req, Response[] resp)
62     {
63     return REQ_CONTINUE;
64     }
65
66
67     /**
68      * Invoked by the HTTPClient.
69      */

70     public void responsePhase1Handler(Response resp, RoRequest req)
71     {
72     }
73
74
75     /**
76      * Invoked by the HTTPClient.
77      */

78     public int responsePhase2Handler(Response resp, Request req)
79     {
80     return RSP_CONTINUE;
81     }
82
83
84     /**
85      * Invoked by the HTTPClient.
86      */

87     public void responsePhase3Handler(Response resp, RoRequest req)
88         throws IOException JavaDoc, ModuleException
89     {
90     if (req.getMethod().equals("HEAD"))
91         return;
92
93     String JavaDoc md5_digest = resp.getHeader("Content-MD5");
94     String JavaDoc trailer = resp.getHeader("Trailer");
95     boolean md5_tok = false;
96     try
97     {
98         if (trailer != null)
99         md5_tok = Util.hasToken(trailer, "Content-MD5");
100     }
101     catch (ParseException pe)
102         { throw new ModuleException(pe.toString()); }
103
104     if ((md5_digest == null && !md5_tok) ||
105         resp.getHeader("Transfer-Encoding") != null)
106         return;
107
108     if (DebugMods)
109     {
110         if (md5_digest != null)
111         System.err.println("CMD5M: Received digest: " + md5_digest +
112                     " - pushing md5-check-stream");
113         else
114         System.err.println("CMD5M: Expecting digest in trailer " +
115                     " - pushing md5-check-stream");
116     }
117
118     resp.inp_stream = new MD5InputStream(resp.inp_stream,
119                          new VerifyMD5(resp));
120     }
121
122
123     /**
124      * Invoked by the HTTPClient.
125      */

126     public void trailerHandler(Response resp, RoRequest req)
127     {
128     }
129 }
130
131
132 class VerifyMD5 implements HashVerifier, GlobalConstants
133 {
134     RoResponse resp;
135
136
137     public VerifyMD5(RoResponse resp)
138     {
139     this.resp = resp;
140     }
141
142
143     public void verifyHash(byte[] hash, long len) throws IOException JavaDoc
144     {
145     String JavaDoc hdr;
146     try
147     {
148         if ((hdr = resp.getHeader("Content-MD5")) == null)
149         hdr = resp.getTrailer("Content-MD5");
150     }
151     catch (IOException JavaDoc ioe)
152         { return; } // shouldn't happen
153

154     if (hdr == null) return;
155
156     hdr = hdr.trim();
157     byte[] ContMD5 = new byte[hdr.length()];
158     hdr.getBytes(0, ContMD5.length, ContMD5, 0);
159     ContMD5 = Codecs.base64Decode(ContMD5);
160
161     for (int idx=0; idx<hash.length; idx++)
162     {
163         if (hash[idx] != ContMD5[idx])
164         throw new IOException JavaDoc("MD5-Digest mismatch: expected " +
165                       hex(ContMD5) + " but calculated " +
166                       hex(hash));
167     }
168
169     if (DebugMods)
170         System.err.println("CMD5M: hash successfully verified");
171     }
172
173
174     /**
175      * Produce a string of the form "A5:22:F1:0B:53"
176      */

177     private static String JavaDoc hex(byte[] buf)
178     {
179     StringBuffer JavaDoc str = new StringBuffer JavaDoc(buf.length*3);
180     for (int idx=0; idx<buf.length; idx++)
181     {
182         str.append(Character.forDigit((buf[idx] >>> 4) & 15, 16));
183         str.append(Character.forDigit(buf[idx] & 15, 16));
184         str.append(':');
185     }
186     str.setLength(str.length()-1);
187
188     return str.toString();
189     }
190 }
191
192
Popular Tags