Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions examples/complete/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ Description: >

# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Api:
BinaryMediaTypes:
- application~1fastinfoset
Function:
Timeout: 120

Expand Down
49 changes: 36 additions & 13 deletions src/main/java/co/zeroae/gate/App.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package co.zeroae.gate;

import co.zeroae.gate.b64.Handler;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;

import com.amazonaws.util.Base64;
import com.amazonaws.xray.AWSXRay;
import com.amazonaws.xray.entities.Subsegment;

Expand Down Expand Up @@ -70,11 +72,18 @@ public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent in
response.getHeaders().put("Content-Type", responseType);
}

final String bodyType = input.getHeaders().get("Content-Type");
final FeatureMap featureMap = Factory.newFeatureMap();
featureMap.put(Document.DOCUMENT_STRING_CONTENT_PARAMETER_NAME, input.getBody());
final String bodyType = input.getHeaders().get("Content-Type");
if (bodyType != null)
featureMap.put(Document.DOCUMENT_MIME_TYPE_PARAMETER_NAME, bodyType);
if (input.getIsBase64Encoded() != null && input.getIsBase64Encoded())
featureMap.put(
Document.DOCUMENT_URL_PARAMETER_NAME,
new URL("b64", "localhost", 64, input.getBody(),
new Handler()));
else
featureMap.put(Document.DOCUMENT_STRING_CONTENT_PARAMETER_NAME, input.getBody());

final String inputDigest = AWSXRay.createSubsegment("Message Digest",
(subsegment) -> {
String rv = computeMessageDigest(featureMap);
Expand Down Expand Up @@ -108,19 +117,19 @@ public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent in
AWSXRay.beginSubsegment("Gate Export");
AWSXRay.getCurrentSubsegment().putMetadata("Content-Type", responseType);
try {
return response.withBody(export(doc, exporter)).withStatusCode(200);
return export(exporter, doc, response).withStatusCode(200);
} finally {
Factory.deleteResource(doc);
AWSXRay.endSubsegment();
}
} catch (GateException e) {
logger.error(e);
AWSXRay.getCurrentSegment().addException(e);
AWSXRay.getCurrentSubsegmentOptional().ifPresent((segment -> segment.addException(e)));
response.getHeaders().put("Content-Type", "text/plain");
return response.withBody(e.getMessage()).withStatusCode(400);
} catch (IOException e) {
logger.error(e);
AWSXRay.getCurrentSegment().addException(e);
AWSXRay.getCurrentSubsegmentOptional().ifPresent((segment -> segment.addException(e)));
response.getHeaders().put("Content-Type", "text/plain");
return response.withBody(e.getMessage()).withStatusCode(406);
}
Expand Down Expand Up @@ -165,26 +174,34 @@ private Document cacheComputeIfNull(String key, Utils.TextProcessor processor) t
}

