Exemplo n.º 1
0
/**
 * Callback used for doc request
 */
static void doc_request_cb(struct evhttp_request *req, void *arg)
{
	std::chrono::high_resolution_clock::time_point t0 = std::chrono::high_resolution_clock::now();

	if (evhttp_request_get_command(req) != EVHTTP_REQ_GET)
	{
		std::cerr << "Invalid query request! Needs to be GET" << std::endl;
		evhttp_send_error(req, HTTP_BADREQUEST, 0);
	}
	else
	{
		struct evbuffer *evb = NULL;
		const char *uri = evhttp_request_get_uri(req);
		struct evhttp_uri *decoded = NULL;
		// const char *path = NULL;
		const char *query = NULL;

		printf("Got a GET request for %s\n",  uri);

		// Decode the URI
		decoded = evhttp_uri_parse(uri);

		if (!decoded)
		{
			printf("It's not a good URI. Sending BADREQUEST\n");
			evhttp_send_error(req, HTTP_BADREQUEST, 0);
			return;
		}

		// path = evhttp_uri_get_path(decoded);
		// std::cout << path << std::endl;

		query = evhttp_uri_get_query(decoded);
		// std::cout << query << std::endl;

		// This holds the content we're sending
		evb = evbuffer_new();

		struct evkeyvalq params;	// create storage for your key->value pairs
		struct evkeyval *param;		// iterator

		int result = evhttp_parse_query_str(query, &params);

		if (result == 0)
		{
			bool found = false;

			for (param = params.tqh_first; param; param = param->next.tqe_next)
			{
				std::string key(param->key);
				std::string value(param->value);

				// printf("%s %s\n", key.c_str(), value.c_str());

				if (key.compare(zsearch::server::DOC_ID_KEY) == 0)
				{
					unsigned int docId = 0;

					try
					{
						docId = ZUtil::getUInt(value);

						std::cout << "retrieving document " << value << std::endl;

						std::shared_ptr<IDocument> document = make_shared<DocumentImpl>();

						if (engine->getDoc(docId, document))
						{
							std::stringstream ss;
							document->write(ss);
							const std::string docStr = ss.str();
							// cout << docStr << endl;

							evbuffer_add(evb, docStr.data(), docStr.size());
							found = true;
						}
					}

					// TODO: consider splitting out the errors so we know if the problem is getting the docId or in the engine

					catch (const std::string& e)
					{
						// no need to do anything here
						// evbuffer_add_printf(evb, "Invalid docId\n");
						// evbuffer_add_printf(evb, e.c_str());
					}

					break; // break out of looping through parameters
				}
			}

			if (found)
			{
				evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/xml");
				evhttp_send_reply(req, 200, "OK", evb);
			}
			else
			{
				/*
				evbuffer_add_printf(evb, "Document not found or invalid docId");
				evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/html");
				*/

				evhttp_send_error(req, 404, "Document not found.");
			}

		}
		else
		{
			evhttp_send_error(req, HTTP_BADREQUEST, 0);
		}

		evhttp_clear_headers(&params);


		if (decoded)
		{
			evhttp_uri_free(decoded);
		}

		if (evb)
		{
			evbuffer_free(evb);
		}
	}

	std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now();
	std::chrono::nanoseconds timeTaken = std::chrono::duration_cast<std::chrono::nanoseconds>(t1 - t0);
	std::cout << ZUtil::printTimeTaken(timeTaken) << std::endl;
}
Exemplo n.º 2
0
static void static_files_cb(struct evhttp_request *req, void *arg)
{
    http_serverlog_request(req);
    const char *static_root = arg;
    apr_pool_t *local_pool;
    const char *full_name;
    struct stat64 file_stat;
    const char *mime_type;

    if(!static_root)
    {
        LOG4C_ERROR(logger, "static root not configured");
        evhttp_send_error(req, HTTP_NOTFOUND, "Static file server not configured");
        return;
    }

    const char *uri = evhttp_request_get_uri(req);

    if (strstr(uri, "..") != NULL)
    {
        LOG4C_ERROR(logger, "illegal URL");
        evhttp_send_error(req, HTTP_BADREQUEST, "Illegal URL");
        return;
    }

    CREATE_POOL(local_pool, NULL);

    const char *path = get_path_from_uri(local_pool, uri);

    mime_type = guess_mime_type(uri);

    LOG4C_DEBUG(logger, "mime type is %s", mime_type);

    full_name = apr_pstrcat(local_pool, static_root, "/", path, NULL);

    if (lstat64(full_name, &file_stat) < 0)
    {
        LOG4C_ERROR(logger, "file not found");
        evhttp_send_error(req, HTTP_NOTFOUND, NULL);
        return;
    }

    int fd = open(full_name, O_RDONLY);
    if (fd < 0)
    {
        LOG4C_ERROR(logger, "open failed");
        evhttp_send_error(req, HTTP_NOTFOUND, NULL);
        return;
    }

    struct evbuffer *rep_buf = evbuffer_new();

    evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", mime_type);
    evbuffer_set_flags(rep_buf, EVBUFFER_FLAG_DRAINS_TO_FD);
    //TODO: LIBEVENT DOES NOT SUPPORT LARGE FILES - USES off_t BUT _FILE_OFFSET_BITS=64 IS NOT DEFINED!
    evbuffer_add_file(rep_buf, fd, 0, file_stat.st_size); //
    evhttp_send_reply(req, HTTP_OK, "OK", rep_buf);

    evbuffer_free(rep_buf);

    RELEASE_POOL(local_pool);
}
Exemplo n.º 3
0
/**
 * Call back used for a POST request
 */
static void post_request_cb(struct evhttp_request *req, void *arg)
{
	std::chrono::high_resolution_clock::time_point t0 = std::chrono::high_resolution_clock::now();

	/*

	bool isPostRequest = false;
	const char *cmdtype = NULL;

	switch (evhttp_request_get_command(req))
	{
		case EVHTTP_REQ_GET: cmdtype = "GET"; break;
		case EVHTTP_REQ_POST: cmdtype = "POST"; isPostRequest = true; break;
		case EVHTTP_REQ_HEAD: cmdtype = "HEAD"; break;
		case EVHTTP_REQ_PUT: cmdtype = "PUT"; break;
		case EVHTTP_REQ_DELETE: cmdtype = "DELETE"; break;
		case EVHTTP_REQ_OPTIONS: cmdtype = "OPTIONS"; break;
		case EVHTTP_REQ_TRACE: cmdtype = "TRACE"; break;
		case EVHTTP_REQ_CONNECT: cmdtype = "CONNECT"; break;
		case EVHTTP_REQ_PATCH: cmdtype = "PATCH"; break;
		default: cmdtype = "unknown"; break;
	}

	if (!isPostRequest)
	{
		evhttp_send_error(req, HTTP_BADREQUEST, 0);
	}
	*/

	if (evhttp_request_get_command(req) != EVHTTP_REQ_POST)
	{
		std::cerr << "Invalid request! Needs to be POST" << std::endl;
		evhttp_send_error(req, HTTP_BADREQUEST, 0);
	}
	else
	{
		struct evbuffer *evb = NULL;
		struct evkeyvalq *headers;
		struct evkeyval *header;
		struct evbuffer *buf;

		printf("Received a POST request for %s\nHeaders:\n", evhttp_request_get_uri(req));

		headers = evhttp_request_get_input_headers(req);

		for (header = headers->tqh_first; header; header = header->next.tqe_next)
		{
			printf("  %s: %s\n", header->key, header->value);
		}

		buf = evhttp_request_get_input_buffer(req);

		std::string postData;

		while (evbuffer_get_length(buf))
		{
			int n;
			char cbuf[128];
			n = evbuffer_remove(buf, cbuf, sizeof(buf)-1);
			if (n > 0)
			{
				// (void) fwrite(cbuf, 1, n, stdout);
				postData.append(cbuf, n);
			}
		}

		// std::cout << "Post data: " << std::endl << postData << std::endl;

		// do not remove this
		struct evkeyvalq params;	// create storage for your key->value pairs
		struct evkeyval *param;		// iterator

		// working code to return the parameters as plain text ...
		/*
		std::string postDataDecoded;

		if (result == 0)
		{
			for (param = params.tqh_first; param; param = param->next.tqe_next)
			{
				printf("%s %s\n", param->key, param->value);
				postDataDecoded.append(param->key);
				postDataDecoded.append(" ");
				postDataDecoded.append(param->value);
				postDataDecoded.append("\n");
			}

			evb = evbuffer_new();
			evbuffer_add_printf(evb, postDataDecoded.c_str());
			evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/html");

			evhttp_send_reply(req, 200, "OK", evb);
		}
		else
		{
			evhttp_send_error(req, HTTP_BADREQUEST, 0);
		}
		*/

		// working code to decode and index data

		int result = evhttp_parse_query_str(postData.c_str(), &params);

		// if we were able to parse post data ok
		if (result == 0)
		{
			param = params.tqh_first;

			std::string key(param->key);
			std::string value(param->value);

			// std::cout << value << std::endl;

			evb = evbuffer_new();

			// check that the first key is data
			if (key.compare(zsearch::server::POST_DATA_KEY) == 0)
			{
				try
				{
					std::shared_ptr<IDocument> document = std::make_shared<DocumentImpl>(value);
					unsigned int docId = engine->addDocument(document);
					std::cout << "Added document: " << docId << std::endl;
					evbuffer_add_printf(evb, "%d", docId);
				}
				catch (const std::string& e)
				{
					evbuffer_add_printf(evb, "Error parsing document. See documentation for more details\n");
					evbuffer_add_printf(evb, e.c_str());
				}
				catch (const std::exception& e)
				{
					evbuffer_add_printf(evb, "Error parsing document. See documentation for more details\n");
					evbuffer_add_printf(evb, e.what());
				}
			}
			else
			{
				evbuffer_add_printf(evb, "Invalid post data, first key must be in the form of data -> {xml}. See documentation for more details\n");
			}

			evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/html");
			evhttp_send_reply(req, 200, "OK", evb);

		}
		else
		{
			evhttp_send_error(req, HTTP_BADREQUEST, 0);
		}

		evhttp_clear_headers(&params);

		if (evb)
		{
			evbuffer_free(evb);
		}
	}

	std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now();
	std::chrono::nanoseconds timeTaken = std::chrono::duration_cast<std::chrono::nanoseconds>(t1 - t0);
	std::cout << ZUtil::printTimeTaken(timeTaken) << std::endl;
}
Exemplo n.º 4
0
/**
 * This callback gets invoked when we get any http request that doesn't match
 * any other callback.  Like any evhttp server callback, it has a simple job:
 * it must eventually call evhttp_send_error() or evhttp_send_reply().
 */
