예제 #1
0
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();
	}
}
예제 #2
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] );
}
예제 #3
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();
	}
}
예제 #4
0
/*
 * Start reply to client
 * @param [Fixnum] code HTTP code
 * @param [String] reason (optional) response descriptor
 * @return [nil]
 */
static VALUE t_send_reply_start(VALUE self, VALUE code, VALUE reason) {
    Libevent_HttpRequest *http_request;

    Data_Get_Struct(self, Libevent_HttpRequest, http_request);
    Check_Type(code, T_FIXNUM);

    evhttp_send_reply_start(http_request->ev_request, FIX2INT(code), reason == Qnil ? NULL : RSTRING_PTR(reason));

    return Qnil;
}
예제 #5
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;
}
예제 #6
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);

}
예제 #7
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;
}
void HTTPHandler::info_handle(struct evhttp_request *req, void *arg) {
  if (evhttp_request_get_command(req) != EVHTTP_REQ_GET)
    return;

  LOG(INFO) << "Request for server infomation.";

  // TODO(binfei): need memory pool
  struct evbuffer *databuf = evbuffer_new();
  evbuffer_add_printf(databuf, "hello world");
  evhttp_send_reply_start(req, 200, "OK");
  evhttp_send_reply_chunk(req, databuf);
  evhttp_send_reply_end(req);
  evbuffer_free(databuf);
}
//-----------------------------------------------------------------------------
void HTTPHandler::admin_handle(struct evhttp_request *req, void *arg) {
  //TODO(binfei): need ssl and sepecial command to do admin privilege
  LOG(INFO) << "Request for server admin.";
  // TODO(binfei): need memory pool
  struct evbuffer *databuf = evbuffer_new();
  evbuffer_add_printf(databuf, "Server will be stoped.");
  evhttp_send_reply_start(req, 200, "OK");
  evhttp_send_reply_chunk(req, databuf);
  evhttp_send_reply_end(req);
  evbuffer_free(databuf);
  
  HTTPServer *server = static_cast<HTTPServer*>(arg);
  server->Stop();
}
예제 #10
0
void PendingResponseQueue::process() {
  // clean up the pipe for next signals
  char buf[512];
  if (read(m_ready.getOut(), buf, sizeof(buf)) < 0) {
    // an error occured but nothing we can really do
  }

  // making a copy so we don't hold up the mutex very long
  ResponsePtrVec responses;
  for (int i = 0; i < RuntimeOption::ResponseQueueCount; i++) {
    ResponseQueue &q = *m_responseQueues[i];
    Lock lock(q.m_mutex);
    responses.insert(responses.end(),
                     q.m_responses.begin(), q.m_responses.end());
    q.m_responses.clear();
  }

  for (unsigned int i = 0; i < responses.size(); i++) {
    Response &res = *responses[i];
    evhttp_request *request = res.request;
    int code = res.code;

    if (request->evcon == nullptr) {
      evhttp_request_free(request);
      continue;
    }

    bool skip_sync = false;
#ifdef _EVENT_USE_OPENSSL
    skip_sync = evhttp_is_connection_ssl(request->evcon);
#endif

    if (res.chunked) {
      if (res.chunk) {
        if (res.firstChunk) {
          const char *reason = HttpProtocol::GetReasonString(code);
          evhttp_send_reply_start(request, code, reason);
        }
        evhttp_send_reply_chunk(request, res.chunk);
      } else {
        evhttp_send_reply_end(request);
      }
    } else if (RuntimeOption::LibEventSyncSend && !skip_sync) {
      evhttp_send_reply_sync_end(res.nwritten, request);
    } else {
      const char *reason = HttpProtocol::GetReasonString(code);
      evhttp_send_reply(request, code, reason, nullptr);
    }
  }
}
예제 #11
0
/*
 * Send reply to client
 * @param [Fixnum] code HTTP code
 * @param [Hash] headers hash of http output headers
 * @param [Object] body object that response to each method that returns strings
 * @return [nil]
 */
