Example usage for java.io OutputStreamWriter write

List of usage examples for java.io OutputStreamWriter write

Introduction

In this page you can find the example usage for java.io OutputStreamWriter write.

Prototype

public void write(int c) throws IOException 

Source Link

Document

Writes a single character.

Usage

From source file:com.techventus.server.voice.Voice.java

/**
 * Mark a Conversation with a known Message ID as unread.
 *
 * @param msgID the msg id//from w  w  w  . j  a va 2  s  .c  o m
 * @return the string
 * @throws IOException Signals that an I/O exception has occurred.
 */
public String markUnRead(String msgID) throws IOException {
    String out = "";
    StringBuffer calldata = new StringBuffer();

    // POST /voice/inbox/mark/ 
    // messages=[messageID]
    // &read=0
    // &_rnr_se=[pull from page]

    calldata.append("messages=");
    calldata.append(URLEncoder.encode(msgID, enc));
    calldata.append("&read=0");
    calldata.append("&_rnr_se=");
    calldata.append(URLEncoder.encode(rnrSEE, enc));

    URL callURL = new URL("https://www.google.com/voice/b/0/inbox/mark");

    URLConnection callconn = callURL.openConnection();
    callconn.setRequestProperty("Authorization", "GoogleLogin auth=" + authToken);
    callconn.setRequestProperty("User-agent", USER_AGENT);

    callconn.setDoOutput(true);
    OutputStreamWriter callwr = new OutputStreamWriter(callconn.getOutputStream());

    callwr.write(calldata.toString());
    callwr.flush();

    BufferedReader callrd = new BufferedReader(new InputStreamReader(callconn.getInputStream()));

    String line;
    while ((line = callrd.readLine()) != null) {
        out += line + "\n\r";

    }

    callwr.close();
    callrd.close();

    if (out.equals("")) {
        throw new IOException("No Response Data Received.");
    }

    return out;
}

From source file:com.techventus.server.voice.Voice.java

/**
 * Delete message./* w  w w. jav a 2  s .  c o  m*/
 *
 * @param msgID the msg id
 * @return the string
 * @throws IOException Signals that an I/O exception has occurred.
 */
public String deleteMessage(String msgID) throws IOException {
    String out = "";
    StringBuffer calldata = new StringBuffer();

    // POST /voice/inbox/deleteMessages/
    // messages=[messageID]
    // &trash=1
    // &_rnr_se=[pull from page]

    calldata.append("messages=");
    calldata.append(URLEncoder.encode(msgID, enc));
    calldata.append("&trash=1");
    calldata.append("&_rnr_se=");
    calldata.append(URLEncoder.encode(rnrSEE, enc));

    URL callURL = new URL("https://www.google.com/voice/b/0/inbox/deleteMessages/");

    URLConnection callconn = callURL.openConnection();
    callconn.setRequestProperty("Authorization", "GoogleLogin auth=" + authToken);
    callconn.setRequestProperty("User-agent", USER_AGENT);

    callconn.setDoOutput(true);
    OutputStreamWriter callwr = new OutputStreamWriter(callconn.getOutputStream());

    callwr.write(calldata.toString());
    callwr.flush();

    BufferedReader callrd = new BufferedReader(new InputStreamReader(callconn.getInputStream()));

    String line;
    while ((line = callrd.readLine()) != null) {
        out += line + "\n\r";

    }

    callwr.close();
    callrd.close();

    if (out.equals("")) {
        throw new IOException("No Response Data Received.");
    }

    return out;
}

From source file:com.techventus.server.voice.Voice.java

/**
 * Place a call.//from  www.jav a  2 s .co m
 * 
 * @param originNumber
 *            the origin number
 * @param destinationNumber
 *            the destination number
 * @param phoneType
 *            the phone type, this is a number such as 1,2,7 formatted as a String
 * @return the raw response string received from Google Voice.
 * @throws IOException
 *             Signals that an I/O exception has occurred.
 */
