Home | History | Annotate | Download | only in utility
      1 // Copyright 2013 Google Inc. All Rights Reserved.
      2 
      3 package com.android.exchange.utility;
      4 
      5 import android.os.Build;
      6 import android.util.Base64;
      7 import android.util.Log;
      8 
      9 import com.android.exchange.Eas;
     10 
     11 import org.apache.http.Header;
     12 import org.apache.http.HttpEntity;
     13 import org.apache.http.HttpEntityEnclosingRequest;
     14 import org.apache.http.HttpRequest;
     15 import org.apache.http.HttpRequestInterceptor;
     16 import org.apache.http.client.methods.HttpUriRequest;
     17 import org.apache.http.impl.client.RequestWrapper;
     18 import org.apache.http.protocol.HttpContext;
     19 
     20 import java.io.ByteArrayOutputStream;
     21 import java.io.IOException;
     22 import java.net.URI;
     23 
     24 /**
     25  * Logs cURL commands equivalent to requests.
     26  * Curl Logging is copied over from AndroidHttpClient. Just switching to AndroidHttpClient is
     27  * not trivial so it's easier to borrow the curl logging code this way.
     28  */
     29 public class CurlLogger implements HttpRequestInterceptor {
     30     private static final String TAG = Eas.LOG_TAG;
     31 
     32     @Override
     33     public void process(HttpRequest request, HttpContext context) throws IOException {
     34         if (request instanceof HttpUriRequest) {
     35             if ((Build.TYPE.equals("userdebug") || Build.TYPE.equals("eng"))
     36                     &&  Log.isLoggable(TAG, Log.VERBOSE)) {
     37                 // Allow us to log auth token on dev devices - this is not a big security risk
     38                 // because dev devices have a readable account.db file where all the auth tokens
     39                 // are stored.
     40                 Log.d(TAG, toCurl((HttpUriRequest) request, true));
     41             } else  if (Log.isLoggable(TAG, Log.DEBUG)) {
     42                 Log.d(TAG, toCurl((HttpUriRequest) request, false));
     43             }
     44         }
     45     }
     46 
     47     /**
     48      * Generates a cURL command equivalent to the given request.
     49      */
     50     private static String toCurl(HttpUriRequest request, boolean logAuthToken) throws IOException {
     51         StringBuilder builder = new StringBuilder();
     52 
     53         builder.append("curl ");
     54 
     55         for (Header header: request.getAllHeaders()) {
     56             builder.append("--header \"");
     57             if (!logAuthToken
     58                     && (header.getName().equals("Authorization") ||
     59                     header.getName().equals("Cookie"))) {
     60 
     61                 builder.append(header.getName()).append(": ").append("${token}");
     62             } else {
     63                 builder.append(header.toString().trim());
     64             }
     65             builder.append("\" ");
     66         }
     67 
     68         URI uri = request.getURI();
     69 
     70         // If this is a wrapped request, use the URI from the original
     71         // request instead. getURI() on the wrapper seems to return a
     72         // relative URI. We want an absolute URI.
     73         if (request instanceof RequestWrapper) {
     74             HttpRequest original = ((RequestWrapper) request).getOriginal();
     75             if (original instanceof HttpUriRequest) {
     76                 uri = ((HttpUriRequest) original).getURI();
     77             }
     78         }
     79 
     80         builder.append("\"");
     81         builder.append(uri);
     82         builder.append("\"");
     83 
     84         if (request instanceof HttpEntityEnclosingRequest) {
     85             HttpEntityEnclosingRequest entityRequest =
     86                     (HttpEntityEnclosingRequest) request;
     87             HttpEntity entity = entityRequest.getEntity();
     88             if (entity != null && entity.isRepeatable()) {
     89                 if (entity.getContentLength() < 1024) {
     90                     ByteArrayOutputStream stream = new ByteArrayOutputStream();
     91                     entity.writeTo(stream);
     92 
     93                     String base64 = Base64.encodeToString(stream.toByteArray(), Base64.NO_WRAP);
     94                     builder.insert(0, "echo '" + base64 + "' | base64 -d > /tmp/$$.bin; ");
     95                     builder.append(" --data-binary @/tmp/$$.bin");
     96                 } else {
     97                     builder.append(" [TOO MUCH DATA TO INCLUDE]");
     98                 }
     99             }
    100         }
    101 
    102         return builder.toString();
    103     }
    104 
    105 }
    106