private String computeMessageDigest(FeatureMap featureMap) {
final String sha256;
try {
final MessageDigest md = MessageDigest.getInstance("SHA-256");
final String bodyContent = (String)featureMap.get(Document.DOCUMENT_STRING_CONTENT_PARAMETER_NAME);
final String mimeType = (String)featureMap.get(Document.DOCUMENT_MIME_TYPE_PARAMETER_NAME);
md.update(bodyContent.getBytes());
final String bodyContent = (String)featureMap.get(Document.DOCUMENT_STRING_CONTENT_PARAMETER_NAME);
final URL sourceUrl = (URL)featureMap.get(Document.DOCUMENT_URL_PARAMETER_NAME);
if (mimeType != null)
md.update(mimeType.getBytes());
sha256 = Hex.encode(md.digest());
if (bodyContent != null)
md.update(bodyContent.getBytes());
if (sourceUrl != null)
md.update(sourceUrl.toString().getBytes());
return Hex.encode(md.digest());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
return sha256;
}

/**
* @param doc an instance of gate.Document
* @param exporter The document exporter
* @param doc an instance of gate.Document
* @param response The response where we put the exported Document as body
* @return the modified response
*/
private String export(Document doc, DocumentExporter exporter) throws IOException {
private APIGatewayProxyResponseEvent export(
DocumentExporter exporter,
Document doc,
APIGatewayProxyResponseEvent response
) throws IOException {
final FeatureMap exportOptions = Factory.newFeatureMap();

// Take *all* annotation types.
Expand All @@ -202,7 +219,13 @@ private String export(Document doc, DocumentExporter exporter) throws IOExceptio
AWSXRay.getCurrentSubsegment().addException(e);
throw e;
}
return baos.toString();
// If we add a second type, then we should create a "Set" at the Utils level and test against it.
if (exporter.getMimeType().equals("application/fastinfoset")) {
response.withIsBase64Encoded(true).setBody(Base64.encodeAsString(baos.toByteArray()));
} else {
response.setBody(baos.toString());
}
return response;
}

private static CorpusController loadApplication() {
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/co/zeroae/gate/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,13 @@ static void loadDocumentFormats() {
static Map<String, DocumentExporter> loadExporters() {
final GateXMLExporter gateXMLExporter = new GateXMLExporter();
final GATEJsonExporter gateJsonExporter = new GATEJsonExporter();
final FastInfosetExporter fastInfosetExporter = new FastInfosetExporter();

final Map<String, DocumentExporter> rv = new HashMap<>();
rv.put("application/gate+xml", gateXMLExporter);
rv.put("application/gate+json", gateJsonExporter);
rv.put("application/json", gateJsonExporter);
rv.put("application/fastinfoset", fastInfosetExporter);
return Collections.unmodifiableMap(rv);
}
}
35 changes: 35 additions & 0 deletions src/main/java/co/zeroae/gate/b64/Handler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package co.zeroae.gate.b64;

import com.amazonaws.util.StringInputStream;
import org.apache.commons.codec.binary.Base64InputStream;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;

public class Handler extends URLStreamHandler {
private class Connection extends URLConnection {
/**
* Constructs a URL connection to the specified URL. A connection to
* the object referenced by the URL is not created.
*
* @param url the specified URL.
*/
protected Connection(URL url) {
super(url);
}
@Override
public void connect() {
}
@Override
public InputStream getInputStream() throws IOException {
return new Base64InputStream(new StringInputStream(url.getPath()));
}
}
@Override
protected URLConnection openConnection(URL u) {
return new Connection(u);
}
}
47 changes: 39 additions & 8 deletions src/test/java/co/zeroae/gate/AppTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
import com.amazonaws.util.Base64;
import com.amazonaws.util.IOUtils;
import com.amazonaws.xray.AWSXRay;
import com.fasterxml.jackson.core.JsonFactory;
Expand Down Expand Up @@ -81,18 +82,32 @@ public void testMissingContentType() {

@Test
public void testGateJSONResponse() throws Exception {
input_headers.put("Accept", "application/gate+json");
for (String responseType: new String[]{"application/gate+json", "application/json"}) {
input_headers.put("Accept", responseType);

final APIGatewayProxyResponseEvent result = app.handleRequest(input, context);
assertEquals(200, result.getStatusCode().intValue());

// Ensure we get back application/gate+json back
assertEquals(responseType, result.getHeaders().get("Content-Type"));
final JsonFactory factory = new JsonFactory();
final JsonParser parser = factory.createParser(result.getBody());
while (!parser.isClosed()) {
parser.nextToken();
}
}
}

@Test
public void testFastInfosetResponse() {
input_headers.put("Accept", "application/fastinfoset");

final APIGatewayProxyResponseEvent result = app.handleRequest(input, context);
assertEquals(200, result.getStatusCode().intValue());

// Ensure we get back application/gate+json back
assertEquals("application/gate+json", result.getHeaders().get("Content-Type"));
final JsonFactory factory = new JsonFactory();
final JsonParser parser = factory.createParser(result.getBody());
while (!parser.isClosed()) {
parser.nextToken();
}
// Ensure we get back application/fastinfoset back
assertEquals("application/fastinfoset", result.getHeaders().get("Content-Type"));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assertTrue(result.getIsBase64Encoded());
}

@Test
Expand Down Expand Up @@ -156,6 +171,22 @@ public void testMediaWikiInput() throws IOException {
assertFalse(result.getBody().contains("{{Short Description|"));
}

@Test
public void testFastInfosetInput() throws IOException {
final byte[] body = IOUtils.toByteArray(getClass().getResourceAsStream("example.finf"));
input.withIsBase64Encoded(true)
.withBody(Base64.encodeAsString(body))
.getHeaders().put("Content-Type", "application/fastinfoset");

final APIGatewayProxyResponseEvent result = app.handleRequest(input, context);
assertEquals(200, result.getStatusCode().intValue());
assertEquals("MISS", result.getHeaders().get("x-zae-gate-cache"));

final APIGatewayProxyResponseEvent cachedResult = app.handleRequest(input, context);
assertEquals(200, cachedResult.getStatusCode().intValue());
assertEquals("HIT", cachedResult.getHeaders().get("x-zae-gate-cache"));
}

@Test
public void testCacheCoherenceWithContentType() {
final int cacheBust= new Random().nextInt();
Expand Down
Binary file added src/test/resources/co/zeroae/gate/example.finf
Binary file not shown.