All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.taobao.api.internal.toplink.embedded.websocket.impl.WebSocketDraft76 Maven / Gradle / Ivy

/*
 * The MIT License
 * 
 * Copyright (c) 2011 Takahiro Hashimoto
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.taobao.api.internal.toplink.embedded.websocket.impl;

import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.util.Random;
//import java.util.logging.Logger;


import com.taobao.api.internal.toplink.embedded.websocket.WebSocket;
import com.taobao.api.internal.toplink.embedded.websocket.exception.WebSocketException;
import com.taobao.api.internal.toplink.embedded.websocket.frame.Frame;
import com.taobao.api.internal.toplink.embedded.websocket.frame.FrameHeader;
import com.taobao.api.internal.toplink.embedded.websocket.frame.FrameParser;
import com.taobao.api.internal.toplink.embedded.websocket.frame.draft76.BinaryFrame;
import com.taobao.api.internal.toplink.embedded.websocket.frame.draft76.CloseFrame;
import com.taobao.api.internal.toplink.embedded.websocket.frame.draft76.FrameBuilderDraft76;
import com.taobao.api.internal.toplink.embedded.websocket.frame.draft76.TextFrame;
import com.taobao.api.internal.toplink.embedded.websocket.handler.StreamHandlerAdapter;
import com.taobao.api.internal.toplink.embedded.websocket.handler.StreamHandlerChain;
import com.taobao.api.internal.toplink.embedded.websocket.handler.WebSocketHandler;
import com.taobao.api.internal.toplink.embedded.websocket.handler.WebSocketPipeline;
import com.taobao.api.internal.toplink.embedded.websocket.handshake.Handshake;
import com.taobao.api.internal.toplink.embedded.websocket.proxy.Proxy;

import static com.taobao.api.internal.toplink.embedded.websocket.exception.ErrorCode.*;


/**
 * A simple websocket client
 * this class is implement the WebSocket Draft76 specification.
 * 
 * @see draft-hixie-thewebsocketprotocol-76
 * @author t-hashimoto
 * 
 */
public class WebSocketDraft76 extends WebSocketBase {
	
	/** The logger. */
	//private static Logger logger = Logger.getLogger(WebSocketDraft76.class.getName());

	/** The Constant VERSION. */
	private static final int VERSION = 76;

	/**
	 * Instantiates a new web socket draft76.
	 *
	 * @param url the url
	 * @param handler the handler
	 * @param protocols the protocols
	 * @throws WebSocketException the web socket exception
	 */
	public WebSocketDraft76(String url, WebSocketHandler handler,
			String... protocols) throws WebSocketException {
		super(url, (String)null, handler, protocols);
	}
	
	/**
	 * Instantiates a new web socket draft76.
	 *
	 * @param url the url
	 * @param proxy the proxy
	 * @param handler the handler
	 * @param protocols the protocols
	 * @throws WebSocketException the web socket exception
	 */
	public WebSocketDraft76(String url, Proxy proxy, WebSocketHandler handler,
			String... protocols) throws WebSocketException {
		super(url, (String)null, proxy, handler, protocols);
	}
	
