1
2
3
4
5
6
7
8
9
10
11
12
13 package org.abstracthorizon.danube.http;
14
15 import org.abstracthorizon.danube.connection.Connection;
16 import org.abstracthorizon.danube.connection.ConnectionHandler;
17 import org.abstracthorizon.danube.http.util.ErrorConnectionHandler;
18 import org.abstracthorizon.danube.http.util.MultiStringMap;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.OutputStream;
23 import java.io.PrintWriter;
24 import java.lang.reflect.Method;
25 import java.util.HashMap;
26 import java.util.Map;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 public class BaseReflectionHTTPConnectionHandler implements ConnectionHandler {
48
49 protected Map<String, Method> cachedMethods;
50
51
52 protected boolean noDefaultHead = false;
53
54
55 protected boolean noDefaultTrace = false;
56
57
58 protected ConnectionHandler errorResponse = new ErrorConnectionHandler();
59
60
61
62
63 public BaseReflectionHTTPConnectionHandler() {
64 }
65
66
67
68
69
70 public ConnectionHandler getErrorResponse() {
71 return errorResponse;
72 }
73
74
75
76
77
78 public void setErrorResponse(ConnectionHandler errorResponse) {
79 this.errorResponse = errorResponse;
80 }
81
82
83
84
85
86 public boolean getNoDefaultHead() {
87 return noDefaultHead;
88 }
89
90
91
92
93
94 public void setNoDefaultHead(boolean noDefaultHead) {
95 this.noDefaultHead = noDefaultHead;
96 updateDefaultHeadMethod();
97 }
98
99
100
101
102 protected void updateDefaultHeadMethod() {
103 try {
104 Method method = BaseReflectionHTTPConnectionHandler.class.getMethod("methodHEAD", new Class[]{HTTPConnection.class});
105 if (noDefaultHead) {
106 if (method == cachedMethods.get("HEAD")) {
107 cachedMethods.remove("HEAD");
108 }
109 } else {
110 cachedMethods.put("HEAD", method);
111 }
112 } catch (Exception ignore) {
113 }
114 }
115
116
117
118
119
120 public boolean getNoDefaultTrace() {
121 return noDefaultTrace;
122 }
123
124
125
126
127
128 public void setNoDefaultTrace(boolean noDefaultTrace) {
129 this.noDefaultTrace = noDefaultTrace;
130 updateDefaultTraceMethod();
131 }
132
133
134
135
136 protected void updateDefaultTraceMethod() {
137 try {
138 Method method = BaseReflectionHTTPConnectionHandler.class.getMethod("methodTRACE", new Class[]{HTTPConnection.class});
139 if (noDefaultTrace) {
140 if (method == cachedMethods.get("TRACE")) {
141 cachedMethods.remove("TRACE");
142 }
143 } else {
144 cachedMethods.put("TRACE", method);
145 }
146 } catch (Exception ignore) {
147 }
148 }
149
150
151
152
153
154 protected void cacheMethods() {
155 cachedMethods = new HashMap<String, Method>();
156 Method[] methods = getClass().getMethods();
157 for (Method method : methods) {
158 String methodName = method.getName();
159 if ((methodName.length() > 6)
160 && methodName.startsWith("method")
161 && (method.getParameterTypes().length == 1)
162 && (HTTPConnection.class.isAssignableFrom(method.getParameterTypes()[0]))) {
163
164 cachedMethods.put(methodName.substring(6), method);
165 }
166 }
167 updateDefaultHeadMethod();
168 updateDefaultTraceMethod();
169 }
170
171
172
173
174
175 public void handleConnection(Connection connection) {
176 if (cachedMethods == null) {
177 cacheMethods();
178 }
179 HTTPConnection httpConnection = (HTTPConnection)connection.adapt(HTTPConnection.class);
180 invokeMethod(httpConnection, httpConnection.getRequestMethod());
181 }
182
183
184
185
186
187
188 protected void invokeMethod(HTTPConnection httpConnection, String methodName) {
189 Method method = cachedMethods.get(methodName);
190 if (method != null) {
191 try {
192 method.invoke(this, new Object[]{httpConnection});
193 } catch (Exception e) {
194 throw new RuntimeException(e);
195 }
196 } else {
197 httpConnection.setResponseStatus(Status.METHOD_NOT_ALLOWED);
198 errorResponse.handleConnection(httpConnection);
199 }
200 }
201
202
203
204
205
206 public void methodOPTIONS(HTTPConnection httpConnection) {
207 StringBuffer allowedMethods = new StringBuffer();
208 boolean first = true;
209 for (String method : cachedMethods.keySet()) {
210 if (first) {
211 first = false;
212 } else {
213 allowedMethods.append(", ");
214 }
215 allowedMethods.append(method);
216 }
217 httpConnection.getResponseHeaders().putOnly("Allow", allowedMethods.toString());
218 httpConnection.getResponseHeaders().removeAll("Content-Type");
219 }
220
221
222
223
224
225 public void methodTRACE(HTTPConnection httpConnection) {
226 MultiStringMap requestHeaders = httpConnection.getRequestHeaders();
227 MultiStringMap responseHeaders = httpConnection.getResponseHeaders();
228 String contentLength = requestHeaders.getOnly("Content-Length");
229 if (contentLength == null) {
230 httpConnection.setResponseStatus(Status.LENGTH_REQUIRED);
231
232
233
234 errorResponse.handleConnection(httpConnection);
235 } else {
236 long len = Long.parseLong(contentLength);
237 responseHeaders.putOnly("Content-Length", contentLength);
238
239 try {
240 InputStream inputStream = (InputStream)httpConnection.adapt(InputStream.class);
241 OutputStream outputStream = (OutputStream)httpConnection.adapt(OutputStream.class);
242 int bufSize = 10240;
243 if (len < bufSize) {
244 bufSize = (int)len;
245 }
246
247 byte[] buf = new byte[bufSize];
248
249 int r = bufSize;
250 if (len < r) {
251 r = (int)len;
252 }
253
254 r = inputStream.read(buf, 0, r);
255 while ((r > 0) && (len > 0)) {
256 outputStream.write(buf, 0, r);
257 len = len - r;
258 r = bufSize;
259 if (len < r) {
260 r = (int)len;
261 }
262 r = inputStream.read(buf, 0, r);
263 }
264 outputStream.flush();
265 } catch (IOException ignore) {
266 }
267 }
268
269 }
270
271
272
273
274
275 public void methodHEAD(HTTPConnection httpConnection) {
276 invokeMethod(httpConnection, "GET");
277 }
278
279 public void returnError(HTTPConnection httpConnection, Status status) {
280 httpConnection.setResponseStatus(status);
281 errorResponse.handleConnection(httpConnection);
282 }
283
284
285 public void returnSimpleContent(HTTPConnection httpConnection, Status status, String contentType, String content) {
286 httpConnection.setResponseStatus(status);
287 if (contentType != null) {
288 httpConnection.getResponseHeaders().putOnly("Content-Type", contentType);
289 }
290 if (content != null) {
291 PrintWriter out = (PrintWriter)httpConnection.adapt(PrintWriter.class);
292 out.print(content);
293 }
294 }
295 }