static void generic_request_cb(struct evhttp_request *req, void *arg)
{
	std::chrono::high_resolution_clock::time_point t0 = std::chrono::high_resolution_clock::now();

	// if this is not a GET request error out
	if (evhttp_request_get_command(req) != EVHTTP_REQ_GET)
	{
		std::cerr << "Invalid request! Needs to be GET" << std::endl;
		evhttp_send_error(req, HTTP_BADREQUEST, 0);
	}
	else
	{
		struct evbuffer *evb = NULL;
		const char *docroot = (char *) arg;
		const char *uri = evhttp_request_get_uri(req);
		struct evhttp_uri *decoded = NULL;
		const char *path;
		char *decoded_path;
		char *whole_path = NULL;
		size_t len;
		int fd = -1;
		struct stat st;

		printf("Got a GET request for %s\n",  uri);

		// Decode the URI
		decoded = evhttp_uri_parse(uri);
		if (!decoded)
		{
			printf("It's not a good URI. Sending BADREQUEST\n");
			evhttp_send_error(req, HTTP_BADREQUEST, 0);
			return;
		}

		// Let's see what path the user asked for
		path = evhttp_uri_get_path(decoded);
		if (!path)
		{
			path = zsearch::server::ROOT.c_str();
		}

		// We need to decode it, to see what path the user really wanted
		decoded_path = evhttp_uridecode(path, 0, NULL);

		bool error = false;

		if (decoded_path == NULL)
		{
			error = true;
		}
		else
		{
			// This holds the content we're sending
			evb = evbuffer_new();

			// add headers
			evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/html");

			if (zsearch::server::POST_HTM.compare(decoded_path) == 0)
			{
				len = strlen(decoded_path)+strlen(docroot)+2;
				whole_path = (char *) malloc(len);

				if (whole_path)
				{
					evutil_snprintf(whole_path, len, "%s/%s", docroot, decoded_path);

					if (stat(whole_path, &st)<0)
					{
						error = true;
					}
					else
					{
						if ((fd = open(whole_path, O_RDONLY)) < 0)
						{
							perror("open");
							error = true;

						}
						else
						{
							if (fstat(fd, &st)<0)
							{
								// Make sure the length still matches, now that we opened the file :/
								perror("fstat");
								error = true;
							}
							else
							{
								evbuffer_add_file(evb, fd, 0, st.st_size);
							}
						}
					}
				}
				else
				{
					perror("malloc");
					error = true;
				}
			}
			else // if (ROOT.compare(decoded_path) == 0)
			{
				evbuffer_add_printf(evb, "Invalid request <br />\n");
				evbuffer_add_printf(evb, "%s to post data manually or %s to post via api<br />\n", zsearch::server::POST_HTM.c_str(), zsearch::server::INDEX_PATH.c_str());
				evbuffer_add_printf(evb, "%s to search <br />\n", zsearch::server::SEARCH_PATH.c_str());
				evbuffer_add_printf(evb, "%s to get document by id <br />\n", zsearch::server::DOC_PATH.c_str());
			}
		}

		if (error)
		{
			if (fd >= 0)
				close(fd);

			evhttp_send_error(req, 404, "Document not found.");
		}
		else
		{
			evhttp_send_reply(req, 200, "OK", evb);
		}

		if (decoded)
			evhttp_uri_free(decoded);
		if (decoded_path)
			free(decoded_path);
		if (whole_path)
			free(whole_path);
		if (evb)
			evbuffer_free(evb);
	}

	std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now();
	std::chrono::nanoseconds timeTaken = std::chrono::duration_cast<std::chrono::nanoseconds>(t1 - t0);
	std::cout << ZUtil::printTimeTaken(timeTaken) << std::endl;
}
Exemplo n.º 5
0
static void
s2cover_request_cb(struct evhttp_request *req, void *arg)
{
  struct evkeyvalq  args;

  struct evbuffer *inputBuffer = evhttp_request_get_input_buffer (req);
  size_t record_len = evbuffer_get_length(inputBuffer);
  char *postData = NULL;
  const char *path = "/?";
  if (record_len > 0) { 
    postData = (char *)malloc(strlen(path) + record_len + 10);
    postData[0] = '/';
    postData[1] = '?';
    evbuffer_pullup(inputBuffer, -1);                                                                                                                                                     
    evbuffer_copyout(inputBuffer, (char *)postData + strlen(path), record_len);
    postData[strlen(path) + record_len] = '\0';
    printf("trying to parse: %s\n", (const char *)postData);
    evhttp_parse_query((const char *)postData, &args);
    char* points = (char *)evhttp_find_header(&args, "points");
    cout << points << endl;
  } else {
    const char *uri = evhttp_request_get_uri(req);
    evhttp_parse_query(uri, &args);
  }

  char* callback = (char *)evhttp_find_header(&args, "callback");

  char* points = (char *)evhttp_find_header(&args, "points");
  std::vector<S2CellId> cellids_vector;
  if (points != NULL) {
    printf(points);
    scoped_ptr<S2PolygonBuilder> builder(new S2PolygonBuilder(S2PolygonBuilderOptions::DIRECTED_XOR()));
    
    std::vector<std::string> points_vector = split(string(points), ',');
    std::vector<S2Point> s2points_vector;

    for (int i = 0; i < points_vector.size(); i += 2) {
      char *endptr;
      s2points_vector.push_back(S2LatLng::FromDegrees(
        strtod(points_vector[i].c_str(), &endptr),
        strtod(points_vector[i+1].c_str(), &endptr)
      ).ToPoint());
    }

    if (s2points_vector.size() == 1) {
      char* min_level = (char *)evhttp_find_header(&args, "min_level");
      if (min_level == NULL) {
        min_level = (char *)evhttp_find_header(&args, "max_level");
      }
      if (min_level == NULL) {
        min_level = "14";
      }

      int min_level_int = atoi(min_level);
      if (min_level_int > S2::kMaxCellLevel) {
        min_level_int = S2::kMaxCellLevel;
      }
      if (min_level_int < 0) {
        min_level_int = 0;
      }

      cellids_vector.push_back(S2CellId::FromPoint(s2points_vector[0]).parent(min_level_int));
    } else {
      for (int i = 0; i < s2points_vector.size(); i++) {
        builder->AddEdge(
          s2points_vector[i],
          s2points_vector[(i + 1) % s2points_vector.size()]);
      }

      S2Polygon polygon;
      typedef vector<pair<S2Point, S2Point> > EdgeList;
      EdgeList edgeList;
      builder->AssemblePolygon(&polygon, &edgeList);

      S2RegionCoverer coverer;

      char* min_level = (char *)evhttp_find_header(&args, "min_level");
      if (min_level) {
	int min_level_int = atoi(min_level);
	if (min_level_int > S2::kMaxCellLevel) {
	  min_level_int = S2::kMaxCellLevel;
        }
        if (min_level_int < 0) {
          min_level_int = 0;
        }
        coverer.set_min_level(min_level_int);
      }

      char* max_level = (char *)evhttp_find_header(&args, "max_level");
      if (max_level) {
	int max_level_int = atoi(max_level);
	if (max_level_int > S2::kMaxCellLevel) {
	  max_level_int = S2::kMaxCellLevel;
        }
        if (max_level_int < 0) {
          max_level_int = 0;
        }
        coverer.set_max_level(max_level_int);
      }

      char* level_mod = (char *)evhttp_find_header(&args, "level_mod");
      if (level_mod) {
        coverer.set_level_mod(atoi(level_mod));
      }

      char* max_cells = (char *)evhttp_find_header(&args, "max_cells");
      if (max_cells) {
        coverer.set_max_cells(atoi(max_cells));
      }

      coverer.GetCovering(polygon, &cellids_vector); 
    }
  }

  printf("\n");

	evhttp_add_header(evhttp_request_get_output_headers(req),
		    "Content-Type", "application/json");
	struct evbuffer *evb = NULL;
	evb = evbuffer_new();
  char* json = s2CellIdsToJson(callback, cellids_vector);
  evbuffer_add_printf(evb, "%s", json);
	evhttp_send_reply(req, 200, "OK", evb);
 
  free(json);

  if (postData)
    free(postData);

  if (evb)
    evbuffer_free(evb);
}
Exemplo n.º 6
0
Arquivo: owl.c Projeto: eliasson/owl
//
// Function called when a new HTTP request have been recieved.
//
static void http_handler(struct evhttp_request *request, void *userdata) {
    struct owl_state* state = userdata;

    // Setup general response headers
    struct evkeyvalq *headers = evhttp_request_get_output_headers(request);
    evhttp_add_header(headers, "Server", USER_AGENT);

    // Get the requested URI
    const char* uri = evhttp_request_get_uri(request);
    const int http_method = evhttp_request_get_command(request);

    if( http_method != EVHTTP_REQ_GET &&
            http_method != EVHTTP_REQ_PUT &&
            http_method != EVHTTP_REQ_POST) {
        evhttp_send_error(request, 501, "Not Implemented");
        return;
    }

    TRACE("Received HTTP request: %s (method %d)\n", uri, http_method);

    // Keep the request for async usage
    state->http_request = request;

    //
    // Retrieve application state (sync)
    if(string_starts_with(uri, "/api/state") && http_method == EVHTTP_REQ_GET) {
        state_action(state);
    }

    //
    // Shutdown owl application (async)
    else if(string_starts_with(uri, "/api/shutdown") && http_method == EVHTTP_REQ_GET) {
        shutdown_action(state);
    }

    //
    // Try to login to Spotify (async)
    else if(string_starts_with(uri, "/api/login") && http_method == EVHTTP_REQ_GET) {
        char* username = extract_uri_section(2, uri);
        char* password = extract_uri_section(3, uri);

        if(username != NULL && password != NULL) {
            login_to_spotify_action(state, username, password);
        }
        else {
            WARN("Could not extract username and password in order to login to Spotify!\n");
            respond_error(request, OWL_HTTO_ERROR_NO_LOGIN_DETAILS, "No username or password given");
        }
    }

    else if(string_starts_with(uri, "/api/login") && http_method == EVHTTP_REQ_POST) {
        TRACE("POST LOGIN\n");
        get_post_argument(request, "username");
        evhttp_send_error(request, 501, "Not Implemented");
    }

    //
    // Logout from spotify (async)
    else if(string_starts_with(uri, "/api/logout") && http_method == EVHTTP_REQ_GET) {
        if(state->state > OWL_STATE_LOGGING_IN && state->state < OWL_STATE_LOGGING_OUT)
            logout_from_spotify_action(state);
        else
            respond_success(request);
    }

    //
    // Clear the entire queue
    else if(string_starts_with(uri, "/api/queue/clear") && http_method == EVHTTP_REQ_GET) {
        if(state->state < OWL_STATE_IDLE || state->state > OWL_STATE_PLAYING) {
            respond_error(request, OWL_HTTP_ERROR_NOT_LOGGED_IN, "Operation not allowed when not logged in");
        }
        else {
            const int size = queue_size(state->spotify_state->queue);
            for(int i = 0; i < size; i++) {
                owl_track *track = pop_from_queue(state->spotify_state->queue);
                free_track(track);
            }
            respond_success(request);
        }
    }

    //
    // Get the current playback queue (sync)
    else if(string_starts_with(uri, "/api/queue") && http_method == EVHTTP_REQ_GET) {
        if(state->state < OWL_STATE_IDLE || state->state > OWL_STATE_PLAYING) {
            WARN("Operation not allowed at this state (%d)\n", state->state);
            respond_error(request, OWL_HTTP_ERROR_NOT_LOGGED_IN, "Operation not allowed when not logged in");
        }
        else {
            respond_with_queue(state->http_request, state->spotify_state->queue);
        }
    }

    //
    // Serve static file immediately
    else {
        // Create the buffer to retrn as content
        struct evbuffer *content_buffer = evbuffer_new();

        // If not a handler this is a static request
        char *static_file = (char *) malloc(strlen(doc_root) + strlen(uri) + 1);
        stpcpy(stpcpy(static_file, doc_root), uri);

        TRACE("Looking for static file: %s\n", static_file);

        bool file_exists = 1;
        struct stat st;
        if(stat(static_file, &st) == -1 || S_ISDIR(st.st_mode)) {
            file_exists = 0;
            evhttp_send_error(request, HTTP_NOTFOUND, "Not Found");
        }

        if(file_exists) {
            const int file_size = st.st_size;
            FILE *fp = fopen(static_file, "r");
            const char* content_type = resolve_content_type(static_file);

            evbuffer_add_file(content_buffer, fileno(fp), 0, file_size); // will close

            TRACE("Resolving content type for filename: %s to: %s\n", static_file, content_type);
            evhttp_add_header(headers, "Content-Type", content_type);
            evhttp_send_reply(request, HTTP_OK, "OK", content_buffer);
        }
        free(static_file);

        // Send the data
        evhttp_send_reply(request, HTTP_OK, USER_AGENT, content_buffer);

        // Free memrory
        evbuffer_free(content_buffer);
    }
    return;
}
Exemplo n.º 7
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;

      ret = transcode_setup(&st->xcode, mfi, &st->size, 1);
      if (ret < 0)
	{
	  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;
    }

  evutil_timerclear(&tv);
  event_set(&st->ev, -1, EV_TIMEOUT, stream_cb, st);
  event_base_set(evbase_httpd, &st->ev);
  ret = event_add(&st->ev, &tv);
  if (ret < 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);
}
Exemplo n.º 8
0
void HTTPRequest::WriteHeader(const std::string& hdr, const std::string& value)
{
    struct evkeyvalq* headers = evhttp_request_get_output_headers(req);
    assert(headers);
    evhttp_add_header(headers, hdr.c_str(), value.c_str());
}
Exemplo n.º 9
0
/*
 ******************************************************************************
 * dgadmin_rest_sync_version_query --                                         *//**
 *
 * \brief This routine sends version GET request to DMC.
 *
 * \param [out]	req_body_buf	A pointer to request input body buffer.
 *
 * \retval 0 	Success
 * \retval >0 	Failure
 *
 *****************************************************************************/
