Пример #1
0
void
RESTRequest::requestHeaderData()
{
    MHD_get_connection_values( connection, MHD_HEADER_KIND, RESTRequest::iterate_headers, this);

    MHD_get_connection_values( connection, MHD_GET_ARGUMENT_KIND, RESTRequest::iterate_arguments, this);

}
Пример #2
0
/**
 * @brief get_url_from_query
 * @param connection
 * @param redirect_url as plaintext - not url encoded
 * @param redirect_url_len
 * @return NULL or redirect url
 */
static const char *get_redirect_url(struct MHD_Connection *connection)
{
	struct collect_query_key query_key = { .key = "redir" };

	MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, &collect_query_key, &query_key);

	if (!query_key.value)
		return NULL;

	return query_key.value;
}

/* save the query or empty string into **query.
 * the call must free query later */
static int get_query(struct MHD_Connection *connection, char **query)
{
	int element_counter;
	char **elements;
	struct collect_query collect_query;
	int i;
	int j;
	int length = 0;

	element_counter = MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, counter_iterator, NULL);
	if (element_counter == 0) {
		*query = safe_strdup("");
		return 0;
	}
	elements = calloc(element_counter, sizeof(char *));
	collect_query.i = 0;
	collect_query.elements = elements;

	//	static int get_host_value_callback(void *cls, enum MHD_ValueKind kind, const char *key, const char *value) {
	MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, collect_query_string, &collect_query);

	for(i=0; i<element_counter; i++) {
		if(!elements[i])
			continue;
		length += strlen(elements[i]);

		if(i >0) /* q=foo&o=bar the '&' need also some space */
			length++;
	}

	/* don't miss the zero terminator */
	*query = calloc(1, length+1);

	for(i=0, j=0; i<element_counter; i++) {
		if(!elements[i])
			continue;
		strncpy(*query + j, elements[i], length-j);
		free(elements[i]);
	}

	free(elements);
	return 0;
}
Пример #3
0
/**
 * @brief authenticated - called for all request from authenticated clients.
 * @param connection
 * @param ip_addr
 * @param mac
 * @param url
 * @param client
 * @return
 *
 * It's unsual to received request from clients which are already authed.
 * Happens when the user:
 * - clicked in multiple windows on "accept" -> redirect to origin - no checking
 * - when the user reloaded a splashpage -> redirect to origin
 * - when a user calls deny url -> deauth it
 */
static int authenticated(struct MHD_Connection *connection,
						 const char *ip_addr,
						 const char *mac,
						 const char *url,
						 t_client *client)
{
	s_config *config = config_get_config();
	const char *redirect_url;
	const char *host = NULL;
	char redirect_to_us[128];

	MHD_get_connection_values(connection, MHD_HEADER_KIND, get_host_value_callback, &host);

	if (is_splashpage(host, url) ||
			check_authdir_match(url, config->authdir)) {
		redirect_url = get_redirect_url(connection);
		/* TODO: what should we do when we get such request? */
		if (redirect_url == NULL || strlen(redirect_url) == 0)
			return show_splashpage(connection, client);
		else
			return authenticate_client(connection, ip_addr, mac, redirect_url, client);
	} else if (check_authdir_match(url, config->denydir)) {
		auth_client_action(ip_addr, mac, AUTH_MAKE_DEAUTHENTICATED);
		snprintf(redirect_to_us, 128, "http://%s:%u/", config->gw_address, config->gw_port);
		return send_redirect_temp(connection, redirect_to_us);
	}

	/* user doesn't wants the splashpage or tried to auth itself */
	return serve_file(connection, client, url);
}
Пример #4
0
//--------------------------------------------------------------------------
// Callback appelée par libmicrohttpd
//--------------------------------------------------------------------------
int HTTPDServer::answer (struct MHD_Connection *connection, const char *url, const char *method, const char *version, 
					const char *upload_data, size_t *upload_data_size, void **con_cls)
{
	MHD_ValueKind t = MHD_GET_ARGUMENT_KIND;
	if (0 == strcmp (method, "GET"))		t = MHD_GET_ARGUMENT_KIND;
	else if (0 == strcmp (method, "POST"))	t = MHD_POSTDATA_KIND;
	else {
		string msg = "Method ";
		msg += method;
		msg += " is not supported";
		return send (connection, msg.c_str(), 0, MHD_HTTP_BAD_REQUEST);
	}

	Message msg (url);
	MHD_get_connection_values (connection, t, _get_params, &msg);
	vector<Message*> outMsgs;
	if (fDebug) {
		cout << method << ": ";
		msg.print(cout);
		cout << endl;
	}
	fProcessor->processMessage (&msg, outMsgs);
	if (outMsgs.size())
		send (connection, outMsgs);
	else 
		page (connection, url);
	return MHD_YES;
}
Пример #5
0
int CWebServer::GetRequestHeaderValues(struct MHD_Connection *connection, enum MHD_ValueKind kind, std::multimap<std::string, std::string> &headerValues)
{
  if (connection == NULL)
    return -1;

  return MHD_get_connection_values(connection, kind, FillArgumentMultiMap, &headerValues);
}
Пример #6
0
int HTTPRequestHandlerUtils::GetRequestHeaderValues(struct MHD_Connection *connection, enum MHD_ValueKind kind, std::multimap<std::string, std::string> &headerValues)
{
  if (connection == nullptr)
    return -1;

  return MHD_get_connection_values(connection, kind, FillArgumentMultiMap, &headerValues);
}
Пример #7
0
int ahc_echo(void* servctx, MHD_Connection* connection, const char* url, const char* method, const char* version, const char* upload_data, size_t* upload_data_size, void** reqctx)
{
	static int dummy;
	if (reqctx == NULL)
	{
		// The first time only the headers are valid, do not respond in the first round.
		*reqctx = &dummy;
		return MHD_YES;
	}

	ServerContext* pServCtx = (ServerContext*)servctx;	// Not used yet
	printf("%s %s %s\n", method, url, version);

	if (strcmp(method, "GET") == 0)
	{
		if (*upload_data_size != 0)
			return MHD_NO;	// No upload data expected in HTTP GET method
 
		// Parse headers
		puts("[HEADERS]");
		MHD_get_connection_values(connection, MHD_HEADER_KIND, &print_out_key, NULL);

		// Parse GET parameters
		puts("[GET PARAMS]");
		StringPairList spl;
		MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, &print_out_key, &spl);

		std::string text = "<html><body>\n";
		text += "<p>URL="; text += url; 
		text += "</p>\n<p>Parameters</p>\n<ul>\n";
		for (StringPairList::iterator it = spl.begin(); it != spl.end(); ++it)
		{
			text += "<li>"; text += it->first; text += '='; text += it->second; text += "</li>\n";
		}
		text += "</body></html>\n";

		MHD_Response* response = MHD_create_response_from_buffer(text.size(), (void*)text.c_str(), MHD_RESPMEM_MUST_COPY);
		MHD_add_response_header(response, "Content-Type", "text/html");
		int ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
		MHD_destroy_response(response);

		*reqctx = NULL; // clear context pointer
		return ret;
	}
	else
		return MHD_NO;	// Not supported yet
}
Пример #8
0
static char *http_get_header(struct MHD_Connection *connection, const char *header)
{
	struct header_finder_t finder;
	finder.header = header;
	finder.value = NULL;
	MHD_get_connection_values (connection, MHD_HEADER_KIND, &get_key, &finder);
	return finder.value;
}
Пример #9
0
static int handle_request(void* /*cls*/, MHD_Connection* connection, const char* url, const char* method, const char*, const char*, unsigned int*, void** /*con_cls*/) {
  if (std::string(method) != "GET") {
    return report_error(connection, MHD_HTTP_NOT_IMPLEMENTED, "501 Not Implemented");
  }
  
  if (mp3d_debug_httpd) {
    MHD_get_connection_values(connection, MHD_HEADER_KIND, dump_key, NULL);
    MHD_get_connection_values(connection, MHD_COOKIE_KIND, dump_key, NULL);
    MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, dump_key, NULL);
    std::cout << "*** " << method << " request for '" << url << "'" << std::endl;
  }
  
  const char* q = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "mp3d_q");
  
  const std::string request_url(url);
  if (request_url == "/") {
    std::string page_data;
    make_main_page(page_data, q);
    return send_string_response(connection, MHD_HTTP_OK, page_data);
  } else if (boost::starts_with(request_url, "/static/")) {
    StringStringMap::const_iterator it = static_file_map.find(request_url);
    if (it == static_file_map.end()) {
      return report_error(connection, MHD_HTTP_NOT_FOUND, "404 Not Found");
    }
    return send_string_response(connection, MHD_HTTP_OK, it->second);
  } else if (boost::starts_with(request_url, "/play/")) {
    const size_t id = strtoul(request_url.substr(6).c_str(), 0, 10); // FIXME: error checking.
    play_queue.clear();
    play_queue.push_back(all_mp3s[id]); // FIXME: lookup by id (don't assume id == index).
    return see_other(connection, "/");
  } else if (boost::starts_with(request_url, "/add/")) {
    const size_t id = strtoul(request_url.substr(5).c_str(), 0, 10); // FIXME: error checking.
    play_queue.push_back(all_mp3s[id]); // FIXME: lookup by id (don't assume id == index).
    return see_other(connection, "/");
  } else if (boost::starts_with(request_url, "/remove/")) {
    const size_t id = strtoul(request_url.substr(8).c_str(), 0, 10); // FIXME: error checking.
    play_queue.remove(id); // FIXME: is this set-like behavior the behavior we want?
    return see_other(connection, "/");
  } else {
    return report_error(connection, MHD_HTTP_NOT_FOUND, "404 Not Found");
  }
}
Пример #10
0
int QMHDServerPrivate::onRequest(MHD_Connection* mhdConnection,
                                 const char* method,
                                 const char* path,
                                 const char* httpVersion,
                                 void** requestPtr)
{
    QMHDRequest* request = new QMHDRequest(mhdConnection);
    QStringHash  query;
    QStringHash  headers;

    MHD_get_connection_values(mhdConnection, MHD_GET_ARGUMENT_KIND, &header_values_iterator, &query);
    MHD_get_connection_values(mhdConnection, MHD_HEADER_KIND, &header_values_iterator, &headers);
    request->setMethod(qmhd_method_from_string(method));
    request->setPath(path);
    request->setQuery(query);
    request->setHttpVersion(qmhd_http_version_from_string(httpVersion));
    request->setHeaders(headers);
    request->setResponse(new QMHDResponse(mhdConnection));
    *requestPtr = request;
    return MHD_YES;
}
Пример #11
0
static int
answer_to_connection (void *cls, struct MHD_Connection *connection,
                      const char *url, const char *method,
                      const char *version, const char *upload_data,
                      size_t *upload_data_size, void **con_cls)
{
  printf ("New %s request for %s using version %s\n", method, url, version);

  MHD_get_connection_values (connection, MHD_HEADER_KIND, print_out_key,
                             NULL);

  return MHD_NO;
}
Пример #12
0
// add security related headers and send the response on the given connection
// the reference counter is not touched
// this function is a wrapper around MHD_queue_response
// MHD_queue_response should be replaced with this function
static void secure_queue_response(MHD_Connection *connection, unsigned int status_code, struct MHD_Response* response)
{
    // TODO: protect againts handling untrusted content to the browser
    // see:
    // http://www.dotnetnoob.com/2012/09/security-through-http-response-headers.html
    // http://www.w3.org/TR/CSP2/
    // https://code.google.com/p/doctype-mirror/wiki/ArticleContentSniffing

    // check content type
    // don't server when no type or no whitelisted type is given
    // TODO sending invalid mime types is as bad as not sending them TODO
    /*
    std::vector<std::string> allowed_types;
    allowed_types.push_back("text/html");
    allowed_types.push_back("application/json");
    allowed_types.push_back("image/png");
    */
    const char* type = MHD_get_response_header(response, "Content-Type");
    if(type == 0 /*|| std::find(allowed_types.begin(), allowed_types.end(), std::string(type)) == allowed_types.end()*/)
    {
        std::string page;
        if(type == 0)
            page = "<html><body><p>Fatal Error: no content type was set on this response. This is a bug.</p></body></html>";
        else
            page = "<html><body><p>Fatal Error: this content type is not allowed. This is a bug.<br/> Content-Type: "+std::string(type)+"</p></body></html>";
        struct MHD_Response* resp = MHD_create_response_from_data(page.size(), (void*)page.data(), 0, 1);
        MHD_add_response_header(resp, "Content-Type", "text/html");
        MHD_queue_response(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, resp);
        MHD_destroy_response(resp);
    }

    // tell Internet Explorer to not do content sniffing
    MHD_add_response_header(response, "X-Content-Type-Options", "nosniff");

    // Content security policy header, its a new technology and not implemented everywhere

    // get own host name as the browser sees it
    std::string host;
    MHD_get_connection_values(connection, MHD_HEADER_KIND, _extract_host_header_it_cb, (void*)&host);

    std::string csp;
    csp += "default-src 'none';";
    csp += "script-src '"+host+STATIC_FILES_ENTRY_PATH+"';";
    csp += "font-src '"+host+STATIC_FILES_ENTRY_PATH+"';";
    csp += "img-src 'self';"; // allow images from all paths on this server
    csp += "media-src 'self';"; // allow media files from all paths on this server

    MHD_add_response_header(response, "X-Content-Security-Policy", csp.c_str());

    MHD_queue_response(connection, status_code, response);
}
Пример #13
0
/**
 * @brief preauthenticated - called for all request of a client in this state.
 * @param connection
 * @param ip_addr
 * @param mac
 * @return
 */
