Commit 1a4cb248 authored by Roger Dingledine's avatar Roger Dingledine
Browse files

interim commit for http proxy support


svn:r2431
parent 2bcd0f34
Loading
Loading
Loading
Loading
+76 −40
Original line number Diff line number Diff line
@@ -29,7 +29,8 @@
static void
directory_initiate_command(routerinfo_t *router, uint8_t purpose,
                           const char *payload, int payload_len);
static void directory_send_command(connection_t *conn, int purpose,
static void
directory_send_command(connection_t *conn, routerinfo_t *router, int purpose,
                       const char *payload, int payload_len);
static int directory_handle_command(connection_t *conn);

@@ -128,8 +129,7 @@ directory_initiate_command(routerinfo_t *router, uint8_t purpose,
  tor_assert(router);
  tor_assert(router->dir_port);

  switch (purpose)
    {
  switch (purpose) {
    case DIR_PURPOSE_FETCH_DIR:
      log_fn(LOG_DEBUG,"initiating directory fetch");
      break;
@@ -150,8 +150,13 @@ directory_initiate_command(routerinfo_t *router, uint8_t purpose,
  conn = connection_new(CONN_TYPE_DIR);

  /* set up conn so it's got all the data we need to remember */
  if(options.HttpProxy) {
    conn->addr = options.HttpProxyAddr;
    conn->port = options.HttpProxyPort;
  } else {
    conn->addr = router->addr;
    conn->port = router->dir_port;
  }
  conn->address = tor_strdup(router->address);
  conn->nickname = tor_strdup(router->nickname);
  tor_assert(router->identity_pkey);
@@ -180,7 +185,7 @@ directory_initiate_command(routerinfo_t *router, uint8_t purpose,
        /* fall through */
      case 0:
        /* queue the command on the outbuf */
        directory_send_command(conn, purpose, payload, payload_len);
        directory_send_command(conn, router, purpose, payload, payload_len);

        connection_watch_events(conn, POLLIN | POLLOUT | POLLERR);
        /* writable indicates finish, readable indicates broken link,
@@ -201,7 +206,7 @@ directory_initiate_command(routerinfo_t *router, uint8_t purpose,
    conn->state = DIR_CONN_STATE_CLIENT_SENDING;
    connection_add(conn);
    /* queue the command on the outbuf */
    directory_send_command(conn, purpose, payload, payload_len);
    directory_send_command(conn, router, purpose, payload, payload_len);
    connection_watch_events(conn, POLLIN | POLLOUT | POLLERR);
  }
}
@@ -210,44 +215,49 @@ directory_initiate_command(routerinfo_t *router, uint8_t purpose,
 * <b>purpose</b>, <b>payload</b>, and <b>payload_len</b> are as in
 * directory_initiate_command.
 */
static void directory_send_command(connection_t *conn, int purpose,
static void
directory_send_command(connection_t *conn, routerinfo_t *router, int purpose,
                       const char *payload, int payload_len) {
  char fetchwholedir[] = "GET / HTTP/1.0\r\n\r\n"; /* deprecated */
  char fetchwholedir_z[] = "GET /tor/dir.z HTTP/1.0\r\n\r\n";
  char fetchrunninglist[] = "GET /tor/running-routers HTTP/1.0\r\n\r\n";
  char tmp[8192];
  routerinfo_t *router;
  char proxystring[128];
  char hoststring[128];
  char url[128];
  int use_newer = 0;
  char *httpcommand = NULL;

  tor_assert(conn && conn->type == CONN_TYPE_DIR);

  router = router_get_by_digest(conn->identity_digest);
  tor_assert(router); /* the func that calls us found it, so we should too */
  tor_assert(router);

  use_newer = tor_version_as_new_as(router->platform, "0.0.9pre1");

  if(router->dir_port == 80) {
    strlcpy(hoststring, router->address, sizeof(hoststring));
  } else {
    sprintf(hoststring, "%s:%d", router->address, router->dir_port);
  }
  if(options.HttpProxy) {
    sprintf(proxystring, "http://%s", hoststring);
  } else {
    proxystring[0] = 0;
  }

  switch(purpose) {
    case DIR_PURPOSE_FETCH_DIR:
      tor_assert(payload == NULL);
      if(use_newer) {
        log_fn(LOG_DEBUG, "Asking for compressed directory from server running  %s", router->platform);
        connection_write_to_buf(fetchwholedir_z, strlen(fetchwholedir_z), conn);
      } else {
        log_fn(LOG_DEBUG, "Asking for uncompressed directory from server running  %s", router->platform);
        connection_write_to_buf(fetchwholedir, strlen(fetchwholedir), conn);
      }
      log_fn(LOG_DEBUG, "Asking for %scompressed directory from server running %s",
             use_newer?"":"un", router->platform);
      httpcommand = "GET";
      strlcpy(url, use_newer ? "/tor/dir.z" : "/", sizeof(url));
      break;
    case DIR_PURPOSE_FETCH_RUNNING_LIST:
      tor_assert(payload == NULL);
      connection_write_to_buf(fetchrunninglist, strlen(fetchrunninglist), conn);
      httpcommand = "GET";
      strlcpy(url, use_newer ? "/tor/running-routers" : "/running-routers", sizeof(url));
      break;
    case DIR_PURPOSE_UPLOAD_DIR:
      tor_assert(payload);
      snprintf(tmp, sizeof(tmp), "POST %s/ HTTP/1.0\r\nContent-Length: %d\r\n\r\n",
               use_newer ? "/tor" : "",
               payload_len);
      connection_write_to_buf(tmp, strlen(tmp), conn);
      connection_write_to_buf(payload, payload_len, conn);
      httpcommand = "POST";
      strlcpy(url, use_newer ? "/tor/" : "/", sizeof(url));
      break;
    case DIR_PURPOSE_FETCH_RENDDESC:
      tor_assert(payload);
@@ -258,21 +268,32 @@ static void directory_send_command(connection_t *conn, int purpose,
      memcpy(conn->rend_query, payload, payload_len);
      conn->rend_query[payload_len] = 0;

      snprintf(tmp, sizeof(tmp), "GET %s%s HTTP/1.0\r\n\r\n", "/rendezvous/", payload);
      connection_write_to_buf(tmp, strlen(tmp), conn);
      httpcommand = "GET";
      sprintf(url, "%s/rendezvous/%s", use_newer ? "/tor" : "", payload);
      break;
    case DIR_PURPOSE_UPLOAD_RENDDESC:
      tor_assert(payload);
      snprintf(tmp, sizeof(tmp),
        "POST %s HTTP/1.0\r\nContent-Length: %d\r\n\r\n", "/rendezvous/publish", payload_len);
      httpcommand = "POST";
      sprintf(url, "%s/rendezvous/publish", use_newer ? "/tor" : "");
      break;
  }

  snprintf(tmp, sizeof(tmp), "%s %s%s HTTP/1.0\r\nContent-Length: %d\r\nHost: %s\r\n\r\n",
           httpcommand,
           proxystring,
           url,
           payload_len,
           hoststring);
  connection_write_to_buf(tmp, strlen(tmp), conn);
      /* could include nuls, need to write it separately */

  if(purpose == DIR_PURPOSE_UPLOAD_DIR || purpose == DIR_PURPOSE_UPLOAD_RENDDESC) {
    /* then send the payload afterwards too */
    connection_write_to_buf(payload, payload_len, conn);
      break;
  }
}

/** Parse an HTTP request string <b>headers</b> of the form "\%s \%s HTTP/1..."
/** Parse an HTTP request string <b>headers</b> of the form
 * "\%s [http[s]://]\%s HTTP/1..."
 * If it's well-formed, strdup the second \%s into *<b>url</b>, and
 * null-terminate it. If the url doesn't start with "/tor/", rewrite it
 * so it does. Return 0.
@@ -281,7 +302,7 @@ static void directory_send_command(connection_t *conn, int purpose,
static int
parse_http_url(char *headers, char **url)
{
  char *s, *start;
  char *s, *start, *tmp;

  s = (char *)eat_whitespace_no_nl(headers);
  if (!*s) return -1;
@@ -292,6 +313,21 @@ parse_http_url(char *headers, char **url)
  start = s; /* this is it, assuming it's valid */
  s = (char *)find_whitespace(start);
  if (!*s) return -1;

  /* tolerate the http[s] proxy style of putting the hostname in the url */
  if(s-start >= 4 && !strcmpstart(start,"http")) {
    tmp = start + 4;
    if(*tmp == 's')
      tmp++;
    if(s-tmp >= 3 && !strcmpstart(tmp,"://")) {
      tmp = strchr(tmp+3, '/');
      if(tmp && tmp < s) {
        log_fn(LOG_DEBUG,"Skipping over 'http[s]://hostname' string");
        start = tmp;
      }
    }
  }

  if(s-start < 5 || strcmpstart(start,"/tor/")) { /* need to rewrite it */
    *url = tor_malloc(s - start + 5);
    strcpy(*url,"/tor");
+6 −1
Original line number Diff line number Diff line
@@ -894,7 +894,12 @@ typedef struct {
                                          allowed to sign directories. */
  struct config_line_t *RendConfigLines; /**< List of configuration lines
                                          * for rendezvous services. */
  char *ContactInfo; /** Contact info to be published in the directory */
  char *ContactInfo; /**< Contact info to be published in the directory */

  char *HttpProxy; /**< hostname[:port] to use as http proxy, if any */
  uint32_t HttpProxyAddr; /**< Parsed IPv4 addr for http proxy, if any */
  uint16_t HttpProxyPort; /**< Parsed port for http proxy, if any */

} or_options_t;

/* XXX are these good enough defaults? */