2016-06-23 1 views
0

Java에서 RFC-822 문서를 구문 분석하는 가장 간단한 방법을 찾으려고합니다. HTTP 메시지가 저장된 메시지 대기열이 있다고 가정합니다. 요청과 응답 모두. 그래서 그들은 소켓 연결을 "포트 80"으로 만들고 거기에서 메시지를 보내거나 가져옴으로써 "정상적인"방법으로 검색되지 않습니다.이 예제 HTTP 요청에서 본문을 가져 오는 방법은 무엇입니까?

아래 코드에서 의도적으로 "메일"헤더와 HTTP 메시지가 혼합되었습니다. 이 두 가지가별로 다르지 않다는 것을 증명하는 의미입니다. 그러나 그것은 그 요점입니다. 여기 코드는 다음과 같습니다

package httpexample; 

import java.io.ByteArrayInputStream; 
import java.io.IOException; 
import org.apache.http.Header; 
import org.apache.http.HttpException; 
import org.apache.http.HttpRequest; 
import org.apache.http.impl.io.DefaultHttpRequestParser; 
import org.apache.http.impl.io.HttpTransportMetricsImpl; 
import org.apache.http.impl.io.SessionInputBufferImpl; 
import org.apache.http.io.HttpMessageParser; 
import org.apache.http.message.BasicHttpEntityEnclosingRequest; 

public class HttpExample { 

    // RFC 822 

    public static void main(String[] args) throws IOException, HttpException { 
     String str = "POST http://localhost:8080/foobar/1234567 HTTP/1.1\n" + 
      "Message-ID: <[email protected]>\n" + 
      "Date: Wed, 6 Mar 2010 12:32:20 -0800 (PST)\n" + 
      "From: [email protected]\n" + 
      "To: [email protected]\n" + 
      "Subject: some subject\n" + 
      "Mime-Version: 1.0\n" + 
      "Content-Type: text/plain; charset=us-ascii\n" + 
      "Content-Transfer-Encoding: 7bit\n" + 
      "X-From: one, some <[email protected]>\n" + 
      "X-To: one\n" + 
      "X-cc: \n" + 
      "X-bcc: \n" + 
      "X-Origin: Bob-R\n" + 
      "X-FileName: rbob (Non-Privileged).pst\n" + 
      "\n" + 
      "some message\n"; 
     ByteArrayInputStream fakeStream = new ByteArrayInputStream(
       str.getBytes()); 
     HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl(); 
     SessionInputBufferImpl inbuffer = new SessionInputBufferImpl(metrics, 1024); 

     inbuffer.bind(fakeStream); 
     HttpMessageParser<HttpRequest> requestParser = 
       new DefaultHttpRequestParser(inbuffer); 
     BasicHttpEntityEnclosingRequest request = (BasicHttpEntityEnclosingRequest)requestParser.parse(); 

     for (Header hdr : request.getAllHeaders()) { 
      System.out.println(String.format("%-30s = %s", hdr.getName(), hdr.getValue())); 
     } 
     System.out.println(String.format("Request Line: %s", request.getRequestLine())); 
     System.out.println(String.format("Body\n------------------\n%s", 
       request.getEntity())); 
    } 

} 

출력은 다음과 같습니다 : 나는 알아낼 수 없습니다 무엇

Message-ID      = <[email protected]> 
Date       = Wed, 6 Mar 2010 12:32:20 -0800 (PST) 
From       = [email protected] 
To        = [email protected] 
Subject      = some subject 
Mime-Version     = 1.0 
Content-Type     = text/plain; charset=us-ascii 
Content-Transfer-Encoding  = 7bit 
X-From       = one, some <[email protected]> 
X-To       = one 
X-cc       = 
X-bcc       = 
X-Origin      = Bob-R 
X-FileName      = rbob (Non-Privileged).pst 
Request Line: POST http://localhost:8080/foobar/1234567 HTTP/1.1 
Body 
------------------ 
null 

는 메시지의 에 액세스하는 방법입니다.

나는 내용 some message\n

나는 나에게이 값을 줄 것 BasicHttpEntityEnclosingRequest의 모든 방법을 찾을 수있을 것으로 예상한다. 이전 버전 I는 즉 getEntity 방법이 있기 때문에이 I BasicHttpEntityEnclosingRequest로 변경

HttpRequest request = requestParser.parse(); 

대신

BasicHttpEntityEnclosingRequest request = 
    (BasicHttpEntityEnclosingRequest) requestParser.parse(); 

사용. 하지만 그 값은 null입니다.

그래서 나는 조금 길다.

어디에서 시체를 찾을 수 있습니까?

답변

1

나는 그렇지 않으면 파서는 단순히 POST 본문을 무시 콘텐츠 길이 헤더를 추가했습니다. 나는 지금은 잘 몸을 구문 분석, 코드를 수정했습니다 :

