Browse Source

Handle non-compressed requests gracefully.

This patch makes us use FALLBACK_COMPRESS_METHOD to try to fetch an
object from the consensus diff manager in case no mutually supported
result was found. This object, if found, is then decompressed using the
spooling system to the client.

See: https://bugs.torproject.org/21667
Alexander Færøy 7 years ago
parent
commit
008194035f
1 changed files with 30 additions and 3 deletions
  1. 30 3
      src/or/directory.c

+ 30 - 3
src/or/directory.c

@@ -3677,6 +3677,13 @@ parse_or_diff_from_header(smartlist_t **digests_out, const char *headers)
   return 0;
 }
 
+/** Fallback compression method.  The fallback compression method is used in
+ * case a client requests a non-compressed document. We only store compressed
+ * documents, so we use this compression method to fetch the document and let
+ * the spooling system do the streaming decompression.
+ */
+#define FALLBACK_COMPRESS_METHOD ZLIB_METHOD
+
 /**
  * Try to find the best consensus diff possible in order to serve a client
  * request for a diff from one of the consensuses in <b>digests</b> to the
@@ -3706,6 +3713,16 @@ find_best_diff(const smartlist_t *digests, int flav,
       }
     }
   } SMARTLIST_FOREACH_END(diff_from);
+
+  SMARTLIST_FOREACH_BEGIN(digests, const uint8_t *, diff_from) {
+    if (consdiffmgr_find_diff_from(&result, flav, DIGEST_SHA3_256, diff_from,
+          DIGEST256_LEN, FALLBACK_COMPRESS_METHOD) == CONSDIFF_AVAILABLE) {
+      tor_assert_nonfatal(result);
+      *compression_used_out = FALLBACK_COMPRESS_METHOD;
+      return result;
+    }
+  } SMARTLIST_FOREACH_END(diff_from);
+
   return NULL;
 }
 
@@ -3735,6 +3752,13 @@ find_best_consensus(int flav,
     }
   }
 
+  if (consdiffmgr_find_consensus(&result, flav,
+        FALLBACK_COMPRESS_METHOD) == CONSDIFF_AVAILABLE) {
+    tor_assert_nonfatal(result);
+    *compression_used_out = FALLBACK_COMPRESS_METHOD;
+    return result;
+  }
+
   return NULL;
 }
 
@@ -3911,12 +3935,15 @@ handle_get_current_consensus(dir_connection_t *conn,
   }
 
   clear_spool = 0;
+
+  // The compress_method might have been NO_METHOD, but we store the data
+  // compressed. Decompress them using `compression_used`. See fallback code in
+  // find_best_consensus() and find_best_diff().
   write_http_response_header(conn, -1,
-                             compression_used,
+                             compress_method == NO_METHOD ?
+                               NO_METHOD : compression_used,
                              smartlist_len(conn->spool) == 1 ? lifetime : 0);
 
-  // The compress_method requested was NO_METHOD, but we store the data
-  // compressed. Decompress them using `compression_used`.
   if (compress_method == NO_METHOD)
     conn->compress_state = tor_compress_new(0, compression_used,
                                             HIGH_COMPRESSION);