Пример #1
0
void HTMLForm::load(const HTTPRequest& request, std::istream& requestBody, PartHandler& handler)
{
	clear();

	URI uri(request.getURI());
	const std::string& query = uri.getRawQuery();
	if (!query.empty())
	{
		std::istringstream istr(query);
		readUrl(istr);
	}

	if (request.getMethod() == HTTPRequest::HTTP_POST || request.getMethod() == HTTPRequest::HTTP_PUT)
	{
		std::string mediaType;
		NameValueCollection params;
		MessageHeader::splitParameters(request.getContentType(), mediaType, params); 
		_encoding = mediaType;
		if (_encoding == ENCODING_MULTIPART)
		{
			_boundary = params["boundary"];
			readMultipart(requestBody, handler);
		}
		else
		{
			readUrl(requestBody);
		}
	}
}
Пример #2
0
void HTTPDigestCredentials::updateAuthParams(const HTTPRequest& request)
{
	MD5Engine engine;
	const std::string& qop = _requestAuthParams.get(QOP_PARAM, DEFAULT_QOP);
	const std::string& realm = _requestAuthParams.getRealm();
	const std::string& nonce = _requestAuthParams.get(NONCE_PARAM);

	_requestAuthParams.set(URI_PARAM, request.getURI());

	if (qop.empty())
	{
		const std::string ha1 = digest(engine, _username, realm, _password);
		const std::string ha2 = digest(engine, request.getMethod(), request.getURI());

		_requestAuthParams.set(RESPONSE_PARAM, digest(engine, ha1, nonce, ha2));
	}
	else if (icompare(qop, AUTH_PARAM) == 0) 
	{
		const std::string& cnonce = _requestAuthParams.get(CNONCE_PARAM);

		const std::string ha1 = digest(engine, _username, realm, _password);
		const std::string ha2 = digest(engine, request.getMethod(), request.getURI());
		const std::string nc = formatNonceCounter(updateNonceCounter(nonce));

		_requestAuthParams.set(NC_PARAM, nc);
		_requestAuthParams.set(RESPONSE_PARAM, digest(engine, ha1, nonce, nc, cnonce, qop, ha2));
	}
}
Пример #3
0
HTTPServer::HTTPServer(const std::string &addr, const std::string &port, int maxClientsCount,
                       std::function<HTTPResponse(HTTPRequest &request)> onGet,
                       std::function<HTTPResponse(HTTPRequest &request)> onPost,
                       EpollHandler &epoll) {
    std::function<void(TCPSocket &)> onAccept = [&onGet, &onPost, this](TCPSocket &sock) {
        const int BUF_MAX_SIZE = 4096;
        char buf[BUF_MAX_SIZE];

        int len;
        while (true) {
            len = sock.recieveMsg(buf, BUF_MAX_SIZE);
            if (len <= 0) break;
            addBufToString(currentRequest[sock.sockfd], buf, len);
        }
        std::cerr << " ======\n" << currentRequest[sock.sockfd] << "\n===========\n";
        HTTPRequest httpRequest;
        HTTPResponse httpResponse;
        try {
            //std::cout << currentRequest << "\n";
            httpRequest = HTTPRequest(currentRequest[sock.sockfd]);

            //std::cout << "Request from soket " << sock.sockfd << ": " << currentRequest << "\n";
            if (httpRequest.getMethod() == "GET") {
                httpResponse = onGet(httpRequest);
            } else if (httpRequest.getMethod() == "POST") {
                httpResponse = onPost(httpRequest);
            }
            std::cout << "Response for socket " << sock.sockfd << ": \n";
            sock.sendMsg(httpResponse.buildResponse().c_str());
            currentRequest[sock.sockfd] = "";
        } catch (NotFullRequestException &e) {
            std::cerr << "Not full request: " << e.getMessage() << "\n";
        } catch (HTTPException &e) {
            std::cerr << "Bad HTTP Request: " << e.getMessage() << "\n";

            httpResponse.setHttpVersion("HTTP/1.1");
            httpResponse.setStatusCode(400);
            httpResponse.setReasonPhrase("Bad Request");
            httpResponse.addEntityHeader("Content-Type", "*/*");

            std::cout << "Response for socket " << sock.sockfd << ": \n";
            sock.sendMsg(httpResponse.buildResponse().c_str());
            currentRequest[sock.sockfd] = "";
        }


    };
    tcpServer = new TCPServer(addr.c_str(), port.c_str(), maxClientsCount * 2, onAccept, epoll);
}
Пример #4
0
CGIParser::CGIParser(const HTTPRequest& request, bool queryOnly)
{
    parse(request.getQueryString());
    if (!queryOnly && !strcmp(request.getMethod(),"POST")) {
        if (request.getContentType().find("application/x-www-form-urlencoded") != string::npos)
            parse(request.getRequestBody());
    }
}
Пример #5
0
void HTMLForm::prepareSubmit(HTTPRequest& request)
{
	if (request.getMethod() == HTTPRequest::HTTP_POST || request.getMethod() == HTTPRequest::HTTP_PUT)
	{
		if (_encoding == ENCODING_URL)
		{
			request.setContentType(_encoding);
			request.setChunkedTransferEncoding(false);
			Poco::CountingOutputStream ostr;
			writeUrl(ostr);
			request.setContentLength(ostr.chars());
		}
		else
		{
			_boundary = MultipartWriter::createBoundary();
			std::string ct(_encoding);
			ct.append("; boundary=\"");
			ct.append(_boundary);
			ct.append("\"");
			request.setContentType(ct);
		}
		if (request.getVersion() == HTTPMessage::HTTP_1_0)
		{
			request.setKeepAlive(false);
			request.setChunkedTransferEncoding(false);
		}
		else if (_encoding != ENCODING_URL)
		{
			request.setChunkedTransferEncoding(true);
		}
	}
	else
	{
		std::string uri = request.getURI();
		std::ostringstream ostr;
		writeUrl(ostr);
		uri.append("?");
		uri.append(ostr.str());
		request.setURI(uri);
	}
}
Пример #6
0
void HTTPRequestTest::testRead1()
{
	std::string s("GET / HTTP/1.0\r\n\r\n");
	std::istringstream istr(s);
	HTTPRequest request;
	request.read(istr);
	assert (request.getMethod() == HTTPRequest::HTTP_GET);
	assert (request.getURI() == "/");
	assert (request.getVersion() == HTTPMessage::HTTP_1_0);
	assert (request.empty());
	assert (istr.get() == -1);
}
Пример #7
0
TEST(HTTPRequest, testRead1)
{
	std::string s("GET / HTTP/1.0\r\n\r\n");
	std::istringstream istr(s);
	HTTPRequest request;
	request.read(istr);
	EXPECT_TRUE (request.getMethod() == HTTPRequest::HTTP_GET);
	EXPECT_TRUE (request.getURI() == "/");
	EXPECT_TRUE (request.getVersion() == HTTPMessage::HTTP_1_0);
	EXPECT_TRUE (request.empty());
	EXPECT_TRUE (istr.get() == -1);
}
Пример #8
0
bool HTTPDigestCredentials::verifyAuthParams(const HTTPRequest& request, const HTTPAuthenticationParams& params) const
{
	const std::string& nonce = params.get(NONCE_PARAM);
	const std::string& realm = params.getRealm();
	const std::string& qop   = params.get(QOP_PARAM, DEFAULT_QOP);
	std::string response;
	MD5Engine engine;
	if (qop.empty())
	{
		const std::string ha1 = digest(engine, _username, realm, _password);
		const std::string ha2 = digest(engine, request.getMethod(), request.getURI());
		response = digest(engine, ha1, nonce, ha2);
	}
	else if (icompare(qop, AUTH_PARAM) == 0) 
	{
		const std::string& cnonce = params.get(CNONCE_PARAM);
		const std::string& nc = params.get(NC_PARAM);
		const std::string ha1 = digest(engine, _username, realm, _password);
		const std::string ha2 = digest(engine, request.getMethod(), request.getURI());
		response = digest(engine, ha1, nonce, nc, cnonce, qop, ha2);
	}
	return response == params.get(RESPONSE_PARAM);
}
Пример #9
0
void HTTPRequestTest::testRead2()
{
	std::string s("HEAD /index.html HTTP/1.1\r\nConnection: Keep-Alive\r\nHost: localhost\r\nUser-Agent: Poco\r\n\r\n");
	std::istringstream istr(s);
	HTTPRequest request;
	request.read(istr);
	assert (request.getMethod() == HTTPRequest::HTTP_HEAD);
	assert (request.getURI() == "/index.html");
	assert (request.getVersion() == HTTPMessage::HTTP_1_1);
	assert (request.size() == 3);
	assert (request["Connection"] == "Keep-Alive");
	assert (request["Host"] == "localhost");
	assert (request["User-Agent"] == "Poco");
	assert (istr.get() == -1);
}
Пример #10
0
std::string OAuth::createSignatureBaseString(HTTPRequest& r) {
  HTTPURL url = r.getURL();
  std::string method = (r.getMethod() == HTTP_METHOD_POST) ? "POST" : "GET";

  // Get the percent encoded parameters
  HTTPParameters collected_parameters = collectParameters(r);
  collected_parameters.percentEncode();

  // We need to encode the parameter string (again)
  PercentEncode encoder;
  std::string parameter_string = collected_parameters.getQueryString();
  std::string normalized_url = createNormalizedURL(r.getURL());
  std::string signature_string = method +"&" +encoder.encode(normalized_url) +"&" +encoder.encode(parameter_string);

  return signature_string;
}
Пример #11
0
void HTTPRequestTest::testRead4()
{
	std::string s("POST /test.cgi HTTP/1.1\r\nConnection: Close\r\nContent-Length:   100  \r\nContent-Type: text/plain\r\nHost: localhost:8000\r\nUser-Agent: Poco\r\n\r\n");
	std::istringstream istr(s);
	HTTPRequest request;
	request.read(istr);
	assert (request.getMethod() == HTTPRequest::HTTP_POST);
	assert (request.getURI() == "/test.cgi");
	assert (request.getVersion() == HTTPMessage::HTTP_1_1);
	assert (request.size() == 5);
	assert (request["Connection"] == "Close");
	assert (request["Host"] == "localhost:8000");
	assert (request["User-Agent"] == "Poco");
	assert (request.getContentType() == "text/plain");
	assert (request.getContentLength() == 100);
	assert (istr.get() == -1);
}
Пример #12
0
CGIParser::CGIParser(const HTTPRequest& request)
{
    const char* pch=NULL;
    if (!strcmp(request.getMethod(),"POST"))
        pch=request.getRequestBody();
    else
        pch=request.getQueryString();
    size_t cl=pch ? strlen(pch) : 0;
    
    const URLEncoder* dec = XMLToolingConfig::getConfig().getURLEncoder();
    while (cl && pch) {
        char *name;
        char *value;
        value=fmakeword('&',&cl,&pch);
        plustospace(value);
        dec->decode(value);
        name=makeword(value,'=');
        kvp_map.insert(pair<const string,char*>(name,value));
        free(name);
    }
}
Пример #13
0
void AbstractHandler::preservePostData(
    const Application& application, const HTTPRequest& request, HTTPResponse& response, const char* relayState
    ) const
{
#ifdef HAVE_STRCASECMP
    if (strcasecmp(request.getMethod(), "POST")) return;
#else
    if (stricmp(request.getMethod(), "POST")) return;
#endif

    // No specs mean no save.
    const PropertySet* props=application.getPropertySet("Sessions");
    pair<bool,const char*> mech = props->getString("postData");
    if (!mech.first) {
        m_log.info("postData property not supplied, form data will not be preserved across SSO");
        return;
    }

    DDF postData = getPostData(application, request);
    if (postData.isnull())
        return;

    if (strstr(mech.second,"ss:") == mech.second) {
        mech.second+=3;
        if (!*mech.second) {
            postData.destroy();
            throw ConfigurationException("Unsupported postData mechanism ($1).", params(1, mech.second - 3));
        }

        string postkey;
        if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
            DDFJanitor postjan(postData);
#ifndef SHIBSP_LITE
            StorageService* storage = application.getServiceProvider().getStorageService(mech.second);
            if (storage) {
                // Use a random key
                string rsKey;
                SAMLConfig::getConfig().generateRandomBytes(rsKey,20);
                rsKey = SAMLArtifact::toHex(rsKey);
                ostringstream out;
                out << postData;
                if (!storage->createString("PostData", rsKey.c_str(), out.str().c_str(), time(NULL) + 600))
                    throw IOException("Attempted to insert duplicate storage key.");
                postkey = string(mech.second-3) + ':' + rsKey;
            }
            else {
                m_log.error("storage-backed PostData mechanism with invalid StorageService ID (%s)", mech.second);
            }
#endif
        }
        else if (SPConfig::getConfig().isEnabled(SPConfig::InProcess)) {
            DDF out,in = DDF("set::PostData").structure();
            DDFJanitor jin(in),jout(out);
            in.addmember("id").string(mech.second);
            in.add(postData);
            out = application.getServiceProvider().getListenerService()->send(in);
            if (!out.isstring())
                throw IOException("StorageService-backed PostData mechanism did not return a state key.");
            postkey = string(mech.second-3) + ':' + out.string();
        }

        // Set a cookie with key info.
        pair<string,const char*> shib_cookie = getPostCookieNameProps(application, relayState);
        postkey += shib_cookie.second;
        response.setCookie(shib_cookie.first.c_str(), postkey.c_str());
    }
    else {
        postData.destroy();
        throw ConfigurationException("Unsupported postData mechanism ($1).", params(1,mech.second));
    }
}
Пример #14
0
void FileServerRequestHandler::handleRequest(const HTTPRequest& request, Poco::MemoryInputStream& message,
                                             const std::shared_ptr<StreamSocket>& socket)
{
    try
    {
        bool noCache = false;
#if ENABLE_DEBUG
        noCache = true;
#endif
        Poco::Net::HTTPResponse response;
        Poco::URI requestUri(request.getURI());
        LOG_TRC("Fileserver request: " << requestUri.toString());
        requestUri.normalize(); // avoid .'s and ..'s

        std::string path(requestUri.getPath());
        if (path.find("loleaflet/" LOOLWSD_VERSION_HASH "/") == std::string::npos)
        {
            LOG_WRN("client - server version mismatch, disabling browser cache.");
            noCache = true;
        }

        std::vector<std::string> requestSegments;
        requestUri.getPathSegments(requestSegments);
        const std::string relPath = getRequestPathname(request);
        // Is this a file we read at startup - if not; its not for serving.
        if (requestSegments.size() < 1 || FileHash.find(relPath) == FileHash.end())
            throw Poco::FileNotFoundException("Invalid URI request: [" + requestUri.toString() + "].");

        const auto& config = Application::instance().config();
        const std::string loleafletHtml = config.getString("loleaflet_html", "loleaflet.html");
        const std::string endPoint = requestSegments[requestSegments.size() - 1];
        if (endPoint == loleafletHtml)
        {
            preprocessFile(request, message, socket);
            return;
        }

        if (request.getMethod() == HTTPRequest::HTTP_GET)
        {
            if (endPoint == "admin.html" ||
                endPoint == "adminSettings.html" ||
                endPoint == "adminHistory.html" ||
                endPoint == "adminAnalytics.html")
            {
                preprocessAdminFile(request, socket);
                return;
            }

            if (endPoint == "admin-bundle.js" ||
                endPoint == "admin-localizations.js")
            {
                noCache = true;

                if (!LOOLWSD::AdminEnabled)
                    throw Poco::FileAccessDeniedException("Admin console disabled");

                if (!FileServerRequestHandler::isAdminLoggedIn(request, response))
                    throw Poco::Net::NotAuthenticatedException("Invalid admin login");

                // Ask UAs to block if they detect any XSS attempt
                response.add("X-XSS-Protection", "1; mode=block");
                // No referrer-policy
                response.add("Referrer-Policy", "no-referrer");
            }

            // Do we have an extension.
            const std::size_t extPoint = endPoint.find_last_of('.');
            if (extPoint == std::string::npos)
                throw Poco::FileNotFoundException("Invalid file.");

            const std::string fileType = endPoint.substr(extPoint + 1);
            std::string mimeType;
            if (fileType == "js")
                mimeType = "application/javascript";
            else if (fileType == "css")
                mimeType = "text/css";
            else if (fileType == "html")
                mimeType = "text/html";
            else if (fileType == "png")
                mimeType = "image/png";
            else if (fileType == "svg")
                mimeType = "image/svg+xml";
            else
                mimeType = "text/plain";

            auto it = request.find("If-None-Match");
            if (it != request.end())
            {
                // if ETags match avoid re-sending the file.
                if (!noCache && it->second == "\"" LOOLWSD_VERSION_HASH "\"")
                {
                    // TESTME: harder ... - do we even want ETag support ?
                    std::ostringstream oss;
                    Poco::DateTime now;
                    Poco::DateTime later(now.utcTime(), int64_t(1000)*1000 * 60 * 60 * 24 * 128);
                    oss << "HTTP/1.1 304 Not Modified\r\n"
                        << "Date: " << Poco::DateTimeFormatter::format(
                            now, Poco::DateTimeFormat::HTTP_FORMAT) << "\r\n"
                        << "Expires: " << Poco::DateTimeFormatter::format(
                            later, Poco::DateTimeFormat::HTTP_FORMAT) << "\r\n"
                        << "User-Agent: " << WOPI_AGENT_STRING << "\r\n"
                        << "Cache-Control: max-age=11059200\r\n"
                        << "\r\n";
                    socket->send(oss.str());
                    socket->shutdown();
                    return;
                }
            }

            response.set("User-Agent", HTTP_AGENT_STRING);
            response.set("Date", Poco::DateTimeFormatter::format(Poco::Timestamp(), Poco::DateTimeFormat::HTTP_FORMAT));

            bool gzip = request.hasToken("Accept-Encoding", "gzip");
            const std::string *content;
#if ENABLE_DEBUG
            if (std::getenv("LOOL_SERVE_FROM_FS"))
            {
                // Useful to not serve from memory sometimes especially during loleaflet development
                // Avoids having to restart loolwsd everytime you make a change in loleaflet
                const std::string filePath = Poco::Path(LOOLWSD::FileServerRoot, relPath).absolute().toString();
                HttpHelper::sendFile(socket, filePath, mimeType, response, noCache);
                return;
            }
#endif
            if (gzip)
            {
                response.set("Content-Encoding", "gzip");
                content = getCompressedFile(relPath);
            }
            else
                content = getUncompressedFile(relPath);

            if (!noCache)
            {
                // 60 * 60 * 24 * 128 (days) = 11059200
                response.set("Cache-Control", "max-age=11059200");
                response.set("ETag", "\"" LOOLWSD_VERSION_HASH "\"");
            }
            response.setContentType(mimeType);
            response.add("X-Content-Type-Options", "nosniff");

            std::ostringstream oss;
            response.write(oss);
            const std::string header = oss.str();
            LOG_TRC("#" << socket->getFD() << ": Sending " <<
                    (!gzip ? "un":"") << "compressed : file [" << relPath << "]: " << header);
            socket->send(header);
            socket->send(*content);
        }
    }
    catch (const Poco::Net::NotAuthenticatedException& exc)
    {
        LOG_ERR("FileServerRequestHandler::NotAuthenticated: " << exc.displayText());
        sendError(401, request, socket, "", "", "WWW-authenticate: Basic realm=\"online\"\r\n");
    }
    catch (const Poco::FileAccessDeniedException& exc)
    {
        LOG_ERR("FileServerRequestHandler: " << exc.displayText());
        sendError(403, request, socket, "403 - Access denied!",
                  "You are unable to access");
    }
    catch (const Poco::FileNotFoundException& exc)
    {
        LOG_WRN("FileServerRequestHandler: " << exc.displayText());
        sendError(404, request, socket, "404 - file not found!",
                  "There seems to be a problem locating");
    }
}