| /* |
| * Copyright 2011 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package com.google.web.bindery.requestfactory.vm.testing; |
| |
| import com.google.web.bindery.requestfactory.shared.RequestFactory; |
| import com.google.web.bindery.requestfactory.shared.RequestTransport; |
| import com.google.web.bindery.requestfactory.shared.ServerFailure; |
| |
| import org.json.Cookie; |
| import org.json.JSONException; |
| import org.json.JSONObject; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.net.HttpURLConnection; |
| import java.net.URL; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.zip.GZIPInputStream; |
| import java.util.zip.InflaterInputStream; |
| |
| /** |
| * A trivial implementation of RequestTransport that uses a |
| * {@link HttpURLConnection}. Details of the connection can be amended by |
| * overriding {@link #configureConnection(HttpURLConnection)}. |
| * <p> |
| * This implementation only supports {@code http} and {@code https} URLs. It has |
| * primitive support for recording and playing back cookies, but does not |
| * implement expiration processing. |
| * <p> |
| * Developers who wish to build a more production-ready client should consider |
| * using a RequestTRansport based around Apache HttpClient instead. |
| */ |
| public class UrlRequestTransport implements RequestTransport { |
| private static final int CONNECT_TIMEOUT = 30000; |
| private static final int READ_TIMEOUT = 60000; |
| |
| private final Map<String, String> cookies = new HashMap<String, String>(); |
| private final URL url; |
| |
| /** |
| * Construct a new UrlRequestTransport. |
| * |
| * @param url the URL to connect to |
| * @throws IllegalArgumentException if the url's protocol is not {@code http} |
| * or {@code https} |
| */ |
| public UrlRequestTransport(URL url) { |
| this.url = url; |
| String proto = url.getProtocol().toLowerCase(); |
| if (!proto.equals("http") && !proto.equals("https")) { |
| throw new IllegalArgumentException("Only http and https URLs supported"); |
| } |
| } |
| |
| /** |
| * Provides access to the cookies that will be sent for subsequent requests. |
| */ |
| public Map<String, String> getCookies() { |
| return cookies; |
| } |
| |
| @Override |
| public void send(String payload, TransportReceiver receiver) { |
| HttpURLConnection connection = null; |
| try { |
| connection = (HttpURLConnection) url.openConnection(); |
| configureConnection(connection); |
| |
| OutputStream out = connection.getOutputStream(); |
| out.write(payload.getBytes("UTF-8")); |
| out.close(); |
| |
| int status = connection.getResponseCode(); |
| if (status != HttpURLConnection.HTTP_OK) { |
| ServerFailure failure = new ServerFailure(status + " " + connection.getResponseMessage()); |
| receiver.onTransportFailure(failure); |
| return; |
| } |
| |
| List<String> cookieHeaders = connection.getHeaderFields().get("Set-Cookie"); |
| if (cookieHeaders != null) { |
| for (String header : cookieHeaders) { |
| try { |
| JSONObject cookie = Cookie.toJSONObject(header); |
| String name = cookie.getString("name"); |
| String value = cookie.getString("value"); |
| String domain = cookie.optString("Domain"); |
| if (domain == null || url.getHost().endsWith(domain)) { |
| String path = cookie.optString("Path"); |
| if (path == null || url.getPath().startsWith(path)) { |
| cookies.put(name, value); |
| } |
| } |
| } catch (JSONException ignored) { |
| } |
| } |
| } |
| |
| String encoding = connection.getContentEncoding(); |
| InputStream in = connection.getInputStream(); |
| if ("gzip".equalsIgnoreCase(encoding)) { |
| in = new GZIPInputStream(in); |
| } else if ("deflate".equalsIgnoreCase(encoding)) { |
| in = new InflaterInputStream(in); |
| } else if (encoding != null) { |
| receiver.onTransportFailure(new ServerFailure("Unknown server encoding " + encoding)); |
| return; |
| } |
| |
| ByteArrayOutputStream bytes = new ByteArrayOutputStream(); |
| byte[] buffer = new byte[4096]; |
| int read = in.read(buffer); |
| while (read != -1) { |
| bytes.write(buffer, 0, read); |
| read = in.read(buffer); |
| } |
| in.close(); |
| |
| String received = new String(bytes.toByteArray(), "UTF-8"); |
| receiver.onTransportSuccess(received); |
| } catch (IOException e) { |
| ServerFailure failure = new ServerFailure(e.getMessage(), e.getClass().getName(), null, true); |
| receiver.onTransportFailure(failure); |
| } finally { |
| if (connection != null) { |
| connection.disconnect(); |
| } |
| } |
| } |
| |
| protected void configureConnection(HttpURLConnection connection) throws IOException { |
| connection.setDoInput(true); |
| connection.setDoOutput(true); |
| connection.setRequestMethod("POST"); |
| connection.setUseCaches(false); |
| connection.setRequestProperty("Accept-Encoding", "gzip, deflate"); |
| connection.setRequestProperty("Content-Type", RequestFactory.JSON_CONTENT_TYPE_UTF8); |
| connection.setRequestProperty("Host", url.getHost()); |
| connection.setRequestProperty("User-Agent", UrlRequestTransport.class.getCanonicalName()); |
| connection.setConnectTimeout(CONNECT_TIMEOUT); |
| connection.setReadTimeout(READ_TIMEOUT); |
| |
| if (!cookies.isEmpty()) { |
| StringBuilder sb = new StringBuilder(); |
| boolean needsSemi = false; |
| for (Map.Entry<String, String> entry : cookies.entrySet()) { |
| if (needsSemi) { |
| sb.append("; "); |
| } else { |
| needsSemi = true; |
| } |
| sb.append(entry.getKey()).append("=").append(entry.getValue()); |
| } |
| connection.setRequestProperty("Cookie", sb.toString()); |
| } |
| } |
| } |