[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] r10451: Server-side support for If-Modified-Since in HTTP requsts fo (in tor/trunk: . src/common src/or)



Author: nickm
Date: 2007-06-02 11:26:57 -0400 (Sat, 02 Jun 2007)
New Revision: 10451

Modified:
   tor/trunk/
   tor/trunk/ChangeLog
   tor/trunk/src/common/util.c
   tor/trunk/src/common/util.h
   tor/trunk/src/or/directory.c
   tor/trunk/src/or/dirserv.c
   tor/trunk/src/or/or.h
Log:
 r13154@catbus:  nickm | 2007-06-02 11:26:44 -0400
 Server-side support for If-Modified-Since in HTTP requsts for v1 stuff, and for network-status documents.



Property changes on: tor/trunk
___________________________________________________________________
 svk:merge ticket from /tor/trunk [r13154] on 8246c3cf-6607-4228-993b-4d95d33730f1

Modified: tor/trunk/ChangeLog
===================================================================
--- tor/trunk/ChangeLog	2007-06-02 15:26:54 UTC (rev 10450)
+++ tor/trunk/ChangeLog	2007-06-02 15:26:57 UTC (rev 10451)
@@ -3,6 +3,12 @@
     - Fix an assertion failure related to servers without extra-info digests.
       Resolves bugs 441 and 442.
 
+  o Minor features (directory):
+    - Support "If-Modified-Since" when answering HTTP requests for
+      directories, running-routers documents, and network-status documents.
+      (There's no need to support it for router descriptors, since those
+      are downloaded by descriptor digest.)
+
   o Minor build issues:
     - Clear up some MIPSPro compiler warnings.
 

Modified: tor/trunk/src/common/util.c
===================================================================
--- tor/trunk/src/common/util.c	2007-06-02 15:26:54 UTC (rev 10450)
+++ tor/trunk/src/common/util.c	2007-06-02 15:26:57 UTC (rev 10451)
@@ -1127,6 +1127,64 @@
   return 0;
 }
 
+/** Given a <b>date</b> in one of the three formats allowed by HTTP (ugh),
+ * parse it into <b>tm</b>.  Return 0 on success, negative on failure. */
+int
+parse_http_time(const char *date, struct tm *tm)
+{
+  const char *cp;
+  char month[4];
+  char wkday[4];
+  int i;
+
+  tor_assert(tm);
+  memset(tm, 0, sizeof(*tm));
+
+  /* First, try RFC1123 or RFC850 format: skip the weekday.  */
+  if ((cp = strchr(date, ','))) {
+    ++cp;
+    if (sscanf(date, "%2d %3s %4d %2d:%2d:%2d GMT",
+               &tm->tm_mday, month, &tm->tm_year,
+               &tm->tm_hour, &tm->tm_min, &tm->tm_sec) == 6) {
+      /* rfc1123-date */
+      tm->tm_year -= 1900;
+    } else if (sscanf(date, "%2d-%3s-%2d %2d:%2d:%2d GMT",
+                      &tm->tm_mday, month, &tm->tm_year,
+                      &tm->tm_hour, &tm->tm_min, &tm->tm_sec) == 6) {
+      /* rfc850-date */
+    } else {
+      return -1;
+    }
+  } else {
+    /* No comma; possibly asctime() format. */
+    if (sscanf(date, "%3s %3s %2d %2d:%2d:%2d %4d",
+               wkday, month, &tm->tm_mday,
+               &tm->tm_hour, &tm->tm_min, &tm->tm_sec, &tm->tm_year) == 7) {
+      tm->tm_year -= 1900;
+    } else {
+      return -1;
+    }
+  }
+
+  month[4] = '\0';
+  /* Okay, now decode the month. */
+  for (i = 0; i < 12; ++i) {
+    if (!strcasecmp(MONTH_NAMES[i], month)) {
+      tm->tm_mon = i+1;
+    }
+  }
+
+  if (tm->tm_year < 0 ||
+      tm->tm_mon < 1  || tm->tm_mon > 12 ||
+      tm->tm_mday < 0 || tm->tm_mday > 31 ||
+      tm->tm_hour < 0 || tm->tm_hour > 23 ||
+      tm->tm_min < 0  || tm->tm_min > 59 ||
+      tm->tm_sec < 0  || tm->tm_sec > 61)
+    return -1; /* Out of range, or bad month. */
+
+  return 0;
+}
+
 /* =====
  * File helpers
  * ===== */

