3

I am getting wierd behaviour with server-api 3.0 when using the @MultipartConfig. When I am calling the servlet from a jsp page it works 100% , but when I make a call to the servlet from my own java client (using the java.net api) I get an exception. below is my source code and the output I get in both scenarios.

I am using Java 1.6.0 , and running the servlet on apache-tomcat-7.0.11.

Servet :

import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

@WebServlet(urlPatterns="/MultipartUploadServlet" , name="MultipartUploadServlet")
@MultipartConfig(location="/tmp", maxFileSize = 10485760L)
public class MultipartUploadServlet extends HttpServlet{

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("MultipartUploadServlet.doPost");
        try {

            System.out.println("Print out the request header");
            Enumeration<String> hn = req.getHeaderNames();
            while(hn.hasMoreElements()) {
                String n = hn.nextElement();
                System.out.println(n + " [" + req.getHeader(n) + "]");
            }

            Collection<Part> requestParts = req.getParts();
            System.out.println("there are [" + requestParts.size() +"] multiparts");


            System.out.println("printing out request inputstream");
            InputStream is = req.getInputStream();
            int charRead = 0;
            System.out.println("[");
            while((charRead = is.read()) != -1){
                System.out.print((char)charRead);
            }
            is.close();

            System.out.println("]");

        } catch (Exception excp) {
            excp.printStackTrace();
        } 
    }

}

Jsp client

<html>
    <head></head>
    <body>
        <p>Commons File Upload Example</p>
        <form action="MultipartUploadServlet" enctype="multipart/form-data" method="post">
            <input type="file" name="file1"><br>
            <input type="Submit" value="Upload File"><br>s
        </form>
    </body>
</html>

output on tomcat using jsp client

host [localhost:8080]
user-agent [Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13]
accept [text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8]
accept-language [en-us,en;q=0.5]
accept-encoding [gzip,deflate]
accept-charset [ISO-8859-1,utf-8;q=0.7,*;q=0.7]
keep-alive [115]
connection [keep-alive]
referer [http://localhost:8080/scrappyWeb/test.jsp]
cookie [JSESSIONID=06A3E14F91D4B8E558B7438B1D9C7E99]
content-type [multipart/form-data; boundary=---------------------------1137522503144128232716531729]
content-length [223]
there are [1] multiparts

java client

package com.scrappy.web.client.compass.verification;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

public class TestClient {

    public static void main(String ... aaa)  {
        System.setProperty("http.keepAlive", "false");

        String boundary = "---------------------------" + Long.toHexString(System.currentTimeMillis());
        try {
            URLConnection connection = new URL("http://localhost:8080/scrappyWeb/MultipartUploadServlet").openConnection();
            ((HttpURLConnection)connection).setRequestMethod("POST");
            ((HttpURLConnection)connection).setConnectTimeout(60000);
            connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13"); // Do as if you're using Firefox 3.6.3.
            connection.setDoOutput(true);
            connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
            connection.setRequestProperty("keep-alive", "115");
            connection.setRequestProperty("accept-encoding", "gzip,deflate");
            connection.setRequestProperty("connection", "keep-alive");
            connection.setRequestProperty("accept-charset","ISO-8859-1,utf-8;q=0.7,*;q=0.7");
            connection.setRequestProperty("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
            PrintWriter writer = null;
            OutputStream output = connection.getOutputStream();

            String charset = "UTF-8";

            File textFile = new File("/Users/christiaan/test.txt");

            writer = new PrintWriter(new OutputStreamWriter(output, charset), true);
            writer.println("--" + boundary);
            writer.println("Content-Disposition: form-data; name=\"file1\"; filename=\"" + textFile.getName() + "\"");
            writer.println("Content-Type: text/plain");
            writer.println();
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new InputStreamReader(new FileInputStream(textFile), charset));
                for (String line; (line = reader.readLine()) != null;) {
                    writer.println(line);
                }
            } finally {
                if (reader != null) try { reader.close(); } catch (IOException logOrIgnore) {}
            }
            writer.println(); // Important! Indicates end of binary boundary.

            // End of multipart/form-data.
            writer.println("--" + boundary + "--");
            writer.close();

         ((HttpURLConnection)connection).getResponseCode();

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

output on tomcat using java client

user-agent [Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13]
content-type [multipart/form-data; boundary=---------------------------12f24455f6f]
accept-encoding [gzip,deflate]
accept-charset [ISO-8859-1,utf-8;q=0.7,*;q=0.7]
accept [text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8]
host [localhost:8080]
connection [close]
content-length [183]
java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException: Stream ended unexpectedly
    at org.apache.catalina.connector.Request.parseParts(Request.java:2639)
    at org.apache.catalina.connector.Request.getParts(Request.java:2539)
    at org.apache.catalina.connector.RequestFacade.getParts(RequestFacade.java:1077)
    at com.scrappy.web.servlet.compass.verification.MultipartUploadServlet.doPost(MultipartUploadServlet.java:31)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:498)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:562)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:394)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:243)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:166)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:680)
Caused by: org.apache.tomcat.util.http.fileupload.FileUploadException: Stream ended unexpectedly
    at org.apache.tomcat.util.http.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:336)
    at org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:129)
    at org.apache.catalina.connector.Request.parseParts(Request.java:2609)
    ... 22 more
Caused by: org.apache.tomcat.util.http.fileupload.MultipartStream$MalformedStreamException: Stream ended unexpectedly
    at org.apache.tomcat.util.http.fileupload.MultipartStream.readHeaders(MultipartStream.java:488)
    at org.apache.tomcat.util.http.fileupload.FileUploadBase$FileItemIteratorImpl.findNextItem(FileUploadBase.java:861)
    at org.apache.tomcat.util.http.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:827)
    at org.apache.tomcat.util.http.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:282)
    at org.apache.tomcat.util.http.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:302)
    ... 24 more

The only real difference I see in the headers is the content length. But what gets me , is that if I get the inputStream from the HttpServletRequest and I print that , it prints everyting in the test.txt file as it should be.

I have followed BalusC post

I must be missing something or not understading something , hope someone can help !

4

3 回答 3

6

Mac/Linux在 HTTP 要求时\n用作默认行分隔符(并且是 Windows 上的默认值)。抱歉,这是教程中的一个非常愚蠢的错误。我会尽快修复它。println()\r\nURLConnection

于 2011-04-05T13:49:29.110 回答
3

使用wireshark 查询发送的数据包,我发现MIME Multipart 数据包格式不正确。我基本上将客户端更改为编写内容配置内容以直接使用输出流而不是 PrintWriter。它似乎有效,但我不知道为什么,因为两者本质上是一样的。

感谢Vineet Reynolds将我指向 WireShark

这是新客户:

package com.scrappy.web.client.compass.verification;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

public class TestClient {

    public static void main(String ... aaa)  {
        System.setProperty("http.keepAlive", "false");

        String boundary = "---------------------------" +  Long.toHexString(System.currentTimeMillis());
        try {
            URLConnection connection = new URL("http://localhost:8080/scrappyWeb/MultipartUploadServlet").openConnection();
            ((HttpURLConnection)connection).setRequestMethod("POST");
            ((HttpURLConnection)connection).setConnectTimeout(6000000);
            connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13"); // Do as if you're using Firefox 3.6.3.
            connection.setDoOutput(true);
            connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
            connection.setRequestProperty("accept-encoding", "gzip,deflate");
            connection.setRequestProperty("connection", "keep-alive");
            connection.setRequestProperty("accept-charset","ISO-8859-1,utf-8;q=0.7,*;q=0.7");
            connection.setRequestProperty("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
            connection.setRequestProperty("accept-language", "en-us,en;q=0.5");
            OutputStream output = connection.getOutputStream();

            String charset = "UTF-8";

            File textFile = new File("/Users/christiaan/test.txt");
            output.write(("\r\n\r\n--" + boundary +"\r\n").getBytes());
            output.write(("Content-Disposition: form-data; name=\"file1\"; filename=\"" + textFile.getName() + "\"\r\n").getBytes());
            output.write(("Content-Type: text/plain\r\n").getBytes());
            output.write(("\r\n").getBytes());


            PrintWriter writer = null;
            writer = new PrintWriter(new OutputStreamWriter(output, charset), true);
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new InputStreamReader(new FileInputStream(textFile), charset));
                for (String line; (line = reader.readLine()) != null;) {
                    writer.println(line);
                }
            } finally {
                if (reader != null) try { reader.close(); } catch (IOException logOrIgnore) {}
            }

            // End of multipart/form-data.
            output.write(("\r\n").getBytes());
            output.write(("--" + boundary +"--\r\n").getBytes());
            output.flush();
            writer.close();



         ((HttpURLConnection)connection).getResponseCode();



        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
于 2011-04-05T13:31:58.360 回答
1

我想到了两件事。

  1. 写入器处理字符,流处理字节。您需要知道作者正在使用什么默认字符集,并且它符合您所传递的内容。

  2. 对于多部分 mime 类型,我不确定您上传的文件的内容是否已编码。也许该文件中存在格式错误的内容。

干杯

于 2011-04-07T07:40:44.470 回答