|  | @@ -2161,9 +2161,10 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (!strcmpstart(url,"/tor/status-vote/current/") ||
 | 
	
		
			
				|  |  |        !strcmpstart(url,"/tor/status-vote/next/")) {
 | 
	
		
			
				|  |  | -    /*XXXX020 implement if-modified-since and 503-rate-limiting */
 | 
	
		
			
				|  |  | +    /*XXXX020 implement if-modified-since */
 | 
	
		
			
				|  |  |      int current = 1;
 | 
	
		
			
				|  |  |      ssize_t body_len = 0;
 | 
	
		
			
				|  |  | +    ssize_t estimated_len = 0;
 | 
	
		
			
				|  |  |      smartlist_t *items = smartlist_create();
 | 
	
		
			
				|  |  |      smartlist_t *dir_items = smartlist_create();
 | 
	
		
			
				|  |  |      int lifetime = 60; /* XXXX020 should actually use vote intervals. */
 | 
	
	
		
			
				|  | @@ -2211,13 +2212,24 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      if (!smartlist_len(dir_items) && !smartlist_len(items)) {
 | 
	
		
			
				|  |  |        write_http_status_line(conn, 404, "Not found");
 | 
	
		
			
				|  |  | -      goto done;
 | 
	
		
			
				|  |  | +      goto vote_done;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    SMARTLIST_FOREACH(items, const char *, item,
 | 
	
		
			
				|  |  | -        if (!deflated)
 | 
	
		
			
				|  |  | -          body_len += strlen(item));
 | 
	
		
			
				|  |  |      SMARTLIST_FOREACH(dir_items, cached_dir_t *, d,
 | 
	
		
			
				|  |  |                        body_len += deflated ? d->dir_z_len : d->dir_len);
 | 
	
		
			
				|  |  | +    estimated_len += body_len;
 | 
	
		
			
				|  |  | +    SMARTLIST_FOREACH(items, const char *, item, {
 | 
	
		
			
				|  |  | +        size_t ln = strlen(item);
 | 
	
		
			
				|  |  | +        if (deflated) {
 | 
	
		
			
				|  |  | +          body_len += ln; estimated_len += ln;
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +          estimated_len += ln/2;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (global_write_bucket_low(TO_CONN(conn), estimated_len, 1)) {
 | 
	
		
			
				|  |  | +      write_http_status_line(conn, 503, "Directory busy, try again later.");
 | 
	
		
			
				|  |  | +      goto vote_done;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |      write_http_response_header(conn, body_len ? body_len : -1, deflated,
 | 
	
		
			
				|  |  |                   lifetime);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -2237,6 +2249,9 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
 | 
	
		
			
				|  |  |                                    deflated ? d->dir_z_len : d->dir_len,
 | 
	
		
			
				|  |  |                                    TO_CONN(conn)));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +  vote_done:
 | 
	
		
			
				|  |  | +    smartlist_free(items);
 | 
	
		
			
				|  |  | +    smartlist_free(dir_items);
 | 
	
		
			
				|  |  |      goto done;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -2306,6 +2321,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (!strcmpstart(url,"/tor/keys/")) {
 | 
	
		
			
				|  |  | +    /*XXXX020 implement if-modified-since */
 | 
	
		
			
				|  |  |      smartlist_t *certs = smartlist_create();
 | 
	
		
			
				|  |  |      ssize_t len = -1;
 | 
	
		
			
				|  |  |      if (!strcmp(url, "/tor/keys/all")) {
 | 
	
	
		
			
				|  | @@ -2345,19 +2361,23 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  |        write_http_status_line(conn, 400, "Bad request");
 | 
	
		
			
				|  |  |        smartlist_free(certs);
 | 
	
		
			
				|  |  | -      goto done;
 | 
	
		
			
				|  |  | +      goto keys_done;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      if (!smartlist_len(certs)) {
 | 
	
		
			
				|  |  |        write_http_status_line(conn, 404, "Not found");
 | 
	
		
			
				|  |  |        smartlist_free(certs);
 | 
	
		
			
				|  |  | -      goto done;
 | 
	
		
			
				|  |  | +      goto keys_done;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    if (!deflated) {
 | 
	
		
			
				|  |  | -      len = 0;
 | 
	
		
			
				|  |  | -      SMARTLIST_FOREACH(certs, authority_cert_t *, c,
 | 
	
		
			
				|  |  | -                        len += c->cache_info.signed_descriptor_len);
 | 
	
		
			
				|  |  | +    len = 0;
 | 
	
		
			
				|  |  | +    SMARTLIST_FOREACH(certs, authority_cert_t *, c,
 | 
	
		
			
				|  |  | +                      len += c->cache_info.signed_descriptor_len);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (global_write_bucket_low(TO_CONN(conn), deflated?len/2:len, 1)) {
 | 
	
		
			
				|  |  | +      write_http_status_line(conn, 503, "Directory busy, try again later.");
 | 
	
		
			
				|  |  | +      goto keys_done;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    write_http_response_header(conn, len, deflated, 60*60);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    write_http_response_header(conn, deflated?-1:len, deflated, 60*60);
 | 
	
		
			
				|  |  |      if (deflated) {
 | 
	
		
			
				|  |  |        conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD);
 | 
	
		
			
				|  |  |        SMARTLIST_FOREACH(certs, authority_cert_t *, c,
 | 
	
	
		
			
				|  | @@ -2371,6 +2391,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
 | 
	
		
			
				|  |  |                                      c->cache_info.signed_descriptor_len,
 | 
	
		
			
				|  |  |                                      TO_CONN(conn)));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +  keys_done:
 | 
	
		
			
				|  |  |      smartlist_free(certs);
 | 
	
		
			
				|  |  |      goto done;
 | 
	
		
			
				|  |  |    }
 |