public void handleRequest(HttpRequest req) {
		HttpRequestHeader hdr = (HttpRequestHeader) req.getHeader();
		if (Cache.isCachable(hdr)) {
			CachableHttpObject obj = proxy.cache.get(hdr);
			if (obj == null) {
				// object not in cache
				try {
					obj = new CachableHttpObject(hdr, proxy);
					obj.setCache(proxy.cache);
					obj.setModified(new Date(System.currentTimeMillis()));
					new TransferHandler(conn, obj).run();
					proxy.cache.put(hdr.getURL(), obj);
				} catch (HttpException httpe) { 
					// Response other than 200 OK
					try {
						new TransferHandler(conn, httpe.getResponse()).run();
						proxy.releaseConnection(httpe.getResponse().getConnection());
						conn.close();
					} catch (IOException e) { }
					return;
				} catch (IOException ioe) { 
					proxy.logger.warning(ioe.getMessage());
					return;
				}
			} else {
				// object in cache
				// check if client's cache is consistent.
				String modified = hdr.getHeader("If-Modified-Since");
				if (modified != null) {
					SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDateInstance();
					df.applyPattern("EEE, d MMM yyyy HH:mm:ss z");
					Date dmod = null;
					try {
							dmod = df.parse(modified);
					} catch (ParseException e) { 
						proxy.logger.warning(e.toString());
					}

					if (obj.getLastModified().after(dmod)) {
						// cache is not consistent so transfer the cached object
						new TransferHandler(conn, obj).run();
					} else  {
						// send a 304 Not Modified Response
						handleNotModified();
					}
				} else { 
					new TransferHandler(conn, obj).run();
				}
			}
		} else {
			tunnelRequest(req);
		}
	}