1 package com.cooliris.picasa;
3 import java.io.ByteArrayOutputStream;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.util.zip.GZIPInputStream;
7 import java.util.zip.GZIPOutputStream;
9 import org.apache.http.Header;
10 import org.apache.http.HttpEntity;
11 import org.apache.http.HttpResponse;
12 import org.apache.http.client.methods.HttpGet;
13 import org.apache.http.client.methods.HttpPost;
14 import org.apache.http.client.methods.HttpUriRequest;
15 import org.apache.http.client.params.HttpClientParams;
16 import org.apache.http.conn.scheme.PlainSocketFactory;
17 import org.apache.http.conn.scheme.Scheme;
18 import org.apache.http.conn.scheme.SchemeRegistry;
19 import org.apache.http.entity.ByteArrayEntity;
20 import org.apache.http.entity.InputStreamEntity;
21 import org.apache.http.impl.client.DefaultHttpClient;
22 import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
23 import org.apache.http.params.BasicHttpParams;
24 import org.apache.http.params.HttpConnectionParams;
25 import org.apache.http.params.HttpParams;
26 import org.apache.http.params.HttpProtocolParams;
28 import android.text.TextUtils;
29 import android.util.Log;
31 public final class GDataClient {
32 private static final String TAG = "GDataClient";
33 private static final String USER_AGENT = "Cooliris-GData/1.0; gzip";
34 private static final String X_HTTP_METHOD_OVERRIDE = "X-HTTP-Method-Override";
35 private static final String IF_MATCH = "If-Match";
36 private static final int CONNECTION_TIMEOUT = 20000; // ms.
37 private static final int MIN_GZIP_SIZE = 512;
38 public static final HttpParams HTTP_PARAMS;
39 public static final ThreadSafeClientConnManager HTTP_CONNECTION_MANAGER;
41 private final DefaultHttpClient mHttpClient = new DefaultHttpClient(HTTP_CONNECTION_MANAGER, HTTP_PARAMS);
42 private String mAuthToken;
45 // Prepare HTTP parameters.
46 HttpParams params = new BasicHttpParams();
47 HttpConnectionParams.setStaleCheckingEnabled(params, false);
48 HttpConnectionParams.setConnectionTimeout(params, CONNECTION_TIMEOUT);
49 HttpConnectionParams.setSoTimeout(params, CONNECTION_TIMEOUT);
50 HttpClientParams.setRedirecting(params, true);
51 HttpProtocolParams.setUserAgent(params, USER_AGENT);
54 // Register HTTP protocol.
55 SchemeRegistry schemeRegistry = new SchemeRegistry();
56 schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
58 // Create the connection manager.
59 HTTP_CONNECTION_MANAGER = new ThreadSafeClientConnManager(params, schemeRegistry);
62 public static final class Operation {
63 public String inOutEtag;
65 public InputStream outBody;
68 public void setAuthToken(String authToken) {
69 mAuthToken = authToken;
72 public void get(String feedUrl, Operation operation) throws IOException {
73 callMethod(new HttpGet(feedUrl), operation);
76 public void post(String feedUrl, byte[] data, String contentType, Operation operation) throws IOException {
77 ByteArrayEntity entity = getCompressedEntity(data);
78 entity.setContentType(contentType);
79 HttpPost post = new HttpPost(feedUrl);
80 post.setEntity(entity);
81 callMethod(post, operation);
84 public void put(String feedUrl, byte[] data, String contentType, Operation operation) throws IOException {
85 ByteArrayEntity entity = getCompressedEntity(data);
86 entity.setContentType(contentType);
87 HttpPost post = new HttpPost(feedUrl);
88 post.setHeader(X_HTTP_METHOD_OVERRIDE, "PUT");
89 post.setEntity(entity);
90 callMethod(post, operation);
93 public void putStream(String feedUrl, InputStream stream, String contentType, Operation operation) throws IOException {
94 InputStreamEntity entity = new InputStreamEntity(stream, -1);
95 entity.setContentType(contentType);
96 HttpPost post = new HttpPost(feedUrl);
97 post.setHeader(X_HTTP_METHOD_OVERRIDE, "PUT");
98 post.setEntity(entity);
99 callMethod(post, operation);
102 public void delete(String feedUrl, Operation operation) throws IOException {
103 HttpPost post = new HttpPost(feedUrl);
104 String etag = operation.inOutEtag;
105 post.setHeader(X_HTTP_METHOD_OVERRIDE, "DELETE");
106 post.setHeader(IF_MATCH, etag != null ? etag : "*");
107 callMethod(post, operation);
110 private void callMethod(HttpUriRequest request, Operation operation) throws IOException {
111 // Specify GData protocol version 2.0.
112 request.addHeader("GData-Version", "2");
114 // Indicate support for gzip-compressed responses.
115 request.addHeader("Accept-Encoding", "gzip");
117 // Specify authorization token if provided.
118 String authToken = mAuthToken;
119 if (!TextUtils.isEmpty(authToken)) {
120 request.addHeader("Authorization", "GoogleLogin auth=" + authToken);
123 // Specify the ETag of a prior response, if available.
124 String etag = operation.inOutEtag;
126 request.addHeader("If-None-Match", etag);
129 // Execute the HTTP request.
130 HttpResponse httpResponse = null;
132 httpResponse = mHttpClient.execute(request);
133 } catch (IOException e) {
134 Log.w(TAG, "Request failed: " + request.getURI());
138 // Get the status code and response body.
139 int status = httpResponse.getStatusLine().getStatusCode();
140 InputStream stream = null;
141 HttpEntity entity = httpResponse.getEntity();
142 if (entity != null) {
143 // Wrap the entity input stream in a GZIP decoder if necessary.
144 stream = entity.getContent();
145 if (stream != null) {
146 Header header = entity.getContentEncoding();
147 if (header != null) {
148 if (header.getValue().contains("gzip")) {
149 stream = new GZIPInputStream(stream);
155 // Return the stream if successful.
156 Header etagHeader = httpResponse.getFirstHeader("ETag");
157 operation.outStatus = status;
158 operation.inOutEtag = etagHeader != null ? etagHeader.getValue() : null;
159 operation.outBody = stream;
162 private ByteArrayEntity getCompressedEntity(byte[] data) throws IOException {
163 ByteArrayEntity entity;
164 if (data.length >= MIN_GZIP_SIZE) {
165 ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(data.length / 2);
166 GZIPOutputStream gzipOutput = new GZIPOutputStream(byteOutput);
167 gzipOutput.write(data);
169 entity = new ByteArrayEntity(byteOutput.toByteArray());
171 entity = new ByteArrayEntity(data);
176 public static String inputStreamToString(InputStream stream) {
177 if (stream != null) {
179 ByteArrayOutputStream bytes = new ByteArrayOutputStream();
180 byte[] buffer = new byte[4096];
182 while ((bytesRead = stream.read(buffer)) != -1) {
183 bytes.write(buffer, 0, bytesRead);
185 return new String(bytes.toString());
186 } catch (IOException e) {
187 // Fall through and return null.