static VALUE t_send_reply(VALUE self, VALUE code, VALUE headers, VALUE body) {
    Libevent_HttpRequest *http_request;

    Data_Get_Struct(self, Libevent_HttpRequest, http_request);
    Check_Type(code, T_FIXNUM);
    Check_Type(headers, T_HASH);

    t_set_output_headers(self, headers);

    evhttp_send_reply_start(http_request->ev_request, FIX2INT(code), NULL);
    rb_iterate(rb_each, body, t_send_chunk, self);
    evhttp_send_reply_end(http_request->ev_request);

    return Qnil;
}
//-----------------------------------------------------------------------------
bool HTTPHandler::handle(HTTPRequest *req, HTTPResponse *resp) {
  //call callback functions
  if (func_ == NULL || req == NULL || resp == NULL)
    return false;
  
  //prepare header, check if long or short connection
  const char* value = req->FindHeaders(connection_key);
  if (value != NULL && 
      strncmp(connection_value, value, strlen(connection_value)) == 0)
    evhttp_add_header(resp->req_->output_headers, connection_key, 
                      connection_value);
  evhttp_send_reply_start(resp->req_, HTTP_OK, "OK");
  
  (*func_)(req, resp, boost::bind(&HTTPHandler::finish, this, 
                                        _1, req, resp));
  return true;
}
예제 #13
0
static void
http_chunked_cb(struct evhttp_request *req, void *arg)
{
	struct timeval when = { 0, 0 };
	struct chunk_req_state *state = malloc(sizeof(struct chunk_req_state));
	event_debug(("%s: called\n", __func__));

	memset(state, 0, sizeof(struct chunk_req_state));
	state->req = req;

	/* generate a chunked reply */
	evhttp_send_reply_start(req, HTTP_OK, "Everything is fine");

	/* but trickle it across several iterations to ensure we're not
	 * assuming it comes all at once */
	event_once(-1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when);
}
예제 #14
0
void PendingResponseQueue::process() {
  // clean up the pipe for next signals
  char buf[512];
  read(m_ready.getOut(), buf, sizeof(buf));

  // making a copy so we don't hold up the mutex very long
  ResponsePtrVec responses;
  for (int i = 0; i < RuntimeOption::ResponseQueueCount; i++) {
    ResponseQueue &q = *m_responseQueues[i];
    Lock lock(q.m_mutex);
    responses.insert(responses.end(),q.m_responses.begin(),q.m_responses.end());
    q.m_responses.clear();
  }

  for (unsigned int i = 0; i < responses.size(); i++) {
    Response &res = *responses[i];
    evhttp_request *request = res.request;
    int code = res.code;

    if (res.chunked) {
      if (res.chunk) {
        if (res.firstChunk) {
          const char *reason = HttpProtocol::GetReasonString(code);
          evhttp_send_reply_start(request, code, reason);
        }
        evhttp_send_reply_chunk(request, res.chunk);
      } else {
        evhttp_send_reply_end(request);
      }
    } else if (RuntimeOption::LibEventSyncSend) {
      evhttp_send_reply_sync_end(res.nwritten, request);
    } else {
      const char *reason = HttpProtocol::GetReasonString(code);
      evhttp_send_reply(request, code, reason, NULL);
    }
  }
}
예제 #15
0
파일: server.c 프로젝트: denis2342/pushpool
static void http_handle_req(struct evhttp_request *req, lp_type longpoll, bool *req_valid)
{
	const char *clen_str;
	char *body_str;
	char username[65] = "";
	void *body, *reply = NULL;
	int clen = 0;
	unsigned int reply_len = 0;
	json_t *jreq;
	json_error_t jerr;
	bool rc;
	struct evbuffer *evbuf;

	if (!http_get_username(req, username, req->chunked))
 		return;

	if (longpoll == LP_NONE) {
		clen_str = evhttp_find_header(req->input_headers, "Content-Length");
		if (clen_str)
			clen = atoi(clen_str);
		if (clen < 1 || clen > 999999) {
			reqlog(req->remote_host, username, req->uri);
			goto err_out_bad_req;
		}

		if (EVBUFFER_LENGTH(req->input_buffer) != clen)
			goto err_out_bad_req;
		body = EVBUFFER_DATA(req->input_buffer);
		body_str = strndup(body, clen);
		if (!body_str)
			goto err_out_bad_req;
	} else if (longpoll == LP_REPLY) {
		body_str = strdup("{\"method\":\"getwork\",\"params\":[],\"id\":1}");
	} else if (longpoll == LP_KEEPALIVE || longpoll == LP_CLOSE) {
		reply = malloc(sizeof(char) * 2);
		if (!reply)
			goto err_out_bad_req;
		reply_len = snprintf(reply, 2, " ");
	}

	if (!reply) {
		jreq = JSON_LOADS(body_str, &jerr);

		free(body_str);

		if (!jreq)
			goto err_out_bad_req;

		rc = msg_json_rpc(req, jreq, username, &reply, &reply_len);

		json_decref(jreq);

		if (!rc)
			goto err_out_bad_req;
	}

	evbuf = evbuffer_new();
	if (!evbuf) {
		free(reply);
		goto err_out_bad_req;
	}
	if (evbuffer_add(evbuf, reply, reply_len)) {
		evbuffer_free(evbuf);
		free(reply);
		goto err_out_bad_req;
	}

	free(reply);

	/* req_valid is a pointer to the valid member of the list struct
	 * containing the LP request. When the connection drops and
	 * http_lp_close_cb is called, this bool is set to false. Because we
	 * have the reference, we can check before each send command if the
	 * close callback has been called or if the request is still OK.
	 *
	 * We only have to check this when sending chunked, because if we send
	 * in one go, there is nothing that could have closed the request, as
	 * we're single threaded. For now.
	 */
	if (longpoll == LP_NONE) {
		/* Send normal requests not chunked */
		evhttp_send_reply(req, HTTP_OK, "ok", evbuf);
	} else {
		if (!req->chunked && is_valid(req_valid))
			evhttp_send_reply_start(req, HTTP_OK, "ok");
		if (is_valid(req_valid))
			evhttp_send_reply_chunk(req, evbuf);
		if (longpoll != LP_KEEPALIVE && is_valid(req_valid))
			evhttp_send_reply_end(req);
	}

	evbuffer_free(evbuf);

	return;

err_out_bad_req:
	/* When we've already sent headers, we can't really give an error so
	 * we just send an empty reply...
	 */
	if (req->chunked) {
		if (is_valid(req_valid))
			evhttp_send_reply_end(req);
	} else {
		evhttp_send_reply(req, HTTP_BADREQUEST, "invalid args", NULL);
	}
}
예제 #16
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);
}
 static void HHVM_METHOD(EventHttpRequest, sendReplyStart, int64_t code, const String &reason) {
     EventHttpRequestResourceData *event_http_request_resource_data = FETCH_RESOURCE(this_, EventHttpRequestResourceData, s_event_http_request);
     evhttp_send_reply_start((evhttp_request_t *) event_http_request_resource_data->getInternalResourceData(), code, reason.c_str());
 }
예제 #18
0
void handle_http_static(struct evhttp_request *req, void *arg){
	global_data * global = (global_data *) arg;

	struct evkeyvalq options;

	evhttp_parse_query(req->uri, &options);

	char filename[1000];
	filename[0] = '\0';

	strcat(filename, global->static_source);

//make sure it ends in / at this point
	if(filename[strlen(filename)-1] != '/')
		strcat(filename, "/");

	char * start = req->uri;
	if(*start == '/')
		++start;
	char * ptr = start;

	//look for the end of the string, end of the uri, or ..
	while(*ptr != '\0' && *ptr != '?' && !(*ptr == '.' && *(ptr+1) == '.')) 
		++ptr;

	if(*ptr == '\0'){
		strncat(filename, start, 1000 - (ptr - start) - strlen(filename));
	}else if(*ptr == '?'){
		strncat(filename, start, (ptr - start < (unsigned int)(1000 - strlen(filename)) ? ptr - start : 1000 - strlen(filename)) );
	}
	//if it included .. , just ignore the url altogether

//add index.html if it ends in / at this point
	if(filename[strlen(filename)-1] == '/')
		strcat(filename, "index.html");

	FILE *fd;
	char buf[4096];

	if((fd = fopen(filename, "r")) == NULL){
		struct evbuffer *evb;
		evb = evbuffer_new();
		evbuffer_add_printf(evb, "File Not found:  %s\n", req->uri);
		
		evhttp_send_reply(req, HTTP_NOTFOUND, "Not Found", evb);
		evbuffer_free(evb);
	}else{
		evhttp_send_reply_start(req, HTTP_OK, "OK");

		int len;
		struct evbuffer *evb;
		while((len = fread(buf, sizeof(char), 4096, fd))){
			evb = evbuffer_new();
			evbuffer_add(evb, buf, len);
		
			evhttp_send_reply_chunk(req, evb);
			evbuffer_free(evb);
		}

		evhttp_send_reply_end(req);
		
		fclose(fd);
	}
	evhttp_clear_headers(&options);
}