static int preauthenticated(struct MHD_Connection *connection,
							const char *ip_addr,
							const char *mac,
							const char *url,
							t_client *client)
{
	char *host = NULL;
	const char *redirect_url;
	s_config *config = config_get_config();

	if (!client) {
		client = add_client(ip_addr);
		if (!client)
			return send_error(connection, 503);
	}

	MHD_get_connection_values(connection, MHD_HEADER_KIND, get_host_value_callback, &host);

	/* check if this is a redirect querty with a foreign host as target */
	if(is_foreign_hosts(connection, host)) {
		return redirect_to_splashpage(connection, client, host, url);
	}

	/* request is directed to us */
	/* check if client wants to be authenticated */
	if(check_authdir_match(url, config->authdir)) {

		/* Only the first request will redirected to config->redirectURL.
		 * When the client reloads a page when it's authenticated, it should be redirected
		 * to their origin url
		 */
		if (config->redirectURL)
			redirect_url = config->redirectURL;
		else
			redirect_url = get_redirect_url(connection);

		if (try_to_authenticate(connection, client, host, url)) {
			return authenticate_client(connection, ip_addr, mac, redirect_url, client);
		} else {
			/* user used an invalid token, redirect to splashpage but hold query "redir" intact */
			return encode_and_redirect_to_splashpage(connection, redirect_url);
		}
	}

	if(is_splashpage(host, url)) {
		return show_splashpage(connection, client);
	}

	/* no special handling left - try to serve static content to the user */
	return serve_file(connection, client, url);
}
Пример #14
0
static int check_token_is_valid(struct MHD_Connection *connection, t_client *client)
{
	/* token check */
	struct collect_query_key query_key = { .key = "token" };

	MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, &collect_query_key, &query_key);

	/* token not found in query string */
	if (!query_key.value)
		return 0;

	/* token doesn't match */
	if (strcmp(client->token, query_key.value))
		return 0;

	return 1;
}


/**
 * @brief try_to_authenticate
 * @param connection
 * @param client
 * @param host
 * @param url
 * @return
 */
static int try_to_authenticate(struct MHD_Connection *connection, t_client *client, const char *host, const char *url)
{
	/* a successful auth looks like
	 * http://192.168.42.1:2050/nodogsplash_auth/?redir=http%3A%2F%2Fberlin.freifunk.net%2F&tok=94c4cdd2
	 * when authaction -> http://192.168.42.1:2050/nodogsplash_auth/
	 */
	s_config *config = config_get_config();

	/* we are checking here for the second '/' of /denydir/ */
	if (check_authdir_match(url, config->authdir)) {
		/* matched to authdir */
		if (check_token_is_valid(connection, client)) {
			return 1; /* valid token */
		}
	} else if (check_authdir_match(url, config->denydir)) {
		/* matched to deauth */
		/* TODO: do we need denydir? */
		return 0;
	}

	return 0;
}
static int
ahc_echo (void *cls,
          struct MHD_Connection *connection,
          const char *url,
          const char *method,
          const char *version,
          const char *upload_data, size_t *upload_data_size,
          void **unused)
{
  static int ptr;
  const char *me = cls;
  struct MHD_Response *response;
  int ret;
  const char *hdr;
  (void)version;(void)upload_data;(void)upload_data_size;       /* Unused. Silent compiler warning. */

  if (0 != strcmp (me, method))
    return MHD_NO;              /* unexpected method */
  if (&ptr != *unused)
    {
      *unused = &ptr;
      return MHD_YES;
    }
  *unused = NULL;
  hdr = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "k");
  if ((hdr == NULL) || (0 != strcmp (hdr, "v x")))
    abort ();
  hdr = MHD_lookup_connection_value (connection,
                                     MHD_GET_ARGUMENT_KIND, "hash");
  if ((hdr == NULL) || (0 != strcmp (hdr, "#foo")))
    abort ();
  hdr = MHD_lookup_connection_value (connection,
                                     MHD_GET_ARGUMENT_KIND, "space");
  if ((hdr == NULL) || (0 != strcmp (hdr, "\240bar")))
    abort ();
  if (3 != MHD_get_connection_values (connection,
				      MHD_GET_ARGUMENT_KIND,
				      NULL, NULL))
    abort ();
  response = MHD_create_response_from_buffer (strlen (url),
					      (void *) url,
					      MHD_RESPMEM_MUST_COPY);
  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
  MHD_destroy_response (response);
  if (ret == MHD_NO)
    abort ();
  return ret;
}
Пример #16
0
static int answer_to_connection(void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls)
{
    char buf[5],page[REPLY_PAGE_SIZE], *dyn_format_str = NULL;
	char format_str[50] = "$c:$i:$o:$p0";
    struct MHD_Response *response;
    struct dnetc_values *shmem;
    int i,ret;

	if(strcmp(method,"GET") != 0)
		return MHD_NO;
	
    shmem = (struct dnetc_values *) cls;
	if(!shmem->running)
	{
		snprintf(page,REPLY_PAGE_SIZE,"NONE");
	}
	else
	{
		MHD_get_connection_values (connection, MHD_GET_ARGUMENT_KIND, parse_http_get_param, &dyn_format_str);
		if(dyn_format_str == NULL)
		{
			for(i=1;i<shmem->n_cpu;i++)
			{
				snprintf(buf,5,":$p%d",i);
				strcat(format_str, buf);
			}
			sprint_formated_data(page,REPLY_PAGE_SIZE,format_str,shmem);
		}
		else
		{
			sprint_formated_data(page,REPLY_PAGE_SIZE,dyn_format_str,shmem);
			free(dyn_format_str);
		}
	}

    response = MHD_create_response_from_data (strlen(page), (void *) page, MHD_NO, MHD_YES);
    ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
    MHD_destroy_response (response);

    return ret;
}
Пример #17
0
/**
 * @brief authenticated - called for all request from authenticated clients.
 * @param connection
 * @param ip_addr
 * @param mac
 * @param url
 * @param client
 * @return
 *
 * It's unsual to received request from clients which are already authed.
 * Happens when the user:
 * - clicked in multiple windows on "accept" -> redirect to origin - no checking
 * - when the user reloaded a splashpage -> redirect to origin
 * - when a user calls deny url -> deauth it
 */
