コード例 #1
0
void TActionForkProcess::start()
{
    if (currentActionContext)
        return;

    currentActionContext = this;
    std::cerr << "_accepted" << std::flush;  // send to tfmanager

    QList<THttpRequest> reqs;
    QEventLoop eventLoop;
    httpSocket = new THttpSocket;

    if (!httpSocket->setSocketDescriptor(TActionContext::socketDesc)) {
        emitError(httpSocket->error());
        goto socket_error;
    }
    TActionContext::socketDesc = 0;

    for (;;) {
        reqs = TActionThread::readRequest(httpSocket);
        tSystemDebug("HTTP request count: %d", reqs.count());

        if (reqs.isEmpty()) {
            break;
        }

        for (QMutableListIterator<THttpRequest> it(reqs); it.hasNext(); ) {
            THttpRequest &req = it.next();
            TActionContext::execute(req);

            httpSocket->flush();  // Flush socket
            TActionContext::release();
        }

        if (!httpSocket->waitForReadyRead(5000))
            break;
    }

    closeHttpSocket();  // disconnect

    // For cleanup
    while (eventLoop.processEvents()) {}

    emit finished();
    QCoreApplication::exit(1);

socket_error:
    delete httpSocket;
    httpSocket = 0;
}
コード例 #2
0
ファイル: http.cpp プロジェクト: Aleksandr-S/libHttpServer
void clHttp::stop()
{
    closeThread = true;
    mutex.lock();
    for(int i=0;i<listConnections.count();++i) {
        clProcessingHttp *l_clientThread = listConnections.at(i);
        delete l_clientThread;
        listConnections.replace(i, NULL);
    }
    listConnections.removeAll(NULL);
    mutex.unlock();
    closeHttpSocket();
#ifdef Q_OS_WIN
    WSACleanup();
#endif
    wait(200);
}
コード例 #3
0
void TActionThread::run()
{
    QList<THttpRequest> reqs;
    QEventLoop eventLoop;
    httpSocket = new THttpSocket;

    if (!httpSocket->setSocketDescriptor(TActionContext::socketDesc)) {
        emitError(httpSocket->error());
        goto socket_error;
    }
    TActionContext::socketDesc = 0;

    for (;;) {
        reqs = readRequest(httpSocket);
        tSystemDebug("HTTP request count: %d", reqs.count());

        if (reqs.isEmpty())
            break;

        for (QMutableListIterator<THttpRequest> it(reqs); it.hasNext(); ) {
            THttpRequest &req = it.next();
            TActionContext::execute(req);

            httpSocket->flush();  // Flush socket
            TActionContext::release();
        }

        if (!httpSocket->waitForReadyRead(5000))
            break;
    }

    closeHttpSocket();  // disconnect

    // For cleanup
    while (eventLoop.processEvents()) {}

socket_error:
    delete httpSocket;
    httpSocket = 0;
}
コード例 #4
0
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();
}
コード例 #5
0
ファイル: http.cpp プロジェクト: Aleksandr-S/libHttpServer
void clHttp::run()
{
    while(!closeThread) {
        sockHttp = socket(AF_INET,SOCK_STREAM,0);
#ifdef Q_OS_UNIX
        if(sockHttp == -1) {
#else
        if(sockHttp == INVALID_SOCKET) {
#endif
            debug.add(ERR, "Error creating socket");
            emit started(false);
            return;
        }
        int iBool = 1;
        if(setsockopt(sockHttp, SOL_SOCKET, SO_REUSEADDR, (char *)&iBool, sizeof(iBool)) != 0) {
#ifdef Q_OS_UNIX
            debug.add(ERR, "Error setsockopt: " + QString::fromLocal8Bit(strerror(errno)));
#else
            debug.add(ERR, "Error setsockopt: " + QString().setNum(WSAGetLastError()));
#endif
        }
#ifdef Q_OS_UNIX
        if(fcntl(sockHttp, F_SETFD, FD_CLOEXEC) == -1) { // Освобождает дискриптеры после закрытия сокета
            debug.add(ERR, "Error set FD_CLOEXEC socket: " + QString::fromLocal8Bit(strerror(errno)));
        }
#endif
        sockaddr_in local_addr;
        local_addr.sin_family = AF_INET;
        local_addr.sin_addr.s_addr = INADDR_ANY;
        local_addr.sin_port = htons(port);
        if(bind(sockHttp, (sockaddr *)&local_addr, sizeof(local_addr))) {
#ifdef Q_OS_UNIX
            debug.add(ERR, "Erorr bind port " + QString().setNum(port) + ": " + QString::fromLocal8Bit(strerror(errno)));
#else
            debug.add(ERR, "Erorr bind port "  + QString().setNum(port) + ": " + QString().setNum(WSAGetLastError()));
#endif
            closeHttpSocket();
            unsigned long time = 0;
            while(!closeThread && time < 3*1000) { msleep(200); time += 200; }
            continue;
        }
        if(listen(sockHttp, 10000) == -1) {
#ifdef Q_OS_UNIX
            debug.add(ERR, "Can't listen on port " + QString().setNum(port) + ": " + QString::fromLocal8Bit(strerror(errno)));
#else
            debug.add(ERR, "Can't listen on port " + QString().setNum(port) + ": " + QString().setNum(WSAGetLastError()));
#endif
            closeHttpSocket();
            unsigned long time = 0;
            while(!closeThread && time < 3*1000) { msleep(200); time += 200; }
            continue;
        }
        debug.add(NOTICE, "Started on port " + QString().setNum(htons(local_addr.sin_port)) +
                  " (id: " + QString().setNum((unsigned long)QThread::currentThreadId()) + ")");
        emit started(true);
        break;
    }
    //***********************
    fd_set readSet, errorSet;
    FD_ZERO(&readSet);
    FD_ZERO(&errorSet);
    FD_SET(sockHttp, &errorSet);
    FD_SET(sockHttp, &readSet);
    int SelectTiming = 0;
    //************************
    if ((SelectTiming = select(sockHttp+1, &readSet, 0, &errorSet, 0)) == -1) {
#ifdef Q_OS_UNIX
        debug.add(ERR, "Error on select accept: " + QString::fromLocal8Bit(strerror(errno)));
#else
        debug.add(ERR, "Error on select accept: " + QString().setNum(WSAGetLastError()));
#endif
        closeHttpSocket();
        emit started(false);
        return;
    }
    if(SelectTiming > 0) {
        if (FD_ISSET(sockHttp, &errorSet)) {
            debug.add(ERR, "Error connect server");
            closeHttpSocket();
            emit started(false);
            return;
        }
        if(FD_ISSET(sockHttp, &readSet)) {
            SOCKET client_socket;
            sockaddr_in client_addr;
            memset(&client_addr, 0, sizeof(sockaddr_in));
            while(!closeThread) {
                int client_addr_size = sizeof(client_addr);
#ifdef Q_OS_UNIX
                client_socket = accept(sockHttp, (sockaddr *)&client_addr, (socklen_t *)&client_addr_size);
#else
                client_socket = accept(sockHttp, (sockaddr *)&client_addr, &client_addr_size);
#endif
                if(client_socket > 0) {
                    processingHttp = new clProcessingHttp(client_socket);
                    connect(processingHttp, SIGNAL(disconnectClient(clProcessingHttp*)), this, SLOT(disconnectClient(clProcessingHttp*)));
                    connect(processingHttp, SIGNAL(request(clHtmlData*)), this, SIGNAL(request(clHtmlData*)));
                    connect(processingHttp, SIGNAL(error(QString,QString)), this, SIGNAL(error(QString,QString)));
                    mutex.lock();
                    listConnections.append(processingHttp);
                    mutex.unlock();
                    processingHttp->start();
                    memset(&client_addr, 0, sizeof(sockaddr_in));
                }
            }
        }
    }