示例#1
0
/** Closure sent to main thread to request a reply to be sent to
 * a HTTP request.
 * Replies must be sent in the main loop in the main http thread,
 * this cannot be done from worker threads.
 */
void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
{
    assert(!replySent && req);
    // Send event to main http thread to send reply message
    struct evbuffer* evb = evhttp_request_get_output_buffer(req);
    assert(evb);
    evbuffer_add(evb, strReply.data(), strReply.size());
    auto req_copy = req;
    HTTPEvent* ev = new HTTPEvent(eventBase, true, [req_copy, nStatus]{
        evhttp_send_reply(req_copy, nStatus, nullptr, nullptr);
        // Re-enable reading from the socket. This is the second part of the libevent
        // workaround above.
        if (event_get_version_number() >= 0x02010600 && event_get_version_number() < 0x02020001) {
            evhttp_connection* conn = evhttp_request_get_connection(req_copy);
            if (conn) {
                bufferevent* bev = evhttp_connection_get_bufferevent(conn);
                if (bev) {
                    bufferevent_enable(bev, EV_READ | EV_WRITE);
                }
            }
        }
    });
    ev->trigger(nullptr);
    replySent = true;
    req = nullptr; // transferred back to main thread
}
示例#2
0
static void
stream_end(struct stream_ctx *st, int failed)
{
  struct evhttp_connection *evcon;

  evcon = evhttp_request_get_connection(st->req);

  if (evcon)
    evhttp_connection_set_closecb(evcon, NULL, NULL);

  if (!failed)
    evhttp_send_reply_end(st->req);

  evbuffer_free(st->evbuf);
  event_free(st->ev);

  if (st->xcode)
    transcode_cleanup(st->xcode);
  else
    {
      free(st->buf);
      close(st->fd);
    }

#ifdef HAVE_LIBEVENT2_OLD
  if (g_st == st)
    g_st = NULL;
#endif

  free(st);
}
 static void HHVM_METHOD(EventHttpRequest, closeConnection) {
     struct evhttp_connection *conn;
     EventHttpRequestResourceData *resource_data = FETCH_RESOURCE(this_, EventHttpRequestResourceData, s_event_http_request);
     conn = evhttp_request_get_connection((evhttp_request_t *) resource_data->getInternalResourceData());
     if(conn != NULL){
         evhttp_connection_free(conn);
     }
 }
示例#4
0
static void
stream_chunk_raw_cb(int fd, short event, void *arg)
{
  struct stream_ctx *st;
  size_t chunk_size;
  int ret;

  st = (struct stream_ctx *)arg;

  if (st->end_offset && (st->offset > st->end_offset))
    {
      stream_end(st, 0);
      return;
    }

  if (st->end_offset && ((st->offset + STREAM_CHUNK_SIZE) > (st->end_offset + 1)))
    chunk_size = st->end_offset + 1 - st->offset;
  else
    chunk_size = STREAM_CHUNK_SIZE;  

  ret = read(st->fd, st->buf, chunk_size);
  if (ret <= 0)
    {
      if (ret == 0)
	DPRINTF(E_LOG, L_HTTPD, "Done streaming file id %d\n", st->id);
      else
	DPRINTF(E_LOG, L_HTTPD, "Streaming error, file id %d\n", st->id);

      stream_end(st, 0);
      return;
    }

  DPRINTF(E_DBG, L_HTTPD, "Read %d bytes; streaming file id %d\n", ret, st->id);

  evbuffer_add(st->evbuf, st->buf, ret);

#ifdef HAVE_LIBEVENT2_OLD
  evhttp_send_reply_chunk(st->req, st->evbuf);

  struct evhttp_connection *evcon = evhttp_request_get_connection(st->req);
  struct bufferevent *bufev = evhttp_connection_get_bufferevent(evcon);

  g_st = st; // Can't pass st to callback so use global - limits libevent 2.0 to a single stream
  bufev->writecb = stream_chunk_resched_cb_wrapper;
#else
  evhttp_send_reply_chunk_with_cb(st->req, st->evbuf, stream_chunk_resched_cb, st);
#endif

  st->offset += ret;

  stream_up_playcount(st);
}
static void parseRequest(RequestInfo& requestInfo) {
  const struct evhttp_uri* uri = evhttp_request_get_evhttp_uri(requestInfo.req);
  /*const*/ struct evhttp_connection* conn = evhttp_request_get_connection(requestInfo.req);
  
  requestInfo.method = evhttp_request_get_command(requestInfo.req);
  requestInfo.uriHost = evhttp_uri_get_host(uri);
  requestInfo.uriPath = evhttp_uri_get_path(uri);
  requestInfo.uriQuery = evhttp_uri_get_query(uri);
  requestInfo.uriScheme = evhttp_uri_get_scheme(uri);
  requestInfo.requestHeaders = evhttp_request_get_input_headers(requestInfo.req);
  requestInfo.requestBody = evhttp_request_get_input_buffer(requestInfo.req);
  evhttp_connection_get_peer(conn, &requestInfo.remoteAddress, (ev_uint16_t*) &requestInfo.remotePort);
}
示例#6
0
CService HTTPRequest::GetPeer()
{
    evhttp_connection* con = evhttp_request_get_connection(req);
    CService peer;
    if (con) {
        // evhttp retains ownership over returned address string
        const char* address = "";
        uint16_t port = 0;
        evhttp_connection_get_peer(con, (char**)&address, &port);
        peer = LookupNumeric(address, port);
    }
    return peer;
}
示例#7
0
int dps_rest_remote_node_get(struct evhttp_request *req,
                             ip_addr_t *remote_node)
{
	struct evhttp_connection *evcon = NULL;
	char *remote_host = NULL;
	char *ptr = NULL;
	ev_uint16_t remote_port;
	int ret_val = -1;

	log_debug(RESTHandlerLogLevel, "Enter");
	do
	{
		evcon = evhttp_request_get_connection(req);
		if (evcon == NULL)
		{
			log_error(RESTHandlerLogLevel,
			          "ERROR: evhttp_request_get_connection returns NULL");
			break;
		}
		evhttp_connection_get_peer(evcon, &remote_host, &remote_port);
		if (remote_host == NULL)
		{
			log_error(RESTHandlerLogLevel,
			          "ERROR: evhttp_connection_get_peer returns NULL");
			break;
		}
		log_debug(RESTHandlerLogLevel, "Remote Host %s", remote_host);
		remote_node->port_http = remote_port;
		ptr = strchr(remote_host,':');
		if (NULL == ptr)
		{
			remote_node->family = AF_INET;
			ret_val = inet_pton(AF_INET, remote_host, remote_node->ip6);
		}
		else
		{
			remote_node->family = AF_INET6;
			ret_val = inet_pton(AF_INET6, remote_host, remote_node->ip6);
		}
		if (ret_val != 1)
		{
			log_error(RESTHandlerLogLevel,
			          "ERROR: evhttp_request has invalid remote host %s",
			          remote_host);
			break;
		}
	} while (0);

	log_debug(RESTHandlerLogLevel, "Exit");
	return ret_val;
}
示例#8
0
文件: http.c 项目: snip/aprsc
static void http_router(struct evhttp_request *r, void *which_server)
{
	char *remote_host;
	ev_uint16_t remote_port;
	const char *uri = evhttp_request_get_uri(r);
	struct evhttp_connection *conn = evhttp_request_get_connection(r);
	evhttp_connection_get_peer(conn, &remote_host, &remote_port);
	
	hlog(LOG_DEBUG, "http %s [%s] request %s", (which_server == (void *)1) ? "status" : "upload", remote_host, uri);
	
	http_requests++;
	
	/* status server routing */
	if (which_server == (void *)1) {
		if (strncmp(uri, "/status.json", 12) == 0) {
			http_status(r);
			return;
		}
		
		if (strncmp(uri, "/counterdata?", 13) == 0) {
			http_counterdata(r, uri);
			return;
		}
		
		http_route_static(r, uri);
		return;
	}
	
	/* position upload server routing */
	if (which_server == (void *)2) {
		if (strncmp(uri, "/", 7) == 0) {
			http_upload_position(r, remote_host);
			return;
		}
		
		hlog(LOG_DEBUG, "http request on upload server for '%s': 404 not found", uri);
		evhttp_send_error(r, HTTP_NOTFOUND, "Not found");
		return;
	}
	
	hlog(LOG_ERR, "http request on unknown server for '%s': 404 not found", uri);
	evhttp_send_error(r, HTTP_NOTFOUND, "Server not found");
	
	return;
}
    static Variant HHVM_METHOD(EventHttpRequest, getEventBufferEvent) {
        evhttp_connection_t *conn;
        event_buffer_event_t *bevent;
        EventHttpRequestResourceData *event_http_request_resource_data = FETCH_RESOURCE(this_, EventHttpRequestResourceData, s_event_http_request);

        if((conn = evhttp_request_get_connection((evhttp_request_t *) event_http_request_resource_data->getInternalResourceData())) == NULL){
            return Variant();
        }

        if((bevent = evhttp_connection_get_bufferevent(conn)) == NULL){
            return Variant();
        }

        String ClassName("EventBufferEvent");
        Object event_buffer_event = ObjectData::newInstance(Unit::lookupClass(ClassName.get()));
        Resource resource;
        resource = Resource(NEWOBJ(EventBufferEventResourceData(bevent, event_buffer_event.get())));
        SET_RESOURCE(event_buffer_event, resource, s_event_bufferevent);
        EventBufferEventResourceData *event_buffer_event_resource_data = FETCH_RESOURCE(event_buffer_event, EventBufferEventResourceData, s_event_bufferevent);
        event_buffer_event_resource_data->isInternal = true;
        return event_buffer_event;
    }
