Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 package org.apache.xmlrpc.client;
00020
00021 import java.io.BufferedInputStream;
00022 import java.io.BufferedOutputStream;
00023 import java.io.IOException;
00024 import java.io.InputStream;
00025 import java.io.OutputStream;
00026 import java.io.UnsupportedEncodingException;
00027 import java.net.ConnectException;
00028 import java.net.Socket;
00029 import java.net.URL;
00030 import java.net.UnknownHostException;
00031 import java.util.ArrayList;
00032 import java.util.HashMap;
00033 import java.util.Iterator;
00034 import java.util.List;
00035 import java.util.Map;
00036 import java.util.StringTokenizer;
00037
00038 import org.apache.xmlrpc.XmlRpcException;
00039 import org.apache.xmlrpc.XmlRpcRequest;
00040 import org.apache.xmlrpc.common.XmlRpcStreamRequestConfig;
00041 import org.apache.xmlrpc.util.HttpUtil;
00042 import org.apache.xmlrpc.util.LimitedInputStream;
00043 import org.xml.sax.SAXException;
00044
00045
00049 public class XmlRpcLiteHttpTransport extends XmlRpcHttpTransport {
00050 private static final String userAgent = USER_AGENT + " (Lite HTTP Transport)";
00051 private boolean ssl;
00052 private String hostname;
00053 private String host;
00054 private int port;
00055 private String uri;
00056 private Socket socket;
00057 private OutputStream output;
00058 private InputStream input;
00059 private final Map headers = new HashMap();
00060 private boolean responseGzipCompressed = false;
00061 private XmlRpcHttpClientConfig config;
00062
00067 public XmlRpcLiteHttpTransport(XmlRpcClient pClient) {
00068 super(pClient, userAgent);
00069 }
00070
00071 public Object sendRequest(XmlRpcRequest pRequest) throws XmlRpcException {
00072 config = (XmlRpcHttpClientConfig) pRequest.getConfig();
00073 URL url = config.getServerURL();
00074 ssl = "https".equals(url.getProtocol());
00075 hostname = url.getHost();
00076 int p = url.getPort();
00077 port = p < 1 ? 80 : p;
00078 String u = url.getFile();
00079 uri = (u == null || "".equals(u)) ? "/" : u;
00080 host = port == 80 ? hostname : hostname + ":" + port;
00081 headers.put("Host", host);
00082 return super.sendRequest(pRequest);
00083 }
00084
00085 protected void setRequestHeader(String pHeader, String pValue) {
00086 Object value = headers.get(pHeader);
00087 if (value == null) {
00088 headers.put(pHeader, pValue);
00089 } else {
00090 List list;
00091 if (value instanceof String) {
00092 list = new ArrayList();
00093 list.add(value);
00094 headers.put(pHeader, list);
00095 } else {
00096 list = (List) value;
00097 }
00098 list.add(pValue);
00099 }
00100 }
00101
00102 protected void close() throws XmlRpcClientException {
00103 IOException e = null;
00104 if (input != null) {
00105 try {
00106 input.close();
00107 } catch (IOException ex) {
00108 e = ex;
00109 }
00110 }
00111 if (output != null) {
00112 try {
00113 output.close();
00114 } catch (IOException ex) {
00115 if (e != null) {
00116 e = ex;
00117 }
00118 }
00119 }
00120 if (socket != null) {
00121 try {
00122 socket.close();
00123 } catch (IOException ex) {
00124 if (e != null) {
00125 e = ex;
00126 }
00127 }
00128 }
00129 if (e != null) {
00130 throw new XmlRpcClientException("Failed to close connection: " + e.getMessage(), e);
00131 }
00132 }
00133
00134 private OutputStream getOutputStream() throws XmlRpcException {
00135 try {
00136 final int retries = 3;
00137 final int delayMillis = 100;
00138
00139 for (int tries = 0; ; tries++) {
00140 try {
00141 socket = newSocket(ssl, hostname, port);
00142 output = new BufferedOutputStream(socket.getOutputStream()){
00148 public void close() throws IOException {
00149 flush();
00150 socket.shutdownOutput();
00151 }
00152 };
00153 break;
00154 } catch (ConnectException e) {
00155 if (tries >= retries) {
00156 throw new XmlRpcException("Failed to connect to "
00157 + hostname + ":" + port + ": " + e.getMessage(), e);
00158 } else {
00159 try {
00160 Thread.sleep(delayMillis);
00161 } catch (InterruptedException ignore) {
00162 }
00163 }
00164 }
00165 }
00166 sendRequestHeaders(output);
00167 return output;
00168 } catch (IOException e) {
00169 throw new XmlRpcException("Failed to open connection to "
00170 + hostname + ":" + port + ": " + e.getMessage(), e);
00171 }
00172 }
00173
00174 protected Socket newSocket(boolean pSSL, String pHostName, int pPort) throws UnknownHostException, IOException {
00175 if (pSSL) {
00176 throw new IOException("Unable to create SSL connections, use the XmlRpcLite14HttpTransportFactory.");
00177 }
00178 return new Socket(pHostName, pPort);
00179 }
00180
00181 private byte[] toHTTPBytes(String pValue) throws UnsupportedEncodingException {
00182 return pValue.getBytes("US-ASCII");
00183 }
00184
00185 private void sendHeader(OutputStream pOut, String pKey, String pValue) throws IOException {
00186 pOut.write(toHTTPBytes(pKey + ": " + pValue + "\r\n"));
00187 }
00188
00189 private void sendRequestHeaders(OutputStream pOut) throws IOException {
00190 pOut.write(("POST " + uri + " HTTP/1.0\r\n").getBytes("US-ASCII"));
00191 for (Iterator iter = headers.entrySet().iterator(); iter.hasNext(); ) {
00192 Map.Entry entry = (Map.Entry) iter.next();
00193 String key = (String) entry.getKey();
00194 Object value = entry.getValue();
00195 if (value instanceof String) {
00196 sendHeader(pOut, key, (String) value);
00197 } else {
00198 List list = (List) value;
00199 for (int i = 0; i < list.size(); i++) {
00200 sendHeader(pOut, key, (String) list.get(i));
00201 }
00202 }
00203 }
00204 pOut.write(toHTTPBytes("\r\n"));
00205 }
00206
00207 protected boolean isResponseGzipCompressed(XmlRpcStreamRequestConfig pConfig) {
00208 return responseGzipCompressed;
00209 }
00210
00211 protected InputStream getInputStream() throws XmlRpcException {
00212 final byte[] buffer = new byte[2048];
00213 try {
00214
00215 if (config.getReplyTimeout() != 0)
00216 socket.setSoTimeout(config.getReplyTimeout());
00217 input = new BufferedInputStream(socket.getInputStream());
00218
00219 String line = HttpUtil.readLine(input, buffer);
00220 StringTokenizer tokens = new StringTokenizer(line);
00221 tokens.nextToken();
00222 String statusCode = tokens.nextToken();
00223 String statusMsg = tokens.nextToken("\n\r");
00224 final int code;
00225 try {
00226 code = Integer.parseInt(statusCode);
00227 } catch (NumberFormatException e) {
00228 throw new XmlRpcClientException("Server returned invalid status code: "
00229 + statusCode + " " + statusMsg, null);
00230 }
00231 if (code < 200 || code > 299) {
00232 throw new XmlRpcHttpTransportException(code, statusMsg);
00233 }
00234 int contentLength = -1;
00235 for (;;) {
00236 line = HttpUtil.readLine(input, buffer);
00237 if (line == null || "".equals(line)) {
00238 break;
00239 }
00240 line = line.toLowerCase();
00241 if (line.startsWith("content-length:")) {
00242 contentLength = Integer.parseInt(line.substring("content-length:".length()).trim());
00243 } else if (line.startsWith("content-encoding:")) {
00244 responseGzipCompressed = HttpUtil.isUsingGzipEncoding(line.substring("content-encoding:".length()));
00245 }
00246 }
00247 InputStream result;
00248 if (contentLength == -1) {
00249 result = input;
00250 } else {
00251 result = new LimitedInputStream(input, contentLength);
00252 }
00253 return result;
00254 } catch (IOException e) {
00255 throw new XmlRpcClientException("Failed to read server response: " + e.getMessage(), e);
00256 }
00257 }
00258
00259 protected boolean isUsingByteArrayOutput(XmlRpcHttpClientConfig pConfig) {
00260 boolean result = super.isUsingByteArrayOutput(pConfig);
00261 if (!result) {
00262 throw new IllegalStateException("The Content-Length header is required with HTTP/1.0, and HTTP/1.1 is unsupported by the Lite HTTP Transport.");
00263 }
00264 return result;
00265 }
00266
00267 protected void writeRequest(ReqWriter pWriter) throws XmlRpcException, IOException, SAXException {
00268 pWriter.write(getOutputStream());
00269 }
00270 }