Skip to content

Commit

Permalink
Providing the file names for the uploaded files.
Browse files Browse the repository at this point in the history
  • Loading branch information
nmihajlovski committed Mar 6, 2016
1 parent 28f6f9c commit 087e88c
Show file tree
Hide file tree
Showing 12 changed files with 79 additions and 53 deletions.
Expand Up @@ -22,7 +22,9 @@

import org.rapidoid.annotation.Authors;
import org.rapidoid.annotation.Since;
import org.rapidoid.io.FileContent;

import java.util.List;
import java.util.Map;
import java.util.Set;

Expand All @@ -48,7 +50,7 @@ public interface IReqInfo {

Map<String, Object> posted();

Map<String, byte[]> files();
Map<String, List<FileContent>> files();

Map<String, String> headers();

Expand Down
Expand Up @@ -22,12 +22,10 @@

import org.rapidoid.annotation.Authors;
import org.rapidoid.annotation.Since;
import org.rapidoid.io.FileContent;
import org.rapidoid.u.U;

import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.*;

@Authors("Nikolche Mihajlovski")
@Since("5.0.4")
Expand All @@ -47,7 +45,7 @@ public class MockReqInfo extends AbstractReqInfo {

private Map<String, Object> posted = U.map();

private Map<String, byte[]> files = U.map();
private Map<String, List<FileContent>> files = U.map();

private Map<String, String> headers = U.map();

Expand Down Expand Up @@ -144,11 +142,11 @@ public MockReqInfo setPosted(Map<String, Object> posted) {
}

@Override
public Map<String, byte[]> files() {
public Map<String, List<FileContent>> files() {
return files;
}

public MockReqInfo setFiles(Map<String, byte[]> files) {
public MockReqInfo setFiles(Map<String, List<FileContent>> files) {
this.files = files;
return this;
}
Expand Down
Expand Up @@ -22,8 +22,10 @@

import org.rapidoid.annotation.Authors;
import org.rapidoid.annotation.Since;
import org.rapidoid.io.FileContent;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

Expand Down Expand Up @@ -81,7 +83,7 @@ public Map<String, Object> posted() {
}

@Override
public Map<String, byte[]> files() {
public Map<String, List<FileContent>> files() {
return EMPTY;
}

Expand Down
Expand Up @@ -24,7 +24,9 @@
import org.rapidoid.annotation.Since;
import org.rapidoid.ctx.Current;
import org.rapidoid.http.Req;
import org.rapidoid.io.FileContent;

import java.util.List;
import java.util.Map;
import java.util.Set;

Expand Down Expand Up @@ -68,7 +70,7 @@ public Map<String, Object> posted() {
}

@Override
public Map<String, byte[]> files() {
public Map<String, List<FileContent>> files() {
return req().files();
}

Expand Down
15 changes: 8 additions & 7 deletions rapidoid-http-fast/src/main/java/org/rapidoid/http/FastHttp.java
Expand Up @@ -33,6 +33,7 @@
import org.rapidoid.http.handler.FastHttpHandler;
import org.rapidoid.http.impl.HandlerMatch;
import org.rapidoid.http.processor.AbstractHttpProcessor;
import org.rapidoid.io.FileContent;
import org.rapidoid.log.Log;
import org.rapidoid.net.abstracts.Channel;
import org.rapidoid.net.impl.RapidoidHelper;
Expand All @@ -41,7 +42,6 @@

import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -120,20 +120,21 @@ public void onRequest(Channel channel, boolean isGet, boolean isKeepAlive, Range

byte[] body;
Map<String, Object> posted;
Map<String, byte[]> files;
Map<String, List<FileContent>> files;

if (!isGet && !xbody.isEmpty()) {
KeyValueRanges postedKV = helper.pairs3.reset();
KeyValueRanges filesKV = helper.pairs4.reset();

body = xbody.bytes(buf);

// parse posted body as data
posted = new HashMap<String, Object>();
HTTP_PARSER.parsePosted(buf, headersKV, xbody, postedKV, filesKV, helper, posted);
posted = Collections.synchronizedMap(posted);
posted = U.map();
files = U.map();

HTTP_PARSER.parsePosted(buf, headersKV, xbody, postedKV, files, helper, posted);

files = Collections.synchronizedMap(filesKV.toBinaryMap(buf, true));
posted = Collections.synchronizedMap(posted);
files = Collections.synchronizedMap(files);

} else {
posted = Collections.EMPTY_MAP;
Expand Down
24 changes: 15 additions & 9 deletions rapidoid-http-fast/src/main/java/org/rapidoid/http/HttpParser.java
Expand Up @@ -25,18 +25,21 @@
import org.rapidoid.buffer.Buf;
import org.rapidoid.bytes.Bytes;
import org.rapidoid.bytes.BytesUtil;
import org.rapidoid.commons.Coll;
import org.rapidoid.commons.Err;
import org.rapidoid.data.JSON;
import org.rapidoid.data.KeyValueRanges;
import org.rapidoid.data.Range;
import org.rapidoid.data.Ranges;
import org.rapidoid.io.FileContent;
import org.rapidoid.log.Log;
import org.rapidoid.net.impl.RapidoidHelper;
import org.rapidoid.u.U;
import org.rapidoid.util.Constants;
import org.rapidoid.wrap.BoolWrap;
import org.rapidoid.wrap.IntWrap;

import java.util.List;
import java.util.Map;

@Authors("Nikolche Mihajlovski")
Expand Down Expand Up @@ -231,8 +234,8 @@ public void parseHeadersIntoKV(Buf buf, Ranges headers, KeyValueRanges headersKV
/**
* @return <code>false</code> if JSON data was posted, so it wasn't completely parsed.
*/
public boolean parseBody(Buf src, KeyValueRanges headers, Range body, KeyValueRanges data, KeyValueRanges files,
RapidoidHelper helper) {
public boolean parseBody(Buf src, KeyValueRanges headers, Range body, KeyValueRanges data,
Map<String, List<FileContent>> files, RapidoidHelper helper) {

if (body.isEmpty()) {
return true;
Expand All @@ -256,7 +259,9 @@ public boolean parseBody(Buf src, KeyValueRanges headers, Range body, KeyValueRa

Err.rteIf(multipartBoundary.isEmpty(), "Invalid multi-part HTTP request!");

parseMultiParts(src, body, data, files, multipartBoundary, helper);
Map<String, List<FileContent>> autoFiles = Coll.mapOfLists();
parseMultiParts(src, body, data, autoFiles, multipartBoundary, helper);
files.putAll(autoFiles);

return true;

Expand Down Expand Up @@ -285,7 +290,7 @@ private void detectMultipartBoundary(Buf src, Range body, Range multipartBoundar
}

/* http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2 */
private void parseMultiParts(Buf src, Range body, KeyValueRanges data, KeyValueRanges files,
private void parseMultiParts(Buf src, Range body, KeyValueRanges data, Map<String, List<FileContent>> files,
Range multipartBoundary, RapidoidHelper helper) {

int start = body.start;
Expand Down Expand Up @@ -313,7 +318,7 @@ private void parseMultiParts(Buf src, Range body, KeyValueRanges data, KeyValueR
}
}

private void parseMultiPart(Buf src, Range body, KeyValueRanges data, KeyValueRanges files,
private void parseMultiPart(Buf src, Range body, KeyValueRanges data, Map<String, List<FileContent>> files,
Range multipartBoundary, RapidoidHelper helper, int from, int to) {

KeyValueRanges headers = helper.pairs.reset();
Expand Down Expand Up @@ -387,9 +392,10 @@ private void parseMultiPart(Buf src, Range body, KeyValueRanges data, KeyValueRa
data.keys[ind].assign(name);
data.values[ind].assign(partBody);
} else {
int ind = files.add();
files.keys[ind].assign(name);
files.values[ind].assign(partBody);
String uploadParamName = src.get(name);
String uploadFilename = src.get(filename);
byte[] uploadContent = partBody.bytes(src);
files.get(uploadParamName).add(new FileContent(uploadFilename, uploadContent));
}
}

Expand Down Expand Up @@ -456,7 +462,7 @@ private HttpContentType getContentType(Buf buf, KeyValueRanges headers, Range mu

@SuppressWarnings("unchecked")
public void parsePosted(Buf input, KeyValueRanges headersKV, Range rBody, KeyValueRanges posted,
KeyValueRanges files, RapidoidHelper helper, Map<String, Object> dest) {
Map<String, List<FileContent>> files, RapidoidHelper helper, Map<String, Object> dest) {

boolean completed = parseBody(input, headersKV, rBody, posted, files, helper);

Expand Down
16 changes: 9 additions & 7 deletions rapidoid-http-fast/src/main/java/org/rapidoid/http/Req.java
Expand Up @@ -22,8 +22,10 @@

import org.rapidoid.annotation.Authors;
import org.rapidoid.annotation.Since;
import org.rapidoid.io.FileContent;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

/**
Expand Down Expand Up @@ -153,19 +155,19 @@ public interface Req {
/**
* Gets the <b>posted files</b> from the HTTP request body.
*/
Map<String, byte[]> files();
Map<String, List<FileContent>> files();

/**
* Returns the content of the <b>posted file</b> from the HTTP request body, or throws a runtime exception if it is
* not found.
* Returns the <b>posted files</b> with the specified form parameter name (not filename) from the HTTP request body,
* or throws a runtime exception if not found.
*/
byte[] file(String name);
List<FileContent> files(String name);

/**
* Returns the content of the <b>posted file</b> from the HTTP request body, or the specified default value, if it
* is not found.
* Returns exactly one <b>posted file</b> with the specified form parameter name (not filename) from the HTTP request body,
* or throws a runtime exception if not found.
*/
byte[] file(String name, byte[] defaultValue);
FileContent file(String name);

/* REQUEST DATA PARAMETERS (URL PARAMETERS + POSTED PARAMETERS + POSTED FILES): */

Expand Down
24 changes: 13 additions & 11 deletions rapidoid-http-fast/src/main/java/org/rapidoid/http/ReqImpl.java
Expand Up @@ -25,18 +25,16 @@
import org.rapidoid.buffer.Buf;
import org.rapidoid.cls.Cls;
import org.rapidoid.commons.MediaType;
import org.rapidoid.io.FileContent;
import org.rapidoid.log.Log;
import org.rapidoid.net.abstracts.Channel;
import org.rapidoid.u.U;
import org.rapidoid.util.Constants;
import org.rapidoid.util.UTILS;

import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
import java.util.Map.Entry;
import java.util.UUID;

@Authors("Nikolche Mihajlovski")
@Since("5.0.2")
Expand Down Expand Up @@ -66,7 +64,7 @@ public class ReqImpl implements Req, Constants, HttpMetadata {

private final Map<String, Object> posted;

private final Map<String, byte[]> files;
private final Map<String, List<FileContent>> files;

private final Map<String, Object> attrs = Collections.synchronizedMap(new HashMap<String, Object>());

Expand All @@ -92,7 +90,7 @@ public class ReqImpl implements Req, Constants, HttpMetadata {

public ReqImpl(FastHttp http, Channel channel, boolean isKeepAlive, String verb, String uri, String path,
String query, byte[] body, Map<String, String> params, Map<String, String> headers,
Map<String, String> cookies, Map<String, Object> posted, Map<String, byte[]> files,
Map<String, String> cookies, Map<String, Object> posted, Map<String, List<FileContent>> files,
MediaType defaultContentType) {

this.http = http;
Expand Down Expand Up @@ -187,7 +185,7 @@ public Map<String, Object> posted() {
}

@Override
public Map<String, byte[]> files() {
public Map<String, List<FileContent>> files() {
return files;
}

Expand Down Expand Up @@ -259,13 +257,17 @@ public <T extends Serializable> T posted(String name, T defaultValue) {
}

@Override
public byte[] file(String name) {
public List<FileContent> files(String name) {
return U.notNull(files().get(name), "FILES[%s]", name);
}

@Override
public byte[] file(String name, byte[] defaultValue) {
return U.or(files().get(name), defaultValue);
public FileContent file(String name) {
List<FileContent> uploads = files(name);

U.must(uploads.size() == 1, "Expected exactly 1 uploaded file for parameter '%s', but found %s!", name, uploads.size());

return uploads.get(0);
}

@Override
Expand Down Expand Up @@ -298,7 +300,7 @@ public <T> T data(String name, T defaultValue) {
Object value = posted(name, null);

if (value == null) {
value = file(name, null);
value = files().get(name);

if (value == null) {
value = param(name, null);
Expand Down
Expand Up @@ -38,7 +38,7 @@ public ByteArrayParamRetriever(Class<?> type, String name) {

@Override
public byte[] getParamValue(Req req) {
return req.file(name);
return req.file(name).content();
}

}
Expand Up @@ -23,6 +23,9 @@
import org.rapidoid.annotation.Authors;
import org.rapidoid.annotation.Since;
import org.rapidoid.http.Req;
import org.rapidoid.io.FileContent;

import java.util.List;

@Authors("Nikolche Mihajlovski")
@Since("5.1.0")
Expand All @@ -38,11 +41,11 @@ public ByteArraysParamRetriever(Class<?> type, String name) {

@Override
public byte[][] getParamValue(Req req) {
byte[][] files = new byte[req.files().size()][];
List<FileContent> uploads = req.files(name);
byte[][] files = new byte[uploads.size()][];

int ind = 0;
for (byte[] file : req.files().values()) {
files[ind++] = file;
for (int i = 0; i < files.length; i++) {
files[i] = uploads.get(i).content();
}

return files;
Expand Down
Expand Up @@ -110,9 +110,12 @@ protected void defaultServerSetup() {
On.post("/upload").plain((Req x) -> {
Log.info("Uploaded files", "files", x.files().keySet());

return U.join(":", x.cookies().get("foo"), x.cookies().get("COOKIE1"), x.posted().get("a"), x.files()
.size(), Crypto.md5(x.files().get("f1")), Crypto.md5(x.files().get("f2")), Crypto.md5(U.or(x
.files().get("f3"), new byte[0])));
boolean hasF3 = x.files().containsKey("f3");

return U.join(":", x.cookies().get("foo"), x.cookies().get("COOKIE1"), x.posted().get("a"), x.files().size(),
Crypto.md5(x.file("f1").content()),
Crypto.md5(x.files().get("f2").get(0).content()),
Crypto.md5(hasF3 ? x.file("f3").content() : new byte[0]));
});

On.req((Req x) -> x.response().html(U.join(":", x.verb(), x.path(), x.query())));
Expand Down

0 comments on commit 087e88c

Please sign in to comment.