示例#10
0
/* Thread: httpd */
void
httpd_stream_file(struct evhttp_request *req, int id)
{
  struct media_file_info *mfi;
  struct stream_ctx *st;
  void (*stream_cb)(int fd, short event, void *arg);
  struct stat sb;
  struct timeval tv;
  struct evhttp_connection *evcon;
  struct evkeyvalq *input_headers;
  struct evkeyvalq *output_headers;
  const char *param;
  const char *param_end;
  const char *ua;
  const char *client_codecs;
  char buf[64];
  int64_t offset;
  int64_t end_offset;
  off_t pos;
  int transcode;
  int ret;

  offset = 0;
  end_offset = 0;

  input_headers = evhttp_request_get_input_headers(req);

  param = evhttp_find_header(input_headers, "Range");
  if (param)
    {
      DPRINTF(E_DBG, L_HTTPD, "Found Range header: %s\n", param);

      /* Start offset */
      ret = safe_atoi64(param + strlen("bytes="), &offset);
      if (ret < 0)
	{
	  DPRINTF(E_LOG, L_HTTPD, "Invalid start offset, will stream whole file (%s)\n", param);
	  offset = 0;
	}
      /* End offset, if any */
      else
	{
	  param_end = strchr(param, '-');
	  if (param_end && (strlen(param_end) > 1))
	    {
	      ret = safe_atoi64(param_end + 1, &end_offset);
	      if (ret < 0)
		{
		  DPRINTF(E_LOG, L_HTTPD, "Invalid end offset, will stream to end of file (%s)\n", param);
		  end_offset = 0;
		}

	      if (end_offset < offset)
		{
		  DPRINTF(E_LOG, L_HTTPD, "End offset < start offset, will stream to end of file (%" PRIi64 " < %" PRIi64 ")\n", end_offset, offset);
		  end_offset = 0;
		}
	    }
	}
    }

  mfi = db_file_fetch_byid(id);
  if (!mfi)
    {
      DPRINTF(E_LOG, L_HTTPD, "Item %d not found\n", id);

      evhttp_send_error(req, HTTP_NOTFOUND, "Not Found");
      return;
    }

  if (mfi->data_kind != DATA_KIND_FILE)
    {
      evhttp_send_error(req, 500, "Cannot stream radio station");

      goto out_free_mfi;
    }

  st = (struct stream_ctx *)malloc(sizeof(struct stream_ctx));
  if (!st)
    {
      DPRINTF(E_LOG, L_HTTPD, "Out of memory for struct stream_ctx\n");

      evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error");

      goto out_free_mfi;
    }
  memset(st, 0, sizeof(struct stream_ctx));
  st->fd = -1;

  ua = evhttp_find_header(input_headers, "User-Agent");
  client_codecs = evhttp_find_header(input_headers, "Accept-Codecs");

  transcode = transcode_needed(ua, client_codecs, mfi->codectype);

  output_headers = evhttp_request_get_output_headers(req);

  if (transcode)
    {
      DPRINTF(E_INFO, L_HTTPD, "Preparing to transcode %s\n", mfi->path);

      stream_cb = stream_chunk_xcode_cb;

      st->xcode = transcode_setup(mfi, XCODE_PCM16_HEADER, &st->size);
      if (!st->xcode)
	{
	  DPRINTF(E_WARN, L_HTTPD, "Transcoding setup failed, aborting streaming\n");

	  evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error");

	  goto out_free_st;
	}

      if (!evhttp_find_header(output_headers, "Content-Type"))
	evhttp_add_header(output_headers, "Content-Type", "audio/wav");
    }
  else
    {
      /* Stream the raw file */
      DPRINTF(E_INFO, L_HTTPD, "Preparing to stream %s\n", mfi->path);

      st->buf = (uint8_t *)malloc(STREAM_CHUNK_SIZE);
      if (!st->buf)
	{
	  DPRINTF(E_LOG, L_HTTPD, "Out of memory for raw streaming buffer\n");

	  evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error");

	  goto out_free_st;
	}

      stream_cb = stream_chunk_raw_cb;

      st->fd = open(mfi->path, O_RDONLY);
      if (st->fd < 0)
	{
	  DPRINTF(E_LOG, L_HTTPD, "Could not open %s: %s\n", mfi->path, strerror(errno));

	  evhttp_send_error(req, HTTP_NOTFOUND, "Not Found");

	  goto out_cleanup;
	}

      ret = stat(mfi->path, &sb);
      if (ret < 0)
	{
	  DPRINTF(E_LOG, L_HTTPD, "Could not stat() %s: %s\n", mfi->path, strerror(errno));

	  evhttp_send_error(req, HTTP_NOTFOUND, "Not Found");

	  goto out_cleanup;
	}
      st->size = sb.st_size;

      pos = lseek(st->fd, offset, SEEK_SET);
      if (pos == (off_t) -1)
	{
	  DPRINTF(E_LOG, L_HTTPD, "Could not seek into %s: %s\n", mfi->path, strerror(errno));

	  evhttp_send_error(req, HTTP_BADREQUEST, "Bad Request");

	  goto out_cleanup;
	}
      st->offset = offset;
      st->end_offset = end_offset;

      /* Content-Type for video files is different than for audio files
       * and overrides whatever may have been set previously, like
       * application/x-dmap-tagged when we're speaking DAAP.
       */
      if (mfi->has_video)
	{
	  /* Front Row and others expect video/<type> */
	  ret = snprintf(buf, sizeof(buf), "video/%s", mfi->type);
	  if ((ret < 0) || (ret >= sizeof(buf)))
	    DPRINTF(E_LOG, L_HTTPD, "Content-Type too large for buffer, dropping\n");
	  else
	    {
	      evhttp_remove_header(output_headers, "Content-Type");
	      evhttp_add_header(output_headers, "Content-Type", buf);
	    }
	}
      /* If no Content-Type has been set and we're streaming audio, add a proper
       * Content-Type for the file we're streaming. Remember DAAP streams audio
       * with application/x-dmap-tagged as the Content-Type (ugh!).
       */
      else if (!evhttp_find_header(output_headers, "Content-Type") && mfi->type)
	{
	  ret = snprintf(buf, sizeof(buf), "audio/%s", mfi->type);
	  if ((ret < 0) || (ret >= sizeof(buf)))
	    DPRINTF(E_LOG, L_HTTPD, "Content-Type too large for buffer, dropping\n");
	  else
	    evhttp_add_header(output_headers, "Content-Type", buf);
	}
    }

  st->evbuf = evbuffer_new();
  if (!st->evbuf)
    {
      DPRINTF(E_LOG, L_HTTPD, "Could not allocate an evbuffer for streaming\n");

      evhttp_clear_headers(output_headers);
      evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error");

      goto out_cleanup;
    }

  ret = evbuffer_expand(st->evbuf, STREAM_CHUNK_SIZE);
  if (ret != 0)
    {
      DPRINTF(E_LOG, L_HTTPD, "Could not expand evbuffer for streaming\n");

      evhttp_clear_headers(output_headers);
      evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error");

      goto out_cleanup;
    }

  st->ev = event_new(evbase_httpd, -1, EV_TIMEOUT, stream_cb, st);
  evutil_timerclear(&tv);
  if (!st->ev || (event_add(st->ev, &tv) < 0))
    {
      DPRINTF(E_LOG, L_HTTPD, "Could not add one-shot event for streaming\n");

      evhttp_clear_headers(output_headers);
      evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error");

      goto out_cleanup;
    }

  st->id = mfi->id;
  st->start_offset = offset;
  st->stream_size = st->size;
  st->req = req;

  if ((offset == 0) && (end_offset == 0))
    {
      /* If we are not decoding, send the Content-Length. We don't do
       * that if we are decoding because we can only guesstimate the
       * size in this case and the error margin is unknown and variable.
       */
      if (!transcode)
	{
	  ret = snprintf(buf, sizeof(buf), "%" PRIi64, (int64_t)st->size);
	  if ((ret < 0) || (ret >= sizeof(buf)))
	    DPRINTF(E_LOG, L_HTTPD, "Content-Length too large for buffer, dropping\n");
	  else
	    evhttp_add_header(output_headers, "Content-Length", buf);
	}

      evhttp_send_reply_start(req, HTTP_OK, "OK");
    }
  else
    {
      if (offset > 0)
	st->stream_size -= offset;
      if (end_offset > 0)
	st->stream_size -= (st->size - end_offset);

      DPRINTF(E_DBG, L_HTTPD, "Stream request with range %" PRIi64 "-%" PRIi64 "\n", offset, end_offset);

      ret = snprintf(buf, sizeof(buf), "bytes %" PRIi64 "-%" PRIi64 "/%" PRIi64,
		     offset, (end_offset) ? end_offset : (int64_t)st->size, (int64_t)st->size);
      if ((ret < 0) || (ret >= sizeof(buf)))
	DPRINTF(E_LOG, L_HTTPD, "Content-Range too large for buffer, dropping\n");
      else
	evhttp_add_header(output_headers, "Content-Range", buf);

      ret = snprintf(buf, sizeof(buf), "%" PRIi64, ((end_offset) ? end_offset + 1 : (int64_t)st->size) - offset);
      if ((ret < 0) || (ret >= sizeof(buf)))
	DPRINTF(E_LOG, L_HTTPD, "Content-Length too large for buffer, dropping\n");
      else
	evhttp_add_header(output_headers, "Content-Length", buf);

      evhttp_send_reply_start(req, 206, "Partial Content");
    }

#ifdef HAVE_POSIX_FADVISE
  if (!transcode)
    {
      /* Hint the OS */
      posix_fadvise(st->fd, st->start_offset, st->stream_size, POSIX_FADV_WILLNEED);
      posix_fadvise(st->fd, st->start_offset, st->stream_size, POSIX_FADV_SEQUENTIAL);
      posix_fadvise(st->fd, st->start_offset, st->stream_size, POSIX_FADV_NOREUSE);
    }
#endif

  evcon = evhttp_request_get_connection(req);

  evhttp_connection_set_closecb(evcon, stream_fail_cb, st);

  DPRINTF(E_INFO, L_HTTPD, "Kicking off streaming for %s\n", mfi->path);

  free_mfi(mfi, 0);

  return;

 out_cleanup:
  if (st->evbuf)
    evbuffer_free(st->evbuf);
  if (st->xcode)
    transcode_cleanup(st->xcode);
  if (st->buf)
    free(st->buf);
  if (st->fd > 0)
    close(st->fd);
 out_free_st:
  free(st);
 out_free_mfi:
  free_mfi(mfi, 0);
}
示例#11
0
static void
stream_chunk_xcode_cb(int fd, short event, void *arg)
{
  struct stream_ctx *st;
  struct timeval tv;
  int xcoded;
  int ret;
  int dummy;

  st = (struct stream_ctx *)arg;

  xcoded = transcode(st->evbuf, STREAM_CHUNK_SIZE, st->xcode, &dummy);
  if (xcoded <= 0)
    {
      if (xcoded == 0)
	DPRINTF(E_LOG, L_HTTPD, "Done streaming transcoded file id %d\n", st->id);
      else
	DPRINTF(E_LOG, L_HTTPD, "Transcoding error, file id %d\n", st->id);

      stream_end(st, 0);
      return;
    }

  DPRINTF(E_DBG, L_HTTPD, "Got %d bytes from transcode; streaming file id %d\n", xcoded, st->id);

  /* Consume transcoded data until we meet start_offset */
  if (st->start_offset > st->offset)
    {
      ret = st->start_offset - st->offset;

      if (ret < xcoded)
	{
	  evbuffer_drain(st->evbuf, ret);
	  st->offset += ret;

	  ret = xcoded - ret;
	}
      else
	{
	  evbuffer_drain(st->evbuf, xcoded);
	  st->offset += xcoded;

	  goto consume;
	}
    }
  else
    ret = xcoded;

#ifdef HAVE_LIBEVENT2_OLD
  evhttp_send_reply_chunk(st->req, st->evbuf);

  struct evhttp_connection *evcon = evhttp_request_get_connection(st->req);
  struct bufferevent *bufev = evhttp_connection_get_bufferevent(evcon);

  g_st = st; // Can't pass st to callback so use global - limits libevent 2.0 to a single stream
  bufev->writecb = stream_chunk_resched_cb_wrapper;
#else
  evhttp_send_reply_chunk_with_cb(st->req, st->evbuf, stream_chunk_resched_cb, st);
#endif

  st->offset += ret;

  stream_up_playcount(st);

  return;

 consume: /* reschedule immediately - consume up to start_offset */
  evutil_timerclear(&tv);
  ret = event_add(st->ev, &tv);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_HTTPD, "Could not re-add one-shot event for streaming (xcode)\n");

      stream_end(st, 0);
      return;
    }
}
示例#12
0
文件: easy.c 项目: Garik-/crawler
static void
http_request_done(struct evhttp_request *req, void *ctx) {
    char buffer[256];
    ev_ssize_t nread;
    struct evkeyval *header;


    if (req == NULL) {
        /* If req is NULL, it means an error occurred, but
         * sadly we are mostly left guessing what the error
         * might have been.  We'll do our best... */
        struct bufferevent *bev = (struct bufferevent *) ctx;


        int errcode = EVUTIL_SOCKET_ERROR();
        fprintf(stderr, "some request failed - no idea which one though!\n");
        /* Print out the OpenSSL error queue that libevent
         * squirreled away for us, if any. */

        /* If the OpenSSL error queue was empty, maybe it was a
         * socket error; let's try printing that. */

        fprintf(stderr, "socket error = %s (%d)\n",
                evutil_socket_error_to_string(errcode),
                errcode);
        return;
    }

    /*fprintf(stderr, "Response line: %d %s\n",
            evhttp_request_get_response_code(req),
            evhttp_request_get_response_code_line(req));

    struct evkeyvalq *headers = evhttp_request_get_input_headers(req);
    if (NULL != headers) {
        fprintf(stderr, "Response headers:\n");

        TAILQ_FOREACH(header, headers, next) {
            fprintf(stderr, "%s: %s\r\n",
                    header->key, header->value);
        }

        fprintf(stderr, "\n");
    }*/


    const int http_code = evhttp_request_get_response_code(req);
    struct evhttp_connection *evcon = evhttp_request_get_connection(req);


    if (HTTP_MOVEPERM == http_code || HTTP_MOVETEMP == http_code) {

        const char *location = evhttp_find_header(evhttp_request_get_input_headers(req), "Location");
        if (NULL != location) {
            //fprintf(stderr, "Location: %s\n", location);

            create_request(location);
        }
    }

    if (HTTP_OK == http_code) {

        struct evbuffer *input_buffer = evhttp_request_get_input_buffer(req);

        int found = 0;
        while ((nread = evbuffer_remove(input_buffer, buffer, sizeof (buffer))) > 0) {
            if (0 == search_find(&search_list, buffer, nread)) {
                found = 1;
                break;
            }
        }

        fprintf(stderr, "%s: %d\n", evhttp_find_header(evhttp_request_get_output_headers(req), "Host"), found);


    }


    if (--n_pending_requests == 0)
        event_base_loopexit(base, NULL);
}
示例#13
0
http_delivery_status_t
buffer_delivery(
        struct evhttp_request* req,
        char* decoded_path)
{
    char* my_decoded_path           = NULL;
    char* my_client_ip              = NULL;
    char* my_client_user_agent      = NULL;
    buffer_xact_ctx* p_ctx          = NULL;
    prmm_req prmm_r                 = NULL;
    int content_on_disk             = 0;

    http_delivery_status_t stat;
    stat = http_delivery_internal_error;

    channel_info_t* p_channel;
    p_channel = get_channel(decoded_path);
    if(!p_channel) {
        debug_msg("channel not identified for %s", decoded_path);
        stat = http_delivery_not_found;
        return stat; /*we don't allocate anything, so just return*/
    }

    /*
     * doecode_path points to memory owned by libevent,
     * and will be modified later, so we have keep a copy.
     */
    my_decoded_path = strdup(decoded_path);
    if(!my_decoded_path) {
        debug_msg("strdup");
        goto error;
    }

    char* host;
    uint16_t port;
    evhttp_connection_get_peer(
            evhttp_request_get_connection(req),
            &host,
            &port);
    my_client_ip = strdup(host);
    if(!my_client_ip) {
        debug_msg("strdup");
        goto error;
    }

    struct evkeyvalq* input_headers;
    input_headers = evhttp_request_get_input_headers(req);
    const char* user_agent = evhttp_find_header(input_headers, "User-Agent");
    if(user_agent) {
        my_client_user_agent = strdup(user_agent);
        if(!my_client_user_agent) {
            debug_msg("strdup");
            goto error;
        }
    }

    p_ctx = malloc(sizeof(buffer_xact_ctx));
    if(!p_ctx) {
        debug_msg("malloc");
        goto error;
    }
    p_ctx->client_req           = req;
    p_ctx->data_sent            = 0;
    p_ctx->data_total           = 0;
    p_ctx->decoded_path         = my_decoded_path;
    p_ctx->client_ip            = my_client_ip;
    p_ctx->client_user_agent    = my_client_user_agent;

    prmm_conn prmm_c;
    prmm_c = get_prmm_conn(
            p_channel->channel_id,
            p_channel->maddress,
            p_channel->mport);
    if(!prmm_c) {
        debug_msg("get_prmm_conn");
        goto error;
    }

    prmm_r = prmm_request_new(
            prmm_c,
            decoded_path,
            http_prmm_cb,
            p_ctx);
    if(!prmm_r) {
        debug_msg("prmm_request_new");
        goto error;
    }
    p_ctx->prmm_r = prmm_r;

    prmm_request_stat_t prmm_stat;
    prmm_stat = prmm_request_start(prmm_r);
    switch(prmm_stat) {
        case prmm_request_success:
            break;
        case prmm_request_failed:
            debug_msg("can't get content via prmm");
            stat = http_delivery_not_found;
            goto error;
        case prmm_request_on_disk:
            debug_msg("content has been written to disk just now,");
            debug_msg("so use local delivery instead.");
            content_on_disk = 1;
            goto error; /*this isn't error actually, we just need to free memory*/
        default:
            debug_msg("?! invalid stat: %d", stat);
            goto error;
    }

    /*for memory leak detect when debugging*/
    debug_msg("buffer_xact_ctx[%p] created", p_ctx);

    return http_delivery_success;

error:
    if(my_decoded_path)
        free(my_decoded_path);
    if(my_client_ip)
        free(my_client_ip);
    if(my_client_user_agent)
        free(my_client_user_agent);
    if(p_ctx)
        free(p_ctx);
    if(prmm_r)
        prmm_request_free(prmm_r);

    if(content_on_disk)
        return local_delivery(req, decoded_path);
        
    return stat;
}
示例#14
0
/** HTTP request callback */
static void http_request_cb(struct evhttp_request* req, void* arg)
{
    // Disable reading to work around a libevent bug, fixed in 2.2.0.
    if (event_get_version_number() >= 0x02010600 && event_get_version_number() < 0x02020001) {
        evhttp_connection* conn = evhttp_request_get_connection(req);
        if (conn) {
            bufferevent* bev = evhttp_connection_get_bufferevent(conn);
            if (bev) {
                bufferevent_disable(bev, EV_READ);
            }
        }
    }
    std::unique_ptr<HTTPRequest> hreq(new HTTPRequest(req));

    // Early address-based allow check
    if (!ClientAllowed(hreq->GetPeer())) {
        LogPrint(BCLog::HTTP, "HTTP request from %s rejected: Client network is not allowed RPC access\n",
                 hreq->GetPeer().ToString());
        hreq->WriteReply(HTTP_FORBIDDEN);
        return;
    }

    // Early reject unknown HTTP methods
    if (hreq->GetRequestMethod() == HTTPRequest::UNKNOWN) {
        LogPrint(BCLog::HTTP, "HTTP request from %s rejected: Unknown HTTP request method\n",
                 hreq->GetPeer().ToString());
        hreq->WriteReply(HTTP_BADMETHOD);
        return;
    }

    LogPrint(BCLog::HTTP, "Received a %s request for %s from %s\n",
             RequestMethodString(hreq->GetRequestMethod()), SanitizeString(hreq->GetURI(), SAFE_CHARS_URI).substr(0, 100), hreq->GetPeer().ToString());

    // Find registered handler for prefix
    std::string strURI = hreq->GetURI();
    std::string path;
    std::vector<HTTPPathHandler>::const_iterator i = pathHandlers.begin();
    std::vector<HTTPPathHandler>::const_iterator iend = pathHandlers.end();
    for (; i != iend; ++i) {
        bool match = false;
        if (i->exactMatch)
            match = (strURI == i->prefix);
        else
            match = (strURI.substr(0, i->prefix.size()) == i->prefix);
        if (match) {
            path = strURI.substr(i->prefix.size());
            break;
        }
    }

    // Dispatch to worker thread
    if (i != iend) {
        std::unique_ptr<HTTPWorkItem> item(new HTTPWorkItem(std::move(hreq), path, i->handler));
        assert(workQueue);
        if (workQueue->Enqueue(item.get()))
            item.release(); /* if true, queue took ownership */
        else {
            LogPrintf("WARNING: request rejected because http work queue depth exceeded, it can be increased with the -rpcworkqueue= setting\n");
            item->req->WriteReply(HTTP_INTERNAL, "Work queue depth exceeded");
        }
    } else {
        hreq->WriteReply(HTTP_NOTFOUND);
    }
}