Skip to content

Commit fc1835e

Browse files
author
Mark Hale
committed
Add support for POST requests to HttpRequestTupleFunction.
1 parent d2d0771 commit fc1835e

4 files changed

Lines changed: 84 additions & 7 deletions

File tree

sail/src/main/java/com/msd/gin/halyard/sail/http/HTTP.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ private static IRI iri(String localName) {
2626
public static final IRI RESP_PROPERTY = iri("resp");
2727
public static final IRI RESPONSE_CLASS = iri("Response");
2828
public static final IRI STATUS_CODE_VALUE_PROPERTY = iri("statusCodeValue");
29+
public static final IRI REASON_PHRASE_PROPERTY = iri("reasonPhrase");
2930
public static final IRI BODY_PROPERTY = iri("body");
3031

3132
public static final class METHOD {

sail/src/main/java/com/msd/gin/halyard/sail/http/HttpRequestInterpreter.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ private void processGraphPattern(BGPCollector<RuntimeException> bgp) {
7272
} else if (HTTP.METHOD_NAME_PROPERTY.equals(httpPred)) {
7373
httpSP.replaceWith(new SingletonSet());
7474
httpCall.params.setMethod(httpObjVar);
75+
} else if (HTTP.BODY_PROPERTY.equals(httpPred)) {
76+
httpSP.replaceWith(new SingletonSet());
77+
httpCall.params.setRequestBody(httpObjVar);
7578
} else if (HTTP.RESP_PROPERTY.equals(httpPred)) {
7679
httpSP.replaceWith(new SingletonSet());
7780
List<StatementPattern> respSPs = stmtsBySubj.get(httpObjVar.getName());
@@ -84,6 +87,9 @@ private void processGraphPattern(BGPCollector<RuntimeException> bgp) {
8487
} else if (HTTP.STATUS_CODE_VALUE_PROPERTY.equals(respPred)) {
8588
respSP.replaceWith(new SingletonSet());
8689
httpCall.params.setStatusCodeVarName(respObj.getName());
90+
} else if (HTTP.REASON_PHRASE_PROPERTY.equals(respPred)) {
91+
respSP.replaceWith(new SingletonSet());
92+
httpCall.params.setReasonVarName(respObj.getName());
8793
}
8894
}
8995
} else if (HTTP.HEADERS_PROPERTY.equals(httpPred)) {
@@ -157,10 +163,15 @@ static final class HttpCall {
157163
final HttpParams params = new HttpParams();
158164

159165
boolean initCall() {
166+
if (params.statusCodeVarName == null || params.reasonVarName == null || params.responseBodyVarName == null) {
167+
return false;
168+
}
160169
tfc.addArg(params.absoluteURIVar.clone());
161170
tfc.addArg(params.methodVar != null ? params.methodVar.clone() : new ValueConstant(VF.createLiteral("GET")));
162171
tfc.addArg(new ValueConstant(new ObjectArrayLiteral(params.headers.toArray(), Pair.class)));
172+
tfc.addArg(params.requestBodyVar != null ? params.requestBodyVar.clone() : new ValueConstant(RDF.NIL));
163173
tfc.addResultVar(new Var(params.statusCodeVarName));
174+
tfc.addResultVar(new Var(params.reasonVarName));
164175
tfc.addResultVar(new Var(params.responseBodyVarName));
165176
return true;
166177
}
@@ -169,9 +180,11 @@ boolean initCall() {
169180
static final class HttpParams {
170181
Var absoluteURIVar;
171182
Var methodVar;
183+
Var requestBodyVar;
172184
List<Pair<String, String>> headers = new ArrayList<>();
173185
String responseBodyVarName;
174186
String statusCodeVarName;
187+
String reasonVarName;
175188

176189
void setAbsoluteURI(Var var) {
177190
absoluteURIVar = var;
@@ -181,6 +194,10 @@ void setMethod(Var var) {
181194
methodVar = var;
182195
}
183196

197+
void setRequestBody(Var var) {
198+
requestBodyVar = var;
199+
}
200+
184201
void addHeader(String name, String value) {
185202
headers.add(Pair.of(name, value));
186203
}
@@ -192,5 +209,9 @@ void setResponseBodyVarName(String var) {
192209
void setStatusCodeVarName(String var) {
193210
statusCodeVarName = var;
194211
}
212+
213+
void setReasonVarName(String var) {
214+
reasonVarName = var;
215+
}
195216
}
196217
}

sail/src/main/java/com/msd/gin/halyard/sail/http/HttpRequestTupleFunction.java

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.msd.gin.halyard.sail.http;
22

3-
import com.msd.gin.halyard.common.ByteUtils;
3+
import com.google.common.base.Strings;
4+
import com.msd.gin.halyard.model.Base64Literal;
45
import com.msd.gin.halyard.model.MapLiteral;
56
import com.msd.gin.halyard.model.ObjectArrayLiteral;
67
import com.msd.gin.halyard.model.XMLLiteral;
@@ -16,6 +17,8 @@
1617
import org.apache.commons.lang3.tuple.Pair;
1718
import org.apache.http.Header;
1819
import org.apache.http.HttpEntity;
20+
import org.apache.http.StatusLine;
21+
import org.apache.http.client.entity.EntityBuilder;
1922
import org.apache.http.client.methods.CloseableHttpResponse;
2023
import org.apache.http.client.methods.HttpUriRequest;
2124
import org.apache.http.client.methods.RequestBuilder;
@@ -31,6 +34,7 @@
3134
import org.eclipse.rdf4j.model.Value;
3235
import org.eclipse.rdf4j.model.ValueFactory;
3336
import org.eclipse.rdf4j.model.base.CoreDatatype.XSD;
37+
import org.eclipse.rdf4j.model.vocabulary.RDF;
3438
import org.eclipse.rdf4j.query.QueryEvaluationException;
3539
import org.eclipse.rdf4j.query.algebra.evaluation.TripleSource;
3640
import org.eclipse.rdf4j.query.algebra.evaluation.function.TupleFunction;
@@ -75,17 +79,35 @@ public CloseableIteration<? extends List<? extends Value>> evaluate(TripleSource
7579
} else {
7680
headers = new Object[0];
7781
}
82+
Literal requestBody;
83+
if (args.length > 3 && !RDF.NIL.equals(args[3])) {
84+
requestBody = (Literal) args[3];
85+
} else {
86+
requestBody = null;
87+
}
7888

7989
RequestBuilder requestBuilder = RequestBuilder.create(method.getLocalName()).setUri(uri);
8090
for (Object headerObj : headers) {
8191
Header header = toHeader(headerObj);
8292
requestBuilder.addHeader(header);
8393
}
94+
if (requestBody != null) {
95+
EntityBuilder entityBuilder = EntityBuilder.create();
96+
if (XSD.BASE64BINARY.equals(requestBody.getCoreDatatype())) {
97+
entityBuilder.setBinary(Base64Literal.byteArray(requestBody));
98+
} else {
99+
entityBuilder.setText(requestBody.stringValue());
100+
}
101+
requestBuilder.setEntity(entityBuilder.gzipCompress().build());
102+
}
84103
HttpUriRequest request = requestBuilder.build();
85104
try (final CloseableHttpClient httpClient = HttpClients.createDefault()) {
86105
try (final CloseableHttpResponse resp = httpClient.execute(request)) {
87-
int sc = resp.getStatusLine().getStatusCode();
106+
StatusLine sl = resp.getStatusLine();
107+
int sc = sl.getStatusCode();
108+
String reason = sl.getReasonPhrase();
88109
Literal scLiteral = vf.createLiteral(sc);
110+
Literal reasonLiteral = vf.createLiteral(Strings.nullToEmpty(reason));
89111
HttpEntity entity = resp.getEntity();
90112
ContentType contentType = ContentType.get(entity);
91113
if (contentType == null) {
@@ -100,10 +122,9 @@ public CloseableIteration<? extends List<? extends Value>> evaluate(TripleSource
100122
} else if (mimeType.startsWith("text/")) {
101123
respLiteral = vf.createLiteral(EntityUtils.toString(entity));
102124
} else {
103-
byte[] b = EntityUtils.toByteArray(entity);
104-
respLiteral = vf.createLiteral(ByteUtils.encode(b), XSD.BASE64BINARY);
125+
respLiteral = new Base64Literal(EntityUtils.toByteArray(entity));
105126
}
106-
return new SingletonIteration<List<? extends Value>>(Arrays.asList(scLiteral, respLiteral));
127+
return new SingletonIteration<List<? extends Value>>(Arrays.asList(scLiteral, reasonLiteral, respLiteral));
107128
}
108129
} catch (IOException ioe) {
109130
throw new QueryEvaluationException(ioe);

sail/src/test/java/com/msd/gin/halyard/sail/HttpRequestTest.java

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@
99
import com.sun.net.httpserver.HttpServer;
1010

1111
import java.io.IOException;
12+
import java.io.InputStream;
1213
import java.io.OutputStream;
1314
import java.net.HttpURLConnection;
1415
import java.net.InetSocketAddress;
1516
import java.nio.ByteBuffer;
1617
import java.nio.charset.StandardCharsets;
1718

19+
import org.apache.commons.io.IOUtils;
1820
import org.apache.hadoop.conf.Configuration;
1921
import org.eclipse.rdf4j.model.Literal;
2022
import org.eclipse.rdf4j.query.BindingSet;
@@ -52,7 +54,7 @@ public void simpleRequestTest() throws Exception {
5254
try (RepositoryConnection conn = hbaseRepo.getConnection()) {
5355
TupleQuery q = conn.prepareTupleQuery(
5456
"PREFIX halyard: <http://merck.github.io/Halyard/ns#> PREFIX http: <http://www.w3.org/2011/http#> select * { [] a http:Request; http:absoluteURI '" + server.getUrl()
55-
+ "'; http:resp [http:statusCodeValue ?sc; http:body ?body ] }");
57+
+ "'; http:resp [http:statusCodeValue ?sc; http:reasonPhrase ?reason; http:body ?body ] }");
5658
try (TupleQueryResult iter = q.evaluate()) {
5759
assertTrue(iter.hasNext());
5860
BindingSet bs = iter.next();
@@ -73,7 +75,7 @@ public void headerRequestTest() throws Exception {
7375
Repository hbaseRepo = createRepo("testSimpleRequest");
7476
try (RepositoryConnection conn = hbaseRepo.getConnection()) {
7577
TupleQuery q = conn.prepareTupleQuery("PREFIX halyard: <http://merck.github.io/Halyard/ns#> PREFIX http: <http://www.w3.org/2011/http#> select * { [] a http:Request; http:absoluteURI '" + server.getUrl()
76-
+ "'; http:headers ([http:fieldName 'User-agent'; http:fieldValue '" + userAgent + "']); http:resp [http:statusCodeValue ?sc; http:body ?body ] }");
78+
+ "'; http:headers ([http:fieldName 'User-agent'; http:fieldValue '" + userAgent + "']); http:resp [http:statusCodeValue ?sc; http:reasonPhrase ?reason; http:body ?body ] }");
7779
try (TupleQueryResult iter = q.evaluate()) {
7880
assertTrue(iter.hasNext());
7981
BindingSet bs = iter.next();
@@ -90,6 +92,34 @@ public void headerRequestTest() throws Exception {
9092
}
9193
}
9294

95+
@Test
96+
public void postRequestTest() throws Exception {
97+
String contentType = "text/plain";
98+
String requestBody = "foobar";
99+
String expectedBody = "{\"msg\":\"Hi!\"}";
100+
try (MockHttpServer server = startHttpServer("application/json", toBytes(expectedBody))) {
101+
Repository hbaseRepo = createRepo("testSimpleRequest");
102+
try (RepositoryConnection conn = hbaseRepo.getConnection()) {
103+
TupleQuery q = conn.prepareTupleQuery("PREFIX halyard: <http://merck.github.io/Halyard/ns#> PREFIX http: <http://www.w3.org/2011/http#> select * { [] a http:Request; http:absoluteURI '" + server.getUrl()
104+
+ "'; http:headers ([http:fieldName 'Content-type'; http:fieldValue '" + contentType + "']); http:body '" + requestBody + "'; http:resp [http:statusCodeValue ?sc; http:reasonPhrase ?reason; http:body ?body ] }");
105+
try (TupleQueryResult iter = q.evaluate()) {
106+
assertTrue(iter.hasNext());
107+
BindingSet bs = iter.next();
108+
assertNotNull(server.requestHeaders);
109+
assertEquals(contentType, server.requestHeaders.get("Content-type").get(0));
110+
assertNotNull(server.requestBody);
111+
assertArrayEquals(toBytes(requestBody), server.requestBody);
112+
assertEquals(200, ((Literal) bs.getValue("sc")).intValue());
113+
Literal actualBody = (Literal) bs.getValue("body");
114+
assertEquals(expectedBody, actualBody.stringValue());
115+
assertEquals(HALYARD.MAP_TYPE, actualBody.getDatatype());
116+
assertFalse(iter.hasNext());
117+
}
118+
}
119+
hbaseRepo.shutDown();
120+
}
121+
}
122+
93123
private MockHttpServer startHttpServer(String contentType, byte[] response) throws IOException {
94124
MockHttpServer server = new MockHttpServer(contentType, response);
95125
server.start();
@@ -106,13 +136,17 @@ private static byte[] toBytes(String s) {
106136
static class MockHttpServer implements AutoCloseable {
107137
final HttpServer server;
108138
Headers requestHeaders;
139+
byte[] requestBody;
109140

110141
MockHttpServer(String contentType, byte[] response) throws IOException {
111142
server = HttpServer.create(new InetSocketAddress("localhost", 0), 0);
112143
server.createContext("/", new HttpHandler() {
113144
@Override
114145
public void handle(HttpExchange he) throws IOException {
115146
requestHeaders = he.getRequestHeaders();
147+
try (InputStream in = he.getRequestBody()) {
148+
requestBody = IOUtils.toByteArray(in);
149+
}
116150
he.getResponseHeaders().add("Content-type", contentType);
117151
he.sendResponseHeaders(HttpURLConnection.HTTP_OK, 0);
118152
try (OutputStream out = he.getResponseBody()) {

0 commit comments

Comments
 (0)