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

Side by Side Diff: plugins/org.chromium.sdk.wipbackend.wk118685/src/org/chromium/sdk/internal/websocket/Hybi00Handshake.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.ByteArrayOutputStream;
8 import java.io.IOException;
9 import java.io.InputStream;
10 import java.io.OutputStream;
11 import java.io.OutputStreamWriter;
12 import java.io.Writer;
13 import java.net.InetSocketAddress;
14 import java.security.MessageDigest;
15 import java.security.NoSuchAlgorithmException;
16 import java.util.ArrayList;
17 import java.util.Arrays;
18 import java.util.Collections;
19 import java.util.HashSet;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Random;
23 import java.util.Set;
24
25 import org.chromium.sdk.internal.transport.SocketWrapper;
26
27 /**
28 * A more or less straightforward implementation of WebSocket client-side handsh ake
29 * as defined in Internet-Draft of May 23, 2010.
30 * See http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00
31 * <p>Note that the standard was reworked completely. This implementation is obs olete. However
32 * it is still compatible with the current Chrome implementation.
33 */
34 class Hybi00Handshake {
35 static void performHandshake(SocketWrapper socket, InetSocketAddress endpoint,
36 String resourceName, String origin, Random random) throws IOException {
37 HandshakeUtil.checkOriginString(origin);
38
39 OutputStream output = socket.getLoggableOutput().getOutputStream();
40 Writer outputWriter = new OutputStreamWriter(output, HandshakeUtil.UTF_8_CHA RSET);
41
42 outputWriter.write("GET " + resourceName + " HTTP/1.1\r\n");
43
44 List<String> fields = HandshakeUtil.createHttpFields(endpoint);
45 fields.add("Upgrade: WebSocket");
46 fields.add("Origin: " + origin);
47 int port = endpoint.getPort();
48 String portSuffix = port == 80 ? "" : ":" + port;
49 fields.add("Host: " + endpoint.getHostName() + portSuffix);
50 WsKey key1 = new WsKey(random);
51 WsKey key2 = new WsKey(random);
52 fields.add("Sec-WebSocket-Key1: " + key1.getKeySocketField());
53 fields.add("Sec-WebSocket-Key2: " + key2.getKeySocketField());
54
55 Collections.shuffle(fields, random);
56 for (String field : fields) {
57 outputWriter.write(field);
58 outputWriter.write("\r\n");
59 }
60 outputWriter.write("\r\n");
61 byte[] key3 = new byte[8];
62 random.nextBytes(key3);
63
64 outputWriter.flush();
65
66 output.write(key3);
67 output.flush();
68
69
70 byte[] expectedMd5Bytes;
71 {
72 // Challenge.
73 ByteArrayOutputStream challengeBytes = new ByteArrayOutputStream(16);
74 writeIntBigEndian(key1.getNumber(), challengeBytes);
75 writeIntBigEndian(key2.getNumber(), challengeBytes);
76 challengeBytes.write(key3);
77 MessageDigest digest;
78 try {
79 digest = MessageDigest.getInstance("MD5");
80 } catch (NoSuchAlgorithmException e) {
81 throw new RuntimeException(e);
82 }
83 expectedMd5Bytes = digest.digest(challengeBytes.toByteArray());
84 }
85
86 final InputStream input = socket.getLoggableInput().getInputStream();
87
88 HandshakeUtil.LineReader lineReader = HandshakeUtil.createLineReader(input);
89
90 HandshakeUtil.HttpResponse httpResponse = HandshakeUtil.readHttpResponse(lin eReader);
91
92 if (httpResponse.getCode() != 101) {
93 throw new IOException("Unexpected response code " + httpResponse.getCode() );
94 }
95
96 Map<String, String> responseFields = httpResponse.getFields();
97
98 if (responseFields.size() != EXPECTED_FIELDS.size()) {
99 throw new IOException("Malformed response");
100 }
101 if (!responseFields.keySet().containsAll(EXPECTED_FIELDS)) {
102 throw new IOException("Malformed response");
103 }
104 if (!"WebSocket".equals(responseFields.get("upgrade"))) {
105 throw new IOException("Malformed response");
106 }
107 if (!"upgrade".equalsIgnoreCase(responseFields.get("connection"))) {
108 throw new IOException("Malformed response");
109 }
110 if (!origin.equals(responseFields.get("sec-websocket-origin"))) {
111 throw new IOException("Malformed response");
112 }
113 String expectedUrl = createUrl(endpoint, resourceName, false);
114 if (!expectedUrl.equals(responseFields.get("sec-websocket-location"))) {
115 throw new IOException("Malformed response: unexpected sec-websocket-locati on");
116 }
117
118 {
119 // Challenge response.
120 byte[] actualMd5Bytes = new byte[16];
121 {
122 int readPos = 0;
123 while (readPos < actualMd5Bytes.length) {
124 int readRes = input.read(actualMd5Bytes, readPos, actualMd5Bytes.lengt h - readPos);
125 if (readRes == -1) {
126 throw new IOException("End of stream");
127 }
128 readPos += readRes;
129 }
130 }
131 if (!Arrays.equals(expectedMd5Bytes, actualMd5Bytes)) {
132 throw new IOException("Wrong challenge response: expected=" +
133 Arrays.toString(expectedMd5Bytes) + " recieved=" + Arrays.toString(a ctualMd5Bytes));
134 }
135 }
136 }
137
138 private static String createUrl(InetSocketAddress endpoint, String resourceNam e,
139 boolean secure) {
140 boolean needPort;
141 if (secure) {
142 needPort = endpoint.getPort() != 443;
143 } else {
144 needPort = endpoint.getPort() != 80;
145 }
146 return (secure ? "wss://" : "ws://") +
147 endpoint.getHostName() +
148 (needPort ? ":" + endpoint.getPort() : "") +
149 resourceName;
150 }
151
152 private static void writeIntBigEndian(long value, OutputStream output) throws IOException {
153 output.write((byte) ((value & 0xFF000000L) >> (3 * 8)));
154 output.write((byte) ((value & 0xFF0000L) >> (2 * 8)));
155 output.write((byte) ((value & 0xFF00L) >> (1 * 8)));
156 output.write((byte) ((value & 0xFFL)));
157 }
158
159 private static final Set<String> EXPECTED_FIELDS = new HashSet<String>(Arrays. asList(
160 "upgrade",
161 "connection",
162 "sec-websocket-origin",
163 "sec-websocket-location"
164 ));
165
166 private static class WsKey {
167 private static final long SPEC_MAX = 4294967295l;
168
169 private final long resNumber;
170 private final String keyString;
171
172 WsKey(Random random) {
173 int spaces = random.nextInt(12) + 1;
174 long max = SPEC_MAX / spaces;
175 long number = Math.abs(random.nextLong()) % (max + 1);
176 resNumber = number;
177 long product = number * spaces;
178 assert(product <= SPEC_MAX);
179
180 String productStr = Long.toString(product);
181 List<Byte> keyBytes = new ArrayList<Byte>(40);
182 keyBytes.addAll(Collections.nCopies(productStr.length(), (byte) '1'));
183 int stuffByteNumber = random.nextInt(12) + 1;
184 for (int i = 0; i < stuffByteNumber; i++) {
185 keyBytes.add(StuffBytes.getByte(random));
186 }
187 Collections.shuffle(keyBytes, random);
188 keyBytes.subList(0, keyBytes.size() - 1).addAll(Collections.nCopies(spaces , (byte) ' '));
189 Collections.shuffle(keyBytes.subList(1, keyBytes.size() - 1), random);
190 byte[] resultBytes = new byte[keyBytes.size()];
191 int strPos = 0;
192 for (int i = 0; i < resultBytes.length; i++) {
193 byte b = keyBytes.get(i);
194 if (b == (byte) '1') {
195 b = (byte) productStr.charAt(strPos);
196 strPos++;
197 }
198 resultBytes[i] = b;
199 }
200 assert(strPos == productStr.length());
201 keyString = new String(resultBytes, HandshakeUtil.ASCII_CHARSET);
202 }
203
204 String getKeySocketField() {
205 return keyString;
206 }
207
208 long getNumber() {
209 return resNumber;
210 }
211
212 private static class StuffBytes {
213 private static byte RANGE_1_BEGIN = 0x21;
214 private static byte RANGE_1_END = 0x2F + 1;
215 private static byte RANGE_2_BEGIN = 0x3A;
216 private static byte RANGE_2_END = 0x7E + 1;
217
218 private static int RANDOM_RANGE_1 = RANGE_1_END - RANGE_1_BEGIN;
219 private static int RANDOM_RANGE = RANDOM_RANGE_1 + RANGE_2_END - RANGE_2_B EGIN;
220
221 private static byte getByte(Random random) {
222 int i = random.nextInt(RANDOM_RANGE);
223 if (i < RANDOM_RANGE_1) {
224 return (byte) (i + RANGE_1_BEGIN);
225 } else {
226 return (byte) (i + - RANDOM_RANGE_1 + RANGE_2_BEGIN);
227 }
228 }
229 }
230 }
231 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698