- Moved the dtstart,dtend fixing to icalUtilities so it can be called from updateFrom...
[jgroupdav.git] / src / main / java / net / bionicmessage / groupdav / Common.java
bloba253252ead6e074180d473d81e7b1dcf5491d066
1 /* BionicMessage.net Java GroupDAV library V1.0
2 * groupDAV.java
4 * Created on Friday 23rd May 2008
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
25 package net.bionicmessage.groupdav;
27 import java.io.BufferedInputStream;
28 import java.io.BufferedReader;
29 import java.io.InputStream;
30 import java.io.InputStreamReader;
31 import java.io.UnsupportedEncodingException;
32 import java.net.MalformedURLException;
33 import java.net.Socket;
34 import java.net.URL;
35 import java.util.Iterator;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.logging.Logger;
39 import javax.net.SocketFactory;
40 import javax.net.ssl.SSLContext;
41 import javax.net.ssl.TrustManager;
42 import javax.net.ssl.X509TrustManager;
44 /**
46 * @author matt
48 public class Common {
50 static SocketFactory ssf = null;
51 public static // Create a trust manager that does not validate certificate chains
52 TrustManager[] trustAllCerts = new TrustManager[]{
53 new X509TrustManager() {
55 public java.security.cert.X509Certificate[] getAcceptedIssuers() {
56 return null;
59 public void checkClientTrusted(
60 java.security.cert.X509Certificate[] certs, String authType) {
63 public void checkServerTrusted(
64 java.security.cert.X509Certificate[] certs, String authType) {
69 public static byte[] buildQuery(String method,
70 URL fullURL,
71 byte[] data,
72 Map headers,
73 groupDAV parent)
74 throws UnsupportedEncodingException {
75 StringBuffer buf = new StringBuffer();
76 buf.append(method).append(" ");
77 buf.append(fullURL.getPath());
78 buf.append(" HTTP/1.1\r\n");
79 buf.append("Host: ");
80 buf.append(fullURL.getHost());
81 if (fullURL.getPort() != -1) {
82 buf.append(":").append(fullURL.getPort());
84 buf.append("\r\nConnection: close\r\n");
85 buf.append(parent.getBase64cache()).append("\r\n");
86 buf.append("User-Agent: ").append(groupDAV.USER_AGENT).append("\r\n");
87 if (headers != null) {
88 Iterator headerIt = headers.keySet().iterator();
89 while (headerIt.hasNext()) {
90 String key = (String) headerIt.next();
91 String value = (String) headers.get(key);
92 buf.append(key).append(": ").append(value);
93 buf.append("\r\n");
96 List<HTTPCookie> cookies = parent.getCookieJar();
97 if (cookies.size() > 0) {
98 buf.append("Cookie: ");
99 for (HTTPCookie c : cookies) {
100 buf.append(c.getCookieString());
102 buf.append("\r\n");
104 if ("PUT".equals(method) || "REPORT".equals(method) || "PROPFIND".equals(method)) {
105 buf.append("Content-Length: ").append(data.length);
106 buf.append("\r\n");
108 buf.append("\r\n");
109 byte[] headers_content = buf.toString().getBytes("UTF-8");
110 byte[] fulldata = new byte[headers_content.length + data.length];
111 System.arraycopy(headers_content, 0, fulldata, 0, headers_content.length);
112 System.arraycopy(data, 0, fulldata, headers_content.length, data.length);
113 return fulldata;
116 public static URL createURL(String path,
117 URL serverURL) throws MalformedURLException {
118 String newPath = path;
119 if (path.startsWith("http://") || path.startsWith("https://")) {
120 return new URL(path);
121 } // Don't muck with full URLs
122 // Clean path of: leading slash, etc.
124 if (path.startsWith("/")) {
125 newPath = path.substring(1);
127 newPath = newPath.replace("//", "/");
128 return new URL(serverURL, newPath);
131 public static Socket createSocket(URL url) throws Exception {
132 int port = url.getPort();
133 if (url.getProtocol().contains("https")) {
134 if (port == -1) {
135 port = 443;
137 if (ssf == null) {
138 try {
139 SSLContext sc = SSLContext.getInstance("SSL");
140 sc.init(null, Common.trustAllCerts, new java.security.SecureRandom());
141 ssf = sc.getSocketFactory();
142 } catch (Exception e) {
143 System.err.println("Error configuration SSL cert manager");
144 e.printStackTrace();
147 return ssf.createSocket(url.getHost(), port);
148 } else {
149 if (port == -1) {
150 port = 80;
152 return new Socket(url.getHost(), port);
156 public static HTTPInputStream sendNonKeepAliveRequest(URL srv,
157 byte[] data) throws Exception {
158 int port = srv.getPort();
159 if (port == -1) {
160 port = 80;
162 Socket st = createSocket(srv);
163 st.getOutputStream().write(data);
164 HTTPInputStream is = new HTTPInputStream(st);
165 return is;
168 public static String sendNonKeepAliveRequest(
169 URL server,
170 byte[] by,
171 groupDAV parent,
172 Logger l) throws Exception {
173 String dbugstring = new String(by);
174 String loggableString = dbugstring.replace(parent.getBase64cache(), "Authorization: Basic [removed]");
175 l.fine("We sent:\r\n" + loggableString);
176 // Measure latency
177 long time = new java.util.Date().getTime();
178 Socket st = createSocket(server);
179 st.setSoTimeout(15*1000);
180 st.getOutputStream().write(by);
181 st.getOutputStream().flush();
182 InputStream sc = st.getInputStream();
183 BufferedInputStream bis = new BufferedInputStream(sc);
185 StringBuffer sb = new StringBuffer();
186 int op = 0;
187 int fouls = 0;
188 /* In rare-rare cases some non-printable chars have contaminated the
189 * response we get. Here is a good place to get rid of them */
191 // We need to process the message character by chacter instead of byte by byte
192 // or otherwise 2-4 byte characters (many Unicode characters) get stripped away.
193 // To do this, we use the InputStreamReader class to convert byte stream into
194 // an Unicode character stream.
195 BufferedReader charstream = new BufferedReader(new InputStreamReader(bis, "UTF-8"));
197 while (op != -1) {
198 char[] buf = new char[300];
199 op = charstream.read(buf);
200 if (op != 0 && op != -1) {
201 for (int i = 0; i < op; i++) {
202 char c = buf[i];
203 // Strip bytes which would foul an XML parser, i.e SIF
204 // for Funambol upstream. See
205 // http://cse-mjmcl.cse.bris.ac.uk/blog/2007/02/14/1171465494443.html
206 if ((c == 0x9) ||
207 (c == 0xA) ||
208 (c == 0xD) ||
209 ((c >= 0x20) && (c <= 0xD7FF)) ||
210 ((c >= 0xE000) && (c <= 0xFFFD)) ||
211 ((c >= 0x10000) && (c <= 0x10FFFF))) {
212 sb.append(c);
213 } else {
214 fouls++;
220 if (fouls > 0) {
221 l.fine(fouls + " invalid (XML-wise) characters detected in stream. Is the source/users clean?");
223 charstream.close();
224 bis.close();
225 long closetime = new java.util.Date().getTime();
226 long rtt = closetime - time;
227 l.finer("We got:\r\n" + sb.toString() + "\r\n....in " + rtt + "ms");
228 return sb.toString();