1 |
24 |
|
2 |
|
|
3 |
|
|
4 |
|
|
5 |
|
|
6 |
|
|
7 |
|
|
8 |
|
|
9 |
|
|
10 |
|
|
11 |
|
|
12 |
|
|
13 |
|
|
14 |
|
|
15 |
|
|
16 |
|
package org.apache.xmlrpc.client; |
17 |
|
|
18 |
|
import java.io.BufferedInputStream; |
19 |
|
import java.io.BufferedOutputStream; |
20 |
|
import java.io.IOException; |
21 |
|
import java.io.InputStream; |
22 |
|
import java.io.OutputStream; |
23 |
|
import java.io.UnsupportedEncodingException; |
24 |
|
import java.net.ConnectException; |
25 |
|
import java.net.Socket; |
26 |
|
import java.net.URL; |
27 |
|
import java.util.ArrayList; |
28 |
|
import java.util.HashMap; |
29 |
|
import java.util.Iterator; |
30 |
|
import java.util.List; |
31 |
|
import java.util.Map; |
32 |
|
import java.util.StringTokenizer; |
33 |
|
|
34 |
|
import org.apache.xmlrpc.XmlRpcException; |
35 |
|
import org.apache.xmlrpc.common.XmlRpcStreamRequestConfig; |
36 |
|
import org.apache.xmlrpc.util.HttpUtil; |
37 |
|
import org.apache.xmlrpc.util.LimitedInputStream; |
38 |
|
|
39 |
|
|
40 |
|
|
41 |
|
|
42 |
|
public class XmlRpcLiteHttpTransport extends XmlRpcHttpTransport { |
43 |
|
private class Connection { |
44 |
70 |
private final String hostname; |
45 |
0 |
private final String host; |
46 |
70 |
private int port; |
47 |
70 |
private final String uri; |
48 |
424 |
private Socket socket; |
49 |
422 |
private OutputStream output; |
50 |
691 |
private InputStream input; |
51 |
642 |
private final Map headers = new HashMap(); |
52 |
96 |
Connection(URL pURL) { |
53 |
96 |
hostname = pURL.getHost(); |
54 |
96 |
int p = pURL.getPort(); |
55 |
96 |
port = p < 1 ? 80 : p; |
56 |
96 |
String u = pURL.getFile(); |
57 |
96 |
uri = (u == null || "".equals(u)) ? "/" : u; |
58 |
96 |
host = port == 80 ? hostname : hostname + ":" + port; |
59 |
96 |
headers.put("Host", host); |
60 |
96 |
} |
61 |
|
} |
62 |
|
|
63 |
96 |
private final String userAgent = super.getUserAgent() + " (Lite HTTP Transport)"; |
64 |
|
|
65 |
|
|
66 |
|
|
67 |
|
|
68 |
|
public XmlRpcLiteHttpTransport(XmlRpcClient pClient) { |
69 |
96 |
super(pClient); |
70 |
96 |
} |
71 |
|
|
72 |
96 |
protected String getUserAgent() { return userAgent; } |
73 |
|
|
74 |
|
protected void setRequestHeader(Object pConnection, String pHeader, |
75 |
|
String pValue) { |
76 |
238 |
Connection conn = (Connection) pConnection; |
77 |
238 |
Object value = conn.headers.get(pHeader); |
78 |
238 |
if (value == null) { |
79 |
238 |
conn.headers.put(pHeader, pValue); |
80 |
|
} else { |
81 |
|
List list; |
82 |
0 |
if (value instanceof String) { |
83 |
0 |
list = new ArrayList(); |
84 |
0 |
list.add(value); |
85 |
0 |
conn.headers.put(pHeader, list); |
86 |
|
} else { |
87 |
0 |
list = (List) value; |
88 |
|
} |
89 |
0 |
list.add(pValue); |
90 |
|
} |
91 |
238 |
} |
92 |
|
|
93 |
|
protected boolean isResponseGzipCompressed( |
94 |
|
XmlRpcStreamRequestConfig pConfig, Object pConnection) { |
95 |
|
|
96 |
70 |
return false; |
97 |
|
} |
98 |
|
|
99 |
|
protected Object newConnection(XmlRpcStreamRequestConfig pConfig) |
100 |
|
throws XmlRpcClientException { |
101 |
96 |
return new Connection(((XmlRpcHttpClientConfig) pConfig).getServerURL()); |
102 |
|
} |
103 |
|
|
104 |
|
protected void closeConnection(Object pConnection) |
105 |
|
throws XmlRpcClientException { |
106 |
96 |
Connection conn = (Connection) pConnection; |
107 |
96 |
IOException e = null; |
108 |
96 |
if (conn.input != null) { |
109 |
|
try { |
110 |
70 |
conn.input.close(); |
111 |
0 |
} catch (IOException ex) { |
112 |
0 |
e = ex; |
113 |
|
} |
114 |
|
} |
115 |
96 |
if (conn.output != null) { |
116 |
|
try { |
117 |
70 |
conn.output.close(); |
118 |
24 |
} catch (IOException ex) { |
119 |
24 |
if (e != null) { |
120 |
0 |
e = ex; |
121 |
|
} |
122 |
|
} |
123 |
|
} |
124 |
96 |
if (conn.socket != null) { |
125 |
|
try { |
126 |
70 |
conn.socket.close(); |
127 |
0 |
} catch (IOException ex) { |
128 |
0 |
if (e != null) { |
129 |
0 |
e = ex; |
130 |
|
} |
131 |
|
} |
132 |
|
} |
133 |
96 |
if (e != null) { |
134 |
0 |
throw new XmlRpcClientException("Failed to close connection: " + e.getMessage(), e); |
135 |
|
} |
136 |
96 |
} |
137 |
|
|
138 |
|
protected OutputStream newOutputStream(XmlRpcStreamRequestConfig pConfig, |
139 |
|
Object pConnection) throws XmlRpcClientException { |
140 |
24 |
final Connection conn = (Connection) pConnection; |
141 |
24 |
final int retries = 3; |
142 |
24 |
final int delayMillis = 100; |
143 |
|
|
144 |
24 |
for (int tries = 0; ; tries++) { |
145 |
|
try { |
146 |
24 |
conn.socket = new Socket(conn.hostname, conn.port); |
147 |
24 |
conn.output = new BufferedOutputStream(conn.socket.getOutputStream()){ |
148 |
|
|
149 |
|
|
150 |
|
|
151 |
|
|
152 |
|
|
153 |
|
public void close() throws IOException { |
154 |
48 |
flush(); |
155 |
48 |
conn.socket.shutdownOutput(); |
156 |
24 |
} |
157 |
|
}; |
158 |
24 |
sendRequestHeaders(conn, conn.output); |
159 |
24 |
return conn.output; |
160 |
0 |
} catch (ConnectException e) { |
161 |
0 |
if (tries >= retries) { |
162 |
0 |
throw new XmlRpcClientException("Failed to connect to " + conn.host + ": " + e.getMessage(), e); |
163 |
|
} else { |
164 |
|
try { |
165 |
0 |
Thread.sleep(delayMillis); |
166 |
0 |
} catch (InterruptedException ignore) { |
167 |
|
} |
168 |
|
} |
169 |
0 |
} catch (IOException e) { |
170 |
0 |
throw new XmlRpcClientException("Failed to connect to " + conn.host + ": " + e.getMessage(), e); |
171 |
|
} |
172 |
|
} |
173 |
|
} |
174 |
|
|
175 |
|
private byte[] toHTTPBytes(String pValue) throws UnsupportedEncodingException { |
176 |
326 |
return pValue.getBytes("US-ASCII"); |
177 |
|
} |
178 |
|
|
179 |
|
private void sendHeader(OutputStream pOut, String pKey, String pValue) throws IOException { |
180 |
256 |
pOut.write(toHTTPBytes(pKey + ": " + pValue + "\r\n")); |
181 |
256 |
} |
182 |
|
|
183 |
|
private void sendRequestHeaders(Connection pConnection, |
184 |
|
OutputStream pOut) throws IOException { |
185 |
70 |
pOut.write(("POST " + pConnection.uri + " HTTP/1.0\r\n").getBytes("US-ASCII")); |
186 |
396 |
for (Iterator iter = pConnection.headers.entrySet().iterator(); iter.hasNext(); ) { |
187 |
256 |
Map.Entry entry = (Map.Entry) iter.next(); |
188 |
256 |
String key = (String) entry.getKey(); |
189 |
256 |
Object value = entry.getValue(); |
190 |
256 |
if (value instanceof String) { |
191 |
256 |
sendHeader(pOut, key, (String) value); |
192 |
|
} else { |
193 |
0 |
List list = (List) value; |
194 |
0 |
for (int i = 0; i < list.size(); i++) { |
195 |
0 |
sendHeader(pOut, key, (String) list.get(i)); |
196 |
|
} |
197 |
|
} |
198 |
|
} |
199 |
70 |
pOut.write(toHTTPBytes("\r\n")); |
200 |
70 |
} |
201 |
|
|
202 |
|
protected InputStream newInputStream(XmlRpcStreamRequestConfig pConfig, |
203 |
|
Object pConnection, |
204 |
|
byte[] pContent) throws XmlRpcException { |
205 |
|
try { |
206 |
46 |
Connection conn = (Connection) pConnection; |
207 |
46 |
conn.socket = new Socket(conn.hostname, conn.port); |
208 |
46 |
conn.output = new BufferedOutputStream(conn.socket.getOutputStream()); |
209 |
46 |
sendRequestHeaders(conn, conn.output); |
210 |
46 |
conn.output.write(pContent); |
211 |
46 |
conn.output.flush(); |
212 |
0 |
} catch (IOException e) { |
213 |
0 |
throw new XmlRpcClientException("Failed to send request to sender: " + e.getMessage(), e); |
214 |
|
} |
215 |
46 |
return newInputStream(pConfig, pConnection); |
216 |
|
} |
217 |
|
|
218 |
|
protected InputStream newInputStream(XmlRpcStreamRequestConfig pConfig, |
219 |
|
Object pConnection) throws XmlRpcException { |
220 |
70 |
Connection conn = (Connection) pConnection; |
221 |
70 |
final byte[] buffer = new byte[2048]; |
222 |
|
try { |
223 |
70 |
conn.input = new BufferedInputStream(conn.socket.getInputStream()); |
224 |
|
|
225 |
70 |
String line = HttpUtil.readLine(conn.input, buffer); |
226 |
70 |
StringTokenizer tokens = new StringTokenizer(line); |
227 |
70 |
tokens.nextToken(); |
228 |
70 |
String statusCode = tokens.nextToken(); |
229 |
70 |
String statusMsg = tokens.nextToken("\n\r"); |
230 |
70 |
if (! "200".equals(statusCode)) { |
231 |
0 |
throw new IOException("Unexpected Response from Server: " |
232 |
0 |
+ statusMsg); |
233 |
|
} |
234 |
70 |
int contentLength = -1; |
235 |
245 |
for (;;) { |
236 |
315 |
line = HttpUtil.readLine(conn.input, buffer); |
237 |
315 |
if (line == null || "".equals(line)) { |
238 |
70 |
break; |
239 |
|
} |
240 |
245 |
line = line.toLowerCase(); |
241 |
245 |
if (line.startsWith("content-length:")) { |
242 |
35 |
contentLength = Integer.parseInt(line.substring("content-length:".length()).trim()); |
243 |
|
} |
244 |
|
} |
245 |
|
InputStream result; |
246 |
70 |
if (contentLength == -1) { |
247 |
35 |
result = conn.input; |
248 |
|
} else { |
249 |
35 |
result = new LimitedInputStream(conn.input, contentLength); |
250 |
|
} |
251 |
70 |
return result; |
252 |
0 |
} catch (IOException e) { |
253 |
0 |
throw new XmlRpcClientException("Failed to read server response: " + e.getMessage(), e); |
254 |
|
} |
255 |
|
} |
256 |
|
} |