Package com.subgraph.orchid.xmlrpc

Source Code of com.subgraph.orchid.xmlrpc.OrchidXmlRpcTransport

package com.subgraph.orchid.xmlrpc;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Logger;

import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.XmlRpcRequest;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientException;
import org.apache.xmlrpc.client.XmlRpcHttpClientConfig;
import org.apache.xmlrpc.client.XmlRpcHttpTransport;
import org.apache.xmlrpc.client.XmlRpcHttpTransportException;
import org.apache.xmlrpc.client.XmlRpcLiteHttpTransport;
import org.apache.xmlrpc.common.XmlRpcStreamRequestConfig;
import org.apache.xmlrpc.util.HttpUtil;
import org.apache.xmlrpc.util.LimitedInputStream;
import org.xml.sax.SAXException;

import com.subgraph.orchid.Tor;
import com.subgraph.orchid.sockets.AndroidSSLSocketFactory;

public class OrchidXmlRpcTransport extends XmlRpcHttpTransport {
 
  private final static Logger logger = Logger.getLogger(OrchidXmlRpcTransport.class.getName());
 
  private final SocketFactory socketFactory;
  private final SSLContext sslContext;

  private SSLSocketFactory sslSocketFactory;

  public OrchidXmlRpcTransport(XmlRpcClient pClient, SocketFactory socketFactory, SSLContext sslContext) {
    super(pClient, userAgent);
    this.socketFactory = socketFactory;
    this.sslContext = sslContext;
  }
 
  public synchronized SSLSocketFactory getSSLSocketFactory() {
    if(sslSocketFactory == null) {
      sslSocketFactory = createSSLSocketFactory();
    }
    return sslSocketFactory;
  }

  private SSLSocketFactory createSSLSocketFactory() {
    if(Tor.isAndroidRuntime()) {
      return createAndroidSSLSocketFactory();
    }
    if(sslContext == null) {
      return (SSLSocketFactory) SSLSocketFactory.getDefault();
    } else {
      return sslContext.getSocketFactory();
    }
  }

  private SSLSocketFactory createAndroidSSLSocketFactory() {
    if(sslContext == null) {
      try {
        return new AndroidSSLSocketFactory();
      } catch (NoSuchAlgorithmException e) {
        logger.severe("Failed to create default ssl context");
        System.exit(1);
        return null;
      }
    } else {
      return new AndroidSSLSocketFactory(sslContext);
    }
  }

  protected Socket newSocket(boolean pSSL, String pHostName, int pPort) throws UnknownHostException, IOException {
    final Socket s = socketFactory.createSocket(pHostName, pPort);
    if(pSSL) {
      return getSSLSocketFactory().createSocket(s, pHostName, pPort, true);
    } else {
      return s;
    }
  }
 
  private static final String userAgent = USER_AGENT + " (Lite HTTP Transport)";
  private boolean ssl;
  private String hostname;
  private String host;
  private int port;
  private String uri;
  private Socket socket;
  private OutputStream output;
  private InputStream input;
  private final Map<String, Object> headers = new HashMap<String, Object>();
  private boolean responseGzipCompressed = false;
  private XmlRpcHttpClientConfig config;


  public Object sendRequest(XmlRpcRequest pRequest) throws XmlRpcException {
    config = (XmlRpcHttpClientConfig) pRequest.getConfig();
    URL url = config.getServerURL();
    ssl = "https".equals(url.getProtocol());
    hostname = url.getHost();
        int p = url.getPort();
    port = p < 1 ? 80 : p;
    String u = url.getFile();
    uri = (u == null  ||  "".equals(u)) ? "/" : u;
    host = port == 80 ? hostname : hostname + ":" + port;
    headers.put("Host", host);
    return super.sendRequest(pRequest);
  }

  protected void setRequestHeader(String pHeader, String pValue) {
    Object value = headers.get(pHeader);
    if (value == null) {
      headers.put(pHeader, pValue);
    } else {
      List<Object> list;
      if (value instanceof String) {
        list = new ArrayList<Object>();
        list.add((String)value);
        headers.put(pHeader, list);
      } else {
        list = (List<Object>) value;
      }
      list.add(pValue);
    }
  }

  protected void close() throws XmlRpcClientException {
    IOException e = null;
    if (input != null) {
      try {
        input.close();
      } catch (IOException ex) {
        e = ex;
      }
    }
    if (output != null) {
      try {
        output.close();
      } catch (IOException ex) {
        if (e != null) {
          e = ex;
        }
      }
    }
    if (socket != null) {
      try {
        socket.close();
      } catch (IOException ex) {
        if (e != null) {
          e = ex;
        }
      }
    }
    if (e != null) {
      throw new XmlRpcClientException("Failed to close connection: " + e.getMessage(), e);
    }
  }