static int authenticated(struct MHD_Connection *connection,
						 const char *ip_addr,
						 const char *mac,
						 const char *url,
						 t_client *client)
{
	s_config *config = config_get_config();
	const char *redirect_url;
	const char *host = NULL;
	char redirect_to_us[128];

	MHD_get_connection_values(connection, MHD_HEADER_KIND, get_host_value_callback, &host);

	if (is_splashpage(host, url) ||
			check_authdir_match(url, config->authdir)) {
		redirect_url = get_redirect_url(connection);
		/* TODO: what should we do when we get such request? */
		if (redirect_url == NULL || strlen(redirect_url) == 0)
			return show_splashpage(connection, client);
		else
			return authenticate_client(connection, ip_addr, mac, redirect_url, client);
	} else if (check_authdir_match(url, config->denydir)) {
		auth_client_action(ip_addr, mac, AUTH_MAKE_DEAUTHENTICATED);
		snprintf(redirect_to_us, 128, "http://%s:%u/", config->gw_address, config->gw_port);
		return send_redirect_temp(connection, redirect_to_us);
	}


	/* check if this is an late request meaning the user tries to get the internet, but ended up here,
	 * because the iptables rule came to late */
	if (is_foreign_hosts(connection, host)) {
		/* might happen if the firewall rule isn't yet installed */
		return send_refresh(connection);
	}

	/* user doesn't wants the splashpage or tried to auth itself */
	return serve_file(connection, client, url);
}
Пример #18
0
/* ****************************************************************************
*
* connectionTreat - 
*
* This is the MHD_AccessHandlerCallback function for MHD_start_daemon
* This function returns:
* o MHD_YES  if the connection was handled successfully
* o MHD_NO   if the socket must be closed due to a serious error
*
* - This function is called once when the headers are read and the ciP is created.
* - Then it is called for data payload and once all the payload an acknowledgement
*   must be done, setting *upload_data_size to ZERO.
* - The last call is made with *upload_data_size == 0 and now is when the connection
*   is open to send responses.
*
* Call 1: *con_cls == NULL
* Call 2: *con_cls != NULL  AND  *upload_data_size != 0
* Call 3: *con_cls != NULL  AND  *upload_data_size == 0
*/
static int connectionTreat
(
   void*            cls,
   MHD_Connection*  connection,
   const char*      url,
   const char*      method,
   const char*      version,
   const char*      upload_data,
   size_t*          upload_data_size,
   void**           con_cls
)
{
  ConnectionInfo*        ciP         = (ConnectionInfo*) *con_cls;
  size_t                 dataLen     = *upload_data_size;

  // 1. First call - setup ConnectionInfo and get/check HTTP headers
  if (ciP == NULL)
  {
    //
    // IP Address and port of caller
    //
    char            ip[32];
    unsigned short  port = 0;

    const union MHD_ConnectionInfo* mciP = MHD_get_connection_info(connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS);
    if (mciP != NULL)
    {
      port = (mciP->client_addr->sa_data[0] << 8) + mciP->client_addr->sa_data[1];
      snprintf(ip, sizeof(ip), "%d.%d.%d.%d", mciP->client_addr->sa_data[2]  & 0xFF, mciP->client_addr->sa_data[3]  & 0xFF, mciP->client_addr->sa_data[4] & 0xFF, mciP->client_addr->sa_data[5] & 0xFF);
    }
    else
    {
      port = 0;
      snprintf(ip, sizeof(ip), "IP unknown");
    }



    //
    // ConnectionInfo
    //
    if ((ciP = new ConnectionInfo(url, method, version, connection)) == NULL)
    {
      LM_E(("Runtime Error (error allocating ConnectionInfo)"));
      return MHD_NO;
    }

    *con_cls = (void*) ciP; // Pointer to ConnectionInfo for subsequent calls
    ciP->port = port;
    ciP->ip   = ip;
    
    //
    // Transaction starts here
    //
    LM_TRANSACTION_START("from", ip, port, url);  // Incoming REST request starts



    //
    // URI parameters
    // 
    ciP->uriParam[URI_PARAM_NOTIFY_FORMAT]      = DEFAULT_PARAM_NOTIFY_FORMAT;
    ciP->uriParam[URI_PARAM_PAGINATION_OFFSET]  = DEFAULT_PAGINATION_OFFSET;
    ciP->uriParam[URI_PARAM_PAGINATION_LIMIT]   = DEFAULT_PAGINATION_LIMIT;
    ciP->uriParam[URI_PARAM_PAGINATION_DETAILS] = DEFAULT_PAGINATION_DETAILS;
    
    MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, uriArgumentGet, ciP);
    if (ciP->httpStatusCode != SccOk)
    {
      LM_W(("Bad Input (error in URI parameters)"));
      restReply(ciP, ciP->answer);
      return MHD_YES;
    }
    LM_T(LmtUriParams, ("notifyFormat: '%s'", ciP->uriParam[URI_PARAM_NOTIFY_FORMAT].c_str()));

    MHD_get_connection_values(connection, MHD_HEADER_KIND, httpHeaderGet, &ciP->httpHeaders);
    
    char tenant[128];
    ciP->tenantFromHttpHeader = strToLower(tenant, ciP->httpHeaders.tenant.c_str(), sizeof(tenant));
    LM_T(LmtTenant, ("HTTP tenant: '%s'", ciP->httpHeaders.tenant.c_str()));
    ciP->outFormat            = wantedOutputSupported(ciP->httpHeaders.accept, &ciP->charset);
    if (ciP->outFormat == NOFORMAT)
      ciP->outFormat = XML; // XML is default output format

    ciP->servicePath = ciP->httpHeaders.servicePath;
    if (servicePathSplit(ciP) != 0)
    {
      LM_W(("Bad Input (error in ServicePath http-header)"));
      restReply(ciP, ciP->answer);
    }

    if (contentTypeCheck(ciP) != 0)
    {
      LM_W(("Bad Input (invalid mime-type in Content-Type http-header)"));
      restReply(ciP, ciP->answer);
    }
    else if (outFormatCheck(ciP) != 0)
    {
      LM_W(("Bad Input (invalid mime-type in Accept http-header)"));
      restReply(ciP, ciP->answer);
    }
    else
      ciP->inFormat = formatParse(ciP->httpHeaders.contentType, NULL);

    // Set default mime-type for notifications
    if (ciP->uriParam[URI_PARAM_NOTIFY_FORMAT] == "")
    {
      if (ciP->outFormat == XML)
        ciP->uriParam[URI_PARAM_NOTIFY_FORMAT] = "XML";
      else if (ciP->outFormat == JSON)
        ciP->uriParam[URI_PARAM_NOTIFY_FORMAT] = "JSON";
      else
        ciP->uriParam[URI_PARAM_NOTIFY_FORMAT] = "XML";

      LM_T(LmtUriParams, ("'default' value for notifyFormat (ciP->outFormat == %d)): '%s'", ciP->outFormat, ciP->uriParam[URI_PARAM_NOTIFY_FORMAT].c_str()));
    }

    return MHD_YES;
  }


  //
  // 2. Data gathering calls
  //
  // 2-1. Data gathering calls, just wait
  // 2-2. Last data gathering call, acknowledge the receipt of data
  //
  if (dataLen != 0)
  {
    if (dataLen == ciP->httpHeaders.contentLength)
    {
      if (ciP->httpHeaders.contentLength <= PAYLOAD_MAX_SIZE)
      {
        if (ciP->httpHeaders.contentLength > STATIC_BUFFER_SIZE)
          ciP->payload = (char*) malloc(ciP->httpHeaders.contentLength + 1);
        else
          ciP->payload = static_buffer;

        ciP->payloadSize = dataLen;
        memcpy(ciP->payload, upload_data, dataLen);
        ciP->payload[dataLen] = 0;
      }
      else
      {
        char details[256];
        snprintf(details, sizeof(details), "payload size: %d, max size supported: %d", ciP->httpHeaders.contentLength, PAYLOAD_MAX_SIZE);

        ciP->answer         = restErrorReplyGet(ciP, ciP->outFormat, "", ciP->url, SccRequestEntityTooLarge, details);
        ciP->httpStatusCode = SccRequestEntityTooLarge;
      }

      // All payload received, acknowledge!
      *upload_data_size = 0;
    }
    else
      LM_T(LmtPartialPayload, ("Got %d of payload of %d bytes", dataLen, ciP->httpHeaders.contentLength));

    return MHD_YES;
  }


  // 3. Finally, serve the request (unless an error has occurred)
  if (((ciP->verb == POST) || (ciP->verb == PUT)) && (ciP->httpHeaders.contentLength == 0) && (strncasecmp(ciP->url.c_str(), "/log/", 5) != 0))
  {
    std::string errorMsg = restErrorReplyGet(ciP, ciP->outFormat, "", url, SccLengthRequired, "Zero/No Content-Length in PUT/POST request");
    ciP->httpStatusCode = SccLengthRequired;
    restReply(ciP, errorMsg);
  }
  else if (ciP->answer != "")
    restReply(ciP, ciP->answer);
  else
    serveFunction(ciP);

  return MHD_YES;
}
Пример #19
0
static int
write_to_riemann(void *cls,
                 struct MHD_Connection *connection,
                 const char *url,
                 const char *method,
                 const char *version,
                 const char *upload_data,
                 size_t *upload_data_size,
                 void **ptr)
{
    int marker, ret;
    riemann_client_t *riemann_client = cls;

    if (*ptr != &marker || *upload_data_size != 0) {
        *ptr = &marker;
        *upload_data_size = 0;
        return MHD_YES;
    }

    {
        riemann_message_t msg = RIEMANN_MSG_INIT;
        riemann_event_t event = RIEMANN_EVENT_INIT;
        riemann_event_t *events[] = { NULL };
        attribute_list_t *head, *cur;
        int header_count = 2, i;
        riemann_attribute_pairs_t *attributes;

        events[0] = &event;
        riemann_event_set_host(&event, riemann_field_host);
        riemann_event_set_service(&event, riemann_field_service);

        head = push_riemann_attribute_pair(NULL, "Method", method);
        if (head == NULL) {
            return MHD_NO;
        }
        cur = push_riemann_attribute_pair(head, "URL", url);
        if (cur == NULL) {
            free(head->attr);
            free(head);
            return MHD_NO;
        }
        header_count += MHD_get_connection_values(connection, MHD_HEADER_KIND,
                                                  headers_to_attributes, &cur);

        attributes = calloc(header_count, sizeof(riemann_attribute_pairs_t));
        if (attributes == NULL) {
            cur = head;
            while (cur) {
                free(cur->attr);
                head = cur;
                free(cur);
                cur = head->next;
            }
            return MHD_NO;
        }
        cur = head;
        for (i = 0; i < header_count && cur; ++i) {
            attributes[i].key = cur->attr->key;
            attributes[i].value = cur->attr->value;
            free(cur->attr);
            head = cur->next;
            free(cur);
            cur = head;
        }
        riemann_event_set_attributes(&event, attributes, header_count);
        riemann_message_set_events(&msg, events, 1);

        ret = riemann_client_send_message(riemann_client, &msg, 0, NULL);
        if (ret) {
            fprintf(stderr, "Cannot send message: %s\n", strerror(errno));
        }
        fprintf(stderr, "Notfied riemann about '%s'\n", url);

        riemann_event_free(&event);
        free(attributes);
    }

    {
        struct MHD_Response *response;
        response = MHD_create_response_from_buffer(body_len, (void *)body,
                                                   MHD_RESPMEM_PERSISTENT);
        if (response) {
            MHD_add_response_header(response, "Content-Type", "text/html");
            ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
            MHD_destroy_response(response);
        }
    }
    (void)version;
    (void)upload_data;
    return ret;
}
Пример #20
0
static int url_handler(void *cls, struct MHD_Connection *connection,
        const char *url, const char *method, const char *version,
        const char *upload_data, size_t *upload_data_size, void **con_cls)
{
    char *me;
    struct MHD_Response *response;
    int ret;
    std::map<std::string, std::string> url_args;
    std::string respdata;

    // HTTP access control (CORS)
    // https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS?redirectlocale=en-US&redirectslug=HTTP_access_control
    // some times a preflight check is required which uses the OPTIONS HTTP method to check for permission to
    // call cross-domain requests
    if (0 == strcmp(method, MHD_HTTP_METHOD_OPTIONS))
        return sendAccessControl(connection, url, method, version);

    // we only need to deal with GET requests
    /*  FIXME -- don't need this since the HTTP options/preflight will ensure non-supported methods are rejected?
    if (0 != strcmp(method, MHD_HTTP_METHOD_GET))
        return MHD_NO;*/

    // set up out connection information on the first pass through.
    if (NULL == *con_cls)
    {
        struct connection_info *con_info;
        con_info = (connection_info*) malloc (sizeof (struct connection_info));
        if (NULL == con_info) return MHD_NO;
        static int idCounter = 1;
        con_info->id = idCounter++;
        // FIXME: for some reason this line causes segfaults under linux?
        //con_info->url = std::string(url ? url : "");
        con_info->data = NULL;
        con_info->biomapsId = NULL;
        con_info->dataSize = 0;
        if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
        {
            std::cout << "Setting up con_cls for POST: " << con_info->id << std::endl;
            std::cout << " - with url: " << url << std::endl;
            const char* tmp = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Content-type");
            std::string contentType(tmp ? tmp : "");
            if (contentType.find(JSON_CONTENT_TYPE) == std::string::npos)
            {
                std::cerr << "Error creating POST processor?! Unhandled content type: "
                          << MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Content-type")
                          << std::endl;
                free (con_info);
                return MHD_NO;
            }
            con_info->connectiontype = POST;
        }
        else con_info->connectiontype = GET;
        *con_cls = (void *) con_info;
        return MHD_YES;
    }

    // intercept POST requests for now to test stuff
    if (0 == strcmp(method, MHD_HTTP_METHOD_POST))
    {
        // post recieved, do stuff.
        struct connection_info *con_info = (connection_info*)(*con_cls);
        std::cout << "Received a POST for connection: " << con_info->id << std::endl;
        if (*upload_data_size != 0)
        {
            std::cout << "Processed some data: " << *upload_data_size << std::endl;
            //std::cout << "Data: " << upload_data << std::endl;
            con_info->data = (char*)realloc(con_info->data, con_info->dataSize + *upload_data_size);
            memcpy(con_info->data + con_info->dataSize, upload_data, *upload_data_size);
            con_info->dataSize += *upload_data_size;
            //std::string bob(upload_data, *upload_data_size);
            //con_info->data += bob.c_str();
            //std::cout << "con_info->data: " << con_info->data << std::endl;
            *upload_data_size = 0; // set to 0 to indicate all data considered/handled.
            return MHD_YES;
        }
        else
        {
        }
    }
    else if (0 == strcmp(method, MHD_HTTP_METHOD_GET))
    {
        if (MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND,
                get_url_args, &url_args) < 0)
        {
            return MHD_NO;
        }

        API api;
        respdata = api.executeAPI(url, url_args);
    }

    if (respdata == "BAD RESPONSE")
    {
        return send_bad_response(connection);
    }
    //val = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "q");
    me = (char *) malloc(respdata.size() + 1);
    if (me == 0)
        return MHD_NO;
    strncpy(me, respdata.c_str(), respdata.size() + 1);
    response = MHD_create_response_from_buffer(strlen(me), me,
            MHD_RESPMEM_MUST_FREE);
    if (response == 0)
    {
        free(me);
        return MHD_NO;
    }

    /*it = url_args.find("type");
     if (it != url_args.end() && strcasecmp(it->second.c_str(), "xml") == 0)
     type = typexml;*/

    MHD_add_response_header(response, "Content-Type", "application/json");
    MHD_add_response_header(response, "Content-Range", "items 0-5/5");
    MHD_add_response_header(response, "Access-Control-Allow-Origin", "*");
    // need to make sure we always expose the (non-simple) headers that we use
    MHD_add_response_header(response, "Access-Control-Expose-Headers",
            "Content-Range");
    //MHD_add_response_header(response, "OurHeader", type);

    ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
    MHD_destroy_response(response);
    return ret;
}
Пример #21
0
int answer_to_connection (void *cls, struct MHD_Connection *connection,
		const char *url, const char *method,
		const char *version, const char *upload_data,
		size_t *upload_data_size, void **con_cls)
{
	str page = {NULL, 0};
	struct MHD_Response *response;
	int ret;
	void *async_data = NULL;
	struct httpd_cb *cb;
	const char *normalised_url;
	struct post_request *pr;
	str_str_t *kv;
	char *p;
	int cnt_type = HTTPD_STD_CNT_TYPE;
	int accept_type = HTTPD_STD_CNT_TYPE;
	int ret_code = MHD_HTTP_OK;

	LM_DBG("START *** cls=%p, connection=%p, url=%s, method=%s, "
			"versio=%s, upload_data[%zu]=%p, *con_cls=%p\n",
			cls, connection, url, method, version,
			*upload_data_size, upload_data, *con_cls);

	pr = *con_cls;
	if(pr == NULL){
		pr = pkg_malloc(sizeof(struct post_request));
		if(pr==NULL) {
			LM_ERR("oom while allocating post_request structure\n");
			return MHD_NO;
		}
		memset(pr, 0, sizeof(struct post_request));
		*con_cls = pr;
		pr = NULL;
	}

	if(strncmp(method, "POST", 4)==0) {
		if(pr == NULL){
			pr = *con_cls;
			pr->p_list = slinkedl_init(&httpd_alloc, &httpd_free);
			if (pr->p_list==NULL) {
				LM_ERR("oom while allocating list\n");
				return MHD_NO;
			}
			LM_DBG("running MHD_create_post_processor\n");
			pr->pp = MHD_create_post_processor(connection,
											post_buf_size,
											&post_iterator,
											pr);
			if(pr->pp==NULL) {
				if (*upload_data_size == 0) {
					/* We need to wait for morte data before
					 * handling the POST request */
					return MHD_YES;
				}
				LM_DBG("NOT a regular POST :o)\n");
				if (pr->content_type==0 && pr->content_len==0)
					MHD_get_connection_values(connection, MHD_HEADER_KIND,
											&getConnectionHeader, pr);
				if (pr->content_type<=0 || pr->content_len<=0) {
					LM_ERR("got a bogus request\n");
					return MHD_NO;
				}
				if (*upload_data_size != pr->content_len) {
					/* For now, we don't support large POST with truncated data */
					LM_ERR("got a truncated POST request\n");
					return MHD_NO;
				}
				LM_DBG("got ContentType [%d] with len [%d]: %.*s\\n",
					pr->content_type, pr->content_len,
					(int)*upload_data_size, upload_data);
				/* Here we save data. */
				switch (pr->content_type) {
				case HTTPD_TEXT_XML_CNT_TYPE:
				case HTTPD_APPLICATION_JSON_CNT_TYPE:
					/* Save the entire body as 'body' */
					kv = (str_str_t*)slinkedl_append(pr->p_list,
							sizeof(str_str_t) + 1 +
							*upload_data_size);
					p = (char*)(kv + 1);
					kv->key.len = 1; kv->key.s = p;
					memcpy(p, "1", 1);
					p += 1;
					kv->val.len = *upload_data_size;
					kv->val.s = p;
					memcpy(p, upload_data, *upload_data_size);
					break;
				default:
					LM_ERR("Unhandled data for ContentType [%d]\n",
							pr->content_type);
					return MHD_NO;
				}
				/* Mark the fact that we consumed all data */
				*upload_data_size = 0;
				return MHD_YES;
			}

			LM_DBG("pr=[%p] pp=[%p] p_list=[%p]\n",
					pr, pr->pp, pr->p_list);
			return MHD_YES;
		} else {
			if (pr->pp==NULL) {
				if (*upload_data_size == 0) {
					if (pr->content_type==HTTPD_TEXT_XML_CNT_TYPE)
						cnt_type = HTTPD_TEXT_XML_CNT_TYPE;
					if (pr->content_type==HTTPD_APPLICATION_JSON_CNT_TYPE)
						cnt_type = HTTPD_APPLICATION_JSON_CNT_TYPE;
					*con_cls = pr->p_list;
					cb = get_httpd_cb(url);
					if (cb) {
						normalised_url = &url[cb->http_root->len+1];
						LM_DBG("normalised_url=[%s]\n", normalised_url);
						ret_code = cb->callback(cls, (void*)connection,
								normalised_url,
								method, version,
								upload_data, upload_data_size, con_cls,
								&buffer, &page);
					} else {
						page = MI_HTTP_U_URL;
						ret_code = MHD_HTTP_BAD_REQUEST;
					}
					/* slinkedl_traverse(pr->p_list,
							&httpd_print_data, NULL, NULL); */
					slinkedl_list_destroy(*con_cls);
					pkg_free(pr); *con_cls = pr = NULL;
					goto send_response;
				}
				LM_DBG("NOT a regular POST :o)\n");
				if (pr->content_type==0 && pr->content_len==0)
					MHD_get_connection_values(connection, MHD_HEADER_KIND,
											&getConnectionHeader, pr);
				if (pr->content_type<=0 || pr->content_len<=0) {
					LM_ERR("got a bogus request\n");
					return MHD_NO;
				}
				if (*upload_data_size != pr->content_len) {
					/* For now, we don't support large POST with truncated data */
					LM_ERR("got a truncated POST request\n");
					return MHD_NO;
				}
				LM_DBG("got ContentType [%d] with len [%d]: %.*s\\n",
					pr->content_type, pr->content_len,
					(int)*upload_data_size, upload_data);
				/* Here we save data. */
				switch (pr->content_type) {
				case HTTPD_TEXT_XML_CNT_TYPE:
				case HTTPD_APPLICATION_JSON_CNT_TYPE:
					/* Save the entire body as 'body' */
					kv = (str_str_t*)slinkedl_append(pr->p_list,
							sizeof(str_str_t) + 1 +
							*upload_data_size);
					p = (char*)(kv + 1);
					kv->key.len = 1; kv->key.s = p;
					memcpy(p, "1", 1);
					p += 1;
					kv->val.len = *upload_data_size;
					kv->val.s = p;
					memcpy(p, upload_data, *upload_data_size);
					break;
				default:
					LM_ERR("Unhandled data for ContentType [%d]\n",
							pr->content_type);
					return MHD_NO;
				}
				/* Mark the fact that we consumed all data */
				*upload_data_size = 0;
				return MHD_YES;
			}
			LM_DBG("running MHD_post_process: "
					"pp=%p status=%d upload_data_size=%zu\n",
					pr->pp, pr->status, *upload_data_size);
			if (pr->status<0) {
				slinkedl_list_destroy(pr->p_list);
				pr->p_list = NULL;
				/* FIXME:
				 * It might be better to reply with an error
				 * instead of resetting the connection via MHD_NO */
				return MHD_NO;
			}
			ret =MHD_post_process(pr->pp, upload_data, *upload_data_size);
			LM_DBG("ret=%d upload_data_size=%zu\n", ret, *upload_data_size);
			if(*upload_data_size != 0) {
				*upload_data_size = 0;
				return MHD_YES;
			}

			LM_DBG("running MHD_destroy_post_processor: "
					"pr=[%p] pp=[%p] p_list=[%p]\n",
					pr, pr->pp, pr->p_list);
			MHD_destroy_post_processor(pr->pp);
			LM_DBG("done MHD_destroy_post_processor\n");
			/* slinkedl_traverse(pr->p_list, &httpd_print_data, NULL, NULL); */
			*con_cls = pr->p_list;

			cb = get_httpd_cb(url);
			if (cb) {
				normalised_url = &url[cb->http_root->len+1];
				LM_DBG("normalised_url=[%s]\n", normalised_url);
				ret_code = cb->callback(cls, (void*)connection,
						normalised_url,
						method, version,
						upload_data, upload_data_size, con_cls,
						&buffer, &page);
			} else {
				page = MI_HTTP_U_URL;
				ret_code = MHD_HTTP_BAD_REQUEST;
			}
			/* slinkedl_traverse(pr->p_list, &httpd_print_data, NULL, NULL); */
			slinkedl_list_destroy(*con_cls);
			pkg_free(pr); *con_cls = pr = NULL;
		}
	}else if(strncmp(method, "GET", 3)==0) {
		pr = *con_cls;
		MHD_get_connection_values(connection, MHD_HEADER_KIND,
								&getConnectionHeader, pr);
		accept_type = pr->accept_type;
		pkg_free(pr); *con_cls = pr = NULL;
		LM_DBG("accept_type=[%d]\n", accept_type);
		cb = get_httpd_cb(url);
		if (cb) {
			normalised_url = &url[cb->http_root->len+1];
			LM_DBG("normalised_url=[%s]\n", normalised_url);
			ret_code = cb->callback(cls, (void*)connection,
					normalised_url,
					method, version,
					upload_data, upload_data_size, con_cls,
					&buffer, &page);
		} else {
			page = MI_HTTP_U_URL;
			ret_code = MHD_HTTP_BAD_REQUEST;
		}
	}else{
		page = MI_HTTP_U_METHOD;
		ret_code = MHD_HTTP_METHOD_NOT_ACCEPTABLE;
	}

send_response:
	if (page.s) {
		LM_DBG("MHD_create_response_from_data [%p:%d]\n",
			page.s, page.len);
		response = MHD_create_response_from_data(page.len,
							(void*)page.s,
							0, 1);
	} else {
		LM_DBG("MHD_create_response_from_callback\n");
		response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
							buffer.len,
							cb->flush_data_callback,
							(void*)async_data,
							NULL);
	}
	if (cnt_type==HTTPD_TEXT_XML_CNT_TYPE || accept_type==HTTPD_TEXT_XML_CNT_TYPE)
		MHD_add_response_header(response,
								MHD_HTTP_HEADER_CONTENT_TYPE,
								"text/xml; charset=utf-8");
	if (cnt_type==HTTPD_APPLICATION_JSON_CNT_TYPE || accept_type==HTTPD_APPLICATION_JSON_CNT_TYPE)
		MHD_add_response_header(response,
								MHD_HTTP_HEADER_CONTENT_TYPE,
								"application/json");
	ret = MHD_queue_response (connection, ret_code, response);
	MHD_destroy_response (response);

	return ret;
}
Пример #22
0
static int
ahc_echo (void *cls,
          struct MHD_Connection *connection,
          const char *url,
          const char *method,
          const char *version,
          const char *upload_data, size_t *upload_data_size,
          void **unused)
{
  static int ptr;
  const char *me = cls;
  struct MHD_Response *response;
  int ret;
  const char *hdr;

  if (0 != strcmp (me, method))
    return MHD_NO;              /* unexpected method */
  if (&ptr != *unused)
    {
      *unused = &ptr;
      return MHD_YES;
    }
  *unused = NULL;
  ret = 0;
  MHD_get_connection_values (connection, MHD_HEADER_KIND, &kv_cb, &ret);
  if (ret != 1)
    abort ();
  hdr = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, "NotFound");
  if (hdr != NULL)
    abort ();
  hdr = MHD_lookup_connection_value (connection,
                                     MHD_HEADER_KIND, MHD_HTTP_HEADER_ACCEPT);
  if ((hdr == NULL) || (0 != strcmp (hdr, "*/*")))
    abort ();
  hdr = MHD_lookup_connection_value (connection,
                                     MHD_HEADER_KIND, MHD_HTTP_HEADER_HOST);
  if ((hdr == NULL) || (0 != strcmp (hdr, "127.0.0.1:21080")))
    abort ();
  MHD_set_connection_value (connection,
                            MHD_HEADER_KIND, "FakeHeader", "NowPresent");
  hdr = MHD_lookup_connection_value (connection,
                                     MHD_HEADER_KIND, "FakeHeader");
  if ((hdr == NULL) || (0 != strcmp (hdr, "NowPresent")))
    abort ();

  response = MHD_create_response_from_buffer (strlen (url),
					      (void *) url,
					      MHD_RESPMEM_MUST_COPY);
  MHD_add_response_header (response, "MyHeader", "MyValue");
  hdr = MHD_get_response_header (response, "MyHeader");
  if (0 != strcmp ("MyValue", hdr))
    abort ();
  MHD_add_response_header (response, "MyHeader", "MyValueToo");
  if (MHD_YES != MHD_del_response_header (response, "MyHeader", "MyValue"))
    abort ();
  hdr = MHD_get_response_header (response, "MyHeader");
  if (0 != strcmp ("MyValueToo", hdr))
    abort ();
  if (1 != MHD_get_response_headers (response, NULL, NULL))
    abort ();
  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
  MHD_destroy_response (response);
  if (ret == MHD_NO)
    abort ();
  return ret;
}
Пример #23
0
int http_controller_request(void *cls, struct MHD_Connection *connection,
        const char *url,
        const char *method, const char *version,
        const char *upload_data,
        size_t *upload_data_size, void **con_cls)
{

    char *page = NULL;

    if(!strcmp(method, "GET"))
    {
        if(!strcmp(url, "/"))
            page = http_get_index();
	else if (!strcmp(url, "/playlist"))
	    page = http_get_playlist();
	else if (!strcmp(url, "/status"))
	    page = http_get_status();
	else if (!strcmp(url, "/current"))
	    page = http_get_current();
	else if (!strncmp(url, "/playlist/", 10))
	{
	    char *request = strdup(url);
	    page = http_get_playlist_item(request);
	    free(request);
	}

    } else if(!strcmp(method, "POST"))
    {
        //Calculate content_length
        int content_length = 0;
        MHD_get_connection_values(connection, MHD_HEADER_KIND, http_controller_headers, &content_length);
        
        //We need more post data
        if(content_length > *upload_data_size)
            return MHD_YES;
	
	//Create string from upload_data
	char *strdata = malloc(content_length + 1);
	strncpy(strdata, upload_data, content_length);
	strdata[content_length] = 0;

        //Parse JSON
        json_value *data = json_parse(strdata);
	free(strdata);
	strdata = NULL;

	//Ignore malformed JSON
	if(data)
	{
            //Execute commands
            if(!strcmp(url, "/status"))
                page = http_post_status(data);
	    else if(!strcmp(url, "/current"))
		page = http_post_current(data);
	    else if(!strcmp(url, "/playlist"))
		page = http_post_playlist(data);
	    else if (!strncmp(url, "/playlist/", 10))
	    {
	        char *request = strdup(url);
	        page = http_post_playlist_item(request, data);
	        free(request);
	    }

            json_value_free(data);
            gui_update_playlist();
	}
    } else if(!strcmp(method, "DELETE"))
    {
	if(!strcmp(url, "/playlist"))
	    http_delete_playlist();
	else if(!strncmp(url, "/playlist/", 10))
	{
	    char *request = strdup(url);
	    page = http_delete_playlist_item(request);
	    free(request);
	}
        gui_update_playlist();
    }

    if(page == NULL)
            page = strdup("404 Not Found!");

    struct MHD_Response *response;
    response = MHD_create_response_from_data (strlen (page),
        (void*) page, true, false);

    int ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
    MHD_destroy_response (response);

    return ret;
}
Пример #24
0
/* ****************************************************************************
*
* connectionTreat - 
*
* This is the MHD_AccessHandlerCallback function for MHD_start_daemon
* This function returns:
* o MHD_YES  if the connection was handled successfully
* o MHD_NO   if the socket must be closed due to a serious error
*
* - This function is called once when the headers are read and the ciP is created.
* - Then it is called for data payload and once all the payload an acknowledgement
*   must be done, setting *upload_data_size to ZERO.
* - The last call is made with *upload_data_size == 0 and now is when the connection
*   is open to send responses.
*
* Call 1: *con_cls == NULL
* Call 2: *con_cls != NULL  AND  *upload_data_size != 0
* Call 3: *con_cls != NULL  AND  *upload_data_size == 0
*/
static int connectionTreat
(
   void*            cls,
   MHD_Connection*  connection,
   const char*      url,
   const char*      method,
   const char*      version,
   const char*      upload_data,
   size_t*          upload_data_size,
   void**           con_cls
)
{
  ConnectionInfo* ciP      = (ConnectionInfo*) *con_cls;
  size_t          dataLen  = *upload_data_size;

  // 1. First call - setup ConnectionInfo and get/check HTTP headers
  if (ciP == NULL)
  {
    if ((ciP = new ConnectionInfo(url, method, version, connection)) == NULL)
      LM_RE(MHD_NO, ("Error allocating ConnectionInfo"));
        
    *con_cls = (void*) ciP; // Pointer to ConnectionInfo for subsequent calls

    MHD_get_connection_values(connection, MHD_HEADER_KIND, httpHeaderGet, &ciP->httpHeaders);

    ciP->outFormat  = wantedOutputSupported(ciP->httpHeaders.accept, &ciP->charset);
    if (ciP->outFormat == NOFORMAT)
      ciP->outFormat = XML; // XML is default output format

    if (contentTypeCheck(ciP) != 0)
    {
      LM_W(("Error in Content-Type"));
      restReply(ciP, ciP->answer);
    }
    else if (outFormatCheck(ciP) != 0)
    {
      LM_W(("Bad Accepted Out-Format (in Accept header)"));
      restReply(ciP, ciP->answer);
    }
    else
      ciP->inFormat = formatParse(ciP->httpHeaders.contentType, NULL);

    return MHD_YES;
  }


  //
  // 2. Data gathering calls
  //
  // 2-1. Data gathering calls, just wait
  // 2-2. Last data gathering call, acknowledge the receipt of data
  //
  if (dataLen != 0)
  {
    if (dataLen == ciP->httpHeaders.contentLength)
    {
      if (ciP->httpHeaders.contentLength <= PAYLOAD_MAX_SIZE)
      {
        if (ciP->httpHeaders.contentLength > STATIC_BUFFER_SIZE)
          ciP->payload = (char*) malloc(ciP->httpHeaders.contentLength);
        else
          ciP->payload = static_buffer;

        ciP->payloadSize = dataLen;
        memcpy(ciP->payload, upload_data, dataLen);
        ciP->payload[dataLen] = 0;
      }
      else
      {
        char details[256];
        snprintf(details, sizeof(details), "payload size: %d, max size supported: %d", ciP->httpHeaders.contentLength, PAYLOAD_MAX_SIZE);

        ciP->answer         = restErrorReplyGet(ciP, ciP->outFormat, "", ciP->url, SccRequestEntityTooLarge, details);
        ciP->httpStatusCode = SccRequestEntityTooLarge;
      }

      // All payload received, acknowledge!
      *upload_data_size = 0;
    }
    else
      LM_T(LmtPartialPayload, ("Got %d of payload of %d bytes", dataLen, ciP->httpHeaders.contentLength));

    return MHD_YES;
  }


  // 3. Finally, serve the request (unless an error has occurred)
  if (((ciP->verb == POST) || (ciP->verb == PUT)) && (ciP->httpHeaders.contentLength == 0))
  {
    std::string errorMsg = restErrorReplyGet(ciP, ciP->outFormat, "", url, SccLengthRequired, "Zero/No Content-Length in PUT/POST request");
    ciP->httpStatusCode = SccLengthRequired;
    restReply(ciP, errorMsg);
  }
  else if (ciP->answer != "")
    restReply(ciP, ciP->answer);
  else
    serveFunction(ciP);

  return MHD_YES;
}
Пример #25
0
static int OnHttpRequest(void* cls,
                         struct MHD_Connection* connection,
                         const char* url,
                         const char* method,
                         const char* version,
                         const char* upload_data,
                         size_t* upload_data_size,
                         void** ptr)
{
  if (!*ptr)
  {
    *ptr = new std::string;
    return MHD_YES;
  }

  std::string* str = (std::string*) *ptr;

  if (strcmp(method, "POST") == 0 && *upload_data_size)
  {
    *upload_data_size = 0;
    (*str) += upload_data;
    return MHD_YES;
  }

  CLog::Log(LOGDEBUG,"OnHttpRequest - enter function [url=%s][method=%s][version=%s][upload_data=%s][upload_data_size=%lu] (hsrv)",url,method,version,upload_data,*upload_data_size);

  CHttpServer* httpServer = (CHttpServer*)cls;
  if (!httpServer)
  {
    CLog::Log(LOGERROR,"OnHttpRequest - FAILED to get server context (hsrv)");
    return MHD_NO;
  }

  MAPHTTPHEADER header;
  MHD_get_connection_values(connection, MHD_HEADER_KIND, HeadersIterator, &header);

#if 0
  std::map<char*, char*>::const_iterator end = headerParams.end();
  for (std::map<char*, char*>::const_iterator it = headerParams.begin(); it != end; ++it)
  {
      std::cout << "Key: " << it->first;
      std::cout << "Value: " << it->second << '\n';
  }
#endif

  CHttpRequest httpRequest((char*) method, (char*) version, (char*) url, header, str->size(), (char*) str->c_str());
  CHttpResponse httpResponse;

  CLog::Log(LOGDEBUG,"OnHttpRequest - BEFORE HandleRequest with [method=%s][version=%s][url=%s][str=%s][strSize=%lu] (hsrv)",method,version,url,str->c_str(),str->size());
  httpServer->HandleRequest(httpRequest, httpResponse);
  CLog::Log(LOGDEBUG,"OnHttpRequest - AFTER HandleRequest with [method=%s][version=%s][url=%s][str=%s][strSize=%lu]. [IsChunked=%d] (hsrv)",method,version,url,str->c_str(),str->size(),httpResponse.IsChunked());

  struct MHD_Response* response;

  if (httpResponse.IsChunked())
  {
    CStdString deviceId = "";
    IMAPHTTPHEADER it = header.find("X-Boxee-Device-ID");
    if (it == header.end())
    {
      CLog::Log(LOGWARNING,"OnHttpRequest - FAILED to get X-Boxee-Device-ID from header for chunked request (hsrv)");
    }
    else
    {
      deviceId = it->second;
    }

    CReaderCallback* readerCls = new CReaderCallback(deviceId, CStdString(url));
    readerCls->chunkedCB = httpResponse.GetChunkedCallback();

    CLog::Log(LOGDEBUG,"OnHttpRequest - going to response_from_callback. [method=%s][version=%s][url=%s][str=%s][strSize=%lu]. [IsChunked=%d] (hsrv)",method,version,url,str->c_str(),str->size(),httpResponse.IsChunked());

    response = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, 65535, readerCallback, readerCls, NULL);

    if (MHD_add_response_header(response, "Transfer-Encoding", "chunked") == MHD_NO)
    {
      CLog::Log(LOGERROR,"OnHttpRequest - FAILED to add server to header");
      return MHD_NO;
    }
  }
  else
  {
    unsigned char* bodyPtr = &(httpResponse.GetBody()[0]);
    response = MHD_create_response_from_buffer(httpResponse.GetBody().size(), bodyPtr, MHD_RESPMEM_MUST_COPY);
  }

  if (!response)
  {
    CLog::Log(LOGERROR,"OnHttpRequest - FAILED to create response. [%s] (hsrv)",method);
    return MHD_NO;
  }

  if (MHD_add_response_header(response, "Server", httpServer->GetServerAgent().c_str()) == MHD_NO)
  {
    CLog::Log(LOGERROR,"OnHttpRequest - FAILED to add server to header");
    return MHD_NO;
  }

  std::map<std::string, std::string>::iterator it = httpResponse.GetHeader().begin();
  while (it != httpResponse.GetHeader().end())
  {
    if (MHD_add_response_header(response, it->first.c_str(), it->second.c_str()) == MHD_NO)
    {
      CLog::Log(LOGERROR,"OnHttpRequest - FAILED to add response header [%s=%s] (hsrv)", it->first.c_str(), it->second.c_str());
    }

    it++;
  }

  CLog::Log(LOGDEBUG,"OnHttpRequest - going to queue response. [code=%d][bodySize=%lu] (hsrv)",httpResponse.GetCode(), httpResponse.GetBody().size());

  int retVal = MHD_YES;
  if (MHD_queue_response(connection, httpResponse.GetCode(), response) != MHD_YES)
  {
    CLog::Log(LOGERROR,"OnHttpRequest - FAILED to queue response. [%s] (hsrv)",method);
    retVal = MHD_NO;
  }

  MHD_destroy_response(response);

  delete str;

  return retVal;
}
Пример #26
0
/**
 * Prints everything in the header of a connection
 * @param connection the connection that we want to print all headers.
 */
