hal/src/zutil/net/http/HttpHeaderParser.java

206 lines
7.4 KiB
Java
Raw Normal View History

2016-02-19 20:28:26 +01:00
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 Ziver Koc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package zutil.net.http;
2016-07-07 15:59:25 +02:00
import zutil.StringUtil;
2016-07-13 17:22:11 +02:00
import zutil.io.IOUtil;
import zutil.io.StringInputStream;
2016-02-19 20:28:26 +01:00
import zutil.parser.URLDecoder;
2016-07-16 22:53:56 +02:00
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
2016-02-19 20:28:26 +01:00
import java.util.regex.Pattern;
public class HttpHeaderParser {
2016-07-13 17:22:11 +02:00
private static final String HEADER_COOKIE = "COOKIE";
2016-02-19 20:28:26 +01:00
private static final Pattern PATTERN_COLON = Pattern.compile(":");
private static final Pattern PATTERN_EQUAL = Pattern.compile("=");
private static final Pattern PATTERN_AND = Pattern.compile("&");
2016-07-13 17:22:11 +02:00
private InputStream in;
private boolean readStatusLine;
2016-02-19 20:28:26 +01:00
/**
* Parses the HTTP header information from a stream
*
* @param in is the stream
*/
2016-07-13 17:22:11 +02:00
public HttpHeaderParser(InputStream in){
this.in = in;
this.readStatusLine = true;
2016-02-19 20:28:26 +01:00
}
/**
* Parses the HTTP header information from a String
*
* @param in is the String
*/
public HttpHeaderParser(String in){
2016-07-13 17:22:11 +02:00
this(new StringInputStream(in));
2016-02-19 20:28:26 +01:00
}
public HttpHeader read() throws IOException {
HttpHeader header = new HttpHeader();
2016-07-13 17:22:11 +02:00
String line;
// First line
if (readStatusLine) {
2016-07-14 17:50:39 +02:00
if( (line=IOUtil.readLine(in)) != null && !line.isEmpty() )
parseStatusLine(header, line);
else
return null;
}
// Read header body
2016-07-13 17:22:11 +02:00
while( (line=IOUtil.readLine(in)) != null && !line.isEmpty() ){
parseHeaderLine(header.getHeaderMap(), line);
2016-02-19 20:28:26 +01:00
}
2016-07-13 17:22:11 +02:00
// Post processing
2016-08-08 17:30:58 +02:00
parseCookieValues(header.getCookieMap(), header.getHeader(HEADER_COOKIE));
2016-07-13 17:22:11 +02:00
header.setInputStream(in);
2016-02-19 20:28:26 +01:00
return header;
}
/**
* @param readStatusLine indicates if the stream contains http status lines. (default: true)
*/
public void setReadStatusLine(boolean readStatusLine){
this.readStatusLine = readStatusLine;
}
2016-02-19 20:28:26 +01:00
/**
* Parses the first line of a http request/response and stores the values in a HttpHeader object
*
* @param header the header object where the cookies will be stored.
* @param statusLine the status line String
2016-02-19 20:28:26 +01:00
*/
2016-07-14 17:50:39 +02:00
private static void parseStatusLine(HttpHeader header, String statusLine){
2016-02-19 20:28:26 +01:00
// Server Response
if( statusLine.startsWith("HTTP/") ){
header.setIsRequest(false);
header.setHTTPVersion( Float.parseFloat( statusLine.substring( 5 , 8)));
header.setHTTPCode( Integer.parseInt( statusLine.substring( 9, statusLine.indexOf(' ', 9) )));
2016-02-19 20:28:26 +01:00
}
// Client Request
else if(statusLine.contains("HTTP/")){
header.setIsRequest(true);
header.setRequestType( statusLine.substring(0, statusLine.indexOf(" ")).trim() );
header.setHTTPVersion( Float.parseFloat( statusLine.substring(statusLine.lastIndexOf("HTTP/")+5 , statusLine.length()).trim()));
statusLine = (statusLine.substring(header.getRequestType().length()+1, statusLine.lastIndexOf("HTTP/")));
2016-02-19 20:28:26 +01:00
// parse URL and attributes
int index = statusLine.indexOf('?');
2016-02-19 20:28:26 +01:00
if(index > -1){
header.setRequestURL( statusLine.substring(0, index));
statusLine = statusLine.substring( index+1, statusLine.length());
2016-07-13 17:22:11 +02:00
parseURLParameters(header.getUrlAttributeMap(), statusLine);
2016-02-19 20:28:26 +01:00
}
else{
header.setRequestURL(statusLine);
2016-02-19 20:28:26 +01:00
}
}
}
/**
2016-07-13 17:22:11 +02:00
* Parses a http key value paired header line.
* Note that all header keys will be stored with
* uppercase notation to make them case insensitive.
2016-02-19 20:28:26 +01:00
*
2016-07-13 17:22:11 +02:00
* @param map a map where the header key(Uppercase) and value will be stored.
2016-02-19 20:28:26 +01:00
* @param line is the next line in the header
*/
2016-07-13 17:22:11 +02:00
public static void parseHeaderLine(Map<String,String> map, String line){
2016-02-19 20:28:26 +01:00
String[] data = PATTERN_COLON.split( line, 2 );
2016-07-13 17:22:11 +02:00
map.put(
2016-02-19 20:28:26 +01:00
data[0].trim().toUpperCase(), // Key
(data.length>1 ? data[1] : "").trim()); //Value
}
2016-08-08 17:30:58 +02:00
/**
* Parses a raw cookie header into key and value pairs
*
* @param map the Map where the cookies will be stored.
* @param cookieValue the raw cookie header value String that will be parsed
*/
public static void parseCookieValues(Map<String,String> map, String cookieValue){
parseHeaderValues(map, cookieValue, ";");
}
2016-02-19 20:28:26 +01:00
/**
* Parses a header value string that contains key and value paired data and
* stores them in a HashMap. If a pair only contain a key the the value
* will be set as a empty string.
*
2016-08-08 17:30:58 +02:00
* @param map the Map where key and values will be stored.
* @param headerValue the raw header value String that will be parsed.
* @param delimiter the delimiter that separates key and value pairs (e.g. ';' for Cookies or ',' for Cache-Control)
2016-02-19 20:28:26 +01:00
*/
2016-08-08 17:30:58 +02:00
public static void parseHeaderValues(Map<String,String> map, String headerValue, String delimiter){
if(headerValue != null && !headerValue.isEmpty()){
String[] tmpArr = headerValue.split(delimiter);
for(String cookie : tmpArr){
String[] tmpStr = PATTERN_EQUAL.split(cookie, 2);
map.put(
tmpStr[0].trim(), // Key
StringUtil.trim((tmpStr.length>1 ? tmpStr[1] : "").trim(), '\"')); //Value
2016-02-19 20:28:26 +01:00
}
}
}
2016-07-13 17:22:11 +02:00
2016-02-19 20:28:26 +01:00
/**
* Parses a string with variables from a get or post request that was sent from a client
*
2016-07-13 17:22:11 +02:00
* @param header the header object where the url attributes key and value will be stored.
* @param urlAttributes is the String containing all the attributes
2016-02-19 20:28:26 +01:00
*/
public static void parseURLParameters(HttpHeader header, String urlAttributes){
2016-07-13 17:22:11 +02:00
parseURLParameters(header.getUrlAttributeMap(), urlAttributes);
}
/**
* Parses a string with variables from a get or post request that was sent from a client
*
* @param map a map where the url attributes key and value will be stored.
* @param urlAttributes is the String containing all the attributes
*/
public static void parseURLParameters(Map<String,String> map, String urlAttributes){
2016-02-19 20:28:26 +01:00
String[] tmp;
urlAttributes = URLDecoder.decode(urlAttributes);
2016-02-19 20:28:26 +01:00
// get the variables
String[] data = PATTERN_AND.split( urlAttributes );
2016-02-19 20:28:26 +01:00
for(String element : data){
tmp = PATTERN_EQUAL.split(element, 2);
2016-07-13 17:22:11 +02:00
map.put(
2016-02-19 20:28:26 +01:00
tmp[0].trim(), // Key
(tmp.length>1 ? tmp[1] : "").trim()); //Value
}
}
}