Esempio n. 1
0
bool WebSocketRoute::canHandleRequest(const Poco::Net::HTTPServerRequest& request,
                                      bool isSecurePort) const
{
    if(!BaseRoute_<WebSocketRouteSettings>::canHandleRequest(request, isSecurePort))
    {
        return false;
    }

    // check to see if this is an websocket upgrade request
    if(Poco::icompare(request.get("Upgrade", ""), "websocket")  != 0)
    {
        return false;
    }

    // TODO: firefox hack
    // require websocket upgrade headers
    // this is all fixed in Poco 1.4.6 and 1.5.+
    std::string connectionHeader = Poco::toLower(request.get("Connection", ""));

    if(Poco::icompare(connectionHeader, "Upgrade") != 0 &&
       !ofIsStringInString(connectionHeader, "upgrade"))
    {
        // this request is coming from firefox, which is known to send things that look like:
        // Connection:keep-alive, Upgrade
        // thus failing the standard Poco upgrade test.
        // we can't do this here, but will do a similar hack in the handler
        return false;
    }
    
    return true;
}
Esempio n. 2
0
bool Utility::isAuthenticated(Poco::OSP::Web::WebSession::Ptr pSession, const Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{
	if (!pSession || !pSession->has("username") || request.get("X-XSRF-TOKEN", "") != pSession->csrfToken())
	{
		response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_UNAUTHORIZED);
		response.setContentLength(0);
		response.setChunkedTransferEncoding(false);
		response.send();
		return false;
	}
	return true;
}
Esempio n. 3
0
void
BufferHandler::handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp)
{
    prepareResponse(resp);
    resp.set("ETag", etag);
    resp.set("Cache-Control", "max-age=300, private");

    if (req.get("If-None-Match", "") == etag) {
        // ETag matched. No content to send;
        resp.setStatus(Poco::Net::HTTPResponse::HTTP_NOT_MODIFIED);
        resp.setReason("Not Modified");

        resp.send().flush();
        return;
    }

    resp.setStatus(Poco::Net::HTTPResponse::HTTP_OK);
    resp.setContentType(contentType);
    resp.setContentLength(bufferLen);

    std::ostream & out = resp.send();
    out.write(reinterpret_cast<const char*>(buffer), bufferLen);
    out.flush();
};
Esempio n. 4
0
void AppRequestHandler::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{
	// Check for the favicon.ico request, we don't have one for now,
	// so set status code to HTTP_NOT_FOUND
	if ( request.getURI().compare("/favicon.ico") == 0 )
	{
		response.setStatus(Poco::Net::HTTPResponse::HTTP_NOT_FOUND);
		response.send();
		return;
	}

	std::string lastModifiedHeader = request.get("If-Modified-Since", "");

	Poco::URI uri(request.getURI());

	Poco::Util::Application& app = Poco::Util::Application::instance();
	std::string staticPathname = app.config().getString("mq.web.app", "");
	if ( staticPathname.empty() )
	{
		Poco::Logger& logger = Poco::Logger::get("mq.web");
		logger.error("mq.web.app property not defined. Check your configuration.");
		response.setStatus(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
		response.send();
		return;
	}

	Poco::Path staticPath(staticPathname);
	staticPath.makeDirectory();

	std::vector<std::string> uriPathSegments;
	uri.getPathSegments(uriPathSegments);
	std::vector<std::string>::iterator it = uriPathSegments.begin();
	it++;
	for(; it != uriPathSegments.end(); ++it)
	{
		staticPath.append(*it);
	}
	if (staticPath.isDirectory())
	{
		staticPath.append("index.html");
	}

	Poco::File staticFile(staticPath);

	Poco::Logger& logger = Poco::Logger::get("mq.web.access");
	if ( staticFile.exists() )
	{
		if ( !lastModifiedHeader.empty() )
		{
			Poco::DateTime lastModifiedDate;
			int timeZoneDifferential = 0;
			if ( Poco::DateTimeParser::tryParse(Poco::DateTimeFormat::HTTP_FORMAT, lastModifiedHeader, lastModifiedDate, timeZoneDifferential) )
			{
				if ( staticFile.getLastModified() <= lastModifiedDate.timestamp() )
				{
					logger.information(Poco::Logger::format("$0 : HTTP_NOT_MODIFIED", staticPath.toString()));
					response.setStatus(Poco::Net::HTTPResponse::HTTP_NOT_MODIFIED);
					response.send();
					return;
				}
			}
		}

		logger.information(Poco::Logger::format("$0 : HTTP_OK", staticPath.toString()));

		std::string mimeType;
		if ( staticPath.getExtension().compare("gif") == 0 )
		{
			mimeType = "image/gif";
		}
		else if ( staticPath.getExtension().compare("css") == 0 )
		{
			mimeType = "text/css";
		}
		else if ( staticPath.getExtension().compare("html") == 0 || staticPath.getExtension().compare("htm") == 0)
		{
			mimeType = "text/html";
		}
		else if ( staticPath.getExtension().compare("js") == 0 )
		{
			mimeType = "text/javascript";
		}
		else if ( staticPath.getExtension().compare("png") == 0 )
		{
			mimeType = "image/png";
		}
		else if ( staticPath.getExtension().compare("jpg") == 0 || staticPath.getExtension().compare("jpeg") == 0)
		{
			mimeType = "image/jpeg";
		}

		try
		{
			response.sendFile(staticPath.toString(), mimeType);
		}
		catch(Poco::FileNotFoundException&)
		{
			// We can't get here normally ... but you never know :)
			response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_NOT_FOUND, Poco::Logger::format("Can't find file $0", staticPath.toString()));
		}
		catch(Poco::OpenFileException&)
		{
			response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR, Poco::Logger::format("Can't open file $0", staticPath.toString()));
		}
		return;
	}

	logger.error(Poco::Logger::format("$0 : HTTP_NOT_FOUND", staticFile.path()));
	response.setStatus(Poco::Net::HTTPResponse::HTTP_NOT_FOUND);
	response.send();
}
Esempio n. 5
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);
    });