mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-22 22:32:06 +01:00
Add support for XEP-0363: HTTP File Upload.
Fixes SMACK-747
This commit is contained in:
parent
a8c6de6b98
commit
72d4c8b611
17 changed files with 1073 additions and 1 deletions
|
@ -91,6 +91,7 @@ Experimental Smack Extensions and currently supported XEPs of smack-experimental
|
||||||
| [Internet of Things - Discovery](iot.md) | [XEP-0347](http://xmpp.org/extensions/xep-0347.html) | Describes how Things can be installed and discovered by their owners. |
|
| [Internet of Things - Discovery](iot.md) | [XEP-0347](http://xmpp.org/extensions/xep-0347.html) | Describes how Things can be installed and discovered by their owners. |
|
||||||
| Client State Indication | [XEP-0352](http://xmpp.org/extensions/xep-0352.html) | A way for the client to indicate its active/inactive state. |
|
| Client State Indication | [XEP-0352](http://xmpp.org/extensions/xep-0352.html) | A way for the client to indicate its active/inactive state. |
|
||||||
| [Push Notifications](pushnotifications.md) | [XEP-0357](http://xmpp.org/extensions/xep-0357.html) | Defines a way to manage push notifications from an XMPP Server. |
|
| [Push Notifications](pushnotifications.md) | [XEP-0357](http://xmpp.org/extensions/xep-0357.html) | Defines a way to manage push notifications from an XMPP Server. |
|
||||||
|
| HTTP File Upload | [XEP-0363](http://xmpp.org/extensions/xep-0363.html) | Protocol to request permissions to upload a file to an HTTP server and get a shareable URL. |
|
||||||
| [Multi-User Chat Light](muclight.md) | [XEP-xxxx](http://mongooseim.readthedocs.io/en/latest/open-extensions/xeps/xep-muc-light.html) | Multi-User Chats for mobile XMPP applications and specific enviroment. |
|
| [Multi-User Chat Light](muclight.md) | [XEP-xxxx](http://mongooseim.readthedocs.io/en/latest/open-extensions/xeps/xep-muc-light.html) | Multi-User Chats for mobile XMPP applications and specific enviroment. |
|
||||||
| Google GCM JSON payload | n/a | Semantically the same as XEP-0335: JSON Containers |
|
| Google GCM JSON payload | n/a | Semantically the same as XEP-0335: JSON Containers |
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,375 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2017 Grigory Fedorov
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.httpfileupload;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.AbstractConnectionListener;
|
||||||
|
import org.jivesoftware.smack.ConnectionCreationListener;
|
||||||
|
import org.jivesoftware.smack.Manager;
|
||||||
|
import org.jivesoftware.smack.SmackException;
|
||||||
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
|
import org.jivesoftware.smack.XMPPConnectionRegistry;
|
||||||
|
import org.jivesoftware.smack.XMPPException;
|
||||||
|
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||||
|
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
||||||
|
import org.jivesoftware.smackx.httpfileupload.element.Slot;
|
||||||
|
import org.jivesoftware.smackx.httpfileupload.element.SlotRequest;
|
||||||
|
import org.jivesoftware.smackx.xdata.FormField;
|
||||||
|
import org.jivesoftware.smackx.xdata.packet.DataForm;
|
||||||
|
import org.jxmpp.jid.DomainBareJid;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP File Upload manager class.
|
||||||
|
* XEP version 0.2.5
|
||||||
|
*
|
||||||
|
* @author Grigory Fedorov
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0363.html">XEP-0363: HTTP File Upload</a>
|
||||||
|
*/
|
||||||
|
public final class HttpFileUploadManager extends Manager {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(HttpFileUploadManager.class.getName());
|
||||||
|
|
||||||
|
static {
|
||||||
|
XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() {
|
||||||
|
@Override
|
||||||
|
public void connectionCreated(XMPPConnection connection) {
|
||||||
|
getInstanceFor(connection);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Map<XMPPConnection, HttpFileUploadManager> INSTANCES = new WeakHashMap<>();
|
||||||
|
private DomainBareJid defaultUploadService;
|
||||||
|
private Long maxFileSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the HttpFileUploadManager responsible for a connection.
|
||||||
|
*
|
||||||
|
* @param connection the connection object.
|
||||||
|
* @return a HttpFileUploadManager instance
|
||||||
|
*/
|
||||||
|
public static synchronized HttpFileUploadManager getInstanceFor(XMPPConnection connection) {
|
||||||
|
HttpFileUploadManager httpFileUploadManager = INSTANCES.get(connection);
|
||||||
|
|
||||||
|
if (httpFileUploadManager == null) {
|
||||||
|
httpFileUploadManager = new HttpFileUploadManager(connection);
|
||||||
|
INSTANCES.put(connection, httpFileUploadManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
return httpFileUploadManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpFileUploadManager(XMPPConnection connection) {
|
||||||
|
super(connection);
|
||||||
|
|
||||||
|
connection.addConnectionListener(new AbstractConnectionListener() {
|
||||||
|
@Override
|
||||||
|
public void authenticated(XMPPConnection connection, boolean resumed) {
|
||||||
|
// No need to reset the cache if the connection got resumed.
|
||||||
|
if (resumed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
discoverUploadService();
|
||||||
|
} catch (XMPPException.XMPPErrorException | SmackException.NotConnectedException
|
||||||
|
| SmackException.NoResponseException | InterruptedException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Error during discovering HTTP File Upload service", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discover upload service.
|
||||||
|
*
|
||||||
|
* Called automatically when connection is authenticated.
|
||||||
|
*
|
||||||
|
* Note that this is a synchronous call -- Smack must wait for the server response.
|
||||||
|
*
|
||||||
|
* @return true if upload service was discovered
|
||||||
|
|
||||||
|
* @throws XMPPException.XMPPErrorException
|
||||||
|
* @throws SmackException.NotConnectedException
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws SmackException.NoResponseException
|
||||||
|
*/
|
||||||
|
public boolean discoverUploadService() throws XMPPException.XMPPErrorException, SmackException.NotConnectedException,
|
||||||
|
InterruptedException, SmackException.NoResponseException {
|
||||||
|
defaultUploadService = null;
|
||||||
|
maxFileSize = null;
|
||||||
|
|
||||||
|
List<DiscoverInfo> servicesDiscoverInfo = ServiceDiscoveryManager.getInstanceFor(connection())
|
||||||
|
.findServicesDiscoverInfo(SlotRequest.NAMESPACE, true, false);
|
||||||
|
|
||||||
|
if (servicesDiscoverInfo.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DiscoverInfo discoverInfo = servicesDiscoverInfo.get(0);
|
||||||
|
|
||||||
|
defaultUploadService = discoverInfo.getFrom().asDomainBareJid();
|
||||||
|
|
||||||
|
if (defaultUploadService == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataForm dataForm = DataForm.from(discoverInfo);
|
||||||
|
if (dataForm == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
FormField field = dataForm.getField("max-file-size");
|
||||||
|
if (field == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> values = field.getValues();
|
||||||
|
if (!values.isEmpty()) {
|
||||||
|
maxFileSize = Long.valueOf(values.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if upload service was discovered.
|
||||||
|
*
|
||||||
|
* @return true if upload service was discovered
|
||||||
|
*/
|
||||||
|
public boolean isUploadServiceDiscovered() {
|
||||||
|
return defaultUploadService != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get default upload service if it was discovered.
|
||||||
|
*
|
||||||
|
* @return upload service JID or null if not available
|
||||||
|
*/
|
||||||
|
public DomainBareJid getDefaultUploadService() {
|
||||||
|
return defaultUploadService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get max file size allowed by upload service.
|
||||||
|
*
|
||||||
|
* @return max file size in bytes or null if not available
|
||||||
|
*/
|
||||||
|
public Long getMaxFileSize() {
|
||||||
|
return maxFileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request slot and uploaded file to HTTP file upload service.
|
||||||
|
*
|
||||||
|
* You don't need to request slot and upload file separately, this method will do both.
|
||||||
|
* Note that this is a synchronous call -- Smack must wait for the server response.
|
||||||
|
*
|
||||||
|
* @param file file to be uploaded
|
||||||
|
* @return public URL for sharing uploaded file
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws XMPPException.XMPPErrorException
|
||||||
|
* @throws SmackException
|
||||||
|
* @throws IOException in case of HTTP upload errors
|
||||||
|
*/
|
||||||
|
public URL uploadFile(File file) throws InterruptedException, XMPPException.XMPPErrorException,
|
||||||
|
SmackException, IOException {
|
||||||
|
return uploadFile(file, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback interface to get upload progress.
|
||||||
|
*/
|
||||||
|
public interface UploadProgressListener {
|
||||||
|
/**
|
||||||
|
* Callback for displaying upload progress.
|
||||||
|
*
|
||||||
|
* @param uploadedBytes - number of bytes uploaded at the moment
|
||||||
|
* @param totalBytes - total number of bytes to be uploaded
|
||||||
|
*/
|
||||||
|
void onUploadProgress(long uploadedBytes, long totalBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request slot and uploaded file to HTTP file upload service with progress callback.
|
||||||
|
*
|
||||||
|
* You don't need to request slot and upload file separately, this method will do both.
|
||||||
|
* Note that this is a synchronous call -- Smack must wait for the server response.
|
||||||
|
*
|
||||||
|
* @param file file to be uploaded
|
||||||
|
* @param listener upload progress listener of null
|
||||||
|
* @return public URL for sharing uploaded file
|
||||||
|
*
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws XMPPException.XMPPErrorException
|
||||||
|
* @throws SmackException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public URL uploadFile(File file, UploadProgressListener listener) throws InterruptedException,
|
||||||
|
XMPPException.XMPPErrorException, SmackException, IOException {
|
||||||
|
final Slot slot = requestSlot(file.getName(), file.length(), "application/octet-stream");
|
||||||
|
|
||||||
|
uploadFile(file, slot.getPutUrl(), listener);
|
||||||
|
|
||||||
|
return slot.getGetUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request a new upload slot from default upload service (if discovered).
|
||||||
|
*
|
||||||
|
* When you get slot you should upload file to PUT URL and share GET URL.
|
||||||
|
* Note that this is a synchronous call -- Smack must wait for the server response.
|
||||||
|
*
|
||||||
|
* @param filename name of file to be uploaded
|
||||||
|
* @param fileSize file size in bytes -- must be less or equal
|
||||||
|
* to {@link HttpFileUploadManager#getMaxFileSize()} (if available)
|
||||||
|
* @return file upload Slot in case of success
|
||||||
|
|
||||||
|
* @throws IllegalArgumentException if fileSize is less than or equal to zero
|
||||||
|
* or greater than {@link HttpFileUploadManager#getMaxFileSize()}
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws XMPPException.XMPPErrorException
|
||||||
|
* @throws SmackException.NotConnectedException
|
||||||
|
* @throws SmackException.NoResponseException
|
||||||
|
*/
|
||||||
|
public Slot requestSlot(String filename, long fileSize) throws InterruptedException,
|
||||||
|
XMPPException.XMPPErrorException, SmackException {
|
||||||
|
return requestSlot(filename, fileSize, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request a new upload slot with optional content type from default upload service (if discovered).
|
||||||
|
*
|
||||||
|
* When you get slot you should upload file to PUT URL and share GET URL.
|
||||||
|
* Note that this is a synchronous call -- Smack must wait for the server response.
|
||||||
|
*
|
||||||
|
* @param filename name of file to be uploaded
|
||||||
|
* @param fileSize file size in bytes -- must be less or equal
|
||||||
|
* to {@link HttpFileUploadManager#getMaxFileSize()} (if available)
|
||||||
|
* @param contentType file content-type or null
|
||||||
|
* @return file upload Slot in case of success
|
||||||
|
|
||||||
|
* @throws IllegalArgumentException if fileSize is less than or equal to zero
|
||||||
|
* or greater than {@link HttpFileUploadManager#getMaxFileSize()}
|
||||||
|
* @throws SmackException.NotConnectedException
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws XMPPException.XMPPErrorException
|
||||||
|
* @throws SmackException.NoResponseException
|
||||||
|
*/
|
||||||
|
public Slot requestSlot(String filename, long fileSize, String contentType) throws SmackException,
|
||||||
|
InterruptedException, XMPPException.XMPPErrorException {
|
||||||
|
return requestSlot(filename, fileSize, contentType, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request a new upload slot with optional content type from custom upload service.
|
||||||
|
*
|
||||||
|
* When you get slot you should upload file to PUT URL and share GET URL.
|
||||||
|
* Note that this is a synchronous call -- Smack must wait for the server response.
|
||||||
|
*
|
||||||
|
* @param filename name of file to be uploaded
|
||||||
|
* @param fileSize file size in bytes -- must be less or equal
|
||||||
|
* to {@link HttpFileUploadManager#getMaxFileSize()} (if available)
|
||||||
|
* @param contentType file content-type or null
|
||||||
|
* @param uploadService upload service to use or null for default one
|
||||||
|
* @return file upload Slot in case of success
|
||||||
|
* @throws IllegalArgumentException if fileSize is less than or equal to zero
|
||||||
|
* or greater than {@link HttpFileUploadManager#getMaxFileSize()}
|
||||||
|
* @throws SmackException
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws XMPPException.XMPPErrorException
|
||||||
|
*/
|
||||||
|
public Slot requestSlot(String filename, long fileSize, String contentType, DomainBareJid uploadService)
|
||||||
|
throws SmackException, InterruptedException, XMPPException.XMPPErrorException {
|
||||||
|
if (defaultUploadService == null && uploadService == null) {
|
||||||
|
throw new SmackException("No upload service specified or discovered.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uploadService == null && maxFileSize != null) {
|
||||||
|
if (fileSize > maxFileSize) {
|
||||||
|
throw new IllegalArgumentException("Requested file size " + fileSize
|
||||||
|
+ " is greater than max allowed size " + maxFileSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SlotRequest slotRequest = new SlotRequest(filename, fileSize, contentType);
|
||||||
|
if (uploadService != null) {
|
||||||
|
slotRequest.setTo(uploadService);
|
||||||
|
} else {
|
||||||
|
slotRequest.setTo(defaultUploadService);
|
||||||
|
}
|
||||||
|
|
||||||
|
return connection().createStanzaCollectorAndSend(slotRequest).nextResultOrThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void uploadFile(File file, URL putUrl, UploadProgressListener listener) throws IOException {
|
||||||
|
final HttpURLConnection urlConnection = (HttpURLConnection) putUrl.openConnection();
|
||||||
|
urlConnection.setRequestMethod("PUT");
|
||||||
|
urlConnection.setUseCaches(false);
|
||||||
|
urlConnection.setDoOutput(true);
|
||||||
|
urlConnection.setRequestProperty("Content-Type", "application/octet-stream;");
|
||||||
|
OutputStream outputStream = urlConnection.getOutputStream();
|
||||||
|
|
||||||
|
long bytesSend = 0;
|
||||||
|
|
||||||
|
long fileSize = file.length();
|
||||||
|
if (listener != null) {
|
||||||
|
listener.onUploadProgress(0, fileSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(file));
|
||||||
|
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int bytesRead;
|
||||||
|
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||||
|
outputStream.write(buffer, 0, bytesRead);
|
||||||
|
outputStream.flush();
|
||||||
|
bytesSend += bytesRead;
|
||||||
|
|
||||||
|
if (listener != null) {
|
||||||
|
listener.onUploadProgress(bytesSend, fileSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inputStream.close();
|
||||||
|
outputStream.close();
|
||||||
|
|
||||||
|
int status = urlConnection.getResponseCode();
|
||||||
|
if (status != HttpURLConnection.HTTP_CREATED) {
|
||||||
|
throw new IOException("Error response from server during file upload:"
|
||||||
|
+ " " + urlConnection.getResponseCode()
|
||||||
|
+ " " + urlConnection.getResponseMessage()
|
||||||
|
+ ", file size: " + fileSize
|
||||||
|
+ ", put URL: " + putUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2017 Grigory Fedorov
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.httpfileupload.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.ExtensionElement;
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smack.packet.XMPPError;
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File Too Large error extension.
|
||||||
|
*
|
||||||
|
* @author Grigory Fedorov
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0363.html">XEP-0363: HTTP File Upload</a>
|
||||||
|
*/
|
||||||
|
public class FileTooLargeError implements ExtensionElement {
|
||||||
|
public static final String ELEMENT = "file-too-large";
|
||||||
|
public static final String NAMESPACE = SlotRequest.NAMESPACE;
|
||||||
|
|
||||||
|
private final long maxFileSize;
|
||||||
|
|
||||||
|
public FileTooLargeError(long maxFileSize) {
|
||||||
|
this.maxFileSize = maxFileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getMaxFileSize() {
|
||||||
|
return maxFileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return ELEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNamespace() {
|
||||||
|
return NAMESPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder(this);
|
||||||
|
xml.rightAngleBracket();
|
||||||
|
xml.element("max-file-size", String.valueOf(maxFileSize));
|
||||||
|
xml.closeElement(ELEMENT);
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FileTooLargeError from(IQ iq) {
|
||||||
|
XMPPError error = iq.getError();
|
||||||
|
if (error == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return error.getExtension(ELEMENT, NAMESPACE);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2017 Grigory Fedorov
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.httpfileupload.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Slot responded by upload service.
|
||||||
|
*
|
||||||
|
* @author Grigory Fedorov
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0363.html">XEP-0363: HTTP File Upload</a>
|
||||||
|
*/
|
||||||
|
public class Slot extends IQ {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "slot";
|
||||||
|
public static final String NAMESPACE = SlotRequest.NAMESPACE;
|
||||||
|
|
||||||
|
private final URL putUrl;
|
||||||
|
private final URL getUrl;
|
||||||
|
|
||||||
|
public Slot(URL putUrl, URL getUrl) {
|
||||||
|
super(ELEMENT, NAMESPACE);
|
||||||
|
setType(Type.result);
|
||||||
|
this.putUrl = putUrl;
|
||||||
|
this.getUrl = getUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public URL getPutUrl() {
|
||||||
|
return putUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public URL getGetUrl() {
|
||||||
|
return getUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
||||||
|
xml.rightAngleBracket();
|
||||||
|
|
||||||
|
xml.element("put", putUrl.toString());
|
||||||
|
xml.element("get", getUrl.toString());
|
||||||
|
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2017 Grigory Fedorov
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.httpfileupload.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload slot request.
|
||||||
|
|
||||||
|
* @author Grigory Fedorov
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0363.html">XEP-0363: HTTP File Upload</a>
|
||||||
|
*/
|
||||||
|
public class SlotRequest extends IQ {
|
||||||
|
public static final String ELEMENT = "request";
|
||||||
|
public static final String NAMESPACE = "urn:xmpp:http:upload";
|
||||||
|
|
||||||
|
private final String filename;
|
||||||
|
private final long size;
|
||||||
|
private final String contentType;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create new slot request.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if size is less than or equal to zero
|
||||||
|
* @param filename name of file
|
||||||
|
* @param size size of file in bytes
|
||||||
|
* @param contentType file content type or null
|
||||||
|
*/
|
||||||
|
public SlotRequest(String filename, long size, String contentType) {
|
||||||
|
super(ELEMENT, NAMESPACE);
|
||||||
|
|
||||||
|
if (size <= 0) {
|
||||||
|
throw new IllegalArgumentException("File fileSize must be greater than zero.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.filename = filename;
|
||||||
|
this.size = size;
|
||||||
|
this.contentType = contentType;
|
||||||
|
|
||||||
|
setType(Type.get);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SlotRequest(String filename, long size) {
|
||||||
|
this(filename, size, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFilename() {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentType() {
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
||||||
|
xml.rightAngleBracket();
|
||||||
|
xml.element("filename", filename);
|
||||||
|
xml.element("size", String.valueOf(size));
|
||||||
|
if (contentType != null) {
|
||||||
|
xml.element("content-type", contentType);
|
||||||
|
}
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2017 Grigory Fedorov
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IQ stanzas and extensions for XEP-0363: HTTP File Upload.
|
||||||
|
*
|
||||||
|
* @author Grigory Fedorov
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0363.html">XEP-0363: HTTP File Upload</a>
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.httpfileupload.element;
|
|
@ -0,0 +1,24 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2017 Grigory Fedorov
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smack's API for XEP-0363: HTTP File Upload.
|
||||||
|
*
|
||||||
|
* @author Grigory Fedorov
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0363.html">XEP-0363: HTTP File Upload</a>
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.httpfileupload;
|
|
@ -0,0 +1,57 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2017 Grigory Fedorov
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.httpfileupload.provider;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.provider.ExtensionElementProvider;
|
||||||
|
import org.jivesoftware.smackx.httpfileupload.element.FileTooLargeError;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider for File Too Large error extension.
|
||||||
|
*
|
||||||
|
* @author Grigory Fedorov
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0363.html">XEP-0363: HTTP File Upload</a>
|
||||||
|
*/
|
||||||
|
public class FileTooLargeErrorProvider extends ExtensionElementProvider<FileTooLargeError> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileTooLargeError parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
Long maxFileSize = null;
|
||||||
|
|
||||||
|
outerloop: while(true) {
|
||||||
|
int event = parser.next();
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case XmlPullParser.START_TAG:
|
||||||
|
String name = parser.getName();
|
||||||
|
switch(name) {
|
||||||
|
case "max-file-size":
|
||||||
|
maxFileSize = Long.valueOf(parser.nextText());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XmlPullParser.END_TAG:
|
||||||
|
if (parser.getDepth() == initialDepth) {
|
||||||
|
break outerloop;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new FileTooLargeError(maxFileSize);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2017 Grigory Fedorov
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.httpfileupload.provider;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.SmackException;
|
||||||
|
import org.jivesoftware.smack.provider.IQProvider;
|
||||||
|
import org.jivesoftware.smackx.httpfileupload.element.Slot;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider for Slot.
|
||||||
|
*
|
||||||
|
* @author Grigory Fedorov
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0363.html">XEP-0363: HTTP File Upload</a>
|
||||||
|
*/
|
||||||
|
public class SlotProvider extends IQProvider<Slot> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Slot parse(XmlPullParser parser, int initialDepth) throws XmlPullParserException, IOException, SmackException {
|
||||||
|
URL putUrl = null;
|
||||||
|
URL getUrl = null;
|
||||||
|
|
||||||
|
outerloop: while (true) {
|
||||||
|
int event = parser.next();
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case XmlPullParser.START_TAG:
|
||||||
|
String name = parser.getName();
|
||||||
|
switch(name) {
|
||||||
|
case "put":
|
||||||
|
putUrl = new URL(parser.nextText());
|
||||||
|
break;
|
||||||
|
case "get":
|
||||||
|
getUrl = new URL(parser.nextText());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XmlPullParser.END_TAG:
|
||||||
|
if (parser.getDepth() == initialDepth) {
|
||||||
|
break outerloop;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Slot(putUrl, getUrl);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2017 Grigory Fedorov
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Providers for XEP-0363: HTTP File Upload.
|
||||||
|
*
|
||||||
|
* @author Grigory Fedorov
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0363.html">XEP-0363: HTTP File Upload</a>
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.httpfileupload.provider;
|
|
@ -233,4 +233,16 @@
|
||||||
<className>org.jivesoftware.smackx.chat_markers.provider.AcknowledgedProvider</className>
|
<className>org.jivesoftware.smackx.chat_markers.provider.AcknowledgedProvider</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0363: HTTP File Upload -->
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>slot</elementName>
|
||||||
|
<namespace>urn:xmpp:http:upload</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.httpfileupload.provider.SlotProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>file-too-large</elementName>
|
||||||
|
<namespace>urn:xmpp:http:upload</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.httpfileupload.provider.FileTooLargeErrorProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
</smackProviders>
|
</smackProviders>
|
||||||
|
|
|
@ -4,5 +4,6 @@
|
||||||
<className>org.jivesoftware.smackx.iot.data.IoTDataManager</className>
|
<className>org.jivesoftware.smackx.iot.data.IoTDataManager</className>
|
||||||
<className>org.jivesoftware.smackx.iot.discovery.IoTDiscoveryManager</className>
|
<className>org.jivesoftware.smackx.iot.discovery.IoTDiscoveryManager</className>
|
||||||
<className>org.jivesoftware.smackx.iot.provisioning.IoTProvisioningManager</className>
|
<className>org.jivesoftware.smackx.iot.provisioning.IoTProvisioningManager</className>
|
||||||
|
<className>org.jivesoftware.smackx.httpfileupload.HttpFileUploadManager</className>
|
||||||
</startupClasses>
|
</startupClasses>
|
||||||
</smack>
|
</smack>
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2017 Grigory Fedorov
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.httpfileupload;
|
||||||
|
|
||||||
|
|
||||||
|
import org.jivesoftware.smackx.httpfileupload.element.FileTooLargeError;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class FileTooLargeErrorCreateTest {
|
||||||
|
String fileTooLargeErrorExtensionExample
|
||||||
|
= "<file-too-large xmlns='urn:xmpp:http:upload'>"
|
||||||
|
+ "<max-file-size>20000</max-file-size>"
|
||||||
|
+ "</file-too-large>";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkFileTooLargeErrorExtensionCreation() {
|
||||||
|
FileTooLargeError fileTooLargeError = new FileTooLargeError(20000);
|
||||||
|
|
||||||
|
Assert.assertEquals(20000, fileTooLargeError.getMaxFileSize());
|
||||||
|
Assert.assertEquals(fileTooLargeErrorExtensionExample, fileTooLargeError.toXML().toString());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2017 Grigory Fedorov
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.httpfileupload;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||||
|
import org.jivesoftware.smackx.httpfileupload.element.FileTooLargeError;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class FileTooLargeErrorProviderTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example 7. Alternative response by the upload service if the file size was too large
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0363.html#errors">XEP-0363: HTTP File Upload 5. Error conditions</a>
|
||||||
|
*/
|
||||||
|
String slotErrorFileToLarge
|
||||||
|
= "<iq from='upload.montague.tld' "
|
||||||
|
+ "id='step_03' "
|
||||||
|
+ "to='romeo@montague.tld/garden' "
|
||||||
|
+ "type='error'>"
|
||||||
|
+ "<request xmlns='urn:xmpp:http:upload'>"
|
||||||
|
+ "<filename>my_juliet.png</filename>"
|
||||||
|
+ "<size>23456</size>"
|
||||||
|
+ "</request>"
|
||||||
|
+ "<error type='modify'>"
|
||||||
|
+ "<not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' />"
|
||||||
|
+ "<text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>File too large. The maximum file size is 20000 bytes</text>"
|
||||||
|
+ "<file-too-large xmlns='urn:xmpp:http:upload'>"
|
||||||
|
+ "<max-file-size>20000</max-file-size>"
|
||||||
|
+ "</file-too-large>"
|
||||||
|
+ "</error>"
|
||||||
|
+ "</iq>";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkSlotErrorFileToLarge() throws Exception {
|
||||||
|
IQ fileTooLargeErrorIQ = PacketParserUtils.parseStanza(slotErrorFileToLarge);
|
||||||
|
|
||||||
|
Assert.assertEquals(IQ.Type.error, fileTooLargeErrorIQ.getType());
|
||||||
|
|
||||||
|
FileTooLargeError fileTooLargeError = FileTooLargeError.from(fileTooLargeErrorIQ);
|
||||||
|
Assert.assertEquals(20000, fileTooLargeError.getMaxFileSize());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2017 Grigory Fedorov
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.httpfileupload;
|
||||||
|
|
||||||
|
|
||||||
|
import org.jivesoftware.smackx.httpfileupload.element.Slot;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
public class SlotCreateTest {
|
||||||
|
String testSlot
|
||||||
|
= "<slot xmlns='urn:xmpp:http:upload'>"
|
||||||
|
+ "<put>https://upload.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my_juliet.png</put>"
|
||||||
|
+ "<get>https://download.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my_juliet.png</get>"
|
||||||
|
+ "</slot>";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkSlotRequestCreation() throws MalformedURLException {
|
||||||
|
Slot slot = new Slot(new URL("https://upload.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my_juliet.png"),
|
||||||
|
new URL("https://download.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my_juliet.png"));
|
||||||
|
|
||||||
|
Assert.assertEquals(new URL("https://upload.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my_juliet.png"),
|
||||||
|
slot.getPutUrl());
|
||||||
|
Assert.assertEquals(new URL("https://download.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my_juliet.png"),
|
||||||
|
slot.getGetUrl());
|
||||||
|
|
||||||
|
Assert.assertEquals(testSlot, slot.getChildElementXML().toString());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2017 Grigory Fedorov
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.httpfileupload;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||||
|
import org.jivesoftware.smackx.httpfileupload.element.Slot;
|
||||||
|
import org.jivesoftware.smackx.httpfileupload.provider.SlotProvider;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
|
||||||
|
public class SlotProviderTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example 6. The upload service responds with a slot
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0363.html#request">XEP-0363: HTTP File Upload 4. Requesting a slot</a>
|
||||||
|
*/
|
||||||
|
String slotExample
|
||||||
|
= "<iq from='upload.montague.tld' "
|
||||||
|
+ "id='step_03' "
|
||||||
|
+ "to='romeo@montague.tld/garden' "
|
||||||
|
+ "type='result'>"
|
||||||
|
+ "<slot xmlns='urn:xmpp:http:upload'>"
|
||||||
|
+ "<put>https://upload.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my_juliet.png</put>"
|
||||||
|
+ "<get>https://download.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my_juliet.png</get>"
|
||||||
|
+ "</slot>"
|
||||||
|
+ "</iq>";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkSlotProvider() throws Exception {
|
||||||
|
XmlPullParser parser = PacketParserUtils.getParserFor(slotExample);
|
||||||
|
Slot slot = new SlotProvider().parse(parser);
|
||||||
|
|
||||||
|
Assert.assertEquals(IQ.Type.result, slot.getType());
|
||||||
|
Assert.assertEquals(new URL("https://upload.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my_juliet.png"),
|
||||||
|
slot.getPutUrl());
|
||||||
|
Assert.assertEquals(new URL("https://download.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my_juliet.png"),
|
||||||
|
slot.getGetUrl());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2017 Grigory Fedorov
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.httpfileupload;
|
||||||
|
|
||||||
|
import org.jivesoftware.smackx.httpfileupload.element.SlotRequest;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.jxmpp.stringprep.XmppStringprepException;
|
||||||
|
|
||||||
|
|
||||||
|
public class SlotRequestCreateTest {
|
||||||
|
|
||||||
|
String testRequest
|
||||||
|
= "<request xmlns='urn:xmpp:http:upload'>"
|
||||||
|
+ "<filename>my_juliet.png</filename>"
|
||||||
|
+ "<size>23456</size>"
|
||||||
|
+ "<content-type>image/jpeg</content-type>"
|
||||||
|
+ "</request>";
|
||||||
|
|
||||||
|
String testRequestWithoutContentType
|
||||||
|
= "<request xmlns='urn:xmpp:http:upload'>"
|
||||||
|
+ "<filename>my_romeo.png</filename>"
|
||||||
|
+ "<size>52523</size>"
|
||||||
|
+ "</request>";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkSlotRequestCreation() throws XmppStringprepException {
|
||||||
|
SlotRequest slotRequest = new SlotRequest("my_juliet.png", 23456, "image/jpeg");
|
||||||
|
|
||||||
|
Assert.assertEquals("my_juliet.png", slotRequest.getFilename());
|
||||||
|
Assert.assertEquals(23456, slotRequest.getSize());
|
||||||
|
Assert.assertEquals("image/jpeg", slotRequest.getContentType());
|
||||||
|
|
||||||
|
Assert.assertEquals(testRequest, slotRequest.getChildElementXML().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkSlotRequestCreationWithoutContentType() throws XmppStringprepException {
|
||||||
|
SlotRequest slotRequest = new SlotRequest("my_romeo.png", 52523);
|
||||||
|
|
||||||
|
Assert.assertEquals("my_romeo.png", slotRequest.getFilename());
|
||||||
|
Assert.assertEquals(52523, slotRequest.getSize());
|
||||||
|
Assert.assertEquals(null, slotRequest.getContentType());
|
||||||
|
|
||||||
|
Assert.assertEquals(testRequestWithoutContentType, slotRequest.getChildElementXML().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void checkSlotRequestCreationNegativeSize() {
|
||||||
|
new SlotRequest("my_juliet.png", -23456, "image/jpeg");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void checkSlotRequestCreationZeroSize() {
|
||||||
|
new SlotRequest("my_juliet.png", 0, "image/jpeg");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue