1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package net.anyflow.lannister.http;
18
19 import java.net.URI;
20 import java.net.URISyntaxException;
21 import java.util.ArrayList;
22 import java.util.Date;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Map.Entry;
27 import java.util.Set;
28
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 import com.google.common.base.Strings;
33 import com.google.common.collect.Maps;
34
35 import io.netty.buffer.ByteBuf;
36 import io.netty.buffer.Unpooled;
37 import io.netty.handler.codec.DecoderResult;
38 import io.netty.handler.codec.http.DefaultFullHttpRequest;
39 import io.netty.handler.codec.http.FullHttpRequest;
40 import io.netty.handler.codec.http.HttpHeaderNames;
41 import io.netty.handler.codec.http.HttpHeaderValues;
42 import io.netty.handler.codec.http.HttpMethod;
43 import io.netty.handler.codec.http.QueryStringDecoder;
44 import io.netty.handler.codec.http.cookie.ClientCookieEncoder;
45 import io.netty.handler.codec.http.cookie.Cookie;
46 import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
47 import io.netty.util.CharsetUtil;
48
49
50
51
52 public class HttpRequest extends DefaultFullHttpRequest {
53 private static final Logger logger = LoggerFactory.getLogger(HttpRequest.class);
54
55 private final Map<String, List<String>> parameters;
56 private final URI uri;
57 private final Set<Cookie> cookies;
58
59 private Map<String, String> pathParameters;
60
61 protected HttpRequest(FullHttpRequest fullHttpRequest) throws URISyntaxException {
62 super(fullHttpRequest.protocolVersion(), fullHttpRequest.method(), fullHttpRequest.uri(),
63 fullHttpRequest.content().copy());
64
65 this.headers().set(fullHttpRequest.headers());
66 this.trailingHeaders().set(fullHttpRequest.trailingHeaders());
67 this.setDecoderResult(fullHttpRequest.decoderResult());
68 this.uri = createUriWithNormalizing(fullHttpRequest.uri());
69
70 this.parameters = parameters();
71 this.cookies = cookies();
72 this.pathParameters = Maps.newHashMap();
73 }
74
75 private URI createUriWithNormalizing(String uri) throws URISyntaxException {
76 URI temp = new URI(uri);
77
78 String scheme = temp.getScheme();
79 if (scheme == null) {
80 scheme = "http";
81 }
82
83 int port = temp.getPort();
84 if (port == -1) {
85 if (scheme.equalsIgnoreCase("http")) {
86 port = 80;
87 }
88 else if (scheme.equalsIgnoreCase("https")) {
89 port = 443;
90 }
91 else {
92 throw new URISyntaxException(uri, "Invalid protocol.");
93 }
94 }
95
96 return new URI(scheme, temp.getUserInfo(), temp.getHost(), port, temp.getPath(), temp.getQuery(),
97 temp.getFragment());
98 }
99
100 public Set<Cookie> cookies() {
101 if (cookies != null) { return cookies; }
102
103 String cookie = headers().get(HttpHeaderNames.COOKIE);
104 if (cookie == null || "".equals(cookie)) { return new HashSet<Cookie>(); }
105
106 Set<Cookie> ret = ServerCookieDecoder.STRICT.decode(cookie);
107
108 return ret == null || ret.isEmpty() ? new HashSet<Cookie>() : ret;
109 }
110
111 public Map<String, String> pathParameters() {
112 return pathParameters;
113 }
114
115 public HttpRequest pathParameters(Map<String, String> pathParameters) {
116 this.pathParameters = pathParameters;
117
118 return this;
119 }
120
121 public String pathParameter(String name) {
122 return pathParameters.get(name);
123 }
124
125 public Map<String, List<String>> parameters() {
126
127 if (parameters != null) { return parameters; }
128
129 Map<String, List<String>> ret = Maps.newHashMap();
130
131 if (HttpMethod.GET.equals(method()) || HttpMethod.DELETE.equals(method())) {
132 ret.putAll(new QueryStringDecoder(uri()).parameters());
133 return ret;
134 }
135 else if (headers().contains(HttpHeaderNames.CONTENT_TYPE)
136 && headers().get(HttpHeaderNames.CONTENT_TYPE)
137 .startsWith(HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED.toString())
138 && (HttpMethod.POST.equals(method()) || HttpMethod.PUT.equals(method()))) {
139
140 ret.putAll(new QueryStringDecoder("/dummy?" + content().toString(CharsetUtil.UTF_8)).parameters());
141 }
142
143 return ret;
144 }
145
146
147
148
149
150
151
152
153
154
155 public String parameter(String name) {
156 if (!parameters().containsKey(name) || parameters.get(name).size() <= 0) { return null; }
157
158 return parameters().get(name).get(0);
159 }
160
161 public HttpRequest addParameter(String name, String value) {
162 List<String> values = parameters().get(name);
163 if (values == null) {
164 values = new ArrayList<String>();
165 values.add(value);
166 parameters().put(name, values);
167 }
168 else {
169 values.clear();
170 values.add(value);
171 }
172
173 return this;
174 }
175
176 @Override
177 public boolean equals(Object o) {
178 return toString().equals(o.toString());
179
180 }
181
182 @Override
183 public int hashCode() {
184 return toString().hashCode();
185 }
186
187 public String toString(Date incomingTime) {
188 StringBuilder buf = new StringBuilder();
189
190 buf.append("\r\n");
191 buf.append("Request URI: ").append(this.uri()).append("\r\n");
192 buf.append("HTTP METHOD: ").append(this.method().toString()).append("\r\n");
193 buf.append("Requested Time: ").append(incomingTime.toString()).append("\r\n");
194 buf.append("Version: ").append(this.protocolVersion()).append("\r\n");
195 buf.append("Request Headers:").append("\r\n");
196
197 List<Entry<String, String>> headers = this.headers().entries();
198 if (!headers.isEmpty()) {
199 for (Entry<String, String> h : this.headers().entries()) {
200 String key = h.getKey();
201 String value = h.getValue();
202 buf.append(" ").append(key).append(" = ").append(value).append("\r\n");
203 }
204 }
205
206 Map<String, List<String>> params = parameters();
207
208 buf.append("Query String Parameters: ");
209
210 if (params.isEmpty()) {
211 buf.append("NONE\r\n");
212 }
213 else {
214 for (Entry<String, List<String>> p : params.entrySet()) {
215 String key = p.getKey();
216 List<String> vals = p.getValue();
217 for (String val : vals) {
218 buf.append("\r\n ").append(key).append(" = ").append(val).append("\r\n");
219 }
220 }
221 }
222
223 buf.append("Content: ");
224 if (this.content().isReadable()) {
225 buf.append("\r\n ").append(content().toString(CharsetUtil.UTF_8));
226 }
227 else {
228 buf.append("UNREADABLE CONTENT or NONE");
229 }
230
231 DecoderResult result = this.decoderResult();
232
233 if (!result.isSuccess()) {
234 buf.append("\r\n").append(".. WITH DECODER FAILURE:");
235 buf.append("\r\n ").append(result.cause());
236 }
237
238 return buf.toString();
239 }
240
241 @Override
242 public String toString() {
243 return toString(new Date());
244 }
245
246 public void setContent(String content) {
247 byte[] contentByte = Strings.nullToEmpty(content).getBytes(CharsetUtil.UTF_8);
248
249 headers().set(HttpHeaderNames.CONTENT_LENGTH, contentByte.length);
250 content().writeBytes(contentByte);
251
252 logger.debug(content().toString(CharsetUtil.UTF_8));
253 }
254
255 public URI uriObject() {
256 return uri;
257 }
258
259 protected void normalize() {
260 normalizeParameters();
261
262 String encoded = ClientCookieEncoder.STRICT.encode(cookies);
263 if (encoded == null) { return; }
264
265 headers().set(HttpHeaderNames.COOKIE, encoded);
266 }
267
268 private String convertParametersToString() {
269
270 StringBuilder builder = new StringBuilder();
271
272 for (String name : parameters().keySet()) {
273
274 for (String value : parameters().get(name)) {
275 builder = builder.append(name).append("=").append(value).append("&");
276 }
277 }
278
279 String ret = builder.toString();
280 if (ret.length() <= 0) { return ""; }
281
282 if (ret.charAt(ret.length() - 1) == '&') {
283 return ret.substring(0, ret.length() - 1);
284 }
285 else {
286 return ret;
287 }
288 }
289
290 private void normalizeParameters() {
291 String address = new StringBuilder().append(uriObject().getScheme()).append("://")
292 .append(uriObject().getAuthority()).append(uriObject().getPath()).toString();
293
294 if (HttpMethod.GET.equals(method()) || HttpMethod.DELETE.equals(method())) {
295 String parameters = convertParametersToString();
296 address += Strings.isNullOrEmpty(parameters) ? "" : "?" + parameters;
297 }
298 else if ((HttpMethod.POST.equals(method()) || HttpMethod.PUT.equals(method()))
299 && (!headers().contains(HttpHeaderNames.CONTENT_TYPE) || headers().get(HttpHeaderNames.CONTENT_TYPE)
300 .startsWith(HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED.toString()))) {
301 ByteBuf content = Unpooled.copiedBuffer(convertParametersToString(), CharsetUtil.UTF_8);
302
303 headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());
304 content().clear();
305 content().writeBytes(content);
306 }
307
308 setUri(address);
309 }
310 }