001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.mina.http; 021 022import static org.junit.Assert.assertEquals; 023import static org.junit.Assert.assertTrue; 024 025import java.nio.charset.CharacterCodingException; 026import java.nio.charset.Charset; 027import java.nio.charset.CharsetEncoder; 028 029import org.apache.mina.core.buffer.IoBuffer; 030import org.apache.mina.core.filterchain.IoFilter.NextFilter; 031import org.apache.mina.core.session.DummySession; 032import org.apache.mina.core.session.IoSession; 033import org.apache.mina.filter.codec.AbstractProtocolDecoderOutput; 034import org.apache.mina.filter.codec.ProtocolDecoder; 035import org.apache.mina.http.api.HttpEndOfContent; 036import org.apache.mina.http.api.HttpRequest; 037import org.junit.Test; 038 039public class HttpServerDecoderTest { 040 private static final CharsetEncoder encoder = Charset.forName("US-ASCII").newEncoder(); //$NON-NLS-1$ 041 042 private static final ProtocolDecoder decoder = new HttpServerDecoder(); 043 044 /* 045 * Use a single session for all requests in order to test state management better 046 */ 047 private static IoSession session = new DummySession(); 048 049 /** 050 * Build an IO buffer containing a simple minimal HTTP request. 051 * 052 * @param method the HTTP method 053 * @param body the option body 054 * @return the built IO buffer 055 * @throws CharacterCodingException if encoding fails 056 */ 057 protected static IoBuffer getRequestBuffer(String method, String body) throws CharacterCodingException { 058 IoBuffer buffer = IoBuffer.allocate(0).setAutoExpand(true); 059 buffer.putString(method + " / HTTP/1.1\r\nHost: dummy\r\n", encoder); 060 061 if (body != null) { 062 buffer.putString("Content-Length: " + body.length() + "\r\n\r\n", encoder); 063 buffer.putString(body, encoder); 064 } else { 065 buffer.putString("\r\n", encoder); 066 } 067 068 buffer.rewind(); 069 070 return buffer; 071 } 072 073 protected static IoBuffer getRequestBuffer(String method) throws CharacterCodingException { 074 return getRequestBuffer(method, null); 075 } 076 077 /** 078 * Execute an HTPP request and return the queue of messages. 079 * 080 * @param method the HTTP method 081 * @param body the optional body 082 * @return the protocol output and its queue of messages 083 * @throws Exception if error occurs (encoding,...) 084 */ 085 protected static AbstractProtocolDecoderOutput executeRequest(String method, String body) throws Exception { 086 AbstractProtocolDecoderOutput out = new AbstractProtocolDecoderOutput() { 087 public void flush(NextFilter nextFilter, IoSession session) { 088 } 089 }; 090 091 IoBuffer buffer = getRequestBuffer(method, body); //$NON-NLS-1$ 092 093 while (buffer.hasRemaining()) { 094 decoder.decode(session, buffer, out); 095 } 096 097 return out; 098 } 099 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}