static int dgadmin_rest_sync_version_query(char **req_body_buf, int *resp)
{
	struct evhttp_request *new_request = NULL;
	dgadmin_rest_sync_response_args_t args;
	char uri[DGADMIN_URI_LEN];
	char host_header_str[128];
	int ret = DOVE_STATUS_OK;

    if((!g_dmc_ipv4) || (!g_dmc_port) )
    {
        log_alert(ServiceUtilLogLevel,
                  "Unknown: DMC Info!\n"); 
        return 0;
    }


	do
	{
        struct sockaddr_in sa;
	    char *dmc_httpd_addr = NULL;
		/* construct a new request */
		memset(&args, 0, sizeof(args));
		new_request = evhttp_request_new(dgadmin_rest_sync_response_handler, &args);
		if (new_request == NULL)
		{
			ret = DOVE_STATUS_NO_MEMORY;
            log_notice(ServiceUtilLogLevel,"ERROR");
			break;
		}

        sa.sin_addr.s_addr = g_dmc_ipv4;
        dmc_httpd_addr = inet_ntoa(sa.sin_addr);
		sprintf(host_header_str,"%s:%d", dmc_httpd_addr, g_dmc_port);

		evhttp_add_header(evhttp_request_get_output_headers(new_request), "Host", host_header_str);

        /* Set HTTP Authorization Field
          Basic YWRtaW46YWRtaW4=  Base_64 Encoded Value of the String 'Basic admin:admin" */
        evhttp_add_header(evhttp_request_get_output_headers(new_request),
                          "Authorization", "Basic YWRtaW46YWRtaW4=");

		/* send the GET request to DMC */
		memset(uri, 0, sizeof(uri));
		sprintf(uri, "%s/%d", DGADMIN_REST_SYNC_VERSION_URI, g_dgwconfig_curversion);
		log_notice(ServiceUtilLogLevel, "Sending %s GET REQ to DMC[%s:%d]", 
                  uri, dmc_httpd_addr, g_dmc_port);
		ret = dove_rest_request_and_syncprocess(dmc_httpd_addr,
                                                g_dmc_port,
                                                EVHTTP_REQ_GET, uri,
                                                new_request, NULL,
                                                DGADMIN_REST_SYNC_CONNECT_TIMEOUT);

		*req_body_buf = args.req_body_buf;

		if (ret)
		{
            log_alert(ServiceUtilLogLevel,
                      "ERROR:REST syncprocess\n");
			ret = DOVE_STATUS_ERROR;
			break;
		}
        *resp = args.res_code;
		if ((args.res_code != HTTP_OK) && (args.res_code != 201))
		{
            log_alert(ServiceUtilLogLevel,
                      "ERROR:REST DMC changeversion respose %d\n",args.res_code);
			ret = DOVE_STATUS_ERROR;
			break;
		}
	} while (0);

	return ret;
}
Exemplo n.º 10
0
int
httpd_basic_auth(struct evhttp_request *req, char *user, char *passwd, char *realm)
{
  struct evbuffer *evbuf;
  struct evkeyvalq *headers;
  char *header;
  const char *auth;
  char *authuser;
  char *authpwd;
  int len;
  int ret;

  headers = evhttp_request_get_input_headers(req);
  auth = evhttp_find_header(headers, "Authorization");
  if (!auth)
    {
      DPRINTF(E_DBG, L_HTTPD, "No Authorization header\n");

      goto need_auth;
    }

  if (strncmp(auth, "Basic ", strlen("Basic ")) != 0)
    {
      DPRINTF(E_LOG, L_HTTPD, "Bad Authentication header\n");

      goto need_auth;
    }

  auth += strlen("Basic ");

  authuser = b64_decode(auth);
  if (!authuser)
    {
      DPRINTF(E_LOG, L_HTTPD, "Could not decode Authentication header\n");

      goto need_auth;
    }

  authpwd = strchr(authuser, ':');
  if (!authpwd)
    {
      DPRINTF(E_LOG, L_HTTPD, "Malformed Authentication header\n");

      free(authuser);
      goto need_auth;
    }

  *authpwd = '\0';
  authpwd++;

  if (user)
    {
      if (strcmp(user, authuser) != 0)
	{
	  DPRINTF(E_LOG, L_HTTPD, "Username mismatch\n");

	  free(authuser);
	  goto need_auth;
	}
    }

  if (strcmp(passwd, authpwd) != 0)
    {
      DPRINTF(E_LOG, L_HTTPD, "Bad password\n");

      free(authuser);
      goto need_auth;
    }

  free(authuser);

  return 0;

 need_auth:
  len = strlen(realm) + strlen("Basic realm=") + 3;
  header = (char *)malloc(len);
  if (!header)
    {
      evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error");
      return -1;
    }

  ret = snprintf(header, len, "Basic realm=\"%s\"", realm);
  if ((ret < 0) || (ret >= len))
    {
      evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error");
      return -1;
    }

  evbuf = evbuffer_new();
  if (!evbuf)
    {
      evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error");
      return -1;
    }

  headers = evhttp_request_get_output_headers(req);
  evhttp_add_header(headers, "WWW-Authenticate", header);
  evbuffer_add(evbuf, http_reply_401, strlen(http_reply_401));
  evhttp_send_reply(req, 401, "Unauthorized", evbuf);

  free(header);
  evbuffer_free(evbuf);

  return -1;
}
Exemplo n.º 11
0
/*
 ******************************************************************************
 * dgadmin_rest_sync_target_uri_get --                                        *//**
 *
 * \brief This routine sends a GET request for target URI to DMC.
 *
 * \param [in]  uri		The URI of the HTTP request.
 *
 * \param [out]	req_body_buf	A pointer to request input body buffer.
 *
 * \retval 0 	Success
 * \retval >0 	Failure
 *
 *****************************************************************************/
