You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2008/01/17 16:19:09 UTC
svn commit: r612842 - in /incubator/sling/trunk/usling:
usling-servlets/src/main/java/org/apache/sling/ujax/
usling-webapp/src/test/java/org/apache/sling/usling/webapp/integrationtest/
usling-webapp/src/test/java/org/apache/sling/usling/webapp/integrat...
Author: bdelacretaz
Date: Thu Jan 17 07:18:10 2008
New Revision: 612842
URL: http://svn.apache.org/viewvc?rev=612842&view=rev
Log:
SLING-168, file upload support for UjaxPostServlet, contributed by Tobias Bocanegra, thanks!
Added:
incubator/sling/trunk/usling/usling-servlets/src/main/java/org/apache/sling/ujax/UjaxFileUploadHandler.java (with props)
incubator/sling/trunk/usling/usling-webapp/src/test/java/org/apache/sling/usling/webapp/integrationtest/UploadFileTest.java (with props)
incubator/sling/trunk/usling/usling-webapp/src/test/resources/integration-test/file-to-upload.txt (with props)
Modified:
incubator/sling/trunk/usling/usling-servlets/src/main/java/org/apache/sling/ujax/UjaxPostServlet.java
incubator/sling/trunk/usling/usling-webapp/src/test/java/org/apache/sling/usling/webapp/integrationtest/helpers/UslingIntegrationTestClient.java
Added: incubator/sling/trunk/usling/usling-servlets/src/main/java/org/apache/sling/ujax/UjaxFileUploadHandler.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/usling/usling-servlets/src/main/java/org/apache/sling/ujax/UjaxFileUploadHandler.java?rev=612842&view=auto
==============================================================================
--- incubator/sling/trunk/usling/usling-servlets/src/main/java/org/apache/sling/ujax/UjaxFileUploadHandler.java (added)
+++ incubator/sling/trunk/usling/usling-servlets/src/main/java/org/apache/sling/ujax/UjaxFileUploadHandler.java Thu Jan 17 07:18:10 2008
@@ -0,0 +1,188 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.sling.ujax;
+
+import org.apache.sling.api.request.RequestParameter;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.commons.mime.MimeTypeService;
+import org.apache.jackrabbit.util.Text;
+
+import java.util.Calendar;
+import java.io.IOException;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.nodetype.NodeType;
+
+/**
+ * Handles file uploads.
+ * <p/>
+ *
+ * Simple example:
+ * <xmp>
+ * <form action="/home/admin" method="POST" enctype="multipart/form-data">
+ * <input type="file" name="./portrait" />
+ * </form>
+ * </xmp>
+ *
+ * this will create a nt:file node below "/home/admin" if the node type of
+ * "admin" is (derived from) nt:folder, a nt:resource node otherwise.
+ * <p/>
+ *
+ * Filename example:
+ * <xmp>
+ * <form action="/home/admin" method="POST" enctype="multipart/form-data">
+ * <input type="file" name="./*" />
+ * </form>
+ * </xmp>
+ *
+ * same as above, but uses the filename of the uploaded file as name for the
+ * new node.
+ * <p/>
+ *
+ * Type hint example:
+ * <xmp>
+ * <form action="/home/admin" method="POST" enctype="multipart/form-data">
+ * <input type="file" name="./portrait" />
+ * <input type="hidden" name="./portrait@TypeHint" value="my:file" />
+ * </form>
+ * </xmp>
+ *
+ * this will create a new node with the type my:file below admin. if the hinted
+ * type extends from nt:file an intermediate file node is created otherwise
+ * directly a resource node.
+ *
+ * @version $Rev$, $Date$
+ */
+public class UjaxFileUploadHandler {
+
+ /**
+ * The CVS/SVN id
+ */
+ static final String CVS_ID = "$URL$ $Rev$ $Date$";
+
+ // nodetype name string constants
+ public static final String NT_FOLDER = "nt:folder";
+ public static final String NT_FILE = "nt:file";
+ public static final String NT_RESOURCE = "nt:resource";
+
+ // item name string constants
+ public static final String JCR_CONTENT = "jcr:content";
+ public static final String JCR_LASTMODIFIED = "jcr:lastModified";
+ public static final String JCR_MIMETYPE = "jcr:mimeType";
+ public static final String JCR_ENCODING = "jcr:encoding";
+ public static final String JCR_DATA = "jcr:data";
+
+ /**
+ * Uses the file(s) in the request parameter for creation of new nodes.
+ * if the parent node is a nt:folder a new nt:file is created. otherwise
+ * just a nt:resource. if the <code>name</code> is '*', the filename of
+ * the uploaded file is used.
+ *
+ * @param request the servlet request
+ * @param parent the parent node
+ * @param name the name of the file/resource node or '*'
+ * @param values the request values
+ * @param typeHint a hint for the node type
+ * @throws RepositoryException if an error occurs
+ */
+ void setFile(SlingHttpServletRequest request, Node parent, String name,
+ RequestParameter[] values, String typeHint)
+ throws RepositoryException {
+ RequestParameter value = values[0];
+ assert !value.isFormField();
+
+ // ignore if empty
+ if (value.getSize() <= 0) {
+ return;
+ }
+
+ // get node name
+ if (name.equals("*")) {
+ name = value.getFileName();
+ // strip of possible path (some browsers include the entire path)
+ name = name.substring(name.lastIndexOf('/') + 1);
+ name = name.substring(name.lastIndexOf('\\') + 1);
+ }
+ name = Text.escapeIllegalJcrChars(name);
+
+ // check type hint. if the type is ok and extends from nt:file,
+ // create an nt:file with that type. if it's invalid, drop it and let
+ // the parent node type decide.
+ boolean createNtFile = parent.isNodeType(NT_FOLDER);
+ if (typeHint != null) {
+ try {
+ NodeTypeManager ntMgr = parent.getSession().getWorkspace().getNodeTypeManager();
+ NodeType nt = ntMgr.getNodeType(typeHint);
+ createNtFile = nt.isNodeType(NT_FILE);
+ } catch (RepositoryException e) {
+ // assuming type not valid.
+ typeHint = null;
+ }
+ }
+
+ // set empty type
+ if (typeHint == null) {
+ typeHint = createNtFile ? NT_FILE : NT_RESOURCE;
+ }
+
+ // remove node
+ if (parent.hasNode(name)) {
+ parent.getNode(name).remove();
+ }
+
+ // create nt:file node if needed
+ if (createNtFile) {
+ // create nt:file
+ parent = parent.addNode(name, typeHint);
+ name = JCR_CONTENT;
+ typeHint = NT_RESOURCE;
+ }
+
+ // create resource node
+ Node res = parent.addNode(name, typeHint);
+
+ // get content type
+ String contentType = value.getContentType();
+ if (contentType != null) {
+ int idx = contentType.indexOf(';');
+ if (idx > 0) {
+ contentType = contentType.substring(0, idx);
+ }
+ }
+ if (contentType == null || contentType.equals("application/octet-stream")) {
+ // try to find a better content type
+ MimeTypeService svc = request.getServiceLocator().getService(MimeTypeService.class);
+ if (svc != null) {
+ contentType = svc.getMimeType(value.getFileName());
+ }
+ if (contentType == null || contentType.equals("application/octet-stream")) {
+ contentType = "application/octet-stream";
+ }
+ }
+
+ // set properties
+ res.setProperty(JCR_LASTMODIFIED, Calendar.getInstance());
+ res.setProperty(JCR_MIMETYPE, contentType);
+ try {
+ res.setProperty(JCR_DATA, value.getInputStream());
+ } catch (IOException e) {
+ throw new RepositoryException("Error while retrieving inputstream from parameter value.", e);
+ }
+ }
+}
\ No newline at end of file
Propchange: incubator/sling/trunk/usling/usling-servlets/src/main/java/org/apache/sling/ujax/UjaxFileUploadHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/sling/trunk/usling/usling-servlets/src/main/java/org/apache/sling/ujax/UjaxFileUploadHandler.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision Rev URL
Modified: incubator/sling/trunk/usling/usling-servlets/src/main/java/org/apache/sling/ujax/UjaxPostServlet.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/usling/usling-servlets/src/main/java/org/apache/sling/ujax/UjaxPostServlet.java?rev=612842&r1=612841&r2=612842&view=diff
==============================================================================
--- incubator/sling/trunk/usling/usling-servlets/src/main/java/org/apache/sling/ujax/UjaxPostServlet.java (original)
+++ incubator/sling/trunk/usling/usling-servlets/src/main/java/org/apache/sling/ujax/UjaxPostServlet.java Thu Jan 17 07:18:10 2008
@@ -47,6 +47,7 @@
private static final Logger log = LoggerFactory.getLogger(UjaxPostServlet.class);
private final UjaxPropertyValueSetter propertyValueSetter = new UjaxPropertyValueSetter();
+ private final UjaxFileUploadHandler uploadHandler = new UjaxFileUploadHandler();
private final NodeNameGenerator nodeNameGenerator = new NodeNameGenerator();
/** Prefix for parameter names which control this POST
@@ -85,6 +86,8 @@
/** SLING-130, suffix that maps form field names to different JCR property names */
public static final String VALUE_FROM_SUFFIX = "@ValueFrom";
+ public static final String TYPE_HINT_SUFFIX = "@TypeHint";
+
@Override
protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response)
throws ServletException, IOException {
@@ -263,7 +266,6 @@
}
/** Set Node properties from current request
- * TODO should handle file uploads as well
*/
private void setPropertiesFromRequest(Node n, SlingHttpServletRequest request,
String savePrefix, Set<Node> createdNodes)
@@ -284,7 +286,12 @@
}
propertyName = paramName.substring(savePrefix.length());
}
-
+
+ // ignore field with a '@TypeHint' suffix. this is dealt in setProperty()
+ if (propertyName.endsWith(TYPE_HINT_SUFFIX)) {
+ continue;
+ }
+
// SLING-130: VALUE_FROM_SUFFIX means take the value of this
// property from a different field
RequestParameter[] values = e.getValue();
@@ -306,15 +313,24 @@
continue;
}
}
-
- setProperty(n,request,propertyName,values,createdNodes);
+
+ // @TypeHint example
+ // <input type="text" name="./age" />
+ // <input type="hidden" name="./age@TypeHint" value="long" />
+ // causes the setProperty using the 'long' property type
+ final String thName = e.getKey() + TYPE_HINT_SUFFIX;
+ final RequestParameter rp = request.getRequestParameter(thName);
+ final String typeHint = rp == null ? null : rp.getString();
+ setProperty(n, request, propertyName, values, createdNodes, typeHint);
}
}
/** Set a single Property on node N
* @throws RepositoryException */
- private void setProperty(Node n, SlingHttpServletRequest request, String name,
- RequestParameter[] values, Set<Node> createdNodes) throws RepositoryException {
+ private void setProperty(Node n, SlingHttpServletRequest request,
+ String name, RequestParameter[] values,
+ Set<Node> createdNodes, String typeHint)
+ throws RepositoryException {
// split the relative path identifying the property to be saved
String proppath = name;
@@ -356,10 +372,12 @@
parent = (Node) s.getItem(path);
}
- // TODO String typehint = request.getParameter(proppath + "@TypeHint");
- final String typeHint = null;
- final boolean nodeIsNew = createdNodes.contains(parent);
- propertyValueSetter.setProperty(parent, propname, values, typeHint, nodeIsNew);
+ if (values[0].isFormField()) {
+ final boolean nodeIsNew = createdNodes.contains(parent);
+ propertyValueSetter.setProperty(parent, propname, values, typeHint, nodeIsNew);
+ } else {
+ uploadHandler.setFile(request, parent, propname, values, typeHint);
+ }
}
/**
Added: incubator/sling/trunk/usling/usling-webapp/src/test/java/org/apache/sling/usling/webapp/integrationtest/UploadFileTest.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/usling/usling-webapp/src/test/java/org/apache/sling/usling/webapp/integrationtest/UploadFileTest.java?rev=612842&view=auto
==============================================================================
--- incubator/sling/trunk/usling/usling-webapp/src/test/java/org/apache/sling/usling/webapp/integrationtest/UploadFileTest.java (added)
+++ incubator/sling/trunk/usling/usling-webapp/src/test/java/org/apache/sling/usling/webapp/integrationtest/UploadFileTest.java Thu Jan 17 07:18:10 2008
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.sling.usling.webapp.integrationtest;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.commons.httpclient.methods.GetMethod;
+
+/**
+ * Test uploading files using the ujax post servlet (SLING-168)
+ */
+public class UploadFileTest extends UslingHttpTestBase {
+
+ private static final String TEST_FILE = "src/test/resources/integration-test/file-to-upload.txt";
+
+ public void testDistinctResource() throws IOException {
+ String folderPath = "/UploadFileTest_1_" + System.currentTimeMillis();
+ final String url = HTTP_BASE_URL + folderPath;
+
+ // create new node
+ String urlOfNewNode = null;
+ try {
+ urlOfNewNode = testClient.createNode(url, null);
+ } catch(IOException ioe) {
+ fail("createNode failed: " + ioe);
+ }
+
+ // upload local file
+ File localFile = new File(TEST_FILE);
+ testClient.uploadToFileNode(urlOfNewNode, localFile, "./file", null);
+
+ // get and check URL of created file
+ String urlOfFileNode = urlOfNewNode + "/file";
+ final GetMethod get = new GetMethod(urlOfFileNode);
+ final int status = httpClient.executeMethod(get);
+ assertEquals(urlOfFileNode + " must be accessible after createNode",200,status);
+
+ /*
+ We should check the data, but nt:resources are not handled yet
+ // compare data with local file (just length)
+ final byte[] data = get.getResponseBody();
+ assertEquals("size of file must be same", localFile.length(), data.length);
+ */
+ String data = get.getResponseBodyAsString();
+ assertTrue("checking for content", data.contains("http://www.apache.org/licenses/LICENSE-2.0"));
+
+ // download structure
+ String json = getContent(urlOfFileNode + ".json", CONTENT_TYPE_JSON);
+ // just check for some strings
+ assertTrue("checking primary type", json.contains("\"jcr:primaryType\":\"nt:resource\""));
+ assertTrue("checking mime type", json.contains("\"jcr:mimeType\":\"text/plain\""));
+
+ }
+
+ public void testDistinctResourceWithType() throws IOException {
+ String folderPath = "/UploadFileTest_1_" + System.currentTimeMillis();
+ final String url = HTTP_BASE_URL + folderPath;
+
+ // create new node
+ String urlOfNewNode = null;
+ try {
+ urlOfNewNode = testClient.createNode(url, null);
+ } catch(IOException ioe) {
+ fail("createNode failed: " + ioe);
+ }
+
+ // upload local file
+ File localFile = new File(TEST_FILE);
+ testClient.uploadToFileNode(urlOfNewNode, localFile, "./file", "nt:unstructured");
+
+ // get and check URL of created file
+ String urlOfFileNode = urlOfNewNode + "/file";
+ final GetMethod get = new GetMethod(urlOfFileNode);
+ final int status = httpClient.executeMethod(get);
+ assertEquals(urlOfFileNode + " must be accessible after createNode",200,status);
+
+ /*
+ We should check the data, but nt:resources are not handled yet
+ // compare data with local file (just length)
+ final byte[] data = get.getResponseBody();
+ assertEquals("size of file must be same", localFile.length(), data.length);
+ */
+ String data = get.getResponseBodyAsString();
+ assertTrue("checking for content", data.contains("http://www.apache.org/licenses/LICENSE-2.0"));
+
+ // download structure
+ String json = getContent(urlOfFileNode + ".json", CONTENT_TYPE_JSON);
+ // just check for some strings
+ assertTrue("checking primary type", json.contains("\"jcr:primaryType\":\"nt:unstructured\""));
+ assertTrue("checking mime type", json.contains("\"jcr:mimeType\":\"text/plain\""));
+ }
+
+ public void testDistinctFile() throws IOException {
+ String folderPath = "/UploadFileTest_1_" + System.currentTimeMillis();
+ testClient.mkdirs(WEBDAV_BASE_URL, folderPath);
+ final String url = HTTP_BASE_URL + folderPath;
+
+
+ // upload local file
+ File localFile = new File(TEST_FILE);
+ testClient.uploadToFileNode(url, localFile, "./file", null);
+
+ // get and check URL of created file
+ String urlOfFileNode = url + "/file";
+
+ /*
+ TODO: does not work, since no nt:file resource type handler present ???
+
+ final GetMethod get = new GetMethod(urlOfFileNode);
+ final int status = httpClient.executeMethod(get);
+ assertEquals(urlOfFileNode + " must be accessible after createNode",200,status);
+
+ // compare data with local file (just length)
+ final byte[] data = get.getResponseBody();
+ assertEquals("size of file must be same", localFile.length(), data.length);
+ */
+
+ String webdavUrl = WEBDAV_BASE_URL + folderPath + "/file";
+ final GetMethod get = new GetMethod(webdavUrl);
+ final int status = httpClient.executeMethod(get);
+ assertEquals(urlOfFileNode + " must be accessible after createNode",200,status);
+
+ // compare data with local file (just length)
+ final byte[] data = get.getResponseBody();
+ assertEquals("size of file must be same", localFile.length(), data.length);
+
+ // download structure
+ String json = getContent(urlOfFileNode + ".json", CONTENT_TYPE_JSON);
+ // just check for some strings
+ assertTrue("checking primary type", json.contains("\"jcr:primaryType\":\"nt:file\""));
+ }
+
+}
\ No newline at end of file
Propchange: incubator/sling/trunk/usling/usling-webapp/src/test/java/org/apache/sling/usling/webapp/integrationtest/UploadFileTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/sling/trunk/usling/usling-webapp/src/test/java/org/apache/sling/usling/webapp/integrationtest/UploadFileTest.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision Rev URL
Modified: incubator/sling/trunk/usling/usling-webapp/src/test/java/org/apache/sling/usling/webapp/integrationtest/helpers/UslingIntegrationTestClient.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/usling/usling-webapp/src/test/java/org/apache/sling/usling/webapp/integrationtest/helpers/UslingIntegrationTestClient.java?rev=612842&r1=612841&r2=612842&view=diff
==============================================================================
--- incubator/sling/trunk/usling/usling-webapp/src/test/java/org/apache/sling/usling/webapp/integrationtest/helpers/UslingIntegrationTestClient.java (original)
+++ incubator/sling/trunk/usling/usling-webapp/src/test/java/org/apache/sling/usling/webapp/integrationtest/helpers/UslingIntegrationTestClient.java Thu Jan 17 07:18:10 2008
@@ -18,6 +18,7 @@
import java.io.IOException;
import java.io.InputStream;
+import java.io.File;
import java.util.Map;
import org.apache.commons.httpclient.HttpClient;
@@ -29,6 +30,8 @@
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.methods.multipart.StringPart;
+import org.apache.commons.httpclient.methods.multipart.FilePart;
+import org.apache.sling.usling.webapp.integrationtest.UslingHttpTestBase;
/** Client functions to interact with microsling in integration tests */
public class UslingIntegrationTestClient {
@@ -130,7 +133,37 @@
if(status!=302) {
throw new IOException("Expected status code 302 for POST, got " + status + ", URL=" + url);
}
- final String location = post.getResponseHeader("Location").getValue();
+ String location = post.getResponseHeader("Location").getValue();
+ post.releaseConnection();
+ // simple check if host is missing
+ if (!location.startsWith("http://")) {
+ String host = UslingHttpTestBase.HTTP_BASE_URL;
+ int idx = host.indexOf('/', 8);
+ if (idx > 0) {
+ host = host.substring(0, idx);
+ }
+ location = host + location;
+ }
return location;
}
+
+ /** Upload to an file node structure, see SLING-168 */
+ public void uploadToFileNode(String url, File localFile, String fieldName, String typeHint)
+ throws IOException {
+
+ final Part[] parts = new Part[typeHint == null ? 1 : 2];
+ parts[0] = new FilePart(fieldName, localFile);
+ if (typeHint != null) {
+ parts[1] = new StringPart(fieldName + "@TypeHint", typeHint);
+ }
+ final PostMethod post = new PostMethod(url);
+ post.setFollowRedirects(false);
+ post.setRequestEntity(new MultipartRequestEntity(parts, post.getParams()));
+
+ final int status = httpClient.executeMethod(post);
+ if(status!=302) {
+ throw new IOException("Expected status code 302 for POST, got " + status + ", URL=" + url);
+ }
+ }
+
}
Added: incubator/sling/trunk/usling/usling-webapp/src/test/resources/integration-test/file-to-upload.txt
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/usling/usling-webapp/src/test/resources/integration-test/file-to-upload.txt?rev=612842&view=auto
==============================================================================
--- incubator/sling/trunk/usling/usling-webapp/src/test/resources/integration-test/file-to-upload.txt (added)
+++ incubator/sling/trunk/usling/usling-webapp/src/test/resources/integration-test/file-to-upload.txt Thu Jan 17 07:18:10 2008
@@ -0,0 +1,12 @@
+This file is used by UploadFileTest.java.
+
+In must contain http://www.apache.org/licenses/LICENSE-2.0 for tests.
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Fusce semper ipsum et lorem. In hac habitasse
+platea dictumst. Donec dictum tincidunt purus. Aenean quis nunc. Aliquam rhoncus. Proin sed risus.
+Maecenas porta arcu in nisi. Pellentesque quis sapien quis lectus vehicula aliquet. Cras ornare elit
+eget massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed
+ut justo. Integer porttitor quam. Aliquam aliquet. Nulla interdum arcu vitae nibh. Morbi dapibus odio
+a sem. Integer dictum. Praesent vel eros nec ipsum venenatis malesuada. Vestibulum rutrum mi ac ligula.
+Ut nisl ligula, vehicula dignissim, accumsan quis, faucibus sed, sapien. Quisque purus tellus, euismod
+id, auctor quis, rutrum non, augue.
\ No newline at end of file
Propchange: incubator/sling/trunk/usling/usling-webapp/src/test/resources/integration-test/file-to-upload.txt
------------------------------------------------------------------------------
svn:eol-style = native