/*******************************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*******************************************************************************/
package org.apache.wink.common.internal.providers.multipart;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import javax.ws.rs.core.MultivaluedMap;
import junit.framework.TestCase;
public class TestMultiPartParser extends TestCase {
String boundery = "test boundry";
String NL = "\r";
String[] messages = new String[] {
"bla bla bla\n"
+ "\n--"
+ boundery
+ NL
+ "content-type: message/http;version=1.1;msgtype=request\n"
+ NL + "bla bla bla\n" + NL + "bla bla bla\n" + NL
+ "bla bla bla\n" + NL + "--" + boundery + "--" + NL,
"--"
+ boundery
+ ""
+ NL
+ "content-type: message/http;version=1.1;msgtype=request"
+ NL
+ ""
+ NL
+ "PUT /service/business-services/phone-book HTTP/1.1"
+ NL
+ "content-type: application/atom+xml;type=entry"
+ NL
+ ""
+ NL
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">"
+ NL
+ " ..."
+ NL
+ " <title type=\"text\" xml:lang=\"en\">Phonebook Business Service</title>"
+ NL
+ " ..."
+ NL
+ " <link href=\"slug: implementations/my-new-implementation\" type=\"application/atom+xml\" rel=\"implementation\"/>"
+ NL
+ " ..."
+ NL
+ "</entry>"
+ NL
+ ""
+ NL
+ "--"
+ boundery
+ ""
+ NL
+ "content-type: message/http;version=1.1;msgtype=request"
+ NL
+ ""
+ NL
+ "POST /service/implementations HTTP/1.1"
+ NL
+ "content-type: application/atom+xml;type=entry"
+ NL
+ "slug: implementations/my-new-implementation"
+ NL
+ ""
+ NL
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">"
+ NL
+ " ..."
+ NL
+ " <title type=\"text\" xml:lang=\"en\">Phonebook Service Implementation</title>"
+ NL
+ " ..."
+ NL
+ " <link href=\"business-services/phone-book\" type=\"application/atom+xml\" rel=\"business-service\"/>"
+ NL
+ " <link href=\"slug: documentations/my-new-phonebook-reference-guide\" type=\"application/msword\" rel=\"documentation\"/>"
+ NL
+ " ..."
+ NL
+ "</entry>"
+ NL
+ ""
+ NL
+ "--symphony-batch"
+ NL
+ "content-type: message/http;version=1.1;msgtype=request"
+ NL
+ ""
+ NL
+ "DELETE /service/documentations/obsolete-documentation HTTP/1.1"
+ NL
+ ""
+ NL
+ "--"
+ boundery
+ NL
+ "content-type: message/http;version=1.1;msgtype=request"
+ NL
+ ""
+ NL
+ "POST /service/documentations HTTP/1.1"
+ NL
+ "content-type: application/msword"
+ NL
+ "slug: documentations/my-new-phonebook-reference-guide"
+ NL
+ ""
+ NL
+ "... binary MS WORD media type..."
+ NL
+ ""
+ NL
+ "--"
+ boundery
+ ""
+ NL
+ "content-type: message/http;version=1.1;msgtype=request"
+ NL
+ ""
+ NL
+ "POST /service/ws-policies HTTP/1.1"
+ NL
+ "content-type: application/xml"
+ NL
+ "slug: ws-policies/my-new-policy"
+ NL
+ ""
+ NL
+ "<wsp:Policy xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2004/09/policy\"...>"
+ NL + " ..." + NL + "</wsp>" + NL + "" + NL + "--"
+ boundery + "" + NL
+ "content-type: message/http;version=1.1;msgtype=request"
+ NL + "" + NL + "POST /service/ws-policies HTTP/1.1" + NL
+ "content-type: application/atom+xml" + NL
+ "slug: ws-policies/my-new-policy" + NL + "" + NL
+ "<asf:entry>" + NL + " ..." + NL + "</asf:entry>" + NL
+ "" + NL + "--" + boundery + "--" + NL + "" + NL
};
public void testParser() throws IOException {
try {
for (String s : messages) {
printMessage(s);
}
} catch (IOException e) {
throw e;
}
}
public void testMsg() throws IOException {
try {
for (String s : messages) {
printMessage(s);
}
} catch (IOException e) {
throw e;
}
}
public void printMessage(String part) throws IOException {
System.out.println(part);
ByteArrayInputStream is = new ByteArrayInputStream(part.getBytes());
MultiPartParser mpp = new MultiPartParser(is, boundery);
System.out.println("=========== BEGINE ==================");
while (mpp.nextPart()) {
System.out.println("=========== PART ==================");
printHeaders(mpp.getPartHeaders());
InputStream partStream = mpp.getPartBodyStream();
printIS(partStream);
}
System.out.println("=========== END ==================");
int i = 0;
}
private void printHeaders(MultivaluedMap<String, String> headers) {
System.out.println(" ---------- Headers start --------------");
for (String header : headers.keySet()) {
List<String> values = headers.get(header);
System.out.print(header + " :");
for (String value : values) {
System.out.println(value);
}
}
System.out.println(" ---------- Headers end --------------");
}
private void printIS(InputStream is) throws IOException {
System.out.println(" ---------- Body start --------------");
// ArrayList<Byte> array = new ArrayList<Byte>();
byte[] array = new byte[100000];
int b;
int i = 0;
while ((b = is.read()) != -1) {
array[i] = (byte) b;
i++;
}
String s = new String(array, 0, i);
System.out.print(s);
System.out.println("\n ---------- Body end --------------");
}
public void testHugeMsg() throws IOException{
String boundery ="This is my boundery 123";
String prefix = "bla bla bla\n"
+ "\n--" + boundery + NL
+ "content-type: message/http;version=1.1;msgtype=request\n"
+ NL
+ "bla bla bla\n" + NL
+ "bla bla bla\n" + NL;
String suffix = "bla bla bla\n" + NL +
"--" + boundery + "--" + NL;
// 100 MG msg
HugeMsg msg = new HugeMsg(prefix.getBytes(),suffix.getBytes(),100000000);
MultiPartParser mpp = new MultiPartParser(msg,boundery);
int parts = 0;
while (mpp.nextPart())
parts++;
assertEquals(parts, 1);
}
public void testMsgBodyLength() throws IOException{
String boundery ="This is my boundery 123";
String prefix = "bla bla bla\n"
+ "\n--" + boundery + NL
+ "content-type: message/http;version=1.1;msgtype=request\n"
+ NL;
String suffix = NL +
"--" + boundery + "--" + NL;
int length= 12;
HugeMsg msg = new HugeMsg(prefix.getBytes(),suffix.getBytes(),length);
MultiPartParser mpp = new MultiPartParser(msg,boundery);
int size = 0;
mpp.nextPart();
InputStream is = mpp.getPartBodyStream();
while(is.read()!= -1)
size++;
assertEquals(size, length);
}
public void testMsg01() throws Exception {
TestMsgInfo msg = new TestMsgInfo("msg01.txt", "boundary");
checkNumOfParts(msg, 2);
assertEquals(getHeader(msg, 1, "Content-Id"), "part1");
}
public void testMsg02() throws Exception {
TestMsgInfo msg = new TestMsgInfo("msg02.txt", "----=_Part_7_10584188.1123489648993");
checkNumOfParts(msg, 2);
assertEquals(getHeader(msg, 1, "Content-Type").toLowerCase(), "text/xml; charset=UTF-8".toLowerCase());
}
public void testMsg03() throws Exception {
TestMsgInfo msg = new TestMsgInfo("msg03.txt", "----=_Part_7_10584188.1123489648993");
checkNumOfParts(msg, 2);
assertEquals(getHeaders(msg, 1).size(),2);
}
public void testMsg04() throws Exception {
TestMsgInfo msg = new TestMsgInfo("msg04.txt", "----=_Part_1_2_3_4_5_6");
checkNumOfParts(msg, 2);
//assertEquals(getHeaders(msg, 1).size(),2);
}
public void testMsg05() throws Exception {
TestMsgInfo msg = new TestMsgInfo("msg05.txt", "----=_Part_1_807283631.1066069460327");
checkNumOfParts(msg, 2);
//assertEquals(getHeaders(msg, 1).size(),2);
}
public void testMsg07() throws Exception {
TestMsgInfo msg = new TestMsgInfo("msg07.txt", "Boundary1");
checkNumOfParts(msg, 1);
}
private void checkNumOfParts(TestMsgInfo msgInfo, int expectedNumParts)
throws IOException {
MultiPartParser mpp = msgInfo.createMPParser();
int parts = 0;
while (mpp.nextPart())
parts++;
assertEquals(parts, expectedNumParts);
}
private MultivaluedMap<String, String> getHeaders(TestMsgInfo msgInfo, int partNum)
throws IOException {
MultiPartParser mpp = msgInfo.createMPParser();
int sec = 0;
while (sec <partNum){
mpp.nextPart();
sec++;
}
return mpp.getPartHeaders();
}
private String getHeader(TestMsgInfo msgInfo, int partNum,String headerName)
throws IOException {
String header = getHeaders(msgInfo,partNum).getFirst(headerName);
return header;
}
/***
* Helper class to generate a parser out of a file
* @author barame
*/
class TestMsgInfo {
String resource;
String boundery;
public TestMsgInfo(String resource, String boudery) {
this.resource = resource;
this.boundery = boudery;
}
public MultiPartParser createMPParser() {
InputStream in = getClass().getResourceAsStream(resource);
return new MultiPartParser(in, boundery);
}
}
class HugeMsg extends InputStream{
private byte[] prefix;
private byte[] sufix;
int length;
int index=0;
int bodyByte = 'A';
HugeMsg(byte[] prefix,byte[] sufix,int length){
this.prefix = prefix;
this.sufix = sufix;
this .length = length;
}
@Override
public int read() throws IOException {
if(index< prefix.length){
int res = prefix[index];
index++;
return res;
}
if(index< prefix.length + length){
index++;
return bodyByte;
}
if(index< prefix.length + length +sufix.length){
int res = sufix[index-(length+prefix.length)];
index++;
return res;
}
return -1;
}
}
}