package org.apache.http.examples; 

import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.net.Socket; 

import org.apache.http.Header; 
import org.apache.http.HttpException; 
import org.apache.http.message.BasicHttpEntityEnclosingRequest; 
import org.apache.http.util.EntityUtils; 

public class HttpExample { 

    // RFC 822 

    public static void main(String[] args) throws IOException, HttpException { 
     String str = "POST http://localhost:8080/foobar/1234567 HTTP/1.1\n" + 
      "Message-ID: <[email protected]>\n" + 
      "Date: Wed, 6 Mar 2010 12:32:20 -0800 (PST)\n" + 
      "From: [email protected]\n" + 
      "To: [email protected]\n" + 
      "Subject: some subject\n" + 
      "Mime-Version: 1.0\n" + 
      "Content-Type: text/plain; charset=us-ascii\n" + 
      "Content-Transfer-Encoding: 7bit\n" + 
      "X-From: one, some <[email protected]>\n" + 
      "X-To: one\n" + 
      "X-cc: \n" + 
      "X-bcc: \n" + 
      "X-Origin: Bob-R\n" + 
      "X-FileName: rbob (Non-Privileged).pst\n" + 
      "Content-Length: 13\n" + 
      "\n" + 
      "some message\n"; 
     ByteArrayInputStream fakeStream = new ByteArrayInputStream(
       str.getBytes()); 

     BHttpConnectionBaseImpl b = new BHttpConnectionBaseImpl(fakeStream); 

     BasicHttpEntityEnclosingRequest request1 = (BasicHttpEntityEnclosingRequest) b.receiveRequestHeader(); 
     b.receiveRequestEntity(request1); 


     for (Header hdr : request1.getAllHeaders()) { 
      System.out.println(String.format("%-30s = %s", hdr.getName(), hdr.getValue())); 
     } 
     System.out.println(String.format("Request Line: %s", request1.getRequestLine())); 
     System.out.println(String.format("Body\n------------------\n%s", 
       EntityUtils.toString(request1.getEntity()))); 
    } 

} 

class BHttpConnectionBaseImpl extends org.apache.http.impl.DefaultBHttpServerConnection{ 

    private InputStream inputStream; 

    public BHttpConnectionBaseImpl(final InputStream inputStream) { 
     super(4048); 
     this.inputStream = inputStream; 
     try { 
      super.bind(new Socket()); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    @Override 
    protected InputStream getSocketInputStream(final Socket socket) throws IOException { 
     return inputStream; 
    } 

    @Override 
    protected OutputStream getSocketOutputStream(final Socket socket) throws IOException { 
     return new ByteArrayOutputStream(); 
    } 
} 

POST 본문의 구문 분석 유일한 생성자 보호하고 매개 변수를 많이 필요로 누구든지 org.apache.http.impl.BHttpConnectionBase.prepareInput(HttpMessage)에 발생합니다. 자식 org.apache.http.impl.DefaultBHttpServerConnection에는 편리한 public 생성자가 있고 헤더 구문 분석은 receiveRequestHeader()입니다. 오버로딩하는 메소드는 몇 가지 오류 검사를 우회해야합니다. 나는 그것을 테스트하지 않았습니다 있지만 Socket == null하고는 fakeStream

에서 작업 수도 또 다른 방법을 요청을 읽을 수 있도록하면, Socket를 대체 특히 그 getInputStream()getOutputStream(). 그런 다음 DefaultBHttpServerConnection의 인스턴스를 만들고 bind 메서드를 호출합니다. 나머지는 동일해야합니다.

+0

나는 정답을 'Content-Length'와'DefaultBHttpServerConnection'에 필수적으로 줄여므로 정답이라고 생각합니다. 'Transfer-Encoding'이나'.getBytes()'도 잘못되었습니다. 'DefaultBHttpServerConnection'에 대해 약간의 메모를 추가하고 그것이 필요한 이유가 무엇입니까? – exhuma

0

나는 메시지 헤더에서 몸의 길이가 명확하지 않으므로 수신자가 무시하는 것이 문제라고 생각합니다. HTTP specification이 정보를 전달하는 방법에 대한 몇 가지 옵션을 정의하고 그들 중 누구도 여기에 적용 할 것 같다 :

  1. Content-Transfer-EncodingTransfer-Encoding
  2. 7bitthe standard options 있지 않기해야합니다.
  3. str.getBytes()을 사용하면 us-asciiContent-Type으로 선언되지 않은 UTF-16 바이트를 제공합니다.

그래서, 귀하의 요청 약간 변경됩니다 :

  1. 사용 헤더 Content-Type: text/plain; charset=UTF-16
  2. 제거 헤더를 Content-Transfer-Encoding
  3. 추가 Content-Lenght: 28 (28 인 "some message\n".getBytes().length()).