blob: 9ad1f188834cf4718c8164ed626b4ad2aa21609c [file] [log] [blame]
/**
* 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.netbeans.html.presenters.browser;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.netbeans.html.presenters.browser.HttpServer.Handler;
import org.netbeans.html.presenters.browser.HttpServer.WebSocketApplication;
final class DynamicHTTP extends Handler {
private static final Logger LOG = Logger.getLogger(DynamicHTTP.class.getName());
private static int resourcesCount;
private final List<Resource> resources = new ArrayList<>();
private final HttpServer server;
DynamicHTTP(HttpServer s) {
server = s;
}
@Override
public <Request, Response> void service(HttpServer<Request, Response, ?, ?> s, Request request, Response response) throws IOException {
if ("/dynamic".equals(s.getRequestURI(request))) {
String mimeType = s.getParameter(request, "mimeType");
List<String> params = new ArrayList<>();
boolean webSocket = false;
for (int i = 0;; i++) {
String p = s.getParameter(request, "param" + i);
if (p == null) {
break;
}
if ("protocol:ws".equals(p)) {
webSocket = true;
continue;
}
params.add(p);
}
final String cnt = s.getParameter(request, "content");
String mangle = cnt.replace("%20", " ").replace("%0A", "\n");
ByteArrayInputStream is = new ByteArrayInputStream(mangle.getBytes("UTF-8"));
URI url;
final Resource res = new Resource(is, mimeType, "/dynamic/res" + ++resourcesCount, params.toArray(new String[params.size()]));
if (webSocket) {
url = registerWebSocket(res);
} else {
url = registerResource(res);
}
server.getWriter(response).write(url.toString());
server.getWriter(response).write("\n");
return;
}
for (Resource r : resources) {
if (r.httpPath.equals(s.getRequestURI(request))) {
server.setContentType(response, r.httpType);
r.httpContent.reset();
String[] params = null;
if (r.parameters.length != 0) {
params = new String[r.parameters.length];
for (int i = 0; i < r.parameters.length; i++) {
params[i] = s.getParameter(request, r.parameters[i]);
if (params[i] == null) {
if ("http.method".equals(r.parameters[i])) {
params[i] = s.getMethod(request);
} else if ("http.requestBody".equals(r.parameters[i])) {
params[i] = s.getBody(request);
} else if (r.parameters[i].startsWith("http.header.")) {
params[i] = s.getHeader(request, r.parameters[i].substring(12));
}
}
if (params[i] == null) {
params[i] = "null";
}
}
}
copyStream(r.httpContent, server.getOutputStream(response), null, params);
}
}
}
private URI registerWebSocket(Resource r) {
// WebSocketEngine.getEngine().register("", r.httpPath, new WS(r));
return pageURL("ws", server, r.httpPath);
}
private URI registerResource(Resource r) {
if (!resources.contains(r)) {
resources.add(r);
server.addHttpHandler(this, r.httpPath);
}
return pageURL("http", server, r.httpPath);
}
private static URI pageURL(String proto, HttpServer server, final String page) {
int port = server.getPort();
try {
return new URI(proto + "://localhost:" + port + page);
} catch (URISyntaxException ex) {
throw new IllegalStateException(ex);
}
}
static final class Resource {
final InputStream httpContent;
final String httpType;
final String httpPath;
final String[] parameters;
Resource(InputStream httpContent, String httpType, String httpPath,
String[] parameters) {
httpContent.mark(Integer.MAX_VALUE);
this.httpContent = httpContent;
this.httpType = httpType;
this.httpPath = httpPath;
this.parameters = parameters;
}
}
static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException {
for (;;) {
int ch = is.read();
if (ch == -1) {
break;
}
if (ch == '$' && params.length > 0) {
int cnt = is.read() - '0';
if (baseURL != null && cnt == 'U' - '0') {
os.write(baseURL.getBytes("UTF-8"));
} else {
if (cnt >= 0 && cnt < params.length) {
os.write(params[cnt].getBytes("UTF-8"));
} else {
os.write('$');
os.write(cnt + '0');
}
}
} else {
os.write(ch);
}
}
}
private static class WS extends WebSocketApplication {
private final Resource r;
private WS(Resource r) {
this.r = r;
}
@Override
public <WebSocket> void onMessage(HttpServer<?,?, WebSocket, ?> server, WebSocket socket, String text) {
try {
r.httpContent.reset();
ByteArrayOutputStream out = new ByteArrayOutputStream();
copyStream(r.httpContent, out, null, text);
String s = new String(out.toByteArray(), "UTF-8");
server.send(socket, s);
} catch (IOException ex) {
LOG.log(Level.WARNING, "Error processing message " + text, ex);
}
}
}
}