Modified: tor/trunk/src/common/util.h
===================================================================
--- tor/trunk/src/common/util.h	2007-06-02 15:26:54 UTC (rev 10450)
+++ tor/trunk/src/common/util.h	2007-06-02 15:26:57 UTC (rev 10451)
@@ -198,6 +198,7 @@
 void format_local_iso_time(char *buf, time_t t);
 void format_iso_time(char *buf, time_t t);
 int parse_iso_time(const char *buf, time_t *t);
+int parse_http_time(const char *buf, struct tm *tm);
 
 /* File helpers */
 int write_all(int fd, const char *buf, size_t count, int isSocket);

Modified: tor/trunk/src/or/directory.c
===================================================================
--- tor/trunk/src/or/directory.c	2007-06-02 15:26:54 UTC (rev 10450)
+++ tor/trunk/src/or/directory.c	2007-06-02 15:26:57 UTC (rev 10451)
@@ -1633,9 +1633,11 @@
                              const char *body, size_t body_len)
 {
   size_t dlen;
-  const char *cp;
   char *url = NULL;
   or_options_t *options = get_options();
+  time_t if_modified_since = 0;
+  char *header;
+
   /* We ignore the body of a GET request. */
   (void)body;
   (void)body_len;
@@ -1648,6 +1650,15 @@
     write_http_status_line(conn, 400, "Bad request");
     return 0;
   }
+  if ((header = http_get_header(headers, "If-Modified-Since: "))) {
+    struct tm tm;
+    if (parse_http_time(header, &tm) == 0) {
+      if_modified_since = tor_timegm(&tm);
+    }
+    /* The correct behavior on a malformed If-Modified-Since header is to
+     * act as if no If-Modified-Since header had been given. */
+    tor_free(header);
+  }
   log_debug(LD_DIRSERV,"rewritten url as '%s'.", url);
 
   if (!strcmp(url,"/tor/") || !strcmp(url,"/tor/dir.z")) { /* dir fetch */
@@ -1664,6 +1675,12 @@
       tor_free(url);
       return 0;
     }
