xhr4j/src/test/java/org/netbeans/html/xhr4j/JsonDynamicHTTP.java
author Jaroslav Tulach <jtulach@netbeans.org>
Mon, 29 Feb 2016 05:25:31 +0100
branchxhr4j
changeset 1057 b547f8f663f5
parent 940 ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusDynamicHTTP.java@bdec4103bdb2
permissions -rw-r--r--
#257849: xhr4j module uses java.net package to handle @OnReceive requests to workaround CORS limitations
     1 /**
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
     5  *
     6  * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
     7  * Other names may be trademarks of their respective owners.
     8  *
     9  * The contents of this file are subject to the terms of either the GNU
    10  * General Public License Version 2 only ("GPL") or the Common
    11  * Development and Distribution License("CDDL") (collectively, the
    12  * "License"). You may not use this file except in compliance with the
    13  * License. You can obtain a copy of the License at
    14  * http://www.netbeans.org/cddl-gplv2.html
    15  * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    16  * specific language governing permissions and limitations under the
    17  * License.  When distributing the software, include this License Header
    18  * Notice in each file and include the License file at
    19  * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    20  * particular file as subject to the "Classpath" exception as provided
    21  * by Oracle in the GPL Version 2 section of the License file that
    22  * accompanied this code. If applicable, add the following below the
    23  * License Header, with the fields enclosed by brackets [] replaced by
    24  * your own identifying information:
    25  * "Portions Copyrighted [year] [name of copyright owner]"
    26  *
    27  * Contributor(s):
    28  *
    29  * The Original Software is NetBeans. The Initial Developer of the Original
    30  * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
    31  *
    32  * If you wish your version of this file to be governed by only the CDDL
    33  * or only the GPL Version 2, indicate your decision by adding
    34  * "[Contributor] elects to include this software in this distribution
    35  * under the [CDDL or GPL Version 2] license." If you do not indicate a
    36  * single choice of license, a recipient has the option to distribute
    37  * your version of this file under either the CDDL, the GPL Version 2 or
    38  * to extend the choice of license to its licensees as provided above.
    39  * However, if you add GPL Version 2 code and therefore, elected the GPL
    40  * Version 2 license, then the option applies only if the new code is
    41  * made subject to such option by the copyright holder.
    42  */
    43 package org.netbeans.html.xhr4j;
    44 
    45 import java.io.ByteArrayInputStream;
    46 import java.io.ByteArrayOutputStream;
    47 import java.io.IOException;
    48 import java.io.InputStream;
    49 import java.io.OutputStream;
    50 import java.io.Reader;
    51 import java.net.URI;
    52 import java.net.URISyntaxException;
    53 import java.util.ArrayList;
    54 import java.util.List;
    55 import java.util.logging.Level;
    56 import java.util.logging.Logger;
    57 import org.glassfish.grizzly.PortRange;
    58 import org.glassfish.grizzly.http.server.HttpHandler;
    59 import org.glassfish.grizzly.http.server.HttpServer;
    60 import org.glassfish.grizzly.http.server.NetworkListener;
    61 import org.glassfish.grizzly.http.server.Request;
    62 import org.glassfish.grizzly.http.server.Response;
    63 import org.glassfish.grizzly.http.server.ServerConfiguration;
    64 import org.glassfish.grizzly.websockets.WebSocket;
    65 import org.glassfish.grizzly.websockets.WebSocketAddOn;
    66 import org.glassfish.grizzly.websockets.WebSocketApplication;
    67 import org.glassfish.grizzly.websockets.WebSocketEngine;
    68 
    69 /**
    70  *
    71  * @author Jaroslav Tulach
    72  */
    73 final class JsonDynamicHTTP extends HttpHandler {
    74     private static int resourcesCount;
    75     private static List<Resource> resources;
    76     private static ServerConfiguration conf;
    77     private static HttpServer server;
    78 
    79     private JsonDynamicHTTP() {
    80     }
    81 
    82     static URI initServer() throws Exception {
    83         server = HttpServer.createSimpleServer(null, new PortRange(8080, 65535));
    84         final WebSocketAddOn addon = new WebSocketAddOn();
    85         for (NetworkListener listener : server.getListeners()) {
    86             listener.registerAddOn(addon);
    87         }
    88         resources = new ArrayList<Resource>();
    89 
    90         conf = server.getServerConfiguration();
    91         final JsonDynamicHTTP dh = new JsonDynamicHTTP();
    92 
    93         conf.addHttpHandler(dh, "/");
    94 
    95         server.start();
    96 
    97         return pageURL("http", server, "/test.html");
    98     }
    99 
   100     @Override
   101     public void service(Request request, Response response) throws Exception {
   102         if ("/test.html".equals(request.getRequestURI())) {
   103             response.setContentType("text/html");
   104             final InputStream is = JsonDynamicHTTP.class.getResourceAsStream("test.html");
   105             copyStream(is, response.getOutputStream(), null);
   106             return;
   107         }
   108         if ("/dynamic".equals(request.getRequestURI())) {
   109             String mimeType = request.getParameter("mimeType");
   110             List<String> params = new ArrayList<String>();
   111             boolean webSocket = false;
   112             for (int i = 0;; i++) {
   113                 String p = request.getParameter("param" + i);
   114                 if (p == null) {
   115                     break;
   116                 }
   117                 if ("protocol:ws".equals(p)) {
   118                     webSocket = true;
   119                     continue;
   120                 }
   121                 params.add(p);
   122             }
   123             final String cnt = request.getParameter("content");
   124             String mangle = cnt.replace("%20", " ").replace("%0A", "\n");
   125             ByteArrayInputStream is = new ByteArrayInputStream(mangle.getBytes("UTF-8"));
   126             URI url;
   127             final Resource res = new Resource(is, mimeType, "/dynamic/res" + ++resourcesCount, params.toArray(new String[params.size()]));
   128             if (webSocket) {
   129                 url = registerWebSocket(res);
   130             } else {
   131                 url = registerResource(res);
   132             }
   133             response.getWriter().write(url.toString());
   134             response.getWriter().write("\n");
   135             return;
   136         }
   137 
   138         for (Resource r : resources) {
   139             if (r.httpPath.equals(request.getRequestURI())) {
   140                 response.setContentType(r.httpType);
   141                 r.httpContent.reset();
   142                 String[] params = null;
   143                 if (r.parameters.length != 0) {
   144                     params = new String[r.parameters.length];
   145                     for (int i = 0; i < r.parameters.length; i++) {
   146                         params[i] = request.getParameter(r.parameters[i]);
   147                         if (params[i] == null) {
   148                             if ("http.method".equals(r.parameters[i])) {
   149                                 params[i] = request.getMethod().toString();
   150                             } else if ("http.requestBody".equals(r.parameters[i])) {
   151                                 Reader rdr = request.getReader();
   152                                 StringBuilder sb = new StringBuilder();
   153                                 for (;;) {
   154                                     int ch = rdr.read();
   155                                     if (ch == -1) {
   156                                         break;
   157                                     }
   158                                     sb.append((char) ch);
   159                                 }
   160                                 params[i] = sb.toString();
   161                             } else if (r.parameters[i].startsWith("http.header.")) {
   162                                 params[i] = request.getHeader(r.parameters[i].substring(12));
   163                             }
   164                         }
   165                         if (params[i] == null) {
   166                             params[i] = "null";
   167                         }
   168                     }
   169                 }
   170 
   171                 copyStream(r.httpContent, response.getOutputStream(), null, params);
   172             }
   173         }
   174     }
   175 
   176     private URI registerWebSocket(Resource r) {
   177         WebSocketEngine.getEngine().register("", r.httpPath, new WS(r));
   178         return pageURL("ws", server, r.httpPath);
   179     }
   180 
   181     private URI registerResource(Resource r) {
   182         if (!resources.contains(r)) {
   183             resources.add(r);
   184             conf.addHttpHandler(this, r.httpPath);
   185         }
   186         return pageURL("http", server, r.httpPath);
   187     }
   188 
   189     private static URI pageURL(String proto, HttpServer server, final String page) {
   190         NetworkListener listener = server.getListeners().iterator().next();
   191         int port = listener.getPort();
   192         try {
   193             return new URI(proto + "://localhost:" + port + page);
   194         } catch (URISyntaxException ex) {
   195             throw new IllegalStateException(ex);
   196         }
   197     }
   198 
   199     static final class Resource {
   200 
   201         final InputStream httpContent;
   202         final String httpType;
   203         final String httpPath;
   204         final String[] parameters;
   205 
   206         Resource(InputStream httpContent, String httpType, String httpPath,
   207             String[] parameters) {
   208             httpContent.mark(Integer.MAX_VALUE);
   209             this.httpContent = httpContent;
   210             this.httpType = httpType;
   211             this.httpPath = httpPath;
   212             this.parameters = parameters;
   213         }
   214     }
   215 
   216     static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException {
   217         for (;;) {
   218             int ch = is.read();
   219             if (ch == -1) {
   220                 break;
   221             }
   222             if (ch == '$' && params.length > 0) {
   223                 int cnt = is.read() - '0';
   224                 if (baseURL != null && cnt == 'U' - '0') {
   225                     os.write(baseURL.getBytes("UTF-8"));
   226                 } else {
   227                     if (cnt >= 0 && cnt < params.length) {
   228                         os.write(params[cnt].getBytes("UTF-8"));
   229                     } else {
   230                         os.write('$');
   231                         os.write(cnt + '0');
   232                     }
   233                 }
   234             } else {
   235                 os.write(ch);
   236             }
   237         }
   238     }
   239 
   240     private static class WS extends WebSocketApplication {
   241         private final Resource r;
   242 
   243         private WS(Resource r) {
   244             this.r = r;
   245         }
   246 
   247         @Override
   248         public void onMessage(WebSocket socket, String text) {
   249             try {
   250                 r.httpContent.reset();
   251                 ByteArrayOutputStream out = new ByteArrayOutputStream();
   252                 copyStream(r.httpContent, out, null, text);
   253                 String s = new String(out.toByteArray(), "UTF-8");
   254                 socket.send(s);
   255             } catch (IOException ex) {
   256                 LOG.log(Level.WARNING, null, ex);
   257             }
   258         }
   259         private static final Logger LOG = Logger.getLogger(WS.class.getName());
   260 
   261     }
   262 }