2018년 6월 17일 일요일

analysis http server (JLHTTP) source for upload in android (파일 upload를 위한 웹서버 소스 코드 분석) #2




앞에서 https://swlock.blogspot.com/2018/06/analysis-http-server-jlhttp-source-for.html JLHTTP를 실행시키는 방법에 대해서 알아보았습니다.

최초 이글을 쓰게되는 upload 관련해서 예제가 없어서 확인이 어려웠습니다. 예제는 구하기 어려웠지만 FAQ에서 중요한 단서를 찾았습니다.

아래 내용입니다.
How do I handle uploaded files?
When an HTML form is used to upload a file or other large content, the default application/x-www-form-urlencoded encoding is insufficient. In this case, the form is submitted as a multipart body of a POST request with the multipart/form-data content type instead. The parts are sent in the same order as the form fields.

You can use a MultipartIterator to parse the request body and iterate over its parts. String values can be conveniently retrieved as such, but the file can be read directly as a stream, thus preventing various issues that would arise from holding the entire file contents in memory at once.
Here's a basic example:
String comment;
String filename;
File file;
Iterator<Part> it = new MultipartIterator(request);
while (it.hasNext()) {
    Part part = it.next();
    if ("comment".equals(part.getName())) {
        comment = part.getString()
    } else if ("file".equals(part.getName())) {
        filename = part.getFilename();
        file = File.createTempFile(filename, ".uploaded");
        FileOutputStream out = new FileOutputStream(file);
        try {
            transfer(part.getBody(), out, -1);
        } finally {
            out.close();
        }
    }
}
// now do something with the comment, filename and file
Alternatively, you can use the lower-level MultipartInputStream directly.

그렇지만 어떻게 하는것인지 해당 코드를 어떻게 넣어야 하는것인지 몰라서 만들어 보았습니다.

main 코드에 위 내용을 추가 하여 보았습니다.
아래 예제는 파일을 upload하게되면 temp영역에 파일을 저장하는 내용입니다.

    public static void main(String[] args) {
        try {
            if (args.length == 0) {
                System.err.printf("Usage: java [-options] %s <directory> [port]%n" +
                    "To enable SSL: specify options -Djavax.net.ssl.keyStore, " +
                    "-Djavax.net.ssl.keyStorePassword, etc.%n", HTTPServer.class.getName());
                return;
            }
            File dir = new File(args[0]);
            if (!dir.canRead())
                throw new FileNotFoundException(dir.getAbsolutePath());
            int port = args.length < 2 ? 80 : Integer.parseInt(args[1]);
            // set up server
            for (File f : Arrays.asList(new File("/etc/mime.types"), new File(dir, ".mime.types")))
                if (f.exists())
                    addContentTypes(f);
            HTTPServer server = new HTTPServer(port);
            if (System.getProperty("javax.net.ssl.keyStore") != null) // enable SSL if configured
                server.setServerSocketFactory(SSLServerSocketFactory.getDefault());
            VirtualHost host = server.getVirtualHost(null); // default host
            host.setAllowGeneratedIndex(true); // with directory index pages
            host.addContext("/", new FileContextHandler(dir));
            host.addContext("/api/time", new ContextHandler() {
                public int serve(Request req, Response resp) throws IOException {
                    long now = System.currentTimeMillis();
                    resp.getHeaders().add("Content-Type", "text/plain");
                    resp.send(200, String.format("%tF %<tT", now));
                    return 0;
                }
            });
            host.addContext("/upload", new ContextHandler() {
                public int serve(Request req, Response resp)  {
                 System.out.println("upload");
                 String comment="";
                 String filename="";
                 File file;
                 try {
                  Iterator<MultipartIterator.Part> it = new MultipartIterator(req);
 
                  while (it.hasNext()) {
                   MultipartIterator.Part part = it.next();
                   System.out.println(part.getName());
                      if ("comment".equals(part.getName())) {
                          comment = part.getString();
                      } else if ("file1".equals(part.getName())) {
                          filename = part.getFilename();
                          file = File.createTempFile(filename, ".uploaded");
                          System.out.println(file.getAbsolutePath());
                          FileOutputStream out = new FileOutputStream(file);
                          try {
                              transfer(part.getBody(), out, -1);
                          } finally {
                              out.close();
                          }
                      }
                  }
                 } catch (Exception e ){
                  e.printStackTrace();
                 }
                    resp.getHeaders().add("Content-Type", "text/plain");
                    try {
      resp.send(200, "Hello, World!"+comment+" "+filename);
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
                    return 0;
                }
            },"POST");
            server.start();
            System.out.println("HTTPServer is listening on port " + port);
        } catch (Exception e) {
            System.err.println("error: " + e);
        }

살펴보아햐 하는 부분은 addContext /upload 하는 부분입니다.
host.addContext("/upload", new ContextHandler() {

제작자는 이것을 context handler 라고 부르며, http로 path 요청이 들어오면 그것을 처리하기 위한 context 라고 보면 됩니다.

html 페이지도 준비하였습니다. 이때 form의 action 부분을 "upload"로 한 이유는 context 처리 페이지가 upload이기 때문에 맞추어 주어야 합니다. 그리고 form은 다음과 같이 값을 맞추어야 합니다. method="POST" enctype="multipart/form-data"

index.html
<html>
<body>
<form action="upload" method="POST" enctype="multipart/form-data" name="">
 <div>
   <label for="file">Choose file to upload</label>
   <input type="file" id="file1" name="file1" >
 </div>
 <div>
   <label for="file">Choose file to upload</label>
   <input type="file" id="file2" name="file2" >
 </div>
 <div>
   <button>Submit</button>
 </div>
</form>
</body>
</html>

JLHTTP를 실행하고 localhost로 접속을 하면 아래와 같이 나옵니다.
(실행방법을 잘 모르겠으면 이전 링크를 참고하세요.)
1.png(임의의 파일)파일을 선택해서 submit 버튼을 누르면 다음과 같이 나옵니다.


HTTP 서버측 로그 화면
HTTPServer is listening on port 8080
upload
file1
C:\Users\xxx\AppData\Local\Temp\1.png3242384259546787045.uploaded
file2


전체 소스 링크 입니다.

소스는 파일 하나로 구성되어 있어 http server의 동작을 이해하는 좋은 참고 소스가 될것이라고 생각됩니다. 참고로 라이센스는 GPL 입니다.







댓글 없음:

댓글 쓰기