public String call(String originNumber, String destinationNumber, String phoneType) throws IOException {
    String out = "";
    StringBuffer calldata = new StringBuffer();

    // POST /voice/call/connect/ 
    // outgoingNumber=[number to call]
    // &forwardingNumber=[forwarding number]
    // &subscriberNumber=undefined
    // &phoneType=[phone type from google]
    // &remember=0
    // &_rnr_se=[pull from page]

    calldata.append("outgoingNumber=");
    calldata.append(URLEncoder.encode(destinationNumber, enc));
    calldata.append("&forwardingNumber=");
    calldata.append(URLEncoder.encode(originNumber, enc));
    calldata.append("&subscriberNumber=undefined");
    calldata.append("&phoneType=");
    calldata.append(URLEncoder.encode(phoneType, enc));
    calldata.append("&remember=0");
    calldata.append("&_rnr_se=");
    calldata.append(URLEncoder.encode(rnrSEE, enc));

    URL callURL = new URL("https://www.google.com/voice/b/0/call/connect/");

    URLConnection callconn = callURL.openConnection();
    callconn.setRequestProperty("Authorization", "GoogleLogin auth=" + authToken);
    callconn.setRequestProperty("User-agent", USER_AGENT);

    callconn.setDoOutput(true);
    OutputStreamWriter callwr = new OutputStreamWriter(callconn.getOutputStream());

    callwr.write(calldata.toString());
    callwr.flush();

    BufferedReader callrd = new BufferedReader(new InputStreamReader(callconn.getInputStream()));

    String line;
    while ((line = callrd.readLine()) != null) {
        out += line + "\n\r";

    }

    callwr.close();
    callrd.close();

    if (out.equals("")) {
        throw new IOException("No Response Data Received.");
    }

    return out;

}

From source file:com.techventus.server.voice.Voice.java

/**
 * Use this login method to login - use captchaAnswer to answer a captcha challenge
 * @param pCaptchaAnswer (optional) String entered by the user as an answer to a CAPTCHA challenge. - null to make a normal login attempt
 * @param pCaptchaToken (optional) token which matches the response/url from the captcha challenge
 * @throws IOException if login encounters a connection error
 *//* w w w.j  a  v a2  s  . c o m*/
