Procházet zdrojové kódy

more robust http(ish) handling

svn:r123
Roger Dingledine před 23 roky
rodič
revize
827c7444f8
4 změnil soubory, kde provedl 76 přidání a 11 odebrání
  1. 24 2
      src/or/buffers.c
  2. 4 0
      src/or/connection.c
  3. 37 7
      src/or/directory.c
  4. 11 2
      src/or/or.h

+ 24 - 2
src/or/buffers.c

@@ -129,9 +129,9 @@ int write_to_buf(char *string, int string_len,
 }
 
 int fetch_from_buf(char *string, int string_len,
-                 char **buf, int *buflen, int *buf_datalen) {
+                   char **buf, int *buflen, int *buf_datalen) {
 
-  /* if there is string_len bytes in buf, write them onto string,
+  /* if there are string_len bytes in buf, write them onto string,
    * then memmove buf back (that is, remove them from buf) */
 
   assert(string && buf && *buf && buflen && buf_datalen);
@@ -147,3 +147,25 @@ int fetch_from_buf(char *string, int string_len,
   return *buf_datalen;
 }
 
+int find_on_inbuf(char *string, int string_len,
+                  char *buf, int buf_datalen) {
+  /* find first instance of needle 'string' on haystack 'buf'. return how
+   * many bytes from the beginning of buf to the end of string.
+   * If it's not there, return -1.
+   */
+
+  char *location;
+  char *last_possible = buf + buf_datalen - string_len;
+
+  assert(string && string_len > 0 && buf);
+
+  if(buf_datalen < string_len)
+    return -1;
+
+  for(location = buf; location <= last_possible; location++)
+    if((*location == *string) && !memcmp(location+1, string+1, string_len-1))
+      return location-buf+string_len;
+
+  return -1;
+}
+

+ 4 - 0
src/or/connection.c

@@ -352,6 +352,10 @@ int connection_fetch_from_buf(char *string, int len, connection_t *conn) {
   return fetch_from_buf(string, len, &conn->inbuf, &conn->inbuflen, &conn->inbuf_datalen);
 }
 
+int connection_find_on_inbuf(char *string, int len, connection_t *conn) {
+  return find_on_inbuf(string, len, conn->inbuf, conn->inbuf_datalen);
+}
+
 int connection_wants_to_flush(connection_t *conn) {
   return conn->outbuf_flushlen;
 }

+ 37 - 7
src/or/directory.c

@@ -12,8 +12,10 @@ extern or_options_t options; /* command-line and config-file options */
 
 static char the_directory[MAX_DIR_SIZE+1];
 static int directorylen=0;
+static int reading_headers=0;
 
-static char getstring[] = "GET / HTTP/1.0\n\r";
+static char getstring[] = "GET / HTTP/1.0\r\n\r\n";
+static char answerstring[] = "HTTP/1.0 200 OK\r\n\r\n";
 
 /********* END VARIABLES ************/
 
@@ -22,11 +24,14 @@ void directory_initiate_fetch(routerinfo_t *router) {
   struct sockaddr_in router_addr;
   int s;
 
-  log(LOG_DEBUG,"directory_initiate_fetch(): initiating directory fetch");
-
   if(!router) /* i guess they didn't have one in mind for me to use */
     return;
 
+  if(connection_get_by_type(CONN_TYPE_DIR)) /* there's already a fetch running */
+    return;
+
+  log(LOG_DEBUG,"directory_initiate_fetch(): initiating directory fetch");
+
   conn = connection_new(CONN_TYPE_DIR);
   if(!conn)
     return;
@@ -107,7 +112,7 @@ int directory_send_command(connection_t *conn) {
 void directory_rebuild(void) {
 
   dump_directory_to_string(the_directory, MAX_DIR_SIZE);
-  log(LOG_DEBUG,"New directory:\n'%s'",the_directory);  
+  log(LOG_DEBUG,"New directory:\n%s",the_directory);  
   directorylen = strlen(the_directory);
 
 }
@@ -155,6 +160,7 @@ int connection_dir_process_inbuf(connection_t *conn) {
 }
 
 int directory_handle_command(connection_t *conn) {
+  char buf[15];
 
   assert(conn && conn->type == CONN_TYPE_DIR);
 
@@ -163,7 +169,14 @@ int directory_handle_command(connection_t *conn) {
     return 0; /* not yet */
   }
 
-  /* for now, don't bother reading it. */
+  if(connection_fetch_from_buf(buf,strlen(getstring),conn) < 0) {
+    return -1;    
+  }
+
+  if(strncasecmp(buf,getstring,strlen("GET / HTTP/"))) {
+    log(LOG_DEBUG,"directory_handle_command(): Command doesn't seem to be a get. Closing,");
+    return -1;
+  }
 
   if(directorylen == 0) {
     log(LOG_DEBUG,"directory_handle_command(): My directory is empty. Closing.");
@@ -171,7 +184,8 @@ int directory_handle_command(connection_t *conn) {
   }
 
   log(LOG_DEBUG,"directory_handle_command(): Dumping directory to client."); 
-  if(connection_write_to_buf(the_directory, directorylen, conn) < 0) {
+  if((connection_write_to_buf(answerstring, strlen(answerstring), conn) < 0) ||
+     (connection_write_to_buf(the_directory, directorylen, conn) < 0)) {
     log(LOG_DEBUG,"directory_handle_command(): my outbuf is full. Oops.");
     return -1;
   }
@@ -182,9 +196,24 @@ int directory_handle_command(connection_t *conn) {
 
 int directory_handle_reading(connection_t *conn) {
   int amt;
+  char *headers;
 
   assert(conn && conn->type == CONN_TYPE_DIR);
 
+  if(reading_headers) {
+    amt = connection_find_on_inbuf("\r\n\r\n", 4, conn);
+    if(amt < 0) /* not there yet */
+      return 0;
+    headers = malloc(amt+1);
+    if(connection_fetch_from_buf(headers,amt,conn) < 0) {
+      log(LOG_DEBUG,"directory_handle_reading(): fetch_from_buf failed (reading headers).");
+      return -1;
+    }
+    headers[amt] = 0; /* null terminate it, */
+    free(headers); /* and then throw it away */
+    reading_headers = 0;
+  }
+
   amt = conn->inbuf_datalen;
 
   if(amt + directorylen >= MAX_DIR_SIZE) {
@@ -196,7 +225,7 @@ int directory_handle_reading(connection_t *conn) {
     amt, directorylen);
 
   if(connection_fetch_from_buf(the_directory+directorylen,amt,conn) < 0) {
-    log(LOG_DEBUG,"directory_handle_reading(): fetch_from_buf failed.");
+    log(LOG_DEBUG,"directory_handle_reading(): fetch_from_buf failed (reading dir).");
     return -1;    
   }
 
@@ -233,6 +262,7 @@ int connection_dir_finished_flushing(connection_t *conn) {
     case DIR_CONN_STATE_SENDING_COMMAND:
       log(LOG_DEBUG,"connection_dir_finished_flushing(): client finished sending command.");
       directorylen = 0;
+      reading_headers = 1;
       conn->state = DIR_CONN_STATE_READING;
       connection_watch_events(conn, POLLIN);
       return 0;

+ 11 - 2
src/or/or.h

@@ -387,8 +387,16 @@ int write_to_buf(char *string, int string_len,
 
 int fetch_from_buf(char *string, int string_len,
 		                 char **buf, int *buflen, int *buf_datalen);
-	  /* if there is string_len bytes in buf, write them onto string,
-	  *    * then memmove buf back (that is, remove them from buf) */
+  /* if there is string_len bytes in buf, write them onto string,
+   * then memmove buf back (that is, remove them from buf)
+   */
+
+int find_on_inbuf(char *string, int string_len,
+                  char *buf, int buf_datalen);
+  /* find first instance of needle 'string' on haystack 'buf'. return how
+   * many bytes from the beginning of buf to the end of string.
+   * If it's not there, return -1.
+   */
 
 /********************************* cell.c ***************************/
 
@@ -463,6 +471,7 @@ int connection_read_to_buf(connection_t *conn);
 int connection_fetch_from_buf(char *string, int len, connection_t *conn);
 
 int connection_outbuf_too_full(connection_t *conn);
+int connection_find_on_inbuf(char *string, int len, connection_t *conn);
 int connection_wants_to_flush(connection_t *conn);
 int connection_flush_buf(connection_t *conn);