示例#1
0
文件: cpolld.c 项目: sizeof/c-poller
void request_handler(struct evhttp_request *req, void *arg)
{
    const char *uri;
    uri = evhttp_request_uri(req);

    if(strncmp(uri, "/updates/", 9) != 0){
        evhttp_send_error(req, HTTP_NOTFOUND, "Not Found");
        if (settings.verbose > 0)
            fprintf(stderr, "URL not found.. needs to be /updates/... but was %s\n", uri);
        return;
    }
    
    const char *rkey;
    struct evkeyvalq args;
    TAILQ_INIT(&args);

    evhttp_parse_query(uri, &args);
    
    rkey = evhttp_find_header(&args, "rkey");
    
    if (NULL == rkey) {
        evhttp_send_error(req, HTTP_BADREQUEST, "Bad Request");
        if (settings.verbose > 0)
            fprintf(stderr, "RKey param not found in request URI %s\n", uri);
        evhttp_clear_headers(&args);
        return;
    }
    
    fprintf(stderr, "Using RKey: %s\n", rkey);
    
    char *cached = fetch_memcached(rkey);
    
    if (NULL == cached) {
        evhttp_send_error(req, HTTP_BADREQUEST, "Bad Request");
        fprintf(stderr, "RKey %s not found in Memcache!\n", rkey);
        evhttp_clear_headers(&args);
        return;
    }
    
    int uid = atoi(cached);

    fprintf(stderr, "Great, found RKey in Memcached: %s = %s and now UID %d\n", rkey, cached, uid);
    
	struct evbuffer *buf = evbuffer_new();
    
    evhttp_add_header(req->output_headers, "Content-Type", "text/html; charset=UTF-8");
    evhttp_add_header(req->output_headers, "Connection", "keep-alive");
    evhttp_add_header(req->output_headers, "Cache-Control", "no-cache");
    
    evhttp_send_reply_start(req, HTTP_OK, "OK");
    evbuffer_add_printf(buf, "Welcome, RKey: ‘%s’\n", rkey);
    evhttp_send_reply_chunk(req, buf);
    evbuffer_free(buf);

    clients[uid] = req;
    evhttp_clear_headers(&args);
    free(cached);
    
    evhttp_connection_set_closecb( req->evcon, cleanup, &slots[uid] );
}
示例#2
0
void Subscriber::close() {
    if(req->evcon) {
        evhttp_connection_set_closecb(req->evcon, NULL, NULL);
    }
    evhttp_send_reply_end(req);
    channel->serv->sub_end(this);
}
void Subscriber::start(){
#ifndef WIN32
	bufferevent_enable(req->evcon->bufev, EV_READ);
#endif
	evhttp_connection_set_closecb(req->evcon, on_sub_disconnect, this);
	evhttp_add_header(req->output_headers, "Connection", "keep-alive");
	evhttp_add_header(req->output_headers, "Content-Type", "text/html;charset=UTF-8");
	evhttp_send_reply_start(req, HTTP_OK, "OK");

	if (this->type == POLL){
	}
	else if (this->type == IFRAME){
		struct evbuffer *buf = evbuffer_new();
		evbuffer_add_printf(buf, "%s\n", iframe_header.c_str());
		evhttp_send_reply_chunk(this->req, buf);
		evbuffer_free(buf);
	}

	if (this->seq_next == 0)
	{
		this->seq_next = channel->seq_next;
	}
	if (!channel->msg_list.empty() && channel->seq_next != this->seq_next){
		this->send_old_msgs();
	}
}
示例#4
0
static void perform_ssl_connection (void)
{
    struct evhttp_connection *con;
    struct evhttp_request *req;
    struct bufferevent *bev;
    SSL_CTX *sctx;
    SSL *ssl;

    sctx = SSL_CTX_new (SSLv23_client_method ());
    assert (sctx);

    SSL_CTX_set_options (sctx, SSL_OP_NO_TLSv1_2);
	//SSL_CTX_set_options (sctx, SSL_OP_ALL);
	SSL_CTX_set_timeout (sctx, 3000);
	SSL_CTX_set_verify (sctx, SSL_VERIFY_PEER, SSLX_CTX_verify_callback);
	SSL_CTX_set_default_verify_paths (sctx);
    SSL_CTX_set_cipher_list (sctx, "RC4-MD5");

    ssl = SSL_new (sctx);
    assert (ssl);

     bev = bufferevent_openssl_socket_new (evbase, -1, ssl, BUFFEREVENT_SSL_CONNECTING , BEV_OPT_CLOSE_ON_FREE);
    //bev = bufferevent_socket_new (evbase, -1, BEV_OPT_CLOSE_ON_FREE);
    assert (bev);

    con = evhttp_connection_base_bufferevent_new (evbase, dnsbase, bev, HOST, PORT);
    evhttp_connection_set_closecb (con, on_connection_close, NULL);
    evhttp_connection_set_timeout (con, 10);

	req = evhttp_request_new (on_response_cb, NULL);
	evhttp_add_header (req->output_headers, "Host", HOST);
//	evhttp_add_header (req->output_headers, "Connection", "Keep-Alive");

    evhttp_make_request (con, req, EVHTTP_REQ_GET, "/index.html");
}
示例#5
0
static int upnpc_get_desc(upnpc_device_t * d, const char * url)
{
	char hostname[MAXHOSTNAMELEN+1];
	char hostname_port[MAXHOSTNAMELEN+1+6];
	unsigned short port;
	char * path;
	unsigned int scope_id;
	struct evhttp_request * req;
	struct evkeyvalq * headers;

	/* if(d->root_desc_location == NULL) {
		return -1;
	} */
	if(!parseURL(url/*d->root_desc_location*/, hostname, &port,
	             &path, &scope_id)) {
		return -1;
	}
	if(port != 80)
		snprintf(hostname_port, sizeof(hostname_port), "%s:%hu", hostname, port);
	else
		strncpy(hostname_port, hostname, sizeof(hostname_port));
	if(d->desc_conn == NULL) {
		d->desc_conn = evhttp_connection_base_new(d->parent->base, NULL, hostname, port);
	}
#ifdef DEBUG
	evhttp_connection_set_closecb(d->desc_conn, upnpc_conn_close_cb, d);
#endif /* DEBUG */
	/*evhttp_connection_set_timeout(p->desc_conn, 600);*/
	req = evhttp_request_new(upnpc_desc_received/*callback*/, d);
	headers = evhttp_request_get_output_headers(req);
	evhttp_add_header(headers, "Host", hostname_port);
	evhttp_add_header(headers, "Connection", "close");
	/*evhttp_add_header(headers, "User-Agent", "***");*/
	return evhttp_make_request(d->desc_conn, req, EVHTTP_REQ_GET, path);
}
示例#6
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);
}
示例#7
0
void Subscriber::start(){
	bufferevent_enable(req->evcon->bufev, EV_READ);
	evhttp_connection_set_closecb(req->evcon, on_sub_disconnect, this);
	evhttp_add_header(req->output_headers, "Connection", "keep-alive");
	//evhttp_add_header(req->output_headers, "Cache-Control", "no-cache");
	//evhttp_add_header(req->output_headers, "Expires", "0");
	evhttp_add_header(req->output_headers, "Content-Type", "text/html; charset=utf-8");
	evhttp_send_reply_start(req, HTTP_OK, "OK");

	if(this->type == POLL){
		//
	}else if(this->type == IFRAME){
		struct evbuffer *buf = evhttp_request_get_output_buffer(this->req);
		evbuffer_add_printf(buf, "%s\n", iframe_header.c_str());
		evhttp_send_reply_chunk(this->req, buf);
	}
	
	// send buffered messages
	if(this->seq_next == 0){
		this->seq_next = channel->seq_next;
	}
	if(!channel->msg_list.empty() && channel->seq_next != this->seq_next){
		this->send_old_msgs();
	}
}
示例#8
0
文件: server.cpp 项目: ITSTONE/icomet
int Server::psub_end(PresenceSubscriber *psub){
	struct evhttp_request *req = psub->req;
	if(req->evcon){
		evhttp_connection_set_closecb(req->evcon, NULL, NULL);
	}
	evhttp_send_reply_end(req);
	psubs.remove(psub);
	log_info("%s:%d psub_end, psubs: %d", req->remote_host, req->remote_port, psubs.size);
	return 0;
}
示例#9
0
文件: server.cpp 项目: ieee820/icomet
int Server::sub(struct evhttp_request *req){
	struct evkeyvalq params;
	const char *uri = evhttp_request_get_uri(req);
	evhttp_parse_query(uri, &params);

	struct bufferevent *bev = evhttp_connection_get_bufferevent(req->evcon);
	bufferevent_enable(bev, EV_READ);

	int cid = -1;
	const char *cb = NULL;
	//const char *token = NULL;
	struct evkeyval *kv;
	for(kv = params.tqh_first; kv; kv = kv->next.tqe_next){
		if(strcmp(kv->key, "id") == 0){
			cid = atoi(kv->value);
		}else if(strcmp(kv->key, "cb") == 0){
			cb = kv->value;
		}
	}
	
	if(cid < 0 || cid >= channels.size()){
		evhttp_send_reply(req, 404, "Not Found", NULL);
		return 0;
	}
	
	Channel *channel = &channels[cid];
	if(channel->sub_count >= MAX_SUBSCRIBERS_PER_CHANNEL){
		evhttp_send_reply(req, 429, "Too Many Requests", NULL);
		return 0;
	}
	
	Subscriber *sub = sub_pool.alloc();
	sub->req = req;
	sub->serv = this;
	sub->cb = cb? cb : DEFAULT_JSONP_CALLBACK;
	//sub->last_recv = ...
	channel->add_subscriber(sub);
	log_debug("channel: %d, add sub, sub_count: %d", channel->id, channel->sub_count);

	evhttp_add_header(req->output_headers, "Content-Type", "text/html; charset=utf-8");
	evhttp_send_reply_start(req, HTTP_OK, "OK");

	struct evbuffer *buf;
	buf = evbuffer_new();
	evbuffer_add_printf(buf, "%s({type: \"hello\", id: \"%d\", content: \"From icomet server.\"});\n",
		sub->cb.c_str(),
		channel->id);
	evhttp_send_reply_chunk(req, buf);
	evbuffer_free(buf);

	evhttp_connection_set_closecb(req->evcon, on_disconnect, sub);

	return 0;
}
示例#10
0
文件: movid.cpp 项目: AChurikov/Movid
void web_pipeline_stream(struct evhttp_request *req, void *arg) {
	struct timeval when = { 0, 20 };
	struct evkeyvalq headers;
	const char *uri;
	int	idx = 0;
	moModule *module = NULL;

	uri = evhttp_request_uri(req);
	evhttp_parse_query(uri, &headers);

	if ( evhttp_find_header(&headers, "objectname") == NULL ) {
		evhttp_clear_headers(&headers);
		return web_error(req, "missing objectname");
	}

	module = module_search(evhttp_find_header(&headers, "objectname"), pipeline);
	if ( module == NULL ) {
		evhttp_clear_headers(&headers);
		return web_error(req, "object not found");
	}

	if ( evhttp_find_header(&headers, "index") != NULL )
		idx = atoi(evhttp_find_header(&headers, "index"));

	if ( idx < 0 || idx >= module->getOutputCount() ) {
		evhttp_clear_headers(&headers);
		return web_error(req, "invalid index");
	}

	struct chunk_req_state *state = (struct chunk_req_state*)malloc(sizeof(struct chunk_req_state));

	memset(state, 0, sizeof(struct chunk_req_state));
	state->req = req;
	state->closed = false;
	state->stream = new otStreamModule();
	state->delay = 100;

	if ( evhttp_find_header(&headers, "scale") != NULL )
		state->stream->property("scale").set(evhttp_find_header(&headers, "scale"));

	if ( evhttp_find_header(&headers, "delay") != NULL )
		state->delay = atoi(evhttp_find_header(&headers, "delay"));

	state->stream->setInput(module->getOutput(idx));

	evhttp_add_header(req->output_headers, "Content-Type", "multipart/x-mixed-replace; boundary=mjpegstream");
	evhttp_send_reply_start(req, HTTP_OK, "Everything is fine");

	evhttp_connection_set_closecb(req->evcon, web_pipeline_stream_close, state);

	event_once(-1, EV_TIMEOUT, web_pipeline_stream_trickle, state, &when);

}
示例#11
0
void HttpClient_YPL::post()
{
    //char *url = "/portal/sss";
    char *url = "/api/service";
    struct evhttp_request *req = evhttp_request_new(onRequestDone, this);
    evhttp_add_header(req->output_headers, "Host", m_host.c_str());
    evhttp_make_request(m_conn, req, EVHTTP_REQ_POST, url);
    evhttp_connection_set_timeout(req->evcon, 3);
    evhttp_connection_set_closecb(req->evcon, onClose, this);
    //evbuffer_add(req->output_buffer, "123", 3);
    event_base_dispatch(m_base);
}
示例#12
0
文件: server.cpp 项目: ITSTONE/icomet
int Server::psub(struct evhttp_request *req){
	bufferevent_enable(req->evcon->bufev, EV_READ);

	PresenceSubscriber *psub = new PresenceSubscriber();
	psub->req = req;
	psub->serv = this;
	psubs.push_back(psub);
	log_info("%s:%d psub, psubs: %d", req->remote_host, req->remote_port, psubs.size);

	evhttp_send_reply_start(req, HTTP_OK, "OK");
	evhttp_connection_set_closecb(req->evcon, on_psub_disconnect, psub);
	return 0;
}
示例#13
0
// create S3HttpConnection object
// establish HTTP connections to S3
gpointer s3http_connection_create (Application *app)
{
    S3HttpConnection *con;
    int port;
    AppConf *conf;

    con = g_new0 (S3HttpConnection, 1);
    if (!con) {
        LOG_err (CON_LOG, "Failed to create S3HttpConnection !");
        return NULL;
    }
    
    conf = application_get_conf (app);
    con->app = app;
    con->bucket_name = g_strdup (application_get_bucket_name (app));

    con->is_acquired = FALSE;

    port = application_get_port (app);
    // if no port is specified, libevent returns -1
    if (port == -1) {
        port = conf->http_port;
    }

    LOG_debug (CON_LOG, "Connecting to %s:%d", 
        application_get_host (app),
        port
    );

    // XXX: implement SSL
    con->evcon = evhttp_connection_base_new (
        application_get_evbase (app),
        application_get_dnsbase (app),
        application_get_host (app),
        port
    );

    if (!con->evcon) {
        LOG_err (CON_LOG, "Failed to create evhttp_connection !");
        return NULL;
    }
    
    evhttp_connection_set_timeout (con->evcon, conf->timeout);
    evhttp_connection_set_retries (con->evcon, conf->retries);

    evhttp_connection_set_closecb (con->evcon, s3http_connection_on_close, con);

    return (gpointer)con;
}
示例#14
0
void Subscriber::close(){
	log_debug("subscriber close invoked");
	if (req->evcon){
		evhttp_connection_set_closecb(req->evcon, NULL, NULL);
		log_debug("evhttp_connection_set_closecb invoked");
	}

	log_debug("before evhttp_send_reply_end");
	evhttp_send_reply_end(req);

	log_debug("before channel->serv->sub_end(this);");
	channel->serv->sub_end(this);
	log_debug("after channel->serv->sub_end(this);");
	
}
示例#15
0
void
mkhttp(runner *run)
{
    struct evhttp_connection *evcon;

    evcon = evhttp_connection_new(http_hostname, http_port);
    if(evcon == nil)
        panic("evhttp_connection_new");

    evhttp_connection_set_closecb(evcon, &closecb, run);
    /*
        note: we manage our own per-request timeouts, since the underlying
        library does not give us enough error reporting fidelity
    */
    run->evcon = evcon;
}
示例#16
0
文件: IoEvConnection.c 项目: ADTSH/io
IoObject *IoEvConnection_connect(IoEvConnection *self, IoObject *locals, IoMessage *m)
{
	IoEventManager *em = IoObject_getSlot_(self, IOSYMBOL("eventManager"));
	IoSeq *address = IoObject_seqGetSlot_(self, IOSYMBOL("address"));
	int port = IoObject_doubleGetSlot_(self, IOSYMBOL("port"));

	IOASSERT(CONN(self) == 0x0, "already have connection");
	IOASSERT(ISEEVENTMANAGER(em), "eventManager slot not set properly");

	//printf("IoEventManager_rawBase(em) = %p\n", (void *)IoEventManager_rawBase(em));

	IoObject_setDataPointer_(self, evhttp_connection_new(CSTRING(address), port));
	evhttp_connection_set_base(CONN(self), IoEventManager_rawBase(em));
	evhttp_connection_set_closecb(CONN(self), IoEvConnection_ConnectionCloseCallback, self);
	return self;
}
示例#17
0
struct evhttp_connection *
mkhttp()
{
	struct evhttp_connection *evcon;

	evcon = evhttp_connection_new(http_hostname, http_port);
	if(evcon == nil)
		panic("evhttp_connection_new");

	evhttp_connection_set_closecb(evcon, &closecb, nil);
	/*
		note: we manage our own per-request timeouts, since the underlying
		library does not give us enough error reporting fidelity
	*/

	/* also set some socket options manually. */


	return(evcon);
}
示例#18
0
void EvHttpSyncClient::open(const std::string& sHost, int32_t nPort)
{
    m_sHost = sHost;
    m_nPort = nPort;
    m_bOwnEventBase = false;

    if (!m_evbase)
    {
        FX_EVENT_BASE_NEW(m_evbase);
        m_bOwnEventBase = true;
    }

    m_pConn = evhttp_connection_base_new(m_evbase, NULL, m_sHost.c_str(), (unsigned short)m_nPort);
    if (!m_pConn)
    {
        FIRTEX_THROW_AND_LOG(NetworkException, "evhttp_connection_base_new FAILED");
    }

    setTimeout(DEFAULT_TIMEOUT);
    setRetries(DEFAULT_MAX_RETRY);
    evhttp_connection_set_closecb(m_pConn, onCloseConnection, this);

    m_lastState = ST_OK;
}
示例#19
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);
}
示例#20
0
文件: cmd.c 项目: orls/webdis
int
cmd_run(struct server *s, struct evhttp_request *rq,
		const char *uri, size_t uri_len, const char *body, size_t body_len) {

	char *qmark = strchr(uri, '?');
	char *slash;
	const char *p;
	int cmd_len;
	int param_count = 0, cur_param = 1, i;

	struct cmd *cmd;

	formatting_fun f_format;

	/* count arguments */
	if(qmark) {
		uri_len = qmark - uri;
	}
	for(p = uri; p && p < uri + uri_len; param_count++) {
		p = strchr(p+1, '/');
	}

	if(body && body_len) { /* PUT request */
		param_count++;
	}

	cmd = cmd_new(rq, param_count);

	/* parse URI parameters */
	evhttp_parse_query(uri, &cmd->uri_params);

	/* get output formatting function */
	uri_len = cmd_select_format(cmd, uri, uri_len, &f_format);

	/* check if we only have one command or more. */
	slash = memchr(uri, '/', uri_len);
	if(slash) {
		cmd_len = slash - uri;
	} else {
		cmd_len = uri_len;
	}

	/* there is always a first parameter, it's the command name */
	cmd->argv[0] = uri;
	cmd->argv_len[0] = cmd_len;


	/* check that the client is able to run this command */
	if(!acl_allow_command(cmd, s->cfg, rq)) {
		return -1;
	}

	/* check if we have to split the connection */
	if(cmd_is_subscribe(cmd)) {
		struct pubsub_client *ps;

		ps = calloc(1, sizeof(struct pubsub_client));
		ps->s = s = server_copy(s);
		ps->cmd = cmd;
		ps->rq = rq;
		evhttp_connection_set_closecb(rq->evcon, on_http_disconnect, ps);
	}

	/* no args (e.g. INFO command) */
	if(!slash) {
		redisAsyncCommandArgv(s->ac, f_format, cmd, 1, cmd->argv, cmd->argv_len);
		return 0;
	}
	p = slash + 1;
	while(p < uri + uri_len) {

		const char *arg = p;
		int arg_len;
		char *next = strchr(arg, '/');
		if(!next || next > uri + uri_len) { /* last argument */
			p = uri + uri_len;
			arg_len = p - arg;
		} else { /* found a slash */
			arg_len = next - arg;
			p = next + 1;
		}

		/* record argument */
		cmd->argv[cur_param] = decode_uri(arg, arg_len, &cmd->argv_len[cur_param], 1);
		cur_param++;
	}

	if(body && body_len) { /* PUT request */
		cmd->argv[cur_param] = body;
		cmd->argv_len[cur_param] = body_len;
	}

	/* push command to Redis. */
	redisAsyncCommandArgv(s->ac, f_format, cmd, cmd->count, cmd->argv, cmd->argv_len);

	for(i = 1; i < cur_param; ++i) {
		free((char*)cmd->argv[i]);
	}

	return 0;
}
示例#21
0
bool LibEventHttpClient::send(const std::string &url,
                              const std::vector<std::string> &headers,
                              int timeoutSeconds, bool async,
                              const void *data /* = NULL */,
                              int size /* = 0 */) {
  clear();
  m_url = url;

  if (m_conn == NULL) {
    m_conn = evhttp_connection_new(m_address.c_str(), m_port);
    evhttp_connection_set_closecb(m_conn, on_connection_closed, this);
    evhttp_connection_set_base(m_conn, m_eventBase);
  }
  m_request = evhttp_request_new(on_request_completed, this);

  // REVIEW: libevent never sends a Host header (nor does it properly send HTTP
  // 400 for HTTP/1.1 requests without such a header), in blatent violation of
  // RFC2616; this should perhaps be fixed in the library proper.
  if (m_port == 80) {
    evhttp_add_header(m_request->output_headers, "Host", m_address.c_str());
  } else {
    std::ostringstream ss;
    ss << m_address << ":" << m_port;
    evhttp_add_header(m_request->output_headers, "Host", ss.str().c_str());
  }

  // request headers
  bool keepalive = true;
  for (unsigned int i = 0; i < headers.size(); i++) {
    const std::string &header = headers[i];
    size_t pos = header.find(':');
    if (pos != string::npos && header[pos + 1] == ' ') {
      string name = header.substr(0, pos);
      if (strcasecmp(name.c_str(), "Connection") == 0) {
        keepalive = false;
      }
      int ret = evhttp_add_header(m_request->output_headers,
                                  name.c_str(), header.c_str() + pos + 2);
      if (ret >= 0) {
        continue;
      }
    }
    Logger::Error("invalid request header: [%s]", header.c_str());
  }
  if (keepalive) {
    evhttp_add_header(m_request->output_headers, "Connection", "keep-alive");
  }

  // post data
  if (data && size) {
    evbuffer_add(m_request->output_buffer, data, size);
  }

  // url
  evhttp_cmd_type cmd = data ? EVHTTP_REQ_POST : EVHTTP_REQ_GET;
  int ret = evhttp_make_request(m_conn, m_request, cmd, url.c_str());
  if (ret != 0) {
    Logger::Error("evhttp_make_request failed");
    return false;
  }

  if (timeoutSeconds > 0) {
    struct timeval timeout;
    timeout.tv_sec = timeoutSeconds;
    timeout.tv_usec = 0;

    event_set(&m_eventTimeout, -1, 0, timer_callback, m_eventBase);
    event_base_set(m_eventBase, &m_eventTimeout);
    event_add(&m_eventTimeout, &timeout);
  }

  if (async) {
    m_thread = new AsyncFunc<LibEventHttpClient>
      (this, &LibEventHttpClient::sendImpl);
    m_thread->start();
  } else {
    sendImpl();
  }
  return true;
}
示例#22
0
bool LibEventHttpClient::send(const std::string &url,
                              const std::vector<std::string> &headers,
                              int timeoutSeconds, bool async,
                              const void *data /* = NULL */,
                              int size /* = 0 */) {
  clear();
  m_url = url;

  evhttp_request* request = evhttp_request_new(on_request_completed, this);

  // request headers
  bool keepalive = true;
  bool addHost = true;
  for (unsigned int i = 0; i < headers.size(); i++) {
    const std::string &header = headers[i];
    size_t pos = header.find(':');
    if (pos != std::string::npos && header[pos + 1] == ' ') {
      std::string name = header.substr(0, pos);
      if (strcasecmp(name.c_str(), "Connection") == 0) {
        keepalive = false;
      } else if (strcasecmp(name.c_str(), "Host") == 0) {
        addHost = false;
      }
      int ret = evhttp_add_header(request->output_headers,
                                  name.c_str(), header.c_str() + pos + 2);
      if (ret >= 0) {
        continue;
      }
    }
    Logger::Error("invalid request header: [%s]", header.c_str());
  }
  if (keepalive) {
    evhttp_add_header(request->output_headers, "Connection", "keep-alive");
  }
  if (addHost) {
    // REVIEW: libevent never sends a Host header (nor does it properly send
    // HTTP 400 for HTTP/1.1 requests without such a header), in blatant
    // violation of RFC2616; this should perhaps be fixed in the library
    // proper.  For now, add it if it wasn't set by the caller.
    if (m_port == 80) {
      evhttp_add_header(request->output_headers, "Host", m_address.c_str());
    } else {
      std::ostringstream ss;
      ss << m_address << ":" << m_port;
      evhttp_add_header(request->output_headers, "Host", ss.str().c_str());
    }
  }

  // post data
  if (data && size) {
    evbuffer_add(request->output_buffer, data, size);
  }

  // url
  evhttp_cmd_type cmd = data ? EVHTTP_REQ_POST : EVHTTP_REQ_GET;

  // if we have a cached connection, we need to pump the event loop to clear
  // any "connection closed" events that may be sitting there patiently.
  if (m_conn) {
    event_base_loop(m_eventBase, EVLOOP_NONBLOCK);
  }

  // even if we had an m_conn immediately above, it may have been cleared out
  // by onConnectionClosed().
  if (m_conn == nullptr) {
    m_conn = evhttp_connection_new(m_address.c_str(), m_port);
    evhttp_connection_set_closecb(m_conn, on_connection_closed, this);
    evhttp_connection_set_base(m_conn, m_eventBase);
  }

  int ret = evhttp_make_request(m_conn, request, cmd, url.c_str());
  if (ret != 0) {
    Logger::Error("evhttp_make_request failed");
    return false;
  }

  if (timeoutSeconds > 0) {
    struct timeval timeout;
    timeout.tv_sec = timeoutSeconds;
    timeout.tv_usec = 0;

    event_set(&m_eventTimeout, -1, 0, timer_callback, m_eventBase);
    event_base_set(m_eventBase, &m_eventTimeout);
    event_add(&m_eventTimeout, &timeout);
  }

  if (async) {
    m_thread = new AsyncFunc<LibEventHttpClient>
      (this, &LibEventHttpClient::sendImpl);
    m_thread->start();
  } else {
    IOStatusHelper io("libevent_http", m_address.c_str(), m_port);
    sendImpl();
  }
  return true;
}