org.xsocket.connection.http.RequestHeader Maven / Gradle / Ivy
/*
* Copyright (c) xsocket.org, 2006 - 2008. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Please refer to the LGPL license at: http://www.gnu.org/copyleft/lesser.txt
* The latest copy of this software may be found on http://www.xsocket.org/
*/
package org.xsocket.connection.http;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.xsocket.DataConverter;
import org.xsocket.IDataSink;
import org.xsocket.connection.IConnection;
import org.xsocket.connection.INonBlockingConnection;
/**
* http request header representation
*
* @author [email protected]
*/
public final class RequestHeader extends AbstractMessageHeader {
private Logger LOG = Logger.getLogger(RequestHeader.class.getName());
private static final String HOST = "Host";
private ByteBuffer[] rawHeader = null;
private IConnection connection = null;
private Boolean isSecure = null;
private String method = null;
private String hostname = null;
private Integer port = null;
private String requestUri = null;
private String path = null;
private String query = null;
private String protocol = null;
private String scheme = null;
private String schemeVersion = "1.1";
private Map parameterMap = null;
private boolean isParametersModified = false;
private boolean isFirstLineModified = false;
// performance optimization
private String userAgent = null;
private String host = null;
/**
* constructor
*
* @param uri the uri
*/
public RequestHeader(String uri) {
this(null, uri);
}
/**
* constructor
*
* @param method the method
* @param uri the uri
*/
public RequestHeader(String method, String uri) {
this(method, uri, null, "1.1");
}
/**
* constructor
*
* @param method the method
* @param uri the uri
* @param contentType the content type
*/
public RequestHeader(String method, String uri, String contentType) {
this(method, uri, contentType, "1.1");
}
private RequestHeader(String method, String uri, String contentType, String schemeVersion) {
try {
this.method = method;
this.schemeVersion = schemeVersion;
if (contentType != null) {
setContentType(contentType);
}
URI u = new URI(uri);
scheme = u.getScheme();
path = u.getRawPath();
query = u.getRawQuery();
hostname = u.getHost();
port = u.getPort();
scheme = u.getScheme();
if (scheme != null) {
if (!scheme.equalsIgnoreCase("http") && !scheme.equalsIgnoreCase("https")) {
throw new RuntimeException("unsupported protocol " + scheme);
}
if (port == -1) {
if (scheme.equalsIgnoreCase("http")) {
port = 80;
} else if (scheme.equalsIgnoreCase("https")) {
port = 443;
}
}
}
if (scheme != null) {
protocol = scheme + "/" + schemeVersion;
}
if (hostname != null) {
setHost(hostname + ":" + port);
}
} catch (URISyntaxException se) {
throw new RuntimeException("could not resolve url " + uri + " " + se.toString());
}
}
/**
* constructor
*
* @param rawHeader the raw header
* @param connection the underlying connection
*/
RequestHeader(ByteBuffer[] rawHeader, IConnection connection) {
this.rawHeader = rawHeader;
this.connection = connection;
try {
String header = DataConverter.toString(rawHeader, "ISO-8859-1");
String[] headerlines = header.split("\r\n");
// unfolding lines if necessary
headerlines = unfoldingHeaderlines(headerlines);
for (String line : headerlines) {
if (line.length() == 0) {
LOG.warning("got request header with empty line:\r\n" + header);
continue;
}
// read first line
if (method == null) {
// get method
String[] parts = line.split(" ");
method = parts[0];
// full request?
if (parts.length > 1) {
// get pathAndQuery
requestUri = parts[1];
// get protocol
if (parts.length > 2) {
protocol = parts[2];
} else {
scheme = "HTTP";
protocol = scheme + "/1.0";
}
}
// read the remaining
} else {
addHeaderLineSilence(line);
}
}
} catch (UnsupportedEncodingException use) {
throw new RuntimeException(use.toString());
}
}
/**
* {@inheritDoc}
*/
@Override
void onHeaderAdded(String upperHeadername, String headervalue) {
super.onHeaderAdded(upperHeadername, headervalue);
if (upperHeadername.equals("USER-AGENT")) {
userAgent = headervalue;
} else if (upperHeadername.equals("HOST")) {
host = headervalue;;
}
}
/**
* {@inheritDoc}
*/
@Override
void onHeaderRemoved(String upperHeadername) {
super.onHeaderRemoved(upperHeadername);
if (upperHeadername.equals("USER-AGENT")) {
userAgent = null;
} else if (upperHeadername.equals("HOST")) {
host = null;
}
}
/**
* copy the headers
*
* @param otherHeader the other request header
* @param upperExcludenames the header names to exclude
*/
public void copyHeaderFrom(RequestHeader otherHeader, String... upperExcludenames) {
super.copyHeaderFrom(otherHeader, upperExcludenames);
}
/**
* returns the user agent header
* @return
*/
public String getUserAgent() {
return userAgent;
}
/**
* sets the user agent header
*
* @param userAgent the user agent header
*/
public void setUserAgent(String userAgent) {
setHeader(USER_AGENT, userAgent);
}
/**
* sets the host header
*
* @param host the host header
*/
public void setHost(String host) {
setHeader(HOST, host);
this.host = host;
int pos = host.lastIndexOf(":");
hostname = host.substring(0, pos);
port = Integer.parseInt(host.substring(pos + 1 , host.length()));
}
/**
* returns the host header
*
* @return the host header
*/
public String getHost() {
return host;
}
/**
* sets the remote address (updates the uri)
*
* @param address the remote address
*/
public void setRemoteSocketAddress(InetSocketAddress address) {
this.hostname = address.getHostName();
this.port = address.getPort();
setHost(hostname + ":" + port);
}
/**
* returns the remote host
*
* @return the remote host
*/
public String getRemoteHost() {
if (hostname == null) {
if (connection != null) {
hostname = connection.getLocalAddress().getHostName();
}
}
return hostname;
}
/**
* returns the remote port
*
* @return the remote port
*/
public int getRemotePort() {
if (port == null) {
if (connection != null) {
port = connection.getLocalPort();
} else {
return -1;
}
}
return port;
}
/**
* returns the protocol
*
* @return the protocol
*/
public String getProtocol() {
return protocol;
}
/**
* returns the query string
*
* @return the query string
*/
public String getQueryString() {
splitRequestURI();
return query;
}
/**
* returns the request uri
*
* @return the request uri
*/
public String getRequestURI() {
splitRequestURI();
return path;
}
/**
* returns the full request uri
*
* @return the full request uri
*/
public String getFullRequestURI() {
return requestUri;
}
/**
* returns true if is secured
*
* @return true, if is secured
*/
public boolean isSecure() {
if (isSecure == null) {
if (connection != null) {
isSecure = connection.isSecure();
} else {
isSecure = scheme.equalsIgnoreCase("HTTPS");
}
}
return isSecure;
}
/**
* returns the method
*
* @return the method
*/
public String getMethod() {
return method;
}
/**
* set the method
*
* @param method the method
*/
public void setMethod(String method) {
this.method = method;
isFirstLineModified = true;
}
/**
* returns the scheme
*
* @return the scheme
*/
public String getScheme() {
if (scheme == null) {
if (protocol != null) {
int startPos = protocol.indexOf("/");
if (startPos != -1) {
scheme = protocol.substring(0, startPos);
}
}
}
return scheme;
}
/**
* sets the scheme
*
* @param scheme the scheme
*/
public void setScheme(String scheme) {
this.scheme = scheme;
protocol = scheme + "/" + schemeVersion;
isFirstLineModified = true;
}
private void splitRequestURI() {
if ((path == null) && (requestUri != null)) {
int startPos = requestUri.indexOf("?");
if (startPos != -1) {
path = requestUri.substring(0, startPos);
query = requestUri.substring(startPos + 1, requestUri.length());
} else {
path = requestUri;
}
}
}
/**
* removes a parameter
*
* @param parameterName the parameter name
*/
void removeParameter(String parameterName) {
rawHeader = null;
isParametersModified = true;
getParamMap().remove(parameterName);
}
/**
* sets a parameter
*
* @param parameterName the parameter name
* @param parameterValue the parameter value
*/
public void setParameter(String parameterName, String parameterValue) {
rawHeader = null;
isParametersModified = true;
getParamMap().put(parameterName, new String[] { parameterValue });
}
/**
* returns the parameter map
*
* @return the parameter map
*/
@SuppressWarnings("unchecked")
public final Map getParameterMap() {
return Collections.unmodifiableMap(getParamMap());
}
/**
* returns the parameter name set
*
* @return the parameter name set
*/
public final Set getParameterNameSet() {
return Collections.unmodifiableSet(getParamMap().keySet());
}
/**
* gets a parameter
*
* @param name the parameter name
* @return the parameter value or null
*/
public final String getParameter(String name) {
String[] values = getParamMap().get(name);
if (values == null) {
return null;
}
return values[0];
}
private final Map getParamMap() {
if (parameterMap == null) {
parameterMap = new HashMap();
String queryStr = getQueryString();
if (queryStr != null) {
String[] parameters = queryStr.split("&");
for (String parameter : parameters) {
String[] kvp = parameter.split("=");
String[] values = parameterMap.get(kvp[0]);
try {
// decode by using UTF-8 (see http://www.w3.org/TR/html401/appendix/notes.html#h-B.2.1)
String key = URLDecoder.decode(kvp[0], "UTF-8").trim();
String value = URLDecoder.decode(kvp[1], "UTF-8").trim();
if (values == null) {
parameterMap.put(key, new String[] { value });
} else {
String[] newValues = new String[values.length + 1];
System.arraycopy(values, 0, newValues, 0, values.length);
newValues[values.length] = value;
parameterMap.put(key, newValues);
}
} catch (UnsupportedEncodingException usce) {
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("Error occured by decoding parameter " + kvp[0] + "=" + kvp[1] + " " + usce.toString());
}
}
}
}
}
return parameterMap;
}
/**
* return the request line
*
* @return the request line
*/
String getRequestLine() {
if (isParametersModified) {
StringBuilder sb = new StringBuilder();
for (Entry entry : getParamMap().entrySet()) {
for (String value : entry.getValue()) {
try {
sb.append(URLEncoder.encode(entry.getKey(), "UTF-8") + "=" + URLEncoder.encode(value, "UTF-8") + "&");
} catch (UnsupportedEncodingException use) {
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("erro occured by endcoding request params " + use.toString());
}
}
}
}
String query = sb.toString();
if (query.length() > 0) {
query = query.substring(0, query.length() - 1);
sb.append("?" + query);
requestUri = path + "?" + query;
} else {
requestUri = path;
}
}
StringBuilder sb = new StringBuilder(method + " ");
if (requestUri != null) {
sb.append(requestUri);
} else {
sb.append(path);
if (query != null) {
sb.append("?" + query);
}
}
sb.append(" HTTP/" + schemeVersion);
return sb.toString();
}
/**
* signals if request is modified
*
* @return true, if the request is modified
*/
boolean isModified() {
return isParametersModified || isFirstLineModified || super.isHeadersModified();
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getRequestLine() + "\r\n");
sb.append(printHeaders());
// write blank line
sb.append("\r\n");
return sb.toString();
}
/**
* {@inheritDoc}
*/
@Override
public int writeTo(IDataSink dataSink) throws IOException {
if (!isModified() && (rawHeader != null)) {
int written = (int) dataSink.write(rawHeader);
written += dataSink.write("\r\n\r\n");
rawHeader = null; // necessary, because byte buffers pointer will be modified by writing
return written;
} else {
return dataSink.write(toString());
}
}
public static RequestHeader readFrom(INonBlockingConnection connection, int maxLength) throws BufferUnderflowException, IOException {
ByteBuffer[] rawHeader = connection.readByteBufferByDelimiter("\r\n\r\n", "US-ASCII", maxLength);
return new RequestHeader(rawHeader, connection);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy