1 package com.bradmcevoy.http;
2
3 import java.io.ByteArrayInputStream;
4 import java.io.File;
5 import java.io.FileNotFoundException;
6 import java.io.FileOutputStream;
7 import java.io.IOException;
8 import java.io.InputStream;
9 import java.io.OutputStream;
10 import java.io.PrintWriter;
11 import java.util.List;
12 import java.util.Map;
13
14 import org.apache.commons.io.output.ByteArrayOutputStream;
15
16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
18
19 import com.bradmcevoy.io.StreamUtils;
20
21
22
23
24 public class DebugFilter implements Filter{
25
26 private static final Logger log = LoggerFactory.getLogger(DebugFilter.class);
27
28 private static int counter = 0;
29
30 private File logDir;
31
32 public DebugFilter() {
33 logDir = new File(System.getProperty("user.home"));
34 log.debug( "logging to: " + logDir.getAbsolutePath());
35 }
36
37 public DebugFilter( File logDir ) {
38 this.logDir = logDir;
39 log.debug( "logging to: " + logDir.getAbsolutePath());
40 }
41
42
43
44 public void process(FilterChain chain, Request request, Response response) {
45 try {
46 DebugRequest req2 = new DebugRequest(request);
47 DebugResponse resp2 = new DebugResponse(response);
48 chain.process(req2, resp2);
49 record(req2,resp2);
50 response.getOutputStream().write(resp2.out.toByteArray());
51 response.getOutputStream().flush();
52 } catch (IOException ex) {
53 log.error("", ex);
54 }
55 }
56
57 private synchronized void record(DebugRequest req2, DebugResponse resp2) {
58 counter++;
59 FileOutputStream fout = null;
60 try {
61 File f = new File(logDir, counter + "_" + req2.getMethod() + ".req");
62 fout = new FileOutputStream(f);
63 req2.record(fout);
64 } catch (FileNotFoundException ex) {
65 throw new RuntimeException(ex);
66 } finally {
67 StreamUtils.close( fout );
68 }
69
70 try {
71 File f = new File(logDir, counter + "_" + resp2.getStatus().code + ".resp");
72 fout = new FileOutputStream(f);
73 resp2.record(fout);
74 } catch (FileNotFoundException ex) {
75 throw new RuntimeException(ex);
76 } finally {
77 StreamUtils.close( fout );
78 }
79
80 }
81
82 public class DebugResponse extends AbstractResponse {
83 final Response r;
84 final ByteArrayOutputStream out;
85 List<String> challenges;
86
87 public DebugResponse(Response r) {
88 this.r = r;
89 out = new ByteArrayOutputStream();
90 }
91
92 public Status getStatus() {
93 return r.getStatus();
94 }
95
96 public void setStatus(Status status) {
97 r.setStatus(status);
98 }
99
100 public void setNonStandardHeader(String code, String value) {
101 r.setNonStandardHeader(code, value);
102 }
103
104 public String getNonStandardHeader(String code) {
105 return r.getNonStandardHeader(code);
106 }
107
108 public OutputStream getOutputStream() {
109 return out;
110 }
111
112 public Map<String,String> getHeaders() {
113 return r.getHeaders();
114 }
115
116 private void record(FileOutputStream fout) {
117 try {
118 PrintWriter writer = new PrintWriter(fout);
119 if( getStatus() != null ) {
120 writer.println("HTTP/1.1 " + getStatus().code);
121 }
122 for (Map.Entry<String, String> header : this.getHeaders().entrySet()) {
123 writer.println(header.getKey() + ": " + header.getValue());
124 }
125 if( challenges != null ) {
126 for( String ch : challenges) {
127 writer.println(Response.Header.WWW_AUTHENTICATE + ": " + ch);
128 }
129 }
130 writer.flush();
131
132
133 log.debug( out.toString());
134
135 fout.write(out.toByteArray());
136 fout.flush();
137 } catch (IOException ex) {
138 log.error("",ex);
139 }
140 }
141
142 public void setAuthenticateHeader( List<String> challenges ) {
143 this.challenges = challenges;
144 r.setAuthenticateHeader( challenges );
145 }
146
147 public Cookie setCookie( Cookie cookie ) {
148 return r.setCookie( cookie );
149 }
150
151 public Cookie setCookie( String name, String value ) {
152 return r.setCookie( name, value );
153 }
154
155
156 }
157
158 public class DebugRequest extends AbstractRequest {
159 final Request r;
160 final byte[] contentBytes;
161 final ByteArrayInputStream content;
162
163 public DebugRequest(Request r) {
164 this.r = r;
165 ByteArrayOutputStream out = new ByteArrayOutputStream();
166 try {
167 StreamUtils.readTo(r.getInputStream(), out);
168 } catch (IOException ex) {
169 throw new RuntimeException(ex);
170 }
171 this.contentBytes = out.toByteArray();
172 this.content = new ByteArrayInputStream(this.contentBytes);
173 log.debug(out.toString());
174 }
175
176 public Map<String, String> getHeaders() {
177 return r.getHeaders();
178 }
179
180 @Override
181 public String getRequestHeader(Header header) {
182 return r.getRequestHeader(header);
183 }
184
185 public String getFromAddress() {
186 return r.getFromAddress();
187 }
188
189 public Method getMethod() {
190 return r.getMethod();
191 }
192
193 public Auth getAuthorization() {
194 return r.getAuthorization();
195 }
196
197 public void setAuthorization( Auth auth ) {
198 r.setAuthorization( auth );
199 }
200
201
202
203 public String getAbsoluteUrl() {
204 return r.getAbsoluteUrl();
205 }
206
207 public InputStream getInputStream() throws IOException {
208 return content;
209 }
210
211 public void parseRequestParameters(Map<String, String> params, Map<String, FileItem> files) throws RequestParseException {
212 r.parseRequestParameters(params, files);
213 }
214
215 public void record(OutputStream out) {
216 PrintWriter writer = new PrintWriter(out);
217 writer.println(getMethod() + " " + getAbsolutePath() + " HTTP/1.1");
218 for(Map.Entry<String,String> header : this.getHeaders().entrySet()) {
219 writer.println(header.getKey() + ": " + header.getValue());
220 }
221 writer.flush();
222 try {
223 out.write(contentBytes);
224 } catch (IOException ex) {
225 log.error("",ex);
226 }
227 }
228
229 public Cookie getCookie( String name ) {
230 return r.getCookie( name );
231 }
232
233 public List<Cookie> getCookies() {
234 return r.getCookies();
235 }
236
237 public String getRemoteAddr() {
238 return r.getRemoteAddr();
239 }
240
241 }
242
243 }