View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.mina.http;
21  
22  import static org.junit.Assert.assertEquals;
23  import static org.junit.Assert.assertTrue;
24  
25  import java.nio.charset.CharacterCodingException;
26  import java.nio.charset.Charset;
27  import java.nio.charset.CharsetEncoder;
28  
29  import org.apache.mina.core.buffer.IoBuffer;
30  import org.apache.mina.core.filterchain.IoFilter.NextFilter;
31  import org.apache.mina.core.session.DummySession;
32  import org.apache.mina.core.session.IoSession;
33  import org.apache.mina.filter.codec.AbstractProtocolDecoderOutput;
34  import org.apache.mina.filter.codec.ProtocolDecoder;
35  import org.apache.mina.http.api.HttpEndOfContent;
36  import org.apache.mina.http.api.HttpRequest;
37  import org.junit.Test;
38  
39  public class HttpServerDecoderTest {
40      private static final CharsetEncoder encoder = Charset.forName("US-ASCII").newEncoder(); //$NON-NLS-1$
41  
42      private static final ProtocolDecoder decoder = new HttpServerDecoder();
43  
44      /*
45       * Use a single session for all requests in order to test state management better
46       */
47      private static IoSession session = new DummySession();
48  
49      /**
50       * Build an IO buffer containing a simple minimal HTTP request.
51       * 
52       * @param method the HTTP method
53       * @param body the option body
54       * @return the built IO buffer
55       * @throws CharacterCodingException if encoding fails
56       */
57      protected static IoBuffer getRequestBuffer(String method, String body) throws CharacterCodingException {
58          IoBuffer buffer = IoBuffer.allocate(0).setAutoExpand(true);
59          buffer.putString(method + " / HTTP/1.1\r\nHost: dummy\r\n", encoder);
60          
61          if (body != null) {
62              buffer.putString("Content-Length: " + body.length() + "\r\n\r\n", encoder);
63              buffer.putString(body, encoder);
64          } else {
65              buffer.putString("\r\n", encoder);
66          }
67          
68          buffer.rewind();
69          
70          return buffer;
71      }
72  
73      protected static IoBuffer getRequestBuffer(String method) throws CharacterCodingException {
74          return getRequestBuffer(method, null);
75      }
76  
77      /**
78       * Execute an HTPP request and return the queue of messages.
79       * 
80       * @param method the HTTP method
81       * @param body the optional body
82       * @return the protocol output and its queue of messages
83       * @throws Exception if error occurs (encoding,...)
84       */
85      protected static AbstractProtocolDecoderOutput executeRequest(String method, String body) throws Exception {
86          AbstractProtocolDecoderOutput out = new AbstractProtocolDecoderOutput() {
87              public void flush(NextFilter nextFilter, IoSession session) {
88              }
89          };
90  
91          IoBuffer buffer = getRequestBuffer(method, body); //$NON-NLS-1$
92          
93          while (buffer.hasRemaining()) {
94              decoder.decode(session, buffer, out);
95          }
96          
97          return out;
98      }
99  
100     @Test
101     public void testGetRequestWithoutBody() throws Exception {
102         AbstractProtocolDecoderOutput out = executeRequest("GET", null);
103         assertEquals(2, out.getMessageQueue().size());
104         assertTrue(out.getMessageQueue().poll() instanceof HttpRequest);
105         assertTrue(out.getMessageQueue().poll() instanceof HttpEndOfContent);
106     }
107 
108     @Test
109     public void testGetRequestBody() throws Exception {
110         AbstractProtocolDecoderOutput out = executeRequest("GET", "body");
111         assertEquals(3, out.getMessageQueue().size());
112         assertTrue(out.getMessageQueue().poll() instanceof HttpRequest);
113         assertTrue(out.getMessageQueue().poll() instanceof IoBuffer);
114         assertTrue(out.getMessageQueue().poll() instanceof HttpEndOfContent);
115     }
116 
117     @Test
118     public void testPutRequestWithoutBody() throws Exception {
119         AbstractProtocolDecoderOutput out = executeRequest("PUT", null);
120         assertEquals(2, out.getMessageQueue().size());
121         assertTrue(out.getMessageQueue().poll() instanceof HttpRequest);
122         assertTrue(out.getMessageQueue().poll() instanceof HttpEndOfContent);
123     }
124 
125     @Test
126     public void testPutRequestBody() throws Exception {
127         AbstractProtocolDecoderOutput out = executeRequest("PUT", "body");
128         assertEquals(3, out.getMessageQueue().size());
129         assertTrue(out.getMessageQueue().poll() instanceof HttpRequest);
130         assertTrue(out.getMessageQueue().poll() instanceof IoBuffer);
131         assertTrue(out.getMessageQueue().poll() instanceof HttpEndOfContent);
132     }
133 
134     @Test
135     public void testPostRequestWithoutBody() throws Exception {
136         AbstractProtocolDecoderOutput out = executeRequest("POST", null);
137         assertEquals(2, out.getMessageQueue().size());
138         assertTrue(out.getMessageQueue().poll() instanceof HttpRequest);
139         assertTrue(out.getMessageQueue().poll() instanceof HttpEndOfContent);
140     }
141 
142     @Test
143     public void testPostRequestBody() throws Exception {
144         AbstractProtocolDecoderOutput out = executeRequest("POST", "body");
145         assertEquals(3, out.getMessageQueue().size());
146         assertTrue(out.getMessageQueue().poll() instanceof HttpRequest);
147         assertTrue(out.getMessageQueue().poll() instanceof IoBuffer);
148         assertTrue(out.getMessageQueue().poll() instanceof HttpEndOfContent);
149     }
150 
151     @Test
152     public void testDeleteRequestWithoutBody() throws Exception {
153         AbstractProtocolDecoderOutput out = executeRequest("DELETE", null);
154         assertEquals(2, out.getMessageQueue().size());
155         assertTrue(out.getMessageQueue().poll() instanceof HttpRequest);
156         assertTrue(out.getMessageQueue().poll() instanceof HttpEndOfContent);
157     }
158 
159     @Test
160     public void testDeleteRequestBody() throws Exception {
161         AbstractProtocolDecoderOutput out = executeRequest("DELETE", "body");
162         assertEquals(3, out.getMessageQueue().size());
163         assertTrue(out.getMessageQueue().poll() instanceof HttpRequest);
164         assertTrue(out.getMessageQueue().poll() instanceof IoBuffer);
165         assertTrue(out.getMessageQueue().poll() instanceof HttpEndOfContent);
166     }
167     
168     @Test
169     public void testDIRMINA965NoContent() throws Exception {
170         AbstractProtocolDecoderOutput out = new AbstractProtocolDecoderOutput() {
171             public void flush(NextFilter nextFilter, IoSession session) {
172             }
173         };
174         IoBuffer buffer = IoBuffer.allocate(0).setAutoExpand(true);
175         buffer.putString("GET / HTTP/1.1\r\nHost: ", encoder);
176         buffer.rewind();
177         while (buffer.hasRemaining()) {
178             decoder.decode(session, buffer, out);
179         }
180         buffer = IoBuffer.allocate(0).setAutoExpand(true);
181         buffer.putString("dummy\r\n\r\n", encoder);
182         buffer.rewind();
183         while (buffer.hasRemaining()) {
184             decoder.decode(session, buffer, out);
185         }
186         assertEquals(2, out.getMessageQueue().size());
187         assertTrue(out.getMessageQueue().poll() instanceof HttpRequest);
188         assertTrue(out.getMessageQueue().poll() instanceof HttpEndOfContent);
189     }
190 
191     @Test
192     public void testDIRMINA965WithContent() throws Exception {
193         AbstractProtocolDecoderOutput out = new AbstractProtocolDecoderOutput() {
194             public void flush(NextFilter nextFilter, IoSession session) {
195             }
196         };
197         IoBuffer buffer = IoBuffer.allocate(0).setAutoExpand(true);
198         buffer.putString("GET / HTTP/1.1\r\nHost: ", encoder);
199         buffer.rewind();
200         while (buffer.hasRemaining()) {
201             decoder.decode(session, buffer, out);
202         }
203         buffer = IoBuffer.allocate(0).setAutoExpand(true);
204         buffer.putString("dummy\r\nContent-Length: 1\r\n\r\nA", encoder);
205         buffer.rewind();
206         while (buffer.hasRemaining()) {
207             decoder.decode(session, buffer, out);
208         }
209         assertEquals(3, out.getMessageQueue().size());
210         assertTrue(out.getMessageQueue().poll() instanceof HttpRequest);
211         assertTrue(out.getMessageQueue().poll() instanceof IoBuffer);
212         assertTrue(out.getMessageQueue().poll() instanceof HttpEndOfContent);
213     }
214     @Test
215     public void testDIRMINA965WithContentOnTwoChunks() throws Exception {
216         AbstractProtocolDecoderOutput out = new AbstractProtocolDecoderOutput() {
217             public void flush(NextFilter nextFilter, IoSession session) {
218             }
219         };
220         IoBuffer buffer = IoBuffer.allocate(0).setAutoExpand(true);
221         buffer.putString("GET / HTTP/1.1\r\nHost: ", encoder);
222         buffer.rewind();
223         while (buffer.hasRemaining()) {
224             decoder.decode(session, buffer, out);
225         }
226         buffer = IoBuffer.allocate(0).setAutoExpand(true);
227         buffer.putString("dummy\r\nContent-Length: 2\r\n\r\nA", encoder);
228         buffer.rewind();
229         while (buffer.hasRemaining()) {
230             decoder.decode(session, buffer, out);
231         }
232         buffer = IoBuffer.allocate(0).setAutoExpand(true);
233         buffer.putString("B", encoder);
234         buffer.rewind();
235         while (buffer.hasRemaining()) {
236             decoder.decode(session, buffer, out);
237         }
238         assertEquals(4, out.getMessageQueue().size());
239         assertTrue(out.getMessageQueue().poll() instanceof HttpRequest);
240         assertTrue(out.getMessageQueue().poll() instanceof IoBuffer);
241         assertTrue(out.getMessageQueue().poll() instanceof IoBuffer);
242         assertTrue(out.getMessageQueue().poll() instanceof HttpEndOfContent);
243     }
244     
245     @Test
246     public void verifyThatHeaderWithoutLeadingSpaceIsSupported() throws Exception {
247         AbstractProtocolDecoderOutput out = new AbstractProtocolDecoderOutput() {
248             public void flush(NextFilter nextFilter, IoSession session) {
249             }
250         };
251         IoBuffer buffer = IoBuffer.allocate(0).setAutoExpand(true);
252         buffer.putString("GET / HTTP/1.0\r\nHost:localhost\r\n\r\n", encoder);
253         buffer.rewind();
254         while (buffer.hasRemaining()) {
255             decoder.decode(session, buffer, out);
256         }
257         assertEquals(2, out.getMessageQueue().size());
258         HttpRequest request = (HttpRequest) out.getMessageQueue().poll();
259         assertEquals("localhost", request.getHeader("host"));
260         assertTrue(out.getMessageQueue().poll() instanceof HttpEndOfContent);
261     }
262 
263     @Test
264     public void verifyThatLeadingSpacesAreRemovedFromHeader() throws Exception {
265         AbstractProtocolDecoderOutput out = new AbstractProtocolDecoderOutput() {
266             public void flush(NextFilter nextFilter, IoSession session) {
267             }
268         };
269         IoBuffer buffer = IoBuffer.allocate(0).setAutoExpand(true);
270         buffer.putString("GET / HTTP/1.0\r\nHost:  localhost\r\n\r\n", encoder);
271         buffer.rewind();
272         while (buffer.hasRemaining()) {
273             decoder.decode(session, buffer, out);
274         }
275         assertEquals(2, out.getMessageQueue().size());
276         HttpRequest request = (HttpRequest) out.getMessageQueue().poll();
277         assertEquals("localhost", request.getHeader("host"));
278         assertTrue(out.getMessageQueue().poll() instanceof HttpEndOfContent);
279     }
280 
281     @Test
282     public void verifyThatTrailingSpacesAreRemovedFromHeader() throws Exception {
283         AbstractProtocolDecoderOutput out = new AbstractProtocolDecoderOutput() {
284             public void flush(NextFilter nextFilter, IoSession session) {
285             }
286         };
287         IoBuffer buffer = IoBuffer.allocate(0).setAutoExpand(true);
288         buffer.putString("GET / HTTP/1.0\r\nHost:localhost  \r\n\r\n", encoder);
289         buffer.rewind();
290         while (buffer.hasRemaining()) {
291             decoder.decode(session, buffer, out);
292         }
293         assertEquals(2, out.getMessageQueue().size());
294         HttpRequest request = (HttpRequest) out.getMessageQueue().poll();
295         assertEquals("localhost", request.getHeader("host"));
296         assertTrue(out.getMessageQueue().poll() instanceof HttpEndOfContent);
297     }
298 }