public void login(String pCaptchaAnswer, String pCaptchaToken) throws IOException {

    String data = URLEncoder.encode("accountType", enc) + "=" + URLEncoder.encode(account_type, enc);
    data += "&" + URLEncoder.encode("Email", enc) + "=" + URLEncoder.encode(user, enc);
    data += "&" + URLEncoder.encode("Passwd", enc) + "=" + URLEncoder.encode(pass, enc);
    data += "&" + URLEncoder.encode("service", enc) + "=" + URLEncoder.encode(SERVICE, enc);
    data += "&" + URLEncoder.encode("source", enc) + "=" + URLEncoder.encode(source, enc);
    if (pCaptchaAnswer != null && pCaptchaToken != null) {
        data += "&" + URLEncoder.encode("logintoken", enc) + "=" + URLEncoder.encode(pCaptchaToken, enc);
        data += "&" + URLEncoder.encode("logincaptcha", enc) + "=" + URLEncoder.encode(pCaptchaAnswer, enc);
    }

    // Send data
    URL url = new URL(loginURLString);
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setRequestProperty("User-agent", USER_AGENT);

    conn.setDoOutput(true);
    OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
    wr.write(data);
    wr.flush();

    // Get the response
    conn.connect();
    int responseCode = conn.getResponseCode();
    if (PRINT_TO_CONSOLE)
        System.out.println(loginURLString + " - " + conn.getResponseMessage());
    InputStream is;
    if (responseCode == 200) {
        is = conn.getInputStream();
    } else {
        is = conn.getErrorStream();
    }
    InputStreamReader isr = new InputStreamReader(is);
    BufferedReader rd = new BufferedReader(isr);
    String line;
    String completelineDebug = "";

    /*
     * A failure response contains an error code and a URL to an error page that can be displayed to the user. 
     * If the error code is a CAPTCHA challenge, the response also includes a URL to a CAPTCHA image and a special 
     * token. Your application should be able to solicit an answer from the user and then retry the login request. 
     * To display the CAPTCHA image to the user, prefix the CaptchaUrl value with "http://www.google.com/accounts/", 
     * for example: " http://www.google.com/accounts/Captcha?ctoken=HiteT4b0Bk5Xg18_AcVoP6-yFkHPibe7O9EqxeiI7lUSN".
     */
    String lErrorString = "Unknown Connection Error."; // ex: Error=CaptchaRequired

    // String AuthToken = null;
    while ((line = rd.readLine()) != null) {
        completelineDebug += line + "\n";
        if (line.contains("Auth=")) {
            this.authToken = line.split("=", 2)[1].trim();
            if (PRINT_TO_CONSOLE) {
                System.out.println("Logged in to Google - Auth token received");
            }
        } else if (line.contains("Error=")) {
            lErrorString = line.split("=", 2)[1].trim();
            //error = getErrorEnumByCode(lErrorString);
            error = ERROR_CODE.valueOf(lErrorString);
            if (PRINT_TO_CONSOLE)
                System.out.println("Login error - " + lErrorString);

        }
        if (line.contains("CaptchaToken=")) {
            captchaToken = line.split("=", 2)[1].trim();
        }

        if (line.contains("CaptchaUrl=")) {
            captchaUrl = "http://www.google.com/accounts/" + line.split("=", 2)[1].trim();
        }
        if (line.contains("Url=")) {
            captchaUrl2 = line.split("=", 2)[1].trim();
        }

    }
    wr.close();
    rd.close();

    //      if (PRINT_TO_CONSOLE){
    //         System.out.println(completelineDebug);
    //      }

    if (this.authToken == null) {
        AuthenticationException.throwProperException(error, captchaToken, captchaUrl);
    }

    String response = this.getRawPhonesInfo();
    int phoneIndex = response.indexOf("gc-user-number-value\">");
    this.phoneNumber = response.substring(phoneIndex + 22, phoneIndex + 36);
    this.phoneNumber = this.phoneNumber.replaceAll("[^a-zA-Z0-9]", "");
    if (this.phoneNumber.indexOf("+") == -1) {
        this.phoneNumber = "+1" + this.phoneNumber;
    }
}

From source file:com.cloud.bridge.service.EC2RestServlet.java

/**
* Send out an error response according to Amazon convention.
 *//*from  ww w  .j a  va 2  s  . c o  m*/
private void faultResponse(HttpServletResponse response, String errorCode, String errorMessage) {
    try {
        OutputStreamWriter out = new OutputStreamWriter(response.getOutputStream());
        response.setContentType("text/xml; charset=UTF-8");
        out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        out.write("<Response><Errors><Error><Code>");
        out.write(errorCode);
        out.write("</Code><Message>");
        out.write(errorMessage);
        out.write("</Message></Error></Errors><RequestID>");
        out.write(UUID.randomUUID().toString());
        out.write("</RequestID></Response>");
        out.flush();
        out.close();
    } catch (IOException e) {
        logger.error("Unexpected exception " + e.getMessage(), e);
    }
}

From source file:study.tdcc.act.MainCalendar.java

/**
 * XML?????/*w w w  .ja  va2 s  .com*/
 * 
 * @param strUrl
 * @param strXml
 * @param strMethod (PUT,DELETE)
 * @return InputStream ???InputStream
 */
