/******************************************************************
*
* CyberHTTP for Java
*
* Copyright (C) Satoshi Konno 2002-2004
*
* File: HTTPRequest.java
*
* Revision;
*
* 11/18/02 - first revision. 05/23/03 - Giordano Sassaroli
* <sassarol@cefriel.it> - Add a relative URL check to setURI(). 09/02/03 -
* Giordano Sassaroli <sassarol@cefriel.it> - Problem : Devices whose
* description use absolute urls receive wrong http requests - Error : the
* presence of a base url is not mandatory, the API code makes the assumption
* that control and event subscription urls are relative - Description: The
* method setURI should be changed as follows 02/01/04 - Added URI parameter
* methods. 03/16/04 - Removed setVersion() because the method is added to the
* super class. - Changed getVersion() to return the version when the first line
* string has the length. 05/19/04 - Changed post(HTTPResponse *) to close the
* socket stream from the server. 08/19/04 - Fixed getFirstLineString() and
* getHTTPVersion() no to return "HTTP/HTTP/version". 08/25/04 - Added
* isHeadRequest(). 08/26/04 - Changed post(HTTPResponse) not to close the
* connection. - Changed post(String, int) to add a connection header to close.
* 08/27/04 - Changed post(String, int) to support the persistent connection.
* 08/28/04 - Added isKeepAlive(). 10/26/04 - Brent Hills
* <bhills@openshores.com> - Added a fix to post() when the last position of
* Content-Range header is 0. - Added a Content-Range header to the response in
* post(). - Changed the status code for the Content-Range request in post(). -
* Added to check the range of Content-Range request in post(). 03/02/05 -
* Changed post() to suppot chunked stream. 06/10/05 - Changed post() to add a
* HOST headedr before the posting. 07/07/05 - Lee Peik Feng
* <pflee@users.sourceforge.net> - Fixed post() to output the chunk size as a
* hex string.
*
******************************************************************/
package com.guo.duoduo.airplayreceiver.http;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.util.StringTokenizer;
import com.guo.duoduo.airplayreceiver.utils.Debug;
/**
*
* This class rappresnet an HTTP <b>request</b>, and act as HTTP client when it
* sends the request<br>
*
* @author Satoshi "skonno" Konno
* @author Stefano "Kismet" Lenzi
* @version 1.8
*
*/
public class HTTPRequest extends HTTPPacket
{
////////////////////////////////////////////////
// Constructor
////////////////////////////////////////////////
private String method = null;
private String uri = null;
private String requestHost = "";
////////////////////////////////////////////////
// Method
////////////////////////////////////////////////
private int requestPort = -1;
private HTTPSocket httpSocket = null;
private Socket postSocket = null;
public HTTPRequest()
{
setVersion(HTTP.VERSION_10);
}
public HTTPRequest(InputStream in)
{
super(in);
}
public HTTPRequest(HTTPSocket httpSock)
{
this(httpSock.getInputStream());
setSocket(httpSock);
}
public String getMethod()
{
if (method != null)
return method;
return getFirstLineToken(0);
}
public void setMethod(String value)
{
method = value;
}
public boolean isMethod(String method)
{
String headerMethod = getMethod();
if (headerMethod == null)
return false;
return headerMethod.equalsIgnoreCase(method);
}
public boolean isGetRequest()
{
return isMethod(HTTP.GET);
}
////////////////////////////////////////////////
// URI
////////////////////////////////////////////////
public boolean isPostRequest()
{
return isMethod(HTTP.POST);
}
public boolean isHeadRequest()
{
return isMethod(HTTP.HEAD);
}
public boolean isSubscribeRequest()
{
return isMethod(HTTP.SUBSCRIBE);
}
public boolean isUnsubscribeRequest()
{
return isMethod(HTTP.UNSUBSCRIBE);
}
////////////////////////////////////////////////
// URI Parameter
////////////////////////////////////////////////
public boolean isNotifyRequest()
{
return isMethod(HTTP.NOTIFY);
}
public void setURI(String value, boolean isCheckRelativeURL)
{
uri = value;
if (isCheckRelativeURL == false)
return;
// Thanks for Giordano Sassaroli <sassarol@cefriel.it> (09/02/03)
uri = HTTP.toRelativeURL(uri);
}
////////////////////////////////////////////////
// SOAPAction
////////////////////////////////////////////////
public String getURI()
{
if (uri != null)
return uri;
return getFirstLineToken(1);
}
////////////////////////////////////////////////
// Host / Port
////////////////////////////////////////////////
public void setURI(String value)
{
setURI(value, false);
}
public ParameterList getParameterList()
{
ParameterList paramList = new ParameterList();
String uri = getURI();
if (uri == null)
return paramList;
int paramIdx = uri.indexOf('?');
if (paramIdx < 0)
return paramList;
while (0 < paramIdx)
{
int eqIdx = uri.indexOf('=', (paramIdx + 1));
String name = uri.substring(paramIdx + 1, eqIdx);
int nextParamIdx = uri.indexOf('&', (eqIdx + 1));
String value = uri.substring(eqIdx + 1, (0 < nextParamIdx)
? nextParamIdx
: uri.length());
Parameter param = new Parameter(name, value);
paramList.add(param);
paramIdx = nextParamIdx;
}
return paramList;
}
public String getParameterValue(String name)
{
ParameterList paramList = getParameterList();
return paramList.getValue(name);
}
public boolean isSOAPAction()
{
return hasHeader(HTTP.SOAP_ACTION);
}
public String getRequestHost()
{
return requestHost;
}
public void setRequestHost(String host)
{
requestHost = host;
}
////////////////////////////////////////////////
// Socket
////////////////////////////////////////////////
public int getRequestPort()
{
return requestPort;
}
public void setRequestPort(int host)
{
requestPort = host;
}
public HTTPSocket getSocket()
{
return httpSocket;
}
/////////////////////////// /////////////////////
// local address/port
////////////////////////////////////////////////
public void setSocket(HTTPSocket value)
{
httpSocket = value;
}
public String getLocalAddress()
{
return getSocket().getLocalAddress();
}
////////////////////////////////////////////////
// parseRequest
////////////////////////////////////////////////
public int getLocalPort()
{
return getSocket().getLocalPort();
}
////////////////////////////////////////////////
// First Line
////////////////////////////////////////////////
public boolean parseRequestLine(String lineStr)
{
StringTokenizer st = new StringTokenizer(lineStr, HTTP.REQEST_LINE_DELIM);
if (st.hasMoreTokens() == false)
return false;
setMethod(st.nextToken());
if (st.hasMoreTokens() == false)
return false;
setURI(st.nextToken());
if (st.hasMoreTokens() == false)
return false;
setVersion(st.nextToken());
return true;
}
public String getHTTPVersion()
{
if (hasFirstLine() == true)
return getFirstLineToken(2);
return "HTTP/" + super.getVersion();
}
////////////////////////////////////////////////
// getHeader
////////////////////////////////////////////////
public String getFirstLineString()
{
return getMethod() + " " + getURI() + " " + getHTTPVersion() + HTTP.CRLF;
}
////////////////////////////////////////////////
// isKeepAlive
////////////////////////////////////////////////
public String getHeader()
{
StringBuffer str = new StringBuffer();
str.append(getFirstLineString());
String headerString = getHeaderString();
str.append(headerString);
return str.toString();
}
////////////////////////////////////////////////
// read
////////////////////////////////////////////////
public boolean isKeepAlive()
{
if (isCloseConnection() == true)
return false;
if (isKeepAliveConnection() == true)
return true;
String httpVer = getHTTPVersion();
boolean isHTTP10 = (0 < httpVer.indexOf("1.0")) ? true : false;
if (isHTTP10 == true)
return false;
return true;
}
////////////////////////////////////////////////
// POST (Response)
////////////////////////////////////////////////
public boolean read()
{
return super.read(getSocket());
}
////////////////////////////////////////////////
// POST (Request)
////////////////////////////////////////////////
public boolean post(HTTPResponse httpRes)
{
HTTPSocket httpSock = getSocket();
long offset = 0;
long length = httpRes.getContentLength();
if (hasContentRange() == true)
{
long firstPos = getContentRangeFirstPosition();
long lastPos = getContentRangeLastPosition();
// Thanks for Brent Hills (10/26/04)
if (lastPos <= 0)
lastPos = length - 1;
if ((firstPos > length) || (lastPos > length))
return returnResponse(HTTPStatus.INVALID_RANGE);
httpRes.setContentRange(firstPos, lastPos, length);
httpRes.setStatusCode(HTTPStatus.PARTIAL_CONTENT);
offset = firstPos;
length = lastPos - firstPos + 1;
}
return httpSock.post(httpRes, offset, length, isHeadRequest());
//httpSock.close();
}
public HTTPResponse post(String host, int port, boolean isKeepAlive)
{
HTTPResponse httpRes = new HTTPResponse();
setHost(host);
setConnection((isKeepAlive == true) ? HTTP.KEEP_ALIVE : HTTP.CLOSE);
boolean isHeaderRequest = isHeadRequest();
OutputStream out = null;
InputStream in = null;
try
{
if (postSocket == null)
{
// Thanks for Hao Hu
postSocket = new Socket();
postSocket.connect(new InetSocketAddress(host, port),
HTTPServer.DEFAULT_TIMEOUT);
}
out = postSocket.getOutputStream();
PrintStream pout = new PrintStream(out);
pout.print(getHeader());
pout.print(HTTP.CRLF);
boolean isChunkedRequest = isChunked();
String content = getContentString();
int contentLength = 0;
if (content != null)
contentLength = content.length();
if (0 < contentLength)
{
if (isChunkedRequest == true)
{
// Thanks for Lee Peik Feng <pflee@users.sourceforge.net> (07/07/05)
String chunSizeBuf = Long.toHexString(contentLength);
pout.print(chunSizeBuf);
pout.print(HTTP.CRLF);
}
pout.print(content);
if (isChunkedRequest == true)
pout.print(HTTP.CRLF);
}
if (isChunkedRequest == true)
{
pout.print("0");
pout.print(HTTP.CRLF);
}
pout.flush();
in = postSocket.getInputStream();
httpRes.set(in, isHeaderRequest);
}
catch (SocketException e)
{
httpRes.setStatusCode(HTTPStatus.INTERNAL_SERVER_ERROR);
Debug.warning(e);
}
catch (IOException e)
{
//Socket create but without connection
//TODO Blacklistening the device
httpRes.setStatusCode(HTTPStatus.INTERNAL_SERVER_ERROR);
Debug.warning(e);
}
finally
{
if (isKeepAlive == false)
{
try
{
in.close();
}
catch (Exception e)
{
};
if (in != null)
try
{
out.close();
}
catch (Exception e)
{
};
if (out != null)
try
{
postSocket.close();
}
catch (Exception e)
{
};
postSocket = null;
}
}
return httpRes;
}
public HTTPResponse post(String host, int port)
{
return post(host, port, false);
}
////////////////////////////////////////////////
// set
////////////////////////////////////////////////
public void set(HTTPRequest httpReq)
{
set((HTTPPacket) httpReq);
setSocket(httpReq.getSocket());
}
////////////////////////////////////////////////
// OK/BAD_REQUEST
////////////////////////////////////////////////
public boolean returnResponse(int statusCode)
{
HTTPResponse httpRes = new HTTPResponse();
httpRes.setStatusCode(statusCode);
httpRes.setContentLength(0);
return post(httpRes);
}
public boolean returnOK()
{
return returnResponse(HTTPStatus.OK);
}
public boolean returnBadRequest()
{
return returnResponse(HTTPStatus.BAD_REQUEST);
}
////////////////////////////////////////////////
// toString
////////////////////////////////////////////////
public String toString()
{
StringBuffer str = new StringBuffer();
str.append(getHeader());
str.append(HTTP.CRLF);
str.append(getContentString());
return str.toString();
}
public void print()
{
System.out.println(toString());
}
}