| 
					
				 | 
			
			
				@@ -210,6 +210,7 @@ directory_initiate_command(routerinfo_t *router, uint8_t purpose, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void directory_send_command(connection_t *conn, int purpose, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                    const char *payload, int payload_len) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   char fetchwholedir[] = "GET / HTTP/1.0\r\n\r\n"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  char fetchwholedir_z[] = "GET /dir.z HTTP/1.0\r\n\r\n"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   char fetchrunninglist[] = "GET /running-routers HTTP/1.0\r\n\r\n"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   char tmp[8192]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -288,11 +289,12 @@ parse_http_url(char *headers, char **url) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * Otherwise, return -1. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-parse_http_response(char *headers, int *code, char **message, time_t *date) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+parse_http_response(char *headers, int *code, char **message, time_t *date, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    int *compression) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   int n1, n2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  const char *cp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   char datestr[RFC1123_TIME_LEN+1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  smartlist_t *parsed_headers; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(headers && code); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   while(isspace((int)*headers)) headers++; /* tolerate leading whitespace */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -307,22 +309,40 @@ parse_http_response(char *headers, int *code, char **message, time_t *date) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if(message) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /* XXX should set *message correctly */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  parsed_headers = smartlist_create(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  smartlist_split_string(parsed_headers, headers, "\n", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                         SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (date) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    cp = headers; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     *date = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    while (cp && (cp = strchr(cp, '\n'))) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      ++cp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      strlcpy(datestr, cp, 7); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      if (strcmpstart(cp, "Date: ") == 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        strlcpy(datestr, cp+6, sizeof(datestr)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    SMARTLIST_FOREACH(parsed_headers, const char *, s, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (!strcmpstart(s, "Date: ")) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        strlcpy(datestr, s+6, sizeof(datestr)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /* This will do nothing on failure, so we don't need to check 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				            the result.   We shouldn't warn, since there are many other valid 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				            date formats besides the one we use. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         parse_rfc1123_time(datestr, date); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (compression) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const char *enc = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    SMARTLIST_FOREACH(parsed_headers, const char *, s, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (!strcmpstart(s, "Content-Encoding: ")) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        enc = s+16; break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!enc || strcmp(enc, "identity")) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      *compression = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else if (!strcmp(enc, "deflate") || !strcmp(enc, "x-deflate")) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      *compression = ZLIB_METHOD; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else if (!strcmp(enc, "gzip") || !strcmp(enc, "x-gzip")) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      *compression = GZIP_METHOD; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      log_fn(LOG_WARN, "Unrecognized content encoding: '%s'", enc); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      *compression = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  SMARTLIST_FOREACH(parsed_headers, char *, s, tor_free(s)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  smartlist_free(parsed_headers); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -342,6 +362,7 @@ connection_dir_client_reached_eof(connection_t *conn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   int status_code; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   time_t now, date_header=0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   int delta; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  int compression; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   switch(fetch_from_buf_http(conn->inbuf, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                              &headers, MAX_HEADERS_SIZE, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -355,7 +376,8 @@ connection_dir_client_reached_eof(connection_t *conn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /* case 1, fall through */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if(parse_http_response(headers, &status_code, NULL, &date_header) < 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if(parse_http_response(headers, &status_code, NULL, &date_header, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                         &compression) < 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     log_fn(LOG_WARN,"Unparseable headers. Closing."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     free(body); free(headers); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return -1; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -372,6 +394,19 @@ connection_dir_client_reached_eof(connection_t *conn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (compression != 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    char *new_body; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    size_t new_len; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (tor_gzip_uncompress(&new_body, &new_len, body, body_len, compression)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      log_fn(LOG_WARN, "Unable to decompress HTTP body."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      tor_free(body); tor_free(headers); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    tor_free(body); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    body = new_body; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    body_len = (int)new_len; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if(conn->purpose == DIR_PURPOSE_FETCH_DIR) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /* fetch/process the directory to learn about new routers. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     log_fn(LOG_INFO,"Received directory (size %d):\n%s", body_len, body); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -545,8 +580,8 @@ directory_handle_command_get(connection_t *conn, char *headers, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if(!strcmp(url,"/")) { /* directory fetch */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    dlen = dirserv_get_directory(&cp, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if(!strcmp(url,"/") || !strcmp(url,"/dir.z")) { /* directory fetch */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    dlen = dirserv_get_directory(&cp, !strcmp(url,"/dir.z")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if(dlen == 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       log_fn(LOG_WARN,"My directory is empty. Closing."); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -556,9 +591,10 @@ directory_handle_command_get(connection_t *conn, char *headers, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     log_fn(LOG_DEBUG,"Dumping directory to client."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     format_rfc1123_time(date, time(NULL)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    snprintf(tmp, sizeof(tmp), "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\nContent-Type: text/plain\r\n\r\n", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    snprintf(tmp, sizeof(tmp), "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\nContent-Type: text/plain\r\nContent-Encoding: %s\r\n\r\n", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				              date, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             (int)dlen); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             (int)dlen, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             strcmp(url,"/dir.z")?"identity":"deflate"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     connection_write_to_buf(tmp, strlen(tmp), conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     connection_write_to_buf(cp, strlen(cp), conn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return 0; 
			 |