public InputStream httpPostXml(String strUrl, String strXml, String strMethod) {
    Log.d("DEBUG", "MainCalendar httpPostXml Start");
    blHttpSucceeded = false;
    try {
        while (strUrl != null) {
            URL urlObj = new URL(strUrl);
            //URL?????
            HttpURLConnection httpURLCObj = (HttpURLConnection) urlObj.openConnection();
            //?POST?
            httpURLCObj.setRequestMethod("POST");
            //GData-Version?
            httpURLCObj.setRequestProperty(GDATA_VERSION_TAG, GDATA_VERSION);
            if (strMethod != null) {
                //POST??????If-Match:*?X-HTTP-Method-Override
                httpURLCObj.setRequestProperty("If-Match", "*");
                httpURLCObj.setRequestProperty("X-HTTP-Method-Override", strMethod);
            }
            //
            httpURLCObj.setDoOutput(true);
            //Content-Type??XML
            httpURLCObj.setRequestProperty("Content-Type", CONTENT_TYPE_AA);
            //
            httpURLCObj.setUseCaches(false);
            //OutputStreamWriter??XML??
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(httpURLCObj.getOutputStream(),
                    "UTF-8");
            outputStreamWriter.write(strXml);
            outputStreamWriter.close();
            //HTTP??
            intResponseCode = 0;
            intResponseCode = httpURLCObj.getResponseCode();
            strUrl = null;
            Log.d("DEBUG", "MainCalendar httpPostXml HttpResponseCode : " + intResponseCode);
            if (intResponseCode == HttpURLConnection.HTTP_OK
                    || intResponseCode == HttpURLConnection.HTTP_CREATED) {
                //??OK???CREATED?????
                blHttpSucceeded = true;
                Log.d("DEBUG", "MainCalendar httpPostXml End(1)");
                //?InputStream??
                return httpURLCObj.getInputStream();
            } else if (intResponseCode == HttpURLConnection.HTTP_MOVED_TEMP) {
                //??MOVED_TEMP?????????
                //?Location????URL????(?while?
                Map<String, List<String>> mResponseHeaders = httpURLCObj.getHeaderFields();
                if (mResponseHeaders.containsKey("Location")) {
                    strUrl = mResponseHeaders.get("Location").get(0);
                } else if (mResponseHeaders.containsKey("location")) {
                    strUrl = mResponseHeaders.get("location").get(0);
                }
            } else {
                //??OK???CREATED???MOVED_TEMP??
                blHttpSucceeded = false;
                Log.d("DEBUG",
                        "MainCalendar httpPostXml End(2)  ??OK,CREATED,MOVED_TEMP??");
            }
        }
    } catch (Exception e) {
        Log.e("ERROR", "MainCalendar httpPostXml ERROR", e);
    }
    Log.d("DEBUG", "MainCalendar httpPostXml End(3)");
    return null;
}

From source file:cz.cas.lib.proarc.common.export.mets.structure.MetsElementVisitor.java

/**
 * Saves the mets document into a file//from   w  w w  . ja  va 2s  .c  o  m
 *
 * @param mets
 * @param outputFile
 * @throws MetsExportException
 */