static int dgadmin_rest_sync_target_uri_get(const char *uri, char **req_body_buf, int *resp_code)
{
	struct evhttp_request *new_request = NULL;
	dgadmin_rest_sync_response_args_t args;
	char host_header_str[128];
	int ret = DOVE_STATUS_OK;

	do
	{
        struct sockaddr_in sa;
	    char *dmc_httpd_addr = NULL;
		/* construct a new request */
		memset(&args, 0, sizeof(args));
		new_request = evhttp_request_new(dgadmin_rest_sync_response_handler, &args);
		if (new_request == NULL)
		{
			ret = DOVE_STATUS_NO_MEMORY;
            log_notice(ServiceUtilLogLevel,"ERROR");
			break;
		}

        sa.sin_addr.s_addr = g_dmc_ipv4;
        dmc_httpd_addr = inet_ntoa(sa.sin_addr);
		sprintf(host_header_str,"%s:%d", dmc_httpd_addr, g_dmc_port);

		evhttp_add_header(evhttp_request_get_output_headers(new_request), "Host", host_header_str);
        
        /* Set HTTP Authorization Field
          Basic YWRtaW46YWRtaW4=  Base_64 Encoded Value of the String 'Basic admin:admin" */
        evhttp_add_header(evhttp_request_get_output_headers(new_request),
                          "Authorization", "Basic YWRtaW46YWRtaW4=");


		/* send the GET request for target URI to DMC */
		log_notice(ServiceUtilLogLevel, "Sending %s GET REQ to DMC[%s:%d]", 
                  uri, dmc_httpd_addr, g_dmc_port);
		ret = dove_rest_request_and_syncprocess(dmc_httpd_addr,
                                                g_dmc_port,
                                                EVHTTP_REQ_GET, uri,
                                                new_request, NULL,
                                                DGADMIN_REST_SYNC_CONNECT_TIMEOUT);

		*req_body_buf = args.req_body_buf;

		if (ret)
		{
			ret = DOVE_STATUS_ERROR;
            log_notice(ServiceUtilLogLevel,"ERROR");
			break;
		}
        *resp_code = args.res_code;
		if ((args.res_code != HTTP_OK) && (args.res_code != 201))
		{
			ret = DOVE_STATUS_ERROR;
            log_notice(ServiceUtilLogLevel,"ERROR");
			break;
		}
	} while (0);

	return ret;
}
Exemplo n.º 12
0
int
http_client_request(struct http_client_ctx *ctx)
{
  struct evhttp_connection *evcon;
  struct evhttp_request *req;
  struct evkeyvalq *headers;
  char hostname[PATH_MAX];
  char path[PATH_MAX];
  char s[PATH_MAX];
  int port;
  int ret;

  ctx->ret = -1;

  av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, path, sizeof(path), ctx->url);
  if (strlen(hostname) == 0)
    {
      DPRINTF(E_LOG, L_HTTP, "Error extracting hostname from URL: %s\n", ctx->url);

      return ctx->ret;
    }

  if (port <= 0)
    snprintf(s, PATH_MAX, "%s", hostname);
  else
    snprintf(s, PATH_MAX, "%s:%d", hostname, port);

  if (port <= 0)
    port = 80;

  if (strlen(path) == 0)
    {
      path[0] = '/';
      path[1] = '\0';
    }

  ctx->evbase = event_base_new();
  if (!ctx->evbase)
    {
      DPRINTF(E_LOG, L_HTTP, "Could not create or find http client event base\n");

      return ctx->ret;
    }

  evcon = evhttp_connection_base_new(ctx->evbase, NULL, hostname, (unsigned short)port);
  if (!evcon)
    {
      DPRINTF(E_LOG, L_HTTP, "Could not create connection to %s\n", hostname);

      event_base_free(ctx->evbase);
      return ctx->ret;
    }

  evhttp_connection_set_timeout(evcon, HTTP_CLIENT_TIMEOUT);
  
  /* Set up request */
  req = evhttp_request_new(request_cb, ctx);
  if (!req)
    {
      DPRINTF(E_LOG, L_HTTP, "Could not create request to %s\n", hostname);

      evhttp_connection_free(evcon);
      event_base_free(ctx->evbase);
      return ctx->ret;
    }

#ifndef HAVE_LIBEVENT2_OLD
  if (ctx->headers_only)
    evhttp_request_set_header_cb(req, request_header_cb);
#endif

  headers = evhttp_request_get_output_headers(req);
  evhttp_add_header(headers, "Host", s);
  evhttp_add_header(headers, "Content-Length", "0");
  evhttp_add_header(headers, "User-Agent", "forked-daapd/" VERSION);
  evhttp_add_header(headers, "Icy-MetaData", "1");

  /* Make request */
  DPRINTF(E_INFO, L_HTTP, "Making request for http://%s%s\n", s, path);

  ret = evhttp_make_request(evcon, req, EVHTTP_REQ_GET, path);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_HTTP, "Error making request for http://%s%s\n", s, path);

      evhttp_connection_free(evcon);
      event_base_free(ctx->evbase);
      return ctx->ret;
    }

  event_base_dispatch(ctx->evbase);

  evhttp_connection_free(evcon);
  event_base_free(ctx->evbase);

  return ctx->ret;
}
Exemplo n.º 13
0
bool NFCHttpServer::ResponseFile(const NFHttpRequest& req, const std::string& strPath, const std::string& strFileName)
{
    //Add response type
    std::map<std::string, std::string> typeMap;
    typeMap["txt"] = "text/plain";
    typeMap["txt"] = "text/plain";
    typeMap["c"] = "text/plain";
    typeMap["h"] = "text/plain";
    typeMap["html"] = "text/html";
    typeMap["htm"] = "text/htm";
    typeMap["css"] = "text/css";
    typeMap["gif"] = "image/gif";
    typeMap["jpg"] = "image/jpeg";
    typeMap["jpeg"] = "image/jpeg";
    typeMap["png"] = "image/png";
    typeMap["pdf"] = "application/pdf";
    typeMap["ps"] = "application/postsript";

    std::string strFilePath = strPath;
    if (strFilePath.find_last_of("/") != strFilePath.size())
    {
        strFilePath += "/";
    }

    strFilePath = strFilePath + req.url;

    int fd = -1;
    struct stat st;
    if (stat(strFilePath.c_str(), &st) < 0)
    {
        std::string errMsg = strFilePath + strFileName;
        ResponseMsg(req, errMsg.c_str(), NFWebStatus::WEB_ERROR, errMsg.c_str());

        return false;
    }

    if (S_ISDIR(st.st_mode))
    {
        strFilePath += "/" + strFileName;
    }

    if (stat(strFilePath.c_str(), &st) < 0)
    {
        std::string errMsg = strFilePath + strFilePath;
        ResponseMsg(req, errMsg.c_str(), NFWebStatus::WEB_ERROR, errMsg.c_str());
        return false;
    }

#if NF_PLATFORM == NF_PLATFORM_WIN
    if ((fd = open(strFilePath.c_str(), O_RDONLY | O_BINARY)) < 0) {
#else
    if ((fd = open(strFilePath.c_str(), O_RDONLY)) < 0)
    {
#endif
        ResponseMsg(req, "error", NFWebStatus::WEB_ERROR, "error");
        return false;
    }

    if (fstat(fd, &st) < 0)
    {
        ResponseMsg(req, "error", NFWebStatus::WEB_ERROR, "error");
        return false;
    }

    const char* last_period = strrchr(strFilePath.c_str(), '.');
    std::string strType = last_period + 1;
    if (typeMap.find(strType) == typeMap.end())
    {
        strType = "application/misc";
    } else
    {
        strType = typeMap[strType];
    }
    ResponseFile(req, fd, st, strType);
    return false;
}

bool NFCHttpServer::ResponseFile(const NFHttpRequest& req, const int fd, struct stat st, const std::string& strType)
{
    evhttp_request* pHttpReq = (evhttp_request*) req.req;

    //create buffer
    struct evbuffer* eventBuffer = evbuffer_new();
    //send data
    evbuffer_add_file(eventBuffer, fd, 0, st.st_size);
    evhttp_add_header(evhttp_request_get_output_headers(pHttpReq), "Content-Type", strType.c_str());
    evhttp_send_reply(pHttpReq, 200, "OK", eventBuffer);

    //free
    evbuffer_free(eventBuffer);
    return true;
}
Exemplo n.º 14
0
// Request dispatcher
static void handle_request(struct evhttp_request *request,
                            void *userdata) {
  evhttp_connection_set_timeout(request->evcon, 1);
  evhttp_add_header(evhttp_request_get_output_headers(request),
                    "Server", "[email protected]/spotify-api-server");

  // Check request method
  int http_method = evhttp_request_get_command(request);

  switch (http_method) {
    case EVHTTP_REQ_GET:
    case EVHTTP_REQ_PUT:
    case EVHTTP_REQ_POST:
      break;

    default:
      evhttp_send_error(request, HTTP_NOTIMPL, "Not Implemented");
      return;
  }

  struct state *state = userdata;
  sp_session *session = state->session;
  char *uri = evhttp_decode_uri(evhttp_request_get_uri(request));

  char *entity = strtok(uri, "/");

  if (entity == NULL) {
    evhttp_send_error(request, HTTP_BADREQUEST, "Bad Request");
    free(uri);
    return;
  }

  // Handle requests to /user/<user_name>/inbox
  if (strncmp(entity, "user", 4) == 0) {
    char *username = strtok(NULL, "/");

    if (username == NULL) {
      evhttp_send_error(request, HTTP_BADREQUEST, "Bad Request");
      free(uri);
      return;
    }

    char *action = strtok(NULL, "/");
    handle_user_request(request, action, username, session);
    free(uri);
    return;
  }

  // Handle requests to /playlist/<playlist_uri>/<action>
  if (strncmp(entity, "playlist", 8) != 0) {
    evhttp_send_error(request, HTTP_BADREQUEST, "Bad Request");
    free(uri);
    return;
  }

  char *playlist_uri = strtok(NULL, "/");

  if (playlist_uri == NULL) {
    switch (http_method) {
      case EVHTTP_REQ_PUT:
      case EVHTTP_REQ_POST:
        // TODO(liesen): Add code to create playlists
        put_playlist(NULL, request, session);
        break;

      default:
        send_error(request, HTTP_BADREQUEST, "Bad Request");
        break;
    }

    free(uri);
    return;
  }

  sp_link *playlist_link = sp_link_create_from_string(playlist_uri);

  if (playlist_link == NULL) {
    send_error(request, HTTP_NOTFOUND, "Playlist link not found");
    free(uri);
    return;
  }

  if (sp_link_type(playlist_link) != SP_LINKTYPE_PLAYLIST) {
    sp_link_release(playlist_link);
    send_error(request, HTTP_BADREQUEST, "Not a playlist link");
    free(uri);
    return;
  }

  sp_playlist *playlist = sp_playlist_create(session, playlist_link);
  sp_link_release(playlist_link);

  if (playlist == NULL) {
    send_error(request, HTTP_NOTFOUND, "Playlist not found");
    free(uri);
    return;
  }

  sp_playlist_add_ref(playlist);

  // Dispatch request
  char *action = strtok(NULL, "/");
  free(uri);

  // Default request handler
  handle_playlist_fn request_callback = &not_implemented;
  void *callback_userdata = NULL;

  switch (http_method) {
  case EVHTTP_REQ_GET:
    {
      if (action == NULL) {
        // Send entire playlist
        request_callback = &get_playlist;
      } else if (strncmp(action, "collaborative", 13) == 0) {
        request_callback = &get_playlist_collaborative;
      } else if (strncmp(action, "subscribers", 11) == 0) {
        request_callback = &get_playlist_subscribers;
      }
    }
    break;

  case EVHTTP_REQ_PUT:
  case EVHTTP_REQ_POST:
    {
      callback_userdata = session;

      if (strncmp(action, "add", 3) == 0) {
        request_callback = &put_playlist_add_tracks;
      } else if (strncmp(action, "remove", 6) == 0) {
        request_callback = &put_playlist_remove_tracks;
      } else if (strncmp(action, "patch", 5) == 0) {
        callback_userdata = state;
        request_callback = &put_playlist_patch;
      }
    }
    break;
  }

  if (sp_playlist_is_loaded(playlist)) {
    request_callback(playlist, request, callback_userdata);
  } else {
    // Wait for playlist to load
    register_playlist_callbacks(playlist, request, request_callback,
                                &playlist_state_changed_callbacks,
                                callback_userdata);
  } 
}
Exemplo n.º 15
0
/* Thread: httpd */
void
httpd_send_reply(struct evhttp_request *req, int code, const char *reason, struct evbuffer *evbuf)
{
  unsigned char outbuf[128 * 1024];
  z_stream strm;
  struct evbuffer *gzbuf;
  struct evkeyvalq *headers;
  const char *param;
  int flush;
  int zret;
  int ret;

  if (!req)
    return;

  if (!evbuf || (EVBUFFER_LENGTH(evbuf) == 0))
    {
      DPRINTF(E_DBG, L_HTTPD, "Not gzipping body-less reply\n");

      goto no_gzip;
    }

  headers = evhttp_request_get_input_headers(req);

  param = evhttp_find_header(headers, "Accept-Encoding");
  if (!param)
    {
      DPRINTF(E_DBG, L_HTTPD, "Not gzipping; no Accept-Encoding header\n");

      goto no_gzip;
    }
  else if (!strstr(param, "gzip") && !strstr(param, "*"))
    {
      DPRINTF(E_DBG, L_HTTPD, "Not gzipping; gzip not in Accept-Encoding (%s)\n", param);

      goto no_gzip;
    }

  gzbuf = evbuffer_new();
  if (!gzbuf)
    {
      DPRINTF(E_LOG, L_HTTPD, "Could not allocate evbuffer for gzipped reply\n");

      goto no_gzip;
    }

  strm.zalloc = Z_NULL;
  strm.zfree = Z_NULL;
  strm.opaque = Z_NULL;

  /* Set up a gzip stream (the "+ 16" in 15 + 16), instead of a zlib stream (default) */
  zret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY);
  if (zret != Z_OK)
    {
      DPRINTF(E_DBG, L_HTTPD, "zlib setup failed: %s\n", zError(zret));

      goto out_fail_init;
    }

  strm.next_in = EVBUFFER_DATA(evbuf);
  strm.avail_in = EVBUFFER_LENGTH(evbuf);

  flush = Z_NO_FLUSH;

  /* 2 iterations: Z_NO_FLUSH until input is consumed, then Z_FINISH */
  for (;;)
    {
      do
	{
	  strm.next_out = outbuf;
	  strm.avail_out = sizeof(outbuf);

	  zret = deflate(&strm, flush);
	  if (zret == Z_STREAM_ERROR)
	    {
	      DPRINTF(E_LOG, L_HTTPD, "Could not deflate data: %s\n", strm.msg);

	      goto out_fail_gz;
	    }

	  ret = evbuffer_add(gzbuf, outbuf, sizeof(outbuf) - strm.avail_out);
	  if (ret < 0)
	    {
	      DPRINTF(E_LOG, L_HTTPD, "Out of memory adding gzipped data to evbuffer\n");

	      goto out_fail_gz;
	    }
	}
      while (strm.avail_out == 0);

      if (flush == Z_FINISH)
	break;

      flush = Z_FINISH;
    }

  if (zret != Z_STREAM_END)
    {
      DPRINTF(E_LOG, L_HTTPD, "Compressed data not finalized!\n");

      goto out_fail_gz;
    }

  deflateEnd(&strm);

  headers = evhttp_request_get_output_headers(req);

  evhttp_add_header(headers, "Content-Encoding", "gzip");
  evhttp_send_reply(req, code, reason, gzbuf);

  evbuffer_free(gzbuf);

  /* Drain original buffer, as would be after evhttp_send_reply() */
  evbuffer_drain(evbuf, EVBUFFER_LENGTH(evbuf));

  return;

 out_fail_gz:
  deflateEnd(&strm);
 out_fail_init:
  evbuffer_free(gzbuf);
 no_gzip:
  evhttp_send_reply(req, code, reason, evbuf);
}
Exemplo n.º 16
0
/**
 * Handle a file request.
 */
void FileHandler::handle_request(struct evhttp_request* request) {
    //Figure out which file to get.
    std::string uri(request_uri_path(request));
    std::string relative_file_path(uri.substr(url_root_.size()));
    
    //Check whether the user entered a valid file path.
    if (!this->is_permitted_file_path(relative_file_path)) {
        // Invalid request.  Cannot find the file.
        server_->send_response(request, std::string(""), HTTP_NOTFOUND);
        return;
    }
    
    //Attempt to load the file.
    //std::string full_path = file_root_ + relative_file_path;
    CachedFilePtr cached_file;
    const bool has_loaded = file_cache_->get_cached_object(relative_file_path, cached_file);
    
    if (!has_loaded) {
        // No such file.
        server_->send_response(request, std::string(""), HTTP_NOTFOUND);
        return;
    }
    
    // Start writing the response.
    // Add Last-Modified response header.
    const time_t last_modified = cached_file->last_modified();
    struct evkeyvalq* response_headers = evhttp_request_get_output_headers(request);
    shared_array<char> sz_last_modified(time_to_string(last_modified));
    evhttp_add_header(response_headers, "Last-Modified", sz_last_modified.get());
    
    // Add Cache Control response header.
    if (!cache_control_.empty()) {
        evhttp_add_header(response_headers, "Cache-Control", cache_control_.c_str());
    }
    
    // Set the Content-Type header.
    std::string extension;
    size_t extension_start = relative_file_path.find_last_of(".");
    const char* content_type = NULL;
    
    if (extension_start != std::string::npos) {
        extension = relative_file_path.substr(extension_start + 1);
    }
    
    if      (extension == "css")    { content_type = "text/css";} 
    else if (extension == "js")     { content_type = "text/javascript"; }
    else if (extension == "png")    { content_type = "image/png"; }
    else if (extension == "jpeg")   { content_type = "image/jpeg"; }
    else if (extension == "jpg")    { content_type = "image/jpeg"; }
    else if (extension == "gif")    { content_type = "image/gif"; }
    else if (extension == "ico")    { content_type = "image/vnd.microsoft.icon"; }
    else if (extension == "txt")    { content_type = "text/plain"; }
    else if (extension == "h")      { content_type = "text/plain"; }
    else if (extension == "cpp")    { content_type = "text/plain"; }
    else if (extension == "hpp")    { content_type = "text/plain"; }
    else if (extension == "html")   { content_type = "text/html"; }
    else                            { content_type = "text/html"; }
    
    evhttp_add_header(response_headers, "Content-Type", content_type);
    
    // Check whether the user agent already has the right version of the file.
    // TODO: need to implement handling "If-None-Match" header.
    struct evkeyvalq* request_headers = evhttp_request_get_input_headers(request);
    const char* if_modified_since = evhttp_find_header(request_headers, "If-Modified-Since");
    const time_t t_if_modified_since = string_to_time(if_modified_since);
    
    if (t_if_modified_since >= cached_file->last_modified()) {
        server_->send_response(request, std::string(""), HTTP_NOTMODIFIED);
        return;
    }
    
    // Respond with the file data..
    shared_array<char> file_data = cached_file->data();
    size_t data_size = cached_file->data_size();
    server_->send_response_data(request, file_data.get(), data_size, HTTP_OK);
}
Exemplo n.º 17
0
/* Thread: httpd */
static void
serve_file(struct evhttp_request *req, char *uri)
{
  const char *host;
  char *ext;
  char path[PATH_MAX];
  char *deref;
  char *ctype;
  char *passwd;
  struct evbuffer *evbuf;
  struct evkeyvalq *headers;
  struct stat sb;
  int fd;
  int i;
  int ret;

  /* Check authentication */
  passwd = cfg_getstr(cfg_getsec(cfg, "general"), "admin_password");
  if (passwd)
    {
      DPRINTF(E_DBG, L_HTTPD, "Checking web interface authentication\n");

      ret = httpd_basic_auth(req, "admin", passwd, PACKAGE " web interface");
      if (ret != 0)
	return;

      DPRINTF(E_DBG, L_HTTPD, "Authentication successful\n");
    }
  else
    {
      host = evhttp_request_get_host(req);
      if ((strcmp(host, "::1") != 0)
	  && (strcmp(host, "127.0.0.1") != 0))
	{
	  DPRINTF(E_LOG, L_HTTPD, "Remote web interface request denied; no password set\n");

	  evhttp_send_error(req, 403, "Forbidden");
	  return;
	}
    }

  ret = snprintf(path, sizeof(path), "%s%s", WEBFACE_ROOT, uri + 1); /* skip starting '/' */
  if ((ret < 0) || (ret >= sizeof(path)))
    {
      DPRINTF(E_LOG, L_HTTPD, "Request exceeds PATH_MAX: %s\n", uri);

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

      return;
    }

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

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

      return;
    }

  if (S_ISDIR(sb.st_mode))
    {
      redirect_to_index(req, uri);

      return;
    }
  else if (S_ISLNK(sb.st_mode))
    {
      deref = m_realpath(path);
      if (!deref)
	{
	  DPRINTF(E_LOG, L_HTTPD, "Could not dereference %s: %s\n", path, strerror(errno));

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

	  return;
	}

      if (strlen(deref) + 1 > PATH_MAX)
	{
	  DPRINTF(E_LOG, L_HTTPD, "Dereferenced path exceeds PATH_MAX: %s\n", path);

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

	  free(deref);
	  return;
	}

      strcpy(path, deref);
      free(deref);

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

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

	  return;
	}

      if (S_ISDIR(sb.st_mode))
	{
	  redirect_to_index(req, uri);

	  return;
	}
    }

  if (path_is_legal(path) != 0)
    {
      evhttp_send_error(req, 403, "Forbidden");

      return;
    }

  evbuf = evbuffer_new();
  if (!evbuf)
    {
      DPRINTF(E_LOG, L_HTTPD, "Could not create evbuffer\n");

      evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal error");
      return;
    }

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

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

  /* FIXME: this is broken, if we ever need to serve files here,
   * this must be fixed.
   */
  ret = evbuffer_read(evbuf, fd, sb.st_size);
  close(fd);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_HTTPD, "Could not read file into evbuffer\n");

      evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal error");
      return;
    }

  ctype = "application/octet-stream";
  ext = strrchr(path, '.');
  if (ext)
    {
      for (i = 0; ext2ctype[i].ext; i++)
	{
	  if (strcmp(ext, ext2ctype[i].ext) == 0)
	    {
	      ctype = ext2ctype[i].ctype;
	      break;
	    }
	}
    }

  headers = evhttp_request_get_output_headers(req);

  evhttp_add_header(headers, "Content-Type", ctype);
  evhttp_send_reply(req, HTTP_OK, "OK", evbuf);

  evbuffer_free(evbuf);
}
Exemplo n.º 18
0
/* This callback gets invoked when we get any http request that doesn't match
 * any other callback.  Like any evhttp server callback, it has a simple job:
 * it must eventually call evhttp_send_error() or evhttp_send_reply().
 */
static void
send_document_cb(struct evhttp_request *req, void *arg)
{
	struct evbuffer *evb = NULL;
	const char *docroot = (const char *)arg;
	const char *uri = evhttp_request_get_uri(req);
	struct evhttp_uri *decoded = NULL;
	const char *path;
	char *decoded_path;
	char *whole_path = NULL;
	size_t len;
	int fd = -1;
	struct stat st;

	if (evhttp_request_get_command(req) != EVHTTP_REQ_GET) {
		dump_request_cb(req, arg);
		return;
	}

	printf("Got a GET request for <%s>\n",  uri);

	/* Decode the URI */
	decoded = evhttp_uri_parse(uri);
	if (!decoded) {
		printf("It's not a good URI. Sending BADREQUEST\n");
		evhttp_send_error(req, HTTP_BADREQUEST, 0);
		return;
	}

	/* Let's see what path the user asked for. */
	path = evhttp_uri_get_path(decoded);
	if (!path) path = "/";

	/* We need to decode it, to see what path the user really wanted. */
	decoded_path = evhttp_uridecode(path, 0, NULL);
	if (decoded_path == NULL)
		goto err;
	/* Don't allow any ".."s in the path, to avoid exposing stuff outside
	 * of the docroot.  This test is both overzealous and underzealous:
	 * it forbids aceptable paths like "/this/one..here", but it doesn't
	 * do anything to prevent symlink following." */
	if (strstr(decoded_path, ".."))
		goto err;

	len = strlen(decoded_path)+strlen(docroot)+2;
	if (!(whole_path = (char *)malloc(len))) {
		perror("malloc");
		goto err;
	}
	evutil_snprintf(whole_path, len, "%s/%s", docroot, decoded_path);

	if (stat(whole_path, &st)<0) {
		goto err;
	}

	/* This holds the content we're sending. */
	evb = evbuffer_new();

	if (S_ISDIR(st.st_mode)) {
		/* If it's a directory, read the comments and make a little
		 * index page */
#ifdef WIN32
		HANDLE d;
		WIN32_FIND_DATAA ent;
		char *pattern;
		size_t dirlen;
#else
		DIR *d;
		struct dirent *ent;
#endif
		const char *trailing_slash = "";

		if (!strlen(path) || path[strlen(path)-1] != '/')
			trailing_slash = "/";

#ifdef WIN32
		dirlen = strlen(whole_path);
		pattern = malloc(dirlen+3);
		memcpy(pattern, whole_path, dirlen);
		pattern[dirlen] = '\\';
		pattern[dirlen+1] = '*';
		pattern[dirlen+2] = '\0';
		d = FindFirstFileA(pattern, &ent);
		free(pattern);
		if (d == INVALID_HANDLE_VALUE)
			goto err;
#else
		if (!(d = opendir(whole_path)))
			goto err;
#endif

		evbuffer_add_printf(evb, "<html>\n <head>\n"
		    "  <title>%s</title>\n"
		    "  <base href='%s%s%s'>\n"
		    " </head>\n"
		    " <body>\n"
		    "  <h1>%s</h1>\n"
		    "  <ul>\n",
		    decoded_path, /* XXX html-escape this. */
		    uri_root, path, /* XXX html-escape this? */
		    trailing_slash,
		    decoded_path /* XXX html-escape this */);
#ifdef WIN32
		do {
			const char *name = ent.cFileName;
#else
		while ((ent = readdir(d))) {
			const char *name = ent->d_name;
#endif
			evbuffer_add_printf(evb,
			    "    <li><a href=\"%s\">%s</a>\n",
			    name, name);/* XXX escape this */
#ifdef WIN32
		} while (FindNextFileA(d, &ent));
#else
		}
#endif
		evbuffer_add_printf(evb, "</ul></body></html>\n");
#ifdef WIN32
		CloseHandle(d);
#else
		closedir(d);
#endif
		evhttp_add_header(evhttp_request_get_output_headers(req),
		    "Content-Type", "text/html");
	} else {
Exemplo n.º 19
0
/**
 * Callback used for search request
 */
static void search_request_cb(struct evhttp_request *req, void *arg)
{
	std::chrono::high_resolution_clock::time_point t0 = std::chrono::high_resolution_clock::now();

	if (evhttp_request_get_command(req) != EVHTTP_REQ_GET)
	{
		// evbuffer_add_printf(evb, "Invalid query request! Needs to be GET\n");
		std::cerr << "Invalid query request! Needs to be GET" << std::endl;
		evhttp_send_error(req, HTTP_BADREQUEST, 0);
	}
	else
	{
		struct evbuffer *evb = NULL;
		const char *uri = evhttp_request_get_uri(req);
		struct evhttp_uri *decoded = NULL;
		// const char *path = NULL;
		const char *query = NULL;
		// struct evkeyvalq *headers;
		// struct evkeyval *header;

		printf("Got a GET request for %s\n",  uri);

		// Decode the URI
		decoded = evhttp_uri_parse(uri);
		if (!decoded) {
			printf("It's not a good URI. Sending BADREQUEST\n");
			evhttp_send_error(req, HTTP_BADREQUEST, 0);
			return;
		}

		// path = evhttp_uri_get_path(decoded);
		// std::cout << path << std::endl;

		query = evhttp_uri_get_query(decoded);
		// std::cout << query << std::endl;

		// This holds the content we're sending
		evb = evbuffer_new();

		/*
		headers = evhttp_request_get_input_headers(req);
		for (header = headers->tqh_first; header;
			header = header->next.tqe_next) {
			printf("  %s: %s\n", header->key, header->value);
		}
		*/

		struct evkeyvalq params;	// create storage for your key->value pairs
		struct evkeyval *param;		// iterator

		int result = evhttp_parse_query_str(query, &params);

		if (result == 0)
		{
			std::string query;
			unsigned int start = 0;
			unsigned int offset = 0;

			for (param = params.tqh_first; param; param = param->next.tqe_next)
			{
				std::string key(param->key);
				std::string value(param->value);

				// std::cout << key << " " << value << std::endl;

				if (key.compare(zsearch::server::GET_SEARCH_QUERY_KEY) == 0)
				{
					query = value;
				}

				if (key.compare(zsearch::server::GET_SEARCH_START_KEY) == 0)
				{
					try
					{
						start = ZUtil::getUInt(value);
					}
					catch (const string& e)
					{
						// do nothing
					}
				}

				if (key.compare(zsearch::server::GET_SEARCH_OFFSET_KEY) == 0)
				{
					try
					{
						offset = ZUtil::getUInt(value);
					}
					catch (const string& e)
					{
						// do nothing
					}
				}
			}

			std::cout << "searching for " << query << " with start " << start << " and offset " << offset << std::endl;

			auto docIdSet = engine->search(query, start, offset);

			if (docIdSet.size())
			{
				for (auto docId : docIdSet)
				{
					evbuffer_add_printf(evb, "%u ", docId);
				}
			}

			evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/html");
			evhttp_send_reply(req, 200, "OK", evb);

		}
		else
		{
			evhttp_send_error(req, HTTP_BADREQUEST, 0);
		}

		evhttp_clear_headers(&params);


		if (decoded)
		{
			evhttp_uri_free(decoded);
		}

		if (evb)
		{
			evbuffer_free(evb);
		}
	}

	std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now();
	std::chrono::nanoseconds timeTaken = std::chrono::duration_cast<std::chrono::nanoseconds>(t1 - t0);
	std::cout << ZUtil::printTimeTaken(timeTaken) << std::endl;
}
Exemplo n.º 20
0
/* Callback used for the /dump URI, and for every non-GET request:
 * dumps all information to stdout and gives back a trivial 200 ok */
static void
s2info_request_cb(struct evhttp_request *req, void *arg)
{

  struct evkeyvalq    args;
  struct evbuffer *inputBuffer = evhttp_request_get_input_buffer (req);
  size_t record_len = evbuffer_get_length(inputBuffer);
  char *postData = NULL;
  const char *path = "/?";
  if (record_len > 0) { 
    postData = (char *)malloc(strlen(path) + record_len + 10);
    postData[0] = '/';
    postData[1] = '?';
    evbuffer_pullup(inputBuffer, -1);                                                                                                                                                     
    evbuffer_copyout(inputBuffer, (char *)postData + strlen(path), record_len);
    postData[strlen(path) + record_len] = '\0';
    printf("trying to parse: %s\n", (const char *)postData);
    evhttp_parse_query((const char *)postData, &args);
  } else {
    const char *uri = evhttp_request_get_uri(req);
    evhttp_parse_query(uri, &args);
  }

  char* callback = (char *)evhttp_find_header(&args, "callback");



  char* ids = (char *)evhttp_find_header(&args, "id");
  std::vector<S2CellId> cellids_vector;
 
  if (ids != NULL) {
    printf("%s\n", ids);
    std::vector<std::string> ids_vector = split(string(ids), ',');
    bool treat_as_tokens = false;
    int num_evenly_divisible = 0;
    for (int i = 0; i < ids_vector.size(); i++) {
      const char *str = ids_vector[i].c_str();
      errno = 0;    /* To distinguish success/failure after call */
      char *endptr;
      uint64_t id = strtoull(str, &endptr, 10);

      if (strlen(endptr) != 0) {
        printf("failed to parse as long long, treating everything as tokens\n");
        treat_as_tokens = true;
      }
      else if (id % 1000 == 0) {
        printf("was even divisible by 1000, assume this was a misinterpreted token\n");
        num_evenly_divisible += 1;
      }
    }

    if (num_evenly_divisible == ids_vector.size()) {
      treat_as_tokens = true;
    }
   
    for (int i = 0; i < ids_vector.size(); i++) {
      const char *str = ids_vector[i].c_str();
      errno = 0;    /* To distinguish success/failure after call */
      char *endptr;
      uint64_t id = strtoull(str, &endptr, 10);
      /*if (str[0] != '-') {
        id = strtoul(str, &endptr, 10);
      }*/

      printf("endptr %d\n", strlen(endptr));
      printf("str %s\n", str);
      printf("id %lld\n", id);

      if (strlen(endptr) != 0 || treat_as_tokens) {
        printf("failed to parse as long long\n");
        cellids_vector.push_back(S2CellId(S2CellId::FromToken(str).id()));
      } else {
        printf("%lld\n", id);
        printf("id != 0 ? %d -- %s %d\n", (id != 0), str, strlen(str));
        printf("is_valid? %d\n", S2CellId(id).is_valid());
        cellids_vector.push_back(S2CellId(id));
      } 
    }
  }

	evhttp_add_header(evhttp_request_get_output_headers(req),
		    "Content-Type", "application/json");
	struct evbuffer *evb = NULL;
	evb = evbuffer_new();
  char* json = s2CellIdsToJson(callback, cellids_vector);
  evbuffer_add_printf(evb, "%s", json);
	evhttp_send_reply(req, 200, "OK", evb);
 
  free(json);

  if (evb)
    evbuffer_free(evb);
}
Exemplo n.º 21
0
Arquivo: rpc.c Projeto: dyustc/searaft
int rpc_call(struct rpc_context *context, 
    const struct rpc_target *dest, const struct method_t *method, 
    rpc_callback client_cb, void *data) {

    //TODO: check the protocol in dest->proto and do http
    // request only if dest->proto == HTTP
    int res = 1;
    struct evhttp_connection *evcon = NULL;
    struct evhttp_request *req = NULL;
    char *json_method = NULL;
    struct client_rpc_callback_with_data *ctx = NULL;

    //TODO: can be make http_connection as part of peer_t?
    evcon = evhttp_connection_base_new(
        context->base, NULL, dest->host, dest->port);
    if (!evcon) {
        goto cleanup;
    }
    ctx = (struct client_rpc_callback_with_data *)malloc(
        sizeof(struct client_rpc_callback_with_data));
    if(!ctx) {
        goto cleanup;
    }
    ctx->cb = client_cb;
    ctx->data = data;
    ctx->evcon = evcon;

    req = evhttp_request_new(http_request_done, ctx);
    if (!req) {
        goto cleanup;
    }

    char uri[256]; 
    snprintf(uri, sizeof(uri)-1, "http://%s:%d/rpc", dest->host, dest->port);
    
    json_method  = serialize_method_call(method);
    if(!json_method) {
        goto cleanup;
    }

    struct evbuffer *output_buffer = evhttp_request_get_output_buffer(req);
    evbuffer_add(output_buffer, json_method, strlen(json_method));

    char content_length[20];
    snprintf(content_length, sizeof(content_length)-1, "%d", (int)strlen(json_method));

    struct evkeyvalq *output_headers = evhttp_request_get_output_headers(req);
    evhttp_add_header(output_headers, "Host", dest->host);
    evhttp_add_header(output_headers, "Connection", "close");
    evhttp_add_header(output_headers, "Content-Length", content_length);

    printf("Sending req %p with ctx = %p\n", req, ctx);
    int r = evhttp_make_request(evcon, req, EVHTTP_REQ_POST, uri);
    if(!r) {
        res = 0;
    }

cleanup:
    if(json_method)
        free(json_method);
    if(res && ctx)
        free(ctx);
    if(res && evcon)
        evhttp_connection_free(evcon);
    if(res && req)
        evhttp_request_free(req);

    return res;
}