Skip to content

Commit

Permalink
Implement XEP-0363: HTTP File Upload: Request/Slot 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 in version 0.9.0.
  • Loading branch information
lnjX committed May 4, 2019
1 parent 8cb3bb4 commit fbe8411
Show file tree
Hide file tree
Showing 8 changed files with 530 additions and 0 deletions.
1 change: 1 addition & 0 deletions doc/xep.doc
Expand Up @@ -47,6 +47,7 @@ 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)
- XEP-0369: Mediated Information eXchange (MIX) (Only IQ queries implemented) (v0.14.2)
- XEP-0405: Mediated Information eXchange (MIX): Participant Server Requirements (Only IQ queries implemented) (v0.4.0)

Expand Down
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 @@ -95,6 +96,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,6 +132,8 @@ 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";
// XEP-0369: Mediated Information eXchange (MIX)
const char* ns_mix = "urn:xmpp:mix:core:1";
const char* ns_mix_create_channel = "urn:xmpp:mix:core:1#create-channel";
Expand Down
2 changes: 2 additions & 0 deletions src/base/QXmppConstants_p.h
Expand Up @@ -144,6 +144,8 @@ 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;
// XEP-0369: Mediated Information eXchange (MIX)
extern const char* ns_mix;
extern const char* ns_mix_create_channel;
Expand Down
250 changes: 250 additions & 0 deletions src/base/QXmppHttpUploadIq.cpp
@@ -0,0 +1,250 @@
/*
* 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"

class QXmppHttpUploadRequestIqPrivate
{
public:
QString fileName;
qint64 size;
QMimeType contentType;
};

QXmppHttpUploadRequestIq::QXmppHttpUploadRequestIq()
: d(new QXmppHttpUploadRequestIqPrivate())
{
}

QXmppHttpUploadRequestIq::~QXmppHttpUploadRequestIq()
{
delete d;
}

/// Returns the file name of the file to be uploaded.

QString QXmppHttpUploadRequestIq::fileName() const
{
return d->fileName;
}

/// Sets the file name. The upload service will use this to create the upload/
/// download URLs. This may also differ from the actual file name to get a
/// different URL. It's not required to replace special characters (this is the
/// server's job).

void QXmppHttpUploadRequestIq::setFileName(const QString &fileName)
{
d->fileName = fileName;
}

/// Returns the file's size in bytes.

qint64 QXmppHttpUploadRequestIq::size() const
{
return d->size;
}

/// Sets the file's size in bytes.

void QXmppHttpUploadRequestIq::setSize(qint64 size)
{
d->size = size;
}

/// Returns the (optional) MIME-type of the file.

QMimeType QXmppHttpUploadRequestIq::contentType() const
{
return d->contentType;
}

/// Sets the MIME-type of the file. This is optional.

void QXmppHttpUploadRequestIq::setContentType(const QMimeType &type)
{
d->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");
d->fileName = request.attribute("filename");
d->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())
d->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", d->fileName);
writer->writeAttribute("size", QString::number(d->size));
// content-type is optional
if (!d->contentType.isDefault() && d->contentType.isValid())
writer->writeAttribute("content-type", d->contentType.name());
writer->writeEndElement();
}
/// \endcond

class QXmppHttpUploadSlotIqPrivate
{
public:
QUrl putUrl;
QUrl getUrl;
QMap<QString, QString> putHeaders;
};

QXmppHttpUploadSlotIq::QXmppHttpUploadSlotIq()
: d(new QXmppHttpUploadSlotIqPrivate())
{
}

QXmppHttpUploadSlotIq::~QXmppHttpUploadSlotIq()
{
delete d;
}

/// Returns the URL for uploading via. HTTP PUT.

QUrl QXmppHttpUploadSlotIq::putUrl() const
{
return d->putUrl;
}

/// Sets the URL the client should use for uploading.

void QXmppHttpUploadSlotIq::setPutUrl(const QUrl &putUrl)
{
d->putUrl = putUrl;
}

/// Returns the URL to where the file will be served.

QUrl QXmppHttpUploadSlotIq::getUrl() const
{
return d->getUrl;
}

/// Sets the download URL.

void QXmppHttpUploadSlotIq::setGetUrl(const QUrl &getUrl)
{
d->getUrl = getUrl;
}

/// Returns a map of header fields (header name -> value) that need to be
/// included in the PUT (upload) request. This won't contain any other fields
/// than: "Authorization", "Cookie" or "Expires".

QMap<QString, QString> QXmppHttpUploadSlotIq::putHeaders() const
{
return d->putHeaders;
}

/// Sets the header fields the client needs to include in the PUT (upload)
/// request. All fields other than "Authorization", "Cookie" or "Expires" will
/// be ignored.

void QXmppHttpUploadSlotIq::setPutHeaders(const QMap<QString, QString> &putHeaders)
{
d->putHeaders.clear();
for (QString &name : putHeaders.keys()) {
if (name == "Authorization" || name == "Cookie" || name == "Expires")
d->putHeaders[name] = putHeaders[name];
}
}

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");
d->getUrl = QUrl::fromEncoded(slot.firstChildElement("get").attribute("url").toUtf8());
d->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");
}

setPutHeaders(headers);
}
}

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

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

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

writer->writeEndElement();
}
/// \endcond
100 changes: 100 additions & 0 deletions src/base/QXmppHttpUploadIq.h
@@ -0,0 +1,100 @@
/*
* 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"

class QXmppHttpUploadRequestIqPrivate;
class QXmppHttpUploadSlotIqPrivate;

/// \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:
QXmppHttpUploadRequestIq();
~QXmppHttpUploadRequestIq();

QString fileName() const;
void setFileName(const QString &filename);

qint64 size() const;
void setSize(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:
QXmppHttpUploadRequestIqPrivate* const d;
};

/// \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:
QXmppHttpUploadSlotIq();
~QXmppHttpUploadSlotIq();

QUrl putUrl() const;
void setPutUrl(const QUrl &putUrl);

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

QMap<QString, QString> putHeaders() const;
void setPutHeaders(const QMap<QString, QString> &putHeaders);

static bool isHttpUploadSlotIq(const QDomElement &element);

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

private:
QXmppHttpUploadSlotIqPrivate* const d;
};

#endif // QXMPPHTTPUPLOADIQ_H

0 comments on commit fbe8411

Please sign in to comment.