private void saveMets(Mets mets, File outputFile, IMetsElement metsElement) throws MetsExportException {
    String fileMd5Name;
    try {
        addFileGrpToMets(fileGrpMap);
        addStructLink();
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(Mets.class, OaiDcType.class,
                    ModsDefinition.class);
            Marshaller marshaller = jaxbContext.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.setProperty(Marshaller.JAXB_ENCODING, "utf-8");
            // marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION,
            // "http://www.w3.org/2001/XMLSchema-instance http://www.w3.org/2001/XMLSchema.xsd http://www.loc.gov/METS/ http://www.loc.gov/standards/mets/mets.xsd http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/mods.xsd http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd");
            marshaller.marshal(mets, outputFile);
            MessageDigest md;
            try {
                md = MessageDigest.getInstance("MD5");
            } catch (NoSuchAlgorithmException e) {
                throw new MetsExportException("Unable to create MD5 hash", false, e);
            }
            md.reset();
            InputStream is;
            try {
                is = new FileInputStream(outputFile);
            } catch (FileNotFoundException e) {
                throw new MetsExportException("Unable to open file:" + outputFile.getAbsolutePath(), false, e);
            }
            byte[] bytes = new byte[2048];
            int numBytes;
            long totalBytes = 0;
            try {
                while ((numBytes = is.read(bytes)) != -1) {
                    totalBytes = totalBytes + numBytes;

                    md.update(bytes, 0, numBytes);
                }
            } catch (IOException e) {
                throw new MetsExportException("Unable to generate MD5 hash", false, e);
            }
            byte[] digest = md.digest();
            String result = new String(Hex.encodeHex(digest));
            metsElement.getMetsContext().getFileList()
                    .add(new FileMD5Info("." + File.separator + outputFile.getName(), result, totalBytes));
            fileMd5Name = "MD5_" + MetsUtils.removeNonAlpabetChars(metsElement.getMetsContext().getPackageID())
                    + ".md5";
            File fileMd5 = new File(metsElement.getMetsContext().getOutputPath() + File.separator
                    + metsElement.getMetsContext().getPackageID() + File.separator + fileMd5Name);
            OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(fileMd5));
            for (FileMD5Info info : metsElement.getMetsContext().getFileList()) {
                osw.write(info.getMd5() + " " + info.getFileName() + "\n");
            }
            osw.close();
            is.close();

            // calculate md5 for md5file - it's inserted into info.xml
            is = new FileInputStream(fileMd5);
            FileMD5Info md5InfoMd5File = MetsUtils.getDigest(is);
            is.close();
            metsElement.getMetsContext().getFileList()
                    .add(new FileMD5Info("." + File.separator + fileMd5Name, null, fileMd5.length()));
            MetsUtils.saveInfoFile(metsElement.getMetsContext().getOutputPath(), metsElement.getMetsContext(),
                    md5InfoMd5File.getMd5(), fileMd5Name, outputFile);
        } catch (Exception ex) {
            throw new MetsExportException(metsElement.getOriginalPid(),
                    "Unable to save mets file:" + outputFile.getAbsolutePath(), false, ex);
        }
        List<String> validationErrors;
        try {
            validationErrors = MetsUtils.validateAgainstXSD(outputFile,
                    Mets.class.getResourceAsStream("mets.xsd"));
        } catch (Exception ex) {
            throw new MetsExportException("Error while validation document:" + outputFile, false, ex);
        }
        if (validationErrors.size() > 0) {
            MetsExportException metsException = new MetsExportException("Invalid mets file:" + outputFile,
                    false, null);
            metsException.getExceptions().get(0).setValidationErrors(validationErrors);
            for (String error : validationErrors) {
                LOG.fine(error);
            }
            throw metsException;
        }
        LOG.log(Level.FINE,
                "Element validated:" + metsElement.getOriginalPid() + "(" + metsElement.getElementType() + ")");
    } finally {
        JhoveUtility.destroyConfigFiles(metsElement.getMetsContext().getJhoveContext());
    }
    metsElement.getMetsContext().getGeneratedPSP().add(metsElement.getMetsContext().getPackageID());
}

From source file:edu.unc.lib.dl.admin.controller.RESTProxyController.java

@RequestMapping(value = { "/services/rest", "/services/rest/*", "/services/rest/**/*" })
public final void proxyAjaxCall(HttpServletRequest request, HttpServletResponse response) throws IOException {
    log.debug("Prepending service url " + this.servicesUrl + " to " + request.getRequestURI());
    String url = request.getRequestURI().replaceFirst(".*/services/rest/?", this.servicesUrl);
    if (request.getQueryString() != null)
        url = url + "?" + request.getQueryString();

    OutputStreamWriter writer = new OutputStreamWriter(response.getOutputStream());
    HttpClient client = new HttpClient();
    HttpMethod method = null;//w w  w. ja  v  a  2s .c o m
    try {
        log.debug("Proxying ajax request to services REST api via " + request.getMethod());
        // Split this according to the type of request
        if (request.getMethod().equals("GET")) {
            method = new GetMethod(url);
        } else if (request.getMethod().equals("POST")) {
            method = new PostMethod(url);
            // Set any eventual parameters that came with our original
            // request (POST params, for instance)
            Enumeration<String> paramNames = request.getParameterNames();
            while (paramNames.hasMoreElements()) {
                String paramName = paramNames.nextElement();
                ((PostMethod) method).setParameter(paramName, request.getParameter(paramName));
            }
        } else {
            throw new NotImplementedException("This proxy only supports GET and POST methods.");
        }

        // Forward the user's groups along with the request
        method.addRequestHeader(HttpClientUtil.SHIBBOLETH_GROUPS_HEADER, GroupsThreadStore.getGroupString());
        method.addRequestHeader("On-Behalf-Of", GroupsThreadStore.getUsername());

        // Execute the method
        client.executeMethod(method);

        // Set the content type, as it comes from the server
        Header[] headers = method.getResponseHeaders();
        for (Header header : headers) {
            if ("Content-Type".equalsIgnoreCase(header.getName())) {
                response.setContentType(header.getValue());
            }
        }
        try (InputStream responseStream = method.getResponseBodyAsStream()) {
            int b;
            while ((b = responseStream.read()) != -1) {
                response.getOutputStream().write(b);
            }
        }
        response.getOutputStream().flush();
    } catch (HttpException e) {
        writer.write(e.toString());
        throw e;
    } catch (IOException e) {
        e.printStackTrace();
        writer.write(e.toString());
        throw e;
    } finally {
        if (method != null)
            method.releaseConnection();
    }
}

