/*
* Copyright (c) 1998-2010 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source 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, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Nam Nguyen
*/
package com.caucho.quercus.lib.curl;
import com.caucho.quercus.QuercusModuleException;
import com.caucho.quercus.env.*;
import com.caucho.quercus.lib.file.BinaryInput;
import com.caucho.quercus.lib.file.BinaryOutput;
import com.caucho.quercus.lib.file.FileModule;
import com.caucho.util.L10N;
import com.caucho.vfs.Path;
import com.caucho.vfs.WriteStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
public class CurlResource {
private static final Logger log = Logger.getLogger(CurlResource.class.getName());
private static final L10N L = new L10N(CurlResource.class);
private String _requestMethod = "GET";
private int _responseCode;
private String _URL;
private int _port = -1;
private String _username;
private String _password;
private boolean _isProxying = false;
private String _proxyUsername;
private String _proxyPassword;
private String _proxyURL;
private String _proxyType = "HTTP";
private int _proxyPort = -1;
private boolean _isFollowingRedirects = true;
private boolean _isReturningBody = true;
private boolean _isReturningData = false;
private boolean _isReturningHeader = false;
private boolean _isVerifySSLPeer = true;
private boolean _isVerifySSLCommonName = true;
private boolean _isVerifySSLHostname = true;
private boolean _ifModifiedSince = true;
private String _modifiedTime;
private int _errorCode = CurlModule.CURLE_OK;
private String _error = "";
private boolean _failOnError = false;
private boolean _isVerbose = false;
private int _readTimeout = -1;
private int _connectTimeout = -1;
private HashMap<String, String> _requestProperties = new HashMap<String, String>();
private StringValue _header;
private StringValue _body;
private Value _postBody;
private String _contentType;
private int _contentLength;
private String _cookie;
private String _cookieFilename;
private BinaryOutput _outputFile;
private BinaryOutput _outputHeaderFile;
private BinaryInput _uploadFile;
private int _uploadFileSize;
private Callable _headerCallback;
private Callable _passwordCallback;
private Callable _readCallback;
private Callable _writeCallback;
public CurlResource() {
}
/**
* Returns body of last transfer.
*/
public Value getBody() {
return _body;
}
/**
* Sets the body of the last request.
*/
public void setBody(StringValue body) {
_body = body;
}
/**
* Returns the max time until timeout while establishing a connection.
*/
public int getConnectTimeout() {
return _connectTimeout;
}
/**
* Sets the max time until timeout while establishing a connection.
*/
public void setConnectTimeout(int timeout) {
_connectTimeout = timeout;
}
/**
* Returns the length of the body from the last request.
*/
public int getContentLength() {
return _contentLength;
}
/**
* Sets the length of the body from the last request.
*/
public void setContentLength(int length) {
_contentLength = length;
}
/**
* Returns the "Content-Type" header from the last request.
*/
public String getContentType() {
return _contentType;
}
/**
* Sets the "Content-Type" from the last request.
*/
public void setContentType(String type) {
_contentType = type;
}
/**
* Sets the "Set-Cookie" request property.
*/
public void setCookie(String cookie) {
_cookie = cookie;
}
/**
* Sets the filename to save the cookies from the last request.
*/
public void setCookieFilename(String filename) {
_cookieFilename = filename;
}
/**
* Returns the error string from the last request.
*/
public String getError() {
return _error;
}
/**
* Sets the error string from the last request.
*/
public void setError(String error) {
_error = error;
}
/**
* Sets the error code from the last request.
*/
public int getErrorCode() {
return _errorCode;
}
/**
* Returns the error code from the last request.
*/
public void setErrorCode(int code) {
_errorCode = code;
}
/**
* Set to true to fail on response codes >= 400.
*/
public void setFailOnError(boolean failOnError) {
_failOnError = failOnError;
}
/**
* Returns the header from the last request.
*/
public Value getHeader() {
return _header;
}
/**
* Saves the header that was returned by the server.
*/
public void setHeader(StringValue header) {
_header = header;
}
/*
* Returns the header callback.
*/
public Callable getHeaderCallback() {
return _headerCallback;
}
/**
* Sets the callback to read the header.
*/
public void setHeaderCallback(Callable callback) {
_headerCallback = callback;
}
/**
* Set to true to set the If-Modified-Since property.
* Time to use is set with setModifiedTime().
*/
public void setIfModifiedSince(boolean option) {
_ifModifiedSince = option;
}
/**
* Returns true if automatically following redirects.
*/
public boolean getIsFollowingRedirects() {
return _isFollowingRedirects;
}
/**
* Set to true to automatically follow redirects.
*/
public void setIsFollowingRedirects(boolean followRedirects) {
_isFollowingRedirects = followRedirects;
}
/**
* Returns true if a proxy is to be used.
*/
public boolean getIsProxying() {
return _isProxying;
}
/**
* Set to true to proxy request.
*/
public void setIsProxying(boolean proxy) {
_isProxying = proxy;
}
/**
* Set to true to return body for this request.
*/
public void setIsReturningBody(boolean returnBody) {
_isReturningBody = returnBody;
}
/**
* Set to true to return data instead of to stdout.
*/
public void setIsReturningData(boolean returnData) {
_isReturningData = returnData;
}
/**
* Set to true to return the body from this request.
*/
public void setIsReturningHeader(boolean returnHeader) {
_isReturningHeader = returnHeader;
}
/**
* Returns the verbosity of this library.
*/
public boolean getIsVerbose() {
return _isVerbose;
}
/**
* Sets the verbosity of this library.
*/
public void setIsVerbose(boolean verbose) {
_isVerbose = verbose;
}
public boolean getIsVerifySSLPeer() {
return _isVerifySSLPeer;
}
public void setIsVerifySSLPeer(boolean isVerify) {
_isVerifySSLPeer = isVerify;
}
public boolean getIsVerifySSLCommonName() {
return _isVerifySSLCommonName;
}
public void setIsVerifySSLCommonName(boolean isVerify) {
_isVerifySSLCommonName = isVerify;
}
public boolean getIsVerifySSLHostname() {
return _isVerifySSLHostname;
}
public void setIsVerifySSLHostname(boolean isVerify) {
_isVerifySSLHostname = isVerify;
}
/**
* Sets the modified time request property.
*/
public void setModifiedTime(String time) {
_modifiedTime = time;
}
/**
* Sets the file to save the data to save from a request.
*/
public void setOutputFile(BinaryOutput file) {
_outputFile = file;
}
/**
* Sets the file to save the header from a request.
*/
public void setOutputHeaderFile(BinaryOutput file) {
_outputHeaderFile = file;
}
/**
* Returns the password to use for authentication.
*/
public String getPassword() {
return _password;
}
/**
* Sets the password to use for authentication.
*/
public void setPassword(String pwd) {
_password = pwd;
}
/**
*
*/
public void setPasswordCallback(Callable callback) {
_passwordCallback = callback;
}
/**
* Returns the port to use for this request.
*/
public int getPort() {
return _port;
}
/**
* Sets the port to use for this request.
*/
public void setPort(int port) {
_port = port;
}
/**
* Gets the body to POST to the server.
*/
public Value getPostBody() {
return _postBody;
}
/**
* Sets the body to POST to the server.
*/
public void setPostBody(Value body) {
_postBody = body;
}
/**
* Returns the password to use for proxy authentication.
*/
public String getProxyPassword() {
return _proxyPassword;
}
/**
* Sets the password to use for proxy authentication.
*/
public void setProxyPassword(String pass) {
_proxyPassword = pass;
}
/**
* Returns the port to use for the proxy.
*/
public int getProxyPort() {
return _proxyPort;
}
/**
* Sets the port to use for the proxy.
*/
public void setProxyPort(int port) {
_proxyPort = port;
}
/**
* Returns of type of the proxy (Http or SOCKS).
*/
public String getProxyType() {
return _proxyType;
}
/**
* Sets the type of the proxy (Http or SOCKS).
*/
public void setProxyType(String type) {
_proxyType = type;
}
/**
* Returns the URL of the proxy.
*/
public String getProxyURL() {
return _proxyURL;
}
/**
* Sets the URL of the proxy.
*/
public void setProxyURL(String proxy) {
_proxyURL = proxy;
}
/**
* Returns the username to use for proxy authentication.
*/
public String getProxyUsername() {
return _proxyUsername;
}
/**
* Sets the username to use for proxy authentication.
*/
public void setProxyUsername(String user) {
_proxyUsername = user;
}
/*
* Returns the callback to read the body.
*/
public Callable getReadCallback() {
return _readCallback;
}
/**
* Sets the callback to read the body.
*/
public void setReadCallback(Callable callback) {
_readCallback = callback;
}
/**
* Returns the max time until timeout while reading body.
*/
public int getReadTimeout() {
return _readTimeout;
}
/**
* Sets the max time until timeout while reading body.
*/
public void setReadTimeout(int timeout) {
_readTimeout = timeout;
}
/**
* Returns the current request method.
*/
public String getRequestMethod() {
return _requestMethod;
}
/**
* Sets the request method to use for this request.
*/
public void setRequestMethod(String method) {
_requestMethod = method;
}
/**
* Returns a map of all the request properties.
*/
public HashMap<String, String> getRequestPropertiesMap() {
return _requestProperties;
}
/**
* Returns all the request properties as a String.
*/
public Value getRequestProperties(Env env) {
StringValue bb = env.createBinaryBuilder();
for (Map.Entry<String, String> entry : _requestProperties.entrySet()) {
bb.append(entry.getKey());
bb.append(": ");
bb.append(entry.getValue());
bb.append("\r\n");
}
bb.append("\r\n");
return bb;
}
/**
* Sets a request property to use for this request.
*/
public void setRequestProperty(String key, String value) {
_requestProperties.put(key, value);
if (key.equals("Content-Type")) {
setContentType(value);
}
}
/**
* Returns the response code for the last request.
*/
public int getResponseCode() {
return _responseCode;
}
/**
* Sets the response code for the last request.
*/
public void setResponseCode(int code) {
_responseCode = code;
}
/**
* Returns handle of file to upload.
*/
public BinaryInput getUploadFile() {
return _uploadFile;
}
/**
* Sets handle of file to upload.
*/
public void setUploadFile(BinaryInput file) {
_uploadFile = file;
}
/**
* Returns size of file to upload.
*/
public int getUploadFileSize() {
return _uploadFileSize;
}
/**
* Sets size of file to upload.
*/
public void setUploadFileSize(int size) {
_uploadFileSize = size;
}
/**
* Gets the URL to use for this request.
*/
public String getURL() {
return _URL;
}
/**
* Sets the URL to use for this request.
*/
public void setURL(String url) {
_URL = url;
}
/**
* Gets the username to use for authentication.
*/
public String getUsername() {
return _username;
}
/**
* Sets the username to use for authentication.
*/
public void setUsername(String user) {
_username = user;
}
/**
*
*/
public void setWriteCallback(Callable callback) {
_writeCallback = callback;
}
/**
* Remove a request property.
*/
public void removeRequestProperty(String key) {
_requestProperties.remove(key);
}
/**
* Finalizes the request properties for this connection.
*/
private void init() {
_error = null;
_errorCode = CurlModule.CURLE_OK;
if (_modifiedTime != null) {
if (_ifModifiedSince) {
removeRequestProperty("If-Unmodified-Since");
setRequestProperty("If-Modified-Since", _modifiedTime);
} else {
removeRequestProperty("If-Modified-Since");
setRequestProperty("If-Unmodified-Since", _modifiedTime);
}
}
if (_cookie != null) {
setRequestProperty("Cookie", _cookie);
} else {
removeRequestProperty("Cookie");
}
}
/**
* Executes this request.
*/
public Value execute(Env env) {
init();
HttpRequest httpRequest = HttpRequest.getRequest(this);
env.addCleanup(httpRequest);
if (!httpRequest.execute(env)) {
return BooleanValue.FALSE;
}
//if (hasError())
//return BooleanValue.FALSE;
if (_cookie != null && _cookieFilename != null) {
saveCookie(env);
}
return getReturnValue(env);
}
/**
* Returns headers and/or body of the last request.
*/
private Value getReturnValue(Env env) {
StringValue data;
if (_responseCode == HttpURLConnection.HTTP_NOT_MODIFIED
|| _responseCode == HttpURLConnection.HTTP_PRECON_FAILED
|| (_failOnError && _responseCode >= 400)) {
if (_isReturningHeader) {
data = _header;
} else {
return BooleanValue.TRUE;
}
} else {
StringValue bb = env.createBinaryBuilder();
if (_isReturningHeader) {
bb.append(_header);
}
if (_isReturningBody) {
bb.append(_body);
}
data = bb;
}
if (_isReturningData) {
return data;
}
if (_outputHeaderFile != null) {
FileModule.fwrite(env,
_outputHeaderFile,
_header.toInputStream(),
Integer.MAX_VALUE);
}
if (_outputFile != null) {
FileModule.fwrite(env,
_outputFile,
data.toInputStream(),
Integer.MAX_VALUE);
} else {
env.print(data);
}
return BooleanValue.TRUE;
}
/**
* Save the cookies from the last request.
*/
private void saveCookie(Env env) {
WriteStream out = null;
try {
Path path = env.getPwd().lookup(_cookieFilename);
out = path.openWrite();
int len = _cookie.length();
for (int i = 0; i < len; i++) {
out.write((byte) _cookie.charAt(i));
}
} catch (IOException e) {
throw new QuercusModuleException(e);
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
// intentionally don't do anything
}
}
}
/**
*
*/
public void close() {
}
/**
* Returns true if an error occuring during the last operation.
*/
protected boolean hasError() {
return _errorCode != CurlModule.CURLE_OK;
}
/**
* Returns a copy of this resource.
*/
@Override
public CurlResource clone() {
CurlResource curl = new CurlResource();
curl.setBody(_body);
curl.setConnectTimeout(_connectTimeout);
curl.setContentLength(_contentLength);
curl.setContentType(_contentType);
curl.setCookie(_cookie);
curl.setCookieFilename(_cookieFilename);
curl.setError(_error);
curl.setErrorCode(_errorCode);
curl.setFailOnError(_failOnError);
curl.setHeaderCallback(_headerCallback);
curl.setHeader(_header);
curl.setIsFollowingRedirects(_isFollowingRedirects);
curl.setIfModifiedSince(_ifModifiedSince);
curl.setIsProxying(_isProxying);
curl.setIsReturningBody(_isReturningBody);
curl.setIsReturningData(_isReturningData);
curl.setIsReturningHeader(_isReturningHeader);
curl.setIsVerbose(_isVerbose);
curl.setModifiedTime(_modifiedTime);
curl.setOutputFile(_outputFile);
curl.setOutputHeaderFile(_outputHeaderFile);
curl.setPassword(_password);
curl.setPasswordCallback(_passwordCallback);
curl.setPort(_port);
curl.setPostBody(_postBody);
curl.setProxyPassword(_proxyPassword);
curl.setProxyPort(_proxyPort);
curl.setProxyType(_proxyType);
curl.setProxyURL(_proxyURL);
curl.setProxyUsername(_proxyUsername);
curl.setReadCallback(_readCallback);
curl.setReadTimeout(_readTimeout);
curl.setRequestMethod(_requestMethod);
for (Map.Entry<String, String> entry : _requestProperties.entrySet()) {
curl.setRequestProperty(entry.getKey(), entry.getValue());
}
curl.setResponseCode(_responseCode);
curl.setUploadFile(_uploadFile);
curl.setUploadFileSize(_uploadFileSize);
curl.setURL(_URL);
curl.setUsername(_username);
curl.setWriteCallback(_writeCallback);
return curl;
}
@Override
public String toString() {
return "CurlResource[" + _requestMethod + "]";
}
}