	/* (non-Javadoc)
	 * @see jp.a840.websocket.impl.WebSocketBase#newHandshakeInstance()
	 */
	@Override
	protected Handshake newHandshakeInstance() {
		return new Handshake() {
			private ByteBuffer bodyBuf = ByteBuffer.allocate(16);
			
			/**
			 * Create a handshake requtest
			 * 
			 * 
			 * Sample (Draft76) client => server
			 * GET /demo HTTP/1.1
			 * Host: example.com
			 * Connection: Upgrade
			 * Sec-WebSocket-Key2: 12998 5 Y3 1  .P00
			 * Sec-WebSocket-Protocol: sample
			 * Upgrade: WebSocket
			 * Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5
			 * Origin: http://example.com
			 * 
			 * ^n:ds[4U
			 * 
* */ @Override public ByteBuffer createHandshakeRequest() { bodyBuf.clear(); // initilize a buffer // Send GET request to server StringBuilder sb = new StringBuilder(); sb.append("GET " + path + " HTTP/1.1\r\n"); addHeader(sb, "Host", endpointAddress.getHostName()); addHeader(sb, "Upgrade", "websocket"); addHeader(sb, "Connection", "Upgrade"); addHeader(sb, "Sec-WebSocket-Key1", SecWebSocketKey.generateKey()); addHeader(sb, "Sec-WebSocket-Key2", SecWebSocketKey.generateKey()); if (origin != null) { addHeader(sb, "Origin", origin); } if (protocols != null && protocols.length > 0) { addHeader(sb, "Sec-WebSocket-Protocol", join(",", protocols)); } sb.append("\r\n"); ByteBuffer buf = ByteBuffer.allocate(512); buf.put(sb.toString().getBytes()); buf.put(SecWebSocketKey.generateKey3()); buf.put((byte) 0xd); buf.put((byte) 0xa); buf.flip(); return buf; } /** * check handshake response * *
			 * server => client
			 * HTTP/1.1 101 WebSocket Protocol Handshake
			 * Upgrade: WebSocket
			 * Connection: Upgrade
			 * Sec-WebSocket-Origin: http://example.com
			 * Sec-WebSocket-Location: ws://example.com/demo
			 * Sec-WebSocket-Protocol: sample
			 * 
			 * 8jKS'y:G*Co,Wxa-
			 * 
* * @param buffer */ @Override protected boolean parseHandshakeResponseHeader(ByteBuffer buffer) throws WebSocketException { if(!super.parseHandshakeResponseHeader(buffer)){ return false; } if(!"websocket".equalsIgnoreCase(this.getResponseHeader().getHeaderValue("upgrade"))){ throw new WebSocketException(E3500, responseHeader.getHeaderValue("upgrade")); } if(!"upgrade".equalsIgnoreCase(this.getResponseHeader().getHeaderValue("connection"))){ throw new WebSocketException(E3501, responseHeader.getHeaderValue("connection")); } String serverOrigin = this.getResponseHeader().getHeaderValue("sec-websocket-origin"); if(origin != null && serverOrigin != null && !serverOrigin.equals(origin)){ throw new WebSocketException(E3502, origin, serverOrigin); } String serverLocation = this.getResponseHeader().getHeaderValue("sec-websocket-location"); try{ // reformat location URI. // drop custom port URI uri = new URI(location.getScheme(), location.getHost(), location.getPath(), location.getFragment() ); if(serverLocation != null && !serverLocation.equals(uri.toString())){ throw new WebSocketException(E3503, uri.toString(), serverLocation); } }catch(URISyntaxException e){ ; } String protocolStr = this.getResponseHeader().getHeaderValue("sec-websocket-protocol"); if(protocolStr != null){ serverProtocols = protocolStr.split(","); } return true; } @Override protected boolean parseHandshakeResponseBody(ByteBuffer buffer) throws WebSocketException { if(!super.parseHandshakeResponseBody(buffer)){ return false; } if(buffer.remaining() < bodyBuf.capacity()){ return false; } buffer.get(bodyBuf.array(), 0, bodyBuf.capacity()); return true; } }; } /* (non-Javadoc) * @see jp.a840.websocket.impl.WebSocketBase#getWebSocketVersion() */ @Override protected int getWebSocketVersion() { return VERSION; } /** * The Class SecWebSocketKey. * * @author Takahiro Hashimoto */ private static class SecWebSocketKey { /** The Constant random. */ private static final Random random = new Random(); /** The Constant LARGEST_INTEGER. */ private static final long LARGEST_INTEGER = 4294967295L; /** The Constant CHARS. */ private static final char[] CHARS = new char[84]; static { int i = 0; for (int c = 0x21; c <= 0x2F; c++) { CHARS[i++] = (char) c; } for (int c = 0x3A; c <= 0x7E; c++) { CHARS[i++] = (char) c; } } /** * Generate key. * * @return the string */ public static String generateKey() { int spaces = random.nextInt(12) + 1; long max = LARGEST_INTEGER / spaces; long number = Math.abs(random.nextLong()) % max; long product = number * spaces; StringBuilder key = new StringBuilder(); key.append(product); int charsNum = random.nextInt(12) + 1; for (int i = 0; i < charsNum; i++) { int position = random.nextInt(key.length()); char c = CHARS[random.nextInt(CHARS.length)]; key.insert(position, c); } for (int i = 0; i < spaces; i++) { int position = random.nextInt(key.length() - 1) + 1; key.insert(position, ' '); } return key.toString(); } /** * Generate key3. * * @return the byte[] */ public static byte[] generateKey3() { byte[] key3 = new byte[8]; random.nextBytes(key3); return key3; } } @Override public Frame createFrame(byte[] bytes) throws WebSocketException { return new BinaryFrame(bytes); } /* (non-Javadoc) * @see jp.a840.websocket.impl.WebSocketBase#createFrame(java.lang.String) */ @Override public Frame createFrame(String str) throws WebSocketException { return new TextFrame(str); } /* (non-Javadoc) * @see jp.a840.websocket.impl.WebSocketBase#newFrameParserInstance() */ @Override protected FrameParser newFrameParserInstance() { return new FrameParser() { @Override protected FrameHeader createFrameHeader(ByteBuffer chunkData) { return FrameBuilderDraft76.createFrameHeader(chunkData); } @Override protected Frame createFrame(FrameHeader h, byte[] bodyData) { return FrameBuilderDraft76.createFrame(h, bodyData); } }; } /* (non-Javadoc) * @see jp.a840.websocket.impl.WebSocketBase#initializePipeline(jp.a840.websocket.handler.WebSocketPipeline) */ @Override protected void initializePipeline(WebSocketPipeline pipeline) throws WebSocketException { super.initializePipeline(pipeline); // Add base response handler this.pipeline.addStreamHandler(new StreamHandlerAdapter() { public void nextDownstreamHandler(WebSocket ws, ByteBuffer buffer, Frame frame, StreamHandlerChain chain) throws WebSocketException { if(frame instanceof CloseFrame){ WebSocketDraft76.this.handler.onClose(ws); }else{ WebSocketDraft76.this.handler.onMessage(ws, frame); } } public void nextHandshakeDownstreamHandler(WebSocket ws, ByteBuffer buffer, StreamHandlerChain chain) throws WebSocketException { // set response status responseHeader = getHandshake().getResponseHeader(); responseStatus = getHandshake().getResponseStatus(); transitionTo(State.WAIT); // HANDSHAKE -> WAIT WebSocketDraft76.this.handler.onOpen(WebSocketDraft76.this); } }); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy