📄 httpinputstreamreader.java
字号:
package wjhk.jupload2.upload.helper;
import java.io.IOException;
import java.io.PushbackInputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.net.ssl.SSLSocket;
import wjhk.jupload2.exception.JUploadException;
import wjhk.jupload2.policies.UploadPolicy;
/**
* A helper, to read the response coming from the server.
*
* @author etienne_sf
*/
public class HTTPInputStreamReader {
// //////////////////////////////////////////////////////////////////////////////
// //////////////////// Main attributes
// //////////////////////////////////////////////////////////////////////////////
/**
* The current upload policy, always useful.
*/
private UploadPolicy uploadPolicy = null;
private HTTPConnectionHelper httpConnectionHelper = null;
/**
* Contains the HTTP response body, that is: the server response, without
* the headers.
*/
String responseBody = null;
/**
* The headers of the HTTP response.
*/
String responseHeaders = null;
/**
* The status message from the first line of the response (e.g. "200 OK").
*/
String responseMsg = null;
// ////////////////////////////////////////////////////////////////////////////////////
// /////////////////// ATTRIBUTE CONTAINING DATA COMING FROM THE RESPONSE
// ////////////////////////////////////////////////////////////////////////////////////
private CookieJar cookies = new CookieJar();
boolean gotClose = false;
private boolean gotChunked = false;
private boolean gotContentLength = false;
private int clen = 0;
/**
* The server HTTP response. Should be 200, in case of success.
*/
private int httpStatusCode = 0;
private String line = "";
private byte[] body = new byte[0];
private String charset = "ISO-8859-1";
// ////////////////////////////////////////////////////////////////////////////////////
// /////////////////// CONSTANTS USED TO CONTROL THE HTTP INTPUT
// ////////////////////////////////////////////////////////////////////////////////////
private final static int CHUNKBUF_SIZE = 4096;
private final byte chunkbuf[] = new byte[CHUNKBUF_SIZE];
private final static Pattern pChunked = Pattern.compile(
"^Transfer-Encoding:\\s+chunked", Pattern.CASE_INSENSITIVE);
private final static Pattern pClose = Pattern.compile(
"^Connection:\\s+close", Pattern.CASE_INSENSITIVE);
private final static Pattern pProxyClose = Pattern.compile(
"^Proxy-Connection:\\s+close", Pattern.CASE_INSENSITIVE);
private final static Pattern pHttpStatus = Pattern
.compile("^HTTP/\\d\\.\\d\\s+((\\d+)\\s+.*)$");
private final static Pattern pContentLen = Pattern.compile(
"^Content-Length:\\s+(\\d+)$", Pattern.CASE_INSENSITIVE);
private final static Pattern pContentTypeCs = Pattern.compile(
"^Content-Type:\\s+.*;\\s*charset=([^;\\s]+).*$",
Pattern.CASE_INSENSITIVE);
private final static Pattern pSetCookie = Pattern.compile(
"^Set-Cookie:\\s+(.*)$", Pattern.CASE_INSENSITIVE);
/**
* The standard constructor: does nothing ! Oh yes, it initialize some
* attribute from the given parameter... :-)
*
* @param httpConnectionHelper The connection helper, associated with this
* instance.
* @param uploadPolicy The current upload policy.
*/
public HTTPInputStreamReader(HTTPConnectionHelper httpConnectionHelper,
UploadPolicy uploadPolicy) {
this.httpConnectionHelper = httpConnectionHelper;
this.uploadPolicy = uploadPolicy;
}
/**
* Return the last read http response (200, in case of success).
*
* @return The last read http response
*/
public int gethttpStatusCode() {
return this.httpStatusCode;
}
/**
* Get the last response body.
*
* @return The last read response body.
*/
public String getResponseBody() {
return this.responseBody;
}
/**
* Get the headers of the HTTP response.
*
* @return The HTTP headers.
*/
public String getResponseHeaders() {
return this.responseHeaders;
}
/**
* Get the last response message.
*
* @return The response message from the first line of the response (e.g.
* "200 OK").
*/
public String getResponseMsg() {
return this.responseMsg;
}
/**
* The main method: reads the response in the input stream.
*
* @return The response status (e.g.: 200 if everything was ok)
* @throws JUploadException
*/
public int readHttpResponse() throws JUploadException {
PushbackInputStream httpDataIn = this.httpConnectionHelper
.getInputStream();
try {
// If the user requested abort, we are not going to send
// anymore, so shutdown the outgoing half of the socket.
// This helps the server to speed up with it's response.
if (this.httpConnectionHelper.gotStopped()
&& !(this.httpConnectionHelper.getSocket() instanceof SSLSocket))
this.httpConnectionHelper.getSocket().shutdownOutput();
// We first read the headers,
readHeaders(httpDataIn);
// then the body.
// If we're in a HEAD request ... we're not interested in the body!
if (this.httpConnectionHelper.getMethod().equals("HEAD")) {
this.uploadPolicy.displayDebug(
"This is a HEAD request: we don't care about the body",
70);
this.responseBody = "";
} else {
readBody(httpDataIn);
}
} catch (Exception e) {
throw new JUploadException(e);
}
return this.httpStatusCode;
}
// //////////////////////////////////////////////////////////////////////////////////////
// //////////////////// Various utilities
// //////////////////////////////////////////////////////////////////////////////////////
/**
* Concatenates two byte arrays.
*
* @param buf1 The first array
* @param buf2 The second array
* @return A byte array, containing buf2 appended to buf2
*/
static byte[] byteAppend(byte[] buf1, byte[] buf2) {
byte[] ret = new byte[buf1.length + buf2.length];
System.arraycopy(buf1, 0, ret, 0, buf1.length);
System.arraycopy(buf2, 0, ret, buf1.length, buf2.length);
return ret;
}
/**
* Concatenates two byte arrays.
*
* @param buf1 The first array
* @param buf2 The second array
* @param len Number of bytes to copy from buf2
* @return A byte array, containing buf2 appended to buf2
*/
static byte[] byteAppend(byte[] buf1, byte[] buf2, int len) {
if (len > buf2.length)
len = buf2.length;
byte[] ret = new byte[buf1.length + len];
System.arraycopy(buf1, 0, ret, 0, buf1.length);
System.arraycopy(buf2, 0, ret, buf1.length, len);
return ret;
}
/**
* Similar like BufferedInputStream#readLine() but operates on raw bytes.
* Line-Ending is <b>always</b> "\r\n".
*
* @param inputStream
*
* @param charset The input charset of the stream.
* @param includeCR Set to true, if the terminating CR/LF should be included
* in the returned byte array.
* @return The line, encoded from the input stream with the given charset
* @throws IOException
*/
public static String readLine(PushbackInputStream inputStream,
String charset, boolean includeCR) throws IOException {
byte[] line = readLine(inputStream, includeCR);
return (null == line) ? null : new String(line, charset);
}
/**
* Similar like BufferedInputStream#readLine() but operates on raw bytes.
* According to RFC 2616, and of line may be CR (13), LF (10) or CRLF.
* Line-Ending is <b>always</b> "\r\n" in header, but not in text bodies.
* Update done by TedA (sourceforge account: tedaaa). Allows to manage
* response from web server that send LF instead of CRLF ! Here is a part of
* the RFC: <I>"we recommend that applications, when parsing such headers,
* recognize a single LF as a line terminator and ignore the leading
* CR"</I>. <BR>
* Corrected again to manage line finished by CR only. This is not allowed
* in headers, but this method is also used to read lines in the body.
*
* @param inputStream
*
* @param includeCR Set to true, if the terminating CR/LF should be included
* in the returned byte array. In this case, CR/LF is always
* returned to the caller, whether the input stream got CR, LF or
* CRLF.
* @return The byte array from the input stream, with or without a trailing
* CRLF
* @throws IOException
*/
public static byte[] readLine(PushbackInputStream inputStream,
boolean includeCR) throws IOException {
final byte EOS = -1;
final byte CR = 13;
final byte LF = 10;
int len = 0;
int buflen = 128; // average line length
byte[] buf = new byte[buflen];
byte[] ret = null;
int b;
boolean lineRead = false;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -