void GetServiceHandler::handleRequestImpl(Poco::Net::HTTPServerRequest & httpRequest, Poco::Net::HTTPServerResponse & httpResponse) {

	SOAP::CommonSoapPreprocessing soapHandling(_grammarProvider);
	soapHandling.parse(httpRequest.stream());

	const auto soapAction(soapHandling.normalizedMessage->Header().Action().get());

	std::unique_ptr<SOAP::Command> command(new SOAP::SoapFaultCommand(httpResponse));

	if (soapAction == DPWS::GetMetadataTraits::RequestAction()) {
		const std::string serverAddress(httpRequest.serverAddress().toString());
		command = std::unique_ptr<SOAP::Command>(new SOAP::GetMetadataActionCommand(std::move(soapHandling.normalizedMessage), _service.getMetadata(serverAddress)));
	} else if (soapAction == GetMDIBTraits::RequestAction()) {
		command = std::unique_ptr<SOAP::Command>(new SOAP::GenericSoapActionCommand<GetMDIBTraits>(std::move(soapHandling.normalizedMessage), _service));
	} else if (soapAction == GetMDDescriptionTraits::RequestAction()) {
		command = std::unique_ptr<SOAP::Command>(new SOAP::GenericSoapActionCommand<GetMDDescriptionTraits>(std::move(soapHandling.normalizedMessage), _service));
	} else if (soapAction == GetMdStateTraits::RequestAction()) {
		command = std::unique_ptr<SOAP::Command>(new SOAP::GenericSoapActionCommand<GetMdStateTraits>(std::move(soapHandling.normalizedMessage), _service));
	} else {
		log_error([&] { return "GetServiceHandler can't handle action: " + soapAction; });
	}

	std::unique_ptr<MESSAGEMODEL::Envelope> responseMessage(command->Run());

	SOAP::SoapHTTPResponseWrapper response(httpResponse);
	response.send(SOAP::NormalizedMessageSerializer::serialize(*responseMessage));
}
Exemple #2
0
bool RESTHandler::build_message(Poco::Net::HTTPServerRequest &request, Poco::Net::HTMLForm &form, Poco::URI &url,
                                zmqpp::message &msg) {

    Json::Value root;
    bool ok = false;
    /// Find 'args' param in query or as POST body
    if (form.has("args")) {
        ok = reader.parse(form.get("args"), root);
    } else if (request.getMethod() == Poco::Net::HTTPRequest::HTTP_POST) {
        ok = reader.parse(request.stream(), root);
    }
    if (!ok || !root.isArray()) {
        return false;
    }
    if (verbose) {
        std::clog << "0\t" << url.getPath().substr(1) << std::endl;
    }
    /// Get service name as path without leading slash
    msg << url.getPath().substr(1);
    for (size_t i = 0; i < root.size(); ++i) {
        auto val = root.get(i, "");
        if (!verbose)
            msg << (val.isString() ? root.get(i, "").asString() : val.toStyledString());
        else {
            std::string s = (val.isString() ? root.get(i, "").asString() : val.toStyledString());
            msg << s;
            std::clog << (i + 1) << '\t' << s << std::endl;
        }
    }
    return true;
}
void EachNodeValue(Poco::Net::HTTPServerRequest &request, const F &f)
{
    if(!request.hasContentLength() || request.getContentLength()>1024*4) {
        return;
    }
    size_t size = (size_t)request.getContentLength();
    std::istream& stream = request.stream();
    std::string encoded_content;
    std::string content;
    encoded_content.resize(size);
    stream.read(&encoded_content[0], size);
    Poco::URI::decode(encoded_content, content);

    std::regex reg("(\\d+)");
    std::cmatch m;
    size_t pos = 0;
    for(;;) {
        if(std::regex_search(content.c_str()+pos, m, reg)) {
            f(m[1].str().c_str());
            pos += m.position()+m.length();
        }
        else {
            break;
        }
    }
}
Exemple #4
0
void TimeHandler::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{
    response.setChunkedTransferEncoding(true);
    response.setContentType("text/html");

    Poco::Net::HTMLForm form(request, request.stream());
    std::ostream& responseStream = response.send();
    responseStream << "";
    responseStream << "\n";
    responseStream << "";
    responseStream << "\n";
    responseStream << "\n";
    responseStream << "";
#line 6 "/ws/poco-1.3/PageCompiler/samples/HTTPTimeServer/src/TimeHandler.cpsp"

    Poco::DateTime now;
    std::string dt(Poco::DateTimeFormatter::format(now, "%W, %e %b %y %H:%M:%S %Z"));
    responseStream << "\n";
    responseStream << "<html>\n";
    responseStream << "<head>\n";
    responseStream << "<title>HTTPTimeServer powered by POCO C++ Libraries and PageCompiler</title>\n";
    responseStream << "<meta http-equiv=\"refresh\" content=\"1\">\n";
    responseStream << "</head>\n";
    responseStream << "<body>\n";
    responseStream << "<p style=\"text-align: center; font-size: 48px;\">";
#line 16 "/ws/poco-1.3/PageCompiler/samples/HTTPTimeServer/src/TimeHandler.cpsp"
    responseStream << ( dt );
    responseStream << "</p>\n";
    responseStream << "</body>\n";
    responseStream << "</html>\n";
    responseStream << "";
}
Exemple #5
0
			void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) {

				jsonrpc::handleRequest(response, [&](){

					HttpServerHelpers::ReturnType ret = HttpServerHelpers::preprocess(p, request, response);
					if (ret == HttpServerHelpers::RequestFinished){
						return;
					}

					std::string serviceName = request.getURI();

					std::cout << "servicename before: " << serviceName << std::endl;

					if (serviceName.find('/') == 0) {
						serviceName = serviceName.substr(1);
					}
					std::string::size_type question = serviceName.find('?');
					if (question != std::string::npos) {
						serviceName = serviceName.substr(0, question);
					}

					std::cout << "servicename after: " << serviceName << std::endl;

					for (auto i = p.getRequestHandlers().begin(); i != p.getRequestHandlers().end(); i++){
						if ((*i)->canHandle(serviceName)){
							std::cout << "SPECIAL HANDLING of " << serviceName << std::endl;
							(*i)->handle(request, response);
							return;
						}
					}

					//std::cout << "service name: " << serviceName << std::endl;

					std::istream& rs = request.stream();
					std::stringstream outstr;
					Poco::StreamCopier::copyStream(rs, outstr);
					std::string rsp;
					std::string req = outstr.str();

					//std::cout << "requset: " << req << std::endl;

					//this->handlerProvider.GetHandler()

					LTRACE("Json") << "request " << req << LE;

					if (auto sHandlerProvider = handlerProvider.lock()) {
						sHandlerProvider->getHandler(serviceName)->HandleRequest(req, rsp);
					} else {
						throw Poco::Exception("Request refused - server destroyed");
					}

					LTRACE("Json") << "response " << rsp << LE;
					//std::cout << "response: " << rsp << std::endl;

					response.setContentType("application/json");
					response.sendBuffer(rsp.data(), rsp.length());
				});
			}
Exemple #6
0
void PostHightScore::generateResponse(Poco::Net::HTTPServerRequest& inRequest,
                                      Poco::Net::HTTPServerResponse& outResponse)
{
    std::string requestBody;
    inRequest.stream() >> requestBody;

    Args args;
    GetArgs(requestBody, args);

    std::string name = URIDecode(GetArg(args, "name"));
    const std::string & score = GetArg(args, "score");

    Statement insert(getSession());
    insert << "INSERT INTO HighScores VALUES(NULL, strftime('%s', 'now'), ?, ?)", use(name), use(score);
    insert.execute();

    // Return an URL instead of a HTML page.
    // This is because the client is the JavaScript application in this case.
    std::string body = ResourceManager::Instance().getResourceLocation(GetResourceId());
    outResponse.setContentLength(body.size());
    outResponse.send() << body;
}
Exemple #7
0
void DeleteHighScore::generateResponse(Poco::Net::HTTPServerRequest& inRequest,
                                       Poco::Net::HTTPServerResponse& outResponse)
{
    std::string requestBody;
    inRequest.stream() >> requestBody;

    GetLogger().information("Request body is: " + requestBody);

    std::string sql = Poco::replace<std::string>("DELETE FROM HighScores WHERE {{args}}",
                                                 "{{args}}",
                                                 Args2String(GetArgs(requestBody)));

    GetLogger().information("SQL statement is: " + sql);

    Statement insert(getSession());
    insert << sql;
    insert.execute();

    // Return a message indicating success.
    std::string body = "Succesfully performed the following SQL statement: " + sql;
    outResponse.setContentLength(body.size());
    outResponse.send() << body;
}
void ContextEventSinkHandler::handleRequestImpl(Poco::Net::HTTPServerRequest & httpRequest, Poco::Net::HTTPServerResponse & httpResponse) {

	SOAP::CommonSoapPreprocessing soapHandling(_grammarProvider);
	soapHandling.parse(httpRequest.stream());

	const auto soapAction(soapHandling.normalizedMessage->Header().Action().get());

	std::unique_ptr<SOAP::Command> command(new SOAP::SoapFaultCommand(httpResponse));

	if (soapAction == EpisodicContextChangedReportTraits::Action()) {
		command = std::unique_ptr<SOAP::Command>(new SOAP::GenericSoapEventCommand<EpisodicContextChangedReportTraits>(std::move(soapHandling.normalizedMessage), _service));
	} else if (soapAction == PeriodicContextChangedReportTraits::Action()) {
		command = std::unique_ptr<SOAP::Command>(new SOAP::GenericSoapEventCommand<PeriodicContextChangedReportTraits>(std::move(soapHandling.normalizedMessage), _service));
	} else {
		log_error([&] { return "ContextEventSinkHandler can't handle action: " + soapAction; });
	}

	std::unique_ptr<MESSAGEMODEL::Envelope> responseMessage(command->Run());

	// todo add proper soap fault handling in response

	SOAP::SoapHTTPResponseWrapper response(httpResponse, SOAP::SoapHTTPResponseWrapper::HTTPStatus::HTTP_ACCEPTED);
	response.send("");
}
void chat::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{
	std::string nick;

	MyPartHandler partHandler;
	HTMLForm form(request, request.stream(), partHandler);

	response.setChunkedTransferEncoding(true);
	response.setContentType("text/html");

	if (!form.empty())
	{
		NameValueCollection::ConstIterator it;
		NameValueCollection::ConstIterator end;

		it = form.begin();
		end = form.end();
		for (; it != end; ++it)
		{
			if (it->first == "user")
				nick = it->second;
		}
	}

	std::ostream& responseStream = response.send();
	responseStream << "<!DOCTYPE html>\n";
	responseStream << "<html>\n";
	responseStream << "\t<head>\n";
	responseStream << "\t\t<link rel = \"stylesheet\" type = \"text/css\" href = \"styles.css\">\n";
	responseStream << "\t\t<title>Chat</title>\n";
	responseStream << "\t\t<script type = \"text/JavaScript\" src = \"jquery.js\"></script>\n";
	responseStream << "\t\t<script type = \"text/JavaScript\" src = \"jqueryui.js\"></script>\n";
	responseStream << "\t\t<script type = \"text/JavaScript\" src = \"script.js\"></script>\n";
	responseStream << "<script>\n";
	responseStream << "\tvar nick=\"" << nick << "\";\n";
	responseStream << "</script>\n";
	responseStream << "\t\t<link rel = \"stylesheet\" type = \"text/css\" href = \"jqueryuiss.css\">\n";
	responseStream << "\t</head>\n";
	responseStream << "\t<body>\n";
	responseStream << "\t\t<audio id=\"myAudio\">\n";
	responseStream << "\t\t\t<source src=\"newmessage.mp3\" type=\"audio/mpeg\">\n";
	responseStream << "\t\t\t<source src=\"newmessage.ogg\" type=\"audio/ogg\">\n";
	responseStream << "\t\t\tYour browser does not suport the audio tag\n";
	responseStream << "</audio>\n";
	responseStream << "\t\t<div id = \"FtHeader\">\n";
	responseStream << "\t\t\t<h1 align = \"center\"><img src = \"logo.jpg\" alt = \"some_text\"></h1>\n";
	responseStream << "\t\t</div>\n";
	responseStream << "\t\t<div id = \"chatTable2\">\n";
	responseStream << "\t\t\t<table align = \"center\">\n";
	responseStream << "\t\t\t\t<tr>\n";
	responseStream << "\t\t\t\t<td>\n";
	responseStream << "\t\t\t\t<div id=\"tabs\">\n";
	responseStream << "\t\t\t\t\t<ul>\n";
	responseStream << "\t\t\t\t\t\t<li><a href=\"#chatWindow\">Public</a></li>\n";
	responseStream << "\t\t\t\t\t\t<li><a href=\"#privateChatWindow\">Private</a></li>\n";
	responseStream << "\t\t\t\t\t</ul>\n";
	responseStream << "\t\t\t\t\t<div id = \"chatWindow\"></div>\n";
	responseStream << "\t\t\t\t\t<div id = \"privateChatWindow\"></div>\n";
	responseStream << "\t\t\t\t</div>\n";
	responseStream << "\t\t\t\t</td>\n";
	responseStream << "\t\t\t\t<td>\n";
	responseStream << "\t\t\t\t\t<div id = \"OnlineBox\">\n";
	responseStream << "\t\t\t\t\t</div>\n";
	responseStream << "\t\t\t\t</td>\n";
	responseStream << "\t\t\t\t</tr>\n";
	responseStream << "\t\t\t\t<tr>\n";
	responseStream << "\t\t\t\t<td>\n";
	responseStream << "\t\t\t\t\t<textarea maxlength = \"320\" id = \"TxTBox\" type = \"text\" style = \"resize:none\" name = \"TxTBox\" onkeypress = \"if(event.keyCode == 13){event.preventDefault(); sendMsgToServer();}\"></textarea>\n";
	responseStream << "\t\t\t\t</td>\n";
	responseStream << "\t\t\t\t<td>\n";
	responseStream << "\t\t\t\t\t<Button id = \"SendButton\" onclick = \"  sendMsgToServer();\"  onkeypress = \"if (event.keyCode == 13) {event.preventDefault(); sendMsgToServer(); }\">Send!</Button><br>\n";
	responseStream << "\t\t\t\t\t<form method=\"POST\" action=\"/\">\n";
	responseStream << "\t\t\t\t\t\t<input type=\"submit\" value=\"Logout\" id=\"LogoutButton\" onclick=\"loggingOut();\">\n";
	responseStream << "\t\t\t\t\t</form>\n";
	responseStream << "\t\t\t\t</td>\n";
	responseStream << "\t\t\t\t</tr>\n";
	responseStream << "\t\t\t</table>\n";
	responseStream << "\t\t</div>\n";
	responseStream << "\t</body>\n";
	responseStream << "</html>";
}
Exemple #10
0
void ODBCHandler::handleRequest(Poco::Net::HTTPServerRequest & request, Poco::Net::HTTPServerResponse & response)
{
    Poco::Net::HTMLForm params(request, request.stream());
    LOG_TRACE(log, "Request URI: " + request.getURI());

    auto process_error = [&response, this](const std::string & message)
    {
        response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
        if (!response.sent())
            response.send() << message << std::endl;
        LOG_WARNING(log, message);
    };

    if (!params.has("query"))
    {
        process_error("No 'query' in request body");
        return;
    }

    if (!params.has("columns"))
    {
        process_error("No 'columns' in request URL");
        return;
    }

    if (!params.has("connection_string"))
    {
        process_error("No 'connection_string' in request URL");
        return;
    }

    UInt64 max_block_size = DEFAULT_BLOCK_SIZE;
    if (params.has("max_block_size"))
    {
        std::string max_block_size_str = params.get("max_block_size", "");
        if (max_block_size_str.empty())
        {
            process_error("Empty max_block_size specified");
            return;
        }
        max_block_size = parse<size_t>(max_block_size_str);
    }

    std::string columns = params.get("columns");
    std::unique_ptr<Block> sample_block;
    try
    {
        sample_block = parseColumns(std::move(columns));
    }
    catch (const Exception & ex)
    {
        process_error("Invalid 'columns' parameter in request body '" + ex.message() + "'");
        LOG_WARNING(log, ex.getStackTrace().toString());
        return;
    }

    std::string format = params.get("format", "RowBinary");
    std::string query = params.get("query");
    LOG_TRACE(log, "Query: " << query);

    std::string connection_string = params.get("connection_string");
    LOG_TRACE(log, "Connection string: '" << connection_string << "'");

    WriteBufferFromHTTPServerResponse out(request, response, keep_alive_timeout);
    try
    {
        BlockOutputStreamPtr writer = FormatFactory::instance().getOutput(format, out, *sample_block, *context);
        auto pool = getPool(connection_string);
        ODBCBlockInputStream inp(pool->get(), query, *sample_block, max_block_size);
        copyData(inp, *writer);
    }
    catch (...)
    {
        auto message = getCurrentExceptionMessage(true);
        response.setStatusAndReason(
            Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR); // can't call process_error, bacause of too soon response sending
        writeStringBinary(message, out);
        tryLogCurrentException(log);
    }
}
Exemple #11
0
void HTTPHandler::processQuery(
    Poco::Net::HTTPServerRequest & request,
    HTMLForm & params,
    Poco::Net::HTTPServerResponse & response,
    Output & used_output)
{
    Context context = server.context();
    context.setGlobalContext(server.context());

    CurrentThread::QueryScope query_scope(context);

    LOG_TRACE(log, "Request URI: " << request.getURI());

    std::istream & istr = request.stream();

    /// Part of the query can be passed in the 'query' parameter and the rest in the request body
    /// (http method need not necessarily be POST). In this case the entire query consists of the
    /// contents of the 'query' parameter, a line break and the request body.
    std::string query_param = params.get("query", "");
    if (!query_param.empty())
        query_param += '\n';

    /// The user and password can be passed by headers (similar to X-Auth-*),
    /// which is used by load balancers to pass authentication information.
    std::string user = request.get("X-ClickHouse-User", "");
    std::string password = request.get("X-ClickHouse-Key", "");
    std::string quota_key = request.get("X-ClickHouse-Quota", "");

    if (user.empty() && password.empty() && quota_key.empty())
    {
        /// User name and password can be passed using query parameters
        /// or using HTTP Basic auth (both methods are insecure).
        if (request.hasCredentials())
        {
            Poco::Net::HTTPBasicCredentials credentials(request);

            user = credentials.getUsername();
            password = credentials.getPassword();
        }
        else
        {
            user = params.get("user", "default");
            password = params.get("password", "");
        }

        quota_key = params.get("quota_key", "");
    }
    else
    {
        /// It is prohibited to mix different authorization schemes.
        if (request.hasCredentials()
            || params.has("user")
            || params.has("password")
            || params.has("quota_key"))
        {
            throw Exception("Invalid authentication: it is not allowed to use X-ClickHouse HTTP headers and other authentication methods simultaneously", ErrorCodes::REQUIRED_PASSWORD);
        }
    }

    std::string query_id = params.get("query_id", "");
    context.setUser(user, password, request.clientAddress(), quota_key);
    context.setCurrentQueryId(query_id);

    /// The user could specify session identifier and session timeout.
    /// It allows to modify settings, create temporary tables and reuse them in subsequent requests.

    std::shared_ptr<Context> session;
    String session_id;
    std::chrono::steady_clock::duration session_timeout;
    bool session_is_set = params.has("session_id");
    const auto & config = server.config();

    if (session_is_set)
    {
        session_id = params.get("session_id");
        session_timeout = parseSessionTimeout(config, params);
        std::string session_check = params.get("session_check", "");

        session = context.acquireSession(session_id, session_timeout, session_check == "1");

        context = *session;
        context.setSessionContext(*session);
    }

    SCOPE_EXIT({
        if (session_is_set)
            session->releaseSession(session_id, session_timeout);
    });
Exemple #12
0
void Controller::handle(const std::vector<std::string>& parameters, Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{
	_parameters = parameters;
	_request = &request;
	_response = &response;

	if ( _parameters.size() > 0 )
	{
		_action = _parameters.front();
		_parameters.erase(_parameters.begin());
	}
	else
	{
		setResponseStatus(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST, "Invalid URI parameters");
		return;
	}

	for(std::vector<std::string>::iterator it = _parameters.begin(); it != _parameters.end(); ++it)
	{
		int pos = it->find_first_of(':');
		if ( pos != std::string::npos )
		{
			std::string name = it->substr(0, pos);
			std::string value = it->substr(pos+1);
			_namedParameters[name] = value;
		}
	}

	std::string contentType = request.getContentType();
	if ( contentType == "application/json" )
	{
		Poco::JSON::Parser parser;
		try
		{
			Poco::Dynamic::Var json = parser.parse(request.stream());
			if ( ! json.isEmpty() && json.type() == typeid(Poco::JSON::Object::Ptr) )
			{
				_data->set("filter", json.extract<Poco::JSON::Object::Ptr>());
			}
		}
		catch(Poco::JSON::JSONException& jsone)
		{
			// Make sure everything is read, otherwise this can result
			// in Bad Request error in the next call.
			Poco::NullOutputStream nos;
			Poco::StreamCopier::copyStream(request.stream(), nos);

			setResponseStatus(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST, "JSON error occurred: " + jsone.displayText());
			return;
		}
	}
	else
	{
		_form.load(request, request.stream(), *this);
	}

	// Make sure everything is read, otherwise this can result
	// in Bad Request error in the next call.
	Poco::NullOutputStream nos;
	Poco::StreamCopier::copyStream(request.stream(), nos);

	beforeAction();

	if ( response.getStatus() != Poco::Net::HTTPResponse::HTTP_OK
		|| _data->has("error") )
	{
		//TODO: return error template file or json error
	}

	const ActionMap& actions = getActions();
	ActionMap::const_iterator it = actions.find(_action);
	if ( it == actions.end() )
	{
		setResponseStatus(Poco::Net::HTTPResponse::HTTP_NOT_FOUND, "Invalid action '" + _action + "' specified.");
		return;
	}

	ActionFn action = it->second;
	(this->*action)();

	afterAction();
}
void ControllerRequestHandler::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{
	if (request.getURI() == "/favicon.ico")
	{
		return response.redirect("/images/favicon.ico", Poco::Net::HTTPResponse::HTTP_SEE_OTHER);
	}

	Poco::OSP::Web::WebSession::Ptr pSession = _pSessionManager->get(_sessionId, request, _sessionTimeout, context());

	const std::string loginPage = "/macchina/login";
	const std::string launcherPage = "/macchina/launcher";

	std::string message;
	std::string nextPage;
	std::string username;
	Poco::Net::HTMLForm form(request, request.stream());
	std::string action(form.get("action", ""));
	
	if (action == "login")
	{
		username = form.get("username", "");
		std::string password = form.get("password", "");
		if (_pAuthService->authenticate(username, password))
		{
			if (_logger.information())
			{
				_logger.information(format("User %s successfully logged in.", username));
			}
			nextPage = launcherPage;
			pSession->set("username", username);
		}
		else
		{
			if (_logger.warning())
			{
				_logger.warning(format("User %s failed authentication.", username));
			}
			message = "The given username is not known, the password is wrong or the account has been disabled.";
		}
	}
	else if (action == "logout")
	{
		username = pSession->getValue<std::string>("username", "");
		if (!username.empty())
		{
			if (_logger.information())
			{
				_logger.information(format("User %s logged out.", username));
			}
			_pSessionManager->remove(pSession);
		}
	}
	else
	{
		username = pSession->getValue<std::string>("username", "");
		if (!username.empty())
		{
			nextPage = launcherPage;
		}
	}
	
	if (!message.empty())
	{
		pSession->set("message", message);
	}
	else
	{
		pSession->erase("message");
	}
	
	if (nextPage.empty())
	{
		nextPage = loginPage;
	}
	response.setContentLength(0);
	response.redirect(nextPage, Poco::Net::HTTPResponse::HTTP_SEE_OTHER);
	response.set("Cache-Control", "no-cache");
}
void
RemoveByAttributesHandler::handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp)
{
    prepareApiResponse(resp);

    if (req.getMethod() != "POST") {
        resp.setStatus(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
        resp.setReason("Bad Request");

        Error error("Only POST requests are supported");

        std::ostream & out = resp.send();
        out << error;
        out.flush();
        return;
    }


    auto job = std::make_shared<Job>(Job::Type::REMOVE_BY_ATTRIBUTES);
    try {
        // read the whole request body into memory
        std::stringstream bodystream;
        bodystream << req.stream().rdbuf();

        // parse received json into the job object
        job->fromString( bodystream.str() );
    }
    catch (std::exception &e) {
        resp.setStatus(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
        resp.setReason("Bad Request");
        
        Error error(e.what());
        poco_warning(logger, e.what());

        std::ostream & out = resp.send();
        out << error;
        out.flush();
        return;
    }

    // return 404 if layer does not exist
    try {
        auto layer = configuration->getLayer(job->getLayerName());
    }
    catch (ConfigurationError) {
        // layer does not exist
        resp.setStatus(Poco::Net::HTTPResponse::HTTP_NOT_FOUND);
        resp.setReason("Not Found");
        
        std::stringstream msgstream;
        msgstream << "Layer \"" << job->getLayerName() << "\" does not exist";

        Error error(msgstream.str());
        poco_warning(logger, error.getMessage());

        std::ostream & out = resp.send();
        out << error;
        out.flush();
        return;
    }


    if (auto jobstorage = jobs.lock()) {
        poco_debug(logger, "pushing job to jobstorage");
        jobstorage->push(job);
    }
    else {
        resp.setStatus(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
        resp.setReason("Internal Server Error");
        
        const char * emsg = "Could not get a lock on jobstorage";
        Error error(emsg);
        poco_error(logger, emsg);

        std::ostream & out = resp.send();
        out << error;
        out.flush();
        return;
    }

    resp.setStatus(Poco::Net::HTTPResponse::HTTP_OK);
    std::ostream & out = resp.send();
    out << *job;
    out.flush();
};
	void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
	{
		//Poco::Util::Application& app = Poco::Util::Application::instance();
		//app.logger().information("Request from " + request.clientAddress().toString());
        std::cout << "Request from " << request.clientAddress().toString() << std::endl;

        MyPartHandler partHandler;
        Poco::Net::HTMLForm form(request, request.stream(), partHandler);

        std::string spinToken, sceneString, nodeString, args;
        std::istringstream pathstream(request.getURI());
        pathstream.get(); // ignore leading slash
        getline(pathstream, spinToken, '/');
        getline(pathstream, sceneString, '/');
        getline(pathstream, nodeString, '?');

        if (sceneString.empty()) sceneString = "default";
        //if (nodeString.empty()) nodeString = "shp";
        if (form.empty()) args = "createNode shp ShapeNode";
        else args = form["args"];

        response.setChunkedTransferEncoding(true);
        response.setContentType("text/html");

        std::ostream& ostr = response.send();

        ostr <<
        "<html>\n"
        "<head>\n"
        "<title>SPIN Web Service</title>\n"
        "</head>\n"
        "<body>\n"
        "<h1>SPIN Web Service</h1>\n"
        "<h3>Enter a SPIN command in the form below:</h3>\n"
        "<table><tr><td nowrap=\"nowrap\">\n"
        "<form name=\"urlForm\" method=\"GET\" action=\"null\">\n"
        "/SPIN/"
        "<input type=\"text\" name=\"sceneID\" value=\"" << sceneString << "\" size=\"10\">\n"
        "/<input type=\"text\" name=\"nodeID\" value=\"" << nodeString << "\" size=\"10\">"
        "</form></td>\n"
        "<td nowrap=\"nowrap\">\n"
        "<form name=\"spinform\" method=\"GET\" action=\"null\">\n"
        "<input type=\"text\" name=\"args\" value=\"" << args << "\" size=\"20\">\n"
        "<input type=\"submit\" value=\"GO\" onclick=\"this.form.action='/SPIN/'+document.forms['urlForm']['sceneID'].value+'/'+document.forms['urlForm']['nodeID'].value\">\n"
        "</form>\n"
        "</tr></table>\n"
        "<p>(NOTE: you can send scene messages by leaving the node name blank)</p>\n"
        "\n";
        /*
        ostr <<
            "<html>\n"
            "<head>\n"
            "<title>SPIN Web Server Sample</title>\n"
            "</head>\n"
            "<body>\n"
            "<h1>SPIN Web Server Sample</h1>\n"
            "<h2>Tests:</h2>\n"
            "<form name=\"spinform\" method=\"GET\" action=\"null\">\n"
            "/SPIN/default/"
            "<input type=\"text\" name=\"nodeID\" value=\"shp\" size=\"15\">"
            "&nbsp;&nbsp;&nbsp;"
            "<input type=\"text\" name=\"method\" value=\"rotate\" size=\"15\">"
            " move<input type=\"text\" name=\"x\" value=\"0\" size=\"3\">"
            " <input type=\"text\" name=\"y\" value=\"0\" size=\"3\">"
            " <input type=\"text\" name=\"z\" value=\"10\" size=\"3\">\n"
            " <input type=\"submit\" value=\"GO\" onclick=\"this.form.action='/SPIN/default/'+this.form.nodeID.value\">\n"
            "</form>\n"
            "\n";
        ostr <<
            "<html>\n"
            "<head>\n"
            "<title>SPIN Web Server Sample</title>\n"
            "</head>\n"
            "<body>\n"
            "<h1>SPIN Web Server Sample</h1>\n"
            "<h2>GET Form</h2>\n"
            "<form method=\"GET\" action=\"/form\">\n"
            "<input type=\"text\" name=\"text\" size=\"31\">\n"
            "<input type=\"submit\" value=\"GET\">\n"
            "</form>\n"
            "<h2>POST Form</h2>\n"
            "<form method=\"POST\" action=\"/form\">\n"
            "<input type=\"text\" name=\"text\" size=\"31\">\n"
            "<input type=\"submit\" value=\"POST\">\n"
            "</form>\n"
            "<h2>File Upload</h2>\n"
            "<form method=\"POST\" action=\"/form\" enctype=\"multipart/form-data\">\n"
            "<input type=\"file\" name=\"file\" size=\"31\"> \n"
            "<input type=\"submit\" value=\"Upload\">\n"
            "</form>\n";
            */

        ostr << "<h2>Result</h2><p>\n";
        ostr << "Method: " << request.getMethod() << "<br>\n";
        ostr << "URI: " << request.getURI() << "<br>\n";
        Poco::Net::NameValueCollection::ConstIterator it = request.begin();
        Poco::Net::NameValueCollection::ConstIterator end = request.end();
        for (; it != end; ++it)
        {
            ostr << it->first << ": " << it->second << "<br>\n";
        }
        ostr << "</p>";
        /*
        if (!form.empty())
        {
            ostr << "<h2>Result</h2><p>\n";
            it = form.begin();
            end = form.end();
            for (; it != end; ++it)
            {
                ostr << it->first << ": " << it->second << "<br>\n";
            }
            ostr << "</p>";
        }
        */

        // --------parse

        introspect_invoke(request.getURI(), form);

        // ---------------

        if (!partHandler.name().empty())
        {
            ostr << "<h2>Upload</h2><p>\n";
            ostr << "Name: " << partHandler.name() << "<br>\n";
            ostr << "File Name: " << partHandler.fileName() << "<br>\n";
            ostr << "Type: " << partHandler.contentType() << "<br>\n";
            ostr << "Size: " << partHandler.length() << "<br>\n";
            ostr << "</p>";
        }
        ostr << "</body>\n";
    }