From source file:geotheme.servlet.wms.java

/**
 * @see HttpServlet#service(HttpServletRequest req, HttpServletResponse res)
 *//*  w ww  .ja  v  a  2 s.  c o m*/
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

    OutputStreamWriter wr = null;
    InputStream in = null;
    OutputStream out = null;

    //req.setCharacterEncoding("UTF-8");

    try {
        Map<String, Object> reqMap = new HashMap<String, Object>();

        Enumeration<?> en = req.getParameterNames();
        String key = new String();

        /**
         * Converting all Map Keys into Upper Case
         **/
        while (en.hasMoreElements()) {
            key = (String) en.nextElement();
            reqMap.put(key.toUpperCase(), req.getParameter(key));
        }

        wmsParamBean wmsBean = new wmsParamBean();
        BeanUtils.populate(wmsBean, reqMap);

        HttpSession session = req.getSession(true);

        /**
         * Reading the saved SLD
         **/
        String sessionName = wmsBean.getLAYER();

        if (sessionName.length() < 1)
            sessionName = wmsBean.getLAYERS();

        if (session.getAttribute(sessionName) != null) {

            wmsBean.setSLD_BODY((String) session.getAttribute(sessionName));
            wmsBean.setSLD("");
            wmsBean.setSTYLES("");
        }

        if (wmsBean.getREQUEST().compareToIgnoreCase("GetPDFGraphic") == 0) {
            /**
             * Generate PDF Request
             */
            generatePDF pdf = new generatePDF(this.pdfURL, this.pdfLayers);

            ByteArrayOutputStream baos = pdf.createPDFFromImage(wmsBean, this.geoserverURL);

            res.addHeader("Content-Type", "application/force-download");
            res.addHeader("Content-Disposition", "attachment; filename=\"MapOutput.pdf\"");

            res.getOutputStream().write(baos.toByteArray());
        } else {
            /**
             * Generating Map from GeoServer
             **/
            URL geoURL = new URL(this.geoserverURL);

            URLConnection geoConn = geoURL.openConnection();
            geoConn.setDoOutput(true);

            wr = new OutputStreamWriter(geoConn.getOutputStream(), "UTF-8");
            wr.write(wmsBean.getURL_PARAM());
            wr.flush();

            in = geoConn.getInputStream();
            out = res.getOutputStream();

            res.setContentType(wmsBean.getFORMAT());

            int b;
            while ((b = in.read()) != -1) {
                out.write(b);
            }
        }
    } catch (Exception e) {
        //e.printStackTrace();
    } finally {
        if (out != null) {
            out.flush();
            out.close();
        }
        if (in != null) {
            in.close();
        }
        if (wr != null) {
            wr.close();
        }
    }
}

From source file:net.jotel.ws.client.WebSocketClient.java

