public static CacheControl getCacheControl(IHttpHeaders headers, long requestTime)
 {
     CacheControl cc=new CacheControl();
     bool proxyRevalidate=false;
     int sMaxAge=0;
     bool publicCache=false;
     bool privateCache=false;
     bool noCache=false;
     long expires=0;
     bool hasExpires=false;
     cc.uri=headers.getUrl();
     string cacheControl=headers.getHeaderField("cache-control");
     if(cacheControl!=null){
       int index=0;
       int[] intval=new int[1];
       while(index<cacheControl.Length){
     int current=index;
     if((index=HeaderParser.parseToken(cacheControl,current,"private",true))!=current){
       privateCache=true;
     } else if((index=HeaderParser.parseToken(cacheControl,current,"no-cache",true))!=current){
       noCache=true;
       //Console.WriteLine("returning early because it saw no-cache");
       return null; // return immediately, this is not cacheable
     } else if((index=HeaderParser.parseToken(
     cacheControl,current,"no-store",false))!=current){
       cc.noStore=true;
       //Console.WriteLine("returning early because it saw no-store");
       return null; // return immediately, this is not cacheable or storable
     } else if((index=HeaderParser.parseToken(
     cacheControl,current,"public",false))!=current){
       publicCache=true;
     } else if((index=HeaderParser.parseToken(
     cacheControl,current,"no-transform",false))!=current){
       cc.noTransform=true;
     } else if((index=HeaderParser.parseToken(
     cacheControl,current,"must-revalidate",false))!=current){
       cc.mustRevalidate=true;
     } else if((index=HeaderParser.parseToken(
     cacheControl,current,"proxy-revalidate",false))!=current){
       proxyRevalidate=true;
     } else if((index=HeaderParser.parseTokenWithDelta(
     cacheControl,current,"max-age",intval))!=current){
       cc.maxAge=intval[0];
     } else if((index=HeaderParser.parseTokenWithDelta(
     cacheControl,current,"s-maxage",intval))!=current){
       sMaxAge=intval[0];
     } else {
       index=HeaderParser.skipDirective(cacheControl,current);
     }
       }
       if(!publicCache && !privateCache && !noCache){
     noCache=true;
       }
     } else {
       int code=headers.getResponseCode();
       if((code==200 || code==203 || code==300 || code==301 || code==410) &&
       headers.getHeaderField("authorization")==null){
     publicCache=true;
     privateCache=false;
       } else {
     noCache=true;
       }
     }
     if(headers.getResponseCode()==206) {
       noCache=true;
     }
     string pragma=headers.getHeaderField("pragma");
     if(pragma!=null && "no-cache".Equals(StringUtility.toLowerCaseAscii(pragma))){
       noCache=true;
       //Console.WriteLine("returning early because it saw pragma no-cache");
       return null;
     }
     long now=DateTimeUtility.getCurrentDate();
     cc.code=headers.getResponseCode();
     cc.date=now;
     cc.responseTime=now;
     cc.requestTime=requestTime;
     if(proxyRevalidate){
       // Enable must-revalidate for simplicity;
       // proxyRevalidate usually only applies to shared caches
       cc.mustRevalidate=true;
     }
     if(headers.getHeaderField("date")!=null){
       cc.date=headers.getHeaderFieldDate("date",Int64.MinValue);
       if(cc.date==Int64.MinValue) {
     noCache=true;
       }
     } else {
       noCache=true;
     }
     string expiresHeader=headers.getHeaderField("expires");
     if(expiresHeader!=null){
       expires=headers.getHeaderFieldDate("expires",Int64.MinValue);
       hasExpires=(cc.date!=Int64.MinValue);
     }
     if(headers.getHeaderField("age")!=null){
       try {
     cc.age=Int32.Parse(headers.getHeaderField("age"),NumberStyles.AllowLeadingSign,CultureInfo.InvariantCulture);
     if(cc.age<0) {
       cc.age=0;
     }
       } catch(FormatException){
     cc.age=-1;
       }
     }
     if(cc.maxAge>0 || sMaxAge>0){
       long maxAge=cc.maxAge; // max age in seconds
       if(maxAge==0) {
     maxAge=sMaxAge;
       }
       if(cc.maxAge>0 && sMaxAge>0){
     maxAge=Math.Max(cc.maxAge,sMaxAge);
       }
       cc.maxAge=maxAge*1000L; // max-age and s-maxage are in seconds
       hasExpires=false;
     } else if(hasExpires && !noCache){
       long maxAge=expires-cc.date;
       cc.maxAge=(maxAge>Int32.MaxValue) ? Int32.MaxValue : (int)maxAge;
     } else if(noCache || cc.noStore){
       cc.maxAge=0;
     } else {
       cc.maxAge=24L*3600L*1000L;
     }
     string reqmethod=headers.getRequestMethod();
     if(reqmethod==null || (
     !StringUtility.toLowerCaseAscii(reqmethod).Equals("get")))
       // caching responses other than GET responses not supported
       return null;
     cc.requestMethod=StringUtility.toLowerCaseAscii(reqmethod);
     cc.cacheability=2;
     if(noCache) {
       cc.cacheability=0;
     } else if(privateCache) {
       cc.cacheability=1;
     }
     int i=0;
     cc.headers.Add(headers.getHeaderField(null));
     while(true){
       string newValue=headers.getHeaderField(i);
       if(newValue==null) {
     break;
       }
       string key=headers.getHeaderFieldKey(i);
       i++;
       if(key==null){
     //Console.WriteLine("null key");
     continue;
       }
       key=StringUtility.toLowerCaseAscii(key);
       // to simplify matters, don't include Age header fields;
       // so-called hop-by-hop headers are also not included
       if(!"age".Equals(key) &&
       !"connection".Equals(key) &&
       !"keep-alive".Equals(key) &&
       !"proxy-authenticate".Equals(key) &&
       !"proxy-authorization".Equals(key) &&
       !"te".Equals(key) &&
       !"trailer".Equals(key) && // NOTE: NOT Trailers
       !"transfer-encoding".Equals(key) &&
       !"upgrade".Equals(key)){
     cc.headers.Add(key);
     cc.headers.Add(newValue);
       }
     }
     //Console.WriteLine(" cc: %s",cc);
     return cc;
 }