static void print_headers(struct MHD_Connection *connection)
{
    fprintf(stdout, _("Headers for this connection are:\n"));
    MHD_get_connection_values(connection, MHD_HEADER_KIND, &print_out_key, NULL);
}
Пример #27
0
int httpd_callback (void *cls, struct MHD_Connection *connection, 
																				const char *url, 
																				const char *method, const char *version, 
																				const char *upload_data, 
																				size_t *upload_data_size, void **con_cls) {

	struct MHD_Response *response;
	int ret, timeout;

	while(! page_delivered) {
		if (avr_failure == 1) {
			waiting_for_response = 0;
			page_delivered = 1;
			return MHD_NO;
		}
		printf("HTTPD_CALLBACK: F*****g waiting for page to be delivered\n");
		sleep(1);
	}

	printf ("HTTPD_CALLBACK: Starting HTTP Callback for new %s request for %s using version %s\n", method, url, version);

	memset(&page[0], 0, 65535);
	if (! MHD_get_connection_values (connection, MHD_GET_ARGUMENT_KIND, &parse_get_args, NULL)) {
		if (strncmp(url, "/\0", 2) == 0) {
			url = "/index.html";
		}

		char httpd_file_path[256] = HTTPD_ROOT;
		strncat(httpd_file_path, url, 256);
		

		struct stat sb;
		if (stat(httpd_file_path, &sb) == -1) {
			fprintf(stderr, "HTTPD_CALLBACK: stat error: %s\n", httpd_file_path);
			return MHD_NO;
		}
		
		if ((sb.st_mode & S_IFMT) == S_IFREG) {
			fprintf(stderr, "HTTPD_CALLBACK: delivering %s\n", httpd_file_path);
			int pageIdx = 0;
			char inChar;
			FILE *fp;
			fp = fopen(httpd_file_path, "r");
			while (inChar != EOF) {
				inChar = fgetc(fp);
				if (inChar != EOF) {
					page[pageIdx++] = inChar;
				}
			}
			fclose(fp);
		} else {
			// 404
			fprintf(stderr, "HTTPD_CALLBACK: not a regular file: %s 0x%x != 0x%x\n", httpd_file_path, sb.st_mode & S_IFMT, S_IFREG);
			return MHD_NO;
		}
	}

	printf("HTTPD_CALLBACK: delivering page\n");

	response = MHD_create_response_from_data(strlen(page), (void*)page, 0, 0);
 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
	MHD_destroy_response (response);

	page_delivered = 1;
	return ret;
}
Пример #28
0
static int connectionTreat
(
   void*            cls,
   MHD_Connection*  connection,
   const char*      url,
   const char*      method,
   const char*      version,
   const char*      upload_data,
   size_t*          upload_data_size,
   void**           con_cls
)
{
  ConnectionInfo*        ciP         = (ConnectionInfo*) *con_cls;
  size_t                 dataLen     = *upload_data_size;

  // 1. First call - setup ConnectionInfo and get/check HTTP headers
  if (ciP == NULL)
  {
    //
    // First thing to do on a new connection, set correlator to N/A.
    // After reading HTTP headers, the correlator id either changes due to encountering a 
    // Fiware-Correlator HTTP Header, or, if no HTTP header with Fiware-Correlator is found,
    // a new correlator is generated.
    //
    correlatorIdSet("N/A");

    //
    // IP Address and port of caller
    //
    char            ip[32];
    unsigned short  port = 0;

    const union MHD_ConnectionInfo* mciP = MHD_get_connection_info(connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS);

    if (mciP != NULL)
    {
      struct sockaddr* addr = (struct sockaddr*) mciP->client_addr;

      port = (addr->sa_data[0] << 8) + addr->sa_data[1];
      snprintf(ip, sizeof(ip), "%d.%d.%d.%d",
               addr->sa_data[2] & 0xFF,
               addr->sa_data[3] & 0xFF,
               addr->sa_data[4] & 0xFF,
               addr->sa_data[5] & 0xFF);
      snprintf(clientIp, sizeof(clientIp), "%s", ip);
    }
    else
    {
      port = 0;
      snprintf(ip, sizeof(ip), "IP unknown");
    }


    //
    // Reset time measuring?
    //
    if (timingStatistics)
    {
      memset(&threadLastTimeStat, 0, sizeof(threadLastTimeStat));
    }


    //
    // ConnectionInfo
    //
    // FIXME P1: ConnectionInfo could be a thread variable (like the static_buffer),
    // as long as it is properly cleaned up between calls.
    // We would save the call to new/free for each and every request.
    // Once we *really* look to scratch some efficiency, this change should be made.
    //
    // Also, is ciP->ip really used?
    //
    if ((ciP = new ConnectionInfo(url, method, version, connection)) == NULL)
    {
      LM_E(("Runtime Error (error allocating ConnectionInfo)"));
      return MHD_NO;
    }

    if (timingStatistics)
    {
      clock_gettime(CLOCK_REALTIME, &ciP->reqStartTime);
    }

    LM_T(LmtRequest, (""));
    // WARNING: This log message below is crucial for the correct function of the Behave tests - CANNOT BE REMOVED
    LM_T(LmtRequest, ("--------------------- Serving request %s %s -----------------", method, url));
    *con_cls     = (void*) ciP; // Pointer to ConnectionInfo for subsequent calls
    ciP->port    = port;
    ciP->ip      = ip;
    ciP->callNo  = reqNo;

    ++reqNo;


    //
    // URI parameters
    //
    // FIXME P1: We might not want to do all these assignments, they are not used in all requests ...
    //           Once we *really* look to scratch some efficiency, this change should be made.
    //     
    ciP->uriParam[URI_PARAM_PAGINATION_OFFSET]  = DEFAULT_PAGINATION_OFFSET;
    ciP->uriParam[URI_PARAM_PAGINATION_LIMIT]   = DEFAULT_PAGINATION_LIMIT;
    ciP->uriParam[URI_PARAM_PAGINATION_DETAILS] = DEFAULT_PAGINATION_DETAILS;
    
    MHD_get_connection_values(connection, MHD_HEADER_KIND, httpHeaderGet, &ciP->httpHeaders);

    char correlator[CORRELATOR_ID_SIZE + 1];
    if (ciP->httpHeaders.correlator == "")
    {
      correlatorGenerate(correlator);
      ciP->httpHeaders.correlator = correlator;
    }

    correlatorIdSet(ciP->httpHeaders.correlator.c_str());

    ciP->httpHeader.push_back("Fiware-Correlator");
    ciP->httpHeaderValue.push_back(ciP->httpHeaders.correlator);

    //
    // Transaction starts here
    //
    lmTransactionStart("from", ip, port, url);  // Incoming REST request starts


    /* X-Forwared-For (used by a potential proxy on top of Orion) overrides ip */
    if (ciP->httpHeaders.xforwardedFor == "")
    {
      lmTransactionSetFrom(ip);
    }
    else
    {
      lmTransactionSetFrom(ciP->httpHeaders.xforwardedFor.c_str());
    }

    ciP->apiVersion = apiVersionGet(ciP->url.c_str());

    char tenant[SERVICE_NAME_MAX_LEN + 1];
    ciP->tenantFromHttpHeader = strToLower(tenant, ciP->httpHeaders.tenant.c_str(), sizeof(tenant));
    ciP->outMimeType          = wantedOutputSupported(ciP->apiVersion, ciP->httpHeaders.accept, &ciP->charset);
    if (ciP->outMimeType == NOMIMETYPE)
    {
      ciP->outMimeType = JSON; // JSON is default output mimeType
    }

    MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, uriArgumentGet, ciP);

    return MHD_YES;
  }


  //
  // 2. Data gathering calls
  //
  // 2-1. Data gathering calls, just wait
  // 2-2. Last data gathering call, acknowledge the receipt of data
  //
  if (dataLen != 0)
  {
    //
    // If the HTTP header says the request is bigger than our PAYLOAD_MAX_SIZE,
    // just silently "eat" the entire message
    //
    if (ciP->httpHeaders.contentLength > PAYLOAD_MAX_SIZE)
    {
      *upload_data_size = 0;
      return MHD_YES;
    }

    //
    // First call with payload - use the thread variable "static_buffer" if possible,
    // otherwise allocate a bigger buffer
    //
    // FIXME P1: This could be done in "Part I" instead, saving an "if" for each "Part II" call
    //           Once we *really* look to scratch some efficiency, this change should be made.
    //
    if (ciP->payloadSize == 0)  // First call with payload
    {
      if (ciP->httpHeaders.contentLength > STATIC_BUFFER_SIZE)
      {
        ciP->payload = (char*) malloc(ciP->httpHeaders.contentLength + 1);
      }
      else
      {
        ciP->payload = static_buffer;
      }
    }

    // Copy the chunk
    LM_T(LmtPartialPayload, ("Got %d of payload of %d bytes", dataLen, ciP->httpHeaders.contentLength));
    memcpy(&ciP->payload[ciP->payloadSize], upload_data, dataLen);
    
    // Add to the size of the accumulated read buffer
    ciP->payloadSize += *upload_data_size;

    // Zero-terminate the payload
    ciP->payload[ciP->payloadSize] = 0;

    // Acknowledge the data and return
    *upload_data_size = 0;
    return MHD_YES;
  }


  //
  // 3. Finally, serve the request (unless an error has occurred)
  // 
  // URL and headers checks are delayed to the "third" MHD call, as no 
  // errors can be sent before all the request has been read
  //
  if (urlCheck(ciP, ciP->url) == false)
  {
    alarmMgr.badInput(clientIp, "error in URI path");
    restReply(ciP, ciP->answer);
  }

  ciP->servicePath = ciP->httpHeaders.servicePath;
  lmTransactionSetSubservice(ciP->servicePath.c_str());

  if (servicePathSplit(ciP) != 0)
  {
    alarmMgr.badInput(clientIp, "error in ServicePath http-header");
    restReply(ciP, ciP->answer);
  }

  if (contentTypeCheck(ciP) != 0)
  {
    alarmMgr.badInput(clientIp, "invalid mime-type in Content-Type http-header");
    restReply(ciP, ciP->answer);
  }
  else if (outMimeTypeCheck(ciP) != 0)
  {
    alarmMgr.badInput(clientIp, "invalid mime-type in Accept http-header");
    restReply(ciP, ciP->answer);
  }
  else
  {
    ciP->inMimeType = mimeTypeParse(ciP->httpHeaders.contentType, NULL);
  }

  if (ciP->httpStatusCode != SccOk)
  {
    alarmMgr.badInput(clientIp, "error in URI parameters");
    restReply(ciP, ciP->answer);
    return MHD_YES;
  }  

  //
  // Here, if the incoming request was too big, return error about it
  //
  if (ciP->httpHeaders.contentLength > PAYLOAD_MAX_SIZE)
  {
    char details[256];
    snprintf(details, sizeof(details), "payload size: %d, max size supported: %d", ciP->httpHeaders.contentLength, PAYLOAD_MAX_SIZE);

    alarmMgr.badInput(clientIp, details);

    ciP->answer         = restErrorReplyGet(ciP, "", ciP->url, SccRequestEntityTooLarge, details);
    ciP->httpStatusCode = SccRequestEntityTooLarge;
  }

  //
  // Requests of verb POST, PUT or PATCH are considered erroneous if no payload is present - with two exceptions.
  //
  // - Old log requests  (URL contains '/log/')
  // - New log requests  (URL is exactly '/admin/log')
  //
  if (((ciP->verb == POST) || (ciP->verb == PUT) || (ciP->verb == PATCH )) && 
      (ciP->httpHeaders.contentLength == 0) && 
      ((strncasecmp(ciP->url.c_str(), "/log/", 5) != 0) && (strncasecmp(ciP->url.c_str(), "/admin/log", 10) != 0)))
  {
    std::string errorMsg = restErrorReplyGet(ciP, "", url, SccContentLengthRequired, "Zero/No Content-Length in PUT/POST/PATCH request");

    ciP->httpStatusCode  = SccContentLengthRequired;
    restReply(ciP, errorMsg);
    alarmMgr.badInput(clientIp, errorMsg);
  }
  else if (ciP->answer != "")
  {
    alarmMgr.badInput(clientIp, ciP->answer);
    restReply(ciP, ciP->answer);
  }
  else
  {
    serveFunction(ciP);
  }

  return MHD_YES;
}
Пример #29
0
static int check_token_is_valid(struct MHD_Connection *connection, t_client *client)
{
	/* token check */
	struct collect_query_key token_key = { .key = "token" };
	struct collect_query_key tok_key = { .key = "tok" };

	MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, &collect_query_key, &token_key);
	MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, &collect_query_key, &tok_key);

	/* token not found in query string */
	if (!token_key.value && !tok_key.value)
		return 0;

	if (token_key.value && !strcmp(client->token, token_key.value))
		return 1;

	if (tok_key.value && !strcmp(client->token, tok_key.value))
		return 1;

	return 0;
}