private void handshake() throws IOException {
    OutputStreamWriter writer = new OutputStreamWriter(outputStream, Charset.forName("UTF8"));

    // Once a connection to the server has been established (including a
    // connection via a proxy or over a TLS-encrypted tunnel), the client
    // MUST send an opening handshake to the server. The handshake consists
    // of an HTTP upgrade request, along with a list of required and
    // optional headers. The requirements for this handshake are as
    // follows.//from www  .  ja v  a 2 s  .  co  m

    // 1. The handshake MUST be a valid HTTP request as specified by
    // [RFC2616].

    // 2. The Method of the request MUST be GET and the HTTP version
    // MUST be at least 1.1.

    log.debug("Upgrade request");
    // 3. The request MUST contain a "Request-URI" as part of the GET
    // method. This MUST match the /resource name/ Section 3 (a
    // relative URI), or be an absolute URI that, when parsed, has a
    // matching /resource name/ as well as matching /host/, /port/, and
    // appropriate scheme (ws or wss).
    writer.write("GET ");
    writer.write(resourceName);
    writer.write(" HTTP/1.1\r\n");

    // 4. The request MUST contain a "Host" header whose value is equal to
    // /host/.
    writer.write(HOST_HEADER);
    writer.write(": ");
    writer.write(host);
    writer.write(CRLF);

    // 5. The request MUST contain an "Upgrade" header whose value is
    // equal to "websocket".
    writer.write(UPGRADE_HEADER);
    writer.write(": websocket\r\n");

    // 6. The request MUST contain a "Connection" header whose value MUST
    // include the "Upgrade" token.
    writer.write(CONNECTION_HEADER);
    writer.write(": Upgrade\r\n");

    // 7. The request MUST include a header with the name "Sec-WebSocket-
    // Key". The value of this header MUST be a nonce consisting of a
    // randomly selected 16-byte value that has been base64-encoded
    // [RFC3548]. The nonce MUST be selected randomly for each
    // connection.

    SecWebSocketKey key = generateSecWebSocketKey();

    writer.write(SEC_WEB_SOCKET_KEY_HEADER);
    writer.write(": ");
    writer.write(key.getKey());
    writer.write(CRLF);

    // 8. The request MUST include a header with the name "Sec-WebSocket-
    // Origin" if the request is coming from a browser client. If the
    // connection is from a non-browser client, the request MAY include
    // this header if the semantics of that client match the use-case
    // described here for browser clients. The value of this header
    // MUST be the ASCII serialization of origin of the context in
    // which the code establishing the connection is running, and MUST
    // be lower-case. The value MUST NOT contain letters in the range
    // U+0041 to U+005A (i.e. LATIN CAPITAL LETTER A to LATIN CAPITAL
    // LETTER Z) [I-D.ietf-websec-origin]. The ABNF is as defined in
    // Section 6.1 of [I-D.ietf-websec-origin].
    writer.write(ORIGIN_HEADER);
    writer.write(": ");
    writer.write(origin);
    writer.write(CRLF);

    // 9. The request MUST include a header with the name "Sec-WebSocket-
    // Version". The value of this header MUST be 8.
    writer.write(SEC_WEB_SOCKET_VERSION_HEADER);
    writer.write(": 8\r\n");

    // 10. The request MAY include a header with the name "Sec-WebSocket-
    // Protocol". If present, this value indicates the subprotocol(s)
    // the client wishes to speak, ordered by preference. The elements
    // that comprise this value MUST be non-empty strings with
    // characters in the range U+0021 to U+007E not including separator
    // characters as defined in [RFC2616], and MUST all be unique
    // strings. The ABNF for the value of this header is 1#token,
    // where the definitions of constructs and rules are as given in
    // [RFC2616].
    //
    if (!StringUtils.isBlank(protocol)) {
        writer.write(SEC_WEB_SOCKET_PROTOCOL_HEADER);
        writer.write(": ");
        writer.write(protocol);
        writer.write(CRLF);
    }

    // 11. The request MAY include a header with the name "Sec-WebSocket-
    // Extensions". If present, this value indicates the protocol-
    // level extension(s) the client wishes to speak. The
    // interpretation and format of this header is described in
    // Section 9.1.

    // TODO

    // 12. The request MAY include headers associated with sending cookies,
    // as defined by the appropriate specifications
    // [I-D.ietf-httpstate-cookie]. These headers are referred to as
    // _Headers to Send Appropriate Cookies_.
    //

    // TODO

    // extra headers
    for (Map.Entry<String, String> entry : extraHeaders.entrySet()) {
        writer.write(entry.getKey());
        writer.write(": ");
        writer.write(entry.getValue());
        writer.write(CRLF);
    }

    writer.write(CRLF);
    writer.flush();

    // Once the client's opening handshake has been sent, the client MUST
    // wait for a response from the server before sending any further data.

    String code = readStatusCode(inputStream);

    log.debug("Server response code {}", code);
    // The client MUST validate the server's response as follows:

    // 1. If the status code received from the server is not 101, the
    // client handles the response per HTTP procedures. Otherwise,
    // proceed as follows.

    if (!"101".equals(code)) {
        throw new WebSocketException("Invalid handshake response");
    }

    Map<String, List<String>> fieldMap = readFields(inputStream);

    String value;

    // 2. If the response lacks an "Upgrade" header or the "Upgrade" header
    // contains a value that is not an ASCII case-insensitive match for
    // the value "websocket", the client MUST _Fail the WebSocket
    // Connection _.

    value = getFieldValue(fieldMap, "upgrade");
    if (!"WebSocket".equalsIgnoreCase(value)) {
        throw new WebSocketException("Expected WebSocket as Updgrade field value!");
    }

    // 3. If the response lacks a "Connection" header or the "Connection"
    // header contains a value that is not an ASCII case-insensitive
    // match for the value "Upgrade", the client MUST _Fail the
    // WebSocket Connection_.
    value = getFieldValue(fieldMap, "connection");
    if (!UPGRADE_HEADER.equalsIgnoreCase(value)) {
        throw new WebSocketException("Expected Upgrade as Connection field value!");
    }

    // 4. If the response lacks a "Sec-WebSocket-Accept" header or the
    // "Sec-WebSocket-Accept" contains a value other than the base64-
    // encoded SHA-1 of the concatenation of the "Sec-WebSocket-Key" (as
    // a string, not base64-decoded) with the string "258EAFA5-E914-
    // 47DA-95CA-C5AB0DC85B11", the client MUST _Fail the WebSocket
    // Connection_
    value = getFieldValue(fieldMap, "sec-websocket-accept");

    if (!key.isServerKeyValid(value)) {
        throw new WebSocketException("Server key doesn't match an expected response");
    }

    // 5. If the response includes a "Sec-WebSocket-Extensions" header, and
    // this header indicates the use of an extension that was not
    // present in the client' handshake (the server has indicated an
    // extension not requested by the client), the client MUST _Fail the
    // WebSocket Connection_. (The parsing of this header to determine
    // which extensions are requested is discussed in Section 9.1.)

    value = getFieldValue(fieldMap, "sec-websocket-extensions");
    if (!StringUtils.isEmpty(value)) {
        throw new WebSocketException("The server has indicated an extension not request by the client!");
    }

    if (fieldMap.containsKey("")) {
        throw new WebSocketException("Empty field name found in field list!");
    }

    // If the server's response is validated as provided for above, it is
    // said that _The WebSocket Connection is Established_ and that the
    // WebSocket Connection is in the OPEN state. The _Extensions In Use_
    // is defined to be a (possibly empty) string, the value of which is
    // equal to the value of the |Sec-WebSocket-Extensions| header supplied
    // by the server's handshake, or the null value if that header was not
    // present in the server's handshake. The _Subprotocol In Use_ is
    // defined to be the value of the |Sec-WebSocket-Protocol| header in the
    // server's handshake, or the null value if that header was not present
    // in the server's handshake. Additionally, if any headers in the
    // server's handshake indicate that cookies should be set (as defined by
    // [I-D.ietf-httpstate-cookie]), these cookies are referred to as
    // _Cookies Set During the Server's Opening Handshake_.
}