|  | @@ -1675,6 +1675,7 @@ directory_send_command(dir_connection_t *conn,
 | 
	
		
			
				|  |  |    const char *payload = req->payload;
 | 
	
		
			
				|  |  |    const size_t payload_len = req->payload_len;
 | 
	
		
			
				|  |  |    const time_t if_modified_since = req->if_modified_since;
 | 
	
		
			
				|  |  | +  const int anonymized_connection = dirind_is_anon(req->indirection);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    char proxystring[256];
 | 
	
		
			
				|  |  |    char hoststring[128];
 | 
	
	
		
			
				|  | @@ -1740,11 +1741,13 @@ directory_send_command(dir_connection_t *conn,
 | 
	
		
			
				|  |  |      proxystring[0] = 0;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /* Add Accept-Encoding. */
 | 
	
		
			
				|  |  | -  accept_encoding = accept_encoding_header();
 | 
	
		
			
				|  |  | -  smartlist_add_asprintf(headers, "Accept-Encoding: %s\r\n",
 | 
	
		
			
				|  |  | -                         accept_encoding);
 | 
	
		
			
				|  |  | -  tor_free(accept_encoding);
 | 
	
		
			
				|  |  | +  if (! anonymized_connection) {
 | 
	
		
			
				|  |  | +    /* Add Accept-Encoding. */
 | 
	
		
			
				|  |  | +    accept_encoding = accept_encoding_header();
 | 
	
		
			
				|  |  | +    smartlist_add_asprintf(headers, "Accept-Encoding: %s\r\n",
 | 
	
		
			
				|  |  | +                           accept_encoding);
 | 
	
		
			
				|  |  | +    tor_free(accept_encoding);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* Add additional headers, if any */
 | 
	
		
			
				|  |  |    {
 | 
	
	
		
			
				|  | @@ -2199,8 +2202,8 @@ static int handle_response_upload_renddesc_v2(dir_connection_t *,
 | 
	
		
			
				|  |  |  static int
 | 
	
		
			
				|  |  |  connection_dir_client_reached_eof(dir_connection_t *conn)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -  char *body;
 | 
	
		
			
				|  |  | -  char *headers;
 | 
	
		
			
				|  |  | +  char *body = NULL;
 | 
	
		
			
				|  |  | +  char *headers = NULL;
 | 
	
		
			
				|  |  |    char *reason = NULL;
 | 
	
		
			
				|  |  |    size_t body_len = 0;
 | 
	
		
			
				|  |  |    int status_code;
 | 
	
	
		
			
				|  | @@ -2209,10 +2212,15 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
 | 
	
		
			
				|  |  |    compress_method_t compression;
 | 
	
		
			
				|  |  |    int plausible;
 | 
	
		
			
				|  |  |    int skewed = 0;
 | 
	
		
			
				|  |  | +  int rv;
 | 
	
		
			
				|  |  |    int allow_partial = (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
 | 
	
		
			
				|  |  |                         conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO ||
 | 
	
		
			
				|  |  |                         conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC);
 | 
	
		
			
				|  |  |    size_t received_bytes;
 | 
	
		
			
				|  |  | +  const int anonymized_connection =
 | 
	
		
			
				|  |  | +    purpose_needs_anonymity(conn->base_.purpose,
 | 
	
		
			
				|  |  | +                            conn->router_purpose,
 | 
	
		
			
				|  |  | +                            conn->requested_resource);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    received_bytes = connection_get_inbuf_len(TO_CONN(conn));
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -2236,8 +2244,9 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
 | 
	
		
			
				|  |  |                            &compression, &reason) < 0) {
 | 
	
		
			
				|  |  |      log_warn(LD_HTTP,"Unparseable headers (server '%s:%d'). Closing.",
 | 
	
		
			
				|  |  |               conn->base_.address, conn->base_.port);
 | 
	
		
			
				|  |  | -    tor_free(body); tor_free(headers);
 | 
	
		
			
				|  |  | -    return -1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    rv = -1;
 | 
	
		
			
				|  |  | +    goto done;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    if (!reason) reason = tor_strdup("[no reason given]");
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -2311,8 +2320,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
 | 
	
		
			
				|  |  |      if ((ds = router_get_fallback_dirserver_by_digest(id_digest)))
 | 
	
		
			
				|  |  |        ds->fake_status.last_dir_503_at = now;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    tor_free(body); tor_free(headers); tor_free(reason);
 | 
	
		
			
				|  |  | -    return -1;
 | 
	
		
			
				|  |  | +    rv = -1;
 | 
	
		
			
				|  |  | +    goto done;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    plausible = body_is_plausible(body, body_len, conn->base_.purpose);
 | 
	
	
		
			
				|  | @@ -2340,13 +2349,29 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
 | 
	
		
			
				|  |  |                 description2,
 | 
	
		
			
				|  |  |                 (compression>0 && guessed>0)?"  Trying both.":"");
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      /* Try declared compression first if we can.
 | 
	
		
			
				|  |  | -     * tor_compress_supports_method() also returns true for NO_METHOD. */
 | 
	
		
			
				|  |  | +     * tor_compress_supports_method() also returns true for NO_METHOD.
 | 
	
		
			
				|  |  | +     * Ensure that the server is not sending us data compressed using a
 | 
	
		
			
				|  |  | +     * compression method that is not allowed for anonymous connections. */
 | 
	
		
			
				|  |  | +    if (anonymized_connection &&
 | 
	
		
			
				|  |  | +        ! allowed_anonymous_connection_compression_method(compression)) {
 | 
	
		
			
				|  |  | +      rv = -1;
 | 
	
		
			
				|  |  | +      goto done;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      if (tor_compress_supports_method(compression))
 | 
	
		
			
				|  |  |        tor_uncompress(&new_body, &new_len, body, body_len, compression,
 | 
	
		
			
				|  |  |                       !allow_partial, LOG_PROTOCOL_WARN);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      /* Okay, if that didn't work, and we think that it was compressed
 | 
	
		
			
				|  |  |       * differently, try that. */
 | 
	
		
			
				|  |  | +    if (anonymized_connection &&
 | 
	
		
			
				|  |  | +        ! allowed_anonymous_connection_compression_method(guessed)) {
 | 
	
		
			
				|  |  | +      rv = -1;
 | 
	
		
			
				|  |  | +      goto done;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      if (!new_body && tor_compress_supports_method(guessed) &&
 | 
	
		
			
				|  |  |          compression != guessed)
 | 
	
		
			
				|  |  |        tor_uncompress(&new_body, &new_len, body, body_len, guessed,
 | 
	
	
		
			
				|  | @@ -2357,8 +2382,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
 | 
	
		
			
				|  |  |        log_fn(LOG_PROTOCOL_WARN, LD_HTTP,
 | 
	
		
			
				|  |  |               "Unable to decompress HTTP body (server '%s:%d').",
 | 
	
		
			
				|  |  |               conn->base_.address, conn->base_.port);
 | 
	
		
			
				|  |  | -      tor_free(body); tor_free(headers); tor_free(reason);
 | 
	
		
			
				|  |  | -      return -1;
 | 
	
		
			
				|  |  | +      rv = -1;
 | 
	
		
			
				|  |  | +      goto done;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      if (new_body) {
 | 
	
		
			
				|  |  |        tor_free(body);
 | 
	
	
		
			
				|  | @@ -2367,7 +2392,6 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  int rv;
 | 
	
		
			
				|  |  |    response_handler_args_t args;
 | 
	
		
			
				|  |  |    memset(&args, 0, sizeof(args));
 | 
	
		
			
				|  |  |    args.status_code = status_code;
 | 
	
	
		
			
				|  | @@ -2416,6 +2440,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
 | 
	
		
			
				|  |  |        rv = -1;
 | 
	
		
			
				|  |  |        break;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | + done:
 | 
	
		
			
				|  |  |    tor_free(body);
 | 
	
		
			
				|  |  |    tor_free(headers);
 | 
	
		
			
				|  |  |    tor_free(reason);
 | 
	
	
		
			
				|  | @@ -3331,6 +3357,14 @@ static compress_method_t srv_meth_pref_streaming_compression[] = {
 | 
	
		
			
				|  |  |    NO_METHOD
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/** Array of allowed compression methods to use (if supported) when receiving a
 | 
	
		
			
				|  |  | + * response from a request that was required to be anonymous. */
 | 
	
		
			
				|  |  | +static compress_method_t client_meth_allowed_anonymous_compression[] = {
 | 
	
		
			
				|  |  | +  ZLIB_METHOD,
 | 
	
		
			
				|  |  | +  GZIP_METHOD,
 | 
	
		
			
				|  |  | +  NO_METHOD
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /** Parse the compression methods listed in an Accept-Encoding header <b>h</b>,
 | 
	
		
			
				|  |  |   * and convert them to a bitfield where compression method x is supported if
 | 
	
		
			
				|  |  |   * and only if 1 << x is set in the bitfield. */
 | 
	
	
		
			
				|  | @@ -3830,6 +3864,29 @@ find_best_compression_method(unsigned compression_methods, int stream)
 | 
	
		
			
				|  |  |    return NO_METHOD;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/** Check if the given compression method is allowed for a connection that is
 | 
	
		
			
				|  |  | + * supposed to be anonymous. Returns 1 if the compression method is allowed,
 | 
	
		
			
				|  |  | + * otherwise 0. */
 | 
	
		
			
				|  |  | +STATIC int
 | 
	
		
			
				|  |  | +allowed_anonymous_connection_compression_method(compress_method_t method)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  unsigned u;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  for (u = 0; u < ARRAY_LENGTH(client_meth_allowed_anonymous_compression);
 | 
	
		
			
				|  |  | +       ++u) {
 | 
	
		
			
				|  |  | +    compress_method_t allowed_method =
 | 
	
		
			
				|  |  | +      client_meth_allowed_anonymous_compression[u];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (! tor_compress_supports_method(allowed_method))
 | 
	
		
			
				|  |  | +      continue;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (method == allowed_method)
 | 
	
		
			
				|  |  | +      return 1;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /** Encodes the results of parsing a consensus request to figure out what
 | 
	
		
			
				|  |  |   * consensus, and possibly what diffs, the user asked for. */
 | 
	
		
			
				|  |  |  typedef struct {
 |