/**
 * @brief try_to_authenticate
 * @param connection
 * @param client
 * @param host
 * @param url
 * @return
 */
static int try_to_authenticate(struct MHD_Connection *connection, t_client *client, const char *host, const char *url)
{
	/* a successful auth looks like
	 * http://192.168.42.1:2050/nodogsplash_auth/?redir=http%3A%2F%2Fberlin.freifunk.net%2F&tok=94c4cdd2
	 * when authaction -> http://192.168.42.1:2050/nodogsplash_auth/
	 */
	s_config *config = config_get_config();

	/* we are checking here for the second '/' of /denydir/ */
	if (check_authdir_match(url, config->authdir)) {
		/* matched to authdir */
		if (check_token_is_valid(connection, client)) {
			return 1; /* valid token */
		}
	} else if (check_authdir_match(url, config->denydir)) {
		/* matched to deauth */
		/* TODO: do we need denydir? */
		return 0;
	}

	return 0;
}

/**
 * @brief authenticate the client and redirect them
 * @param connection
 * @param ip_addr - needs to be freed
 * @param mac - needs to be freed
 * @param redirect_url - redirect the client to this url
 * @return
 */
static int authenticate_client(struct MHD_Connection *connection,
							   const char *ip_addr,
							   const char *mac,
							   const char *redirect_url,
							   t_client *client)
{
	/* TODO: handle redirect_url == NULL */
	auth_client_action(ip_addr, mac, AUTH_MAKE_AUTHENTICATED);
	if (redirect_url)
		return send_redirect_temp(connection, redirect_url);
	else
		return send_error(connection, 200);
}
Пример #30
0
int
http_cb_request (void *cls,
                struct MHD_Connection *connection,
                const char *url,
                const char *method,
                const char *version,
                const char *upload_data,
                size_t *upload_data_size,
                void **ptr)
{
  (void)cls;
  (void)url;
  (void)upload_data;
  (void)upload_data_size;
  
  int ret;
  struct Proxy *proxy;
  struct SPDY_Headers spdy_headers;
  bool with_body = false;
  struct HTTP_URI *http_uri;
  const char *header_value;

  if (NULL == ptr || NULL == *ptr)
    return MHD_NO;
    
  http_uri = (struct HTTP_URI *)*ptr;
    
  if(NULL == http_uri->proxy)
  {
    //first call for this request
    if (0 != strcmp (method, MHD_HTTP_METHOD_GET) && 0 != strcmp (method, MHD_HTTP_METHOD_POST))
    {
      free(http_uri->uri);
      free(http_uri);
      PRINT_INFO2("unexpected method %s", method);
      return MHD_NO;
    }
    
    if(NULL == (proxy = au_malloc(sizeof(struct Proxy))))
    {
      free(http_uri->uri);
      free(http_uri);
      PRINT_INFO("No memory");
      return MHD_NO; 
    }
    
    ++glob_opt.responses_pending;
    proxy->id = rand();
    proxy->http_active = true;
    proxy->http_connection = connection;
    http_uri->proxy = proxy;
    return MHD_YES;
  }
  
  proxy = http_uri->proxy;
  
  if(proxy->spdy_error || proxy->http_error)
    return MHD_NO; // handled at different place TODO? leaks?

  if(proxy->spdy_active)
  {
    if(0 == strcmp (method, MHD_HTTP_METHOD_POST))
    {
      PRINT_INFO("POST processing");
        
      int rc= spdylay_session_resume_data(proxy->spdy_connection->session, proxy->stream_id);
      PRINT_INFO2("rc is %i stream is %i", rc, proxy->stream_id);
      proxy->spdy_connection->want_io |= WANT_WRITE;
      
      if(0 == *upload_data_size)
      {
      PRINT_INFO("POST http EOF");
        proxy->receiving_done = true;
        return MHD_YES;
      }
      
      if(!copy_buffer(upload_data, *upload_data_size, &proxy->received_body, &proxy->received_body_size))
      {
        //TODO handle it better?
        PRINT_INFO("not enough memory (malloc/realloc returned NULL)");
        return MHD_NO;
      }
      
      *upload_data_size = 0;
                               
      return MHD_YES;
    }
  
    //already handled
    PRINT_INFO("unnecessary call to http_cb_request");
    return MHD_YES;
  }
  
  //second call for this request

  PRINT_INFO2("received request for '%s %s %s'", method, http_uri->uri, version);

  proxy->url = http_uri->uri;
  
  header_value = MHD_lookup_connection_value(connection,
    MHD_HEADER_KIND, MHD_HTTP_HEADER_CONTENT_LENGTH);
  
  with_body = 0 == strcmp (method, MHD_HTTP_METHOD_POST)
    && (NULL == header_value || 0 != strcmp ("0", header_value));
    
  PRINT_INFO2("body will be sent %i", with_body);
    
  ret = parse_uri(&glob_opt.uri_preg, proxy->url, &proxy->uri);
  if(ret != 0)
    DIE("parse_uri failed");
  proxy->http_uri = http_uri;

  spdy_headers.num = MHD_get_connection_values (connection,
                       MHD_HEADER_KIND,
                       NULL,
                       NULL);
  if(NULL == (spdy_headers.nv = au_malloc(((spdy_headers.num + 5) * 2 + 1) * sizeof(char *))))
    DIE("no memory");
  spdy_headers.nv[0] = ":method";     spdy_headers.nv[1] = method;
  spdy_headers.nv[2] = ":path";       spdy_headers.nv[3] = proxy->uri->path_and_more;
  spdy_headers.nv[4] = ":version";    spdy_headers.nv[5] = (char *)version;
  spdy_headers.nv[6] = ":scheme";     spdy_headers.nv[7] = proxy->uri->scheme;
  spdy_headers.nv[8] = ":host";       spdy_headers.nv[9] = NULL;
  //nv[14] = NULL;
  spdy_headers.cnt = 10;
  MHD_get_connection_values (connection,
                       MHD_HEADER_KIND,
                       &http_cb_iterate,
                       &spdy_headers);
                       
  spdy_headers.nv[spdy_headers.cnt] = NULL;
  if(NULL == spdy_headers.nv[9])
    spdy_headers.nv[9] = proxy->uri->host_and_port;

  if(0 != spdy_request(spdy_headers.nv, proxy, with_body))
  {
    free(spdy_headers.nv);
    //free_proxy(proxy);
    
    return MHD_NO;
  }
  free(spdy_headers.nv);
  
  proxy->http_response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
                         4096,
                         &http_cb_response,
                         proxy,
                         &http_cb_response_done);

  if (NULL == proxy->http_response)
    DIE("no response");
  
  if(MHD_NO == MHD_add_response_header (proxy->http_response,
                 "Proxy-Connection", "keep-alive"))
    PRINT_INFO("SPDY_name_value_add failed: ");
  if(MHD_NO == MHD_add_response_header (proxy->http_response,
                 "Connection", "Keep-Alive"))
    PRINT_INFO("SPDY_name_value_add failed: ");
  if(MHD_NO == MHD_add_response_header (proxy->http_response,
                 "Keep-Alive", "timeout=5, max=100"))
    PRINT_INFO("SPDY_name_value_add failed: ");
    
  proxy->spdy_active = true;
  
  return MHD_YES;
}