コード例 #1
0
ファイル: WebServer.cpp プロジェクト: outtahere/nzbget
void WebProcessor::SendErrorResponse(const char* errCode, bool printWarning)
{
	const char* RESPONSE_HEADER =
		"HTTP/1.0 %s\r\n"
		"Connection: close\r\n"
		"Content-Length: %i\r\n"
		"Content-Type: text/html\r\n"
		"Server: nzbget-%s\r\n"
		"\r\n";

	if (printWarning)
	{
		warn("Web-Server: %s, Resource: %s", errCode, *m_url);
	}

	BString<1024> responseBody("<html><head><title>%s</title></head><body>Error: %s</body></html>",
		errCode, errCode);
	int pageContentLen = responseBody.Length();

	BString<1024> responseHeader(RESPONSE_HEADER, errCode, pageContentLen, Util::VersionRevision());

	// Send the response answer
	m_connection->Send(responseHeader, responseHeader.Length());
	m_connection->Send(responseBody, pageContentLen);
}
コード例 #2
0
ファイル: WebServer.cpp プロジェクト: outtahere/nzbget
void WebProcessor::SendBodyResponse(const char* body, int bodyLen, const char* contentType)
{
	const char* RESPONSE_HEADER =
		"HTTP/1.1 200 OK\r\n"
		"Connection: close\r\n"
		"Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n"
		"Access-Control-Allow-Origin: %s\r\n"
		"Access-Control-Allow-Credentials: true\r\n"
		"Access-Control-Max-Age: 86400\r\n"
		"Access-Control-Allow-Headers: Content-Type, Authorization\r\n"
		"X-Auth-Token: %s\r\n"
		"Content-Length: %i\r\n"
		"%s"					// Content-Type: xxx
		"%s"					// Content-Encoding: gzip
		"Server: nzbget-%s\r\n"
		"\r\n";

#ifndef DISABLE_GZIP
	CharBuffer gbuf;
	bool gzip = m_gzip && bodyLen > MAX_UNCOMPRESSED_SIZE;
	if (gzip)
	{
		uint32 outLen = ZLib::GZipLen(bodyLen);
		gbuf.Reserve(outLen);
		int gzippedLen = ZLib::GZip(body, bodyLen, *gbuf, outLen);
		if (gzippedLen > 0 && gzippedLen < bodyLen)
		{
			body = gbuf;
			bodyLen = gzippedLen;
		}
		else
		{
			gzip = false;
		}
	}
#else
	bool gzip = false;
#endif

	BString<1024> contentTypeHeader;
	if (contentType)
	{
		contentTypeHeader.Format("Content-Type: %s\r\n", contentType);
	}

	BString<1024> responseHeader(RESPONSE_HEADER,
		m_origin.Str(),
		m_serverAuthToken[m_userAccess], bodyLen, *contentTypeHeader,
		gzip ? "Content-Encoding: gzip\r\n" : "",
		Util::VersionRevision());

	// Send the request answer
	m_connection->Send(responseHeader, responseHeader.Length());
	m_connection->Send(body, bodyLen);
}
コード例 #3
0
ファイル: WebServer.cpp プロジェクト: outtahere/nzbget
void WebProcessor::SendRedirectResponse(const char* url)
{
	const char* REDIRECT_RESPONSE_HEADER =
		"HTTP/1.0 301 Moved Permanently\r\n"
		"Location: %s\r\n"
		"Connection: close\r\n"
		"Server: nzbget-%s\r\n"
		"\r\n";
	BString<1024> responseHeader(REDIRECT_RESPONSE_HEADER, url, Util::VersionRevision());

	// Send the response answer
	debug("ResponseHeader=%s", *responseHeader);
	m_connection->Send(responseHeader, responseHeader.Length());
}
コード例 #4
0
ファイル: WebServer.cpp プロジェクト: outtahere/nzbget
void WebProcessor::SendAuthResponse()
{
	const char* AUTH_RESPONSE_HEADER =
		"HTTP/1.0 401 Unauthorized\r\n"
		"WWW-Authenticate: Basic realm=\"NZBGet\"\r\n"
		"Connection: close\r\n"
		"Content-Type: text/plain\r\n"
		"Server: nzbget-%s\r\n"
		"\r\n";
	BString<1024> responseHeader(AUTH_RESPONSE_HEADER, Util::VersionRevision());

	// Send the response answer
	debug("ResponseHeader=%s", *responseHeader);
	m_connection->Send(responseHeader, responseHeader.Length());
}
コード例 #5
0
ファイル: WebServer.cpp プロジェクト: outtahere/nzbget
void WebProcessor::SendOptionsResponse()
{
	const char* OPTIONS_RESPONSE_HEADER =
		"HTTP/1.1 200 OK\r\n"
		"Connection: close\r\n"
		//"Content-Type: plain/text\r\n"
		"Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n"
		"Access-Control-Allow-Origin: %s\r\n"
		"Access-Control-Allow-Credentials: true\r\n"
		"Access-Control-Max-Age: 86400\r\n"
		"Access-Control-Allow-Headers: Content-Type, Authorization\r\n"
		"Server: nzbget-%s\r\n"
		"\r\n";
	BString<1024> responseHeader(OPTIONS_RESPONSE_HEADER,
		m_origin.Str(), Util::VersionRevision());

	// Send the response answer
	debug("ResponseHeader=%s", *responseHeader);
	m_connection->Send(responseHeader, responseHeader.Length());
}
コード例 #6
0
void QHttpSocketEngine::slotSocketReadNotification()
{
    Q_D(QHttpSocketEngine);
    if (d->state != Connected && d->socket->bytesAvailable() == 0)
        return;

    if (d->state == Connected) {
        // Forward as a read notification.
        if (d->readNotificationEnabled)
            emitReadNotification();
        return;
    }

  readResponseContent:
    if (d->state == ReadResponseContent) {
        char dummybuffer[4096];
        while (d->pendingResponseData) {
            int read = d->socket->read(dummybuffer, qMin(sizeof(dummybuffer), (size_t)d->pendingResponseData));
            if (read >= 0)
                dummybuffer[read] = 0;

            if (read == 0)
                return;
            if (read == -1) {
                d->socket->disconnectFromHost();
                emitWriteNotification();
                return;
            }
            d->pendingResponseData -= read;
        }
        if (d->pendingResponseData > 0)
            return;
        d->state = SendAuthentication;
        slotSocketConnected();
        return;
    }

    // Still in handshake mode. Wait until we've got a full response.
    bool done = false;
    do {
        d->readBuffer += d->socket->readLine();
    } while (!(done = d->readBuffer.endsWith("\r\n\r\n")) && d->socket->canReadLine());

    if (!done) {
        // Wait for more.
        return;
    }

    if (!d->readBuffer.startsWith("HTTP/1.")) {
        // protocol error, this isn't HTTP
        d->readBuffer.clear();
        d->socket->close();
        setState(QAbstractSocket::UnconnectedState);
        setError(QAbstractSocket::ProxyProtocolError, tr("Did not receive HTTP response from proxy"));
        emitConnectionNotification();
        return;
    }

    QHttpResponseHeader responseHeader(QString::fromLatin1(d->readBuffer));
    d->readBuffer.clear(); // we parsed the proxy protocol response. from now on direct socket reading will be done

    int statusCode = responseHeader.statusCode();
    QAuthenticatorPrivate *priv = 0;
    if (statusCode == 200) {
        d->state = Connected;
        setLocalAddress(d->socket->localAddress());
        setLocalPort(d->socket->localPort());
        setState(QAbstractSocket::ConnectedState);
        d->authenticator.detach();
        priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
        priv->hasFailed = false;
    } else if (statusCode == 407) {
        if (d->credentialsSent) {
            //407 response again means the provided username/password were invalid.
            d->authenticator = QAuthenticator(); //this is needed otherwise parseHttpResponse won't set the state, and then signal isn't emitted.
            d->authenticator.detach();
            priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
            priv->hasFailed = true;
        }
        else if (d->authenticator.isNull())
            d->authenticator.detach();
        priv = QAuthenticatorPrivate::getPrivate(d->authenticator);

        priv->parseHttpResponse(responseHeader, true);

        if (priv->phase == QAuthenticatorPrivate::Invalid) {
            // problem parsing the reply
            d->socket->close();
            setState(QAbstractSocket::UnconnectedState);
            setError(QAbstractSocket::ProxyProtocolError, tr("Error parsing authentication request from proxy"));
            emitConnectionNotification();
            return;
        }

        bool willClose;
        QString proxyConnectionHeader = responseHeader.value(QLatin1String("Proxy-Connection"));
        // Although most proxies use the unofficial Proxy-Connection header, the Connection header
        // from http spec is also allowed.
        if (proxyConnectionHeader.isEmpty())
            proxyConnectionHeader = responseHeader.value(QLatin1String("Connection"));
        proxyConnectionHeader = proxyConnectionHeader.toLower();
        if (proxyConnectionHeader == QLatin1String("close")) {
            willClose = true;
        } else if (proxyConnectionHeader == QLatin1String("keep-alive")) {
            willClose = false;
        } else {
            // no Proxy-Connection header, so use the default
            // HTTP 1.1's default behaviour is to keep persistent connections
            // HTTP 1.0 or earlier, so we expect the server to close
            willClose = (responseHeader.majorVersion() * 0x100 + responseHeader.minorVersion()) <= 0x0100;
        }

        if (willClose) {
            // the server will disconnect, so let's avoid receiving an error
            // especially since the signal below may trigger a new event loop
            d->socket->disconnectFromHost();
            d->socket->readAll();
        }

        if (priv->phase == QAuthenticatorPrivate::Done)
            emit proxyAuthenticationRequired(d->proxy, &d->authenticator);
        // priv->phase will get reset to QAuthenticatorPrivate::Start if the authenticator got modified in the signal above.
        if (priv->phase == QAuthenticatorPrivate::Done) {
            setError(QAbstractSocket::ProxyAuthenticationRequiredError, tr("Authentication required"));
            d->socket->disconnectFromHost();
        } else {
            // close the connection if it isn't already and reconnect using the chosen authentication method
            d->state = SendAuthentication;
            if (willClose) {
                d->socket->connectToHost(d->proxy.hostName(), d->proxy.port());
            } else {
                bool ok;
                int contentLength = responseHeader.value(QLatin1String("Content-Length")).toInt(&ok);
                if (ok && contentLength > 0) {
                    d->state = ReadResponseContent;
                    d->pendingResponseData = contentLength;
                    goto readResponseContent;
                } else {
                    d->state = SendAuthentication;
                    slotSocketConnected();
                }
            }
            return;
        }
    } else {
        d->socket->close();
        setState(QAbstractSocket::UnconnectedState);
        if (statusCode == 403 || statusCode == 405) {
            // 403 Forbidden
            // 405 Method Not Allowed
            setError(QAbstractSocket::SocketAccessError, tr("Proxy denied connection"));
        } else if (statusCode == 404) {
            // 404 Not Found: host lookup error
            setError(QAbstractSocket::HostNotFoundError, QAbstractSocket::tr("Host not found"));
        } else if (statusCode == 503) {
            // 503 Service Unavailable: Connection Refused
            setError(QAbstractSocket::ConnectionRefusedError, QAbstractSocket::tr("Connection refused"));
        } else {
            // Some other reply
            //qWarning("UNEXPECTED RESPONSE: [%s]", responseHeader.toString().toLatin1().data());
            setError(QAbstractSocket::ProxyProtocolError, tr("Error communicating with HTTP proxy"));
        }
    }

    // The handshake is done; notify that we're connected (or failed to connect)
    emitConnectionNotification();
}
コード例 #7
0
void QHttpSocketEngine::slotSocketReadNotification()
{
    Q_D(QHttpSocketEngine);
    if (d->state != Connected && d->socket->bytesAvailable() == 0)
        return;

    if (d->state == Connected) {
        // Forward as a read notification.
        if (d->readNotificationEnabled)
            emitReadNotification();
        return;
    }

  readResponseContent:
    if (d->state == ReadResponseContent) {
        char dummybuffer[4096];
        while (d->pendingResponseData) {
            int read = d->socket->read(dummybuffer, qMin(sizeof(dummybuffer), (size_t)d->pendingResponseData));
            dummybuffer[read] = 0;

            if (read == 0)
                return;
            if (read == -1) {
                d->socket->disconnectFromHost();
                emitWriteNotification();
                return;
            }
            d->pendingResponseData -= read;
        }
        if (d->pendingResponseData > 0)
            return;
        d->state = SendAuthentication;
        slotSocketConnected();
        return;
    }

    // Still in handshake mode. Wait until we've got a full response.
    bool done = false;
    do {
        d->readBuffer += d->socket->readLine();
    } while (!(done = d->readBuffer.endsWith("\r\n\r\n")) && d->socket->canReadLine());

    if (!done) {
        // Wait for more.
        return;
    }

    QHttpResponseHeader responseHeader(QString::fromLatin1(d->readBuffer));
    d->readBuffer.clear();

    int statusCode = responseHeader.statusCode();
    if (statusCode == 200) {
        d->state = Connected;
    } else if (statusCode == 503) {
        // 503 Service Unavailable: Connection Refused
        d->socket->close();
        setState(QAbstractSocket::UnconnectedState);
        setError(QAbstractSocket::ConnectionRefusedError, QAbstractSocket::tr("Connection refused"));
    } else if (statusCode == 407) {
        if (d->authenticator.isNull())
            d->authenticator.detach();
        QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(d->authenticator);

        priv->parseHttpResponse(responseHeader, true);

        if (priv->phase == QAuthenticatorPrivate::Done)
            emit proxyAuthenticationRequired(d->proxy, &d->authenticator);

        // priv->phase will get reset to QAuthenticatorPrivate::Start if the authenticator got modified in the signal above.
        if (priv->phase == QAuthenticatorPrivate::Done) {
            setError(QAbstractSocket::ProxyAuthenticationRequiredError, tr("Authentication required"));
            d->socket->disconnectFromHost();
        } else {
            // close the connection if it isn't already and reconnect using the chose authentication method
            d->state = SendAuthentication;
            bool willClose = (responseHeader.value(QLatin1String("Proxy-Connection")).toLower() == QLatin1String("close"));
            if (willClose) {
                d->socket->disconnectFromHost();
                d->socket->readAll();
                d->socket->connectToHost(d->proxy.hostName(), d->proxy.port());
            } else {
                bool ok;
                int contentLength = responseHeader.value(QLatin1String("Content-Length")).toInt(&ok);
                if (ok && contentLength > 0) {
                    d->state = ReadResponseContent;
                    d->pendingResponseData = contentLength;
                    goto readResponseContent;
                } else {
                    d->state = SendAuthentication;
                    slotSocketConnected();
                }
            }
            return;
        }
    } else {
        qWarning("UNEXPECTED RESPONSE: [%s]", responseHeader.toString().toLatin1().data());
        d->socket->disconnectFromHost();
    }

    // The handshake is done; request a new connection attempt by sending a write
    // notification.
    emitWriteNotification();
}
コード例 #8
0
ファイル: InspectorServerQt.cpp プロジェクト: dzhshf/WebKit
void InspectorServerRequestHandlerQt::tcpReadyRead()
{
    WebKit::QHttpRequestHeader header;
    bool isWebSocket = false;
    if (!m_tcpConnection)
        return;

    if (!m_endOfHeaders) {
        while (m_tcpConnection->bytesAvailable() && !m_endOfHeaders) {
            QByteArray line = m_tcpConnection->readLine();
            m_data.append(line);
            if (line == "\r\n")
                m_endOfHeaders = true;
        }
        if (m_endOfHeaders) {
            header = WebKit::QHttpRequestHeader(QString::fromLatin1(m_data));
            if (header.isValid()) {
                m_path = header.path();
                m_contentType = header.contentType().toLatin1();
                m_contentLength = header.contentLength();
                if (header.hasKey(QLatin1String("Upgrade")) && (header.value(QLatin1String("Upgrade")) == QLatin1String("WebSocket")))
                    isWebSocket = true;

                m_data.clear();
            }
        }
    }

    if (m_endOfHeaders) {
        QStringList pathAndQuery = m_path.split(QLatin1Char('?'));
        m_path = pathAndQuery[0];
        QStringList words = m_path.split(QLatin1Char('/'));

        if (isWebSocket) {
            // switch to websocket-style WebSocketService messaging
            if (m_tcpConnection) {
                m_tcpConnection->disconnect(SIGNAL(readyRead()));
                connect(m_tcpConnection, SIGNAL(readyRead()), SLOT(webSocketReadyRead()), Qt::QueuedConnection);

                QByteArray key3 = m_tcpConnection->read(8);

                quint32 number1 = parseWebSocketChallengeNumber(header.value(QLatin1String("Sec-WebSocket-Key1")));
                quint32 number2 = parseWebSocketChallengeNumber(header.value(QLatin1String("Sec-WebSocket-Key2")));

                char responseData[16];
                generateWebSocketChallengeResponse(number1, number2, (unsigned char*)key3.data(), (unsigned char*)responseData);
                QByteArray response(responseData, sizeof(responseData));

                WebKit::QHttpResponseHeader responseHeader(101, QLatin1String("WebSocket Protocol Handshake"), 1, 1);
                responseHeader.setValue(QLatin1String("Upgrade"), header.value(QLatin1String("Upgrade")));
                responseHeader.setValue(QLatin1String("Connection"), header.value(QLatin1String("Connection")));
                responseHeader.setValue(QLatin1String("Sec-WebSocket-Origin"), header.value(QLatin1String("Origin")));
                responseHeader.setValue(QLatin1String("Sec-WebSocket-Location"), (QLatin1String("ws://") + header.value(QLatin1String("Host")) + m_path));
                responseHeader.setContentLength(response.size());
                m_tcpConnection->write(responseHeader.toString().toLatin1());
                m_tcpConnection->write(response);
                m_tcpConnection->flush();

                if ((words.size() == 4)
                    && (words[1] == QString::fromLatin1("devtools"))
                    && (words[2] == QString::fromLatin1("page"))) {
                    int pageNum = words[3].toInt();

                    m_inspectorClient = m_server->inspectorClientForPage(pageNum);
                    // Attach remoteFrontendChannel to inspector, also transferring ownership.
                    if (m_inspectorClient)
                        m_inspectorClient->attachAndReplaceRemoteFrontend(this);
                }

            }

            return;
        }
        if (m_contentLength && (m_tcpConnection->bytesAvailable() < m_contentLength))
            return;

        QByteArray content = m_tcpConnection->read(m_contentLength);
        m_endOfHeaders = false;

        QByteArray response;
        int code = 200;
        QString text = QString::fromLatin1("OK");

        // If no path is specified, generate an index page.
        if (m_path.isEmpty() || (m_path == QString(QLatin1Char('/')))) {
            QString indexHtml = QLatin1String("<html><head><title>Remote Web Inspector</title></head><body><ul>\n");
            for (QMap<int, InspectorClientQt* >::const_iterator it = m_server->m_inspectorClients.begin();
                 it != m_server->m_inspectorClients.end(); 
                 ++it) {
                indexHtml.append(QString::fromLatin1("<li><a href=\"/webkit/inspector/inspector.html?page=%1\">%2</li>\n")
                                 .arg(it.key())
                                 .arg(it.value()->m_inspectedWebPage->mainFrame()->url().toString()));
            }
            indexHtml.append(QLatin1String("</ul></body></html>"));
            response = indexHtml.toLatin1();
        } else {
            QString path = QString::fromLatin1(":%1").arg(m_path);
            QFile file(path);
            // It seems that there should be an enum or define for these status codes somewhere in Qt or WebKit,
            // but grep fails to turn one up.
            // QNetwork uses the numeric values directly.
            if (file.exists()) {
                file.open(QIODevice::ReadOnly);
                response = file.readAll();
            } else {
                code = 404;
                text = QString::fromLatin1("Not OK");
            }
        }

        WebKit::QHttpResponseHeader responseHeader(code, text, 1, 0);
        responseHeader.setContentLength(response.size());
        if (!m_contentType.isEmpty())
            responseHeader.setContentType(QString::fromLatin1(m_contentType));

        QByteArray asciiHeader = responseHeader.toString().toLatin1();
        m_tcpConnection->write(asciiHeader);

        m_tcpConnection->write(response);
        m_tcpConnection->flush();
        m_tcpConnection->close();

        return;
    }
}