aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Dingledine <arma@torproject.org>2002-09-28 05:53:00 +0000
committerRoger Dingledine <arma@torproject.org>2002-09-28 05:53:00 +0000
commit827c7444f8c6759388e8b137d98c740dc3d5eae7 (patch)
tree5746d19f31b69b76827c8fb8dbf4cdb368fffc49
parente0f77fc36b9df2824c83435f131e637afe103a22 (diff)
downloadtor-827c7444f8c6759388e8b137d98c740dc3d5eae7.tar
tor-827c7444f8c6759388e8b137d98c740dc3d5eae7.tar.gz
more robust http(ish) handling
svn:r123
-rw-r--r--src/or/buffers.c26
-rw-r--r--src/or/connection.c4
-rw-r--r--src/or/directory.c44
-rw-r--r--src/or/or.h13
4 files changed, 76 insertions, 11 deletions
diff --git a/src/or/buffers.c b/src/or/buffers.c
index 30b476e20..5b4053c90 100644
--- a/src/or/buffers.c
+++ b/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;
+}
+
diff --git a/src/or/connection.c b/src/or/connection.c
index f4c3cb968..d2445effe 100644
--- a/src/or/connection.c
+++ b/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;
}
diff --git a/src/or/directory.c b/src/or/directory.c
index 861d3163c..12e5f9dfa 100644
--- a/src/or/directory.c
+++ b/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;
diff --git a/src/or/or.h b/src/or/or.h
index 0a9bf90c1..72eb79176 100644
--- a/src/or/or.h
+++ b/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);