qint64 TActionContext::writeResponse(int statusCode, THttpResponseHeader &header, const QByteArray &contentType, QIODevice *body, qint64 length) { T_TRACEFUNC("statusCode:%d contentType:%s length:%s", statusCode, contentType.data(), qPrintable(QString::number(length))); header.setStatusLine(statusCode, THttpUtility::getResponseReasonPhrase(statusCode)); if (!contentType.isEmpty()) header.setContentType(contentType); return writeResponse(header, body, length); }
qint64 TActionContext::writeResponse(THttpResponseHeader &header, QIODevice *body, qint64 length) { T_TRACEFUNC("length:%s", qPrintable(QString::number(length))); header.setContentLength(length); header.setRawHeader("Server", "TreeFrog server"); header.setCurrentDate(); // Write data return writeResponse(header, body); }
qint64 TActionContext::writeResponse(THttpResponseHeader& header, QIODevice *body, qint64 length) { T_TRACEFUNC("length:%s", qPrintable(QString::number(length))); qint64 res = -1; if (httpSocket) { header.setContentLength(length); header.setRawHeader("Server", "TreeFrog server"); header.setRawHeader("Date", QLocale::c().toString(QDateTime::currentDateTime().toUTC(), QLatin1String("ddd, dd MMM yyyy hh:mm:ss 'GMT'")).toLatin1()); header.setRawHeader("Connection", "close"); res = httpSocket->write(static_cast<THttpHeader*>(&header), body); } return res; }
qint64 TActionContext::writeResponse(THttpResponseHeader &header, QIODevice *body, qint64 length) { T_TRACEFUNC("length:%s", qPrintable(QString::number(length))); header.setContentLength(length); header.setRawHeader("Server", "TreeFrog server"); # if QT_VERSION >= 0x040700 QDateTime utc = QDateTime::currentDateTimeUtc(); #else QDateTime utc = QDateTime::currentDateTime().toUTC(); #endif header.setRawHeader("Date", QLocale(QLocale::C).toString(utc, QLatin1String("ddd, dd MMM yyyy hh:mm:ss 'GMT'")).toLatin1()); // Write data return writeResponse(header, body); }
qint64 TActionWorker::writeResponse(THttpResponseHeader &header, QIODevice *body) { header.setRawHeader("Connection", "Keep-Alive"); accessLogger.setStatusCode(header.statusCode()); // Check auto-remove bool autoRemove = false; QFile *f = qobject_cast<QFile *>(body); if (f) { QString filePath = f->fileName(); if (TActionContext::autoRemoveFiles.contains(filePath)) { TActionContext::autoRemoveFiles.removeAll(filePath); autoRemove = true; // To remove after sent } } if (!TActionContext::stopped) { TEpollSocket::setSendData(socketId, static_cast<THttpHeader*>(&header), body, autoRemove, accessLogger); } accessLogger.close(); // not write in this thread return 0; }
void TAbstractWebSocket::sendHandshakeResponse() { THttpResponseHeader response; response.setStatusLine(Tf::SwitchingProtocols, THttpUtility::getResponseReasonPhrase(Tf::SwitchingProtocols)); response.setRawHeader("Upgrade", "websocket"); response.setRawHeader("Connection", "Upgrade"); QByteArray secAccept = QCryptographicHash::hash(reqHeader.rawHeader("Sec-WebSocket-Key").trimmed() + saltToken, QCryptographicHash::Sha1).toBase64(); response.setRawHeader("Sec-WebSocket-Accept", secAccept); writeRawData(response.toByteArray()); }
void TActionContext::execute() { T_TRACEFUNC(""); THttpResponseHeader responseHeader; accessLogger.open(); try { if (!readRequest()) { return; } const THttpRequestHeader &hdr = httpReq->header(); // Access log accessLogger.setTimestamp(QDateTime::currentDateTime()); QByteArray firstLine = hdr.method() + ' ' + hdr.path(); firstLine += QString(" HTTP/%1.%2").arg(hdr.majorVersion()).arg(hdr.minorVersion()).toLatin1(); accessLogger.setRequest(firstLine); accessLogger.setRemoteHost( (Tf::app()->appSettings().value(LISTEN_PORT).toUInt() > 0) ? clientAddress().toString().toLatin1() : QByteArray("(unix)") ); tSystemDebug("method : %s", hdr.method().data()); tSystemDebug("path : %s", hdr.path().data()); Tf::HttpMethod method = httpReq->method(); QString path = THttpUtility::fromUrlEncoding(hdr.path().mid(0, hdr.path().indexOf('?'))); // Routing info exists? TRouting rt = TUrlRoute::instance().findRouting(method, path); tSystemDebug("Routing: controller:%s action:%s", rt.controller.data(), rt.action.data()); if (rt.isEmpty()) { // Default URL routing rt.params = path.split('/'); if (path.startsWith(QLatin1Char('/')) && !rt.params.isEmpty()) { rt.params.removeFirst(); // unuse first item } if (path.endsWith(QLatin1Char('/')) && !rt.params.isEmpty()) { rt.params.removeLast(); // unuse last item } // Direct view render mode? if (Tf::app()->appSettings().value(DIRECT_VIEW_RENDER_MODE).toBool()) { // Direct view setting rt.controller = "directcontroller"; rt.action = "show"; } else { if (!rt.params.value(0).isEmpty()) { rt.controller = rt.params.takeFirst().toLower().toLatin1() + "controller"; if (rt.controller == "applicationcontroller") { rt.controller.clear(); // Can not call 'ApplicationController' } // Default action: index rt.action = rt.params.value(0, QLatin1String("index")).toLatin1(); if (!rt.params.isEmpty()) { rt.params.takeFirst(); } } tSystemDebug("Active Controller : %s", rt.controller.data()); } } // Call controller method TDispatcher<TActionController> ctlrDispatcher(rt.controller); currController = ctlrDispatcher.object(); if (currController) { currController->setActionName(rt.action); // Session if (currController->sessionEnabled()) { TSession session; QByteArray sessionId = httpReq->cookie(TSession::sessionName()); if (!sessionId.isEmpty()) { // Finds a session session = TSessionManager::instance().findSession(sessionId); } currController->setSession(session); // Exports flash-variant currController->exportAllFlashVariants(); } // Verify authenticity token if (Tf::app()->appSettings().value(ENABLE_CSRF_PROTECTION_MODULE, true).toBool() && currController->csrfProtectionEnabled() && !currController->exceptionActionsOfCsrfProtection().contains(rt.action)) { if (method == Tf::Post || method == Tf::Put || method == Tf::Delete) { if (!currController->verifyRequest(*httpReq)) { throw SecurityException("Invalid authenticity token", __FILE__, __LINE__); } } } if (currController->sessionEnabled()) { if (currController->session().id().isEmpty() || Tf::app()->appSettings().value(AUTO_ID_REGENERATION).toBool()) { TSessionManager::instance().remove(currController->session().sessionId); // Removes the old session // Re-generate session ID currController->session().sessionId = TSessionManager::instance().generateId(); tSystemDebug("Re-generate session ID: %s", currController->session().sessionId.data()); } // Sets CSRF protection informaion TActionController::setCsrfProtectionInto(currController->session()); } // Database Transaction transactions.setEnabled(currController->transactionEnabled()); // Do filters if (currController->preFilter()) { // Dispathes bool dispatched = ctlrDispatcher.invoke(rt.action, rt.params); if (dispatched) { autoRemoveFiles << currController->autoRemoveFiles; // Adds auto-remove files // Post fileter currController->postFilter(); if (currController->rollbackRequested()) { rollbackTransactions(); } else { // Commits a transaction to the database commitTransactions(); } // Session store if (currController->sessionEnabled()) { bool stored = TSessionManager::instance().store(currController->session()); if (stored) { QDateTime expire; if (TSessionManager::sessionLifeTime() > 0) { expire = QDateTime::currentDateTime().addSecs(TSessionManager::sessionLifeTime()); } // Sets the path in the session cookie QString cookiePath = Tf::app()->appSettings().value(SESSION_COOKIE_PATH).toString(); currController->addCookie(TSession::sessionName(), currController->session().id(), expire, cookiePath); } } } } // Sets charset to the content-type QByteArray ctype = currController->response.header().contentType().toLower(); if (ctype.startsWith("text") && !ctype.contains("charset")) { ctype += "; charset="; ctype += Tf::app()->codecForHttpOutput()->name(); currController->response.header().setContentType(ctype); } // Sets the default status code of HTTP response accessLogger.setStatusCode( (!currController->response.isBodyNull()) ? currController->statusCode() : Tf::InternalServerError ); currController->response.header().setStatusLine(accessLogger.statusCode(), THttpUtility::getResponseReasonPhrase(accessLogger.statusCode())); // Writes a response and access log int bytes = writeResponse(currController->response.header(), currController->response.bodyIODevice(), currController->response.bodyLength()); accessLogger.setResponseBytes(bytes); // Session GC TSessionManager::instance().collectGarbage(); } else { accessLogger.setStatusCode( Tf::BadRequest ); if (method == Tf::Get) { // GET Method path.remove(0, 1); QFile reqPath(Tf::app()->publicPath() + path); QFileInfo fi(reqPath); if (fi.isFile() && fi.isReadable()) { // Check "If-Modified-Since" header for caching bool sendfile = true; QByteArray ifModifiedSince = hdr.rawHeader("If-Modified-Since"); if (!ifModifiedSince.isEmpty()) { QDateTime dt = THttpUtility::fromHttpDateTimeString(ifModifiedSince); sendfile = (!dt.isValid() || dt != fi.lastModified()); } if (sendfile) { // Sends a request file responseHeader.setRawHeader("Last-Modified", THttpUtility::toHttpDateTimeString(fi.lastModified())); QByteArray type = Tf::app()->internetMediaType(fi.suffix()); int bytes = writeResponse(Tf::OK, responseHeader, type, &reqPath, reqPath.size()); accessLogger.setResponseBytes( bytes ); } else { // Not send the data int bytes = writeResponse(Tf::NotModified, responseHeader); accessLogger.setResponseBytes( bytes ); } } else { int bytes = writeResponse(Tf::NotFound, responseHeader); accessLogger.setResponseBytes( bytes ); } accessLogger.setStatusCode( responseHeader.statusCode() ); } else if (method == Tf::Post) { // file upload? } else { // HEAD, DELETE, ... } } } catch (ClientErrorException &e) { tWarn("Caught ClientErrorException: status code:%d", e.statusCode()); int bytes = writeResponse(e.statusCode(), responseHeader); accessLogger.setResponseBytes( bytes ); accessLogger.setStatusCode( e.statusCode() ); } catch (SqlException &e) { tError("Caught SqlException: %s [%s:%d]", qPrintable(e.message()), qPrintable(e.fileName()), e.lineNumber()); tSystemError("Caught SqlException: %s [%s:%d]", qPrintable(e.message()), qPrintable(e.fileName()), e.lineNumber()); closeHttpSocket(); } catch (KvsException &e) { tError("Caught KvsException: %s [%s:%d]", qPrintable(e.message()), qPrintable(e.fileName()), e.lineNumber()); tSystemError("Caught KvsException: %s [%s:%d]", qPrintable(e.message()), qPrintable(e.fileName()), e.lineNumber()); closeHttpSocket(); } catch (SecurityException &e) { tError("Caught SecurityException: %s [%s:%d]", qPrintable(e.message()), qPrintable(e.fileName()), e.lineNumber()); tSystemError("Caught SecurityException: %s [%s:%d]", qPrintable(e.message()), qPrintable(e.fileName()), e.lineNumber()); closeHttpSocket(); } catch (RuntimeException &e) { tError("Caught RuntimeException: %s [%s:%d]", qPrintable(e.message()), qPrintable(e.fileName()), e.lineNumber()); tSystemError("Caught RuntimeException: %s [%s:%d]", qPrintable(e.message()), qPrintable(e.fileName()), e.lineNumber()); closeHttpSocket(); } catch (...) { tError("Caught Exception"); tSystemError("Caught Exception"); closeHttpSocket(); } // Push to the pool TActionContext::releaseSqlDatabases(); TActionContext::releaseKvsDatabases(); TActionContext::accessLogger.write(); // Writes access log releaseHttpSocket(); }
qint64 TActionForkProcess::writeResponse(THttpResponseHeader &header, QIODevice *body) { header.setRawHeader("Connection", "Keep-Alive"); return httpSocket->write(static_cast<THttpHeader*>(&header), body); }