Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
// Copyright (c) 2003-present, Jodd Team (http://jodd.org)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
package jodd.http;
import jodd.datetime.TimeUtil;
import jodd.http.up.ByteArrayUploadable;
import jodd.http.up.FileUploadable;
import jodd.http.up.Uploadable;
import jodd.io.FastCharArrayWriter;
import jodd.io.FileNameUtil;
import jodd.io.StreamUtil;
import jodd.upload.FileUpload;
import jodd.upload.MultipartStreamParser;
import jodd.util.MimeTypes;
import jodd.util.RandomString;
import jodd.util.StringPool;
import jodd.util.StringUtil;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;
import static jodd.util.StringPool.CRLF;
/**
* Base class for {@link HttpRequest} and {@link HttpResponse}.
*/
@SuppressWarnings("unchecked")
public abstract class HttpBase {
public static final String HEADER_ACCEPT = "Accept";
public static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
public static final String HEADER_CONTENT_TYPE = "Content-Type";
public static final String HEADER_CONTENT_LENGTH = "Content-Length";
public static final String HEADER_CONTENT_ENCODING = "Content-Encoding";
public static final String HEADER_HOST = "Host";
public static final String HEADER_ETAG = "ETag";
public static final String HEADER_CONNECTION = "Connection";
public static final String HEADER_KEEP_ALIVE = "Keep-Alive";
public static final String HEADER_CLOSE = "Close";
public static final String HTTP_1_0 = "HTTP/1.0";
public static final String HTTP_1_1 = "HTTP/1.1";
protected String httpVersion = HTTP_1_1;
protected HttpMultiMap headers = HttpMultiMap.newCaseInsensitveMap();
protected HttpMultiMap> form; // holds form data (when used)
protected String body; // holds raw body string (always)
// ---------------------------------------------------------------- properties
/**
* Returns HTTP version string. By default it's "HTTP/1.1".
*/
public String httpVersion() {
return httpVersion;
}
/**
* Sets the HTTP version string. Must be formed like "HTTP/1.1".
*/
public T httpVersion(String httpVersion) {
this.httpVersion = httpVersion;
return (T) this;
}
// ---------------------------------------------------------------- headers
/**
* Returns value of header parameter.
* If multiple headers with the same names exist,
* the first value will be returned. Returns null
* if header doesn't exist.
*/
public String header(String name) {
return headers.get(name);
}
/**
* Returns all values for given header name.
*/
public List headers(String name) {
return headers.getAll(name);
}
/**
* Removes all header parameters for given name.
*/
public void removeHeader(String name) {
String key = name.trim().toLowerCase();
headers.remove(key);
}
/**
* Adds header parameter. If a header with the same name exist,
* it will not be overwritten, but the new header with the same
* name is going to be added.
* The order of header parameters is preserved.
* Also detects 'Content-Type' header and extracts
* {@link #mediaType() media type} and {@link #charset() charset}
* values.
*/
public T header(String name, String value) {
return header(name, value, false);
}
/**
* Adds or sets header parameter.
* @see #header(String, String)
*/
public T header(String name, String value, boolean overwrite) {
String key = name.trim().toLowerCase();
value = value.trim();
if (key.equalsIgnoreCase(HEADER_CONTENT_TYPE)) {
mediaType = HttpUtil.extractMediaType(value);
charset = HttpUtil.extractContentTypeCharset(value);
}
if (overwrite) {
headers.set(key, value);
} else {
headers.add(key, value);
}
return (T) this;
}
/**
* Internal direct header setting.
*/
protected void _header(String name, String value, boolean overwrite) {
String key = name.trim().toLowerCase();
value = value.trim();
if (overwrite) {
headers.set(key, value);
} else {
headers.add(key, value);
}
}
/**
* Adds int value as header parameter,
* @see #header(String, String)
*/
public T header(String name, int value) {
_header(name, String.valueOf(value), false);
return (T) this;
}
/**
* Adds date value as header parameter.
* @see #header(String, String)
*/
public T header(String name, long millis) {
_header(name, TimeUtil.formatHttpDate(millis), false);
return (T) this;
}
/**
* Returns {@link HttpMultiMap} of all headers.
*/
public HttpMultiMap headers() {
return headers;
}
// ---------------------------------------------------------------- content type
protected String charset;
/**
* Returns charset, as defined by 'Content-Type' header.
* If not set, returns null - indicating
* the default charset (ISO-8859-1).
*/
public String charset() {
return charset;
}
/**
* Defines just content type charset. Setting this value to
* null will remove the charset information from
* the header.
*/
public T charset(String charset) {
this.charset = null;
contentType(null, charset);
return (T) this;
}
protected String mediaType;
/**
* Returns media type, as defined by 'Content-Type' header.
* If not set, returns null - indicating
* the default media type, depending on request/response.
*/
public String mediaType() {
return mediaType;
}
/**
* Defines just content media type.
* Setting this value to null will
* not have any effects.
*/
public T mediaType(String mediaType) {
contentType(mediaType, null);
return (T) this;
}
/**
* Returns full "Content-Type" header.
* It consists of {@link #mediaType() media type}
* and {@link #charset() charset}.
*/
public String contentType() {
return header(HEADER_CONTENT_TYPE);
}
/**
* Sets full "Content-Type" header. Both {@link #mediaType() media type}
* and {@link #charset() charset} are overridden.
*/
public T contentType(String contentType) {
header(HEADER_CONTENT_TYPE, contentType, true);
return (T) this;
}
/**
* Sets "Content-Type" header by defining media-type and/or charset parameter.
* This method may be used to update media-type and/or charset by passing
* non-null value for changes.
*
* Important: if Content-Type header has some other parameters, they will be removed!
*/
public T contentType(String mediaType, String charset) {
if (mediaType == null) {
mediaType = this.mediaType;
} else {
this.mediaType = mediaType;
}
if (charset == null) {
charset = this.charset;
} else {
this.charset = charset;
}
String contentType = mediaType;
if (charset != null) {
contentType += ";charset=" + charset;
}
_header(HEADER_CONTENT_TYPE, contentType, true);
return (T) this;
}
// ---------------------------------------------------------------- keep-alive
/**
* Defines "Connection" header as "Keep-Alive" or "Close".
* Existing value is overwritten.
*/
public T connectionKeepAlive(boolean keepAlive) {
if (keepAlive) {
header(HEADER_CONNECTION, HEADER_KEEP_ALIVE, true);
} else {
header(HEADER_CONNECTION, HEADER_CLOSE, true);
}
return (T) this;
}
/**
* Returns true if connection is persistent.
* If "Connection" header does not exist, returns true
* for HTTP 1.1 and false for HTTP 1.0. If
* "Connection" header exist, checks if it is equal to "Close".
*
* In HTTP 1.1, all connections are considered persistent unless declared otherwise.
* Under HTTP 1.0, there is no official specification for how keepalive operates.
*/
public boolean isConnectionPersistent() {
String connection = header(HEADER_CONNECTION);
if (connection == null) {
return !httpVersion.equalsIgnoreCase(HTTP_1_0);
}
return !connection.equalsIgnoreCase(HEADER_CLOSE);
}
// ---------------------------------------------------------------- common headers
/**
* Returns full "Content-Length" header or
* null if not set.
*/
public String contentLength() {
return header(HEADER_CONTENT_LENGTH);
}
/**
* Sets the full "Content-Length" header.
*/
public T contentLength(int value) {
_header(HEADER_CONTENT_LENGTH, String.valueOf(value), true);
return (T) this;
}
/**
* Returns "Content-Encoding" header.
*/
public String contentEncoding() {
return header(HEADER_CONTENT_ENCODING);
}
/**
* Returns "Accept" header.
*/
public String accept() {
return header(HEADER_ACCEPT);
}
/**
* Sets "Accept" header.
*/
public T accept(String encodings) {
header(HEADER_ACCEPT, encodings, true);
return (T) this;
}
/**
* Returns "Accept-Encoding" header.
*/
public String acceptEncoding() {
return header(HEADER_ACCEPT_ENCODING);
}
/**
* Sets "Accept-Encoding" header.
*/
public T acceptEncoding(String encodings) {
header(HEADER_ACCEPT_ENCODING, encodings, true);
return (T) this;
}
// ---------------------------------------------------------------- form
/**
* Initializes form.
*/
protected void initForm() {
if (form == null) {
form = HttpMultiMap.newCaseInsensitveMap();
}
}
/**
* Wraps non-Strings form values with {@link jodd.http.up.Uploadable uploadable content}.
* Detects invalid types and throws an exception. So all uploadable values
* are of the same type.
*/
protected Object wrapFormValue(Object value) {
if (value == null) {
return null;
}
if (value instanceof CharSequence) {
return value.toString();
}
if (value instanceof Number) {
return value.toString();
}
if (value instanceof Boolean) {
return value.toString();
}
if (value instanceof File) {
return new FileUploadable((File) value);
}
if (value instanceof byte[]) {
return new ByteArrayUploadable((byte[]) value, null);
}
if (value instanceof Uploadable) {
return value;
}
throw new HttpException("Unsupported value type: " + value.getClass().getName());
}
/**
* Adds the form parameter. Existing parameter will not be overwritten.
*/
public T form(String name, Object value) {
initForm();
value = wrapFormValue(value);
((HttpMultiMap