Skip to content

Commit

Permalink
Implement XEP-0363: HTTP File Upload: Request IQs
Browse files Browse the repository at this point in the history
This implements the IQs for requesting and receiving upload slots as
defined by XEP-0363: HTTP File Upload [v0.9.0].
  • Loading branch information
lnjX committed Jan 20, 2019
1 parent 2a34abc commit 8751c76
Show file tree
Hide file tree
Showing 8 changed files with 474 additions and 0 deletions.
1 change: 1 addition & 0 deletions doc/xep.doc
Expand Up @@ -46,5 +46,6 @@ Ongoing:
- XEP-0009: Jabber-RPC (API is not finalized yet)
- XEP-0060: Publish-Subscribe (Only basic IQ implemented)
- XEP-0077: In-Band Registration (Only basic IQ implemented)
- XEP-0363: HTTP File Upload [v0.9.0]

*/
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Expand Up @@ -19,6 +19,7 @@ set(INSTALL_HEADER_FILES
base/QXmppDiscoveryIq.h
base/QXmppElement.h
base/QXmppEntityTimeIq.h
base/QXmppHttpUploadIq.h
base/QXmppIbbIq.h
base/QXmppIq.h
base/QXmppJingleIq.h
Expand Down Expand Up @@ -93,6 +94,7 @@ set(SOURCE_FILES
base/QXmppDiscoveryIq.cpp
base/QXmppElement.cpp
base/QXmppEntityTimeIq.cpp
base/QXmppHttpUploadIq.cpp
base/QXmppIbbIq.cpp
base/QXmppIq.cpp
base/QXmppJingleIq.cpp
Expand Down
2 changes: 2 additions & 0 deletions src/base/QXmppConstants.cpp
Expand Up @@ -132,3 +132,5 @@ const char* ns_idle = "urn:xmpp:idle:1";
const char* ns_chat_markers = "urn:xmpp:chat-markers:0";
// XEP-0352: Client State Indication
const char* ns_csi = "urn:xmpp:csi:0";
// XEP-0363: HTTP File Upload
const char* ns_http_upload = "urn:xmpp:http:upload:0";
2 changes: 2 additions & 0 deletions src/base/QXmppConstants_p.h
Expand Up @@ -144,5 +144,7 @@ extern const char* ns_idle;
extern const char* ns_chat_markers;
// XEP-0352: Client State Indication
extern const char* ns_csi;
// XEP-0363: HTTP File Upload
extern const char* ns_http_upload;

#endif // QXMPPCONSTANTS_H
195 changes: 195 additions & 0 deletions src/base/QXmppHttpUploadIq.cpp
@@ -0,0 +1,195 @@
/*
* Copyright (C) 2008-2019 The QXmpp developers
*
* Authors:
* Linus Jahn <lnj@kaidan.im>
*
* Source:
* https://github.com/qxmpp-project/qxmpp
*
* This file is a part of QXmpp library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
*/

#include <QDomElement>
#include <QMimeDatabase>

#include "QXmppHttpUploadIq.h"
#include "QXmppConstants_p.h"

QString QXmppHttpUploadRequestIq::fileName() const
{
return m_fileName;
}

void QXmppHttpUploadRequestIq::setFileName(const QString &fileName)
{
m_fileName = fileName;
}

qint64 QXmppHttpUploadRequestIq::size() const
{
return m_size;
}

void QXmppHttpUploadRequestIq::setSize(const qint64 &size)
{
m_size = size;
}

QMimeType QXmppHttpUploadRequestIq::contentType() const
{
return m_contentType;
}

void QXmppHttpUploadRequestIq::setContentType(const QMimeType &type)
{
m_contentType = type;
}

bool QXmppHttpUploadRequestIq::isHttpUploadRequestIq(const QDomElement &element)
{
if (element.tagName() == "iq") {
QDomElement request = element.firstChildElement("request");
return !request.isNull() && request.namespaceURI() == ns_http_upload;
}
return false;
}

/// \cond
void QXmppHttpUploadRequestIq::parseElementFromChild(const QDomElement &element)
{
QDomElement request = element.firstChildElement("request");
m_fileName = request.attribute("filename");
m_size = request.attribute("size").toLongLong();
if (request.hasAttribute("content-type")) {
QMimeDatabase mimeDb;
QMimeType type = mimeDb.mimeTypeForName(request.attribute("content-type"));
if (!type.isDefault() && type.isValid())
m_contentType = type;
}
}

void QXmppHttpUploadRequestIq::toXmlElementFromChild(QXmlStreamWriter *writer) const
{
writer->writeStartElement("request");
writer->writeAttribute("xmlns", ns_http_upload);
// filename and size are required
writer->writeAttribute("filename", m_fileName);
writer->writeAttribute("size", QString::number(m_size));
// content-type is optional
if (!m_contentType.isDefault() && m_contentType.isValid())
writer->writeAttribute("content-type", m_contentType.name());
writer->writeEndElement();
}
/// \endcond

QUrl QXmppHttpUploadSlotIq::putUrl() const
{
return m_putUrl;
}

void QXmppHttpUploadSlotIq::setPutUrl(const QUrl &putUrl)
{
m_putUrl = putUrl;
}

QUrl QXmppHttpUploadSlotIq::getUrl() const
{
return m_getUrl;
}

void QXmppHttpUploadSlotIq::setGetUrl(const QUrl &getUrl)
{
m_getUrl = getUrl;
}

QMap<QString, QString> QXmppHttpUploadSlotIq::headerFields() const
{
return m_headerFields;
}

void QXmppHttpUploadSlotIq::setHeaderFields(const QMap<QString, QString> &headerFields)
{
m_headerFields.clear();
for (QString &name : headerFields.keys()) {
if (name == "Authorization" || name == "Cookie" || name == "Expires") {
QString value = headerFields[name];
m_headerFields[name] = value.replace("\n", "");
}
}
}

/// Returns whether the URLs (put and get) are both HTTPS URLs. It will return
/// false, if the URLs are non-HTTPS URLs or not set. HTTP URLs are not
/// XEP-compliant, but are used in some cases.

bool QXmppHttpUploadSlotIq::hasHttpsUrls() const
{
return m_getUrl.toString().startsWith("https://") &&
m_putUrl.toString().startsWith("https://");
}

bool QXmppHttpUploadSlotIq::isHttpUploadSlotIq(const QDomElement &element)
{
if (element.tagName() == "iq") {
QDomElement slot = element.firstChildElement("slot");
return !slot.isNull() && slot.namespaceURI() == ns_http_upload;
}
return false;
}

/// \cond
void QXmppHttpUploadSlotIq::parseElementFromChild(const QDomElement &element)
{
QDomElement slot = element.firstChildElement("slot");
QDomElement put = slot.firstChildElement("put");
m_getUrl = QUrl::fromEncoded(slot.firstChildElement("get").attribute("url").toUtf8());
m_putUrl = QUrl::fromEncoded(put.attribute("url").toUtf8());
if (put.hasChildNodes()) {
QMap<QString, QString> headers;
QDomElement header = put.firstChildElement("header");
while (!header.isNull()) {
headers[header.attribute("name")] = header.text();

header = header.nextSiblingElement("header");
}

setHeaderFields(headers);
}
}

void QXmppHttpUploadSlotIq::toXmlElementFromChild(QXmlStreamWriter *writer) const
{
writer->writeStartElement("slot");
writer->writeAttribute("xmlns", ns_http_upload);

writer->writeStartElement("put");
writer->writeAttribute("url", m_putUrl.toEncoded());
if (!m_headerFields.isEmpty()) {
for (const QString &name : m_headerFields.keys()) {
writer->writeStartElement("header");
writer->writeAttribute("name", name);
writer->writeCharacters(m_headerFields[name]);
writer->writeEndElement();
}
}
writer->writeEndElement();

writer->writeStartElement("get");
writer->writeAttribute("url", m_getUrl.toEncoded());
writer->writeEndElement();

writer->writeEndElement();
}
/// \endcond
97 changes: 97 additions & 0 deletions src/base/QXmppHttpUploadIq.h
@@ -0,0 +1,97 @@
/*
* Copyright (C) 2008-2019 The QXmpp developers
*
* Authors:
* Linus Jahn <lnj@kaidan.im>
*
* Source:
* https://github.com/qxmpp-project/qxmpp
*
* This file is a part of QXmpp library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
*/

#ifndef QXMPPHTTPUPLOADIQ_H
#define QXMPPHTTPUPLOADIQ_H

#include <QMap>
#include <QMimeType>
#include <QUrl>

#include "QXmppIq.h"

/// \brief Represents an HTTP File Upload IQ for requesting an upload slot as
/// defined by XEP-0363: HTTP File Upload [v0.9.0].
///
/// \ingroup Stanzas

class QXMPP_EXPORT QXmppHttpUploadRequestIq : public QXmppIq
{
public:
QString fileName() const;
void setFileName(const QString &filename);

qint64 size() const;
void setSize(const qint64 &size);

QMimeType contentType() const;
void setContentType(const QMimeType &type);

static bool isHttpUploadRequestIq(const QDomElement &element);

protected:
/// \cond
void parseElementFromChild(const QDomElement &element);
void toXmlElementFromChild(QXmlStreamWriter *writer) const;
/// \endcond

private:
QString m_fileName;
qint64 m_size;
QMimeType m_contentType;
};

/// \brief Represents an HTTP File Upload IQ result for receiving an upload slot as
/// defined by XEP-0363: HTTP File Upload [v0.9.0].
///
/// \ingroup Stanzas

class QXMPP_EXPORT QXmppHttpUploadSlotIq : public QXmppIq
{
public:
QUrl putUrl() const;
void setPutUrl(const QUrl &putUrl);

QUrl getUrl() const;
void setGetUrl(const QUrl &getUrl);

QMap<QString, QString> headerFields() const;
void setHeaderFields(const QMap<QString, QString> &headerFields);

bool hasHttpsUrls() const;

static bool isHttpUploadSlotIq(const QDomElement &element);

protected:
/// \cond
void parseElementFromChild(const QDomElement &element);
void toXmlElementFromChild(QXmlStreamWriter *writer) const;
/// \endcond

private:
QUrl m_putUrl;
QUrl m_getUrl;
QMap<QString, QString> m_headerFields;
};

#endif // QXMPPHTTPUPLOADIQ_H
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Expand Up @@ -21,6 +21,7 @@ add_simple_test(qxmppcarbonmanager)
add_simple_test(qxmppdataform)
add_simple_test(qxmppdiscoveryiq)
add_simple_test(qxmppentitytimeiq)
add_simple_test(qxmpphttpuploadiq)
add_simple_test(qxmppiceconnection)
add_simple_test(qxmppiq)
add_simple_test(qxmppjingleiq)
Expand Down

0 comments on commit 8751c76

Please sign in to comment.