package org.wiztools.restclient.util;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.wiztools.commons.Charsets;
import org.wiztools.commons.MultiValueMap;
import org.wiztools.commons.StringUtil;
import org.wiztools.restclient.bean.ContentType;
import org.wiztools.restclient.bean.ContentTypeBean;
import org.wiztools.restclient.bean.HTTPMethod;
/**
*
* @author subwiz
*/
public final class HttpUtil {
public static final ContentType DEFAULT_CONTENT_TYPE = new ContentTypeBean("text/plain", Charsets.UTF_8);
public static final Charset DEFAULT_CHARSET = Charsets.UTF_8;
public static ContentType getContentType(String header) {
final String[] arr = header.split("\\s*;\\s*");
if(arr.length == 1) {
return new ContentTypeBean(header, null);
}
else {
final String contentType = arr[0];
for(int i=1; i<arr.length; i++) {
final String headerPart = arr[i];
if(headerPart.contains("charset=")) {
Pattern p = Pattern.compile("charset=(.+)");
Matcher m = p.matcher(headerPart);
if(m.matches()) {
Charset charset = Charset.forName(m.group(1));
return new ContentTypeBean(contentType, charset);
}
}
}
return new ContentTypeBean(contentType, null);
}
}
public static ContentType getContentType(MultiValueMap<String, String> headers) {
for(String key: headers.keySet()) {
if("content-type".equalsIgnoreCase(key.trim())) {
return getContentType(headers.get(key).iterator().next());
}
}
return null;
}
/**
* Parses the HTTP response status line, and returns the status code.
* @param statusLine The HTTP status line.
* @return The status code from HTTP response status line.
*/
public static int getStatusCodeFromStatusLine(final String statusLine){
int retVal = -1;
final String STATUS_PATTERN = "[^\\s]+\\s([0-9]{3})\\s.*";
Pattern p = Pattern.compile(STATUS_PATTERN);
Matcher m = p.matcher(statusLine);
if(m.matches()){
retVal = Integer.parseInt(m.group(1));
}
return retVal;
}
/**
* Method formats content-type and charset for use as HTTP header value
* @param contentType The content type string.
* @param charset The charset string.
* @return The formatted content-type and charset.
*/
public static String getFormattedContentType(final String contentType, final String charset){
String charsetFormatted = StringUtil.isEmpty(charset)? "": "; charset=" + charset;
return contentType + charsetFormatted;
}
public static String getFormattedContentType(final String contentType, final Charset charset){
return getFormattedContentType(contentType, (charset!=null? charset.name(): null));
}
public static String getFormattedContentType(final ContentType contentType){
return getFormattedContentType(contentType.getContentType(), contentType.getCharset());
}
public static String getCharsetFromContentType(final String contentType) {
Pattern p = Pattern.compile("^.+charset=([^;]+).*$");
Matcher m = p.matcher(contentType);
if(m.matches()) {
return m.group(1).trim();
}
return null;
}
/**
* Parses the Content-Type HTTP header and returns the MIME type part of the
* response. For example, when receiving Content-Type header like:
*
* application/xml;charset=UTF-8
*
* This method will return "application/xml".
* @param contentType The content-type string.
* @return The mime part of the content-type string.
*/
public static String getMimeFromContentType(final String contentType) {
final int occurance = contentType.indexOf(';');
if(occurance == -1) {
return contentType;
}
else {
return contentType.substring(0, occurance);
}
}
private static String getContentTypeBeforeSemiColon(String contentType) {
return (contentType.indexOf(';') != -1)?
contentType.split(";")[0]:
contentType;
}
public static boolean isWebImageContentType(final String contentType) {
final String ct = getContentTypeBeforeSemiColon(contentType);
return ct.equals("image/jpeg")
|| ct.equals("image/png")
|| ct.equals("image/gif");
}
// All text content that needs to be rendered as text except those
// starting with `text/`:
private static List<String> TEXT_CT = Arrays.asList(new String[]{
"application/x-javascript", "application/javascript"
});
public static boolean isTextContentType(final String contentType) {
final String ct = getContentTypeBeforeSemiColon(contentType);
return ct.startsWith("text/")
|| isXmlContentType(ct)
|| isJsonContentType(ct)
|| TEXT_CT.contains(ct);
}
public static boolean isXmlContentType(final String contentType) {
final String ct = getContentTypeBeforeSemiColon(contentType);
return ct.startsWith("application/xml")
|| ct.startsWith("text/xml")
|| ct.endsWith("+xml");
}
public static boolean isJsonContentType(final String contentType) {
final String ct = getContentTypeBeforeSemiColon(contentType);
return ct.startsWith("application/json")
|| ct.endsWith("+json");
}
public static boolean isJsContentType(final String contentType) {
final String ct = getContentTypeBeforeSemiColon(contentType);
return ct.startsWith("application/javascript")
|| ct.startsWith("application/x-javascript")
|| ct.startsWith("text/javascript");
}
public static boolean isCssContentType(final String contentType) {
final String ct = getContentTypeBeforeSemiColon(contentType);
return ct.startsWith("text/css");
}
public static boolean isHTMLContentType(final String contentType) {
final String ct = getContentTypeBeforeSemiColon(contentType);
return ct.startsWith("text/html")
|| ct.endsWith("+html");
}
public static Charset getCharsetDefault(final ContentType type) {
return type != null?
(type.getCharset() != null? type.getCharset(): DEFAULT_CHARSET)
: DEFAULT_CHARSET;
}
private static final List<String> entityEnclosingMethods =
Collections.unmodifiableList(
Arrays.asList(new String[]{"GET", "POST", "PUT", "PATCH", "DELETE"}));
public static boolean isEntityEnclosingMethod(final String method) {
return entityEnclosingMethods.contains(method);
}
public static boolean isEntityEnclosingMethod(final HTTPMethod method) {
return isEntityEnclosingMethod(method.name());
}
}