  private OutputStream getOutputStream() throws XmlRpcException {
    try {
      final int retries = 3;
          final int delayMillis = 100;
 
      for (int tries = 0;  ;  tries++) {
        try {
          socket = newSocket(ssl, hostname, port);
          output = new BufferedOutputStream(socket.getOutputStream()){
            /** Closing the output stream would close the whole socket, which we don't want,
             * because the don't want until the request is processed completely.
             * A close will later occur within
             * {@link XmlRpcLiteHttpTransport#close()}.
             */
            public void close() throws IOException {
              flush();
              if(!(socket instanceof SSLSocket)) {
                socket.shutdownOutput();
              }
            }
          };
          break;
        } catch (ConnectException e) {
          if (tries >= retries) {
            throw new XmlRpcException("Failed to connect to "
                + hostname + ":" + port + ": " + e.getMessage(), e);
          } else {
                      try {
                          Thread.sleep(delayMillis);
                      } catch (InterruptedException ignore) {
                      }
          }
        }
      }
      sendRequestHeaders(output);
      return output;
    } catch (IOException e) {
      throw new XmlRpcException("Failed to open connection to "
          + hostname + ":" + port + ": " + e.getMessage(), e);
    }
  }

  

  private byte[] toHTTPBytes(String pValue) throws UnsupportedEncodingException {
    return pValue.getBytes("US-ASCII");
  }

  private void sendHeader(OutputStream pOut, String pKey, String pValue) throws IOException {
    pOut.write(toHTTPBytes(pKey + ": " + pValue + "\r\n"));
  }

  private void sendRequestHeaders(OutputStream pOut) throws IOException {
    pOut.write(("POST " + uri + " HTTP/1.0\r\n").getBytes("US-ASCII"));
    for (Iterator iter = headers.entrySet().iterator();  iter.hasNext()) {
      Map.Entry entry = (Map.Entry) iter.next();
      String key = (String) entry.getKey();
      Object value = entry.getValue();
      if (value instanceof String) {
        sendHeader(pOut, key, (String) value);
      } else {
        List list = (List) value;
        for (int i = 0;  i < list.size();  i++) {
          sendHeader(pOut, key, (String) list.get(i));
        }
      }
    }
    pOut.write(toHTTPBytes("\r\n"));
  }

  protected boolean isResponseGzipCompressed(XmlRpcStreamRequestConfig pConfig) {
    return responseGzipCompressed;
  }

  protected InputStream getInputStream() throws XmlRpcException {
    final byte[] buffer = new byte[2048];
    try {
            // If reply timeout specified, set the socket timeout accordingly
            if (config.getReplyTimeout() != 0)
                socket.setSoTimeout(config.getReplyTimeout());
            input = new BufferedInputStream(socket.getInputStream());
      // start reading  server response headers
      String line = HttpUtil.readLine(input, buffer);
      StringTokenizer tokens = new StringTokenizer(line);
      tokens.nextToken(); // Skip HTTP version
      String statusCode = tokens.nextToken();
      String statusMsg = tokens.nextToken("\n\r");
      final int code;
      try {
          code = Integer.parseInt(statusCode);
      } catch (NumberFormatException e) {
                throw new XmlRpcClientException("Server returned invalid status code: "
                        + statusCode + " " + statusMsg, null);
      }
      if (code < 200  ||  code > 299) {
            throw new XmlRpcHttpTransportException(code, statusMsg);
        }
      int contentLength = -1;
      for (;;) {
        line = HttpUtil.readLine(input, buffer);
        if (line == null  ||  "".equals(line)) {
          break;
        }
        line = line.toLowerCase();
        if (line.startsWith("content-length:")) {
          contentLength = Integer.parseInt(line.substring("content-length:".length()).trim());
        } else if (line.startsWith("content-encoding:")) {
          responseGzipCompressed = HttpUtil.isUsingGzipEncoding(line.substring("content-encoding:".length()));
        }
      }
      InputStream result;
      if (contentLength == -1) {
        result = input;
      } else {
        result = new LimitedInputStream(input, contentLength);
      }
      return result;
    } catch (IOException e) {
      throw new XmlRpcClientException("Failed to read server response: " + e.getMessage(), e);
    }
  }

  protected boolean isUsingByteArrayOutput(XmlRpcHttpClientConfig pConfig) {
      boolean result = super.isUsingByteArrayOutput(pConfig);
        if (!result) {
            throw new IllegalStateException("The Content-Length header is required with HTTP/1.0, and HTTP/1.1 is unsupported by the Lite HTTP Transport.");
        }
        return result;
    }

    protected void writeRequest(ReqWriter pWriter) throws XmlRpcException, IOException, SAXException {
        pWriter.write(getOutputStream());
  }
}
TOP

Related Classes of com.subgraph.orchid.xmlrpc.OrchidXmlRpcTransport

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.