Exemplo n.º 1
0
static const char *test_parse_http_message(void) {
  static const char *a = "GET / HTTP/1.0\n\n";
  static const char *b = "GET /blah HTTP/1.0\r\nFoo:  bar  \r\n\r\n";
  static const char *c = "get b c\nz:  k \nb: t\nvvv\n\n xx";
  static const char *d = "a b c\nContent-Length: 21 \nb: t\nvvv\n\n";
  struct ns_str *v;
  struct http_message req;

  ASSERT(ns_parse_http("\b23", 3, &req) == -1);
  ASSERT(ns_parse_http("get\n\n", 5, &req) == -1);
  ASSERT(ns_parse_http(a, strlen(a) - 1, &req) == 0);
  ASSERT(ns_parse_http(a, strlen(a), &req) == (int) strlen(a));

  ASSERT(ns_parse_http(b, strlen(b), &req) == (int) strlen(b));
  ASSERT(req.header_names[0].len == 3);
  ASSERT(req.header_values[0].len == 3);
  ASSERT(req.header_names[1].p == NULL);

  ASSERT(ns_parse_http(c, strlen(c), &req) == (int) strlen(c) - 3);
  ASSERT(req.header_names[2].p == NULL);
  ASSERT(req.header_names[0].p != NULL);
  ASSERT(req.header_names[1].p != NULL);
  ASSERT(memcmp(req.header_values[1].p, "t", 1) == 0);
  ASSERT(req.header_names[1].len == 1);
  ASSERT(req.body.len == 0);

  ASSERT(ns_parse_http(d, strlen(d), &req) == (int) strlen(d));
  ASSERT(req.body.len == 21);
  ASSERT(req.message.len == 21 + strlen(d));
  ASSERT(ns_get_http_header(&req, "foo") == NULL);
  ASSERT((v = ns_get_http_header(&req, "contENT-Length")) != NULL);
  ASSERT(v->len == 2 && memcmp(v->p, "21", 2) == 0);

  return NULL;
}
Exemplo n.º 2
0
static int is_keep_alive(struct http_message *hm) {
    const struct ns_str *connection_header = ns_get_http_header(hm, "Connection");
    if (connection_header == NULL) {
        /* HTTP/1.1 connections are keep-alive by default. */
        if (ns_vcasecmp(&hm->proto, "HTTP/1.1") != 0) return 0;
    } else if (ns_vcasecmp(connection_header, "keep-alive") != 0) {
        return 0;
    }
    // We must also have Content-Length.
    return ns_get_http_header(hm, "Content-Length") != NULL;
}
Exemplo n.º 3
0
static struct http_backend *choose_backend_from_list(
    struct http_message *hm, struct http_backend *backends, int num_backends) {
    int i;
    struct ns_str vhost = {"", 0};
    const struct ns_str *host = ns_get_http_header(hm, "host");
    if (host != NULL) vhost = *host;

    const char *vhost_end = vhost.p;

    while (vhost_end < vhost.p + vhost.len && *vhost_end != ':') {
        vhost_end++;
    }
    vhost.len = vhost_end - vhost.p;

    struct http_backend *chosen = NULL;
    for (i = 0; i < num_backends; i++) {
        struct http_backend *be = &backends[i];
        if (has_prefix(&hm->uri, be->uri_prefix) &&
                matches_vhost(&vhost, be->vhost) &&
                (chosen == NULL ||
                 /* Prefer most specific URI prefixes */
                 strlen(be->uri_prefix) > strlen(chosen->uri_prefix) ||
                 /* Among prefixes of the same length chose the least used. */
                 (strlen(be->uri_prefix) == strlen(chosen->uri_prefix) &&
                  be->usage_counter < chosen->usage_counter))) {
            chosen = be;
        }
    }

    return chosen;
}
Exemplo n.º 4
0
static void choose_backend(struct ns_connection *nc) {
  struct http_message hm;
  struct iobuf *io = &nc->recv_iobuf;
  int req_len = ns_parse_http(io->buf, io->len, &hm);

  if (req_len < 0 || (req_len == 0 && io->len >= NS_MAX_HTTP_REQUEST_SIZE)) {
    /* Invalid, or too large request */
    nc->flags |= NSF_CLOSE_IMMEDIATELY;
  } else if (req_len == 0) {
    /* Do nothing, request is not yet fully buffered */
  } else {
    /*
     * Got HTTP request, look which backend to use. Round-robin over the
     * backends with the same uri_prefix and vhost.
     */
    struct ns_str vhost = *ns_get_http_header(&hm, "host");
    const char *vhost_end = vhost.p;
    while(vhost_end < vhost.p + vhost.len &&
          *vhost_end != ':') {
      vhost_end++;
    }
    vhost.len = vhost_end - vhost.p;

    int i, chosen = -1;
    for (i = 0; i < s_num_http_backends; i++) {
      if (has_prefix(&hm.uri, s_http_backends[i].uri_prefix) &&
          matches_vhost(&vhost, s_http_backends[i].vhost) &&
          (chosen == -1 || s_http_backends[i].usage_counter <
           s_http_backends[chosen].usage_counter)) {
        chosen = i;
      }
    }

    if (chosen == -1) {
      /* No backend with given uri_prefix found, bail out */
      ns_printf(nc, "%s%s\r\n", s_error_404, s_content_len_0);
    } else if (s_http_backends[chosen].redirect != 0) {
      ns_printf(nc, "HTTP/1.1 302 Found\r\nLocation: %s\r\n\r\n",
                s_http_backends[chosen].host_port);
      nc->flags |= NSF_SEND_AND_CLOSE;
    } else if ((nc->proto_data = ns_connect(nc->mgr,
               s_http_backends[chosen].host_port, ev_handler)) == NULL) {
      /* Connection to backend failed */
      ns_printf(nc, "%s%s\r\n", s_error_500, s_content_len_0);
    } else {
      /*
       * Forward request to the backend. Note that we can insert extra headers
       * to pass information to the backend.
       * Store backend index as user_data for the backend connection.
       */
      ((struct ns_connection *) nc->proto_data)->proto_data = nc;
      ((struct ns_connection *) nc->proto_data)->user_data =
        (void *) (long) chosen;
      s_http_backends[chosen].usage_counter++;
      ns_send(nc->proto_data, io->buf, io->len);
      iobuf_remove(io, io->len);
    }
  }
}
Exemplo n.º 5
0
static void cb10(struct ns_connection *nc, int ev, void *ev_data) {
  struct http_message *hm = (struct http_message *) ev_data;
  struct ns_str *s;

  if (ev == NS_HTTP_REPLY &&
      (s = ns_get_http_header(hm, "Content-Type")) != NULL) {
    sprintf((char *) nc->user_data, "%.*s", (int) s->len, s->p);
  }
}
Exemplo n.º 6
0
static void cb7(struct ns_connection *nc, int ev, void *ev_data) {
  struct http_message *hm = (struct http_message *) ev_data;
  struct ns_str *s;
  size_t size;
  char *data;

  if (ev == NS_HTTP_REPLY) {
    /* Make sure that we've downloaded this executable, byte-to-byte */
    data = read_file(s_argv_0, &size);
    strcpy((char *) nc->user_data, data == NULL || size != hm->body.len ||
           (s = ns_get_http_header(hm, "Content-Type")) == NULL ||
           (ns_vcmp(s, "text/plain")) != 0 ||
           memcmp(hm->body.p, data, size) != 0 ? "fail" : "success");
    free(data);
    nc->flags |= NSF_CLOSE_IMMEDIATELY;
  }
}