예제 #1
0
void rhizome_client_poll(struct sched_ent *alarm)
{
  rhizome_http_request *r = (rhizome_http_request *)alarm;
  if (alarm->poll.revents == 0){
    rhizome_server_free_http_request(r);
    return;
  }
  switch(r->request_type)
    {
    case RHIZOME_HTTP_REQUEST_RECEIVING:
      /* Keep reading until we have two CR/LFs in a row */
      r->request[r->request_length] = '\0';
      sigPipeFlag=0;
      int bytes = read_nonblock(r->alarm.poll.fd, &r->request[r->request_length], RHIZOME_HTTP_REQUEST_MAXLEN - r->request_length);
      /* If we got some data, see if we have found the end of the HTTP request */
      if (bytes > 0) {
	// reset inactivity timer
	r->alarm.alarm = gettime_ms() + RHIZOME_IDLE_TIMEOUT;
	r->alarm.deadline = r->alarm.alarm + RHIZOME_IDLE_TIMEOUT;
	unschedule(&r->alarm);
	schedule(&r->alarm);
	r->request_length += bytes;
	if (http_header_complete(r->request, r->request_length, bytes + 4)) {
	  /* We have the request. Now parse it to see if we can respond to it */
	  rhizome_server_parse_http_request(r);
	}
      } else {
	if (debug & DEBUG_RHIZOME_TX)
	  DEBUG("Empty read, closing connection");
	rhizome_server_free_http_request(r);
	return;
      }
      if (sigPipeFlag) {
	if (debug & DEBUG_RHIZOME_TX)
	  DEBUG("Received SIGPIPE, closing connection");
	rhizome_server_free_http_request(r);
	return;
      }
      break;
    default:
      /* Socket already has request -- so just try to send some data. */
      rhizome_server_http_send_bytes(r);
      break;
  }
  return;
}
예제 #2
0
static int rhizome_server_parse_http_request(rhizome_http_request *r)
{
  /* Switching to writing, so update the call-back */
  r->alarm.poll.events=POLLOUT;
  watch(&r->alarm);
  // Start building up a response.
  r->request_type = 0;
  // Parse the HTTP "GET" line.
  char *path = NULL;
  size_t pathlen = 0;
  if (str_startswith(r->request, "GET ", &path)) {
    char *p;
    // This loop is guaranteed to terminate before the end of the buffer, because we know that the
    // buffer contains at least "\n\n" and maybe "\r\n\r\n" at the end of the header block.
    for (p = path; !isspace(*p); ++p)
      ;
    pathlen = p - path;
    if ( str_startswith(p, " HTTP/1.", &p)
      && (str_startswith(p, "0", &p) || str_startswith(p, "1", &p))
      && (str_startswith(p, "\r\n", &p) || str_startswith(p, "\n", &p))
    )
      path[pathlen] = '\0';
    else
      path = NULL;
  }
  if (path) {
    char *id = NULL;
    INFOF("RHIZOME HTTP SERVER, GET %s", alloca_toprint(1024, path, pathlen));
    if (strcmp(path, "/favicon.ico") == 0) {
      r->request_type = RHIZOME_HTTP_REQUEST_FAVICON;
      rhizome_server_http_response_header(r, 200, "image/vnd.microsoft.icon", favicon_len);
    } else if (strcmp(path, "/rhizome/groups") == 0) {
      /* Return the list of known groups */
      rhizome_server_sql_query_http_response(r, "id", "groups", "from groups", 32, 1);
    } else if (strcmp(path, "/rhizome/files") == 0) {
      /* Return the list of known files */
      rhizome_server_sql_query_http_response(r, "id", "files", "from files", 32, 1);
    } else if (strcmp(path, "/rhizome/bars") == 0) {
      /* Return the list of known BARs */
      rhizome_server_sql_query_http_response(r, "bar", "manifests", "from manifests", 32, 0);
    } else if (str_startswith(path, "/rhizome/file/", &id)) {
      /* Stream the specified payload */
      if (!rhizome_str_is_file_hash(id)) {
	rhizome_server_simple_http_response(r, 400, "<html><h1>Invalid payload ID</h1></html>\r\n");
      } else {
	// TODO: Check for Range: header and return 206 if returning partial content
	str_toupper_inplace(id);
	long long rowid = -1;
	sqlite_exec_int64(&rowid, "select rowid from files where id='%s';", id);
	if (rowid >= 0 && sqlite3_blob_open(rhizome_db, "main", "files", "data", rowid, 0, &r->blob) != SQLITE_OK)
	  rowid = -1;
	if (rowid == -1) {
	  rhizome_server_simple_http_response(r, 404, "<html><h1>Payload not found</h1></html>\r\n");
	} else {
	  r->source_index = 0;
	  r->blob_end = sqlite3_blob_bytes(r->blob);
	  rhizome_server_http_response_header(r, 200, "application/binary", r->blob_end - r->source_index);
	  r->request_type |= RHIZOME_HTTP_REQUEST_BLOB;
	}
      }
    } else if (str_startswith(path, "/rhizome/manifest/", &id)) {
      // TODO: Stream the specified manifest
      rhizome_server_simple_http_response(r, 500, "<html><h1>Not implemented</h1></html>\r\n");
    } else {
      rhizome_server_simple_http_response(r, 404, "<html><h1>Not found</h1></html>\r\n");
    }
  } else {
    if (debug & DEBUG_RHIZOME_TX)
      DEBUGF("Received malformed HTTP request: %s", alloca_toprint(120, (const char *)r->request, r->request_length));
    rhizome_server_simple_http_response(r, 400, "<html><h1>Malformed request</h1></html>\r\n");
  }
  
  /* Try sending data immediately. */
  rhizome_server_http_send_bytes(r);

  return 0;
}
예제 #3
0
int rhizome_direct_parse_http_request(rhizome_http_request *r)
{
  const char *submitBareFileURI=confValueGet("rhizome.api.addfile.uri", NULL);
  DEBUGF("uri=%s", submitBareFileURI ? alloca_str_toprint(submitBareFileURI) : "NULL");
  
  /* Switching to writing, so update the call-back */
  r->alarm.poll.events=POLLOUT;
  watch(&r->alarm);
  // Parse the HTTP request into verb, path, protocol, headers and content.
  char *const request_end = r->request + r->request_length;
  char *verb = r->request;
  char *path = NULL;
  char *proto = NULL;
  size_t pathlen = 0;
  char *headers = NULL;
  int headerlen = 0;
  char *content = NULL;
  int contentlen = 0;
  char *p;
  if ((str_startswith(verb, "GET", &p) || str_startswith(verb, "POST", &p)) && isspace(*p)) {
    *p++ = '\0';
    path = p;
    while (p < request_end && !isspace(*p))
      ++p;
    if (p < request_end) {
      pathlen = p - path;
      *p++ = '\0';
      proto = p;
      if ( str_startswith(p, "HTTP/1.", &p)
	&& (str_startswith(p, "0", &p) || str_startswith(p, "1", &p))
	&& (str_startswith(p, "\r\n", &headers) || str_startswith(p, "\n", &headers))
      ) {
	*p = '\0';
	char *eoh = str_str(headers, "\r\n\r\n", request_end - p);
	if (eoh) {
	  content = eoh + 4;
	  headerlen = content - headers;
	  contentlen = request_end - content;
	}
      }
    }
  }
  if (content == NULL) {
    if (debug & DEBUG_RHIZOME_TX)
      DEBUGF("Received malformed HTTP request %s", alloca_toprint(160, (const char *)r->request, r->request_length));
    return rhizome_server_simple_http_response(r, 400, "<html><h1>Malformed request</h1></html>\r\n");
  }
  INFOF("RHIZOME HTTP SERVER, %s %s %s", verb, alloca_toprint(-1, path, pathlen), proto);
  if (debug & DEBUG_RHIZOME_TX)
    DEBUGF("headers %s", alloca_toprint(-1, headers, headerlen));
  if (strcmp(verb, "GET") == 0 && strcmp(path, "/favicon.ico") == 0) {
    r->request_type = RHIZOME_HTTP_REQUEST_FAVICON;
    rhizome_server_http_response_header(r, 200, "image/vnd.microsoft.icon", favicon_len);
  } else if (strcmp(verb, "POST") == 0
      && (   strcmp(path, "/rhizome/import") == 0 
	  || strcmp(path, "/rhizome/enquiry") == 0
	  || (submitBareFileURI && strcmp(path, submitBareFileURI) == 0)
	 )
  ) {
    const char *cl_str=str_str(headers,"Content-Length: ",headerlen);
    const char *ct_str=str_str(headers,"Content-Type: multipart/form-data; boundary=",headerlen);
    if (!cl_str)
      return rhizome_server_simple_http_response(r,400,"<html><h1>Missing Content-Length header</h1></html>\r\n");
    if (!ct_str)
      return rhizome_server_simple_http_response(r,400,"<html><h1>Missing or unsupported Content-Type header</h1></html>\r\n");
    /* ok, we have content-type and content-length, now make sure they are well formed. */
    long long content_length;
    if (sscanf(cl_str,"Content-Length: %lld",&content_length)!=1)
      return rhizome_server_simple_http_response(r,400,"<html><h1>Malformed Content-Length header</h1></html>\r\n");
    char boundary_string[1024];
    int i;
    ct_str+=strlen("Content-Type: multipart/form-data; boundary=");
    for(i=0;i<1023&&*ct_str&&*ct_str!='\n'&&*ct_str!='\r';i++,ct_str++)
      boundary_string[i]=*ct_str;
    boundary_string[i] = '\0';
    if (i<4||i>128)
      return rhizome_server_simple_http_response(r,400,"<html><h1>Malformed Content-Type header</h1></html>\r\n");

    DEBUGF("content_length=%lld, boundary_string=%s contentlen=%d", (long long) content_length, alloca_str_toprint(boundary_string), contentlen);

    /* Now start receiving and parsing multi-part data.  If we already received some of the
	post-header data, process that first.  Tell the HTTP request that it has moved to multipart
	form data parsing, and what the actual requested action is.
    */

    /* Remember boundary string and source path.
	Put the preceeding -- on the front to make our life easier when
	parsing the rest later. */
    strbuf bs = strbuf_local(r->boundary_string, sizeof r->boundary_string);
    strbuf_puts(bs, "--");
    strbuf_puts(bs, boundary_string);
    if (strbuf_overrun(bs))
      return rhizome_server_simple_http_response(r,500,"<html><h1>Internal server error: Multipart boundary string too long</h1></html>\r\n");
    strbuf ps = strbuf_local(r->path, sizeof r->path);
    strbuf_puts(ps, path);
    if (strbuf_overrun(ps))
      return rhizome_server_simple_http_response(r,500,"<html><h1>Internal server error: Path too long</h1></html>\r\n");
    r->boundary_string_length = strbuf_len(bs);
    r->source_index = 0;
    r->source_count = content_length;
    r->request_type = RHIZOME_HTTP_REQUEST_RECEIVING_MULTIPART;
    r->request_length = 0;
    r->source_flags = 0;

    /* Find the end of the headers and start of any body bytes that we have read
	so far. Copy the bytes to a separate buffer, because r->request and 
	r->request_length get used internally in the parser.
      */
    if (contentlen) {
      char buffer[contentlen];
      bcopy(content, buffer, contentlen);
      rhizome_direct_process_post_multipart_bytes(r, buffer, contentlen);
    }

    /* Handle the rest of the transfer asynchronously. */
    return 0;
  } else {
    rhizome_server_simple_http_response(r, 404, "<html><h1>Not found (OTHER)</h1></html>\r\n");
  }
  
  /* Try sending data immediately. */
  rhizome_server_http_send_bytes(r);

  return 0;
}