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; }
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; }
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(); };
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(); }
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); });