+    if (d->published < if_modified_since) {
+      write_http_status_line(conn, 304, "Not modified");
+      tor_free(url);
+      return 0;
+    }
+
     dlen = deflated ? d->dir_z_len : d->dir_len;
 
     if (global_write_bucket_low(TO_CONN(conn), dlen, 1)) {
@@ -1699,8 +1716,8 @@
   if (!strcmp(url,"/tor/running-routers") ||
       !strcmp(url,"/tor/running-routers.z")) { /* running-routers fetch */
     int deflated = !strcmp(url,"/tor/running-routers.z");
-    dlen = dirserv_get_runningrouters(&cp, deflated);
-    if (!dlen) { /* we failed to create/cache cp */
+    cached_dir_t *d = dirserv_get_runningrouters();
+    if (!d) {
       write_http_status_line(conn, 503, "Directory unavailable");
       /* try to get a new one now */
       if (!already_fetching_directory(DIR_PURPOSE_FETCH_RUNNING_LIST))
@@ -1708,6 +1725,13 @@
       tor_free(url);
       return 0;
     }
+    if (d->published < if_modified_since) {
+      write_http_status_line(conn, 304, "Not modified");
+      tor_free(url);
+      return 0;
+    }
+    dlen = deflated ? d->dir_z_len : d->dir_len;
+
     if (global_write_bucket_low(TO_CONN(conn), dlen, 1)) {
       log_info(LD_DIRSERV,
                "Client asked for running-routers, but we've been "
@@ -1722,7 +1746,7 @@
                  deflated?"application/octet-stream":"text/plain",
                  deflated?"deflate":"identity",
                  RUNNINGROUTERS_CACHE_LIFETIME);
-    connection_write_to_buf(cp, strlen(cp), TO_CONN(conn));
+    connection_write_to_buf(deflated ? d->dir_z : d->dir, dlen, TO_CONN(conn));
     return 0;
   }
 
@@ -1751,6 +1775,12 @@
       smartlist_free(dir_fps);
       return 0;
     }
+    if (dirserv_statuses_are_old(dir_fps, if_modified_since)) {
+      write_http_status_line(conn, 304, "Not modified");
+      smartlist_free(dir_fps);
+      return 0;
+    }
+
     dlen = dirserv_estimate_data_size(dir_fps, 0, deflated);
     if (global_write_bucket_low(TO_CONN(conn), dlen, 2)) {
       log_info(LD_DIRSERV,

Modified: tor/trunk/src/or/dirserv.c
===================================================================
--- tor/trunk/src/or/dirserv.c	2007-06-02 15:26:54 UTC (rev 10450)
+++ tor/trunk/src/or/dirserv.c	2007-06-02 15:26:57 UTC (rev 10451)
@@ -1279,6 +1279,7 @@
   }
 }
 
+#if 0
 /** Helper: If we're authoritative and <b>auth_src</b> is set, use
  * <b>auth_src</b>, otherwise use <b>cache_src</b>.  If we're using
  * <b>auth_src</b> and it's been <b>dirty</b> for at least
@@ -1313,6 +1314,7 @@
     return 0;
   }
 }
+#endif
 
 /** Return the most recently generated encoded signed v1 directory,
  * generating a new one as necessary.  If not a v1 authoritative directory
@@ -1418,10 +1420,10 @@
 /** Set *<b>rr</b> to the most recently generated encoded signed
  * running-routers list, generating a new one as necessary.  Return the
  * size of the directory on success, and 0 on failure. */
-size_t
-dirserv_get_runningrouters(const char **rr, int compress)
+cached_dir_t *
+dirserv_get_runningrouters(void)
 {
-  return dirserv_get_obj(rr, compress,
+  return dirserv_pick_cached_dir_obj(
                          &cached_runningrouters, &the_runningrouters,
                          runningrouters_is_dirty,
                          generate_runningrouters,
@@ -2247,6 +2249,25 @@
     ctr = (ctr + 1) % 128;
 }
 
+/** Return true iff every networkstatus listed in <b>fps</b> is older
+ * than <b>cutoff</b>. */
+int
+dirserv_statuses_are_old(smartlist_t *fps, time_t cutoff)
+{
+  SMARTLIST_FOREACH(fps, const char *, digest,
+  {
+    cached_dir_t *d;
+    if (router_digest_is_me(digest) && the_v2_networkstatus)
+      d = the_v2_networkstatus;
+    else
+      d = digestmap_get(cached_v2_networkstatus, digest);
+    if (d && d->published > cutoff)
+      return 0;
+  });
+
+  return 1;
+}
+
 /** Return an approximate estimate of the number of bytes that will
  * be needed to transmit the server descriptors (if is_serverdescs --
  * they can be either d/ or fp/ queries) or networkstatus objects (if

Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h	2007-06-02 15:26:54 UTC (rev 10450)
+++ tor/trunk/src/or/or.h	2007-06-02 15:26:57 UTC (rev 10451)
@@ -2670,7 +2670,7 @@
                                      int complete);
 void directory_set_dirty(void);
 cached_dir_t *dirserv_get_directory(void);
-size_t dirserv_get_runningrouters(const char **rr, int compress);
+cached_dir_t *dirserv_get_runningrouters(void);
 void dirserv_set_cached_directory(const char *directory, time_t when,
                                   int is_running_routers);
 void dirserv_set_cached_networkstatus_v2(const char *directory,
@@ -2693,6 +2693,7 @@
 int authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg,
                                    int complain);
 int dirserv_would_reject_router(routerstatus_t *rs);
+int dirserv_statuses_are_old(smartlist_t *fps, time_t cutoff);
 size_t dirserv_estimate_data_size(smartlist_t *fps, int is_serverdescs,
                                   int compressed);
 int routerstatus_format_entry(char *buf, size_t buf_len,