Support mocking HTTP requests out for testing. Essentially you register URLs to mock, and the URL to direct to instead. (Generally this would be a local HTTP server.) It can't be mocked to a file URL because we cast to HttpURLConnection in places, but it can be built to not hit eBay. by mrs, 08 Nov, 2009 09:24 AM
Diff this changeset:
CookieJar.java
cyberfox 1   package com.jbidwatcher.util.http;
cyberfox 2   /*
cyberfox 3    * Copyright (c) 2000-2007, CyberFOX Software, Inc. All Rights Reserved.
cyberfox 4    *
cyberfox 5    * Developed by mrs (Morgan Schweers)
cyberfox 6    */
cyberfox 7   
mrs      8   import com.jbidwatcher.util.config.JConfig;
cyberfox 9   
cyberfox 10  import java.net.*;
cyberfox 11  import java.util.*;
cyberfox 12  import java.io.IOException;
cyberfox 13  
cyberfox 14  public class CookieJar {
mrs      15    private Map<String, Cookie> mCookies;
mrs      16    private boolean mIgnoreRedirectCookies = false;
mrs      17    private final static boolean sUberDebug = false;
cyberfox 18  
cyberfox 19    public CookieJar() {
mrs      20      mCookies = new TreeMap<String, Cookie>();
cyberfox 21    }
cyberfox 22  
cyberfox 23    public Cookie getCookie(String keyName) {
mrs      24      return mCookies.get(keyName);
cyberfox 25    }
cyberfox 26  
mrs      27    public String dump() {
mrs      28      StringBuffer rval = new StringBuffer();
mrs      29      for(String cookieName : mCookies.keySet()) {
mrs      30        Cookie value = mCookies.get(cookieName);
mrs      31        rval.append(cookieName).append(": ").append(value.getValue()).append('\n');
mrs      32      }
mrs      33      return rval.toString();
cyberfox 34    }
cyberfox 35  
mrs      36    public static class CookieException extends Exception {
mrs      37      public CookieException(String text, Throwable trigger) {
mrs      38        super(text, trigger);
mrs      39      }
cyberfox 40    }
cyberfox 41  
mrs      42    public static class CookieRedirectException extends RuntimeException {
mrs      43      public CookieRedirectException(String text, Throwable trigger) {
mrs      44        super(text, trigger);
mrs      45      }
mrs      46    }
mrs      47  
cyberfox 48    /**
cyberfox 49     * Get all the cookies and the page data itself, using post or get.
cyberfox 50     *
mrs      51     * @param page     - The URL to retrieve.
mrs      52     * @param body     - The body of the POST to send, if we want to do a POST operation.
cyberfox 53     * @param referer  - The URL that referred us to this page (can be null).
cyberfox 54     * @return - A StringBuffer containing the data at the provided URL, or returned from the POST operation.
cyberfox 55     *
cyberfox 56     * @throws com.jbidwatcher.util.http.CookieJar.CookieException - If the connection is refused.
cyberfox 57     */
mrs      58    public StringBuffer getPage(String page, String body, String referer) throws CookieException {
mrs      59      URLConnection uc = connect(page, body, referer, body != null, null);
cyberfox 60      if(uc == null) return null;
cyberfox 61  
cyberfox 62      StringBuffer sb = null;
cyberfox 63  
cyberfox 64      try {
mrs      65        sb = Http.net().receivePage(uc);
cyberfox 66      } catch(ConnectException ce) {
mrs      67        logException(page, ce);
cyberfox 68        if(ce.toString().indexOf("Connection refused") != -1) {
cyberfox 69          throw new CookieException("Connection refused", ce);
cyberfox 70        }
cyberfox 71      } catch(IOException e) {
mrs      72        logException(page, e);
cyberfox 73        return null;
cyberfox 74      }
cyberfox 75  
cyberfox 76      return sb;
cyberfox 77    }
cyberfox 78  
cyberfox 79    private void logException(String pageName, Exception e) {
cyberfox 80      int qLoc = pageName.indexOf('?');
cyberfox 81  
mrs      82      String errmsg = "Error loading page: ";
cyberfox 83      if(qLoc == -1) {
cyberfox 84        errmsg += pageName;
cyberfox 85      } else {
cyberfox 86        errmsg += pageName.substring(0,qLoc);
cyberfox 87      }
mrs      88      JConfig.log().handleException(errmsg, e);
cyberfox 89    }
cyberfox 90  
cyberfox 91    /**
cyberfox 92     * Retrieve any cookies from the provided page via GET or POST, but only return
cyberfox 93     * the URLConnection letting the caller do what they want to with it.
cyberfox 94     *
mrs      95     * @param page - The page to load.
cyberfox 96     * @return - A URLConnection connected to the response from the server for the given request.
cyberfox 97     */
mrs      98    public URLConnection connect(String page) {
mrs      99      return connect(page, null, null, false, null);
cyberfox 100   }
cyberfox 101 
mrs      102   private Map<String, Integer> mRedirections;
mrs      103 
mrs      104   public URLConnection connect(String page, String body, String referer, boolean post, List<String> pages) {
mrs      105     URLConnection rval;
mrs      106     mRedirections = new HashMap<String, Integer>();
mrs      107     rval = internal_connect(page, body, referer, post, pages);
mrs      108     mRedirections = null;
mrs      109     return rval;
mrs      110   }
mrs      111 
mrs      112   private URLConnection internal_connect(String page, String body, String referer, boolean post, List<String> pages) {
mrs      113     if(handleInfiniteRedirection(page)) {
mrs      114       //  If we're posting, and we hit an infloop, maybe we don't want to re-submit the data...
mrs      115       if(post) {
mrs      116         post = false;
mrs      117         body = null;
mrs      118       } else {
mrs      119         throw new CookieRedirectException("Looped redirect to " + page, null);
mrs      120       }
mrs      121     }
mrs      122 
mrs      123     if(pages != null) pages.add(page);
cyberfox 124 
mrs      125     HttpURLConnection uc = initiateRequest(post, page, body, referer);
cyberfox 126 
cyberfox 127     if(uc != null) {
mrs      128       String redirect = handleRedirect(uc, page);
cyberfox 129 
cyberfox 130       if(redirect != null) {
mrs      131         if (JConfig.debugging()) {
mrs      132           //  Don't log passwords in redirection messages.
mrs      133           if(!page.contains("pass")) JConfig.log().logMessage("Redirecting from: " + page);
mrs      134           if(!page.contains("pass")) JConfig.log().logMessage("Redirecting to: " + redirect);
mrs      135           try {
mrs      136             if(JConfig.queryConfiguration("debug.urls", "false").equals("true")) {
mrs      137               JConfig.log().logMessage("Content: " + Http.net().receivePage(uc));
mrs      138             }
mrs      139           } catch (IOException ignored) {
mrs      140             //  If there's no content or it's an unrecognized type, ignore it.
mrs      141           }
cyberfox 142         }
mrs      143 
mrs      144         return internal_connect(redirect, body, referer, post, pages);
cyberfox 145       }
cyberfox 146     }
cyberfox 147 
cyberfox 148     return uc;
cyberfox 149   }
cyberfox 150 
mrs      151   private boolean handleInfiniteRedirection(String page) {
mrs      152     Integer pageCount = mRedirections.get(page);
mrs      153     if(pageCount == null) pageCount = 0;
mrs      154     if(pageCount >= 2) return true;
mrs      155     mRedirections.put(page, pageCount+1);
mrs      156     return false;
mrs      157   }
mrs      158 
cyberfox 159   private String handleRedirect(HttpURLConnection uc, String pageName) {
cyberfox 160     int i = 1;
cyberfox 161     String redirect = null;
cyberfox 162     String nextKey;
cyberfox 163     do {
cyberfox 164       nextKey = uc.getHeaderFieldKey(i);
cyberfox 165       if(nextKey != null) {
mrs      166         if(sUberDebug) {
mrs      167           JConfig.log().logDebug(nextKey+": " + uc.getHeaderField(i));
cyberfox 168         }
cyberfox 169         //  If we're redirected, shortcut to loading the new page.
cyberfox 170         if(nextKey.startsWith("Location") ||
cyberfox 171            nextKey.startsWith("location")) {
cyberfox 172           redirect = uc.getHeaderField(i);
cyberfox 173           redirect = stripQuotedAmpersands(redirect);
cyberfox 174           if(!redirect.startsWith("http")) {
cyberfox 175             redirect = fixRelativeRedirect(pageName, redirect);
cyberfox 176           }
cyberfox 177         }
cyberfox 178 
cyberfox 179         if(nextKey.startsWith("Set-Cookie") ||
cyberfox 180            nextKey.startsWith("Set-cookie")) {
cyberfox 181           Cookie newCookie = new Cookie(uc.getHeaderField(i));
mrs      182           mCookies.put(newCookie.getKey(), newCookie);
cyberfox 183         }
cyberfox 184       }
cyberfox 185       i++;
cyberfox 186     } while(nextKey != null);
cyberfox 187     return redirect;
cyberfox 188   }
cyberfox 189 
cyberfox 190   private String fixRelativeRedirect(String pageName, String redirect) {
cyberfox 191     String slash = "";
cyberfox 192     int serverEnd = pageName.indexOf(".com/");
cyberfox 193     if(!redirect.startsWith("/")) {
cyberfox 194       slash = "/";
cyberfox 195     }
mrs      196     String prefix;
cyberfox 197     if(serverEnd == -1) {
cyberfox 198       prefix = pageName;
cyberfox 199     } else {
cyberfox 200       prefix = pageName.substring(0, serverEnd+4);
cyberfox 201     }
cyberfox 202     redirect = prefix + slash + redirect;
cyberfox 203     return redirect;
cyberfox 204   }
cyberfox 205 
cyberfox 206   private String stripQuotedAmpersands(String redirect) {
cyberfox 207     int amploc = redirect.indexOf("&amp;");
cyberfox 208 
cyberfox 209     while(amploc != -1) {
cyberfox 210       redirect = redirect.substring(0, amploc) + "&" +
cyberfox 211                  redirect.substring(amploc+5);
cyberfox 212       amploc = redirect.indexOf("&amp;");
cyberfox 213     }
cyberfox 214     return redirect;
cyberfox 215   }
cyberfox 216 
cyberfox 217   private HttpURLConnection initiateRequest(boolean post, String sendRequest, String cgi, String referer) {
mrs      218     URLConnection uc;
mrs      219     String cookies = mCookies.isEmpty() ? null : this.toString();
cyberfox 220 
mrs      221     if(post) {
mrs      222       uc = Http.net().postFormPage(sendRequest, cgi, cookies, referer, mIgnoreRedirectCookies);
cyberfox 223     } else {
mrs      224       uc = Http.net().getPage(sendRequest, cookies, referer, mIgnoreRedirectCookies);
cyberfox 225     }
mrs      226 
mrs      227     return (HttpURLConnection)uc;
cyberfox 228   }
cyberfox 229 
cyberfox 230   public String toString() {
cyberfox 231     boolean firstThrough = true;
cyberfox 232     StringBuffer outBuf = null;
cyberfox 233 
mrs      234     for (Cookie cookie : mCookies.values()) {
mrs      235       if (cookie.getValue().length() != 0) {
cyberfox 236         if (!firstThrough) {
cyberfox 237           outBuf.append("; ");
cyberfox 238         } else {
cyberfox 239           firstThrough = false;
cyberfox 240           outBuf = new StringBuffer();
cyberfox 241         }
mrs      242         outBuf.append(cookie.getKey());
cyberfox 243         outBuf.append("=");
mrs      244         outBuf.append(cookie.getValue());
cyberfox 245       }
cyberfox 246     }
cyberfox 247 
cyberfox 248     if(outBuf != null) {
cyberfox 249       return outBuf.toString();
cyberfox 250     } else {
cyberfox 251       return null;
cyberfox 252     }
cyberfox 253   }
cyberfox 254 }

Check out the code: svn co jbidwatcher/trunk/src/com/jbidwatcher/util/http/CookieJar.java