|
@@ -0,0 +1,162 @@
|
|
|
+package hello;
|
|
|
+
|
|
|
+/*
|
|
|
+ * #%L
|
|
|
+ * rapidoid-demo
|
|
|
+ * %%
|
|
|
+ * Copyright (C) 2014 - 2015 Nikolche Mihajlovski
|
|
|
+ * %%
|
|
|
+ * 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.
|
|
|
+ * #L%
|
|
|
+ */
|
|
|
+
|
|
|
+import org.rapidoid.buffer.Buf;
|
|
|
+import org.rapidoid.bytes.BytesUtil;
|
|
|
+import org.rapidoid.data.Range;
|
|
|
+import org.rapidoid.data.Ranges;
|
|
|
+import org.rapidoid.http.HttpParser;
|
|
|
+import org.rapidoid.net.Protocol;
|
|
|
+import org.rapidoid.net.abstracts.Channel;
|
|
|
+import org.rapidoid.net.impl.RapidoidHelper;
|
|
|
+import org.rapidoid.util.Dates;
|
|
|
+import org.rapidoid.wrap.BoolWrap;
|
|
|
+
|
|
|
+public class SimpleHttpProtocol implements Protocol {
|
|
|
+
|
|
|
+ private static final byte[] HTTP_200_OK = "HTTP/1.1 200 OK\r\n".getBytes();
|
|
|
+
|
|
|
+ private static final byte[] HTTP_404_NOT_FOUND = "HTTP/1.1 404 Not Found\r\nContent-Length: 10\r\n\r\nNot found!"
|
|
|
+ .getBytes();
|
|
|
+
|
|
|
+ private static final byte[] CONN_KEEP_ALIVE = "Connection: keep-alive\r\n"
|
|
|
+ .getBytes();
|
|
|
+
|
|
|
+ private static final byte[] CONN_CLOSE = "Connection: close\r\n".getBytes();
|
|
|
+
|
|
|
+ private static final byte[] SERVER_X = "Server: X\r\n".getBytes();
|
|
|
+
|
|
|
+ private static final byte[] CONTENT_LENGTH_HDR = "Content-Length: "
|
|
|
+ .getBytes();
|
|
|
+
|
|
|
+ private static final byte[] CONTENT_TYPE_PLAIN = "Content-Type: text/plain; charset=UTF-8\r\n"
|
|
|
+ .getBytes();
|
|
|
+
|
|
|
+ private static final byte[] CONTENT_TYPE_JSON = "Content-Type: application/json; charset=UTF-8\r\n"
|
|
|
+ .getBytes();
|
|
|
+
|
|
|
+ private static final byte[] CONTENT_LENGTH = "Content-Length: "
|
|
|
+ .getBytes();
|
|
|
+
|
|
|
+ private static final byte[] RESPONSE = "Hello, World!".getBytes();
|
|
|
+
|
|
|
+ private static final byte[] DATE_HDR = "Date: ".getBytes();
|
|
|
+
|
|
|
+ private static final byte[] RESPONSE_LENGTH = String.valueOf(
|
|
|
+ RESPONSE.length).getBytes();
|
|
|
+
|
|
|
+ private static final byte[] URI_PLAIN = "/plaintext".getBytes();
|
|
|
+
|
|
|
+ private static final byte[] URI_JSON = "/json".getBytes();
|
|
|
+
|
|
|
+ private static final HttpParser HTTP_PARSER = new HttpParser();
|
|
|
+
|
|
|
+ public void process(Channel ctx) {
|
|
|
+ if (ctx.isInitial()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ Buf buf = ctx.input();
|
|
|
+ RapidoidHelper helper = ctx.helper();
|
|
|
+
|
|
|
+ Range[] ranges = helper.ranges1.ranges;
|
|
|
+ Ranges headers = helper.ranges2;
|
|
|
+
|
|
|
+ BoolWrap isGet = helper.booleans[0];
|
|
|
+ BoolWrap isKeepAlive = helper.booleans[1];
|
|
|
+
|
|
|
+ Range verb = ranges[ranges.length - 1];
|
|
|
+ Range uri = ranges[ranges.length - 2];
|
|
|
+ Range path = ranges[ranges.length - 3];
|
|
|
+ Range query = ranges[ranges.length - 4];
|
|
|
+ Range protocol = ranges[ranges.length - 5];
|
|
|
+ Range body = ranges[ranges.length - 6];
|
|
|
+
|
|
|
+ HTTP_PARSER.parse(buf, isGet, isKeepAlive, body, verb, uri, path,
|
|
|
+ query, protocol, headers, helper);
|
|
|
+
|
|
|
+ response(ctx, buf, path, isGet.value, isKeepAlive.value);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void response(Channel ctx, Buf buf, Range path, boolean isGet,
|
|
|
+ boolean isKeepAlive) {
|
|
|
+ boolean processed = false;
|
|
|
+
|
|
|
+ if (isGet) {
|
|
|
+
|
|
|
+ ctx.write(HTTP_200_OK);
|
|
|
+
|
|
|
+ ctx.write(isKeepAlive ? CONN_KEEP_ALIVE : CONN_CLOSE);
|
|
|
+
|
|
|
+ ctx.write(SERVER_X);
|
|
|
+
|
|
|
+ ctx.write(DATE_HDR);
|
|
|
+ ctx.write(Dates.getDateTimeBytes());
|
|
|
+ ctx.write(CR_LF);
|
|
|
+
|
|
|
+ if (BytesUtil.matches(buf.bytes(), path, URI_PLAIN, true)
|
|
|
+ || path.length == 1) {
|
|
|
+ handlePlaintext(ctx);
|
|
|
+ processed = true;
|
|
|
+ } else if (BytesUtil.matches(buf.bytes(), path, URI_JSON, true)) {
|
|
|
+ handleJson(ctx);
|
|
|
+ processed = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ ctx.closeIf(!isKeepAlive);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!processed) {
|
|
|
+ ctx.write(HTTP_404_NOT_FOUND);
|
|
|
+ ctx.close();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handlePlaintext(Channel ctx) {
|
|
|
+ ctx.write(CONTENT_LENGTH_HDR);
|
|
|
+ ctx.write(RESPONSE_LENGTH);
|
|
|
+ ctx.write(CR_LF);
|
|
|
+
|
|
|
+ ctx.write(CONTENT_TYPE_PLAIN);
|
|
|
+ ctx.write(CR_LF);
|
|
|
+ ctx.write(RESPONSE);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handleJson(Channel ctx) {
|
|
|
+ Buf output = ctx.output();
|
|
|
+
|
|
|
+ ctx.write(CONTENT_TYPE_JSON);
|
|
|
+ ctx.write(CONTENT_LENGTH);
|
|
|
+
|
|
|
+ int posConLen = output.size() - 10;
|
|
|
+ ctx.write(CR_LF);
|
|
|
+ ctx.write(CR_LF);
|
|
|
+
|
|
|
+ int posBefore = output.size();
|
|
|
+
|
|
|
+ ctx.writeJSON(new Message("Hello, World!"));
|
|
|
+
|
|
|
+ int posAfter = output.size();
|
|
|
+ output.putNumAsText(posConLen, posAfter - posBefore, false);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|