Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(76)

Side by Side Diff: plugins/org.chromium.sdk.wipbackend.wk118685/src/org/chromium/sdk/internal/websocket/Hybi17Handshake.java

Issue 11829027: drop old backends (Closed) Base URL: https://chromedevtools.googlecode.com/svn/trunk
Patch Set: Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.sdk.internal.websocket;
6
7 import java.io.IOException;
8 import java.net.InetSocketAddress;
9 import java.nio.ByteBuffer;
10 import java.security.MessageDigest;
11 import java.security.NoSuchAlgorithmException;
12 import java.util.Collections;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Random;
16
17 import javax.xml.bind.DatatypeConverter;
18
19 import org.chromium.sdk.internal.websocket.ManualLoggingSocketWrapper.LoggableIn put;
20 import org.chromium.sdk.util.BasicUtil;
21
22 /**
23 * WebSocket connection handshake.
24 * @see http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17
25 */
26 class Hybi17Handshake {
27 static Result performHandshake(ManualLoggingSocketWrapper socket, InetSocketAd dress endpoint,
28 String resourceName, Random random) throws IOException {
29 final ManualLoggingSocketWrapper.LoggableInput input = socket.getLoggableInp ut();
30 ManualLoggingSocketWrapper.LoggableOutput output = socket.getLoggableOutput( );
31
32 writeHttpLine(output, "GET " + resourceName + " HTTP/1.1");
33
34 List<String> headerFields = HandshakeUtil.createHttpFields(endpoint);
35 headerFields.add("Upgrade: websocket");
36 headerFields.add("Host: " + endpoint.getHostName());
37
38 byte[] secKeyBytes = new byte[16];
39 random.nextBytes(secKeyBytes);
40
41 String secKeyString = DatatypeConverter.printBase64Binary(secKeyBytes);
42 headerFields.add("Sec-WebSocket-Key: " + secKeyString);
43 headerFields.add("Sec-WebSocket-Version: 13");
44
45 Collections.shuffle(headerFields, random);
46
47 for (String field : headerFields) {
48 writeHttpLine(output, field);
49 }
50
51 writeHttpLine(output, "");
52
53 HandshakeUtil.LineReader lineReader = new HandshakeUtil.LineReader() {
54 @Override
55 byte[] readUpTo0x0D0A() throws IOException {
56 ByteBuffer buffer = input.readUpTo0x0D0A();
57 byte[] result = new byte[buffer.limit()];
58 buffer.get(result);
59 return result;
60 }
61 };
62
63 HandshakeUtil.HttpResponse httpResponse = HandshakeUtil.readHttpResponse(lin eReader);
64
65 if (httpResponse.getCode() != 101) {
66 return processResult(input, httpResponse);
67 }
68
69 Map<String, String> responseFields = httpResponse.getFields();
70
71 if (!"websocket".equalsIgnoreCase(responseFields.get("upgrade"))) {
72 throw new IOException("Malformed response");
73 }
74 if (!"upgrade".equalsIgnoreCase(responseFields.get("connection"))) {
75 throw new IOException("Malformed response");
76 }
77 if (responseFields.get("sec-websocket-extensions") != null) {
78 throw new IOException("Malformed response");
79 }
80 if (responseFields.get("sec-websocket-protocol") != null) {
81 throw new IOException("Malformed response");
82 }
83
84 String secAcceptString = responseFields.get("sec-websocket-accept");
85 if (secAcceptString == null) {
86 throw new IOException("Malformed response");
87 }
88
89 String expectedConcatenation = secKeyString + GUID;
90 byte[] expectedAcceptSha1;
91 {
92 MessageDigest digest;
93 try {
94 digest = MessageDigest.getInstance("SHA-1");
95 } catch (NoSuchAlgorithmException e) {
96 throw new RuntimeException(e);
97 }
98 expectedAcceptSha1 = digest.digest(expectedConcatenation.getBytes());
99 }
100 String expectedAcceptString = DatatypeConverter.printBase64Binary(expectedAc ceptSha1);
101
102 if (!BasicUtil.eq(expectedAcceptString, secAcceptString)) {
103 throw new IOException("Malformed response");
104 }
105 return CONNECTED_RESULT;
106 }
107
108 static abstract class Result {
109 abstract <R> R accept(Visitor<R> visitor);
110
111 interface Visitor<R> {
112 R visitConnected();
113 R visitUnknownError(Exception exception);
114 R visitErrorMessage(int code, String errorName, String text);
115 }
116
117 static Result createError(final Exception exception) {
118 return new Result() {
119 @Override
120 <R> R accept(Visitor<R> visitor) {
121 return visitor.visitUnknownError(exception);
122 }
123 };
124 }
125 }
126
127 private static final Result CONNECTED_RESULT = new Result() {
128 @Override
129 <R> R accept(Visitor<R> visitor) {
130 return visitor.visitConnected();
131 }
132 };
133
134 private static Result processResult(LoggableInput input,
135 final HandshakeUtil.HttpResponse httpResponse) throws IOException {
136 Map<String, String> fields = httpResponse.getFields();
137 String contentType = fields.get("content-type");
138 String contentLength = fields.get("content-length");
139
140 if ("text/html".equals(contentType) && contentLength != null) {
141 int length;
142 try {
143 length = Integer.parseInt(contentLength);
144 } catch (NumberFormatException e) {
145 return Result.createError(new Exception("Failed to parse context-length field", e));
146 }
147 byte[] response = input.readBytes(length);
148 final String contentText = new String(response, HandshakeUtil.ASCII_CHARSE T);
149 return new Result() {
150 @Override
151 <R> R accept(Visitor<R> visitor) {
152 return visitor.visitErrorMessage(httpResponse.getCode(), httpResponse. getReasonPhrase(),
153 contentText);
154 }
155 };
156 }
157
158 return Result.createError(new Exception("Error response: " + httpResponse.ge tCode() + " " +
159 httpResponse.getReasonPhrase()));
160 }
161
162
163 private static void writeHttpLine(ManualLoggingSocketWrapper.LoggableOutput ou tput, String line)
164 throws IOException {
165 output.writeAsciiString(line + "\r\n");
166 }
167
168 private static final String GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
169 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698